From a42ec6aeff48a4ade5705e994ed9d497bd9f8e53 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 10 Jan 2024 19:53:18 -0800 Subject: [PATCH] initial upload --- .gitignore | 3 + LICENSE | 19 + README.md | 226 + build.bat | 105 + data/Inconsolata-Regular.ttf | Bin 0 -> 84548 bytes data/Roboto-Regular.ttf | Bin 0 -> 158604 bytes data/icons.ttf | Bin 0 -> 25260 bytes data/liberation-mono.ttf | Bin 0 -> 108168 bytes project.4coder | 118 + src/base/base_arena.c | 316 + src/base/base_arena.h | 94 + src/base/base_arena_dev.c | 197 + src/base/base_arena_dev.h | 47 + src/base/base_bits.c | 103 + src/base/base_bits.h | 18 + src/base/base_command_line.c | 229 + src/base/base_command_line.h | 53 + src/base/base_context_cracking.h | 144 + src/base/base_inc.c | 18 + src/base/base_inc.h | 23 + src/base/base_ins.h | 52 + src/base/base_linked_lists.h | 73 + src/base/base_markup.c | 2 + src/base/base_markup.h | 79 + src/base/base_math.c | 607 + src/base/base_math.h | 648 + src/base/base_string.c | 1878 +++ src/base/base_string.h | 351 + src/base/base_thread_context.c | 78 + src/base/base_thread_context.h | 40 + src/base/base_types.c | 454 + src/base/base_types.h | 683 + src/coff/coff.c | 1119 ++ src/coff/coff.h | 872 ++ src/ctrl/ctrl.mc | 84 + src/ctrl/ctrl_core.c | 3020 ++++ src/ctrl/ctrl_core.h | 601 + src/ctrl/ctrl_inc.c | 4 + src/ctrl/ctrl_inc.h | 77 + src/ctrl/generated/ctrl.meta.c | 5 + src/ctrl/generated/ctrl.meta.h | 216 + src/dasm/dasm.c | 539 + src/dasm/dasm.h | 206 + src/dbgi/dbgi.c | 888 ++ src/dbgi/dbgi.h | 262 + src/demon/demon_accel.c | 235 + src/demon/demon_accel.h | 66 + src/demon/demon_common.c | 270 + src/demon/demon_common.h | 150 + src/demon/demon_core.c | 871 ++ src/demon/demon_core.h | 293 + src/demon/demon_inc.c | 14 + src/demon/demon_inc.h | 20 + src/demon/demon_os.h | 92 + src/demon/linux/demon_os_linux.c | 2106 +++ src/demon/linux/demon_os_linux.h | 222 + src/demon/test/demon_attach.cpp | 65 + src/demon/test/demon_regs_test.cpp | 166 + src/demon/test/demon_scratch.cpp | 250 + src/demon/test/demon_win32_freeze_test.cpp | 935 ++ src/demon/test/demon_win32_thread_test.cpp | 874 ++ src/demon/win32/demon_os_win32.c | 2006 +++ src/demon/win32/demon_os_win32.h | 378 + src/df/core/df_core.c | 8043 +++++++++++ src/df/core/df_core.h | 1668 +++ src/df/core/df_core.mc | 1891 +++ src/df/core/generated/df_core.meta.c | 225 + src/df/core/generated/df_core.meta.h | 1785 +++ src/df/df_inc.c | 7 + src/df/df_inc.h | 12 + src/df/gfx/df_gfx.c | 11760 ++++++++++++++++ src/df/gfx/df_gfx.h | 1053 ++ src/df/gfx/df_gfx.mc | 721 + src/df/gfx/df_view_rule_hooks.c | 1251 ++ src/df/gfx/df_view_rule_hooks.h | 41 + src/df/gfx/df_views.c | 8855 ++++++++++++ src/df/gfx/df_views.h | 464 + src/df/gfx/generated/df_gfx.meta.c | 23 + src/df/gfx/generated/df_gfx.meta.h | 5707 ++++++++ src/draw/draw.c | 679 + src/draw/draw.h | 192 + src/draw/draw.mc | 58 + src/draw/generated/draw.meta.c | 17 + src/draw/generated/draw.meta.h | 50 + src/eval/eval.mc | 81 + src/eval/eval_compiler.c | 1624 +++ src/eval/eval_compiler.h | 204 + src/eval/eval_decode.c | 50 + src/eval/eval_decode.h | 12 + src/eval/eval_machine.c | 630 + src/eval/eval_machine.h | 45 + src/eval/eval_parser.c | 1372 ++ src/eval/eval_parser.h | 145 + src/eval/generated/eval.meta.c | 5 + src/eval/generated/eval.meta.h | 176 + src/font_cache/font_cache.c | 1027 ++ src/font_cache/font_cache.h | 265 + .../dwrite/font_provider_dwrite.cpp | 449 + .../dwrite/font_provider_dwrite.h | 99 + .../dwrite/font_provider_dwrite_main.cpp | 12 + src/font_provider/font_provider.c | 18 + src/font_provider/font_provider.h | 61 + src/font_provider/font_provider_inc.c | 12 + src/font_provider/font_provider_inc.h | 35 + src/geo_cache/geo_cache.c | 445 + src/geo_cache/geo_cache.h | 168 + src/hash_store/hash_store.c | 331 + src/hash_store/hash_store.h | 149 + src/mdesk/mdesk.c | 1093 ++ src/mdesk/mdesk.h | 302 + src/metagen/metagen.c | 1119 ++ src/metagen/metagen.h | 290 + src/metagen/metagen_base/metagen_base_arena.c | 316 + src/metagen/metagen_base/metagen_base_arena.h | 94 + .../metagen_base/metagen_base_arena_dev.c | 197 + .../metagen_base/metagen_base_arena_dev.h | 47 + src/metagen/metagen_base/metagen_base_bits.c | 103 + src/metagen/metagen_base/metagen_base_bits.h | 18 + .../metagen_base/metagen_base_command_line.c | 229 + .../metagen_base/metagen_base_command_line.h | 53 + .../metagen_base_context_cracking.h | 144 + src/metagen/metagen_base/metagen_base_inc.c | 18 + src/metagen/metagen_base/metagen_base_inc.h | 23 + src/metagen/metagen_base/metagen_base_ins.h | 52 + .../metagen_base/metagen_base_linked_lists.h | 73 + .../metagen_base/metagen_base_markup.c | 2 + .../metagen_base/metagen_base_markup.h | 79 + src/metagen/metagen_base/metagen_base_math.c | 607 + src/metagen/metagen_base/metagen_base_math.h | 648 + .../metagen_base/metagen_base_string.c | 1878 +++ .../metagen_base/metagen_base_string.h | 351 + .../metagen_base_thread_context.c | 78 + .../metagen_base_thread_context.h | 40 + src/metagen/metagen_base/metagen_base_types.c | 454 + src/metagen/metagen_base/metagen_base_types.h | 681 + src/metagen/metagen_main.c | 412 + .../core/linux/metagen_os_core_linux.c | 1682 +++ .../core/linux/metagen_os_core_linux.h | 88 + src/metagen/metagen_os/core/metagen_os_core.c | 265 + src/metagen/metagen_os/core/metagen_os_core.h | 365 + .../core/win32/metagen_os_core_win32.c | 1474 ++ .../core/win32/metagen_os_core_win32.h | 91 + src/metagen/metagen_os/metagen_os_inc.c | 29 + src/metagen/metagen_os/metagen_os_inc.h | 39 + src/mule/inline_body.cpp | 8 + src/mule/mule_c.c | 106 + src/mule/mule_c.h | 10 + src/mule/mule_inline.cpp | 64 + src/mule/mule_main.cpp | 2379 ++++ src/mule/mule_module.cpp | 38 + src/mule/mule_o2.cpp | 119 + src/natvis/base.natvis | 161 + src/os/core/linux/os_core_linux.c | 1682 +++ src/os/core/linux/os_core_linux.h | 88 + src/os/core/os_core.c | 265 + src/os/core/os_core.h | 365 + src/os/core/win32/os_core_win32.c | 1476 ++ src/os/core/win32/os_core_win32.h | 91 + src/os/gfx/generated/os_gfx.meta.c | 5 + src/os/gfx/generated/os_gfx.meta.h | 452 + src/os/gfx/os_gfx.c | 191 + src/os/gfx/os_gfx.h | 162 + src/os/gfx/os_gfx.mc | 175 + src/os/gfx/win32/os_gfx_win32.c | 1101 ++ src/os/gfx/win32/os_gfx_win32.h | 62 + src/os/os_inc.c | 29 + src/os/os_inc.h | 39 + src/os/socket/os_socket.c | 16 + src/os/socket/os_socket.h | 49 + src/os/socket/win32/os_socket_win32.c | 353 + src/os/socket/win32/os_socket_win32.h | 54 + src/path/path.c | 167 + src/path/path.h | 16 + src/pe/dos_program.asm | 17 + src/pe/pe.c | 808 ++ src/pe/pe.h | 672 + src/raddbg/raddbg.cpp | 1086 ++ src/raddbg_cons/raddbg_cons.c | 3375 +++++ src/raddbg_cons/raddbg_cons.h | 896 ++ src/raddbg_convert/dwarf/raddbg_dwarf.c | 1888 +++ src/raddbg_convert/dwarf/raddbg_dwarf.h | 1332 ++ .../dwarf/raddbg_dwarf_stringize.c | 102 + .../dwarf/raddbg_dwarf_stringize.h | 28 + src/raddbg_convert/dwarf/raddbg_elf.c | 555 + src/raddbg_convert/dwarf/raddbg_elf.h | 517 + src/raddbg_convert/dwarf/raddbg_from_dwarf.c | 905 ++ src/raddbg_convert/dwarf/raddbg_from_dwarf.h | 50 + src/raddbg_convert/pdb/raddbg_codeview.c | 488 + src/raddbg_convert/pdb/raddbg_codeview.h | 3055 ++++ .../pdb/raddbg_codeview_conversion.c | 124 + .../pdb/raddbg_codeview_conversion.h | 14 + .../pdb/raddbg_codeview_stringize.c | 2385 ++++ .../pdb/raddbg_codeview_stringize.h | 86 + src/raddbg_convert/pdb/raddbg_coff.h | 52 + .../pdb/raddbg_coff_conversion.c | 22 + .../pdb/raddbg_coff_conversion.h | 13 + src/raddbg_convert/pdb/raddbg_from_pdb.c | 3433 +++++ src/raddbg_convert/pdb/raddbg_from_pdb.h | 262 + src/raddbg_convert/pdb/raddbg_from_pdb_main.c | 116 + src/raddbg_convert/pdb/raddbg_msf.c | 284 + src/raddbg_convert/pdb/raddbg_msf.h | 60 + src/raddbg_convert/pdb/raddbg_pdb.c | 908 ++ src/raddbg_convert/pdb/raddbg_pdb.h | 461 + src/raddbg_convert/pdb/raddbg_pdb_stringize.c | 26 + src/raddbg_convert/pdb/raddbg_pdb_stringize.h | 12 + src/raddbg_dump/raddbg_dump.c | 428 + src/raddbg_dump/raddbg_dump.h | 45 + src/raddbg_dump/raddbg_stringize.c | 776 + src/raddbg_dump/raddbg_stringize.h | 120 + src/raddbg_format/raddbg_format.c | 97 + src/raddbg_format/raddbg_format.h | 923 ++ src/raddbg_format/raddbg_format_parse.c | 537 + src/raddbg_format/raddbg_format_parse.h | 196 + src/raddbg_markup/raddbg_markup.h | 78 + src/regs/generated/regs.meta.c | 104 + src/regs/generated/regs.meta.h | 1240 ++ src/regs/generated/regs_raddbg.meta.c | 322 + src/regs/raddbg/generated/regs_raddbg.meta.c | 323 + src/regs/raddbg/generated/regs_raddbg.meta.h | 10 + src/regs/raddbg/regs_raddbg.c | 4 + src/regs/raddbg/regs_raddbg.h | 10 + src/regs/raddbg/regs_raddbg.mc | 63 + src/regs/regs.c | 58 + src/regs/regs.h | 115 + src/regs/regs.mc | 556 + .../d3d11/generated/render_d3d11.meta.c | 66 + .../d3d11/generated/render_d3d11.meta.h | 464 + src/render/d3d11/render_d3d11.cpp | 1379 ++ src/render/d3d11/render_d3d11.h | 169 + src/render/d3d11/render_d3d11.mc | 525 + src/render/d3d11/render_d3d11_main.cpp | 16 + src/render/generated/render.meta.c | 12 + src/render/generated/render.meta.h | 96 + src/render/render_core.c | 77 + src/render/render_core.h | 299 + src/render/render_core.mc | 125 + src/render/render_inc.c | 12 + src/render/render_inc.h | 35 + src/scratch/look_at_raddbg.c | 59 + src/scratch/ryan_scratch.c | 307 + src/text_cache/text_cache.c | 914 ++ src/text_cache/text_cache.h | 291 + src/texture_cache/texture_cache.c | 464 + src/texture_cache/texture_cache.h | 185 + src/third_party/blake2/blake2-config.h | 72 + src/third_party/blake2/blake2-impl.h | 160 + src/third_party/blake2/blake2.h | 195 + src/third_party/blake2/blake2b-load-sse2.h | 68 + src/third_party/blake2/blake2b-load-sse41.h | 402 + src/third_party/blake2/blake2b-ref.c | 379 + src/third_party/blake2/blake2b-round.h | 157 + src/third_party/blake2/blake2b.c | 373 + src/third_party/blake2/blake2bp-ref.c | 359 + src/third_party/blake2/blake2bp.c | 361 + src/third_party/blake2/blake2s-load-sse2.h | 60 + src/third_party/blake2/blake2s-load-sse41.h | 236 + src/third_party/blake2/blake2s-load-xop.h | 191 + src/third_party/blake2/blake2s-ref.c | 367 + src/third_party/blake2/blake2s-round.h | 88 + src/third_party/blake2/blake2s.c | 363 + src/third_party/blake2/blake2sp-ref.c | 359 + src/third_party/blake2/blake2sp.c | 358 + src/third_party/blake2/blake2xb-ref.c | 241 + src/third_party/blake2/blake2xb.c | 241 + src/third_party/blake2/blake2xs-ref.c | 239 + src/third_party/blake2/blake2xs.c | 239 + src/third_party/blake2/genkat-c.c | 139 + src/third_party/blake2/genkat-json.c | 154 + src/third_party/blake2/makefile | 40 + src/third_party/stb/stb_sprintf.h | 1943 +++ src/third_party/udis86/CHANGES | 47 + src/third_party/udis86/LICENSE | 22 + src/third_party/udis86/README | 91 + src/third_party/udis86/README.rad | 24 + src/third_party/udis86/config.h | 72 + src/third_party/udis86/libudis86/decode.c | 1264 ++ src/third_party/udis86/libudis86/decode.h | 197 + src/third_party/udis86/libudis86/extern.h | 113 + src/third_party/udis86/libudis86/itab.c | 5937 ++++++++ src/third_party/udis86/libudis86/itab.h | 935 ++ src/third_party/udis86/libudis86/syn-att.c | 228 + src/third_party/udis86/libudis86/syn-intel.c | 225 + src/third_party/udis86/libudis86/syn.c | 212 + src/third_party/udis86/libudis86/syn.h | 53 + src/third_party/udis86/libudis86/types.h | 259 + src/third_party/udis86/libudis86/udint.h | 97 + src/third_party/udis86/libudis86/udis86.c | 458 + src/third_party/udis86/udis86.h | 33 + .../udis86/udis86_v56ff6c8.LICENSE | 27 + src/third_party/udis86/udis86_v56ff6c8.tps | 19 + src/txti/txti.c | 1247 ++ src/txti/txti.h | 392 + src/type_graph/generated/type_graph.meta.c | 5 + src/type_graph/generated/type_graph.meta.h | 195 + src/type_graph/type_graph.c | 1174 ++ src/type_graph/type_graph.h | 221 + src/type_graph/type_graph.mc | 97 + src/ui/generated/ui.meta.c | 135 + src/ui/generated/ui.meta.h | 252 + src/ui/ui.mc | 114 + src/ui/ui_basic_widgets.c | 1418 ++ src/ui/ui_basic_widgets.h | 179 + src/ui/ui_core.c | 2700 ++++ src/ui/ui_core.h | 794 ++ src/ui/ui_inc.c | 8 + src/ui/ui_inc.h | 10 + src/unwind/unwind.c | 840 ++ src/unwind/unwind.h | 314 + 308 files changed, 162362 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.bat create mode 100644 data/Inconsolata-Regular.ttf create mode 100644 data/Roboto-Regular.ttf create mode 100644 data/icons.ttf create mode 100644 data/liberation-mono.ttf create mode 100644 project.4coder create mode 100644 src/base/base_arena.c create mode 100644 src/base/base_arena.h create mode 100644 src/base/base_arena_dev.c create mode 100644 src/base/base_arena_dev.h create mode 100644 src/base/base_bits.c create mode 100644 src/base/base_bits.h create mode 100644 src/base/base_command_line.c create mode 100644 src/base/base_command_line.h create mode 100644 src/base/base_context_cracking.h create mode 100644 src/base/base_inc.c create mode 100644 src/base/base_inc.h create mode 100644 src/base/base_ins.h create mode 100644 src/base/base_linked_lists.h create mode 100644 src/base/base_markup.c create mode 100644 src/base/base_markup.h create mode 100644 src/base/base_math.c create mode 100644 src/base/base_math.h create mode 100644 src/base/base_string.c create mode 100644 src/base/base_string.h create mode 100644 src/base/base_thread_context.c create mode 100644 src/base/base_thread_context.h create mode 100644 src/base/base_types.c create mode 100644 src/base/base_types.h create mode 100644 src/coff/coff.c create mode 100644 src/coff/coff.h create mode 100644 src/ctrl/ctrl.mc create mode 100644 src/ctrl/ctrl_core.c create mode 100644 src/ctrl/ctrl_core.h create mode 100644 src/ctrl/ctrl_inc.c create mode 100644 src/ctrl/ctrl_inc.h create mode 100644 src/ctrl/generated/ctrl.meta.c create mode 100644 src/ctrl/generated/ctrl.meta.h create mode 100644 src/dasm/dasm.c create mode 100644 src/dasm/dasm.h create mode 100644 src/dbgi/dbgi.c create mode 100644 src/dbgi/dbgi.h create mode 100644 src/demon/demon_accel.c create mode 100644 src/demon/demon_accel.h create mode 100644 src/demon/demon_common.c create mode 100644 src/demon/demon_common.h create mode 100644 src/demon/demon_core.c create mode 100644 src/demon/demon_core.h create mode 100644 src/demon/demon_inc.c create mode 100644 src/demon/demon_inc.h create mode 100644 src/demon/demon_os.h create mode 100644 src/demon/linux/demon_os_linux.c create mode 100644 src/demon/linux/demon_os_linux.h create mode 100644 src/demon/test/demon_attach.cpp create mode 100644 src/demon/test/demon_regs_test.cpp create mode 100644 src/demon/test/demon_scratch.cpp create mode 100644 src/demon/test/demon_win32_freeze_test.cpp create mode 100644 src/demon/test/demon_win32_thread_test.cpp create mode 100644 src/demon/win32/demon_os_win32.c create mode 100644 src/demon/win32/demon_os_win32.h create mode 100644 src/df/core/df_core.c create mode 100644 src/df/core/df_core.h create mode 100644 src/df/core/df_core.mc create mode 100644 src/df/core/generated/df_core.meta.c create mode 100644 src/df/core/generated/df_core.meta.h create mode 100644 src/df/df_inc.c create mode 100644 src/df/df_inc.h create mode 100644 src/df/gfx/df_gfx.c create mode 100644 src/df/gfx/df_gfx.h create mode 100644 src/df/gfx/df_gfx.mc create mode 100644 src/df/gfx/df_view_rule_hooks.c create mode 100644 src/df/gfx/df_view_rule_hooks.h create mode 100644 src/df/gfx/df_views.c create mode 100644 src/df/gfx/df_views.h create mode 100644 src/df/gfx/generated/df_gfx.meta.c create mode 100644 src/df/gfx/generated/df_gfx.meta.h create mode 100644 src/draw/draw.c create mode 100644 src/draw/draw.h create mode 100644 src/draw/draw.mc create mode 100644 src/draw/generated/draw.meta.c create mode 100644 src/draw/generated/draw.meta.h create mode 100644 src/eval/eval.mc create mode 100644 src/eval/eval_compiler.c create mode 100644 src/eval/eval_compiler.h create mode 100644 src/eval/eval_decode.c create mode 100644 src/eval/eval_decode.h create mode 100644 src/eval/eval_machine.c create mode 100644 src/eval/eval_machine.h create mode 100644 src/eval/eval_parser.c create mode 100644 src/eval/eval_parser.h create mode 100644 src/eval/generated/eval.meta.c create mode 100644 src/eval/generated/eval.meta.h create mode 100644 src/font_cache/font_cache.c create mode 100644 src/font_cache/font_cache.h create mode 100644 src/font_provider/dwrite/font_provider_dwrite.cpp create mode 100644 src/font_provider/dwrite/font_provider_dwrite.h create mode 100644 src/font_provider/dwrite/font_provider_dwrite_main.cpp create mode 100644 src/font_provider/font_provider.c create mode 100644 src/font_provider/font_provider.h create mode 100644 src/font_provider/font_provider_inc.c create mode 100644 src/font_provider/font_provider_inc.h create mode 100644 src/geo_cache/geo_cache.c create mode 100644 src/geo_cache/geo_cache.h create mode 100644 src/hash_store/hash_store.c create mode 100644 src/hash_store/hash_store.h create mode 100644 src/mdesk/mdesk.c create mode 100644 src/mdesk/mdesk.h create mode 100644 src/metagen/metagen.c create mode 100644 src/metagen/metagen.h create mode 100644 src/metagen/metagen_base/metagen_base_arena.c create mode 100644 src/metagen/metagen_base/metagen_base_arena.h create mode 100644 src/metagen/metagen_base/metagen_base_arena_dev.c create mode 100644 src/metagen/metagen_base/metagen_base_arena_dev.h create mode 100644 src/metagen/metagen_base/metagen_base_bits.c create mode 100644 src/metagen/metagen_base/metagen_base_bits.h create mode 100644 src/metagen/metagen_base/metagen_base_command_line.c create mode 100644 src/metagen/metagen_base/metagen_base_command_line.h create mode 100644 src/metagen/metagen_base/metagen_base_context_cracking.h create mode 100644 src/metagen/metagen_base/metagen_base_inc.c create mode 100644 src/metagen/metagen_base/metagen_base_inc.h create mode 100644 src/metagen/metagen_base/metagen_base_ins.h create mode 100644 src/metagen/metagen_base/metagen_base_linked_lists.h create mode 100644 src/metagen/metagen_base/metagen_base_markup.c create mode 100644 src/metagen/metagen_base/metagen_base_markup.h create mode 100644 src/metagen/metagen_base/metagen_base_math.c create mode 100644 src/metagen/metagen_base/metagen_base_math.h create mode 100644 src/metagen/metagen_base/metagen_base_string.c create mode 100644 src/metagen/metagen_base/metagen_base_string.h create mode 100644 src/metagen/metagen_base/metagen_base_thread_context.c create mode 100644 src/metagen/metagen_base/metagen_base_thread_context.h create mode 100644 src/metagen/metagen_base/metagen_base_types.c create mode 100644 src/metagen/metagen_base/metagen_base_types.h create mode 100644 src/metagen/metagen_main.c create mode 100644 src/metagen/metagen_os/core/linux/metagen_os_core_linux.c create mode 100644 src/metagen/metagen_os/core/linux/metagen_os_core_linux.h create mode 100644 src/metagen/metagen_os/core/metagen_os_core.c create mode 100644 src/metagen/metagen_os/core/metagen_os_core.h create mode 100644 src/metagen/metagen_os/core/win32/metagen_os_core_win32.c create mode 100644 src/metagen/metagen_os/core/win32/metagen_os_core_win32.h create mode 100644 src/metagen/metagen_os/metagen_os_inc.c create mode 100644 src/metagen/metagen_os/metagen_os_inc.h create mode 100644 src/mule/inline_body.cpp create mode 100644 src/mule/mule_c.c create mode 100644 src/mule/mule_c.h create mode 100644 src/mule/mule_inline.cpp create mode 100644 src/mule/mule_main.cpp create mode 100644 src/mule/mule_module.cpp create mode 100644 src/mule/mule_o2.cpp create mode 100644 src/natvis/base.natvis create mode 100644 src/os/core/linux/os_core_linux.c create mode 100644 src/os/core/linux/os_core_linux.h create mode 100644 src/os/core/os_core.c create mode 100644 src/os/core/os_core.h create mode 100644 src/os/core/win32/os_core_win32.c create mode 100644 src/os/core/win32/os_core_win32.h create mode 100644 src/os/gfx/generated/os_gfx.meta.c create mode 100644 src/os/gfx/generated/os_gfx.meta.h create mode 100644 src/os/gfx/os_gfx.c create mode 100644 src/os/gfx/os_gfx.h create mode 100644 src/os/gfx/os_gfx.mc create mode 100644 src/os/gfx/win32/os_gfx_win32.c create mode 100644 src/os/gfx/win32/os_gfx_win32.h create mode 100644 src/os/os_inc.c create mode 100644 src/os/os_inc.h create mode 100644 src/os/socket/os_socket.c create mode 100644 src/os/socket/os_socket.h create mode 100644 src/os/socket/win32/os_socket_win32.c create mode 100644 src/os/socket/win32/os_socket_win32.h create mode 100644 src/path/path.c create mode 100644 src/path/path.h create mode 100644 src/pe/dos_program.asm create mode 100644 src/pe/pe.c create mode 100644 src/pe/pe.h create mode 100644 src/raddbg/raddbg.cpp create mode 100644 src/raddbg_cons/raddbg_cons.c create mode 100644 src/raddbg_cons/raddbg_cons.h create mode 100644 src/raddbg_convert/dwarf/raddbg_dwarf.c create mode 100644 src/raddbg_convert/dwarf/raddbg_dwarf.h create mode 100644 src/raddbg_convert/dwarf/raddbg_dwarf_stringize.c create mode 100644 src/raddbg_convert/dwarf/raddbg_dwarf_stringize.h create mode 100644 src/raddbg_convert/dwarf/raddbg_elf.c create mode 100644 src/raddbg_convert/dwarf/raddbg_elf.h create mode 100644 src/raddbg_convert/dwarf/raddbg_from_dwarf.c create mode 100644 src/raddbg_convert/dwarf/raddbg_from_dwarf.h create mode 100644 src/raddbg_convert/pdb/raddbg_codeview.c create mode 100644 src/raddbg_convert/pdb/raddbg_codeview.h create mode 100644 src/raddbg_convert/pdb/raddbg_codeview_conversion.c create mode 100644 src/raddbg_convert/pdb/raddbg_codeview_conversion.h create mode 100644 src/raddbg_convert/pdb/raddbg_codeview_stringize.c create mode 100644 src/raddbg_convert/pdb/raddbg_codeview_stringize.h create mode 100644 src/raddbg_convert/pdb/raddbg_coff.h create mode 100644 src/raddbg_convert/pdb/raddbg_coff_conversion.c create mode 100644 src/raddbg_convert/pdb/raddbg_coff_conversion.h create mode 100644 src/raddbg_convert/pdb/raddbg_from_pdb.c create mode 100644 src/raddbg_convert/pdb/raddbg_from_pdb.h create mode 100644 src/raddbg_convert/pdb/raddbg_from_pdb_main.c create mode 100644 src/raddbg_convert/pdb/raddbg_msf.c create mode 100644 src/raddbg_convert/pdb/raddbg_msf.h create mode 100644 src/raddbg_convert/pdb/raddbg_pdb.c create mode 100644 src/raddbg_convert/pdb/raddbg_pdb.h create mode 100644 src/raddbg_convert/pdb/raddbg_pdb_stringize.c create mode 100644 src/raddbg_convert/pdb/raddbg_pdb_stringize.h create mode 100644 src/raddbg_dump/raddbg_dump.c create mode 100644 src/raddbg_dump/raddbg_dump.h create mode 100644 src/raddbg_dump/raddbg_stringize.c create mode 100644 src/raddbg_dump/raddbg_stringize.h create mode 100644 src/raddbg_format/raddbg_format.c create mode 100644 src/raddbg_format/raddbg_format.h create mode 100644 src/raddbg_format/raddbg_format_parse.c create mode 100644 src/raddbg_format/raddbg_format_parse.h create mode 100644 src/raddbg_markup/raddbg_markup.h create mode 100644 src/regs/generated/regs.meta.c create mode 100644 src/regs/generated/regs.meta.h create mode 100644 src/regs/generated/regs_raddbg.meta.c create mode 100644 src/regs/raddbg/generated/regs_raddbg.meta.c create mode 100644 src/regs/raddbg/generated/regs_raddbg.meta.h create mode 100644 src/regs/raddbg/regs_raddbg.c create mode 100644 src/regs/raddbg/regs_raddbg.h create mode 100644 src/regs/raddbg/regs_raddbg.mc create mode 100644 src/regs/regs.c create mode 100644 src/regs/regs.h create mode 100644 src/regs/regs.mc create mode 100644 src/render/d3d11/generated/render_d3d11.meta.c create mode 100644 src/render/d3d11/generated/render_d3d11.meta.h create mode 100644 src/render/d3d11/render_d3d11.cpp create mode 100644 src/render/d3d11/render_d3d11.h create mode 100644 src/render/d3d11/render_d3d11.mc create mode 100644 src/render/d3d11/render_d3d11_main.cpp create mode 100644 src/render/generated/render.meta.c create mode 100644 src/render/generated/render.meta.h create mode 100644 src/render/render_core.c create mode 100644 src/render/render_core.h create mode 100644 src/render/render_core.mc create mode 100644 src/render/render_inc.c create mode 100644 src/render/render_inc.h create mode 100644 src/scratch/look_at_raddbg.c create mode 100644 src/scratch/ryan_scratch.c create mode 100644 src/text_cache/text_cache.c create mode 100644 src/text_cache/text_cache.h create mode 100644 src/texture_cache/texture_cache.c create mode 100644 src/texture_cache/texture_cache.h create mode 100644 src/third_party/blake2/blake2-config.h create mode 100644 src/third_party/blake2/blake2-impl.h create mode 100644 src/third_party/blake2/blake2.h create mode 100644 src/third_party/blake2/blake2b-load-sse2.h create mode 100644 src/third_party/blake2/blake2b-load-sse41.h create mode 100644 src/third_party/blake2/blake2b-ref.c create mode 100644 src/third_party/blake2/blake2b-round.h create mode 100644 src/third_party/blake2/blake2b.c create mode 100644 src/third_party/blake2/blake2bp-ref.c create mode 100644 src/third_party/blake2/blake2bp.c create mode 100644 src/third_party/blake2/blake2s-load-sse2.h create mode 100644 src/third_party/blake2/blake2s-load-sse41.h create mode 100644 src/third_party/blake2/blake2s-load-xop.h create mode 100644 src/third_party/blake2/blake2s-ref.c create mode 100644 src/third_party/blake2/blake2s-round.h create mode 100644 src/third_party/blake2/blake2s.c create mode 100644 src/third_party/blake2/blake2sp-ref.c create mode 100644 src/third_party/blake2/blake2sp.c create mode 100644 src/third_party/blake2/blake2xb-ref.c create mode 100644 src/third_party/blake2/blake2xb.c create mode 100644 src/third_party/blake2/blake2xs-ref.c create mode 100644 src/third_party/blake2/blake2xs.c create mode 100644 src/third_party/blake2/genkat-c.c create mode 100644 src/third_party/blake2/genkat-json.c create mode 100644 src/third_party/blake2/makefile create mode 100644 src/third_party/stb/stb_sprintf.h create mode 100644 src/third_party/udis86/CHANGES create mode 100644 src/third_party/udis86/LICENSE create mode 100644 src/third_party/udis86/README create mode 100644 src/third_party/udis86/README.rad create mode 100644 src/third_party/udis86/config.h create mode 100644 src/third_party/udis86/libudis86/decode.c create mode 100644 src/third_party/udis86/libudis86/decode.h create mode 100644 src/third_party/udis86/libudis86/extern.h create mode 100644 src/third_party/udis86/libudis86/itab.c create mode 100644 src/third_party/udis86/libudis86/itab.h create mode 100644 src/third_party/udis86/libudis86/syn-att.c create mode 100644 src/third_party/udis86/libudis86/syn-intel.c create mode 100644 src/third_party/udis86/libudis86/syn.c create mode 100644 src/third_party/udis86/libudis86/syn.h create mode 100644 src/third_party/udis86/libudis86/types.h create mode 100644 src/third_party/udis86/libudis86/udint.h create mode 100644 src/third_party/udis86/libudis86/udis86.c create mode 100644 src/third_party/udis86/udis86.h create mode 100644 src/third_party/udis86/udis86_v56ff6c8.LICENSE create mode 100644 src/third_party/udis86/udis86_v56ff6c8.tps create mode 100644 src/txti/txti.c create mode 100644 src/txti/txti.h create mode 100644 src/type_graph/generated/type_graph.meta.c create mode 100644 src/type_graph/generated/type_graph.meta.h create mode 100644 src/type_graph/type_graph.c create mode 100644 src/type_graph/type_graph.h create mode 100644 src/type_graph/type_graph.mc create mode 100644 src/ui/generated/ui.meta.c create mode 100644 src/ui/generated/ui.meta.h create mode 100644 src/ui/ui.mc create mode 100644 src/ui/ui_basic_widgets.c create mode 100644 src/ui/ui_basic_widgets.h create mode 100644 src/ui/ui_core.c create mode 100644 src/ui/ui_core.h create mode 100644 src/ui/ui_inc.c create mode 100644 src/ui/ui_inc.h create mode 100644 src/unwind/unwind.c create mode 100644 src/unwind/unwind.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f47970a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build/ +/local/ +*~ diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..84e63ac5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2024 Epic Games Tools + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..657f4457 --- /dev/null +++ b/README.md @@ -0,0 +1,226 @@ +# The RAD Debugger Project + +--- + +## Development Setup Instructions + +**Note: Currently, only x64 Windows development is supported.** + +### 1. Installing the Required Tools (MSVC & Windows SDK) + +In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools +v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both +the Windows SDK and the MSVC compiler and linker. + +If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++ +Build Tools), you may also build with [Clang](https://releases.llvm.org/). + +### 2. Build Environment Setup + +Building the codebase can be done in a terminal which is equipped with the +ability to call either MSVC or Clang from command line. + +This is generally done by calling `vcvarsall.bat x64`, which is included in the +Microsoft C/C++ Build Tools. This script is automatically called by the `x64 +Native Tools Command Prompt for VS ` variant of the vanilla `cmd.exe`. If +you've installed the build tools, this command prompt may be easily located by +searching for `Native` from the Windows Start Menu search. + +You can ensure that the MSVC compiler is accessible from your command line by +running: + +``` +cl +``` + +If everything is set up correctly, you should have output very similar to the +following: + +``` +Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64 +Copyright (C) Microsoft Corporation. All rights reserved. + +usage: cl [ option... ] filename... [ /link linkoption... ] +``` + +### 3. Building + +Within this terminal, `cd` to the root directory of the codebase, and just run +the `build.bat` script: + +``` +build +``` + +You should see the following output: + +``` +metagen_main.c +searching path/to/codebase/src... 591 files found +parsing metadesk... 25 metadesk files parsed +gathering tables... 37 tables found +generating layer code... +raddbg.cpp +``` + +If everything worked correctly, there will be a `build` folder in the root +level of the codebase, and it will contain a freshly-built `raddbg.exe`. + +--- + +## Top-Level Directory Descriptions + +- `data`: Small binary files which are used when building, either to embed + within build artifacts, or to package with them. +- `src`: All source code. + +After setting up the codebase and building, the following directories will +also exist: + +- `build`: All build artifacts. Not checked in to version control. +- `local`: Local files, used for local build configuration input files. + +--- + +## Codebase Introduction + +The codebase is organized into *layers*. Layers are separated either to isolate +certain problems, and to allow inclusion into various builds without needing to +pull everything in the codebase into a build. Layers correspond with folders +inside of the `src` directory. Sometimes, one folder inside of the `src` +directory will include multiple sub-layers, but the structure is intended to be +fairly flat. + +Layers correspond roughly 1-to-1 with *namespaces*. The term "namespaces" in +this context does not refer to specific namespace language features, but rather +a naming convention for C-style namespaces, which are written in the codebase as +a short prefix, usually 1-3 characters, followed by an underscore. These +namespaces are used such that the layer to which certain code belongs may be +quickly understood by glancing at code. The namespaces are generally quite short +to ensure that they aren't much of a hassle to write. Sometimes, multiple sub- +layers will share a namespace. A few layers do not have a namespace, but most +do. Namespaces are either all-caps or lowercase depending on the context in +which they're used. For types, enum values, and some macros, they are +capitalized. For functions and global variables, they are lowercase. + +Layers depend on other layers, but circular dependencies would break the +separability and isolation utility of layers (in effect, forming one big layer), +so in other words, layers are arranged into a directed acyclic graph. + +A list of the layers in the codebase and their associated namespaces is below: +- `base` (no namespace): Universal, codebase-wide constructs. Strings, math, + memory allocators, helper macros, command-line parsing, and so on. Depends + on no other codebase layers. +- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File + Format) file format. +- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements + asynchronous process control, stepping, and breakpoints for all attached + processes. Runs in lockstep with attached processes. When it runs, attached + processes are halted. When attached processes are running, it is halted. + Driven by a debugger frontend on another thread. +- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for + disassembly for a particular virtual address range in a process, and threads + implemented in this layer decode and cache the disassembly for that range. +- `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug + info stored in the RADDBG format. Users ask for debug info for a particular + executable, and on separate threads, this layer loads the associated debug + info file. If necessary, it will launch a separate conversion process to + convert original debug info into the RADDBG format. +- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process + control. The abstraction is used to provide a common interface for process + control on target platforms. Used to implement part of `ctrl`. +- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a + debugger "entity cache" (where "entities" include processes, threads, modules, + breakpoints, source files, targets, and so on). Implements a command loop + for driving process control, which is used to implement stepping commands and + user breakpoints. Implements extractors and caches for various entity-related + data, like full thread unwinds and local variable maps. Also implements core + building blocks for evaluation and evaluation visualization. +- `df/gfx` (`DF_`): The debugger's graphical frontend. Builds on top of + `df/core` to provide all graphical features, including windows, panels, all + of the various debugger interfaces, and evaluation visualization. +- `draw` (`D_`): Implements a high-level graphics drawing API for the debugger's + purposes, using the underlying `render` abstraction layer. Provides high-level + APIs for various draw commands, but takes care of batching them, and so on. +- `eval` (`EVAL_`): Implements a compiler for an expression language built for + evaluation of variables, registers, and so on from debugger-attached processes + and/or debug info. Broken into several phases mostly corresponding to + traditional compiler phases - lexer, parser, type-checker, IR generation, and + IR evaluation. +- `font_cache` (`F_`): Implements a cache of rasterized font data, both in CPU- + side data for text shaping, and in GPU texture atlases for rasterized glyphs. + All cache information is sourced from the `font_provider` abstraction layer. +- `font_provider` (`FP_`): An abstraction layer for various font file decoding + and font rasterization backends. +- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU + geometry data, filled by data sourced in the `hash_store` layer's cache. Used + for asynchronously preparing data for memory visualization in the debugger. +- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a + 128-bit hash of the data. Used as a general data store by other layers. +- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and + data tables. Consumes Metadesk files, stored with the extension `.mc`, and + generates C code which is then included by hand-written C code. Currently, it + does not analyze the codebase's hand-written C code, but in principle this is + possible. This allows easier & less-error-prone management of large data + tables, which are then used to produce e.g. C `enum`s and a number of + associated data tables. There are also a number of other generation features, + like embedding binary files or complex multi-line strings into source code. + This layer cannot depend on any other layer in the codebase directly, + including `base`, because it may be used to generate code for those layers. To + still use `base` and `os` layer features in the `metagen` program, a separate, + duplicate version of `base` and `os` are included in this layer. They are + updated manually, as needed. This is to ensure the stability of the + metaprogram. +- `mule` (no namespace): Test executables for battle testing debugger + functionality. +- `natvis` (no namespace): NatVis files for type visualization of the codebase's + types in other debuggers. +- `os/core` (`OS_`): An abstraction layer providing core, non-graphical + functionality from the operating system under an abstract API, which is + implemented per-target-operating-system. +- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing + graphical operating system features under an abstract API, which is + implemented per-target-operating-system. +- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing + networking operating system features under an abstract API, which is + implemented per-target-operating-system. +- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable) + file format. +- `raddbg` (no namespace): The layer which ties everything together for the main + graphical debugger. Not much "meat", just drives `df`, implements command line + options, and so on. +- `raddbg_cons` (`CONS_`): Implements an API for constructing files of the + RADDBG debug info file format. +- `raddbg_dump` (`DUMP_`): A dumper utility program for dumping textualizations + of RADDBG debug info files. +- `raddbg_format` (`RADDBG_`): Standalone types and helper functions for the + RADDBG debug info file format. Does not depend on `base`. +- `raddbg_markup` (`RADDBG_`): Standalone header file for marking up user + programs to work with various features in the `raddbg` debugger. Does not + depend on `base`. +- `regs` (`REGS_`): Types, helper functions, and metadata for registers on + supported architectures. Used in reading/writing registers in `demon`, or in + looking up register metadata. +- `render` (`R_`): An abstraction layer providing an abstract API for rendering + using various GPU APIs under a common interface. Does not implement a high + level drawing API - this layer is strictly for minimally abstracting on an + as-needed basis. Higher level drawing features are implemented in the `draw` + layer. +- `scratch` (no namespace): Scratch space for small and transient test or sample + programs. +- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU + texture data, filled by data sourced in the `hash_store` layer's cache. Used + for asynchronously preparing data for memory visualization in the debugger. +- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot- + reloaded, asynchronously parsed, and asynchronously mutated source code files. + Used by the debugger to visualize source code files. Users ask for text lines, + tokens, and metadata, and it is prepared on background threads. +- `type_graph` (`TG_`): Code for analyzing and navigating type structures from + RADDBG debug info files, with the additional capability of constructing + synthetic types *not* found in debug info. Used in `eval` and for various + visualization features. +- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a + core immediate mode hierarchical user interface data structure building + API, and has helper layers for building some higher-level widgets. +- `unwind` (`UNW_`): Code for generating unwind information from threads, for + supported operating systems and architectures. diff --git a/build.bat b/build.bat new file mode 100644 index 00000000..d8267a4a --- /dev/null +++ b/build.bat @@ -0,0 +1,105 @@ +@echo off +setlocal +cd /D "%~dp0" + +:: --- Usage Notes (2024/1/10) ------------------------------------------------ +:: +:: This is a central build script for the RAD Debugger project. It takes a list +:: of simple alphanumeric-only arguments which control (a) what is built, (b) +:: which compiler & linker are used, and (c) extra high-level build options. By +:: default, if no options are passed, then the main "raddbg" graphical debugger +:: is built. +:: +:: Below is a non-exhaustive list of possible ways to use the script: +:: `build raddbg` +:: `build raddbg clang` +:: `build raddbg release` +:: `build raddbg asan telemetry` +:: `build raddbg_from_pdb` +:: +:: For a full list of possible build targets and their build command lines, +:: search for @build_targets in this file. +:: +:: Below is a list of all possible non-target command line options: +:: +:: - `asan`: enable address sanitizer +:: - `telemetry`: enable RAD telemetry profiling support + +:: --- Unpack Arguments ------------------------------------------------------- +for %%a in (%*) do set "%%a=1" +if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1 +if not "%release%"=="1" set debug=1 +if "%debug%"=="1" set release=0 && echo [debug mode] +if "%release%"=="1" set debug=0 && echo [release mode] +if "%msvc%"=="1" set clang=0 && echo [msvc compile] +if "%clang%"=="1" set msvc=0 && echo [clang compile] +if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1 + +:: --- Unpack Command Line Build Arguments ------------------------------------ +set auto_compile_flags= +if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled] +if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] + +:: --- Compile/Link Line Definitions ------------------------------------------ +set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /MP +set clang_common= -I..\src\ -I..\local\ -maes -mssse3 -msse4 -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf +set cl_debug= cl /Od /D_DEBUG %cl_common% +set cl_release= cl /O2 /DNDEBUG %cl_common% +set clang_debug= clang -g -O0 /D_DEBUG %clang_common% +set clang_release= clang -g -O3 /DNDEBUG %clang_common% +set cl_link= /link /natvis:%~dp0\src\natvis\base.natvis +set clang_link= -Xlinker /natvis:%~dp0\src\natvis\base.natvis +set cl_out= /out: +set clang_out= -o + +:: --- Per-Build Settings ----------------------------------------------------- +set gfx=-DOS_FEATURE_GRAPHICAL=1 +set net=-DOS_FEATURE_SOCKET=1 +set link_dll=-DLL + +:: --- Choose Compile/Link Lines ---------------------------------------------- +if "%msvc%"=="1" set compile_debug=%cl_debug% +if "%msvc%"=="1" set compile_release=%cl_release% +if "%msvc%"=="1" set compile_link=%cl_link% +if "%msvc%"=="1" set out=%cl_out% +if "%clang%"=="1" set compile_debug=%clang_debug% +if "%clang%"=="1" set compile_release=%clang_release% +if "%clang%"=="1" set compile_link=%clang_link% +if "%clang%"=="1" set out=%clang_out% +if "%debug%"=="1" set compile=%compile_debug% +if "%release%"=="1" set compile=%compile_release% +set compile=%compile% %auto_compile_flags% + +:: --- Prep Directories ------------------------------------------------------- +if not exist build mkdir build +if not exist local mkdir local + +:: --- Build & Run Metaprogram ------------------------------------------------ +if "%no_meta%"=="1" echo [skipping metagen] +if not "%no_meta%"=="1" ( + pushd build + %compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe + metagen.exe + popd +) + +:: --- Build Everything (@build_targets) -------------------------------------- +pushd build +if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg.cpp %compile_link% %out%raddbg.exe +if "%raddbg_from_pdb%"=="1" %compile% ..\src\raddbg_convert\pdb\raddbg_from_pdb_main.c %compile_link% %out%raddbg_from_pdb.exe +if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe +if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe +if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe +if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe +if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %cl_release% /c ..\src\mule\mule_inline.cpp && %cl_release% /c ..\src\mule\mule_o2.cpp && %cl_debug% /EHsc ..\src\mule\mule_main.cpp mule\mule_c.c mule_inline.obj mule_o2.obj +if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll +popd + +:: --- Unset ------------------------------------------------------------------ +for %%a in (%*) do set "%%a=0" +set raddbg= +set compile= +set compile_link= +set out= +set msvc= +set debug= diff --git a/data/Inconsolata-Regular.ttf b/data/Inconsolata-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a87ffba6bef48195c8cf4e3ccb42ea77034f7cbc GIT binary patch literal 84548 zcmeFacX(XYwLZMhnWoW5nvtff&S)f!`luIMw&W_g;6kw^jIfPyrP!v}76dRPShgX- zB*6s|AUDAU!ew+gjBQ9EH{eDR6pCdNCH75l0}{A_5J*7!z3(24!MXgt=lP!J`|Epx zAHB2BKIiPZ*4k^Wz4k#ULI?-ID8$UmFYA~&^OD z@+Dn=7K7D7n7$!|?fJzwELz?ASyr16>G(6uTfFv`fccE#6vA^D&lfCRz3hf>w`KlA z2-gmjv1r+%n^%im5faMuI^1_GyS{hn*wnxLw-ElBLJ18mU$W@he?Ice3_P2H`wh#H zVVbYh;CeF4TYkeW>nq+W>caIoA=IVUuUfq5!`GXCgZkdX^}-t#tzT`JVj02x<#;}D ze>YJ9Vp7Ht6HA1*Q!}CW3$3jtm z`5B(BF;vnC;u(Q09-1}MUye5h>2-6VC3`V-u{KmMzn64eUoQEg_c zK^SmjgAfsvbsduOzd1{%Tr1i{;G^Vt8w~Ts&u{~?fTxbAtMC(uw@l_-GMd)KD&ZF` zB3l%Q--!D}hbR#h;tA0%o<(UjqDxE@Q$!Wglf-O1HyQa)VD2hJG4k?+9rsE^gBUAj zp@ar8S5%8qF%fw+A_uuSqDj=@xf;}xj@)ddzK%C96Fn%U8YMQNtZLCJio{fLElQh+ zdWuj_G47R$#iAMc<8kFce?54+UYrnDp(G)6JRQc91<08oR*N(-6Rn(&wx@~PMK8)- zh1_2WAL@Hnd|%uq@0&2XHautl(mx~08$0@MF8aWKxv~d2=mGy-fxnv3f7y7l5pDkB zUov`;xVjd-;J;$ohhqHlUpxNBkN)$ZXCBmEE&odJF8>PnDO>v`B#V0O8n(v-10C6HF%SM9QiN)Wnk3MkbCgkrHPm3R52AAUR zKJgO%;Xfs!{QJNEHzR-{g9K3JD;&TK(;4we(g@^>Wn=`iY#kYfq(}zZB&G-((y1b4 zQ4G%*f1 zU5p3L5Us$O5-$;LBY%bLBhD5RfOEt|;9M~Yc&V5&@;{JuQ-PODyh5}iJx_E1J0*6B z=_4PAZZQLRrNsGSCel}lOMpERuNJdL-WLnRY~VsM2e?Sg1zsaA1uh2u1(M=2;1Y2; zaH+&)Vjj}VMJI5D=olRw@O?qu0eX8xE8oxVy{?&^lf74$UBfJ#IK2Ez&pfp;GJRx@Gh|uxItVu za$ejmt_R*DZUBB=;y1*NNZ%_~jhusAS`F+IYk-@?O~B0(w}_jOzE9jTa#q|g@tfjS zq`xKB0UwaKRjfz)LD4&MMtoc1cf@T-e^=ZNd`Nr^xJ}$Ka$0N`cL8@u+$lC7{jj(j z_=v>siF-!g#;WlR;G+^B6ZazhxY!8%0q{@aKSUq!hhh`(M-rb9Taex*?gQ=y{!#1^ z_XGEeZvvl`_>}k-(mxhkflmYfTl}YZ5crJv4lpXQUwjv74R{J`*F!*EYzICkF(!5( zy-(}}?gyR}2gJj`=fxwy7sU5~KM~&t{!}~){2A~M;^*Qq;EUpM;4dWpm-qqFzZ5?l z`8}jI@n!KN;6bqqcu3-5u^Z_lV$aBsI4bcK@g&l}5>EktE%7(v$4I{_o*wy~7?Ai| z@t;V)CZfRCCB7m0N8S=|3JrKn;-GjI>El8No{;#Kh>e^OzZ3g_LlS>44j}yp@jMXy z1D+Buj2svLEq((0qxdQCPvU35w5}-{}D$<-V}coM}Z$o{7Afl^xwpm$xlz-cXG?gl%da33*w`MR{wwhpIJGI zLIcng4Dhj-U>{pxMOk4z*+dE~rZiYe4p>MT@Q%1(5qV$<`CtKM!t%+6#ghxWIRFbM zAC^r4ESe%%GR3gbOJTW`!(yp~C!z`#N)0TNI`|_RV2L!r0vQ9#qXibncvu>3@JLKl z%3)hfhD|XQ_J0R#i0QB$W{OK-FU*FWFcz!B0N|yLQ@k0NB0}49HB3KBEVHqre zMX(H(zzSFZ*Fp2Y0UAGjBWs}H-we(ER$lm`M+R!oj63oD{(c~mJ4RzwZufvHhL;nYjJ zLfwHafi2Un-4d7@Sib1msIgG~;>MCK-H||4T-LP$czIVa+SZ+QA-SZxdrU>t$YSsY zp5D@p0#=R|fM1yv`Me@(DxVRE8j9w0&FzYAn4A@Do7|lh3EmJg; z0l3d}$;8I6S0t6~Ghf*;nzF3F=90!B^29#nLZ*5lWmwrcxjKih7{7k~Ogr9wS83kT;t!GMd8OG(7SQ;Z*`2xs{LH z${V+8BMv+qap1-R0Qv%c9s{es4!jDx9h@rQ8R-@l<%qDu2WnAwLK=MW-xBdl<#j{7 zagMpvyvX9Q=t-9+eLLy(q<5`F*2T&HWwY2mO!<52LutMC4GtxJPsX;4Po390_c&j5 zrMgBuPkOKQP4$oWpU-T{yfdpY>%Odk>}ff(a_-6{*o<{rAV^wO&?vs`xN<&&;>u+!OP z>niGM>YCHFyzBPvcduMC|4;KjzbfgfoU7`uy5y>^t8TdJ{+?Mq*Yx!E+}HCTJ$lb; zS6{W@rwe|);P`?+FElUoF8uYPw-)_*(I?j=U6XfB<25rEZ@%{ZC8i~gC4nUqmUJ#z zx#YGb+n4@znQ@taS^2Wb%PwEGV%g7@f4m}PMc#_)6&)+OSC+4wx^nKyMb~}p`X{e{ z{`!}%fAjjY*ZeDAd01-+|!Z|lAH_BnS{-!b`)&O83+ zuC}|n?pl4+!puy6eTeUb$=NuK(F!+~D01+3?BTtL}dB9@{)G&VdGO9|J*mdZ+YK4n+i5vxoOL$^PAt^a@&^k_f5R- z%KPrV?A{lUM$i>HtLO(|2qht(!m ztcWH>qUw;gP*v7wrvUnZdP-G$+H7;wh3aZ`gSu5U^+X*5ZMGjdbjM4MHym#}kdfqw zW)FZlr*uVABU$~aj`7{{!h{P`5-w~g)5bDwN>9`?R8?K*al6c+{G$50hT0lK4X-Q~ zLRK#tEafgWVAJH~-%h9l}5iY5?}!vF6P5 z^z3|JqsRJV3zI=#lgDII3tF?Ya)WtSPfVSh>zC>L`AFNd(00E_R)*A@u&U=N2cphM zR18F&j%db!wl72Ji8W_T%jnK9tkFK2Ic;PD6>N0nKbm z!+V-F{_}~Ik6L}!Vyj_I)ar;P4S-;@N|is+R7W&rAes`<9CjnK(=!zQxSRq% zQ5S}NAnJ~2Ug2c6FP`nghz~^l5iKj8oh>_|eVUC5t=azUl5DgsC!U!bFE>wiNyxDR z-3d&TNE_d+sj`HqiXn7x){LNNN7Ot(%pTI;&mPHEZ;Dz6w48X=IT1{0G{+H5AJR9Z zZ%tR%L{sJ1+XtfdNHpCMb;;Y_foL`eK$eq58qm%u7^}hLv&kxca?j?fJR_?jc%~mQ@fR2 zk-Zf$UT5iYK3>uHG{8Tjf{keOM*x#aPv)xl0UX+N&i>kJd(r5&~{ODM zU_d(szbH#vO!WP2$G6e$S z$+G9mj+VVuX6(^@<;CTAbx%2N9tY?L%8xK(Q#CTq5qb#+>H$vzgm#7v^N<WjjS9+%hStuKPW z9j`Vz-3<-(bw%NNv)S!>w@ooCS2vcK6jP|BthL1DEgK&mbN!?;qoHQTtXbZY=Fpg` zhN{&S73zJ8s#+~YwuudDnyDoD7iqbLk-VISih!wgTvA7iAvpNzD4{1u6(juxvw8z0#+6Dk* zpmtQ?;$1*&Cp7W{!qB6gV3xrc=HrHl{(#{z1B8`2plw$K{;~K8JNhS>L9|@7tPmbn2oHIYkR;Uf^NKF!>11~s(XI&J*1cVeZ{mVw~)4rdq0R-fkT zcHw7A;T46rv$POBTL;jmmdq>R?MQcoKegSpYLC#{&7CZ6s%;*M)7GP$*fdACV}-+T zp}-DT7Yb~%wik95E-PGD2y*Ty>0((OkuH|iUfYSXlv*WZ043DcCBDcDm^2& zSl+`kW73_jK)%bBr>^?^LFJRIs*uZ7P?gm@%@wN3E(?XqN((}7xC$a!Sygx{zY4!0 z*HmXgX<1=WaS3RpVB{m^ztvk|)z*rM>IYgN9g^>{bd1!i0Lo|MkT%Vdl2NU7W_3IgLf}$ID!Wd}|PF91S@7 zD@`A1b%icuk!%_%G)Y)lAgrte{iWa{B|&mYxJbfJ#KpQU?y;*d+2pps1N;6xF_y)VEmC2{{H_J{_#?-~j`duCFoF^P1 zxXSAI{Gbcz!n!i~E<3gz5Y2M*S3^dpIQm=EkF<$JR@|n9UdqyU5zY_}a%|5L_7YAI z-r~Uepk`>tscSr+b`-jX_71g>=j})BZ`sk{bCjD+K0p`YJV0;qclhz(c|S7FxRw*Ki|svI3h2Z5YiBC}F-q-+#sGE^wqR-@zuDMjgwt%| zA=y|Ct)ERikamPkJkK^CfI_7mCH#(XmJL0_HZ~GE31`qkz0u#!)}BT~wW)+g2^X4q zmMOBjwui8hjXZOqrEjC9`t~uq$ADAAb&X!L#cK(hp)Zpi8yck$kFzf1ySJgi-~vFP zgMqyi>A7HRi1|k4`-*Wwe(BV)jd|VG`OT%?Db4Mk!kX;dngXXIC+u6Dmh+Es1;r&< z*(HU=6=}Y_3`c&B&tg~1DQ06uOVj-Fu5iRx(wNtJU0~jnY;dNhFyi;uR2162pI)OV zRWsA41cMdD@A&70-JvXdvfY`K4sY3SpozCa6Ss?+|3^JMWmL;Hg3685vTZO8oTKWr z85RMw>xREb9a^!c`y0Q|qSMD$##Lw3cHhWl%3jpwQ+(0%NWU3;4XNNAirNOEUPsh3 zYMFRYi6>#1NG3~WjRX1{wznZq$@ks??Om+a+FJmU^UGwlGlZ8RRJ1|DHq!4ILLXsM zD&Pp=JYf@wWG|`aMA~^$&BM$%N?1=?*-PjmPwgRWCLACN(bRB<%$1(zm&GQ5to!s6N6znL?pTINuT{46lVI7Kp=ZRvxt(%w5;y zHqEUGv|K$Q6q?vGHrK4qR}6K}-qdu%;>&XC^X9L?-b}&u z+W?Mx9~N%?kU9v{Q`^OXI7pBav7MHqkd9gmjcEfH1#0`tnk62GofF5Qs2icf?EUVAH9cAg8oI9{wI~zw;s_=M>VWm3D z*>dfaqHz0?@y^=0WAgHv=BV?>XLsIk$HYl@t-3O&CF_y}E1Q~DUWL#-1wPr8%2Cw< zU+!n1Qmu`P7mPems%Z#zN?U5CvD7%mINf-qai!6`CTfBjJ*3$!%9=K7)bgTbz;en0 z+Z5Tbx`5UpzMCpBO_pOHYP0^_{;K_?{e4)mLQ4^bGW}%A`zh#Fx{%8U-hj%zjvC0I zmMxhm(aO-%|ITo;=eRYx-6818 zq59fCv_ADzYk$9LdurSZFN{OoPmFXSrgIrQ@$E1)wKkS!7;3XUWB9q@Rl`Zc`vy~w z-fEaleZwpa7)P>)%^*!)TSP?DBHC6A4Sg$*fwtlQa9P3>*;1gxm7vsIm!Dnea5{pS znWe7TH{@ovIFr*I?o@w19D|BzSNzH|%2m{zsRIN+u_#O+-H#AXG(YGLwkykrcPLj) z;`7hKt5XUudJ0;M(OQ)Rdruu2b>~R`&c!|*>FtRtBVTsfj3k^k|KhPxd>J9XKfl21 z?ac6c^MgKLK5K0oIi@@Z`Ct(9F;495YV?+_iC1VV(*Xl!dQy3wKbw`E_@U&0vi5}G zISih@(XfqU_!1fNb;F;KW*4Q7ln^FW)n3J`v?@CxqezXU;%YA%K zo4QYKb}@hQ;#UEA^(7ZkLU~K*Yj76zdqI0ij{XodB$qcN3kiAovy_W}jF1=4KahuX zFCieG02k^95qW|UX~%X8Mr0RQN;^a7By1-fB21;$vXsyXh#fKyn$McSiR~oqPHKkJ zlDo;YC&-8^3AFI_F2{1Pzjhd+K$}K5L7{NWc?NP$Yp2v)2GBRTc2Lhf>^jbsWiQv0 z^Mtc#Y^*P^J+M1qK&^qnz*!{3zqDF5a}S$&j&Ov~!L}|ZoFjAt^dsgIFl@9Awz-?a zyo2prPB>0DLO6y7#@Zd7j%BcSv_oujC(VE>*x0FrrEKwN7v5wm56bmVwwLfWhx{1f zEspiOgiQg!Il>XbTL8raL;4Hjr?$ph1kEZ9hLX3@;DLQK9$HwDa!*bu)Z9^6)X@|S zHgy!u^0?}<{MAL?v=4`T^_f|bklU;V!gtP^ee0~E%FAwTZ(n;wd&{T{=)DTXvs9RWFPpbN|~W0Wr2rIW}*H7K|qFR0qQ)b2y+M`i`Ec%Jk5+l370C zd?n>Ve&xcYIiQ`V-u*GbY^O8J(eG3~(z2XF;nuYL;wt|F|TcAQrhc zYfL$)98=D~rL66y%Yr4w`b^tRyG>w;KJ#|-ZZhH~6zXh%yO@?X)OAam!4j-#sI7Ge z>l+#x8{?`3>C0la%*yI%D4bZ6ot|CjYDo>`<=PaJ$!0PPf4gvAag{$W!<-Q;@nn|d zWxx}ord8EvRkao5)J4iNno@#ArEcrg@@Xpz%Dv%&V7jLy=(M}NRs`WIi0%9vbmTRn z4xKPlHqK#(HxL|VI(X@etpBO4% zCgi1n!w&MYGX55PffZPSNugDk(W=DsN;Qzv8?3U8mY#?4>f5cmq1Wky z8D}}IgU+)QaGR**pDpLhH2^PRJD|uWw;G-1)FhWH6v=F8Rg@-Ypv<2U^gF7`Ci%;ovCmKi{(cFPCRwB^Nt!ts zl+Z>Z7y#&7&5uJ2Q-!y1{i8BZznVx@Is2^?!fk+PveejM+(D#79NQoH$^@>A^0mO?h# zoY1Xbb)F7{yA-&_ z2F)2NuLimA;2O|QW3?j52NM!fDnAJpa)6&47)MxA{VJ3Tv*KV`&^V1|rnGxWw{NpV z2X-%pfc@DRXv}Mo{E3zfY44Xv;izv++D0|qO9J1>rFT1F8%@hTnwBRr&QlK3Zq=W6 z9z}okzT)l0m|$%q-`PcwZ*M1i^jWvlijw}F%`D`RFBP&Mg~To3qbzQ7@lKRO&DC;2 zJYq{wvPiBWzRZ#>%$D#|xw^i1N^N#-eS2y1qP+1YMKQYaN_@WZAPBxPD=^+$ zuC8i*)|bt*M7d3`LjYY1!>18CscR80)2Q5_c>>^p zfCnvGO*ln3NmU>~I7LuBQZ8Y#3|N04a_GvVikLP4uR(uRVwNtVcIngOEK$K7qI9%E z#H9=R?Pvg|rOOmNX%(0hcmwOH$1B<{($GeZl$Wrbu#wu!cEUD#n7o8OfZpfdE}dd@ zE}g^Lq<4h6LYSh%q2u_`4up{3Q2;m(YSh-2;fc<&Wpw(jYs4a^Z**=W1+yl-&$XR8 zo{xoZBJ5-hoBcak!?{Ea+Ch}5w}(1e{yvsJNSMk>Vyxs4;T(y7S=l<&q%Ut=-^dbB zp;8myn~>_1<%>lz;b%6OU2*4?w2UzGO5Uuo)mF33o|opTuM8^g_Ttd^NLF^$gu+Ni zb!Og}xr-EMer0A^n=3EuESRXSZLUvp8j~%~x&<>r#W@W#Dl0E(%q^LD!{p2F?y4BR z500(y#H#G+?L`ftbQ}v*5Zxq{D7ZRV{1z$>XyIjn4)hTk1O&usrh*bk>V_n_6iSE0 z8wN5h`Bx7c8|iy)GQwO>pJwbft}yl*Hyd{v_Zklvlh(wJ8s9R$V}#6lm%KSdc!lsh zAQpcPxYFx5jv}GavXQVZ3NhCoc2rI=XsL8BaLJb*> z!TO*QZM~s#cGdDR!yhY))Q+vgf7teb;@UD1wo?oE;efhM19=c;gu z5ForrSWRdnoTBy}AP6aPXcc=LQmT8PE(qy1cX~Kfls+Nw3Zzd(TuXr4n`|>7!8R9p zzc1(qby-qBsEcTMbs(ncbywD@YowZRTL9Bys3T8mPWeMwSq$|6%+wO+qCRS57t1DX z8ztLrf{)tH9>Puu6jV>xd(HhEqbX$u7%R0cLtXQ@p4}wGWJIR#{sb`BP%1f zML-Tmne{GVDO6c)X*J*&LGJmTMM@v6ISW-o8>~fodHwo&%4Ht~@y?{ZlpN5TrXqI-`${jRc9tE!AXH+zefxZed{AGv`FHtaezd{MJ{=;kPi@xiIlFV%C*%L_ zlin3vexWeC#x$ih^u;!c&gxu*Q6p`u}8Ztc|K;;FSclbg%xGAmm`*yQx@t7vfs%l!VbKt{*c zQo{c9!YX@Kf!iI*OjG_;G1uqsX@G8(nOQL|)NpmCXLd!Psnq8!X?V>!qrzL9n~|Oq z_EuiY5zN2xQvrzCd~|564ahH$8{_Dx4!#ro%1)FP$VU1tidrIz?DbP@QrO zkP8cm*9OiAQ3>cTOE8BIi@h(g^2-H=d>&s=$m(f6$z*8}J(yNahw}%VR*?pWn^c|G zXtp#T+0X|T!9tUU^(xLHKC^BNtXLVLM?XNveZv(#>`2MDBUiqD?1j zOru?X7(AgbFIr!OT-M>umwExL?}o<2P6+oerK#?0sG}iB zQ*=NtgnbGxn|+~uwS9wqtKEdDr^yN@BqEHGU>(`wt}Pj4#A$`)V}fc%E9L_eo|F+s z+K3PG?i3^r1Uk3)6Jb-%FJCA=#7ub$;E{7CTyx4c`sVVzzWm|n7hXCw?#)Cm93n?- zq2zAk>UIi?-T&RG8FyuV*{Mmr#tB-DAXZ90>3<(m5F_DV<-g1Sfd4T+I=jk`cE1l0 z(d@{-xv;V70)NoPvzU&{(Omy{M9HmN6qQh9%Ln5O5T5W_+WiBiY z_#pL{lsDjT)Slzg@Lj^605m_$LzolkXfzM?3ow;prVn=VrrMtpNdhwdw0e9(Tf z>eHDop(kx4A1WHWxhXi$e}(3z*We_V%hhD(K&p%>3PiXa0T1*0Sajg<{oh_?@ByO< z`ylVAHs?XaA#8}7?{Fei!}7r@5LaoWU6a@@`bsZ!G%%!P1*DC$h4OPJp~yi^K#vt2 zgsh;pQHkk-;Zr@NokZExsSiUY>O0f+Qa;LU+=saA$w(qPc=T<~T?sWfzTh3pP;rSx1J z1^ISXv3yf8D z5TE!V_KmT**R&J;QqAV&0s&efcR+!SdU=SEnV2L@I|bLCQ>jJhHWI4D4b zjfzP&d=zV|oKv~5(r^>5;qQZgu)hX3p;{seM_bsW+=RK;i;Ydx%>7iTcM=W|J|%1+ zJPFWunD)>q_z5Jh?l+Y%y@gWvDB&>Gr)I)lfZmkc0e^aIPxAic!`KvyZ*Gwo@Y2Uz zd}%jp7OcS9y>_JNrquq<)G@BDO}-9Bf-$B+`v)P3VzL=zqM!GFN?o#hxjmhmy%l+1mVXVeBrm^=J2{ZfrclKWP zxsQF89X|onb+qI9Io~JjKYN|%@Im&g5fIy+y*qnfHi{Z#)_2)eJ?ABcc}TT-c|LM` z3G3KZI`9gy98xVDjb#GUjAp>YDpdmd?HLczXprgw6^MG}*$FdhuAWg*Hsy-4()PNX zmhhOIssh)NRd#n_bylFQHc;3yGu&KbNS`&WGP}7jw%%YxPhfVn>M7miJ)jQdb@G_q^fMJYc-y4o3 zs5}HYJAS6{c^8ll0QMUeDk9u&aua+XPE>)fkOSAl6%hQf=L|0!-sG;e2UprU0#a+@ zuFxOy@=t(%qv@kqgK?^Ho)M3ltTMO`J_tDW^k&O63r4gHoQ|jX* zF>{h9sVE8dYI6JmdgNl(WV+*!c@S4|nSGIC$^u>0LOli!tz?A-N0Skcfpre+rgb28 z)cTh79jgH%SqqT9GDupJte4TDT4$YXRo7^LLsraWbz2J&VjK@|8bVgBv(_03hb)a@ zi+w2RgN`W&TmITLN4@Ryjj`B!fB6e{0O{G}w_`G(d6z0vw6qLES(|lX+Um3oX;&UDNh2q;P}KMlh#Ip=Xvt4-Pqm18Y{7G<9Lp((w(Ix-g-x zUo;-+7>{&}hvrh!;{r_DuT~cqER0EiUflDOA6LkwAKS|r+y{uoj0cU!ID205D*fB~ zuA~@@I(?TtM*Wh3rP>ZKioOLWH;}QT7#a5gg!TlBxlmTzr*I5K#C99^84saUeQ(kM z8i;->?RyCfp_RpHJE)dFjB=duT??~?aS!HD$my1GMU@EDN2;L_iK_mF*;ScU<(Xvx z$Likblxs>Gf(})+2Wkp$SU0EDsAd$l!Y$`6Z48#ra#(|<)tR#ws&$9#nT2k5L6&29 z_-~VHvnxXxm_AVg+v!d97EyxpGR_?68?9_f9s!Zdj6Lp8#umc{nodk>*4H!T7^2vdbT=ddQ0w4`~nZ^$38vgN()r zlUFv<*L@72hf^DAM(?IJ^bW`FW%}k~gkywh7uNeLkfJerBe_t366PLLMPPNt3! zo(Je1fvy1N_MyTjU|Yq5fb?QZ6FK!l#o9L1cv0<#S)B|Z>R_Gw3EhOFgl#PSAfcUA z?9SVlhvEjAo*I~k>a=|U+@Br1L4jOPt5* z(H3wEqLmQfWgCDhLK>J7yqWQpOqp;n$yo;vx<{E0feJE$SZ*i9+6|qCWt6hp!ASZc z!=M3!b%;FJZtaA;f+Ga`O8cybtdK0{Ndnv!7uq%!vyTuX4=0Mz8EJ&s{Zc_%2Swlx z!hV9>_ojlO9RZAT9(JKa&U7wWn3skJ=X8(HEoi-V`n?m|u3M~huTWQ&UwX^5j+^F| zs`bO_-MzPMAs3AW9KarrO{~_EZ5Y#6u}W*Rx!VyTsL9f^2CoC$W=R+;h--5^&x}|V zZrNSr$xe(Ieb@&0u#G~#57Q2 za<3Z;B>W?*amMvpO|_zR42aPJgvZ$XlZ2lGq%$+#I+Mx(Qi@&0XEp-5RW(H89Lkywxko+%VbYn!_ zTvIJV8lW&)@*te)jj&3;O1d;Y5EH_ ztNa5ksfL9{y(Uw9Uo(=M1Ehrk!s7t83vpK5enhh0hjGgsjjFwfiRFF)DG{y6jJEB&L{4|g%L`Z zVKdTE2X>;^N)P>5$yw;F8I#{V20>Vc6k~?hmr_%?o?ZO@xJw%ll59vdrkHG2%hXQg zT5@IS$Y;tRv;c>4M6+=(0taTnkc2!!8-be-BosS3Y#Px2%k~;#c(uipbUI-Np_lMB z;p>DS5-#l4(%WVo&`(&;bH|e6SKn;i$+VQrFH;1Wp-XVJ`5mCm`mp&)^YiATW*n+m zVeX~NCE02MqiTK*!ft?mEcpzKBNmOA)-7C=9s$IDl`@p_9yZ6d7nt=VKwpv4i*eUd zO%!eV@zitFD2{S{-Gfpy9e}T(sf&Vs>|hDIoLWfkgs{dYJCFQnF%YcwGC+UB z^fv6;DEwVG1IT#$(Xe4H*(?wF$sj8^*~i$O)HLe2`hnCVa>sxTi#L)+^}ggo=%#+i zHpo#w#7>d&#}(41R4Fw=x1lG%j`~9Jhin3r^R4N50zeSRg9k8%=bRKag2#_)(+M(l9&>N|*?8*azBA5-pmUdvlM0(X^A~HpCB^pb9>QiTR50 zNh}J~@F)jZIhLe}ms*wb;rrB8mJI9XAJD%Bw=PzI)glFZ`X=fh8_*5v5ESr`_iG`X zwRr&jaZ{9Tfeq}|LV}vYxyN|Qh;x`{-PE~z0rW?}D+aU<#2a^!S#V*BtcqMntr0E4 zMelmTSdtyAzk9JD(rkjX05O@R>k(19Pm;(^CcjS${MVeO+X#gKNKdM(OWELU1R0d{ zDN`S_VJiUoPQzX*G6y+~=K%T+>mE`(T^xcjpgr2_gqI0CPo;GeGU>sa!PIqx&j>Bd zyNYLoO%}HW@m{86cQPzEgcz=YwdRC8OSgo=>7kOwhreGxu`lb+3F@lhSCyL2w<^c} z`N?nvMxWnFJ;>1)f6=UrR$hQlJ)n#{*uq*XcVAZ_MUj<)>A^p#J!vOCM8WCBAT~28TTnZ~Bno3F>3>3`-5DuYm@%jsc4O(!j7&gPcO6 zoI(VgJYsvw_JR$&V!yHt+1^7!@3yV5;k{<4Qyla&Y|%TI1QFY3ppFMlU&%plAyg9f zQ1;wLI10duq@+u#3@Pa~lNIxHOXKjLF+MfQtL8Mz=T9l`411^{=RiXlM67~Sgq5Y5 z-9#QB@#PWjBFF$i>?=Sd($T~n25l=r5MJbs#{p5hqd$wX@=L~QG6Y9*Vt^8ROZ^_` zbIFeW0DZ%X*2S)!We>VYG{*_^$m;6=`e4dg3bC~?l=aSxWsDRVq|y8Y&625vZ3KA^ z;bppw_YtPi?In%Oy)^AQsAcUZ93f222OJ{o3IVnQ^uh319FG+7*34rY1_^7~5NVNh zrYvJa&N8EmE#OYBz9OTSO*+90*#=oXYu5MY9_EJAVb*hiu!EJI4RfdI3xkIddttbY z81aeyr6M|$Jj1n@jSU1_F0Uz{*%~Msf63NJb5>oMKf5fFl~-4plam~|VqHha+Dj{n zE?IxsmAB6f-qGY8bIr`@3!40jui@(HQ&w_jsihx=Y)ivl(r558U}mM+Bdr^01xaH^ zIxO<2x-FpV;)2(LUWZi7Cr1#iy=>FUe3;;ZXJ*3=sLrj!A};gR;p< zmX3nmoMieM^zFvo)EYe;V!4OT&>qbTW*d#B(>8NNH$zVr($0|ujM_L~E<)dtv`0D_ z_`Z)EyN4k6qx)C{C!87jDokVkk75G})I4pxm*B+7t`OhR~( zmyZK*Je`t8TgzRkqB40-uPD;*#W)w?F!ZQibx}NH5qPKwV@zv<;fd+kKI+Bme8D?F z3=ZjzU;rEA{h4u=YKKf49b^L_2?qdr%ze;} zcP?immk>OJV*owuX~f2DTe>e)9BK+N7-)HDeP~lC33>j4l7i-fX$9Q{D++oGHWwse zN{aE~aY9!m-~{1V4a8t)&9a(xHIQOwaV4}4w)mLw44NA2Gm<=Ti%LaYy&ckr<$9$e*Pm>1)oMVf-JuA4?yc~q^)y?)56c;oVbQE+I zEH7AJu!+rf9yc z3jFounc3BKzT7&cvS+@UTWa!TdQED$dQwS7(bT43*~D3)ve^@Ysyg-?E!Rvf_BYR; zc=^f}Z|)zrJnjmXs){-}xu8C5Dx0-t=G9;82o%g-Oa5*Ge-D7a?IKgj(TsLbq(D4R zTz!WQ4=GI@zD)w>ww3ZakEy@~@r_iEW|dz$&>A_iy9o0DG(WJEVeuouhT#LD0RkaU z=Lc*c*aGf^P`F6@NCUy9Q7EJ;RQvG34$Z1a@sP&oO6C%w?L=Ppz zHbRW>U24Wp5TtzAPEBMpeQ}H)6PjD)Z30V3NQeCt1$zk(6Z-Hx1OUu4#6LSjhJ*}| zlh?HW#zh&yNY2(-TYB5udndIxa;oyxRoBePs;|tq48Nl|M}>e7AsHBMd^z`Hj9dQa_shUEC_@Wh!W z&aI4*`|3*fuu}hpN{_O>cL;BwQhj5=wgMC-YxJQ;eR*U(>p6~kv{)@*H^Gyr3Lc5L zOG2_Wj7kzph_N8}p23BMIh^2WkMeA}Nl~2>sw&6X^IEDZTMF#H+F6ag(@RVS@2tk` zNWLpIx3QvnLUDQy;(}_gR0~_wR6}-tL!l>-o9A>EmPT>{6KVr+pEx9E#eY*2TXDA0IcvRsog;x6?@(wH>99&;T+#rEY24; zxUm}3g=R=N1Hb}#N_2mFzq-2h^HdEi{9E2>%6~EV<(372yzPJbJK zOFPcLYHei0C_%c(1EZ-m3@y6g7QM(nkRZ_h6fi%WDH+n5I7^-mL!;J8pnd3TJsTmc z^|juOUd)-KEI+1J@6Fmwhf;6$=4@(dXD+;TCXMg&)n3nL%6T6ML+|x&=KDUrx;|?Y zUtOQQ39mvD&|#B~4LdK+MWolp9SRWIHM13~>ME$t=APT6tfuLe71Qf;)K#j{ZX52a zYc9-CRY!PCgR*V-x^b5`WoI|cqVb4tfq$m_0W)P*R6m?HKCP9rb2n$F4Zs~axeq6| z<+#jgK0v>MG2BB&KTb%(cXepZ!B4t^;<^byn?sW-Q<%nsg{LC$2)>y!jcnKi;I(<+ zD-6IyAUrLam)MkB0Q&3dpSaa0Z9Xbxa+9!&f+D^ntsgO+;0pVt6H`Ld`Q{ty+juiB zYo+Cu&D@#lRm}a2=?Zlm($Xw5g#6PU-#+EH0YtY4l|Ov`O^g!0v#y*2eWfU$__1Y& zQR0-#Sbq%Aj>L#asfXZy_`iS#i7=9oMz;^K$4J77*A2&z?zfcCdn7$YgUG;8@SGYV z?y+LTc!KFTj>qT?=BZ{Fj~;Uo{3&D>e0!k;D}%lwsh6r_C)0}+cel?+Lbnp;t|3z0Pm&@=+jcVVH4;FQjXx~E2be~hoe8EgRfnI!P0Iee1pUG zL-kn>;V+nBh#TuTjfm0_dV_g_RW5x8)Cz>Y^EUW)@YwI6=WTk68=hX z5^4#H2?ow*h%lL#w-8*syqBrB0FpLfwPR}!i|~X=*Ls#Tk6oN~-3?%};rYtC;XY;e z=ig*#66l3qlQ+OsHnq+VkCQL%RD)-2jkbZ~4`+xxI=_r+LNP$!Wr)%7a4R!j2Sjn= z*_w!thCl6h#&@X)A0>M=0(6hD2pQzhUJh6>fWwScxR)$ZqBJv>i=SZ9mIF8u;HE~5 zQH)=IIitdcM;;~$2%0)iIy#(moOA>d?InpGwY)_VEkas*dz3^^Q=cgYo$7vb30-_m z$Y`@}G;cHSGRNTh(_ZEiZvf!N1wF$2;^cpdF^tpLMOO6%RtIOGFD7#`7x~Scv3Cf! z5uOL=-KG^LxD;gc1*Hd0SxX08%yy7IwgwXSTEbEevplLJ3Lgc5?4Z63?iKLHAyfT6G@gu^yo<@TwM_Rrq3apse| zXM7zZ>DA$1{Qd9vz--N*L1)>ZvlEa@N#f~eO{OFx4l7|A;rruQ-p(E#0O;NLSSZXZ z3T^u5H8p9}GlwD38G?`I`bk;S2uBEO0Tkh1Ar=x-hA*jc0=^K)hd7$c$co2F#>Y{F z(B9zaKBPWDIU!~5QalhBw1`E?p0jhy^!}M(q1Tkk;l7VQ=9)yW*Q-+6=3_4otGR(? zt^xtY#j3WE9J9=@jxz@CS)(@_rom06TMd4CtGc-0Fj%0?8V?3JZ2(#FC>%wTWq|R8 zQa)Rzz2FysORy4Ky5u~=VJm+uJTK9{RTXrY@n-K>!jS-N4Z0u z(X6~&hg9rfGQH=J=DTo38cxD3Y%3@{E{PoyB{*KWd-xTl$dYauUaX86eob9fJuJ+V zs}=qal*HFZb}Rp(J_@a@l0zV)I>Dp;Mn<3^euFzR(iB3Bp*(p8$4T5j%&iO5@O35k z4=0EJTYa?U^E;ba;uq)HujG!8{M5x)9A%I7Dm=^{_ZnU}%pO~7;Bj{J=c426O1vTR z%qtpFg*auUQF(6c@WHXEIqHw7TH^nXv0GUqdjj&qX@3ehgnYv$LtiKcsaCK-=#kuB zV$>vp;;=i*4kO|Q!6Ck0X7OV`_EddjrcV>h z#6=b%NI};=TvuP(1ZMLUOFPL62 z{m%5R$<%|ziCa@WJ3W2%i*8g_DPqL`%roduXe6q1I``O~RbGcDt^&kpqOFcEC$7=SBEm5T&I zBDExZ0|FeQqjF9!KPUjk_T#&b2p6O-pNky$YH_TO{Bj86sl7z;CeIMXn8Mji0C#Vi zQ>Sq!rxa=J2)EFlBs@ZRfiPHrhmIAVDa1qPiji@ygaXdZLZ2hZ;$<)r10ggYOKt+_ z#i>m!nYCy!6s2!>?B>S>Bv2UvSkI@8J0XqID_J~L4dP?4uJG8BKI0=<+qG1 z_}FJr{3M68^coxL=Z{-@`J&0w<`*;L)t&g3b_I5R(tMclJbI;D z5o@o%?;AmgqHg!)`5VmwC+c%mu7; zMvR#q(UO7q^h=v75#uZcYJwJ=a2GfewBW^smrfe9RemN@R_SrdCK3k{HBhFGqg5kBi-X?IAv=&*TgO-F{ZfGovO)d9ubA*Ib*xVj-Nj+w$HQ8b> zYO9{Vupl>ga_N|`k20-^^QpWhLQ1vf&cx9E!yQIw0F{@EWTwqdOSwVO)dz za=V}LBA7UQlFEfI*1_YX54cX@$R%0#1eHpxj8HHz4|=D489k=^?1%WnPhQ~XxbqwX zq}xMy>MTHL$N82#7}&*ES8xjF!DXn&><96pwv6e~w?~hvA7eDwS;85X!@}TWX`q)S z&T2AN)_YOR$B|kScJ4Fs$L7=*`+TKiLQ`r=CoitPY+Qc+xGQQJx|KV|8Z0Rp_H188 zYZ%8Xvzn?q3femBYP(ts@YQadiGW}3MVuta!kMU2&FsSb%%Lf`mF+)8co6_Tk^6jD zj#kkhmq*|@X>;JRqi-!2%!IEM6_3tFVlkJpR5~ycQ}czY0x6r=AJ>FmZi%PZ>1pc^ zVlLoKOPq!x1@8dpz3H3jJoCx@3BqjzAKhA;2=wm9{TQ3PJLt#grB7pBRv-NsgL!8W zVu!O(|5BXZo3WW&QF3QNo`UK_F)?~lws}D_(wDN4ZnAasio}bFZxK52@tC4|e5&({ zNIVZ&C?ONEF(rd`%*xG|BrB#4qi1HgXi{x%e&gg&)s&aYCbrr0bA4u;In`y)$VXbf`>Kn!b%vuun4Y#oYY%=vneVtF)0UxPExDe zXadOksGIBjx)?GB$&;t0+@$~=-KQL6#^A*jY-R<0tia8(B{3Xk1-*n507ZU7#B2#N zwgw+?OAv&mw(i1#X+y!}+B`)WenHJCZ^&wo6pvY2bJ>_cuzBXy|5W%nh{#Okjm-K> zo08I#s^A5!4NuK$>24l#<+#9q87(G%MbI?~^0XB~^-t7mukd&SwqVKDgyTmk7cQg#?vkeO{K%6xmjQ7Q-))zsEBoG86 zjrt(@?N0r$2#;ZzaXMHe9b=2o&7UkNvZJV-qaaQdF^|9884x=~6o{!Xw=>x53csqbjr z(~8lUB+Jz<>72mg$2t0EC$!8NSf^$r*hhZ&Fmcg@J5Bry-wa2zU`T5%AbS#?p^9cN zP;QcI)eOuoX2mt5fJNg-O%|?l3TDW5%b#eIBU*`bLU7`1rz%kZpr^kFc3x{`4%*<;n%Lgf1Fc6|A?J3q;_*rGQkxw8mrD(1bnj5#VcP>&hrYwUhl|%iY}3cQ z!EmrK2!nNB@DR@yd-L)BK7bysYQ$kIt*9CqQwfcPPJr&M591)Twyz%P!TPgIH#VTK z;xSEQI>w+C9b@rm389;SNISR*Cm)%N%6%Qh9e93!2lAVy0rnGOGXaO@0?q=2z61Y* z5Inriv?age0U8MnY<8HsS~Z;RZA!}dyid4XOY|7cNM(D1vXjqxu?$vyE5x$*Ei0t z^3N!&3lwBW#swyAZ1#rhbH>e4OUg~jrlJ<*ZhL{tRhWgM_?zuW#dIm2P-&pK%x}wc zr#lVld8NLr+ORi0H|%MMILph*+!G7)$Cmqt+X6+dtn{Sv!mL~capnsCpEg42hyIa+ zINuEJp9E;`KF+O^7m=b2%7H9{b6KAIn8RZrj}u1E! z#d4^;TT^%@foJTo@iG9-rQZwo$j;%X7@_p($CJ+?jtifxmgfkM;gCw3)teShYfNkB zft9ngDco2j@B~hL9JC+9XB}fX3@rTt=4Rh+w)-!Fs10uEBR0_Y~i@mGGm3%b}vC!*JAAHcS4vkJSz z9RqUjb3_SW2o`S^~Y6kZT$a`AwP5|x0JLtE2>)!fQd%Wu-pxM6Z$z#c!oJ+ zB(O>Xv0w$H@Q`0EJCrtW!(pvpqIi~X-BFp}J|$4+dn!3$NCp}rT5>75^DS5GYJs*Au4l;QUH zE5I>*~U##zV@L#*ApLXaO_0vNSy@7I+P#8V}Kd? z8$0QE-!a0k|H)wBe+dD8*7i#}%4G=fWcr)eQ}x{A^(uxQCOw}V5#S!Zv^LyM3z(;d01pPillS_umE@R3AXQlpJ^2?0OJk8lg zd58htOyYYOF#09d*i$Jlq`bmV;M?w)>O&!5PLKK!e`J~@s) zB+!v_kZKarGfF*a0xap^v;fpGl=IR!QzW!QZ?p)sU3429t3QcoR0g6!7F8?_0>KYs zrKmnjlAg2-oP|uHh8$UHM>b>G-b#o(XY%F{kU46>1PBOy$`rjZfvFm6K*V7+gHV(q zu1Vntc!KlHJ>J8S6bV7M;Yhv5{4g!6Pn&VfC{G;k z#<4QQIi4M1wu&opn{^MBd!HvU>H<(bwm3tbAI7mxS;D3tBk&MB&-PcE*Q3ojnZ-nJ zU2OkBf*8Tw1cL;R6Fg7Q1EB7#-X?korOmPi(qO^HR0j=K65 zqctDNHp`2QHd~c7=&oMu3Hn>4$(BGUQQr_>+%f%E(vncjW$=WXTrkHh=uPx?P9rfe zs@@?36jp*y_bZVznc0Fhp9*47I{#q_z;P1SxS21}*9s#J@5_%->CTzrvW5r~$;7W? zR;*&6W-tL>Coc#l0NQVSt#Gy+#xxX1FvyIDcEF`S!lXX#X8!zC?R% zEy`mtO+S5Iq<=$}*j#?~KqNM>y0i1%f%va7i(CEv)`d-}MQuS}%OcFfyqjyFZTvS> zl#5F(N+tDcH)b?wcKW-~!HpU;7ls-(^f2-JI)X6*dU~)(&lY6`0JSO}x^<8#)@DTT zx8)fT*tUEkgnDuxSg4K8cMk6H)kxD7KmQa4hK^Ql1_k z$90=|565-3#(6ifgO6Yv0Mg9MLh84*alfMW?h`5qX2k6ETN^l;dB-tO!#h zrbyA%i0qmMvxsO%4i9jL45TT!`un*Gwgag9Di47RP%l(oBQqfQsC{Idc0d?WFW9e9 zJQp^A?T)>qa)&_Wl$CVe-vFR1$5gSw;`YkDl?RzTUXymz?NxgzEN`>#K`ZJx`xQ3! zG#i*POsHF3yQ%4BV-f@7<|sdXUNJ9X1F`6Zv~|gd=eA68u(Lj#8*REfW%_ckHHzT! zY;EttCDQK2A3pVVq9t0mH4$mkI0uYYJXfd4qsX!jLVoi^ zA6zDT?(16G7OAT7Ao*)wCO9fhu5Rn>7__@>=1}LN*qi+7Ug+eH;8IeUh0VH+6D-x;sg^gahnYr>3Cqoa^z5Tt3=&3*AzAJ(e8`sV9m_8Hk zu*$J!EV$9;HO(8FF-2>dH4*1L`PC!^npFfMUpNz0YiZ7zV6%ud1P7qup_$q-P+9xGX;D_1i z=t=oTM)cMipUq^fL=L=Q%w;v$JoRy}zq!%F)j4$YJ?VS$3h1A&Dm6Z?P9STV&UDyn zx@%z1mG{Z2n_dLzk^2^xPOMwBE%0Am60^i>^d(hPdT;qb{g1P zynReyi`f7rLx};eX3jRb6 z^?snP{vM1i)%*7&O-s18HSZl99a*HWFn;C_<;7Nut>Ux&Ywl=Ul<+k5cCPw#Z1d87 zjNk%TM31AEY=iFCijA>#H&A97FSV1oeUl&yKn|CFQ+67$Z*XmH<`KZ!u~LLlxqi+Z zL^iX#N%qTmPPiKx1|x}F&eZ`%6+md@<|g46*}3;{Gt%2kMC%p(wW->CEf(`pY&PWt z0X@cxEcw_=-}hrw@vBU$j`2HdxlHDD?n7tFPZs@ksk%HLqFsQNXxK90Mhpr<6Ivoy zP8>Ke;t)$M>K--RhVtW*cUem`-{O-dZ#MVG9I`v!*YvyTb-o&tvnra%1iDr*m;>DI zhp;hE>YP%gVx`1*gAyaXu+=n5`C_q!am*2gmq5X8G17yu*EotIa2t&#{7QNrq%{3o z9<3voA{ZkuYcX1&@(AcC*p1cR>O^%<^-wj9RHiL-dUH&vXC0SGa7ik8#W|&1aAJT2 zou4y7GjoDfiutG(?%bEj51k`;1q~>Zd{p^oo__~G{WtSZ$vpj6^S8-mJZO||G-!Vq?a^}>?l{{MuL^ImgNUDrQ0nienN-OQE82|QNl=$ zQp5MR#GlC61C0hxGXxt63cP04k;%~tHTksT3ndf+Esv<1b^)u9CUb~>p3B(4Jn>GIb~UHNj~c8rfS&bVh64$& z1n_g@|8 zd0s&$iu9~M1lpyp^si@Tt=+V01war1^PZ+TrRbwiv4V&~w-U7t6(WG=IwKwCESx z6TT&PuUIHeR>0g`Ax}?8OQ!#R_2-tg2keji>~m6T`aD)b7R%ubRzj8hDMfDro|@8M zB8Rh%Eb?yv3YJQJP@mTK>EWMvFL~x&{3%Q@Mo_>tI>o`+lR201>~|px7k^Z7vEmn` z1kY5wz>Dh{bM_Q)(0$^e024WYO~rWHiGV_CfqF|tr)mi=-{ z&dVdRVN1cjRi?%GaH&|O2@BT5oRbC14)Z=UllP+CmoYiTNi$hXAT`SHg({QTXHJ@P z=3%n|#LX<@8FHXdQ9f;ao+`?XbgcLd#G?Wnh=V8=-e+8DG$3}vxSKz#_@(%L5Mt7tn9FHGe`d^RU^`&ih z{na;@Z<8kfkDn{b)&Dp~+~kF(|23@0nDo`}I1Mp)9m7fr=V4e$$719_lmK!5qq;AU zo(d1-UKCEjzG5sEQ>-aXnEm3YX^m;437qNxP>C`M?m#ieL?SR2?wV2(Bn4ZE`$u_n zjz>_j0yz_W89>DLy$ksjV?2uqN&5(>>A#MD>Ph|WR(5PrsEoHNpAku!xdI(iRW zLuH>v6X547to0Yw&Hi1)STO3Br1WjLsbHZd>YVus7vsZ3IlHxd@!NR3!MzPqf_lb# zo`F5rz`+z>ZG5BgI;<7C5-CxBz|nu&{Ji-ktYCG$c`J#@2e_zO%mHAc;ttn7*CAGi zc@#~G`a;D=-CuBj)eU3Bt6uU;`0ZTd@6j0$8WTNYM6QuGEm>8r-@2wk-o47|Ff6lp z?0@X?FGHMHLSG@7t?ugj78uHoh2bF&Of>fE==?x%QEK``$KqVFpts5vi#e8U#O%{M z`=2rU)zUo8J6nV>iVO%0(^0<96}hzXUgkRJr^;kGmte3m%?rOFhNed|_X<3Lx55P& zU+kxlAJBtK)=-+#L^PHs@){;!B6;PX0jT{J3@Q(*rW7ynu@Jp4^5};EYO*Rvo5j1_ zUY0~vPt_3W!Txt#x651jmOm8O3kXUj*X?)tK{GDe5J5{W+VA5txFi1)T`DqF!b@~x zKEy7(K=56HUjXQoN7%$Zf|vO1!X9!2M|1qPhouLnuS<6NZEu!pk>_Kweflu{w%2gK zb>IAybWr}Hu2J{A@Y!Xtgc1#`Ly2}qaM0C6@zhX0CVz!2HyWN2!K~#NOTn^J&tbHQ zTyVy$Nbm+W775-Ik5N1g-W|0tC}h7}{VJ4zMH=bP!^1$iMl(HA0q9g#GQkkjh_74) zD4vK+MlSFs8t-!~l?$F6Hm_t?Cm8ldkIxO$xd|>=JcBFUvlZEl+tr$tivxG9l~>)P z?_b;*Yr8#^cRaMHHQ&)Y@^`(D4sD9p?Yw(QSKj1n#wc94xlyWRJG}PPPYe)=X zRGOqE(nV3saUZ3T*Vl81M+-uLZWW18rBp#kkg>T zRYIDLRdPl?FJFb@dhxWKDk~tfynBR75>dfZltjBqL5>vzbj4TX*X6fxx9XFVe0tJO zrP-~A4pG%29{MWvEqTufg~WZHLzD`yp$S(~vwA=TFD2m<{+ai6_(vO~?RFGwO$1u2 z!;P_;#x`3#-Xg7xBs+YzL^zVDX$;r{cINg~ApvIOzeIMG2Hh92evqCU0h2rBC*@}m zqyfc~I%U2@guD*iJ_|HUFN4~Ft~(E#6eg{U`Xqx3RT~(Q|o?E_v5;s)fr06 ztWa~6O>pI06HsQMimS4TCe|Ck5U}TC-NMFB`;D--yJ&Go;VW>CBCX^rP9!al$NT}m zuTGW?H63oiHeZZ*(c%esnmqa~ z>M74zPQzQc2$oXu)2=c>0Im_6K{1K;7-0fhYSpgUJVLzyf{gN-ZgGNK_d=!!X~i(Y z+F3-LjiG88Op7{ZPY+#GPSQ57L*8VeT|iPXCev1y1JHvkf`tjg5j`HEY7ice>XhRW z#6X@vQ4a_<0MYwlAtfBAzWXNxuMvoPX;&!@h{_djh$A5wKuA{J08r1=pJ$5Q<3xAI z2v(8b5&QZGx9_SHH}|W=@4|>K-tYz+{}+NQ^ke+U8_u%v(*$Rk;^j2KYP6~zNls9o z#wL|BX`lrl1Cxn0>!FEC>V;cl6s74(mFo2_8$!OlQvG7HRC#+-b45jcOY5?HY~cp8 zz1OyEO{DLxj?PTDE9uF}n^88@beDZWuijM=wNC%HeEaZb(-zMke=>X5Kti7WtaPs& zZ0?T^-4860y!k8XEMlwB?9DI~-%3Q)8W3r90P#a}5p81B*7V zOuHgDiIn-Z6i!k+nMc(rAW^bnoflzS)+{kIea=zg7@p;f1;9zeMJmDI|4NBAGlkS> zV;xN9FxD*=#U3)t+qfN$02HbYgqRHUbm&|NoBd!ft_KK?5gh8{bZ;XgzLg7QYxyyC zZ|EQsh#tp!RgM9ulc5W^pziNI+>7fzKJCNP$^if^bYF8S_kk{A_X}0^EC+LzJX@d# z5$H;So&qf_K-N*|zcrf;)&8g_8FrZ;T4{}$YN{(!t*wrDW3ao^*4o|WX&w&xf;Lk{ z)V`?8#1!XC<#{=?!|1X#WW#|}Z@%faK1s6Lt#w^#o70x)t+FD&TyAlEL2qM2)8cFp z_+yFg+o=0v2X1Vy=w$i^V66tN<_roA0zt^y36LNpKx37t)L|rhhG<5f6h|zpEsr2g zF$Hv@0__$IIr6JHv=gyX;Lj_T4ZUN5PqY(=_Sm$jnwUVHYAiLR2tbIE>!Ko8h=>oP z_GcK<+?e)ORL9(cTp;4t4RlahN#7Lh-6KHPiq$2MP^kmjNvQ+kL|Fw-DrLQva8Yzc zyGL|IX%H=w1V%0rrDQ~bJtH+Ttb?TbbV-Uh3f~-jdu~neR zuXL4hxo60_oFG8ju`S95nu1@V_;#3rspYikoau_`J=8N+@bDJ3$<&JsVn`=X2PjSA zc#kqifS*+fpr*}zR9uMkC#SfUCkPPCj1K}(2dnR?#_#KCrKk9$9;@G$rWkb9`@R=VjiQ_de)Q3dkn@2vKSSloA%YVC#S6Y`z7Od1kK*=Q)MNe= z)Y`mCygbTO@EZwG8D)#Qrha2RKI$mUVCsp6N#v{26{;q5r*-FaS9I@T=%MApy}bl! zf?9%85?XqfU;;orCtbme6rjQLODQRjNh)eu2Xx>bPR7^Ij){ zVn^L;XsmmbGj!B*+;fIAwA%BCm?5Lr>rHrjymM!$U@`ilp%rCG zEZ@|TP3L3zhWcDA=Wg|Pq;s*n&1SRzprOf4r`eM8tn`a$zP>IO&80g!n()VNYsg1? z-K{=g^}Q}a>Lrv{37}QQRss;3eyUUz z*)N14@M_?2zCh;Y0s+GYMKV470KE`QlT||f2=)VwxOaE>+{w?_${vnwBw^GIQaZm3+{?nh%5A=F~ z^>0a8CS4jXWuly!D0eB-HwPUAaYo!I{48-o(=0q#HNne;7-0xs_$PmD`Y)yzN%x_> zg*RVC%<*%&f^NC|n&R#PC-H0-I{F%cu1jPP6Sh<3BFFu^1R}t!SNp9uOFtqd;O-)A z4`j!>9OFxH!53J93ra-0E0P^+L{-Q}Jp5yV?*P!)(hLC)CaBx+K(6;TKCn>xvvdiK zF1j&P(VzkdCG*A?kW)wMq1V`j7Xii=h_Eze;R4}W=2?hK3pKHCxM2YsyF83rCkTQB z!vxz1P7xdi7#ntsw}UtF4U05MAe@Z|31AmbvWrNR+$5uK4hAStnmS`RPfgx2YUVDJ zZ9GEoJas=q1ZN4TT~hWFU4EH6P*f*7%cCMKJ!b(_Uu_c6Rz+W3vMxu1&jdM55!H4r zjHBxj-k1cST&i4a1-MG%?Jym3p944qpzg~b%7d@*_owJ$f4(2r zPXMU?d8v80aAF=VTrL3QhR7?464z(=Q6dM^VSbe0iiMe3e3U4uExzmkzf36U58$Iz z8nf6WzwH9REz_5%{&AhW)^&aq6%n&O>KH%jBVRVkFWW&d!tXgc^HKZqI4$xs&hj&S z{YidT5uc&@<|X+_Z}Dr^<7>nxDLt56FmN#ZmeH7x(pxz|07W{>ZogXi86~fdKGfN`*lrNK>FB_|B zZ1t@XXRXg&8R%(~cW%a(eA#5N`1FMI05i3SZEC z0(B^1vO78eb(i5Otaq}ONWcC$3dFddqVY{?(Cj!OhN+>p2F4@c8BIjSNRqb9J~?G? zaML^5{ZBloulKm+ui9bZY;e0nb{^EjQ=N4%Y&w_pf5|nvI5N=ProV5jB|DZwoDY}w z13A1I07Z6Mgj~{)Ek4k&sbOaWwon!{4Swm$Q&i-x@UHW2rs`D`Mss)!Mof@sQ`xbOi%PU3g&jW@&8jP+>!KI|#K&%uc1lko34ns| zv@KLAnNh4KD#F>b5Hku@%LC=|Vc={+pu6KWxC0&_2nh&#+B^kF=gKb9oDRo$Z^b)f zDaZKY3gJ_>nj7atEfbrA`uEn2BAHb2MBQZF1z?9_KFs0@ICweyYWNKvl=XSVBZ-N` z=>$5JOW+&d1-2+sLOo6YihLRqdn|n-J(EGWXEJEuX!dyaOqMsb@us#D zZIf*{>*>PTk*TqFIftivPCKlpPZsG7kJUYB^70>d6BZIha z^&lDz3^omdAv%b?to9C#4&koR;Wfj!bZ99qjV@iYlus-hS;i-p@rh+k%iwIT%pJvi z-3UkVc-@)0^Bl!ocsRU@gEtXA9X`i{V&qihEVQD$?P zTv8H4ygoFHaU&K)gG)!2;<#xkkHx5|Bgx3?bdO8%A zJU^M?Q2KIL1tM!4PMfkGJ)uy~NKFB(8qFQ?yAAC3jm`A{gA^mR^OU78xYzq@-a zOJJ_;epD(%`tE3HzN0tN*mrv~eNKTfZqpq^ZTLS#hWRE`uluo5&6<@@x_~B5QoUnv zFTppT`` z135`YRtcI!>FQv1ycRbhoja?0L4eI%9BjzM^Di)&UHO`IB9Znejy0q%*UT?iD@=OrJ!eaq(ZyJ4r zq7_`a328y3!KDkrjU9In3=XvBbBhOh!p#nw-jU8X+9F|VV}tv5(%R{7NmuV|ZpzCG z1}fi(WEN!7^UQjwtHKU@c%;%Bt3A^LTC*71rGJo~LIpxA>MWvA0S&`UA|q2xFZgUI z7b=ji2i!IXNBA&7ps$+Ji8O5BMu~A@N`eyyXcbT|j)jI=3u;=9`B9&(ei6nB`X#|w z4W1gez=Q;7rRJxoIZo)e6e*{TqNGy}A`8Tor1s~71IZn`Qr{>Z6_qm4Z0v#fP8UWFY39mf+0U*CVx(Md8%sLIyKsB9tCHFcoq`E#l-j=Mld5SLY7@s5(Jmic@NL@Tu}g&|E|)L#6Ld^@_ZrMNu#KynjN z+mpQ1nG{s6Gplay+=UF8>Qv_?Cd$lqit9-SUkW1Chj+krvR|WBhjr*arFh(#qrm-!^I)`=xHKGG#XsKK zL@jTq9R{PS4%e>YSw1vE&0jE-4)F{W77rf;pQ?^TR!4XVIeU32hD%Fh_r`cBJ`%?> zfp}9KXQS~o_@jI!gBzaDyp+Msr*N#5cH0W>R^8uvxRqDQ>FyzzAlOPCehK z7}Vks+l1{jl@nrEbJSf3apipuYRP6Z;#tkH&3i}a-xu&UaVWjP1jlWtcIB*b%Y}wH zV8fwR957Ef9>yQiRJ^<=f;kzEthzOBYA}|bHDn|4)f}tG!GkDI6C5VkLoh*bgadb) zU^|AWP_?i1Q0uYQ6Rnf2V5PQmtd0`w1Ncb6yx*fqdXyUytUho=)RXJz?ute|(hL7% zGW6sp7v}2g3fTpVx`vmwul=79o#}5#v9@@i+5AP*7ysy6&CRQUY5qv=mUhU00D1($ zo0x_LSy?2N(zhr2N7K{tALM~mcSxTD2fq__-Xgl!X{!SV9|8wo3dAIl3W6wMPlt)A zoLQt_Ro^t-V5ES<1PlV?!sG%#HAor(42hUqs5W!DVV#J-tzaql;RDVZEfK&;}BZlxi~2gV1(_u6&N|KUX~Sj95zoFKrw32_<+cO1c8o#n%jXUwMigt z0k&kNG|+K-`35L%a9b5LBsq{y%oDXTQEFpanJRK@;IIFBV0?VVfZY1m^S}2!C1F&TMD}%c z*tm-RQOwt&)AF&egsxhF0v^^hTy))v6M=wh!d$@EAL;IaC6gsuF-N?-$#+Lrpf%>H zgd=k><18Ag4EpJ7wf!x1!9Xh1AJH3RIh|~FHlzcP-J$_^++`VPj`cNq-A%~Qp02P~ zV2n2Fek<*lzXad74{6zlV(cbxj)K5uuw%j$MKKc&{-jqCXS0b^v2i^5khA-FE8mt1c% zBm=^wsL$jFpN2`vh(BX37mF)e*0pSIVQoi@C$?k3vJ$m5=>GzZxNve2;e`w)RbLIf z0dGX*=aBj^)V#TBSkznFhEOXYtP#$n1$UMcp4{?Fhf+b?1{iOnsoUEj_5=q%*(1rd zZ83K^5Kaf0at$kcvq;Sx$z-~+O=g=JSp`}W$Q}@nb<1C3%7EI8+0Y*LH-&2!b{Sk1 zkwk5RMV71c>-8`jK+sRESH6h^^0)LRWz?SM^Ymw2Jhrj^A8lm|ro-j|s zX+V9!`Z9isyXmx`d9Mqlcp~X`o1$F{DugGtmfE=+1yCMK+3JnP+IVNUwZb_Vj}O?S z1$t!D)-Q6@MqRF0y|eJxpx;{EnQI9r;c?TurPr1px?^O1&CTgwrMts6S$0OcViw6l zyi&ONJxPUT$ElkSzmIVl8vzPu!^Lr<*b=~A)Xj*2m`TD0-3!#dZ1+XMay6;FeQd;^7bV_wdJ*v;> zutzbsE2s~gBG?2y4;r4W&XN2xRoXxA^!XYiet(2t@r|3yrCs2dUAnIz)R~Ae48Df5 zQvqff+zWktaAqr|6c<6nbnT;>w;ToyFH0e^Awwk6FA$Fl=;YU_51Ai>&xg99Y8$=C zyr{RPQ`eief;^V|^VE%1JIX&9K>TxXn$)_U%yI8Y!`X(aW}|aSZ-0MRAd?Te|GjDJiW03zZNI; z7xdSdZcQ9K)D6srMIRJ@PA_NoHI;6byuUin$BtXiU>g-rI47MKAiI{EIbL%H&A5bSp&YN+D(4!hY}K%!9yE9z zWdDW`0&D{59R4=>4#azUV)35tDIvBh>B06of9vAr3-x9!zvh8K@6pHgdYCJ_^h@-2>mP!nI+tJ-C0QYfBlUTOQ+U#uE`tBW?o|hD%OSCW z*HP{#G4`?Fj5*qoZmh8&y{+u20dv{pJ%D(UeBW*BVwqiE+|wXk*0mb zzS{nX9d7DXaYwgf&~cCBVF%pJH=?J&`5Ak^eVP3}`)6>652kTR1oB{@SK9j#ygvrm5V7oE3TKjV;()qc2Is(U4V#~t-Mx5?Y5|M$1ufj-Qm;pT+& zOEIGS^!Z`k#l}(LUFWVO~b|pJv4Ci`(KX+al1v+(CxPDXFJ-d zctPc=$_8^^MBiY32aj(u+86Km3AR7-XeK1;@rpjvq~E`7DOQ!O?J|`Q0MLE zq+ppY=Q1S^sI-+3&v;-{G^O2PdN`M@vFS;=T=?Y;4PiKqE(+{LK z(Gu_)R2E#gN_9HQ9=e4u8w}ad!g0T}i9fI-jrBlPcTwr<5d+%?YzM!x@f?2cb1+X{ z&VjBf1B>Rf72I18>zh>-)*G>^hD<9>>k)ua)S|a=z`)CmFe4Qikh#%|gGIi(e4qBg zu#}_QO;0VBU$7zF(1+z$T-1J7`={G+;8}=5w+p${2aWd_A7R zw7t}OulG^3t#r*a>1#+fz+#HF3+X~%L0j5Rv94iLEy?>}uOQvbh&PQ8Z?N`DvL(cu zIcWAyfnU9eI!C}AjJPAs{w1vlb*Qj~o%Jn|gt6Las5XS_!*wn7^=aw0G8)z}uzc3$ z3)OfVO%=(2I})^Yr7P?ew(5EpqSsQg6mU30iH45pp%R`ZUvTsPmWsk|nnfK#D=YVk z(8ZlF$0-d~I>y4;Kx9z^l?UTF<6Zm_$71>#3-4lO55&JQ1e~B?5>@`$sab4U*{j$A zVa7pENRT}kQDHw_tGrG7=?WZ;)n8Ns^%P>&Cjw7XqKrA{_^+ObO+xiZa{_|G@n)t@nU^7b%6Wnd5Yp81tyiIy zRL^IxX35pjg^B)Ehiu1eCv20#(TvTU0Z}RYjJ=l zngGsH2K*V-n=EOjypG<^b(${Ql{9q&sxmYCRymPhPwtd(qK*avZ-yV~O)qNoXB)hA zj)i(_tuI#Vtc$zTqkiF09chHLG2PXkquXTH;y{hBHJncSBH@@n(OvIN);Y5&=A!ZSA^`c`Es~PFF2{7k9R`f6P6x zU+Z*!2Yf<0Xri;su1i+H|HNzBKG>_9uJTL`!9JMCU$c5F0wK}c` zX2e1TOC@|eCLk^#6$gymN?Q~^TeP1YQ^l7YuQ*<3nlgszDk}+|CioV?e*!STw5SD^ z;;w2d%^b=kzJ~3?Ass%NSR4c|5S$@+mmmQ^SL0&9-Q?~?kd$Jx61^&?I1x2Y5pnGj zm$cm^a(`0DA)_%9#_pxRaB+D9jsNfdg4%Qv5J6^|YG(T?$Zwv1U9|#`_PlUxa zD9txSwng?t4n&SbCL+8x6k8cvAKMyZt+B(gA}R)|r{m|K)zYaBYnaN5U-2^r304B2 z2fo$5M||6TOz3>ncibmhhMi+WEz>$5s6A3UA$m1jx2kSK-L|?tbqDH>)J^<%dqs8q zBk}F=z43$bqw(W$^k6c60X=ZdlGa>FlM7`~qNsyXPO3?<&iE^5AmDWR{YzG_xcBEH zgQw;Vo{MH}fkv1X1GcREtDxHz47%LG4}bg1UrIYae7ZOxf3~6{S`+fyZ2nM9w3BjN z1@`aH;1y`sxpY5*b1UL%wJMCtDoVNQxpu+2z)$eGN}R7F2oqGr;b{q@(se(ds} z_7vW)+W45fdBMLFt}HlqOzxP50YTRUoyzO-W4bMkp==R~e`g3NW6wKx?xsQ}GWf~sOK85pi}Dp=wbL5i5{sV>DBDad3NRm!K(z{&7fP>hg%r142R&WEyV?wM^l8f~Qn!8nj&)xeZKw&i)J2e8 z-xx_o7q6S&|Ea-5Q?xPNZA{$KxPhv&n(zrhuTwbE=yk0!#=S0Th)(fn7eN6)qtDERkRfQP^WV$16&wy6Cf}ag!$H;q_o;Qqeh+12O`77{aVH`kxmHl1ls*~ zg696Y=wtItAN}AdMCR85o$y6}*-Jsm=iEQjzd2XgzjxR_vI5GRJ zA_>W}0JHAlYSiwDVz)#|VBQ3QQ3e21dt0atR{nqFg=a~2<_m6B(%qx`y7YI_d*D{z zq#w~3FgN^flqWGkP#=`jOlTP-s134!2*bC16V@xWh2_kCg3b#kPN)e%%}dqjL?#C< zX#-c(`_x-pBe+a+*Lwi!W%*tD;J=F(s?4th#Cy&B0d>|_E$>sw%RCIqdjL9>p(*@9 zdLMcWAmLNyIY_5ljbi!(fVa_@bx$U2^GJe*HuD7X_j+}l@Xu=SkTH&f)K&80F1R{ ztZOjN`GBSwr%o7wGwO{+ws9lU}xAanYOK4A} z68Lh#V+-?Jnc)@*`Y664jMEHJ6k*0G_`@5_^bb0Qh)+Bj(-}p zKk<|qXKG`-101B15NApfZ{%ztLFk-&0uvMl!o2jv>TnDyN>DhuIFO?Hq z#eIAhn6^|NM!Dj^h0ByN4iKCpIM1lfH3ZiPeonH>n&NoX&!f0-Jq9qrVfYz(qtcTW zKaFC=>qMNGGRjqSm8}8&W#dWVGsAk@yN^Z zS223(PvSr4ApQXTRf+&27rxI$YjUonhC#g|grAl?I2qrg*Hkk5ef5n$O0)*MZuBJ< z+>xyBuj}aQUli{DL}x>Pu(jubAI4M5?vSP6gNy!fv9vQ5FfRYg`@gU(d14%`{isa`a}B)d29g*Mdoq*+vJp;oT_p-F>Me>Mu~3}g2y_;8Q}s?T zUuY9lk=(%#eeEZ^%Xvj4$b} zmNnGG#0FYxzbPI6cV~Ud=WEicndgw9aZ3IMs+s?Z;+)AhHh?`$)6Ih%&pb}wOc8upSIn)3H`6cr7F&Mk0Acm6^ z#2Ce&5A(XeS+t1N_7#(-p{I+|XK=G*mxc`hFR?!RoYmA#b zNX)d4;40D6?ymh^5cD;k#``~M^(b2n06@tOUBsmSf**r-9hy0HPyGR6m}^8Q`?{Ej znh_a7J~uIIL8%D2@EXQMgVPbY5?kT61!2IMd+6@?qW1c9yskCutm{~m>}!oSWIRn_ zm+V6Ax`tRyyuJnnECRLZ2D^0RkH1jgR)}UsT$aXcZ>VXot3H(Xdmy8*cH&5IHCk(j%6IEFR#OJ(flm>HPvva_ zT@SdB#U%`*-TzYge#wlU*Nj24AL+xbmjK3=@K(L968-okavEoJ^L0Z~QK^c6zK0^1 zn>QmjV8mBWl3>ImBD6Z59bbUe4Aqs+8sTDt5ylW_5ZhQ>c(b^x=*>drKM*HLXXJbb zo`7m&pzJyG`x$i0ZZzf9EtYy6f58P^(%eN(U#C(c;jvLRn_i*H4~NQ?~g}f&C*}yBK7r=N7p7yZGA)Wbay-) zj{6gB{=rY^rC@t+=4r&FA>hIm@Kkr_P#x{l22XqMqIT$u^3WHtmS7Kjyb{zGy~bgH z(g-+}M_~cLJSa~Q6bLR6tRrZ)2yEA!RaS6D%bKI+Tbd)MW`lFWu@9LDX)AaGfT$Rm zdd3nCtP*N-pwq!a?a&;xr|9{-3M5onk6o>- z;?_PNy9&#VG6d35us@RCp5B{2nAReQOt|u3=JS~^XZ}3%t;}~a-_MxV7SCobXWm6T zmTJs+GYDZSsgTrj)mOl>D8qcQ;B1A=%lIbc5pt2@wWsm!Qu=rGZ0s^$JR)BFaQgA| z6X~bZ&!=BXzmn#Q*Jrk7c4ziy4rhv)Q+)Bc%$3Z0e6cCx!;968tvg^8nxi0MP7@SX zgy-6feh6#-Kl2iiB$dOFa~LonwzxRBo_&|x)?Ehy21htRXHi9Y^V>*N0h|2K8H^#Q8t z!{innkl3_7e&k-=>S`P{Pz#0F*;2&=`8jCSyX0EM8wPe*2Mvh&oOg@?6}xau zGGGAj6yow42rtJn9}6P~87^hLf}P4{mCph>BEO8Xz73!E7J=K#)G$g?+@ijae3@x- zf(SZM))3I&Qb{N2)*%#}bSQzo7igv>o8-lgHoH0yoW#pG zqZTK%pknl}2aO!B1fxcs1KNqRxpbV}Q7@#gQKjncpx=s;jElr42a=4D#Dsd-vwHy8 zo6HnKzm&}xw9z7NpGkW|yl~oy>nky!$_9eh$$I^iqQdJ0B3eK&Ior;cT_p$*>?5EqtMqPVD~Z`2f;gfZ6)!;#!BupmU@2oLaE=G@+S1G7v)MsV zH3s(1_UZSb;3~yT*!&@4O1eN6xv!I1zrQ`{_r^Q7Z>jCPy}kL4{%B+GXyT4`N4joT z%_A+ncebQI>+JBfENN?7+*IRjUYKcG+!mD0yZ(OOrw0?!ft8&dYZfKD5`zt~wz@>n z5s23}gI`>NeKjU{x)oxFRU!v(wel3d^dx}TGoqG<*oAj$yHLoLVNNHtV#+!IZTEcS zPV$vHn>vtLPHo!_aU0&L-NikqwMV?+S3{|63R0)gq3z^Ewxzf!XYME8soh^G@Jy(w zyl1ucxM#)hx{d4~^k>C^w&iUPAZ)axEz<)JeNK82uR|n>u3mRL%(zMcUkRp+?qdHa zI!144t?6mSb=u@Z*nA^5?25sBy#iUJo)DhiB9^9Sao zvtv%g_OSHG^uhDipsOZ`jbgI~YijE1olfcg#TVdV6Aae4YN!8!M*-OH(7)8plhTjC zfLjpDl98?})u^qiRZj)M$J&I$oh9Vooy# zKz+k}9cnqHvYPpX6_;Ol&fyzjr1EMfU{7IU4rwRw^$t&|P2pbnw!&u-ZnA1qq!)2W zN~35`86|gDV(X&fb?WQUx3C#CK4eas^qHK~NU}(@0wEGkGA=oHx+;TGwJYCMa4Z9GTKB@z4w&3BkSyh@{ZNM(XieBU6tr63O+?j&|Ofo6-x z%=AMCT6)HeAAej0Ac|UF=Fv8BN)`P!fKvGhQG!)H>$(h1y?DsO1V5B4L)Q?gr4-4P z2u}7CH~#?uo$?a)>khrZ~spC23yZj^fmUnsMa^7}B+&0r9ce&OgcX_p@jbc_iv9q<7xO2rlV&{6H zhbj&v8Ba;ZAc?h3{t+#T?7O0m_py)Sy%u#KwHz`FdIlOSs@=dB$%o8;Sw{b46gv}D zhsa^xASe|J825sohBKyNN=vc+5gk+;^}s6tD4jvup{?kd-~g&ML>-kf$rMsxnawV% zb|D3pG`E!Vl&g5XP;fwm)5;X7XDctyD5&TFiQy9~(#Hj~t!fW-P3O2eALp|166_&h ziFS3HV-FNhI#E$hORg#uU8Q!mvWc@*m)QiHD=kXfwT5XtYr**UVd|;Z(7cWucqWFsjS@m4a8=V8?8a41+hK%8!lZ2K6)P3%!G3dv zbXi6+W@MB9j{w|h;mIRmK^ftRV|>NDr%|DaQ-g!Y<43`KqhoOC@Q*Aw_b;o@LFD@4WJuJfM5;5HG*RV zG@2+qNU}8^FubGo21e;nw3@URo_1U_AINOhA_wFqxmO;Q*T@@X)0W~X`K)}I*+lc&Z*`geD1i+A?m@nB(fF#5aX#_AdoAB=P{fTKr+2>I7b{mee($M!b{e- z@j~i1{6c{Ne*ous=T+zXP)n+2rym)+bV`^F)c~lArBA>}q;?@^D@e|-aj9sKJW?Ef z_ab3Z!NM4bYt9e&xWyU34|gxCt#;^w?QmGZigCA#@o>WjR-{2lP64xlRZwnH&a|VXC&JTV zR8~U~XnYY35h;uC0-cm`OEcK<=CU$XB=0UGnkM|xM0Hb_SE#VMvf~w?t<4VMAp<`X zc%H``kWUElo=cIp`JS{E3=dhP7k6W!z>juQKer4ja8cEL4xr?`s4~eKrlIIRMU|>> zP5dB%pDl?%0$JK#O}vq~&h#Fm&=M*^fF@k3ZUIswLA`S7q1$wKT z1t=AJQeX1D!i;NPVrucO_xUb!!jE?;DA@npm0`S7z2m5^F?LHKFP^o-j#UoVGx9ZV1ljO$}`^Uq$8g_4(`X z{*-iU zB|V+QSWS?+Ul(>1R+)qy-3i($k`oB(*#obIABi_7#Xa%gP(J3GRvm$GfSO_OojUaIL-|?cjBD2|lAcy% zCsuzLXh=CpPypZ-MqwD3l9inho5;&iI|VGHsek5Qgnzc`=m>Yv!)J5Hu8yZVp6h^* zdN+Qc&yj{^<}C7=KnIf60@ih*ESiciw({~X*BgLCJ-JuZz7&!zmNK}d z>bb}jZlG&el*$_fSGgpA0-#fNSaHZVDmw@c5quRu-LBExtz`A~5G3%*;#T)=_kMb5 zZk>7eHNN&I1XuXlxA@w#x89w&LKEtFyi9UxWox>-%dWpnj_NhdD3iz^w#vxR6?Y@} z6;2jnjpG)ndkF&Ay+i5vKx?qRV^J)<@n_h9OLZ(W1beNUaQ9$8Xr zJxF`9TXKE)^;&ziHyLk@7uIxluUgQUaRgfz#A1uP!jAa7=1^0e&t~;GE5E;RrQg$T zH`%O?DtB$1JlX&6EpwV={{K5~8O%WfyZR#dVy~`Gx=ZoHH9=X<^}C56MDQ#C6wKo? z2-ivOgi9qMlhx0wg_}`Uz_yEYIqDE;AM*nCl{Rz++cs0CTEcI!yoV$BWhRAjS-nI% zivim;;}~~C6hy9O?C7zMEL`$o7*-l0!s((lBaAl08^Y1^$8Z%<-XaJ@xx1tLqKBf8 z%yz`~K})OdNbQ3#P~6_Mx9MOLc2@w(pn_$8%i)${%c&M{3fo%tw18_?8KTGSgqDg_ zAss{`qDggoY%g2dmfAy8h!+hMw>Ir=+Rx^ER3^QGEm)}9+OoSvYu5l*0YO$o(t2(@ zI{q2sqO{aU_Nb2u5V~0x2~JN3GDGuR4Gn&n7_4r4O~_W?BpD1N72eyDiN&1_jkzV! zwn67@x7}`OmbNF?uH0DdX>i5nB|2k1OI4L)|8%9l2AeX`(lGzN`2%ZuYcsKDx|bl+ zb*dY-ihgi0C*bEB)Ll|6^nhXEapg6#``I8^6=Xn1(G?4wS?EX#UzoBduXc?^l@Wb2 zg(@Pd!xsi!o>MV>%;!M%0X0;UrOqtiqsyy?*ylK|1u^x(GWr(AdvY%`&c5R9vz>j} z4WM!qUPB-$eBuzF4Cn;&;(Qwpr{GZv7OncnZ;((|t@H+wR)wk;?Z4?G1U}L)eQEj! zk^%WXdqKmi8tQ_nRMYb5$&x4V45{uc5LdO|yi@vnR6cA+ex_e3h8B(*{81E?SlgnE z@#rZ4m2wIglI2(kTAcnSh$_krp5jP^=hK1+0_ije>p2WMG4Ntp265gbb3>_=Tp8k2 z5>9ao0*k>-&Jr}sJ8356H%X(|Nf<#?g`%Sn&GpD4WW$K1=vk;ZQw(}hYQ!HV{|+(} zIA8NN4B<2+!M2WIvGIP*h`5_XT~xI_z@uCKem>%?Jp_~_g;=Vts@gCkkxqh;YKn|E zc(kIomQxNAx^iOH{#dh z2vpn0ZRMwmc`txY*+0{(Jv`dYZqS=i5xqLVqsQ2**9lgZ`=@LW*VvuY1Up2Z4!DlE zCS0do=Ui7@h&wzTJr}*gy}p<4^zog02zJZ|T`gJhBMo}+h?>mF<=0RAaW=5?-*nH@{|nhb_*RW~)T}h*0yTRKxj>8hT=N)=IocgD(19Q6y|@GAXTc{%Tt=Ns z*-7!`CV*;h4+$3ma;k}&cS}E!DO-<5}5$HmF(|3d1 z{5q_4yk61?+Y54BSagfE+U~S+L(dAgL?k1ib7F~-2t`YI{g+c0h~gvi6c;bT0hsy+ z6~H5`0sH90XQt0TzDb&#-qP16-GetRy7@clP3eca8tI5)t-&s)RZ|H86lvzX3Dc&i z^GLTl1l)|7rqu6PzfXBsM6krD{yApFBaiav8jnPU;3Yg|opSZd)<5U%5ggM>kAge_ zuD(YZr}P^hB?-E5I))Ok7tOz*>eWXXyt+zM{(6gwTQ8H6Z{X2cs&F-zcI9atvr#0A z-$yp`8G;{@mweN9gG$A};e{^{yiBl~z(-&=(dR)q#^wJmKq+PR$6%E?>Z=*;EK$si ztFg%}l(4^nN>i;g1(AlmoQ>U2EhiQ^-&JiEVRl8WF3vfA%YK5(1mgSb4sqkG{1v98^ato}iGzCEYd zDKEVVu}FEgBpWdn#zb##lFw%`DG-=wZ~*j_B4XxvxRobEaqGnRUxm0p8i+aqr?`Gh zW)apkfiB>(a09QNQXb*goFcGRGf4oNCs{z{U?C`Z+?)e$nhyG;IT1UZgVzP9X1A$3 zH+m1$h54_|f5$n$2D?g(E4WCv?pxon7;LOV z1eSta0=6X}G8h2DtC;@o{9q)I0-WXWj#!mhYq888mPI_pSWT@x{gWL!VV!Vf$DQzs zm5oB-4^Md$&dge7NJx7qjZ7kIcZeNTqvcTmegHoy@I&b<1)AV@I-~czS}N;JmA&fRaat?H)|%yw*xFHiu6C^UB&(jbA>LT5u1;tK{s}tF zM(Hz3z>3vHiEs;r_8g~KJBsp_bIqGst3 z87J!dFc2?M=JgUBCO8G4qD%{O5WWO8tI)M7r+IV^>}sLvX#MeeR-(CDkBS3TM;nee zoM|}UaJ2#DhLqR2*De!0&$eD65KZ^+s7R0`c%IFjB48?QQNj764ZqOva>J_)Z!}y- z!|{%8p%J3X9 z-4~sHP~LQBx+BoJJomvT?++}HE4Yi6fG-~dj~SC5P^#&>8HVndR4s-Xk*Aa}H}MK$ zs2Xh(AhrW*Jy>QAg$|@l9OpQuiIh%d<)F|MQaPwM#xTPw>tw=^hsZwH#o}fcebAsl zMy#G6Q-__^fT@edi~>u*SBDZ76aTA+%|((f)`vwFyHbHkaNex-fa{|4q{VBYTi6g% z;1v&Bik4Hz!&l`i?_c;sr*pAXRaN!O<&i#j zyel&O0dRz7bN&PDUSV^VDzJNPN+^TAXy$IQ$F+EpH15(OJHU16%wtIL!4fJntq_xF ztyJN6JA5V7P$moCA&A020gy{9H$Onk=5}c1nxy-cN@n2|A(^pCf$JeyKntypiO@;p zT!?A1oB{T&tYXqG!%-UY27)rNO`)#ScKRGqO(^8b+rEsG#ZE8B+C%L|Vo&i6ie?3M zr+J2Vgs{0q7y}k6V>PXg*?Kud+oMtyk-)hUr-B^RoHb_P#jJgmv-Su#>0W{z0O~pa z6)K#QsDm<-H5##ijHbH4Mw)nZoksyYU9hmJea=H%Y>%@MfdbaErQM$WKrE%gyQ;e)g}NO@Vn2-S$U&(-G+*XEAtd%F0ellhgNP#O~^emI-r#o zqQHp-M1d1#BnX_lKou2_RzxVxf$!y*i`=I|++>L|cn`Ar6i{3me^84GGN^JH--snq zJT09=85$70^%V6E6PyB2x5<0>+6i75qU3#w;4-NQQ*Yv@RlIPH;H(kg2=V3t;+QAc z4?$VZvNIbz+qeKGJf}%uu8;)mCCxkzpdJbwqtT6}kd=efjRXkx5%}pqyN}=?7s?5- zWUxj+b0nOLVmeoNBziup)9MjR>e*IN3%uu@*9H+3c}E_GxwxqbDhp$6Vhca1{Luz+fxzUwZz$RM7vvESG3r3N={Efv25Ykdcn3! zf4{bFd(JB7|9`)kTu`>>^!Gbx-g)Pn@B7~8y*$tRyw5eOqP1qr?b%rdPg$s7S+m8R z2O3BZlqto-F9!8X@$h}%sb5!mkXv{)sRx;JFE}&uSg=xHw|(=F>lIu*>Y$l;ul@$| zS9n8GCjw0i#G3l=i*OcxO|^^gX4CC9;pz$1?z&XF*s~YG?)NoqRNSDw5W_EPN~uE=4iL!nG8{$;a9j)_%jHeCzY)Q2&LdaLWLJ{WRsy3G zQSStvccvJG7JO+@c;3=UP#^JN-eeJBae{09NfsyPqj(2JynFG6#Tb*vm*B$D zWhh>SW;4O8CXLNxDw>}|Rsi^&hkg?JMd)`S@Dj$5C#3w&L*t?QLJx-?4?P>A8+cdy z`u1(@JKGt`x4UCQM}Nme2SWMA-k*k@&U3mk(IbR?A7MYl;xGx2>cB3-{w9loY1oev z;^$c85J#tBkG%z1b8KJjOfQ~f2ad4=dCh_5CU)TY=2Pr|J={9pdSC0qt&g`p+e&CZ zr9<07J45?IkA#kf5~@S1IyQAgI(DNI${3jjh8`7EXj)yA@@#{3vM$4>)xB4DYPs4v zxjZ;8eMd*YWboe9SQsqzWcV7ZkyAOdsG+N(;Z|Q261%wDYHL~?zU8$w%jY|@t5?(- zU9%%Y-e6g^(%>)_mAi`IN9`46PAGw^;rA7Ca&-HVC=DWa@tti z487GpgJ_7Dsv}wx&W_kT7c{BxwhMv`pIWD*)pZCJc%A-OH_ZRKajZMu{UUQ`obFB? zoK*VU)TX)u__ZR1Y-+nDvRz~%3C*}d$GF%9hKB{x0^w?ba3L!Z?Ip_;^4}%+aS?H( zxPLND@scuH?Z+Zq+V``_W6^~I1_ngJ*d|EY605wMyb^^7zIuWOClxRG6l?c`=*7M};rr}E4#96^;V1ZB7MCa`{wWL9n|17npM~nz z6RfRgzYZ;Zg8j;6mo~C!VzG2NiU5lE^~-NX>XDFjYiKO=SD}YMcS0E?G$%u6Lhpo_ zM{ib-Gmf?;+Fort+xBi7&%2vCBb~cD@9%uH6Qc6#JLNR`GS3orY@#pl73y9cf8ks( zJN5+bQEvBF#h$1J{zg_J@3_rZ;`F;cff7$`sLCjO<#PWt0ypI$wCfGV&Xopxme*l1r@IR>^XI$mCP#J=%$2K3vsboChrwHJb>+Ei z?yRf~Z>T=6)}L>j2~L4MTHk|nu}5PM=6;?laf)i?h;3dT#fYg>lD;Q%C&!+g+{qm= zXA5IJwuD-g<$@H&pa!R*?BAu-h4wL{9sn0Qrz<#r#+}Au zBkWjOjXlQA$gwbKQerGT2{G0rrF<&>4T`&BE)>L7`}stzJ!Jn35?ND-my_ISl|(hQ z(@tx;C{ayGun~M$`K)56g$*D?Sr8kuL8w=;OFERM3z=IX>&qkhg{&*G)@6mW#R7(AmD4dFlPUt zeMZ!4&R8k^nRExHQuMpRT1pyK0jdc*?9}j4&6El^jAMsuD&>p)2kd+CG*_+*1kq+y zr$h`Qj+=G_a(AhCI8Z)8h(UAXb2Pg6BZ|1ylgAW|*&gLnpPR47CpW2fr{N$)4gefh8!2 zY%yj8O_m_j6|yd<*44}`I1eTDWDOQX4X7ikwTe2bgl?ogA$!EU+kC(IQS+1L=gnrg zz>{wN3yVu2>an+2s65B#p@a+B2mHJI2mFWq%#DP-+Z`?+FTbz+;qu4JpDjOGey04L zaw`ZzS73c$TVQ7ZlOKP}^a0Kfc+$Mfe87Cze9U|T?WA0q&RH%&f*yO7uCC|Uf;;RV z_uuD#*#EfyS^r7@8UH(eyzv_CtPE@n3EX8H@wb1=1>}mnW!0F|hr#;?Ns)>Hu!v8{eD}r54f$)k*>p1T(f| z7$_*k{nc0gP5xYa8FXU(d%Cp#yNLgs6Q7!Q5ve)ju7EEnC|P^!E1NP9XxP|EU@ zULhMCST^YaCmXnetoOB5N!?=OFpZdgd71iaZ0=nqT;_7hiQ+wegA5pfh@Hxi`R_w%{0 z)9~vAAHI(d6VvhVBdEv5$@M?WV!h)3S@ffjmQuxpBbXyG&wvO5rMdufNu!%MNztaf zSdu1y8Z;Iy$})|4Gd zO7oKrtrWJ&_?h%~V7^Y%Kn8Zec9z-}=jd`(;xEofI-;hhe}+#$Y(>v#2#0cX8KIZw zD+Vo$zu|ZfQr`I2vz`J!2jL%nh@W-5OUW-obV32lNSA6*yh?JBS$6Ml3+vkb8y5vl z(wvo@lUKd$DX4{ST(qjjtA(yJrQ4ht87(X1=h54J@*`xGc^a~XJzQ`Pa^0I-hBRP}a(5D_uj)Vns+nv&#f(C(XXA)&&!o6@t>QGbiv;rlpn2;He!9YD_U ziF3T`T*f7AQ*JWo@a?70?S6N2S*WqF;Ks^zZQ8zh69(g-q6oSW-dur3VGG zu`y&wq9=26W)yh`X!m=U%8v%@%`;N8j~JZT<@&{h*e@7!=sBSxWtuja`b`t2lxqU7 zt+Z~m4p?_t4_FUdk6BMx)iuXP$AE(_Q->YY?Wk)i(mbta8ENH&GYtXeKedsSrj4cn z(=O8i(_s@6cwMWJZs!JPzjMOLNaasBpTi43kxpq=3{KfrfFJ-!Oq=I)=9OeEn2)%d znTWrseWRc(%g2D4zASzQ3f%4j{$VDi2fDpu*!P@b@uWi~!h`-hWz~{_?IMg&zk{MWl zm7hh5p5La@^n8t}dNB408I>K#!Q>J*Vdvm}vDa`A%GFp0#x0cbm|@cJl3~hlkulh7 zIi6;}P0o5l4nBwyv*C+*ww*z~y$8y!aH)J6(oS!@B@mfQO9Y4tJXu9{G7<;aG z#7;ekkd%1dGwFHBGv&GH!NApeLLNNt^(eCw*uOsLJ>tc*73voXF@DG@qEVL$>xS47 zh;d=8g@L?k{>rcVF6Z6Jfz5W7=H~}a&#F&Pt}9bb?tZKE$H{7$$sye)$jky z3D^6I_2GHZbJ}ykbD7<2_4Lf?W~?w%oxje|9J+x0b+>E=A5d$YfCXKKNkdQ`2c67iS+kE@Eib|&N|=aW5}+s&D2 zoatZe5T;B_7UP`3xkCgo6#^VH3a@9*Adg%Aoy9q5Fx z^dVbPn+gRWfStjZL9xle==t`Tt!i<@xsIbpJB}UG9{A_wAD!3cFP{a2TkL@)mu;3M z7v$i06GS`6_XqAZ1f?nuM99sn%!)41m}n0QUUcGMhLKl?G&i;!Km`^I888T#QX?k; zgT~mU0OJV@EhNP+))_#lbyvv&QvfTFb)Y}~)$*VGWV!V4xGerwoRRCmzuSa;Rz@wL z-ZbljT}Cd?t1m07ZzwI1eR-v&b#^lh@hlIpA&z_WR9)BM_Gc5t%vJUgm^fH3=y zp4A;x`y$z@EtJjUd5oJjdK$4(jNey4Nj6Ak9$v%wx+>qW$it?Z zONIb@DNf%KyBk*|Z9Eh^3c(J}8>ZtpA@CPfNAs*CJDWe$35Nhj~Wk%0dq$kG!o!Tb;T|T6J z0kK8x;sHSNj0M@mz#!qU2iq-SSLZ4qG7tlJTTGF$Z7P17ZMzLp<^tP7TeFR}Q8br5 zYkSuQfx%3h6dofV6ppTxyqb`y4k^YU9|jo!T|fl0bUUp$$>hP__?I9Oi5D_n&v+|C zEJU84 z4Parw708L6!MZX%Po;oK4=RD*+5j2u(`($YfxO;xkkhk{o~vs31tPc5eTeCz_(L9H&7vDPwt3{GrHE=$QWPScPSDf89>#c)m*C{YczT;CL3ip!Lw zra}>`g}@!%Xf1x$^DZ{E_VT{GI(>)%lK&Dag4j_?s}Hd_K?!Sw#VNk``FW=xS5*E$u>{4_T{S3<){zOE z{Z?r~96;oxY_OD>J#hT7lqFAvbUrOd7Ci(tThxfp>tLNGr}7Mz{DoypZ_oUaJTgf30?1rKlrd zt!r9l$}krdEnBv>!HYGUB}0&l-Xjn)Q@jIIQ|T%o5F<9J68m2<1XRyt;Q)xmh9QQj za+D^BR%Jf?j2%CutC0rH=jHn|#xmq{$4a7N124hb zfiI{t5d`Ng&g4=M=*LH`U&JSJrCB?zw^+AYk#p^w^^*0EuqKRKt$F;--t4%+ahqei z;~vMC9Ok=d{DlXaGjGVeEpvM&Vv&75^8t8*yQvtVg2dYh{{SQ%LnMRD%ePjqmqjaY zD5+fTYOK`msrdNU(p~YDuY7#+jX}Bn4N3P3cuoBbUQ>JFqkve-io3)S*9@Jov=A#{ zimXhoa8kO=Ly{4~N*DSjNGfqZP}6!o=43#)3rW!f6bVzYG^tFKFY(x(MvBVydWoWs zcR|-e8HcrF+6nCk+M60Qe)hvgJ?HnE#`ld-C*(tRBNBgO`mX8w5CSAln=Y6xv+~Wf zr_=rsrjm)%X&2HiqoNCvm>046dpS?n-`O!HANtk5mOS{;&$P0Gb9=W>(JqMUa0t3c z(bwGmnH4tzz<&-5(7PD>B|1du7mq9uEB%+rh^rN3C zh^vun?+0=N=y^7!Mj;ORoCMG?VXtOFVYz|AX~;0YFJD0b28*Zy8H*D<$}nV!ifF`J|x~^5zGKK1{>v1fM}$8v03~qt2kS)!D=N z|537A7zu1m*nH*)D!@%91r<=IW&{(?jN*(SltN%obWZ@8SYq$8uZO-i@mkIsIqxBW z2jmm>RrXE1q+5=naw><`0<#1aDrW;}G>G>Xs~eYPm6sJ*yk3`oUX|B7zc`;#ioaD- zisGCZ8AVu|l%F?bD=zaG1a|SuX;-i|;+xZ=Tp}(k44!@|w4*FyBzBy&%cv!E{u82O zkce#Xl`tbB_u1pbT~4r|vCFI-M=hcAp%e*%HM@yY4v4(50O_bWkF}Rr2z+IBtey-! zhZI?Om<~!#x+Q_J$WkjS7wdmctg1P@=J&8Nk&oJw{ZFhE6?w7^W~aL1DR#0_goVph zJEA=(_W@VT;uvQMQ*?#0k75)lnfdMU%jPRsZMxKa4@Kw2ERH||joCH_&8_AhGiLiZ zu7X8~ACbq&xE0HwY@HFQ>kLxjho+yJehE5AV)G$LY1}Mx7%QY4QutUS&i;v&=8fh7 z2(@EPc%MkD6dS?)BkbTx!$!jZ#Jx$u`^Xn_?kVXX*5ZA4_`B(rA-16}cdNb}QCuPV zLK<02l19dKJ+t^lc}RGXg_0}n;WVnb>_IJlS-S$ZHU1#HhiLdwtOd1Jtw%%WeuJMu zK;uV@$Bnq7*cjx8&saN-_o|rjmXsH5{0q=NnZ71 zGI(w%XIX?$0M$|wZsZX{3Rtkx&*XC(n02H<)MDZdgoQxK6fP0-_7LfciF7C+|8{P6 zMj_LDCKEdc9Cp3N|3LITowodt;R(ZY1|^lYY_tqmc3BQs4qJ{{PFU16+eX`fZI|tU z?Xc~b?S$>xVs7I`tbEZ4Fv>)Krm2*Www;N zrC_li*`pxiF3p->mdr0@kOlM07NsQIm8rB+#Ee$h<(@%ooLuRRS#ofKI1Mwa*dz)> zl2N{tI0kK@2$rcR;#06-Q%XMYm9Y=F9YW}q#aQ1Ua4d6^)-!X|gvwwhWz{hq@jYoh z!vhhxFTM*?kO7UZOE;^5GaM73fUSfwQI9bcTS^l2K8vH&a!r``n-3xAQ{p-EYvwml ziJjwSeU?&E z5x~VsNo#LyqHqjW7ZcnjG zEbe46Kyv^(cE;YtK~luJ2-r3jCkYBcj5EX+o}2;j3AL7qRU6X=2-_+^lsJ`kF6|OS z8xDX0jBm<_fLTlEBn21WCrGPUoMWNDJW05^vepBx_}Q#?37!hPx(z_ZyWJZQ8z=sz z=Y1ZZ37uPc#m_`2_3F!7*#W^x;17YWhQgwT&Wei8`l5pRj{jVAv#(~J!!@s}sHsyM zt+{2qt9$3VU}ewfs+GGo*1i3BRrhVd#h>f0ymx#N=*gF4Og3mopfOud9&kE0s37MH zxtvw!i5|noi5U!8nMd=S;}X(LhOBox{@U?%$5W___zA}kfP1sA#ouy#Ky-v22NulK zz}9Hr$y=0fE6I1u{EUpOf_Yj;M_zkzSzdw5lWECQ=f79vt8y{maS0^`0p{U^U`F@^ z;yY|`fD4em;5!$B03W32w&4&aN)IvnNaemz-thp!}G4-AdQD_P!uiH@nY_e{bKGUvb-60m44|ha|caKE+2gZCAeF0y6ZS9ik z`r5ksD&N}P;Q`<3@Xknh$XBr~GBP?g)Vm{GGuW$FLj5~>BZD=4(H(&*-_qfilXvMb%<4{+PjAMTY$ti2uMe<}g}3_d z*gdE7oZBUIk$MqIA$rt->j&2*9=p70BaA7dg7an5c<3n4+ zBfhbLuP-^{qw)%euQlF#xry*n{`y>|?TeG`$f0bj4Lt8I<1 zcWjw&U~Fu7Sui--Hxd~h8?70|90Sf^PuJ>e|AIJ{Q86rbixI>^?Z;_lO!$yPuMd8L zKG@;a;=d)LTGi@MR^jSe(TgVrP+Kj+Vke#piy`&YHq=MNDBdxIdv@S@jTl62_LUG? z*@0^j{8EEo79>rQsUys=n%7v&Z4nXNU7PyEne8`ZE_cA9|31*AAkRJsQ#mV`Jg}HyL?#ZpPa7=z&N2+;kADo1Qe+?o?5TBO!qPcu}|EL zcD4cb3ALWWXi*=BL45Y%9bA3-SdOdSa>jkQpX-TFuL3stU?VoH?wuJ6V%h9Ba3()( zy>QKNR#W3Yx7`#pz37XMd%c(q_RR-~BMJ`A1KVvAYw+2NYh0tG2xEY18BXOv^nr5_ z!S^xLYw)Mzu|8ixz~2RU|D0#YrK^8e)&L_?{DFQ+l@f7Mq=vf;$S7>Wes2+Jkea81 zJAiH$xwD<%XEI@F=7!cG8!|pGY?bm5jjR9`&_!Y%th;@PZC(ls?fGH>^s(i@;sD|j zEd=$cMqh$SY-|vV#9~mrM%Y$2q2JB0n{E-;fg=fFY}ygQeg%5jEmmUAt_N1F7B?d9 zOAn%ItN~u$j5%0`8QK8Z&n9szA`X96+%7&RHj6D7)4vn{Mf{bxPyC~J1U$+<@t?$( z#5cv0;yd6{{#v{Rp66@QC{5zau(LiO{#pDC7Sewso)W(ozY`ydZ;PkJDe;>4F6ORJ z90X4M5Ht7#@jCdR|0@2Q_>s7THTXZol=$zk(Cin#f%f$*@=Bb+jQmpkTHG)0#C&ZB z#T~>Nd<-l0F3cn;&p76DCsx7-VwboZm~xN!3-Dqm#J9vAaWBj~zaV}k{#Cpn)1+0V z!>;@z@v*ofg|tb#bVweESD8BAS>lUStYAwjrbk}aka7z)<5rx_ry`z zAl?-JQ!bK=#ZSd~@h{?{I43TM1g!sF5pnUXI4S-T{Na9R?Y}Qx6#pQX$VTyiTq>Ky zWw}f?%jL2~UI)=$NVds#*@0NUD`c1Gklk{n@uqdFSEr9+zaH2YuoFS zpADuRk-m{=@>`R+?T(S~&ak;xeOTI}{n4TDc1y4RY3}Un9f=N^x9T6Ac(8ZOvLbm? zIC;|w{nxPiux;-j35SOU!IDJ!%&U9*#>c|uLH%R3e&eA2ag%;=NdLG=zc{2m3@e8E z4dJ1FOLRvs+8na?42%!;_l}J380;M%vqxutGq2TOFrt5~)!#Fsf84BJ9917_xAcX# zg175U8%tKqx9GQxsSne-5wKaNahCRVv)izb&;DkLdNut>n$Zk($x)NMxI9cIWtm?e6eMv}Pze3Ql{#+Pf_hS=`uE-;~}q9334SiDFfel1Wgo OG|;OYVSulL^Zx)kukT&} literal 0 HcmV?d00001 diff --git a/data/Roboto-Regular.ttf b/data/Roboto-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d9a6c4c32d7e920b549caf531e390733496b6e0 GIT binary patch literal 158604 zcmeF42VfLM-~VT3?=HQQ1PFu_Na!G;ix35oqKF;z5y1kepkP5%6h)c{s8~=?x?(}a zj);g#s0Jy5pg{tJO9E$d31EZV{y(#uOG3xz_3`!pyzb_EySHU_eszBHo4JjULWmeX z9HM!bE4p9AH!0NZW7!5?)aAmi)%#Z;z@ZL&?{-n|ORtD+*guNzoPT1@MOR#P!J4#n z4k4!06+%6K=@rddEScXRONb|zaee=rh7K4OwXRo7A)cxwglpSPBkoBGs8M6BPy_Nf zpEhvVprOyccIZl>ZVVM7sNSFfcMs!uB|G<@-Csr5Y`9nfpduZ@218%N1 z=e%kld{Uvydkflj{uRD0?JtObfK4LZByHHHa+i$t+j{61-c}OTVQi$f! zL+-q3faB%sCJNPJGR4;#I$-25=T*U+Z~q$iC*3h%=q+l&?6>*8MhK(husiR*XZzk8 zvxMpxC`9U(VRzj!Ed0ot+3*LN#3gV_2x@LEN(9Q+b_B7Kx&=_>?-=O#z_G{aaHcsgcHZS2>AKN1 z*frJlK|ox}(LB9sy7Mv5(E2MwOh>*!4 z^Fo${d>?W&G%++YbYSSj(6>Xs4gEbVDXeSQ#bK9+^$F`2<_!-IZyequd~o>q@CD&- zgf9;ND12G?j}amwC8A5jz=*LCvm%y7HjTVEa(QG_lfZKHcdUm1N{^swmh(UYU!j@}qu8dEK%bxfa_eld$;zONQot#!4VtBtSrTD5i6 zys^=-ZDX&EeI#~X?Bdwvv0ul16hEi>r0P#qf4=%l)#p`zt@_*5zpXK_#@L#1HQUy_ zw&tjsMG2t^(FtP{W+W_2__3Cw*7LOkYe(1Kp4cO?f8v*O`b8&aC5v`*=hvOmR}8lGA`^@7wssduG5mHK?@lGM$q+v|qctyZ^b z-QINv)*V&%je5iCO{@1oy`}YX(_Crw(?+DNOmnCANq-=HZ2cbfN7kQO-`l{|pnii9 z4PI!lv_Vco)v$iU_KoT`x~tK*jec%iy>XAm!x}%|cuwOt8n0=*r}3f2z9!Y0)NGQ} zq;-=%P3~&4xXFel1x<>Y1~yG>n%VTmrlXpUX*#j#)TS>qUD`CK>F>>wnqAQBgJ#>B z9c^B-d1mu|%}1Wo@tkfg!dnb$F`~uFjOdL18EsI|*jcOg#(@P<_^D}mv~;6^FBK7+m2m3-rR9p$3vY4b{gC1=gexE z<1-hWA9sGs^ItuGOc3ITr%PwoW{MaS$Lf3`$FYI;UunV8RaLI)~b`@RIx_0Y&N7tvie$;h)SKmcR z7hP~sw~KmRlzWk{+f&`%?w;AbUw3bh@E$FDwC|DGqic_gdtBb5Pmg{*#`c)n%uA+;eKr1z6LyBBcDYmPj$b64#i;;#zZ;ywEI?kC^-9 z7;}?+PDIIB<{G&IPr2R9l11h^b+I{H-DF;-ZZ;oOgZMt!+^HTjOVvB(z3N@Qe_~#$ zmYS1|`_03~7~nBi8$X#PMv<9q6q`GZ5_2VfDNclNr5pPVJ1hl=YJc5)-M# z{pLaWkm;4rnfv7mzHc{kxjxqzZvJF=&BMYex|>DRcR%HNDfcJJ_2M6{GTmIW0-v-( z#L8R|OI`D*>ptq5M;-T4$32vkcNSMjN;)87c*+-WBnwV_Aa|PI!G%v$nE9ScH#e(B z<{CIMhbLsgg*>&`{93&SmYVC;r)IHnuUP;m+;Ae__`%GF=hvDGjNu}NGY2_S!kJRe zl)$HR;nVlfb0zdV4LzOCqK;>#^X&K;B(4$RaDKL&Y95B`KgyZtzzXvfe+V6`#Zcc8@sL@c`z{f$nN!75b1s~En=;nQC(VcDGv**U!<;}_x4^ww za*lbMoNK-==b3lQ`DQ=Le?@K=5pXq6{%FqOS@+1j<|A7!4L3jF z-W}Y#gL`*y?+)v#2(Aj{ssmgV&QSzDlK8#HMR%UAD+F!inog^q0&9mhVQP}CJc)Kb?t%>0J>L}MxY zsnd2We7~-}7;3(a)UuJ<9HjOIQd>c-Hp$2_6T>*GxN}(Fs}ZI zs}FFshpRmz0BXHRxCH4Qgz6Hcb`Yr*Lgg0W;>r81r{+?-BJ%)OcsSz`l5dBFQ7)fo zi@Lz_tM_wmKV^C;vxGYiQ08Ilu2Yw1i0&c+ONhcdMu`Bvg<1A6LxjMA{c@HFMMu}5 zhb6>2`t$VH{PmvopC|q&+N=KyTs^TRK6xAaKRnOmv9%N3_@;ZEI_p8meS-lLvgKmMuD>G^YF>+tU#`7^!X z$y*}Z*8b{qXKp3_|GC0$3;s9zy??Bi{GYt~uaVl>S;d)Kguh!k$M&aA_wD~qPT?O) z|6B7!C&tiKkLWDYne#(`!>IeTS&+Y9eb1b2`ZKQhyTyxkKL4+;)ydCM4`HZiCylx#i z)3=X&X;(SN_Y)b`zH*+gOwRZ1ATxhCnRzFf=+DT^cbB<7ADQ_Wa;k&L%!iYik0CQ3 zKxRIi9BUN0&<^BT7m=BdB{ScF%zQXG*W1X!u_>xj1{|}96{rx;9a%IHoKR+@i8N(?(i!s%|C5ISyJ$*(^;m5TP_lV%~ zQ9L&zcn284E0ixV-Z+CX##!cGM({Q;4)-micR%3Yr#1VB_5xXPXK&dfbgMH%1sgXUwpOF+&ey zhCk^sL&j>ETfiu55#xy^+#{*sZe4fou}3jWp{7L6g}V8A6!MJqI(aK_@}nWlNcfi4 za4oIhK3cxLw00|*Yp|O+2H#pEjqfs6`w24ymYQqDe@DA~W)FSlE9@Ro5ZwC;?tKH- zHo&!fVuM|9ZWFUJJaBCeT-zkh?y5k_T1#2Gki<_&LXQsbqP)WL@!s4&c?L%evC-Sa zM$yDYxr_$CMO?Ivm}nRA&}QPHTw7om z7co!NS$L!WjkbEb>4u{l%cWC*Wb%>BPe{g%WHwfrzw_Ur*&)ojsHW!_F=Hskvf`VO z*#N-ayMQ7JVlrABAdp8dJ8-O2zouV&S0Xhd6qe+UvPXhlQfN zwX`rr#BRCxtRlSf#o%VJRL@xB$l>z2NlvaiK-_eIxT%o1=>T!lfwPE%PCcd@VdVnt z8BiY8h*@ZhnaBB_2sx_=?ey{Msh?`kv~rcx>y<}%?#0aOx*05G)~Du#ma&e(_HcAB zNB2T!k+~G!?SP{{a7NG3{E3*rOU|K`E0&(c6{o2aawzt5+v0hpWd4jNpPpA|r-^5- z$Nxrbai-qE+0C{*1AoeA1fG7z=IP5gwe0^pVxCHU{qLaXKi@Xle(2AQrvC4gcIKA- z|8ku6_scn*-aG#N>ibvO|C#mp?^BaA*Y(U-{Pi)y>1U$--Rg7l{NRZ*KL0AMIJ=(n znX{p1zT(so(x2PwJiRCSZ++H(M^siBWmfL}RhIB~^Auhu3s z>-Uem{*l+|f9w4ZfBxam|Kwc(r`Mm;Mc@Ao=gu56ocW4Bt4HupIr>-Vr=HjHcjM2Q zdvI0fr~myjI;ZdV{Zrrn>3bReyZC!{)>rktH>ckZV&t@xk<(H}PW2mFN_nTn3f|D- z;SDXTdAG%O-q7;7P<$)m8)L4Ffo>L#6UJMEdE-SCN4=C)L|Mg@<)y4o%gg$hySGx- z2f|4S2RTzjnfm=B9**v(L=U64y!C?XN;tC5I#Oy~!*e-OB!bRr{8iVm*m}z9a@xGq z$E)iD9mCBWJ)h2^!2fm*d&F3mzJfcBIm)#W%)N^=immx~k-A)F>e+NwmaCt+Rmf(S z>o;{Vw=YSIFh&}sjy{eV&Lyt5U0(-;2OJWyq8;xmY0tY#I*2$iTg1uMjOeyy+aBBs zMuTx8P9=$IDh2dq|2puMh*nu(wTLznM4V9@)B(wqvqD6eaUu%T26fFW(Z&2xbY%?u zBG3)=0GER+K_7VC*DMhK0%N%LF)$X41LMI2FpvA^g9YFf@G4jcUg!Qdz?)zZcnf?0 zJ_H|ukHHe~DbH92J_F0a=RE5R@Fit`ML8?kX0ctxb~W3z+_N5JgKxkluoZjd9h z0*vSUB+fswe()10<{mHGqo9l#dIAJ9 z4;r>ZX|Es-6YU13aR7 z3Cse>K_LhAHh}l)bM9Tiy=&R7W4oU1*KD)dZeaTj+l_2DvE9se3)^qmZe_cT?RRXq zv)#e=d$vEYg-*4T?T>7CvCU<>hiByhHz)w`KzV?EZw)+9KZ9Sv?*M)%AC?V23&OQe+}r%yvFOm4eWo# zT+J-78c&tLo4sm-Iv|PdO+j$;3kCRu0_?f~yDq@43$W_~ z?79G(EWjoUu*m{!vH+Vbz$Oc@$pUP$0GlkpCJV610&KDXn=HU43$R0NYX$N$=2VYo z`vgE&v7rKNr2sq8Hd26%6ksC-*od}=0_>pxdnmvj3b2O)biV-IFF^MT(0i@t1?YJJ zdR~B@7odLy=wAW)SAhN%pnnDEUjh18fc_PrV+H6~0XkNIeiaxk@!_pN8_*WC1LuPa z;K_M##RFG7aK!^xJaEMWS3GdV16Mq7#RFG7aK!^xJaEMWS3GdV16Mq7#RFG7aK!^x zJaEMWS3GdV16Mq7#RFG7aKr;gJaEJVM?7%E14le?!~;h>aKr;gJaEJVM?7%E14le? z!~;h>aKr;gJaEJVM?7%E14le?!~;h>aKr;gJaEJVM?7%E14le?!~;h>aKr;gJaB}! zQPFOUrQH}yyD=7<8jDSh#iqt$Q)4Zi^PqDcbk2j$dC)lzI_E*>Jm{PUo%5h`9(2xw z&Uw%|4?5>T=RD|~hqf-wJSZB17N8|~96Sr21J8r$-~})PtO4u5*I)zq5#)kBAdk1? zg@Z^C4XT08;9@Ws+zlQ8yiH3|hRo)zTA?5j)CJT-)d$o?H3nCJtH9IX89;s1$KWvd z1^fn%fHGhbt4Lq~CkOyRAOxgRH%+A*D&0`&hDtY7x}nkym2RkXL!}!k-B9U4r)-RJx(k4V7-FbVH>ZD&0`& zhDtY7x}nkym2RkXL!}!k-B9UmQSCWi)xdBXceG>&Q?<%#K4&A~f7b7SYl zRgY^JcV+ymH4175CnP1zN?0RW6QAUXbBQ23@W!(-?DIB3;*UJyk38a!JmQZ${OA_( zCEJx?74OVzYi_}pZjs&C=RJq`)Gf5#d9>YmwB335*DdlVFYlJS4qVUv5bz+!9|9BDUkE;De=S%KvcWfC6W9W_g73f%@B`o-ezbvk_~o@E%@jyA{}c=#F`SZrbMXBhPrI1%Z9pasLO`BY^ckIvTP{JhO%rZ%7&tBsL6(! zY^ceGf^2G@O)ayjWj3|TrgquXE}PnAQ@dD zPQ;oMvF1eaDjqHe50`_7%fZ9th~DV#W#Dpio4_9Mcsay|JBbZ<6C3Wv`{m&Ma`1jR zc)uLHUygX6>ptN655Y&^W3U8#%6-egXJ9$_ocq53Yq@7V$OhklO<*hd4(tFwfSq6$ z*bVlAef&Ddg$)OSV1S(w=WQd-+eVzX4NsawoVSxWZzplyPU5_s#Cbc3^L7&F?Z(UI z$gb>SzflKd_M&6AM#i5J2=YmGJyZUqvt4SQqZLE9mIsYRUO`In9Md6 z)Z=^u&;+#Rd{@v5AS1kg4&Fb9_;9znoA37m-Wp14kV9*bLu-(urt2Cixdq@=fGlY>a%eSjXf<-wmmJ%}HV?Q#0oV^bpa?)8vD`LdxoyO9+tg9u zGq(}TZ6lW3MyrxTtCC{`f?&RfvJEFXiUiT18i)hcK}}H0+)XUEn^1?WOI;g4$|}@O)t{)B26!n z^ddU1 z`RGSJ`jL-**_;>pg5%jgAKn&1*i+23((e7V_!a2KtF@k&33XJ%dz>C zLgc9PDTT=H*c{54a~p-ot`ON3BD+FlSBUHikzFCOtD4&=M0N*|RS2>QK~^EiDg;@D zAgd5$6=KP%6j_xbt5RfDimXbJRVlJ6MOLNAsuWq3BCAqlRVwP>Uk@SSQhe+o?mUQJ zJ%nF9g#SE5DF-R#Af+6{e;&er9m9qsYI*y?EheU5$3 z{ulIHT)c5T5Cnq|P?u;u4d^Jp9p`nVf0?fPvqJuoPU}veJZjko8`xV z-vbfxACeo`|Azfd>~A45+r@QzXn*tA?gMU601CkY-~q*yQ^GZ+>>mP$!LQ(VVDdX% z>PpnMiKuN8oO7!re)XKpHia$yBBHfT^e{9hi;3Dck-pxKj*g zis8g^IItZ3(iAU;f?{f4OwDyu|LQUPsrU2P!n=3&k1;|6&UI}t2LIy?fzX;wJz;A7jCGa{Q zKIg;ZeE6F$9^>8Qkz@r5$O;sY6(}GpPymIwP?!sKyTlmIKL&J`WgHj}CV?YA0znR%%s~N}g95m*OMJ;SE5RzThGXl%*I)zq5#$2$Vq_8u$RreyNhlzbP(UW3 z08Zw@$y_+O3r_BmojKNx9NooiZ(=)`?X4Ui!v3A$ZoZFT`vBX~93KbX=KjTe|B&M! zv%ie(YCt{6MijvPT+8zEId+g=7L#)%LqYzVE%{rdkc$*@RbBSskE##gk!lQja{LOm zSAlET@5`@{uLC!*udU@qw!b=k;0Lf1>;i|m{}=EZI0AIO(xfexzyMAV0D?dWNHBMy3A@mQ zU1-8CGA9N6&zCmnGM>5IPkNE07ip9rjS{5cMH*f>?}f`=^jiBmFPtusAMzgxK4!ZV zPpX!vvJP117>+###)5HRJeUAxbM8yFE5Rz> zK~ZV3+LOD{u?X}l0t(&eRs^~gfnG&Gty?}S!l71sayL2^Zd)>K{xZ&g$@kU3vS^NN zVt)(o*U#tNLFC}%e;h;uyc%3^tMf&86|2@B*R8JSm~GMf&>yUt@58`w?i;~xWbfnH zgX}*9CUE>k;<%aMWiXrbb2z_{tDG0{gckwq~ri1-$fB6YqL|2{n8>1-$fB55$4gXEOjJ=!R8dS+QA|`(EKS-#$|b5ORzaXOxB!bK zt3c#XOyp2ZOXQ{X@e&yn6B!f}6%^9~d5H*$i3p0-Jg@+~3SQ&*m(;m7aak#GSt%{| zVOs9PwA_bjxev>B;4<37DQu?$M$>7j57SZ~rlmftt_3r|OJElMpcY63NgxHZBnoT= z+JLs89iSa0Rw(6{+Xsn8ZUpy%IrJogsmEdJp`WSmJ1TMYOpZO~YiDs@MT2zq#vb4G($6?H zd!xs6PnNZ*nz6CRZN1jG?H|n6&__Jo7;0rE#~wrVil^wsg&~13W&n8MF5`Zn8|VS- z9(++n4}Kok%m)j=E8tbI5WLQ{Z-6(!BJdVCUC;h2?#TkH!CJ0e53&JqnAilig73f% z@B`Qhc7fesFW5)Cc5E-dsJxe7B)h}$%lPjk3-O@I9dZjIMhbS=TwdB62oG z$_)y@e!y%QayCWeY>Lj1IVd8ZQ$#+eh-|FR92A`-a}Y*vG>qP87`@RjdZS_VM#Jch zhViZdJ9hJ0vD=N*M#o$Cv7G~mqr`;3vMr z2RzT-V`WPVT@U^oFUuQg_xOKKP_g$IIcgcs;TSr8tlYTv3^JgXU&&{9T+t`@T7B}W z{qf2^xEJj_i1*d~aQI70bZlQ-XM1%I(f0k!k+OXLvHfvmK#O&JpIrOgZTQ@6_}p#y z+->;WZTQ@6_}p#y+->;WZTMWSIcx8%g7@eVzp#R8x6$&~W>!;_xxsu=M4Pl`=DX%0 z^HXy)UOd!%-JHj}zy8od`U^p=r@ zm@#$Nb;S=PdM{VA4{oiVqY^C{EfaXDX4!b!~ybH%Yd zHXqcFF+VrgnIqT^_x(f$Ntl`}~PIW6~$|Ei)Od^Ot~bp4CE* z`jm@ZhFvDvE*4ut_6_`ZIAPWSnt~s!v(`22MVY(Fctw#7U?Fnxe}?P5%EjW4|DN*0 zHowiij6uLB^gGJjLEOzh(bO04Kh46-Ci;w7Xnu_xyynN|Dt+y-izS=zs+y+t-W&&z z8k)sIMxlHum!YM-<+Zi6xBPUNy|vHy@6lVbMdUs41eWwI9kgo6DZ93>pnXHR2JJK- zH)rtqw9QBMO8h0+y6gY;N494xV}F_YdZJdAN}H~%hySXob@LyqqF2`a{^NgSOMLW) z7F{#@o=O`$Ss5qFML)*;&U#qH$>`(kbD+{zDr8~H&AKzP@~PJM@()Xgs%l5olm2V| zkTT~{)PXd$>Ot)m}^W%&on>% zPdl+?Gk5x}%DmrS#>uwF>86w~;+uoXt<)1~%oeFH8i+<@hnk3{q8a_qb3_aBpe;ok z(Uv(y?a8}zU<|Sg@m4q9Ms>NkLR>}UejQ_PW5~mdB?mK}{LABFl6XQ)7E{Dj@g(v8 z(_)%&u3+v1}@v%NDYwY%SZ$cCx)Z zSDq(3$!@Z{yiDFCZ;=D#AURmxDu>9S@(y{Y943d$yX4*S9(k`EA@7qT<^A#jIZ8ex zAC{x#Bl1x>Mvj%^DyMR(U=^;& zSgATHNhPZkm8#mSb5#d*o;qJ$pe|GwsqU($x5Cr@~RTWd^z>A`bGV!epA1zBkHIsQ$A%H!jOhCf{ieP z%$HHisBI(~b&Mn<*+?-`jh03$qm9wlXlI*g-G;V`V?&{}5;DAp0@p@_wOQ&hzAar2H`wU4bOGTC)1V zl2xwUi=2uq>HMyQYQkI19zD(?PqfDqt+6Zi*i-ZtmmOo1*Z&Dt`Fe$2zJCVGT#Ie4 z$2zmI&u>m+q4}q@Q5RMkh@A$@kUwav9kAAp*lXq=vRG}e+FBpAEOjE5`ZPAGE!4Km zs&?tON^O(cB2R6P+8T4PLT!WE0)HyEK->EM9oxJ580#DOr`X?@e`gECj+{nEtAA%V zV!EgI#~1xy>kX_)FBli2+Cj8+de6Xq?Zw5>F#0p$MDljDUw(o&7sv9u7(sqlFY(r= zy%#U4b54kw<;QBUO<>l2t@7`G_QnAX_Nwb{*I(1%U-k3!{0hC&A7P29vI?k(D_^aX z)`zCSzg8Xbto|cPVDvxM+33wtbebncUUGy3MqBTg^{co#Y zq5MK6kt3S_(N--gYp83W>lI{OscWl$Kjxr*x(5|*ozv&_{Th0)xfIA=9M*8`V%Jbx zlh&`wv-DHRQfXV#cWF!0_xqPRoU<1{<%tzX{MQ`6t&TOxylTZPszTZ1a^tGuRCQmUd<|5<-&daL2LINP#pzY}-DUHWcq0rq0^H5!Wj z(8o0`_7Zr~`^!(BViQAc;;jsiwhk-PQ&Bg69Z$bK-YXpc-A}RKl25ihwsJPTehWVK zoc+y~fwp8DT4PVY)VA6e{dv4S>mzmxWM!+YVk-Ay;Et{9CzgNgaowKSt&e|O*+S^! z8a42IF7!1B35HwkO=YRtr^Q<9vG%R~b|BDpqct_e(w{g!HHXf$RO;mEt|Y@#vHEL& z{Pq4;$)?2x9eTCBS4}*!fAv$LX{lT^4gOUh)iJeRZS9ESZaYT1WYK;L24UbhOG5B3qQ zFIwW2+Gw3P=|^QW<1CkneMEn1Pi$+Z|0?^NE=bGI%9C09nnF!^h{a1S8@<@Pu=n*b z+uzvo^+#6vYzSwnez)6r|FddgW%d!<&-m-2@ATI|w@G@j@6ovm?UD3Zf2*p`+KbI4 zUAI`PEwSSp2eq~B#kLq_owef#n-2YH-(^!<*+S`i^||VnR{HC$pH{W5`n!M8x)H|J z8n!OllGOK}OdstU`0w^_qpkYuZaz)q7 z*7oYhw7mYho$c0N_fv1}I#gP6Rjc;zSM@qJy?zVUnteQM8E8wkQB_;)r};nQX+g9X z)}tXY)~DXui;mpwGq!Cck#&<@x?X%GoYqnkrb+qQD%6l$2MrM6cMrX3m}Sq>vJ`!n zvb?a~lSoD1CFLsKUcXV~klVP&xR?CKePlT9Hy$t^G)7sOj?u=W#u!JimG3xkY{ui? zy5~D%o3YjS*4ScfHZ~gH7#oai<7;ERvCdd)tTA>NtBqAgma)?K%J|aw!dPJpF_s&j z8Douq@4kt~GS*L7m$H7sx`g#3)(=^~XZ?Wneb)C_-(_9Q`VQ;ctczIRWPOA6b=KEd z7qY%;yu!MGbw2An*14>6SZA}&VttwQCDxg&Ggx0_eSvj4>+`J7vEI)54C^%3r&+hN zKE?VZ>r~b$tdm)vV4cMJIO{}X0_%9zajct+O-OPK2m}t}W+Z$uh$e4)9@6b1uBU|< zL*}(5xz`uan3?2Odx*JYRWB8gyTu5RC-TYD?k7_^m0am> zWM+>@C1#Q<4Homszr={wWt_|u@93Ng8CI=d-Fcefcv0#(9S-LVX9lWO$KF!Mf&S)! zt5|Y{D()?ku46Yze;;=LU3ZI2G`P$qd_oKin4vf!XJ3k@I@&uIb4ik=+d6gwj)!@o zUTX1;J(VWNSn30OvCrr)_JTc>@AGskc3I}Pl@iJjFd-HNg`RKh}2_p<_%ApHE+c)OOMUfbrhZ8!1>|=(b>wPcjY(m zI+Nam?A^uU5;BRGR%G$6B)5LGxQ3aJeaSEC9Q*bBBH{+oUkrdGJJ0?EdG!~_q|Yal zzJM(HD@gox^5}0^ne=zW+hVbJSG-R~{R499OUSA(LlZs|%Z+ozUE*eOi@4P|kJwNL7h)FtVjq|r$Wk`^W{N_Hm4B*!JEB&Q`e zP41VXQd}t!DbXo4Qxa1erF2W_pK?pRbw7V~#Nji|GJLdNbe)pK9O^WO9KToouBuyg zT1DP_J9QEjbs9^Zrs88ZQ77S;NXNWm;vj zx~{xVQB~@6vsEWaosLo`=`fflvDf_4Tx`xapEs{Ddzr1x8ouXzlgnQ7jq(lhUFW;j zca^WV@4T{|WjSR(lzm^ey=-gQqOv#hKF@nBuXA35z1#NI-CKKat-T3*YwV5O8?iTd zZ_r+~XUm?odtTkMV9(q=-S>3Z(|%90-0Sz$-TmwCt9ISGyZi2LyU*XMp&M0dY77TCxQG-CLlFcPwt!NTx<*#H6;$ki)XFKjM`QEvy}#Dc z-owUg>VC>~(2h0D3=R$oaOr|8%8l2FNGW4^mQ}vNh-iR_H*}!^l*&h&s0?-gEdy5h z*55KfW;y2lt^$3fzk4Miyb@h$i|0{(0Zxq=j&FzcA#{*0^%ZqmBT@NoDdYCoX+65Fe(%%f8I!8kn7ya>_Q=34c)wbgPruv* ztM_#I;g{YoJj3iGIm0(l&X_F!HI;wD++Sm=Z^2~WK$Rx{rL{nc(Pnc;n(Jl8#IMT? zZ`2??Ejg)LbYw(Gu*)yC%+Mgnt0$d~lsd|A8nOHbCxCmi;L$=HCI4vYOAIUZ)H@A z%V^Qs7%=*obsLtyI&0x4D<8gd#E1uGeZ6YK2QM$maj4}l4SV!yIr7@kEzbM;jaN3t z?))*%{l(~658ggtWa|sEUSG66X2s{x-)(fxcGhHlYs5!Kh6FiOpr6k6=eAeMXxCP`0#vM4D2UWVIRxq!p!WIO&yXmtEYw z_hmhL_EyanJU;Q21ry2-UEaONWxj}^YV}aZ3!~qD>yb-FFIqIZ$Dn~dFX?gXtv!xr zkACZ|(Y+p7wCItZg9i2N)noAB9=~*U+|^k}nVIGR$3}RNjD*{XmouYNQ`)vpX`I?P zDKVjDY_;IPfU4Tup?RcXNM~BT>QN4dtc9Qvx6@fkwv-4u!H`&OoJ%@jQTaC&ACQpQ z{w!`Uw|VPsL$lB@!j1RzWAJ`^8MOf zMzt6|&DhiG?k+c^^=*A#zv1xVVdG=j1z+J5>6!R9C6!-)s&N)4WLXttRk|Qd7_ZjF zay*-SZW-j|%CWw4)XT1$iN%{`I>N(bg%slYWQK-1mDNoS74a$|GuZz%MOj>m6m9BA zmx_vwjD|63B5JJc_>L>>@%8H_rMcemeW@;$lT_2|ib>^^S$D$f6tKXRTKFH z&vo(KI@WVLWxB${@S|0q9HSqliGY+wP(lTagv_Ypj;0uvZ;BL%rFC>vt4NjJCWDvZ zsXD$d-gc!;$lmg3n(J-ZNppUm*E8gxnZVD zv&Ap7%y@nCiG^7$A2n5n%idGHRLvQ7Idi#oAhQ?@k$hY^;T4skyJ#^xS+~Rkv$EDv ze5Co95pT8Yb&k7_e7wZ5pzG4QD?U|bEO|}!U-*!#iGHRM{KCi)S?+_03H)BSqV29p z001Mjz2H?VJZ!kIV}fcbHAS_GY8jo;B04tRcBfHRE78gkdF0zIWkK)aEYb$ zut0M#IW@}Js-9Z4%J-Er9KRbcwB~|w#0rU&QBz!)8CtVObYxg)a3F&zelO5C91n?z z9J&pW4m@ZBNGo@AQ0UO$zn_32N)^~En^jnKN*FQ-M6*;Z4RxhmI~;_bl`$vLlx5U1LncS1 z2N(~nUAwaENp;J{vRQJLD@N|0;ae<1@^|z*(=Q?rGb%b)bqKKSeufyeZIh+lszRRIpI-Ky^zo14$OqFdRTuqR; z8>6Fa(>gj<+dx_sP7+cCymO`6QI_4T*H0g;^_YAI~CKwIg z@m-(VMDmV=+#h^DuUqN5@3F-%KC!5)&TlDx@qEBh-_qf9qQ1CV2~wmcC#2U(kBx~4 z3v`K^vSvk8)E3t9gEPgHC5K9c6bG6TAa&?hP6PFZ932x?B|_`AY!Me9(3E!DRT~|* zR0C2(4H+q7pn*o5Xb;s;k6!&+n}+QkzVh)m&s*4k*$;;|uJd_i>Z{j}OPzb~gX5lb zW~J1eUZc+b_lKX?^=Njk?=aE|mZa5Wud<6S?R?88-+lW0)Yoj;3_v&1kxi&*k{PHq z1LpfRzB(+IG}EX#8mtt2x9rez?}7$3wN+%a4z(TWKF^m~2i-@H8mpYKz9qh3-}}ER1l{ zadLNOF$}}krsKeLbg=9Xh78+1*wJy-{nAHn8}+>J$hvL5k{8De8*?~oY4J-l?;164 z?&!N-Z1C8C+b2!FeZZrR4tKrPsL`?q*XHD`eQ;UhhHu^V`MUK-XWTbq#(fVy`lPF^d^2%LGwK#cr>O0M!ylQi?@6+#Ppf7jt zC3CwbUNHLMK~s{ZjlKQJvEx>LFzTZ2(s1XG5d{5kc=txx^TY7=-8p{WQKmy4<)x!)UXhY}o?t zohYs`a*f?p>J_7F)T&;aR_POsK1W|uS6_9Nk@%Hw{Byo>D~qCBdWaNxx96!NEO{r2 zOEbwd>dr6Eu4%Vy75=PwI5M>YLpni51D7-c~T8{~|qhyCl`hx^`k*G>IhbH7~s z!K2%TwZ8f~-@uJ_o%{RFb!~M{7a5|nY>`?0g3Pw9TQqOnuwH7N+BM><#YBb&2Rc+p zMO<60Pv#}j%#Q8oQjXwsq*`Cnql<;j!OWP|9y!>df^ChZ)k_e8fdO$rbZ%g40#u7| z-QA-hOb`J9(E;&62|X9r?~~cLyv(3elo@nFnIb5tN|C25KO`aZn$wldP@M{-QLC+M zUjCG`D>=BY6}Y=}gJN~4(%RJ2emOoM!*FS5+$LHiC&3tz%zixPnIvMYL()E-*1AoM z<NR`?eCzVg5 zz#tua@&5rt{OwN>@z;TY4&~Gt49piOSV?O@Q>W83cC>F0%F0xkOh$c1SN`)RZ9)WqTk?|**r6xv6N)2C@zAr`{X)AUDYGvqV?R%Fhf?f zsEq@q;lPr}DH!yxZN1Za0RdKQg38gNT2;}WG9xOvg+qsgcFQ37svFJp)Oz+#YVsTM zhdin7>Hp+H-_aj^W96s`&%N+ym~X1=bjPIUCj0g~7iVSldoI1&#wlyIs5i@s$31ZW zv(6d!4;gW<=9v^DXv;pw2hF~smz?k7GD&u+E)`1uHF<$e_Y9=G4RmE#lT@NGZ%i*K!L^UE)? zu0wtH!Gc#-u6$*|2XeD3+vkz}WEct&CU5Zlw!`(}d%mBud`DLMet!2QYN{;Wd*FQ# z9p-a0qk|bg3yukn4h!K(pdl+-;#y8dNRH<+?UY~Oa5+iPr54GW!O^5{RO%c27NNGh zjt=x*-x29tS6H~tx!5*^8&2&uz# z9R%Rub?O6wSA-+vL7h5k!o}0ov|wbFy`h#J9c_##yHs7R=9m34!?}2-uK|UWKl5CR z_SPinD)N&ReG#3zvhM>Cf;W~3xp&4z$(2QEdy0&W2MRhe`*vd)BYc*%5QI2{pVx8l3 z!-Z~G&PX?PjxSpJ%KmErg$ ztL(h2EcI2EdaUdr=i;(E)HGWT%VE@5o?(a+`^Q$Q+bU0|Fz8Zd$g!(daWT*AL9Dfm z-AEk~gog$P>8@2p&o~)Bq3{#dTv|hm9MM%6S~%%stt=T)R>rZSd!T;F`Xy`aPfqpO z!}koGs=Ga&U(zRGfv4f!$rHy@bIuot*Nk-#1P$IqIsl>K-4Ds$2mGH zZG}v|=1GRkhz}ySE{h+@${M0-{iw(`jO2GJ)5`9EJ)_iEXW6A?AzI^Y`)I{;o#cB0 z@ft9>A}(h}rX7pZThmSi?bOV#r!_M}-lmimHNBv zJPX}f3T&V&9uUV9tMvL{TWVA~?ma*ofHBG?HyzG$`7V0g*WQ(dw~2Dh{=K)OvpllQ zF<2gXQ9t?^U22>e9Ab@cRFPL~5bY)c)5+0*I2|`sD3SG;49OsbR-(=>wCFQemZOh4 z@&*!mT{*6zd@EPtRM?u%SN|Ki5`0&=DdEY|@n0zwUe>96ANqbZeP750uLz2kBX9$yVv*ptF^IEX{1)mN_chE_r8`YEmc-Us<8=1v&WHY0o_4dqH(8 zTjE^oUAd}g#_ap=pJ(%Cxbs?g6GID|nHgNCcJ;WZ2;w|{->!lF{S!TFp07LnO!z)U zTFKwfB8RBEAGYr~3Bx*f+%e(Dt_%KkQl{OVec6^rw>D{dTE zYie?B9beaoiPqe!@SzQYi3*}H3R+hO(KXXx?8u* z6Ct{W6+r=vm8Hc;?;SSs*2H@2)8i)H<9kQeSoqA7(|udiePxe3-}!dkuvgDXf9KK1 zy9`OGo-(%UxDijy96jd236`!8#qZw-ztcsp%<#0jDanboq9en@s`PC$LTR~@hybYZ zaU((s1GM6qgHruvK+a!Z13x3d$-Al@4w&C;`iQ^Xz|GPIeW20P?37fGcrPtcm@VI9TobSSl&vK z&D0&hbQhG-An6t}(6B@1I#NH12gc~YIXyLi&kVVthATy?FQg;Im9TM}Z_Z-h&Nx@B zZwG-A_4{~84xb0rx{}1g#;%*eRuW~5m7R>HM-Cam zWzxuK5W#Bd46EZkV6- z^Ba0#R;8@*0E>QIQ>$(<)Th|vNyJzkI|KbZ^s#I-UN-#j)kqhwAynU$HIVbWG8sTiz+nzFX0!K) z#$22_H#7U_Eym0lI`+KWktg>%i?AHVg0w&PkK0%?2P(!+f*3ntl#d&%(T5akluxD_ zZ8GHkS-%@@N^$Tr93^feUOedNC6btpw=lD2O0p2?^^zNiFe4VsvJB?S!~$di*0WfW&)M-ZUnsZPcjlq6=%;V2~c3 zK}^~ZBXv4kvqJ}R5aUY7Y<~L7F3SMUl+J-iN7-{90-_T6M*p|b z?yMoRTP97<%9wu3n%u0%Ctvqay|f4WJuy)p+V9(a)fLaUs+Y~{b}=cHBTEnT?dfaO z``T6Wc>r}AfIjR%AFO`66xHK&?n{qDFr-tv!gIHbrq51DB%#qk?C-D?fCK533HwMZ zLyMv4OkOx+`P%PLyNvia<})ZF3p(p@<$ZUu`PJgodDl&R&v5*@An(`T_I{Y}Q13r_ zI4^0&^H?*G)H zRm)}%vWY_nugr|A9xp|$g!nqu>qJF_hLA^(lW`Rpp>txwl%cBG!Jj=+K(~ujx^5kG zO8~`o@2vEgormiLqw(C}-q|^0DH!2y88bxbdQU zrcMY z3lrPT?e)}St)3mQYFF0y$$dwrr#*1>lyY6WqSuroD>m+GRPV*adXJ5NuuE5TZvLvv zddSiXFSB$`GQXIn2K$PkZyc&;uG!qFh)RHcwsyt3{5o8I~&>+ZYyjH#cMWxU?&nvL7bu2rv%f8@fBN4N4s#e94rZ)Q)AZ!|ke zq|G({7>8$D{H*8~>a2)X4S91Gi=(}awZ=@$<-VTsF3OC6qRyGR-w928v+|ODPo9}Z zL#C%y7zWuc-IN8Pfl47TtVfbi&_5fp^iSHkl5%;pin0bF?ppL>os8Py;Vq-izvOfM z^dmzTei#%q(;3j`CdV_fMi%#@I#0pd5b6?Yk2s$sZ<4|g!ZCRhD7IRZV1Mq!;%`On zgb-COy(KH_CV8R9cb|N-P#*M!xvDef|AsHD>=T|@$kzyb|1_g4~B5xbDPO zQpMew`l3{ks{3y>s#lBFnLDT9p95goOG*+p>L4zl-)wuCKr+)>%jr(rIg^CUw2F%Y z>9cBz>`Qg)Sb3q-8eWLERLK5}tx%-OJsmZ73U4)k$dH-oEf)@ZWkuE&lxxQ_Q0~s)Z;Hq>CyS$Jf90{K4<6$Qpjn zb))N1=ebwkkiD(!Dz)&*k=-vix|3>R6SM)2hSc-a`5c>xkbq06NLY~C(?bw3+PTw` z>v2(W+>F8j(y?o|bo!3w=K79gJ^kdAY0pfZ^0Z3#$~L}rC2^&`uVt%}MY*|);@;S^ zhZF=ck*~j_0d>(a(S%dAy?D>&w7Vp3nbD$RiFbHmM~N*@xW%%* z6GJKJ^xtOr$@17pyBJGbPKb>ft!horYB}{fVvPxt zFS|QE{q9SrOtfQ-o)${z=QqJpItYZz!-qjn>8X*Q{25X=1B82z% zGi@6WqVr+*HE9oHG>2%db*9pClb8c@lhbrl>Az4<2+}9%0qJ(#3W)74sbv%Cgc%ib zi;GuJ-qP##+F6TZnoj5wS3k^{?7~=&INHy;vR?pRnK}+49$HHs|7ZCmtK}`PkdEOn zlZvUuRRYwCiN*HB8LRm<95+q+JbU;1OY%q_J=kyXpuSJ6-cY#gnUvkd^E12FZa8DqQy*=f?7DS8UubB~n}J6dd@d= zo$Pe+#p=kBRoc%=-sUEpIqb%Y+cTLiRW*NA8L9SMT&GVaBfrE1PAew>;SOeeL2}?HP zX`5&JR%OdcPduR(m-U`GQ!PHSNrwd|ywaz~WV>%+T0s{&>D3ModF* zdGSB}5uH=S)Qkpp9B&26XszOPYWC1mJOe=16dq>nr0D^>PLc!Pr@CbD559H{UK~@s zN409MD?&Q;PH5)4BS$_x(KzQw($IM!&Y99RtjlmmU1;xzUM!_Pe;`L@c_p;=b|cQ47%;MK?}aBf5*SBV)@q{ zzGvHb-^d>J&@&GX-|%K}n|o6~9J}GxIZc|*9h5!xeNF$Np=j7@qTU3^3 z*BE!pkXL7A`AS`S$Wg>X(+EFJ`sXT@GzI9o$3}!Rj~tpL;|>-vH8n3ZO`2qzCR$#L z7MnC38*5rJV)djwNQ)iX@7jL+4Q=q{EB}wW_W+No+Wv;mKIhDt6w*m2B$G-A&4dto zhR_MUh9bQS3W)SxEc7an00P35CIoDtsHjX7>=QeY`y-YmV&s_cFut4Na3eZEq>&zA4^(DPz~X#!FrSaNTw)=oH%ZTdcx?i z>huq+d!X>b!-@D2vJz!T^-+-YT>Zx*O9pN1*J5OL+hMB@Eh~DsU-RLO3r47)KXk63 zOQS{;3&S6LseOl>2GhEUxN;1R{-_4M3vXV>SFnCKd!)1Utgf>Nno0IZv?gkebBBS_ z&jJ_^Vqw9r5j$Ji3Wj&VA}yt+A1O6_h4vl`eG5-wRwF6`wTrfN$mL_4;Y_JrD=xNX zM1Vi+HYqH{(q)|;BEwai7GoN30{uX)p~qIS;2`}M5ExiKNNj?h$B~HuaxN|^{Uf4p zEK3fB*`y0&jts-8YR`F6)s8PMJK-vOrfk(gO?%R^=-8&0C4To+BCGRe-E*vt$8{1)Q-C z5EJ>kVDkXL3X`F*njqnZH_t!h6Nx0jfppkm3HgLJ#5UFws|@Kxdf{< zzTykpApIxoOG7#jgy@W_saKxdW^pm$p)e3S;zIy`(2`-sK@gV~85;)Dkz$vm1E(3s zm@KRE7+dxl$v6?WAW@xp2xgFa65<(T5LC3C5hf-)SGaEV&fQLq8FR95$;uVkxy_nv zSh=>#@!=zm7j9VfaN}mVjn=FxzxSuZ2Y>qM;NhPpwJvDWYT1faU7s2?_Eh)HD>vk| zYTb16s%_m*jv4tx*R?Cvxu^Iw=6~v004RUQsA^-sj)LYyVU{su)u|rj=Gm<*K{z7) zN%n(|h(iU#l!nkB8>!m~(0K`#0OPMsFa=^n@K@0PARfXTPXB|C1j$7|<3m|fzL+iK zi(UL7f>1$Ox%09Xt8Q^;&wXqTf0lKa^VnRKE{Wek6fO|IhI z%uB}J@x$ez1KPD?H9q?a8mo3{ z=c@G&-~ax9FS#!@?33EL^Mmg-?c(Uvb0a%CbXA?42S*-$<;_nFb?pN)2M->Tpa1N! z!K*W~SC06{*-Ph)89QeV9yO|Y`=|QUhz*Gt-G21A7GY5}YL03@_%2N9p#G&cSnwpf zl2M&5Izyp6(5gd$fLFx~&cSuG(Ulzh@yERG#~K6m8SEeJPpm`O zuhWUad8r42!NIzn7D^g6OiC%qiU#xqPyph;`T$ig-LdP`sa-pc>FS2TgNKeCJ9O|M zcMUe+w_jNi-~a1x{J?A^Kdr+u*iJrzU*sS0k!oLK%Z>|2WPihf3kL1_+&>55L@b&9RuTG`S z1`%SpQSe-=smx~J=plFm?iZLr0j{C*2v$TiRMW(Q;DQJfGEA_*t)>(?bE-UxXAsK> zwt?W)8}QKobnL44;XFNGY*%p{5Xz$fl>m)CLGcSU`WiT5DjgtabHBtCjL7trs?)t`jUHmW__+3c$J0 z+4C$)4>5Jo)(PV_ZyG;w%hJxdjXQSA$?dG4o>)>cank0^lkz%s%F8P(#Jfj9=((o< zf_I0&z75-~Z=AWuKa>hp6{ME94fYQXB0ITgiSofM91o%g|4P*mMFI?{>)BXde2gz; z^N+FS<L|~fQd0>qPkZ7+*StX{o{Wf%T`#LP~
v%Q*Qgy;tdJj4ZONjTx zQ>HOQriyD0-Xf!Pyn-IgkT~x^E`-Ff{cYQHZr`;19@RLo zVEz7%tvhsma>K%>4EAVYey6^jJ1^6xHfx;Kyipxv=**dS=M9dF9^USrdDHJP8Z>Ls zsCBaiVh@+LW!aB9LCV8$fXnK*--X!s#oURC)on{3}3yd2+dgYEQZ zVI!DHh&9+%gy)Z~H0Xb=^G!zYl z(kE4 zEVV|P{yR6?I~8>rkkmM^chBL|Cf{*KqjdWN7|$?u8(RfBXj77_#KwjY9?BCNn=DXe zaAM`Au~kPFviit^zxIAIE~&~a^$9HteUQHcsI6+TzLf2lrh+?I$%Hfs$`Jw@Sscjv z>6<=b)~OvkPd&F|=kt#j_3txqP~W~q`ixD_J-6w;%_mQ8E}AfLzL%z^4wB}40g#2;{EX%*_T7)*XY1D+C6U|A85YNl!=0G-m1T>YNdz+rqDzur{bTWm9qSj^Q za~hs2k?+IWOye`O$MqJV#kG}Xbn|W;i&a?K0DhWa90mqn5A7fN2Z>?OoC(r_myj3K zyothM2ge2cH1%)t2yGqC87VT>vruHjH4HYBEf7*gVnNa=E)gW2a*(LY)kb4R_n9(r z(Be~?`qdL<|6FxnZVUpr)Lk2<44$!IfG2=!;e~0r{fDrUcg4Dj7#({d@|~s9swi!h zpV*yZ3g14HGy_G{Z>8G!!O_A~sHp1*@gik*~ zRvTraa=+|Htva52tTsqykj)NKKWKAM>>y=DRO}Q7K>q6f&YIOT$5=AFGdG-YI20CY z_}RegAfRC(h`ad4hJZa`H$hMFy)c1fGR*-qGt_GsJMfn|v<&;Q^2H(U_s{-}M24@r zyVX>?yH7-^Fa3F#y_jfYLpf60l<)>6?w{FAwG5?nl^MJp#rt3`>0kpY7F&1JxU}ZF(ij~#+fl*W)Z>RCdHZzoVRmVdWX4L+68jonhdRMfs+7H!N zQs>%fJhGpO6-mD1p$micp|~TWbzR8I4xtgMYlm!e--$aw`()h#3QjDzrmw|7~?=7Y!kVxU_*kTf>2a>ImF{( zuTNyC@B^Q6q@!_qL&l_eTt$2>lp(pi{5S%ewU|hjePFN!jx{9ez`@ zJ8B#5EA=L}wxU5Y>lA<8_uCZ^?GX@?)8L^``(9qm-TgK+X4?|Gf+dMDy@+H(A^YmaCSbqNk4QqWj_;@XMFD_ z&O4}xe%amuZCZ-)%wPv_<|SP!qVt8@`zYFs!2PWO>9)NyDkumU3?hS|RpU1zp@dh& zW-{nH=rvtn3aNuX5Hbub?jn3oNRC4LvSM4v@)>~-LJ2@orJygF&da~#zqnj1Xe0h0 zi16cYpMT*S{wjWINJA-h`bC_j0hzIcCs32DMU|5W3lX=LgG$~1g6b|3VQH? zICWB>GC2k8HJLYQ2TtOJc>~l_FnS=cga8IjHnJw9eUic~m{enk!A{dnUR{3RGa(;gv?eNum&Mk#FDdCR83s{ z?5s2mj*xo5WNSd&0PF#%Hd*6>5uFa}Goc0uo*m=|m?I8JJcH-Vaw^!cP0}Ing|0TO zYQnuBz@dT~kh9VYYt1a2sIA6>?-Vq>wCmu>tDk%^e#E#rr&Qb37p5J}b{-w`!GGK> zRJNmJ-16>ib5E6b>H3eXE3+OLtqqyFB2Z=Jvm!?f>M`lamK}!&Oq_jp_i$syQ@y$s z_TlB9&$K;KmY1`lUiabw%|5uNXO}y*1_zeg66X|)Gcba;Biu69wu3kWb68#~h%z6Ug`6Yyk>z@w6Yc~z|;x)(c3&1N2}2f*@ozcY%_yRs760z8#+7G z2IpdeFa40;(>Ub!MWcP`hxlI55AnS+v7HzF0Bz`~JgL{$kK-rGM1cG-H_Sbjh410e z5Y{|Mho*#xBs(^;FI)N;sb$g=4x?Tg>K};>?i&Cmu-?f}xNvO`EF#!&w*Ef@9KcmLVsQLT(ark|SZ2uH1)5-WXMBKjA*u zu9GjU(lalbH_gj{Ozt~xte$?w_!Hkty?&~4kaaQT`YyD%=tJ;!+X=KG{%`l(Gl! zNqAiO9Q|G$Abv0MU)V{nk^1lqRG}ojhV&y#ufcuS{s|MO#j|Fx4uYnDGI?YY*$?SH zq94ewXNAr}{a8Ab?1$(M@jjfb4n#N53rRnizwCqb9@$4f)axTXtXdy}_D~;oO+XNdRoQFgGQ=3Wdn z`#?;OEy0LE8>}%bYNNDIZE3QNEsfgXtp7iwD`TXXkNzy~Wh~~r&l#1LLb!Pm`hpy9 zej@v#PkddAFy^m0l2ku`C1V}>(CakmOd_c1+BKJ}d~#((lm7Pg zJ7gqNqzr9h0VPL{l&|oPYr^>y_8f7?rLAVFvRd46I-k}Zr*n1Lb`ocT;Ld zcidl|acL8xdno$A9e+{Waq7dmwC|gvJWy4TH_El8rerb5*^cf>a5Wk7AZP;ew#cy%O@Jwt=+p?lisHA-_tWoxgf=N=(NY|1&lu=_$T9R$ z_KEvJW3cXroQI!h9)0@3)<C_Y z<(q1IEMlI7U7^rylZ4dP@*K#Cso=1RZ7pK%QW>Gc#kR`yqo!Alz9L zlZ$H{07)o-;AyZc*^x>_dW(e4Z|08#uO+ceIK%%qr>s9y?;aFqNN<4Dg**#y^NYT*UHaP~0@#a+ zS3$_<3mc-en-*0#tJ)AN_MlCX&5ivMx)Lj@h{xIqjuK#=v5FVbW}ToP(zZIaqFq(` zK^5!OyKH-{eqftRtoX0o(~AGf^88KS1la^nZwX>rPDNZ{`;A#K(yng`0$X zmA7VB)SuYvJXded^VnINo4elwn>Fb~uAOLXLmC^ZywqoL<~qcg z5$yW{hVYQg!4gviiX~O!J*1-gP%mr8q~cA8nN4U#$(%tz6qN zuYNw#Uy$$8U+@~w6@^B+^S^7=VKbo@Qtm@Ji4#@EZytMeIphq)ns=v**Gi zPZmx73ngWmJJ+QZ_WwtJ_pin3xQu^fs4%M1vuRlCV4T-LrJmCW41oXGqO7sx{_$NrHyaCuerOGI;+XPChB!_O|A)gFMJu$t$wa% zN0v4OlGVwEK>F91YO?x4oabv|ZACxW>kq2!<653dafVhuXw$h`8_A&#;c90nB#jEu%^2a|NK4nFh(hKhGNZ7vyXtg zl%daxd2}|227}NbVj@8=VD*uR=VCRn`j(wq;MY9}0vUPaZR%|WG$-9YB&yQCKU|#H zI3YNwU0BQZR>mqM^|(f{u@Bq)#tj;%o9V0et9pOA?`uJ)euX_WQCTW*BdBjH^Tm1R z5ft%g^+ag_q!dMnlxez#ZY9DX&9EbrpM?Wggv<+G%@KWviW=rac&~`J6Ol@lk4O}b z#8)GkoVPW*GOU^92Q}F>=E!MGG`Ci8P}}fU?WRrdH#Z%`_~Bjy-~6DwoaVaAW*=Il zDQjmHv?zZYw2kPE^n-<9zp};onhG6t81|g}*Tc+v3AsgN zstgzniVE;ptszN)=@AAMQI}otq<_^Xp(&ZF4LoPSHxrJ5j;`#3K9Tc6d@{Ehk+K2t z&W^G(Kc8XTtTRG!duHK*l)(=Q{LNmo#VM)=#chCi}4mbkCg^!L{n`UPIO zz~A}+VjtP-zA?VXok><2!HY1)Sv&g9}`_OJQyBjC7C6AB-G}i z%-^0Et7$epNdSNW?$T}k5DO9zC?d^t1ZtwZ9?}QN0&u-x?xkCAc@4}25>b_&0;w>< zQy^7G;HJ|l=%&(HF!+Ht@|~^)h&qNLZ_#T`=jkav2_~+$w}O%NC@a^*xM4%bBOEyj z!O4?`51-_nb3#q`1SzvsGW~=}pkX2|I}B2i4iOSF?kR#&|Bmb0hl! zjsM7p#w#M9ny@i7G3T_YnvF@s$cj0EpbEa#yxN>(Kcp{;exMU=s-~mKen?-Weqdv2 z?qwaqoF@bSf!uCZAE-IEt(yO39B)tYx@I4Cw8^jdUGlYx-%T1P$3iwHIhH=a-&D0R z$+6J7$g%Y4<-0Cv;KO?bAI_sWV~-|PTmMEpj^b|72kdp!M){QQl4C(WF{$4|=Fs;F zT!-ifd-RB}T#k7oepmB1aw_|Q6zP=x*qo-UB>DlL4M85)n(u$@J?BVN@h7Bp$$>RmL%0Q1i6bsVQiu>eSjOY>W6si)@r(;?1wO4vY-BJl)!v33-g6Bi++UsE&J)O ze6RE&9aAmsBaW0cuS$Fbcyu*<6ZNCFuJm1i-u>6xx-RDhTNUyS%JB$W)dBJQmH2(O z-dxT_*tLg=-{UMBFN!+>xrKB;wyD~k5V6z3H#x{`Q>U8Gg!G5Yf*uPz1!&FzUmFYN zD19E}GZDT4);rDDXCnI``;+KHnW!w2ePAtxod$i3z<4te11hfKq?Ouf_eBmD^#SBj3PBWG4ctjHdyR$jb;ij^U62hlCJ86RLL-yrl_Oyp zW)+Rdut%QW<3OIIn)PA_4Ax(v97*eK#^jOLF+SLlzJjiQ8t+O``ca)P%8^QTuAo4& zB6<9NP2ylaLYNc)u<#O7W+WJsh&s@lu>+tR2=0*yQM^QIax5W9fsZUrwj_ZY@s#<< zQAeCPRGic}KDb8P@Rsc=6FbEZ=!?8g*DE~wgU-B@JYoFE@kI6y<31sS7C399IBLa( zi5hJl?{+4o0>PM#iVq1>KVA@qW48dlSg&zL1*ut$CocoNxM--m=5{j%f_!gl~k~! zfA!2TI5$MQjR8g;*6|*pTgEH#baFz1P_oA4H-)8+B4-+S44?$a4S?Yzo*)X`M;Ht| zyFgi~kwd|!ovLKru${oPMMCxz$YT2q5~CXZhrFPvXP)s%ka}E=e{{a>rC*ZWtE*>9 z6?rgh6ZO|&7+o!LbWn_89Ldm>`N*(Yw?ODGjc@^s*eE-64P?7Pst(o2Lf#u>wx^^A zBK?VkRS`E8%8Rq{tsfyJrSe>2MNDlpiZZ5{XdPI%Oy5k7SOME;O*{7du^{g}8ph~; z`s>EA)4}D>R>`O_O|>st0Glk?_6lv6Jhr_)6`iZvNu@v4FAel5mFOj){B5M3sa5Kk z5^r?{ZQ98;sGU6(R7}-Mr&>HrV4DSPevsNIGt}>^$>fOjG>V0vV!zpDyTIdUtki?Y z5jacxa=fcpwgHBed;>tjGs`z1FbqgOm9CIzME0B3h*kDOo6;z2Jd=5-w+supaTb5r zlnEcEM&Kvoc$l{gi#D}={Scs;SVJ}idVPqJcSHJI+cKx9BC$85DWcSnrbJdTVI8YN z6xkFrqgb2p7VWKcV!~viZ^Tm=*Dh@{8w);eXwWBc{|@P&Yhku;aKzeI%|9#7smMV~ z<~h7tg`FBO00gVVJ0mDJtu)&yY8D+*voarwt=Lm?^K!JX-5WRT`fZl(j@`5=?mK$d zD!fa*)w?i5L7(bD#-*?!>s|DF5_@r~7&G6MmlJ7A$v|w2YvVy)F_ZtpHegfuufGr? zcCo%!{Yc2tjh#3@#QTB*eexv7f>OX63Sv(5AAunx<3ds~a~D(c$;yB!^*vSJ^Uw<5 zbhotY(y4>3)R?|u!*rvdcb_)s98d4k|HJ0seVTGRxim23ITtVL{~^P^s_fHep;D8K z14QgfwK%|A#;#Nk0^B#QbEh$5I&~R4x_)BqtgPBe^=!2|jTq6X^WY(!60_Zvx8NPPM$*)!Xy{3nKcNZ8EjdH z9`$qL8^k$M2eceEd-lS{!6cRW$BKGc4J=c*St306pTWe+e1w9^h2B4S&;nh7^ z4#bH=Nk6!}@M<+O0{Nn#M<6Q-tciHLz%@e%qn}}&p**pLrKv?uN(^1~5$Gb6#e+ib ztY?KiFXu*WDaMh4YViQY2vr8EibNoG8AUAQ4>C!}JRlU8qP3bisAF+XR`W?S1~=W` zIJ2eg{h>?lY||j_&WDD!X-IoJ8fU(X?R(g$0+h~H{ou+>%woo&5F~KeWw3?J$QwsT zoqk6@U{oUBo&JrH2|g%tE71wUugXNA+_K8>W@1_6dn92HX!&^JrTLct%hso@cv4yq6j+{$ADHTMnrl=Ti{(>7w<6C zrw1404;tt!7(B2}t+@2`xLS3-Zqu({oBZCr^W)Of;%jF>Do5$`tNM>zHF~g)O55_s z`P_Qj`z`_{MNAZ*E66R{xEJd`@SR3aw3*?q!)Ih2>wDU4BM|$dpH=$5D++L~p#7CY zA;ur(9;{#F8;u#b`)w^6AhPcu)ZFy8)|V*ERz>+c)m)--hWIi}j?mjPyz4`giE;4>$_;zPz6Pc}2MI-s7-);sE8| zd+jfiQIc^aSJGb75BNu%3;NgGdwU8)dS=Se%x&r+eqQ^6@f|;@=k>3E);0KVWOc(I z=5EQ4@~DcLn8DwS735JDFY=?W(IDQ^e`lu*JNl?j*W}>vDmt?yH0Ee2-@a4Q$FTFC zX#I90m%|w2W&A`q#N3BjX>h)N0CY8jBkvWpZddXl@7OPenW5R{@Tw5$z0!xX{i>`L|x z@^gSNqm_mP0GOQ!^7nP;Aw^4?gQchs98jHq9sz2p1D|40J*#3p&Kf&mVhr*eVlE>v z7v!K{ooqeM$t8ibRwU0DcMNZgWth!`0hIpQl& zdjuF6_A*V{A#UxiJ35#dd4*0xe@^Q~yIvG~JV)il8zUZC?M=794f=OldK2Km4- z(mOC#JJ#3^A7=GR_E3MIek#BUk^Vy@!YUk*!YBz`3UZC{5ogt?gKE@SedBek9)%9e z_fY*BtX(7Pv+zS2^hT`UTfxwn5+OA7mo)I+$hP~3GoJEE{DjT}FV;m}&r&mLV4`*!s-P*b zP(U&E+>WX<1lhyfa{U<@Ss_jS#@lMhImp>(JV|@UovyLx)z{q@Y$Y4j_G2oh27aeU3l6ToOG%IfiV(I(3HN||85v#82C_%($g7*47v%(XeFXLWdRPRSV%x; z{iMX`D4o(;k);LY1wmB^E`;SV$u75oM!@gj^JDj(lA3xa702jC8{W z{$>x0j%uPczRGg=n^#?5@;6z|moE2}W4jGw*Kuvy@g0V-<2dLG|Kj4O{EB|zg2rln z`Z24mUv@ioKL?rm36(v+^O5INcQ^b%^DDsoP)`H%Ya#XkmULS@<`=6_q;^brSdBnf zm@S?h9UT;4*4IF+01=VO6HXdC>8}d;is4!jx@sS6^45|+~V_2PE>GQ$&YBKE{&cYOoi|W&-D5%e!lI%bo1Ik9_hk}cy ze2@~1OGW|$w#6bEq@B}AH;Yoyil#N8qHW}^f}JEh8fPMha-GQ}Ca9rn$N5k%t={p{ z!2_pvujOIxSu5eY`-A1JoPp{?A&xty7xn-Dbm1A5+tYEgMbIL_IXGqCnEc$*F$vXt(Q?) zCa$FQWZX407pG zY65rp2xVlGb-QcDMb?d~OZHn}%xYRFK#|9^nSr%UMEa)?hUk9)0yV^LXcRSOS`%v|@+>hjDoJ^(4lFyCl?BKQ5(EusoEjlx9if()RV`$>?_sZeJ9@y( zeoB7_}%a7H{d8_xbFw|me~`B zty(*={N={YcP*N7xJ1yZ27H*v9UBN6dH~h>Ch5ULt7_Rm3uNMTQXxgT7h$G>1|{q> zIh4H!Oc|M4wfM9AAs4^@98-`@R&QRea|ioeyXLlaC1@SaxWsKxZoE_=ZED6u!xfhh zof?yh-$d02@T%BV7uy7z44iHdo;5_x(Bnjsgh|vBn~Ae6jM2oMMD8RdMO1DG&sWoO z;aCT?B9u1KF6|(1uCjZ_Op#XH_fOhY{vn&WdcE+e+e)_>{F}nx9yX1*Q6I9b+RXTN z2G=ehj57V`V!Z_2(7WO^-LeLJ0?rVkN$r8S9k`*e_ac;xO5)PoG8IZmpiiEWx8tt^HJRF*$>T_vi@1s#(z6;?)tb< z1BQQf_L)Cy>a#0HPoF*c-gnuj{RVU%J*BI$=g{L@1}{oVnbY~CX9Yzjo+oj*b z7|gxANJAw~#R2(&>`D&Bk(3w{8DRJ5l<71bnbVaj!I8KEH4^d)t&hAB5ZL6t0Pumq zw?MJ-NTj=v3T76gIfUo23`eeZjvrh+b;8)BN1jwmCif~B+IvvrCr++hhd504dRyrf z-gDcP_0#WLxagjJ4HqW%@6fpU2m5ESHV0TE8y#PaSI}tC%?RWt4#jV7mapD{eDtt? zK^3O;kB6RW`UPN67RlDhwr;kepirE0*%EyU|AEy`ChxHDPhO=QB(<`4{ ze_HRbc7EHIwvm!VeC4-m;)qR?vYwkA$Qsq)RfW#{p0!=3R(7 z6pp0khEWNb@JN(MGBG8HuBU^at4Ccw|GxYB`{&*6bTx9-qJ=BeNcT6Z7c5$#s@M2u zEa@6M{3}c5|N3?1lRKV%dIvvtWXFkTc4CDDU(=i2+;$5ph|E3sk7c`+TmXxSTWQ*E zMTmrHKMP|ka_h%73a?jxVD8L$py2O!ZWpj{G?NHe6U;Nug zwoaPWs>O%MqvE$@_|OR@+qcbnc;VuE_Ts+x>(IF6mDkq0>eX3Y)NOX15;`M-hX6Zc z5Z(?0?t%M6S1VeX=?t|Hbec_UZ%WBek8|F%8^y zsv(gIIu;5G1pKq|v{QZz58cf~x?&PT$iL}vX9|QSop5ww)qfDA*Au5m`L;Zju`C%v zPyN_6Vr!m@vC~(6axGgqcQHyotX#$Z`whR`vbnoL`;1*_ob=IKx324Yb&v_(K z_ArMGnL}A^_1sswdVJ2b6|46CJ^}Oo!?KwBLm@%z{@{b%VhwxYu2N3@ zo7ey_CNK(YshJkrGJgn@Rjxz(gcrN`E^Vc@yL_0o8$^@#Md%plGg6UtGm%#=JQVow zs&z9lQ<^oLY~ln9TbLBjk-j=3Cki?K!BS8pf%RT--$M^*1$l4fIREwCr#~Sb-1eh; z+@%Yc`ruvMU0lIW{Cr&?XCt2k6n6YR&9XuW8sbDvV`LOUisBHY z1`EY?MAC2u$%xsI4^*?;G*B6tNCI9&Q*HnqLB)Ap4+rUlHwUi%c2&DEZrP1t)R0sd z`zE?V!kfAxi zBG{bR*}27A>JBl!D&vRVaI~%)91x`iqy|l2nY+;7*WP6dA9eJXJWcPsYtp~i$L?0V zW?>Ii+iv(TS;OkNFKWSTNgu)1u=|5~x~&_|O#<1@u_M3}L`Q{%!i#CyC*o>_1B*v) zIub2O(nQ=m4vgugD`@(5juTl=FPB|Il9&VQ3`ibB z)aakK&u47;M93UJ@)x2I^YVHuPFXE>mB+mOafFIQcNiZqGsbX?ua43|@X$I+9jY)K z6&Z?*19lJI!I_pw&MZ3D(27` zp-X>#%B;HO|i*peL}I>ZOp8 z;}DhA&l#GQ3ba);<-7Neb#OL?w+`vPBGX|}LHbl1z`aH$<^?8+6GKKpA~0A1$j#ow zT_{x&S`{htQ^z7GLqbNi_(f9Z&POfB&9; zhnE<7jn;?XK6i{8{A+%U4PpN3Ce=Ohwes)Y@wIMlR(y@a(8u>^~v4-E+feyLKHMOMnpSV~|P77TYexIENdW>Zmp8)qL=A%2CqNING;39=^N zvb}IoApNEd?Q7gdd++{3Z==0;|KYdM-n;*rx6$6ae^gw(<$S&SM=ZoG+gJ8~>$aZ0 z2bzCi8AV23%IRVk1kx^yA@WD)y7UE=uu-q(%r~+)KU8k967!0 z-cbYkYCC&9J%;mVW>3Fw7J|FRJl$)%`}cuQ-#PT@A|hOW{&{rI_kupjxcA%2he)_n z;oAhpwF=G`H>6p`Tee-$d7>5g!%bZv1P*DBzUZujO7I{V{!H^ycIaNgJ8NRhMY=$- zCcu?LA_2)JyF~-Yaga>lKhsa}q^G`Nb<|g0$XPUnJ^k=gW)*WjxI+141;3iSDS5}e z8~3_%MNxCmR!}-UiSS*BN&w9R=1Rs~5N28iWCJ%+@hxoiWssmoI!Q!>-6b(WN+Xi) zSvE>%K2p&R3-z4gLA6RKl$q)IOT|l*M+YO zB%jVF)q%E)a$0nIi7P-e5Mo7Tc07j`fPmQz}(qzSkn0Mj~IVA?#V%C zOhiOPd_-JSO|!a50L;d?XV&NoOVf*-$@qo8AAFDG>_Q+1uxFIz2nGg-M6$9ym{MI3 zX>?Dw6rhy9ZV%?Wg$+5jKdHh4YYY23-l+^RdzY|G@>pNxqHjD0=CPk|6F%#|#JFg>Kr~{HVO#?y!rEhyn+TD+Axunh zzYB}b3tYT0-1cAFqWQf6q03 z+0t-_*5lRkbwRzlscU%-FJWUi^8T~C*ig0GpI@tI|KKHe>2u9-dvGV%Q(QJ<9>y67 z-39_gWtAck!H&UMciEW|;fLxcjI!_G*D!+O!Xb$VVIus=7z!dJ%)KHcOP0%{Y#qol zfckmbf0~@h=Ocb)Kk#N(*|Iignz3b9c{BFIuj+R9X!@(EATZ2L+yD)=GIOHRKx$5suAhBy)&pyixr<-sr%*SjY{&6) zC!T!fnIrq3I=1?yQ#gZndOfX76 z`3SEU_Y!MQG5iAVK(y0iL5mEaQ%jlY2^@e0_TXQTn=UMa3NM94>$xaM>~4$y5c);$ zuU_A8E4_XQ$_DmY-g~;!;@%@dr>^gvmgk`=CP&=y5Y)FOKZ=N@p?dc!Bn=ZSKv+{c ztEAE5o|_gN3=^huY4OKl)j|Q6CI%GG2(9und+UeX%oTIsOT|D1iALgP*}?@F9umVROazgaz~9U+}%i@rC$H1G*zU?}J6b+6#Io&i&u2(I}={X*LtY z#JfhLu$fSeMzv`dgAMuI{X^4T#cifKVjaU%dylN0!DBzw>@RBLujkKuFe+qSKv=)F zeRLl6Mn)VJ+}iluC=mp}~0}u>e&}NSH<0FxnN9 z`qJTX>?Z2_yzBZ&Y{oYL5&h`?Ll9rYso=eD;5`xWNtu2$Y31eB_x^Y64c>U)!dmg_N#d(} zF#*aY6sR;2ISv99uf&cX&Kiwdk2gzv6edoj6ZJ)yO5LXg zSBrF?mRt>eYQ)EkY>X)YCm> zcHkKhYQ>5JZ^leh{MC$c~g+ zoj<~VtrkNFG^*YN=Zbvq@VrwTil_<&>A-W6AeU(ncCc9}|A{L{9$`|q!1_FhOrrid zDKL&uxj`Y-GKWNIINa~D{%ba}@SoUwF8(}#w7+cM^XN7fqHfN4;lWow2HhK>KDlzv z+^xi$L~NMwWwsN0B5kZ;N)lxH9aO81uu6^w$qnLTqaq{1P!cnVC0Vpd)MaWG4O>9% zgkTMlBY6cy3R5rwl6mbg^hg^h<|hsR=0xD(g8u-ShrOPK3P$CaF<l62Vgk28B8+0uKHwYmuD5@bxEpru#}yB6QEi{RyY+;owK&mc^}2Oy zS8v#;cjxDRvcNZff%b1$W0n$R&ueS!T&U~2cGwDsm3Sd>G-Vz3G6l9UoFlAP4`)G$bSSfANoA>Q8jGah64nM}u-qV&2dtS8d5SFJLc-zpDET#x@#Q z&~I-K({=kL%se0z;c~;xqBVveNZ8-JRf{ID6IUL!s#=JebMNHY_l{lhtZMvu;*AmkI{9?=+6Cn z?K00C)vv#`zTsN|-Amul@}O$)y#|6-E2mt5>~m~2*$}oV z9VM1l<^seR;HLgRl)r8%^4H}ff8Ed3^Vi99r_tPRSFaIB06YilxQ|5ZK<@V}*iXoJ zr32STPI zw;{nKD48N|Q$Q5j2y=yyS)fDX3PR_Jzz+Y0eR%Rge#CHb(C?-wcmIRx4#87y z1+NqDrv11s_8ZlGy+r6rE*C?Ln&daKPFc=MXmKP&qh5uuIFMYcU3c-?Fp^z%k)#gy zdOda?uaNg!jlLX|4 zs$W}GyaA>ISQHlUC<|Fh5K^_(;0KRu`tN%`|NW0EPyI(%pRlTT8>{}wn*68k7cB3y zM-5NaZrXo@$Z7B1d_8ClJPU%w@geoVc)ZI?T)=p&sKj_+O++3Lf$T)NX>59nzm_g1SduI$N|R*Oj+r z_-mIw6TqV;s|S^RX4|@cb-!6@fF7+{cfCH~-S-0C-DCBGF!9=$GcQ+d;(oSOKBY>J z{F?upa7pZ16A<*TBTxR+qn-N~LM82ey;B=Cxs^bB)47B-R68%$Xt2Bse5bxh+=biG zpMhtI>20Q@x3_NcdP;m9CYR);@C$46*+MT)NnsRr+EI_@NhJ?Izjk(lFc=*=cD;pTdCUpC)`|Nr@nHAijN^)mEMSlc7UgZSz1>dl~Px1l$i?=5}h z&vTV;E+4=XSZ};%xh(I+-;dQp3XkKqrG?b?ORy|{z0wb`~}OaVd?h29(zA|+5$m#U^W8_4DdG27gF zik46L?xaBx69PLv=NTAkAdp-q#`QP!X2JZb z>CM)7D)o5y{p9+f=n^fCH44uNm@*3V`U>c^L*nEq-i$qpE&G)*e@l zihq0pI`Q!{-`mtD9vHn~g`dV3vW05EL)sH_1{ft8B%#rO)8( zZG*l{_{<2*=y7MbmH)@e-B?9m#>p^t8V*`TDo z$16fB!17k*a-3vP76`@ES(S2c#Yu=AeO>Km|!Qw4Yu4*9zr43mTmE*DeL&Z+?O7E%FllbWtY|1{fpYSF2A6^G4GvsEcrd3@_w;P zU?;#QC}**&UUB2tFH8P%C=*H3{EPeCkz_FB!O~GTkHGp2=tg*EY&zfx=o~9SC@mn% z?X(=8YfO@d=YHd~lb&>QvCK}9sYp0=BhhTxa)79o@CB-E+49*%RYbH?58+0yd{)S? zB7dTgG5d?pgj%Eg(+1@N2X1a3#`BkTqtNCB2R`>0Lb@=-B=^6{mxX^CJkbU@B zUs5V8HVYj?eN2v2-NUv@R;&8EuYuNBV`QMcARV}i|5tPQZ{nxL{c_1mHE*7aIrZoG z_f>NFKUebd%XF87o@;|&o?Vr93Hg<(=1vg066GV5`m)kiIf5G@?wcp}RObAn9Ey<5S!}z|YXc!~g5pBA_fqsc6c-8?>P*2nXjKn~*hlOK{%|2|kd7y`J&31$ zA=>hzE`C5tU)Rg{b~YL(Lil6tbzm!Qsf=>QG;f-72SQ1*>Sm@BE;A}jpcp+gur*Mb zy3#UUwd)P*fc^zRoCX0vup0rCaN`4TuF)sXHK7?H=?hXwZcZzjj|iV>|CW$g6R2dt z?2vU@1Qt<{MP!PpaG1HL^=`Ry+J1<<8J}Og_gL%vW79t7U$C%`3g$Fvo_1%GrMnL= zA2&O(OzmA(YtDqFNA@hq8FKYMAzIN8U5#J z{@zRF&ibrtaWQ|gUYqilScB7lMpMu4wZrfCryo$Z^13%}!`Zarnx5A(lwc<_O8NyJ|z3x%% zUYke?kB(RuR0o42FE3~_RsoDlKy5^XJ>@=z#!(5UNQv}#RZMQA!Eh?v=4$t=m5!bd zK5$*dM{@S)-99BxkKV21wb$I=Sq><*;$v~Q3Q-PL9C;7TR3G6l zT4d;j7hJ3jeG~$J6Fy$Z)=f%)UVO%#V+q$xd9mVKV*~s_natlAmsuw*#Q}N1v-hy{ zkW^r0lNBD6f<)#YfJib*?&lw12h__G2O20mD=L^FRy-g8x&eS*BI-(75b1o7hzqO~ z0IeNvvm?<#Kmhg*>52W|eevncKi=8pf7%iJ%2sc16<}mCd;r)%i5!FzfaFXck50DY zg)!8>;|{_QK5rom&yU;svYiMVAEZMH;FY<1izV02OC%cTd3Me3sGNlkWeU4y!FE_NMpW z>`;WUc{W?sHc}S|%OU;1WAK7xrN{D@RAbq4)9Q8Mw~%8l*Rhb_ zE||8j<;y|c^4XiVl_#Wp75W~}frQcEJyuiL!JdBzC?Vvg#GMA73%n^rasEZdXNO|f zNymd+2>pnGOW-OH#00qIN{6z*7YS;Z!W^KB%XgpIwDqhSbU;B#sKCUR7D*c){!B8g{icN zGsS|=JOdTfS=+(c0qnYcBujttfWL&0A?^ZUSPq=M}t+R+zX_8 zWl#tpeQweMn4jo8K;^OEde^8Q{&cO}Ha*rAwshM=u4_N0@!6MchW3X0kpNc9{esru z-LLs-cJH1Ab=_OkS@8?@(5J88RhRgycJ~7IA9+qNC&bgWfL%8k)^7NLWxDcc;DpKE zAgjE1=F}hwVnk>VBJnBDDlDfMH+VQP6Lc33NG&BQN6ODizMUhoC8P+Pn>C#ThR?`x zn1i`QIP_6-`IWMF%4RNW80a!uE}!8#|0e%@C(^NPE9JXz*Bt@xeY$7Qqw^zpFLoke z{-b;LTz<#SE-{qwaS|&BX4-EF_JwkzWx{ed#+f99#yZ#`Wc!IjCJw?I1fXV(^ow|E zH#bELDA-C(75>CX!krLJz$OI;!=MshBM=ZtdsI*W#cSicctoJeiy$%k7(E^S+uN`5 z^2yr9@(0Vx^om>ToVuyF{5`Os1-ITnopbxZW$3%*$Q;{@(yE**?bNWFwbd8K90h9o&64okb?YND7{k=R;`?Y*5%3@Xg z)ef_lOWcp%a+^WZx**PcuYDRKQgUJGLlk9ht?p(_P%tWhNvxU>fE-$(8)VRI%GD{b}cBMsbhkmseHr#v9;zgThF2BD- z+b1)z5?$|%HJEM0i8YvT%Qa|MZ4D5jgD@~P(`x}p1cW5(Sq5ReCg{ABxvDHfrT_S5 z%MjsNhT`Q5=1%ADvWBOB9XEKwJ-?j3qig%21wF+gWZu1S?TWQ$%r#Ia_9<-BZ~Oi= zooA*v=Jen4IM$$lf?R{aU3&K_(Q27%0KM1Dc?BHf5@Aa*V>|JA52#RO9=jmKV>cvU zRY-9CtaQ)loQDxwn-syNK>7J!MUyo`WOA;N`pOWh`%EFj@_Q)acPz6tO6io9X*A3c5e&C~&R z48TcL(*|Wv{;p@fy*jm59(-w&9+yb&Hw+KnEnBqh3~(P4oHa;}ph~X@YxLmDpwuKI@40Y< z3lRsJ5k8TbTx6b?+Ht%y9gWC%jF>0LL2wTc1X;GkHNhc}fm%mm-SB0iHSlOVN#1A{?TT>RH*-I^uk#I zAzL(CSQKcbcv_}LKKbkY9^Ug$R+XIjJq)9>|Fc(D$=_PvP1%@w?lu!XNW zO>7~_Exs`jg{4tNPQ*nSaDO-y4d%l{*p74zn7qJkhZ&>_Ay)g4mMYmZ6I}SizVIa`9;BjP z%9j7pnyq2|s?(1uSVbN7_7$KRPh0EA3U0BEm>BHEiI6-rJFO;gnpjPn4XcR&6Iw`- zU5X}&g%sIpNPR_2ZR4s>+BE~KdCNy}adW*NrJXQt^I2RRdM)h)jraB+r478{W7zwf z&XdA*i7QxJ=tCNPD?X?PXbasZyy>CK@`P#a*t9>-v#G3}5Bc+y*&;rN*cE%G{X0~( z>7w*h);m+1HS5v6S(j#=J9TJVkl(6h^CpcO*7voYhFaRm@SfeeYKnhh98#VsP2*KV z&$3LYwn!y7z&{|^A3CxQW(dD%4J81|0Qf)%3kqcZN)W^ca7b_KDnfR=t*b(6Ai8)v z)>Ra_790Y}r6}0D!}W!nYNRKCi{`M5yo{Vky+`hBkHt0LS!!8aXOqP>mn^Om zX4iHl%$`W*)+TqRvg`&+`GvYU&F-H!trJU~#yj?Gjw-RYXM`=N?{L&Fune&3^d<9} zyqh;&e(gxs*k;GC{_xDujk!%W z-g)BtFP>~Vre5>foic|{UpTVYz&Ka*;9esZ-8Zyur`oKeSo-YdK1;7B){Nrsf1CdW zztk!x2SD>L^1o&EqiSxi8GYfgHap&SHgq@|w0V0+o5wCdDOg~OJ@2Q;)ei0QTUl5nQ+Gwq41Dk9qX@T7eXmXpR3oT<4b|UBidF4? zEm*J}COPP^Sz$1GC|VXwrZ7bNql#*R0FwAe)qr?Rs~(C~55gYU0XwEW2*w|&BSdB( zKW|EI3jWF%eXCX_Fy@ZP91CY7E9?l_$n-Ka$)jU$-VjLTZy#k^ZfWsxRzGb>-jY2> zmQI*ctIU0*EOGX@<%f4KZE|N?^Coi&KH@*H_>ZR@%Wr+`-ixdj|Ng_ab8?NX3)t7+ zELgCBkF~rAZR$xcLVc%oh_TE!_dbB7Vts{=!S)o^FI9Qc34V_HL$zTIFl{ov>l*Bl ztdL*9nZ%G6KrUtwEv5pl;Ahk@{Az%J*o_+Y46&kiQlznpeo=t|Dwz|-2YWP(k@;1- zz<&Il9%LyRuibzs7J>gY3D;7h)DYH?X(`5Hb`B%5T) z4CMWM5pqkcGQ(Mea;TE6p)&iE$n;qck%MFeq>Nf-B)yMXfxAqYMFpgmz!#Y}XpR=t zsFv4rTC~mNHk80uAB*>yefRRkYzm-Gzv0|_2h{WHFoZ*n z9?2Jryj%a{`9RA2AI&G!Yd$vuN48+b_3- zxL^?;xeEEZ9{HT~fhkz9O}5ssEjD%_B)YGDr)n*;zP)KtG2V#&C2q7mT zylnO~oR_pboA{f9^j2x=5a#H}KYi-Rzxkz(EbScsS7(-T^3WG7tq>^=UpzejAV1C4 z9GZ8CO**vT5bMGx9GVB*3RBMOd$mVx<&a(;5PJ z?}^W~BWV=`sKg>?Eb)C&Ipzl6LsCVkKYb6m1^OCUaH%U%WG0!+kC>hKTJ#);IaBmB z+S0!y*+|U}XZ)gpdvE3+CdC#gF(c+1tEZYSFSJM>eu8L<#N>c>wm7T$VAF zrFNb=|Na(tWbq428rZhYyL(bt~Vo zFElYUF#!R}kr8;4S%s&LhYI6>Y(VaGrVi*89R?iCxDgo+-9KRF)Vw?Npx};e)Ua?{ zWD>{_^cSXQrXjnw-DWcoFz%O`9v_<=X!8$10A7vE)Ce>Ut5=ihQShY;dq@oPi(|Mi zBn8%DHEJ_h=)njRlu!k{0WfJgYP88%4trEaVnRxYEhxw@D7r?xbMyZ%gEIRJ#+eKK zUyo3Yt|1P4MmohrSP1M$R^>AyBYMVNI z_%vOe&?qOnK`-%%zQm`7{5_wK?g2iJy8GeV%AUCF$$GYxPrv#vMvrmhdKg*Fn`iNF zjPB#{bG>Hx*}w8<_aBu%|9{lIcVHI9^FO|Och5Z`5FmsQdPs-RQb zd+5Crdantc(5ncDR1t#GY={jN6%`N_6$>TLJ-^q?J0m$_xGb3XJ?J?^;UiRwnCa3l`JJazI{o0w1?(KFY6+#TVsd|OBt>1locU}r;}+bLPx4t z@>!sI@fJ4eXL_Sbs;yRVP%%WDEFV&~L;#dDtpj-@@JmE^nbL6OQ2l9%TA`kj%(Y~; zfw(!lO>7FR@gKg%R1?aM#wKuz_57BP-+^kw@E`)mqsRn{e;Cw#oJA&tVG}T%%Ob+m z2sOb^2KZT3tyTUB-5b>`0HBohka@>pyC~btf#~$u&g|uFd&qWdUd8l-7x#M$KQ}E3a<5O+3Yo82# zgO!5D^o`mF-}utWmb72S{Rzf?|G)9yz?vcZ8~;E1nXn@nwBhr9CQdKpJbos%zH+&5 z+`5(h75*US4K;8&J8K7KPMc;VxjZ+hqumBN5tj$QXy;&KTVYKL@b@hQJD(4NpS#aw zv_)ch1zQF&`X-+Z6;=}p=K_W5u^p5<8PhY*swS}0su^7*%;^LZq(v??78j7{UmZv|D(eJ}V$*0WW%g3os5K0CL8 zT|pAcl!l4eqCxqi;|6W2KgCKc3JUQD{Hu6xfjbJGD>|&Tl&#jwzT_|5%Pkl&=K0!- z6to4U4RZ&Wjb)Q^5#JD}XR2v6P$#cAxKeifCcF2Vxa>87aT^C*x|RKGyT{xF`FX-N z?CMBNv_G(Xv9Lu7ZSy$(OY=ngUx~@rXwASp*C$jrpsnI;6#3a{KXi@GFrMLY1f0jA zaiBkFafFS+u4QpJh{0wDA2%&D+sK!#oXWNol?Z%rNVXvSk8}7MP1%i}Xm_SE zIMb*K1jzFt%1ZlA|A#!?Wu~E8?mR~s-(;^}uN*S`WjXmJ)_%Xtl;_tQ&T;8B$0cnP z%IPm`rtKf?3}tfHU&M=|v4L95sK{K&yZF6SGn70kF>f$7irn+qGZfonKF!H!mpc$! zP0+ygZ8+2m;DJ9P3GiCPbMypz=fjF51VcgNp|>Sy( zeLe-TWywZEc6FF#V*O*KcEd=M$Nx6=wb;-zJGlaYxr`a%E81vY87_cEZJ3Dzp zAqSSoh5e$ua`vndhu;a;uggnBo8wcArzCh+43Qd(!FME&_l$e3FVYX*J(31dx>T$* zkixDJszcymdoFxZK)TBZoSl4dHZ-^e=T~?-1i)4kA|Fi4zJ5LX-o3#}>8}<0VPzb) zg)X-b)n;U_SdnS$QD#}d#rzoMfwq(2TYmUa7Zt5-*hl#yUVAA4Zrp$}1@N5%J zGUyIPVNu^!7|~HZJS5zDF$`uua}Nn7)Wjk5&!qZk3`)WAax)4(0&W(mJEmpZ?VKt!ocI5Qj=FuY*;U!qR_5Bdj7abZLww0%H|!r#HKE;8 zdqqeKv{&k8sJ-^$=S$FD7jk>OXFgZ^;V#8)BpL?({i}{gO0(A_&Y>}K*aNuQfq&4o z<`y*WQJmX=L-TP>?B&wO%UnQ5Pld?-)!p_V@Xsb6_vo^IFY7vzb} z0ZLV4HE%vv`pS>j=kzo;AakC(9Pe4luh28jCmj258j{OGP#&HFFdkuwOGXBa-7rF+ z^>Q%Q4D(6W4~!C=zFm2ueA1{v`{#4g=Wm~loi;)_w)%7PR?BZ7Pp(rfn`C+^fRT(F-(E<|d;~cfl(NM>{~hGP>BHlR!98jwCx0FwnGu-FJag3ul>WgASxDibN=HXn z$jQeHBZ3iToKoh!?c1->(y9S--YZY^eb=t-t2?CfuJcN{F0ER1T{EX_Ib~U`Lw9~S z+{*aDm@m5{4vY>L_HLSzVK}mlN0%HTI5_h69sX?w&7D8MHeqMMTFY9|@C|#Lu-4j) zd9=}1xN;>=F1a*M@*%`SuFa(l4x-J8WwFl-d%Q3x)$|}pnMF5Um)ym6G7B>q7qjZT z@Nuj3!cnwqli=KkuL7Yh^!IWWpMG_iY1oeC*^ zLfg@>0eWc+#v`z;LobD+anX2Wcb@S`52GXP*GHO0&NSh9(u6^eWwCxs0AlDjC5rJk zHrCPJd5mR#HJ{7R_&HXVo}D8II-F-$VXUzT=_D)}{GPpy-TkdOX>iq|Ere77MS;QT z9<&>ghI;5lXt?4UZ<0RB2Y*iVug-mTa2}a0Cw*&l8F$s|!o5{Smv5D;%J(@>G7A|( zDU_+|$R7E-&eHNl|HW%F1#lv_Yu4iSG!8)nQ8kNNfp&O#W08;|d(l~K7#NYq7mn7V z@rT9Pk%AC%X8}2C>+iEaJ7sLW%m-{ezGUop$Hy2fS7xgF=!`ApX%2$PQT@~hUw>o1 z(tLx)b65Cz6+F*Rd=;I{=gN;vcY?7&Uk`oihZCILt4f}|uY0T#F1##QhATm%IQ(A< zPKX%nS$U;19}0opjb8c888NzEj8S-MLZdrUU)ZF%LJrB6bB%EbL$^Eo={1XArlMp% zoeL%UyFEvudn3H%jE$Bu@Smh}jf*_*b?oM2C_8bOaqoy0G9Hv6UbETY-MJ3-J#phco{)9PN$gQ^CI>S}i=sY>N5X z1b4+9J5Pn?zhEn>!K9$!6p2Cw$@`epsEcNvQ$`ho3kqtTlq^T92*T71W0)Xk%qgjq zfrFRRy@~oLtTG_fdvxy45bcyU68-CUwwRZFgYcMUfU7*2xjiK$YV7%71Zvrh8|4Ad zP=2zua$3IeqHuoT%Ty3ZF%gI_r|EPa)8p6l0&=xT=1EmLzYjCsf8mMQTF@UkS%Q_B zsN7$@kR`c4vqit`6Hkuh`i2=2MkDRK{D@W3!H`#T1!(v|iO=~VZ-o@6nD?Qb z)wLCdKkSLQUfh&42{4;##XLo;X z!f%f+E?7I@t)7@DZ7)^&Q;Y=yFpQZ)gnTV{;LGA*IaO5|ve&{>`z_DR! zu!7wv7zSvKjbp~LjoUP3O`BIs$=3H|DH)klMX~&2AC!?C74z1wdp|0KxMfEJ0Rl*m9*0t0%{`k-m_})KYK5VPE(C@c~4_g`ZWAI%L zEGtDwaM|#{@Z!*d@Kdx>Y#DcX>*a@pQgKTbMR7}+#l;bS5M0{OoVVEKitBSFrt=9g zxPjM^X*Me(gUs;y30z<}Xi|ZdGxvyy~V{Wjhpu9MuHCyp%ASaz^Y`#Wcv zYI$NmZFBV3KIHLwbwu5BZ6?9#QLYiFjWnK8gnJcptZq){%+}8HgJRmVNc`AL%oYR8 zeUi9@=6f{O5;D2Jd53t2HH7Y158znd zymUZyQ z8GT_C*@}3)$5jtB-+oCw&>GGrt_RG$DUI4YPhDaBK(Tb6jUO;gAp96VP=EMr{Gf#L zbL6Z4%;PnTe+j4MwLCc2fwsq-?_DQtXY!x{bETc;c{Jap4dHD`3;< zYl?EHl!>Dtl#i)b=5l#c5lbb5<1Xwn%MUs$GM(j}be_$lXUte0L`M^o&S70lI++MX zbih8)Ao%-G+=aHbV#NdK6taN8;(@+}DEhi6CX2b{Ke{Mdw4b?S3d0n1tZ0WWcY2x$ z_+UVrYsN~=9etHQVzN?~6_gMU|2>@!2Jwq2g7`And7|`{Npgg-HOKhCcw5a;w8uGv z*Cj>Aoc(RjM~E1A?HxSH=$ z%_>?8Sx7V?+vZ!`M=P)@IC;(G)Nes|&m>-_GrS1l5}zUio5FA)bn(P6zh59`?VRfz~c-lj@xbxMw;_Z z+IGt{C!RDXZ5(USav5oEQ$31-VI@tE^OBT6iUH`8D?^8s7VT|?OO?PTF`Us%rxJVY zr>}|iE}Ye+U{^85lGq*Lj1&X|5YAIF4fix7z+{RQ8ir8LeKWi{gu(#@koLwo0MCb8 zRDBftJhhKB`rZ89`1Px|jQa?$yLSA7O1upsm@gEkTopRsUX`Nfx~N>jyR4$RXAzpk&<)hQ~>emO4+dF zjRL>?QwrUR4`9uA{mn z7cPGP=@otWhE-!S7H639vLEgBiT(t2c!BGAgm@&A%>GIyIqTVsagl{I-*Y{W==Z0Y z!tp1iV7X&FR+2jt&p?Fsd0y^JJS2A}o`H$E&n08~7Rel0ZMi)hXPKk+;F3AE@34MK zVOj<@$gQ8;G3J%BOqXd7!Wp9qR{qdF%sjl%=J1~Lcu%IHG%E5)b(Yu6;||i`8CQ$99v1QDIsjp5Xz9J`+R{yyUv zA$H~AyBRkGd^h8Uh!LTA`EH*1L3}sy3>35S@ZH1%zB};@^la@YkBNiM7GWH+gN%P6 zjvR_}!Z@t5gE;Jog?YOIvUHVY0CR2T%Yi(2cpk}T(_!9CybaGS1KZHwVm%eK42599 z-XT6_+_00=nkSy$az5Y0&$nS*8)Nkm;bd155u%cIz|32kXG&4My7V4o)Uwuc3~3)> zNEIO-qMb9HGMLMP8g|EQv0?m0c5%?rMTl^9+JU;Tj(rD;VcH?@j=H8S)WbMv3-Exh zo}BLBQc5TOMmlpux0ED;X{~Q0TS9njVA^uNQ(xofRgl*!R5qtA=R4&pK9Hh5_=)oa z;0p-b39aln9V&C#A#9;OuspzEf?b#t$sO87!`HBa(Q+NefwbDh!)~n5(fSQmndvwW zGD6+hC->hswi#Q0mHRUn8H0Y7DYEUa#=uQVroE3+A4ivEW-1fx?<&>pb3jiO*Z>eM z@qeL5VS3ylXchOUd>8ZY1*8c9d-@cc%4(~L+xPAM_AC1pf$*+xIxz6Y(zs{8B zj1h8)Q5PLOtX^6gctf$|Z4}`iVRJaXJ)Yzv2Dxk!wm|mxK-6}#GjW}|gdy=W)?f-A z6pV9@L+L~zGyJ!@KimHCJ;RXlC)v+f$0rF5S8PvO{e3a}fjv^GwR!ABEYgrp>52Gw ze{tNX#(2QA=~&+6GgO<~ikB!MMTwvirrIbFq1 zUI(M70N5Rk^$wn7JAEICB+Ny&(#S<~cAJ5tu#2ednV?Wb zdw9sWYZijYM=|b6xoArBoh^H>X>#?83|DCsl;xg23hRl%B9@}FR)PJTB5@-YHT$8u z$6eKQG=-4Tyi*-}g%ns1Q2=wt779`djG#>ubd)zO=(&%ZeinLEF9w@76#-8ASho$) zU1w%uPVHPPaIPL8FQdBCW;Z^f`;#j*7r+ zha--@QcFpETCdw^`O%v_uJn}?PItz^q2DX7c4^-MK}Thsnu$N1^v}v}TE9>*mX)N4 zcigpHN1au|e5-I|`4GfiCEr^diLAIKDaId-3vSG?g}~2^>I+o|$m^EoxCCPqEFsWu zT`#Dc8(4YovKefgH#$3a_?D4w4p1d}OX7fXcHXG7b9by*vX+igdSD+tY|H@JGI7*2 zE_ZOS)Qppx4|vJ6G0QTi%p9Md`SGO@+oQ`Ln%1CMH~H}!J+Ahh^Lj_bKDw=L*o!KV zBHD3VyN@Ac(9rU z!e9pCZB8a#!FF?%0fLA!@Mi4@SAiqk(bvmJL`CmMeQEI8?Fx@!I_P`oNyo zmE&Vaq>VM6=(50j-*xZOtHX`RO3J!<&9YkdUEcW9AJw$!$&FiPv}xYD+qyk#Tc?GV zp3tE=$ZcihsAP)>f-YZ8v*ZYDLdIX^N|r!7^EerujjlL*SQBBv#Z^cv>JSTv<;akt z=~RgbkVI}GrrRUxPNg9yucBhe7XRFr792kCUwlYoHb2+VL$t%)UGXp&`G-`IydOxy zCo(Q}@7A5GQ0KqOA`fy#4;womFziYN|9PX7q}8JvWh>({rp}l!H}m5w!*@iXuIDxw z99$w~X5(37mf4RXtZ8j@f~0pQ8h6!msO$fNAMl6zZ~1{*|KIrW{D=P+ew_Pg-0%@& zjk~h=wQqZL?c1SD@RhKl1A8jI#1HvKMw=F`yRO^4uJx$UGP8R0sNAlYUqG+eZml{Q zz1;keqM_ril{NqeiGwz{br;9Z5ybAs1O%%_Zl7-KTMfnV9aBdrFm!Nc#hZt_Nl1ii z`QO}N8TD^TsYBtVUk?R9aXw#w9p)H9&R^u#7^czQj0s3bFCkK^ue*^wQW!ea`6kz<^=_JfAXy0=!Z>J$x|H9Sco3wCIzW0q+Ha>#WtNjj?D(4k1JR9EcbD*?K6s*O|{&Z;h5iq7YxI5Tw4x~p&IUCrgO&Dd=i#ySN1^<*KV-+|>FDyD>JnYv?h{`2dfC~^S)35&tkTQ< zcYwL>|Vpl&H{eHk&{R-{x3I$1XF8YY)90@0e_C{BBKF-FGaHj$b^ zjS-86ot8@3D!w!&2|p})=<{j8uAtRfLesuWBNn$5d(@`QD2iRyKWEEM&8S}pEPERL zg7(K@l+zid9tS-*Yq8V09uxPuYLR4@&Ij8BJ5i8GqP;Su5q*Lp5{MufLHI&ia_Bhf25b?$t_z;r|33>%OuLs)N+{J0SF+3Y=!7TBnL(q9JQj9p< zpl;&QR}a4b{=vDZrc%YvMB*fQYeYjPeJYK_8*OZ95=fzu3Dw)ga-2#u9_{|w5>Uz zdV`U18?$81+mYYNnjwKJN(J7@h}`%C(Hx3#QggJO66_b_U$~I>^JgK1IEM}u&^GV^ zD>)2{(BBf#yjz`3?&uNW>*^MYXR1x+80EETh!x(cS^6pnf8g2R5X6`J`6`409$uL_ z4Oo|TzuezL@F}ZCj=S1v$ov0|Hs~ax4O073+MI)Is2{n@*r+Z*G|i69c^p%Q<@Mof zAWhw}Zk_!&NXwkpY-g)}E1P_F$Ejo2!=9-?P9w20g?PIaBFxBk6jvT|fk+wY(l@rm zGEg8z(LLpdDkZZL0_s?v#TTT|n*#oqG+xoE8za|R2(cN-4#lA0f@I$`r!Z!8I4z_c zW;X1GQ!Nx>cHDb$iWaLS{grD+-?)5u{X3_?;ZxrlhH-9j`nYr)GKlz3F&261{KCUW zb{;>erl4+^P*}`n6APzdL1rWYms6?|k;+FrN!#i09b&r#GRqnBfma^Y}5!2G}Kd)@`1}j5MG`ABMPL;n=}%rg;NvDLjJ@ z;E6fXgdxpYKC{}i2PDcbOuGea>n__tW$48(+5XXy@g%}N@qC$tXYYcOc26e${CWykIAFB+7UGxKw zCBOA|7an!E$Y4H@9gok*Ht}c&^n*@3x;nfL)e6=bs8;YE|3J$(ZXCnJUfG0b0gfgn zEskxNcR$oOx^WC^K^y=Mvf{YP<3)AP57woW7Ns~PYRcrc(~fA?8P*V-WjrfB!rG8o#}=aag0>IKCclHE~!y zafG>X+yai)P8_X0aplG`i^xJ*0i9zx@*h%Idl}(!>CP}>tS8B z6Wpfgym(ieGS|b>k%rd8sND^Ojg8xsuM5A4r>z@Ls+cExfH#Dvhm$uZ9zQ1@U8dG3 zXJRR5@`iBy%I%VALA#u6>L-tONw)8eI+c}ZLA$J6+~jX@#^JclExGa(lIoiY~N`89%~NF z6KcQGa=Qc`$V>{#WVTDHXWGkW_5-Bk zxWZlajgS&dAGOa{O0(>s)=i$5HhGS9T%68B^$()~)vY=_PyJ)>gZx@gLmIM)Q<`K) zj#;;k9HJ8W9Wjo}#Vms+p6=>6?4@EE%*O>mnpMV|av1E8;S}?ps8KtxoVv&+JR^*q zG!{Xc7&DE}gr^QnolbfnlULERn)+*~2cApZR}db^WNPldB8J9S*1z01 zhKaAZzofpx*?&85MkZ*XzQV*YY(Vb5g6Pn_O1g0j6*uzeFOtdS+*g=5hW5zYS1@0^ zXbccTWmboX&tITwg_)&$K4?n(C}L zmPynb_Zh%TGC9EPGpP1_NqDKx;19SKSw9U%xgFLxjL{N_UNJ^~BO5#Gkq>+$yeRiw z8be9a{gh?^kD-9kJ%%#z)NtcTl;LK%ArGGAzN_bR<4F_;F@j}1N0fQcLu-UgkL+qG zAZ<>1Y##i(OLAq>^Fp~Y>8bC=lPYe?mQFk^J@7>8MO-o=Q+p$z3h^lr2~h6A#zBii zA8q0woo>nR)b%^GyV^VM{JU#;+s6uHr}ibcSNNN9y%ox{hid`)44h|&{8OEMMhC_Z z{i%J)I>Y?7tHmpi&R75)o5MN--*Vepkw<3$kKUff$FiZb-frd@j{=WnAfFe~$eE^J zp7E%Oht>y8Jc%+W&-mEHL+2ovcoK1%((~hE6AyHui3fFSeNnkA1F2jl9@Op2%7wnr zi6<4~gy;K0lODSh5BkEM9z8bd7WJdI*Av`0x?5gYKbCL0f+^3uMgI+@W&YFaJ ztIa%16c1!)$QJbzG-Mz>Yp%Jv)=PDfILLz=cwZiU&UY*yj059^ukws3N*YB}#BN4D zow<&?TS6VZ%zPZZocWlvKo(6}z^@xTW+GZ#Vyr^adV9Fyi_uTrjGBnR%BXZ;2cW1A`vUvDIwWTx#WHo3Y;QRPn`?v( z+Xb*%;qsI#ifOW-AT;;}YKJP6!_Z*qQS}d5)~AQe)|$&+#+t)mw%80jeP4zLILO=1 zW!!LvvtdKN?8}HA7&~P93rMjGbPg4dK~L0k^kB(>@c;|{r(iKAU34o>3#1er2Wz!M z31La&j(N3%Lw@Z2e(@QWC1J-fk7QO+H{>u1tIV_IS+XI*Ttut1 zuzQclHpa;L*>VZ(jlxztImVceGD*=M=S)^ZK7JzkKkR)d5Az9~sjR_alDwGd{H=Vv zdBb^FsB`lM8PqCBXYNi4XoI#^ji?wa=g|d9cv-r;+?=6mOwRh89MCgQ2~Z-`Z?T6j z(xy{PShp+&fL!8ZNury~I3x<9I7LPB<1l83DyN48hsVtu-nH9^;oZ6oS4*T0AD&vf z!;qoS_o&w`SgHsTmqj>c3aD4a2ZA)1&$Vp#^9b`fy;r*-oi1#M@Aj&NVrfN)IFTq? zi&w=ETgjHqn>4Cdm(GLXShl4pj)J$Brnuw6H+r?L;+s4D;OT)-jE+} zTCoQ8*t$wbLBTYYKfl{FMX`?|F&x3bxnwBKIBo3m?kuJmxHisw<0^XYbImLqO3xWV z&p-D&zX-JC*sQrpqr<{RC(YZQH8*)oSlFnh^Rw(eS##%SWzC(pU7g)JIjL1jQc^4V zZtLWxty<&P(}wufnw~uxqP#Oi_L*{^ZhU;*{Zm^^+gB$cq0YW(>h!4x_D^d*b>F_J zIaibW^-FG%)W3gH3->SO$E1FJlba_E7?AYzlSC~IV;0oG6!i_+0J>cVf6TvkDdYKX zNE@npuviPZIEvbcu_1`3hmH!wc22DMla``{FVYIqF9bWmVr6;9O5<}Gu~G@gF6-HT zayC%oldfWq;-_wf%r&xkQ#=ClU30hUs@TE=Gq{-n+BcTGurXN4vU72jplH(<@3^`9w7AQ|FC!l*q z*$U%{pFngST5qv2%cL=;LxoEh7N5sA^k|>dT~wsj#&1Nvo&6`9;ck%?As~6s{N8$4s`|X zq1EDX2v$EaUzz5ZYD_izePgP#PbK}`9(7V)jIafRg!009b{;}yl??EAhAxDE2<^{v z$G@*%LVD$cBzxu4adHdJz0mW+#S=$niZTVHhH4@I0;;im`Jgpu&BzDtO2kXjhqT

sDMz7$^SDZV4x`K*fov0l~+M89O^^Om^v{t zqK(rvqoNG+rLY5Lj8g1aq5g(rkjMeqvgchi@0`0EHmtzE4eAHiuGOvP8(FYav38N; z7Vq1qRI|e?{&Ds@|77l*FmX?$@pQR;ShH91S<;IHEX!1uEtjO~AYZMF``QV%Nsw<; zggQ;`R2tLBt=ViuR)V!a;V?-wi=EBlhWc-bxy=p8TO`hDEJ=J14+}0wr+}CtD}3^M zo&#iSSO&Wx%1YhK3+sC5g`n>I!Cdgw6gE@?mdhlmqB3BJTh<_B)H9(Kx;iFoSK`CS zm=_`rqQ)167dW`a zpN*pOXLuFtzUJ$@p-^EN^yj1!@RZ))?Y2UhmeYqS`U z)I6zQtN5IMrtRA|t;N*+`=`45KJ`-K)5YlPFhm^a_(dHF`b$A8F->N?o%zHPnAszCS+bY*nM=lN(fG< zzuM79(H>kcP@upOA0PSoYnS&ejofG)=-qkQa`nSX%~}i@Y-CE?)gdHfumgIvu$+U> zS~O@15tA$-jvVx7g)QYA{uI9pRztF*vFXE~q)ZY0)HPanwDUr+WPt8sMIb%kcLWY2 zqK(2F*3=gr9)6=M&{TbO?0UV+s4e=|pjGeNdVq_{Mj0tj%{f>Oc zs3G5h@kJ49;rqV=YrFo~fk*gDGX5}Ll8ti)tqwBJyGy`wofXUdRS*rZ{i$wWz=I|6 z()+TUT_h}O-t9ztV`TXC7IS)Rza#uw5qJ8KcQM&%gZ3xFn0ee@_O~s%AO&bG4_nzdtZNvGb+%vo3)o z%+o4sbexVyuTvTV(&+JDs$EQsyQCQ zAOLtI<{0YzoYQKeGMD-ziAa}1+mF2RQ(o{aB%Kh8lYL}}3b|Awi|BrG$tC;ERgX@| zCbDgtHd<%w;2pJ|`m+8Q>z{-Snq&R^Hm}I&kkW+|6*yiHvzi9vMf`c3T_hncoHoVy z2T|AtG}~gdjWf=A^2xRBzqV@iVB33-A6?7(t#!-awqJSjIBn+Cc{fUxzA=Bw49lfi zljeV1w#>)#rp%I0zcoJmbbaP$vg)_>zmd_OWoCSCymzbqo~troaO6N4@cz!7?;H0A zM-DaaU)zncI!+nM$_l+Q_CBDjh2geQ(UNc~CxgGQ9KLT|U~HL!1?v^5)$rKX zpoWpfi&iSpzEcPHb}&on{ipMLFSF=FdOrCc?1YT z;)?~81qZE!NZGGC+uWy?al`m?Nt$zJ>eQXWuO{(f= zzUg4A_w3DpIt}nf9oV3SEFM#-MDvCR8a6LcDWJ7W_tt4U*7z_m^KwA6))Dq{6?-$BlcKhu1z2CvXkw%J=Z$*3c zW>!wtZ?%sAN-x-$(B3z~d+A3lS@grcs`lcPP1MLh+wJIhYM(;;iR7VEXu4#@vQKfh z;S3DY{y;p9erS_L#QPrKOftWD-}TKT^BeFOBT4lZWEQ()h{s+&a4aR-$@@G=;)F1j zW%!NNa=9^Ll`&NL#c=rQMV?5+xGe(jr3iZksa^N4Lik2)Ls{qpxrBtzb%k@pSAPyl))oVSGm796|qSFYWY?idJF@=H}I z0QU)u#%Z4<4+jddR}BqAF#)E{&NyCBM-W$b4?@@h3=2F35yv`HNCNa37x(PBaXN8E zYH-}Rx}*Dj`l*t1@uIqG`RHTs2A19IU$+0?(aUpE;h#cv0n4tYgU)c#6m(lfOJ%F; zxjy#UbG5g}^Ih)e5uzzQr|&Eca4#l08EMvEEe9~~D~)keEm03UcbkhgqKoJu`iKEy zh!`P8iz#A;n1j9Ri^X!WT14BbtXhEs5f;o#pFMN>)G?DrrVSf9Xkfp-y?S=*+O}iM z)`*f@AIBWTg$I@>h=|FkLw6V#(g!$<2Yop<&aua@Zv;11=U4@bgbf%W=9mftONr4Y z#FxTdA($}&y8DO0q=S&|@UHPMs#6eR(w@%C^S2*uj;9nB=a7u*Ak5>pT4Q?OzSE}l z?=wx7>pUPns(htkeNJsks#`xP$!1GdPb8F&iEpdu13I-H*!l5=5f?1w-x>C3h>W{n z`B}yf%lX1mH8w703XX~`X742Z?VX_>y`TL))um32+BLi6{62#JS%Zi1KczwUi4(gI z?>T;a&(B&mtK7(^&?^zi$@ZI{HEhwM;qV46TQE_Ocl3grlAd*$PBd2nh=eDuAi21^o~Xj)}+40CR{HC^2g?d51j${sAHWu_|Ph zF0HtFHm6=r1FcZW@=dz#UNLv4s=h62RgA9{8`-kf<;$0oF)v1cladpi6Rp1gdt9B8 z5i?s%TQg&Z9$T$$Tuk%Q2^~{A?Xfr0yccOC&s~hhny4y&KQa))osBx`e zzlOsaRu4gQG4s))^$(FxamvRxpQ)olNHgL8s?hty!~~YSLQ=6^M5K}37cT5kO33;N z$*<^B=Ox#WmivZ7KXF2zHCroLF1TFR_Q`c@);hrNc$Les7WfMg{`{EZdX~e2S^(Ye z?A&=#k>xfT=_{^$1Y$RA0I}_Pt^yjzY2RxjbT^KC`JH;y%?&j~uG=WfDHnI{d`D5k zuU}ok1QC`4Mh=$~mK|-rwg{RcKhZ%pJ)$EBpJEI_ceTBt_PZ)?oRA-1v40}d&%q1d z_)}Z-bfnxN{~%rs(Y7nU=)0iJixLjM!X_Q&+=K%@P&Gt^L?py22#b7R`HKCzvZ`g< zHZ7ZN_&~ubm_Bm(@{xMIl$3fE-@$;C^!a9Op`4%xnEIS1$`x^}8SLFP@%9=QJ zv7D@*z9I{J^zcJj;L1sT{Dc$p{#uD_`EESCF1;^p(EAKMzTnTr$0JKUfo0K*5!umQHX1LZ*QGH! zIZMZC9WUB1!!IKeOb}CgIF~=Xz26h*@`3%n|RZzso<30;oex=2+~X*mqi-{2v4y<`{>0NxYAhT@@dDmF%^s zD_1>PUd8W1Tpp8NP>iEY(V}_ws{EtNo_}ZS#*w+k0X^Hm(#HI!Bh?B@&JDGWl9Nq{ zq*#vmhhN_Lho60_GTk-*fIMj^uT!2(o|}2d1n_*!1^ZzgOmCrIP&+9(JHeUl3fxZc zPvJJy39{h>Ef3i)9FUK756|UH`4CX!m|?hLp2caMjQii*GVV$LTi?il?5xF$wr*Rz zc&ohjiSdZU;$xZ5_~&D}X5YRwe`f64NA_mqGZFK~s<1&kpAV)m3XVL&+{KlT^SJpq zt*UYJONVjurW6+!r>8GklAgX$Q63rJ%D_i*-`_IGxb?Sk=<=0=M#^hfuNG?m?H z+R4(Qze!<#R~bw^@V9f~X)7*bC7H{~%jWJeg5|g?4Mwdi(T8#xuiSXxx8cN-DwbkK z!)eHKgXw{_QT>q1`?Faubv(EZel<3N5tok2O7E>|FX?UUa@xIj5fY?9oojGVM;aQ_ zplnf(Hj-}k1-dNdTSc1aR zsvo`j(apmTEb{ckUSraR_37KIxO}9n$}%pO2vgL{Zyx?=%Lct*n|_mq4w_se?inrq zZdy`WMVhokf)+QeMV;@-N2e7=h|H647f+}yS7KTH(kxGH5APe`SZ4%lm6#{=o_Lav zc>*h~;o^yjgXE0UAfGUnRd~&~WtIBQPGs{{XAmCjCx@3iXn`L9QOosXrYYr4(-sj= z2T>Y%Xi%;+7Wg(W9$kzW%YI*`*AdZ6x{1p(o%3lU4&)wBI?Dw81st3PWty0$o=rSd zCQgGgt;y5=kVb`WMw%&{*Q+wxUcr~PBO4rgBI*R=YU9HhZugT~u3 z8tXkQ6K=oK#dy=7_0vTB(&eka=58moj8+n30^q=Vq09C#_#uDC2T;5bdVcdcaJO}| z6rD`motQ|ZS&K9SEN{5dAoc=9L+1R++rc>_zV4cy5#%K5*?^(yfM&bI7>w&&Q zKY`%?9;JMihIww{Zadn8<8B`iN@+L2c1D2fX;Bq9K0GZ-(i`fG^8`w_gEexi9;ECVuXCA=vfOEW?7Xr4U?NT>XNB! z8i@H&hqSZ~dTiagu{U9U=dzi7BlXYddoh0=BUiy{#dNuSET8L#MWVQwN8b^DJ8>P6 z?gi~_JT$Mf4m;^V$cNv{)R9$84puSw!{2lLneS7^@%NH7xBGjlKi2J_a~#(n>cHL4 zm^j?}A9S8E^}mV5CCkv=)b35)oeGQ8bM4--4Z5MNTQ?z=k@47U6N-E6@LS zu2B^$Q^-R0l%fdsXk|Ahr-8sV<8a#tI#r9>mcFz4?4~c8-gL;Uy=l~zvSnXB$ANs& z*bHS4p}ABLc~l`^TA*@SK`5(daRuDx*2u2e^4hg;dv)*MDZkH^0($?R@Eh{t?e&l3 zEh9)S_os4Fxn zO-xf%#G?WIXZLN;JtC-VLU5hFEos(kXbHcG`3prwMz^oRxEyDUWW>A5Fz5Ax zY))ahFx8PV&AH@d^Q+w;;~_0{ZMImurefa+*3ULO-cv5C!=2w-@x2N&(zC#pAwk_` zfM?KomOx0}eGY%Y>GukdGkSAz+wbJBuYQOnEgMGvx2JC+gNpRQ5J#cXyDk zq`>?KCp_kduOyw&YFeNDL(H??Py~1>1*vy(mdJyXJ5LxsZuV)#^4Hai_cm=ZzEPBE z8S=0ByHmz**fd%{{Lk$VCf|GA*a7bmSNu5g0|9=Y62LFnvPb4$Ag4173HghozbP$d zO6s*Z zSe?=690u}7gS;aQv_`T=OFn3N%`+4$X}9N9W)&Z^b3Cyywt zOjctL8f}9sE6U?rH;un9XX{1Atva-B{9fx6s~)oW8-E(jjb(T4$ev1tZKwi#&+~BT+z9&Kt2BL&WhX@5 zUY=aF5KnzpW3bN#Z6U3-q}gL`)+K1!^lasPt33-X6MEAnU00FeHn zk(q65R_DVATR{C2N}AI1I1Remm(p`PmcAUHFb?)WlfAy$DC6F(uZ+7FcF&!+8^%g` z{>v}VD-OGyxNyNF#ld)}@0$rc`3O(0wSNS$uN9yN$a>d}DsLK9ugeN4t<=6xM@YOA$t$EZ`*rQsVo$NB-hQu5j!c~R2zNOIa9T{c1W$v>AaKcXvp z?&y(o=ZzYbE;F<5+`S;%pTB$eyqvUZHB1MS*Q_Q30MR7R1Ai_ZX^jh$=d%yV(dyUA z<{+lM17v3;()~vrS%`Gx$ef3Ab>D`a+xJO3rRd+BJa}pJ#z(4BXsuk`Bkh&8BSyB- zms~!+Ysk9IkDco%WP{oU{4ddw#Oc< zyZ8I;tzFPEC&qUhJZ0F>UCM@TZJYJ)-dJCFVBh9ev%^E?_u6u7?^eC}&><;3yR8PF z(Ka*~+o2x|l8*6trXSJ1gRo+!!YZw%oIjs!Kcgviufit1PR`D_e}95nKIf5qsu-%f zzCL9>{Rds;tiaIRx~gUU6^TJL)0&RYj9HTU=DQEhp7=-lZb_X`YEIt))6%pJr2|$L zFSc#+z-l!wzP|UyqYElyhWUy9lVg%H0d7Lw(7F1BTMGLaejI1(3sK{+cv4)(kHck{Z`3i z+a@**3SKrLEpy+T`;#{mDLfSs`2(UuiZ|=kCZT>y0R25k33a?bM zTv0Ff*D<>}F1$0A168fcc12TVd;V4)G<~IMyEhjuf2%{Y`bn>)&)B!Tv#nA0ZcXZS zESa28r)BHfam|!gwK|n5-K*~KNt1@x?OnQ5$65nMjx?&qCf2W3txg@eqHS7g8iZsZ>-=O`u{@VId`|k2;h@!EoWZ9OHvsQ1~ zG4Gfzx27~`(X4r5y~IL@X7SGKH+@S;W!ba|ONS2By`$nA*00|>7+MiLZVv${kG%4Z zGo0-R3p{W|-!o;(9;2I=+_B&2^-%YbC1ZdLT%Q^N3b(^$p+H{uuv_`dxHKWSwUB`|cn$W3aK=%g2 zCXE`VSE*4e>XjN(kUxzbFLRwi$N$@yko28$*?ve?X^5k76Ps>P^j(Y6*LE1SPLTs< zNWFG)WXvm=6!cm+ZB(n_1JYUFsUlOWqm0ti;5l0u9s+11CH$=LFQPU=_7*D-33w0? zp5W4S7%$4b?l?zdhT>3o(`hDSnsj{-NWKO^{87+%+&#yhXM3VGx?lms8?8!CjPM%o1_SF6k zEn1{@XxThfmYTb9>rs&VTjWnK%D%h_@T8Obo0&x>M?;60>{toi-|c<(*n(wsu_>9yY7}x?Q{M?b;3-*0%kSAxiJ0 zo?Tls@6`+SLu0aj=yyEEl)A!WO4ciCzth{Y?<}@2Rm-V=-ZkDbetGjvgk)O1ZXL=r z1LNWZ=(CrX3CwiI%=tGxs}-C+WXd|@$)!(>-`39_Is2arZ$4O`IbzbbZBx?LR+!m+ z$h?JvyHD4urR^$T;pn8xx4*kG>1c(B-Dz)q_+ifGu^Aa-C#+hf1`e1zbLg=7^SQn| zgSK+d#_TVsZ+IUF)HlZLdFxv#z4%bvwr;oX%6wP8ltqnizE9bg6xeWnkF>2Jn`Td5 zJ9+kr-MgDMyYt`{UjF>Zi2lQPST1mNxl&4z&JE}9IdgKuW*Txs?#SK{$o)F|CHUrl z&fXA`%f9f@m3#NDkdMXa@#9D1o@I2_7JaaN$9ox5I(8;QA#mbqP-;u%ZiQ-Nx4ReR zA};*q%TwRWPY3;&Q^|fKUuUn8c#PAB_%(lH9c&c9qX{{c9Ch<`W=zhPbklsK-Tag8 zbYa)SUgaw>MavP5wB2H=OTmP_ac# z5rwtsVg#=9xMt%TiK_{&wYcWt>Vc~-t}clCy+!d6y`bP45X*xv{2p)Fg56oLVBze)Bub<86?^oDNV^r+C^3S+TY-B3-hB_h zn@b|hGEl4l&SLs){4ONw<0_BmJ(Tid3F0P2;GSPi6?N2Y@Zp{=Qh;-ywoohqO+9e$ zNq1$dsE*%*={XD+o0KAsGg?Wplz!t(-X)xVA*ZL`J(X*CR#o&<4vQ%Ky#Nl;RrG?Q zGTm{N#MMs`Uh(J)#ljd;PVWIA!LcSfVqYUA!r_VaMe><~#BJxl6Z0)~GI?yA;)NT!DWR?pJVa*A7G0sNT$apt^f@ zEr*<$e=orO*+q4+Rji{rp|VrndG1tp#^+8(uk&pWs2 zGmd+fiD=_%K>KRsbwn&+{yF7>+5yR;tGq7yDGk2gtX>y;)eNyv9W16RmBePW>+MR6 zXn^PG$`jFB*(|V5lJlbw_UX7U#Jv;lFa+9bD+R@S*bTgeWKSsr{tk3Zvuts^MspY$f8g-icfeiAhx`DBbqWVHjDjezxBEN z#J>Xgj`|OLuSbY@!l|!;4j3TDfsXxrQ6IF)$wMb^UHoHRK>Ratn*6h){zi)xUV$RZ ztGCF)J|dytKtA5M28g59AhgSqh_6rjZ3vfbsoEOt!&fw9{c;YvsHNzQGMoKLckpot zXnMr_bm=wo9qEZZj>aZWT0q9Zc+w{LhJ@gBdm!C#-5KW{jaknl8k7kG}7H`Kjt%KvH zwX!&Cc_P+m*P%a~3LnfSKGc203H_E>W%*gG!m-F_tha$9OeCpapgu^>P}kg!7C~;& zHcZZR0f*9eo9M7G4h4RzKh;i*BMk+;pcpb=@KNBzx3ONPhC% zoitKABw3{P!ZLeS*wm(?9_VB~x$jod31#f5XF*r|fO~rpk6_}_kcU=UJ~7eywrB`h zspqAN-TGG4^FNT4vXGSnBGeLuG1UOEo^+O*XHGs4k7yj{>NB3dyZH5jyU_YNw!Pr_ zi^mer@!$2Gi~ldbBMN<#W5vtfv+kp@5RCyev^&rG$lXWBpxvK&>3diI_o6%DaXo*& zFLw5qu72~SchA1q9CJPEo9XXSjxY`T#l0$EX5zdnZ(>g3jk!r@Je!K&6svTr5aL5z z_y>LRx;{yqq)Xk2DC7k&rbd5^G4C#U3h`cwiiz02JQ-^O^R)r!_m+$H${S*ydKvn< zx7cFMa?Wiq=TZ8h|LKSEK|K2M?V^^tA8}&3iwWSnFOA9d3vtQcf%Cx%+*h+)uwgD|#iVp%VCVQfnI?$SOLb-k*J{)&&|lr}^3 zfgWCq^HetiUk3D01;q=`Mv2ne4pAK;f2&)Y&^{;dqnhaC6(>4l%-;oh&C|TG&!Z47 zZ|sxE2c307M1bBQidAgZ#zWUGhi=@1dt+RIxUS>xr!-c^??S?+^}xK~G;{~_g1T8O zx0J^7EBwtwukS<`(9^CmwiS;1ThOFO-MMp=LqXIm_gt z&GSw)BHwMeE)nl=Kb9vi%EN{CMR(%O9>-sN-9}pQL&X@8@n&XUG zz_D2khYoFsF_Ecjo8mqT*JAZ4`V!(R@Da@zOGHqeX!Aq@)eqO#cri}tDq5&NK#vzg zJ@n^#8HfD(tFy##wHfZdm;+A29B`6IQ&)=icsEe(gmL3>k?EQrYUTO6RMZP-7c+2m zCb=S6bpC@iBC4Q}UKBbwKb~2H#jy&|n_;M9HGVg6ya(9GK`Y^n88%^<#ITj)XFPAs zFvW2mzuWNdw*0o8;}blY!FXmeoW*c9!#NDo8E)lVwlU0NxSin+hC3PVW}JH%?q#@- z;eLj%bG}EIhNBFRF?@sJae~sHQp#bJqgsv1sKzm@&aeg`V)-y64tOKZ_i8}mfH!l% zn>pZ(J=zqTg*f0Xhy&it0dGMZ@MaEp3*vycAP#sl2fPJwz*`UpyajQK^*WF!~t)_>?fSW0dGMZ@D{`YZ$TXJ7Q_K>K^*YL>0AVf1Kxr- z;4O#)-pm1S=72YIz?(VXtr7>kRpLN?Q3E@i@{5|H2w-jaXXTeQ0dYQr<268UhQYuV zDiR!10joP60M>Bq2CV5g30T{)6)?r|Ct!Pi+X3{4!dLtjU}yf_MHImA)$mCQ6>At~ za?14#H!$4D@Cf5M%J3M&Hy9!cD!x5O*kn!05hVhJC=tQx3~K;}fzBTQYdG!#)`quS z7}8&Y$6f))kAMk?=NgXvFMk4dM~)GqkRt=omth%(p^p1_LUWi(Km>BfSEvP~QR4}}T9aX2!19o^UjQ33Y{Iaq<5xUM z;@>F@+cJb*8qYhR6y?F&p8z}a@7?@%55v6-_c7eh@Cd`B439BXiP)=|LG$ z4BudQoZ(5P>J-D%49_q;M-+ksC=u!o?fRhG=t$xhO-#XW;lmoIzg1^Cs9QdcDw}`?)Vlkl3@(PY785p)~cXp z2{vJv#IP0QzY269!4$NSD$s%SyDh&><=-6~pW#VI$2q{x{CghbT*+`1!_^GeFkH(p zgW+z*vxnhchWi-qXZSkfKf?JQWq6F?8w`&#JjrQJF+9x>mLgDcjwq2uDHqf%%B4mT z2h?c5s?d020KFN8!n>_1ICB;-l3@(PY77&MU+}!T<1%0kM{B^EjuC*h9ln66j*kI5 zI3@yibYuZ`=HD|I=S+sP7|v!mhhaLyd5nK0!&MAdGhD-PEyE0knVkE2h8q}eWO$Nu zKgIAg!!r!e5e+CiN(7k!osb!n5n2?bh887QonZ~YD3-}6mdPlV$tae|D3-}6mdPlV z$tae|D3-}6mdPlV$tae|XvP!Gc%m6kG~teAFjNlB$Gn3&ghO-&YVVKTvu45BY?q&>o817}bkKulXM;IPuc#Pp2 z439HBM|nZ!K_SWr%GG!(g<6wgUBGJKwum4Nf*Zj{2qd>zzJfqqdedYrg^q@2g4Sjlh|!_^Ge zFkH(pgW*;#%Ql8t47W4f!Eh(TU5>@TxtrOLerVpYVkGm+EL!1gU?ijy46z{Ywpu`HG@;3poO*jvY4veff78hN1soZC@Uk zRdKI4EZB)G%=RwBu>Ts)PpnOA}|$KFb~cIjnj!UiSu}L0rTlMKElxqw9bPb z{}V79*EbK;YL;?h1+kJ?MXV-nA!8Ghl$V9{!!vF;&I{$;wj>3;u+#u;yL0= z)N`KrGVv9S@EF{-9m(2JFBOXes<~ z5m(zljGB0k(|D`TjUOW4_eP|?3g5T@?8p4w#Njud!=90N){TdMG)CUo2aILjNz_;M zc$`=LfNmc3;2AX@XNul4(dq+?=bov=?h=++s@XQ>K zdx38IQQ|S;apDQ$3vBf%=1&vP5YH0N5nseJZM^joy>XuSGVv8+m-Y$H3iKn+3UJ|G zfS$rgK`-N8@Ea>0=LyaMoF^LN^f`d>qH)rV9|NZ#KM7BFeSjlzUQNPTp)r=|BS(7-jCUIm1)d*OJ7?i zVPruwe27-Vhp>Yu)jrl_jEhf!ZsIOtJ8?I04=@?;8ZQHbh?zG&Lq3bxr4i5MIErU- zjc%d`n1Wir1O^coqht#HP5_AV*pKoW-9!&?I?7)I1`#uH2bm5Qja?d13rA5)qnqdf z&Oi(=3>ZYzckmgwNAw5cTXVo^#OcJD#05k>vS#4C)n$$nj}ea(PiTaffXb;YD;LpC z)K7p9KfW3O z3n&Q-8r?(>a6T;j5~zD~KI(o3)V(<$<*^6lHR|4+55`~OH_LUuq_bbrd1p`OJv|+7 zLzURC<4Ec7j7A+tN=HBR1?o6bI!4?TppGM@TMyxCoQ`*p{=h}dXECqiNa^T1jXI8$ zjxnN9$C1)8Mzn>~#52UR#B;y_~LeFQ@aKo6dV~CR)@N zI`sNqyb&Q9nTZx@yqlN|Z)Bofe+25cs!X&?BWA3D`rRrM?b2lyFyF!a0b(cdAn_3K zFj2olWulE5^*dB1+Ne>#LuI0k+S+O28RA*uIgMx?%Aj>ni`Hq3(>l>QoyT)7a02&C z0WLy|DztxzcWXp>jT4AdfQxxPFXs8Y7_Ga4J^FlJ%>G)8cImu6s~1DFMtxQ3;u+#u;yI1ba}~ca9|?ah!Bt)3E@C@zH*pWJ3?up^P{+*6EFCj1!&~!H zKpitL!@KjdKpitL!y9x5P{+*67&9-!9q?`BbAE^jUS{byd6}i- zX!9Vah?4>jsIc^Tf&!J>4WybRY9jXF+VhU>{mL|(Moa;hz-+H$Hb zr`mF=EvMRYsx7D5a;hz-+H$Hbr`mF=EvMRYsx7D5a;hz-+H$Hbr`mF=EvMRYsx7D5 za;hz-+H$Hbr`igtt)SWps;!{f3aYK3+6tR5IZ!4&_f@&+Mwt{La zsJ4P?E2y@DYAdL=f@&+Mwt{LasJ4P?E2y@DYAdL=l4>idwvuWqskV}8E2$Q59yk*! zskV}8E2*}UYAdO>l4>idwvuWqskV}8E2*}UYAdO>l4>idwvuWqskV}8E2*}UYAdO> zl4`4{wu)-2sJ4n~tEje$YOAQWifXHmY(;if%3~hJ?~QkzONF&mSWAVqR9H)ewNzM3g|$>zONF&mSWAVq zR9H)ewNzM3g|$>zONF&mSVx6*R9HuabyQeKg>_U|M}>7%SVx6*R9HuabyQeKg>_U| zM}>7%SVx6*R9HuabyQeKg>_U|M}>7%SVx6*R9Hua^;B3-h4oZePlfeVSWkuZR9H`i z^;B3-h4oZePlfeVSWkuZR9H`i^;B3-h4oZePlfeVSWkuZR9H`i^;B3-h4oa}!1z3( zk2pUY@P^(GsOPX6a1ZGZ)N@Y_jL$bPKHtFjd;{b24LI{rlJWViw1cQE>};i-t+cb1 zcDB;aR@&K0J6maIEA4EhovpOfNIQ+R(?~mww9`mCjkME9JB_r{NIQ+R(?~mww6l$N zw$aWu+Sx`s+h}JS?QEl+ZM3tEcDB*ZHrm-nJ3D9x@n*DZ2kq>jogK8ZgLZb%&JNny zK|4EWX9w-ckRUQy6IWwCOmg()bkfju>32ao@H+0{6!P&{{(qGf6;{Kgf63J znVUF&(Zub}U|;F^izYlH?Zj`+YW8NbH@8$(A$tqiTgcu*_7<|YlD(Detz>T{dn?&n$=*u# zR}_OkBYPX! z+sNKV_BOJ&k-d%VZDemFdmGu?$lgZwHnO*oy^ZX3)VF1i2W{D)2Ji%yI@VD zj@a*lg-`H}ab3Qh<=a`lo#oqEzMbXUS-zd+ceDI%mfy|tyIFoW%kO6S-7LSG<@d1s z9+uz3@_Sf*56kai`8_PZhvhqPuYcL1^7SnB|59bl~ktaX63I$5iewK`d=leIcotCO`lS*w$^I$7%=YaL{* zgRFIswGOh@LDo9RS_fI{AZs0BtwXGJh_w!})*;q9#9D_~>kw-lVlAwcMC%T-)?wB< z%vy(8>o98_X05}lb(pn|qSiI*C~9fcQ6Q`gBkCy7QPjeI)Y7Pdh9oVAX#)(O@+!CEI+ z>jZ0^V679Zb%M1{u+|CIdI7brS}&j$5M?y#c+m?eqftk4PNB>dppMdtaGDlQ)52+5I86(uY2h?2oTi1-v~ZdhPSe5} zS~x=sXK3LJEu5i+GqiAq7S7PZ8Cp0)3ukEIEG?X+g|oD9mKM&^!dY54OABXd;Vdnj zrG>M!aE=zv(ZV@eI7bWTXyF_!oTG(vv~Z3V&e6g-TIga7p^GsD%q8Q!y9?JejXGA- z#TY^to_79-ypGj$;b}*sj@5MGX-DUEtftG-v6?Q%5V{yc=wb|^i!p>Q#t^y~L+HYj zk1nZW2wiyc(WqlJU3l`*sADxnHB5c42F%!2?i4+6wI2oUoiK+J;x5v>Jc9t4Pa5FqA3fS3mX zVjcvDc@QAxL4cSC0b(8mhnIs(DQ~k2lPA$5c42F z%!2?i4+6wI2%hi|O93MC14QHph<8#TB0oSxet>x22O{zVMC1pE)sjF&et?Kh01^2C zBJu-7J^ApuRyGN1!C1J5UXB+SoI3Ts#hRZy#lf76^K=@K&*NNV$~}Ut6qUv^$NtQ zS0Gls0I5h?3|*Fv0_9BRrrHt6qUv^@=Nk_JE5XaM1%U zdcZ{wxaa{FJ>a4TT=am89&phEE_%R454h+77d_yj2VC@kiym;%11@^NMGv^>0T(^s zq6b{`fQue*(E~1ez(o(Z=m8f!;Gzdy^ni;VaM1%UdcZ{wxaa{FJ>a4TT=am89&phE zZhF8?59oCrEx0o3bHGgxxak2mJ>aGX-1LB(9&pnGZhF8?54h<8y)s1G(dU3(8KP02 z1A1kMMtu&r=>a!A;HC%M^njZlaMJ^BdcaK&xak2mJ>aGX-1LB(9&pnGZhF8?54h<8 zH$9+Np@5MdaMJ^BdcaK&c<2ESJ>a1S^lFp0ac|J0K(98@s7HZ^9`Miu9(uq-4|wPS z4?W@X!MudcZ>uc<2ESJ>a1SJoJEv9`Miu9(uq-4|wPS4?Wa1SJoJEv9`I-n-2AfurV)s~zlX1By(Noei@c}? zs+p=x9ale6SNwwf()^12Uh{YQm-t@_NDNpT@KLYXy|Q~1^=jz#O0V~NI|CB~Hw3;P zG$CkX(7B*bf@cPA2yP3$7!n#18?q*3U&xg{QGIIqTn?QXS`zwP==*&~_RZ@1bl>xR zuY?7Kxx=cHVVvkl&!RK^cRZ27NU+d+?ps8_>kdI!>10PH#}$f+Tj<5e=z*&2svWFh>;`QBbJQ#YGmk0 z$H>@`$s-qz+;?C9`-a~acVFs#3-4Qg-?~u)MvWZh9yN2+qEV|xZ5UNIYR@R&{lo5$ zy+8T>h4(MNf9?HM_rErJ>gai+b4Hhpt{B}i`sx^KO#d;%#yH0$k4YPoHKt(9rZL;c zbc{JQ=8ZA$j`_`)zea>aERDDp=@&U5a%5y&_j65EBKJx9z4W9nksW1fq(VoPGHVq0R5#J(7NA@+lD zJDtOwan9+^Mb3QZMrVU_pYwU=>&{Eg%g!%dL9Rir2-jp+nro?RkL!9|Sezp+HZD1C zVcg2N^>KA^d*Xa?=i}atdoS)v-1YIH;~nE;$0v_pIDX~$_2X;Czv_0lH@V;UBzn$y z-txTf`4o>y{U;2c5I14^ghdmYCbUnuII;J{sS}q>Y@c{3epY-<{QL2rPO>HiO`18W zX43IVZ%w*BIcReK$-^hdO`bk^!Q|}8`I9$JuA1C1`PAf(CtsQT`Q)#rES$1r%JM1O zr|g{4G3EU!A5RULI$-L;sY|9VpZfOHcM=9A6eUz7v?Lr!croEZ!UqXg6Wfy_l9ndD zp6pDnOa2%?4pfw~KDBphSn8dr6{&TpSEnUUYnyg?df4>Y(~r(rHRHvZ_soo*Id$f| znK?7p&irteoK-Mu)2!{YKA3g&!9@?g^57c}zWd;Zv!~8}V@~fmgXTocnLMXx&iXm8 z&$%$?Qko-eRNC6K%X0_L9W^(4ZvNboxf|wI%&nW-G`D?j=iDoEKcD;6yy$sF^A63s zJU@E=hWW277`32d!6yr@r9Yki@xq{m84I%)KKIZ)56ylk`=R!S-pv@8F+C$KV_n9k zjCV6-W>98RW_#w37KJWKTvWE`!s0s@XDog-Yj)Potm9edAC7u>>cdALe*WPXAHMML zr6tiz%9dPOa(T&@kMw?I@*@|rhh(qGe#2Y0bkWlGr5`PeTUNL1i=2#{cXDUtzP&tc zdB*bWCxGbUe9k^ZLQ8(eY7C7U{S&Pf}LxI zt$B0JM{B-%EbXz*$38DwUv#wSaG6_*Gs}mhLuE>Oem=-dAD?AX;JB! z(!Z_^SlfT?thH5ZFFrox@#og1uFF`rYTep(W$S9zZC`isiGfcHdm`$IwNIRR;Dp$wdBEn8o86nIZ(g)HfAhx84V!mvKD7D#=8KyzZ~m&R zciDiltg?=>-;`Y~pI!b|MO;N^Wkltvs?@4itDV)IPy0Q+m?Z{ep z?eyA3wX143)YjGRseP{Y_1br9KdJqqu6Ny_x`?{?y4iJ0>eke4s@q=IS$C%H&AN~3 zzNqhAKd3&UesX%OheZ+&g+rL7-sz1Aoj2Q-dsbT`gy z%xcVUgbV+{e@{1VZ)|UTuJK~y7u)XHHhNp!w#04gwjJO0`SxMkqqa}pes%koJFFd1 zJJ#&ju%lteCrznM8BK3DuWfE@320f~a-`+8mTRpMt;wxfttG8>t#7q{*yh(Zu+7<4 z*Y?UY1D=V0X5lkyp4s`#b35hE(4B*Jj@~(X*N|PSc5T?zu@Kt&E22u3EAV=le}l)o{~LB_Pn>}@}4jD_TD>a@94b~_RiXy zv3J$p4SO5*?%VtP-q-eC+WYaoLHkDUi{CeE-;#Z6_Lc2x+Sj@7%)U4Gy|?emzU%wL z_7B_d+@HFC;r^xjOZHdoZ`*%l|BL%C?Ehf@r~9vW1a%DQi0Fv#nAMThQP8omqp_pC zh8n0#RNfh7ml94I@`bl}i|a|hl$@ZNz>4*az z1)VvaC7l(WEuBX?U+lcl`N6?K2Nxb(aZU3JM#RIkB)rt?8s-AKU?$cg`*)yGmfr3+H~~Nv7lp7#|n<^ zId<{b<>Ld7FFf9H{M8eoC+3}4um7{~*Mfe1Ed5o8NAT`1v1aBG{fC3rvwz6srj9p?DL+@j*V!U9K3RJ8uz z#2ywRO%c1UBd^%ub(9o&b8=UEiyn0pE;pP}HieB*%L-Q~tt`qbF3Iy2I8ZaUsHC{C zz?d)wtyK8Ez$$_NbI=eVc#0-39AU-Ra}9u+~}jzu&)qX`BpBrVsUoF;JQbMf6st@csuE3}pad$tpQ4~4xqTir7sMIWuUlHeWfrD9mj zgC(uh=G5v-uwSd!zclz z!)#rDjDP_cK?Cv2Zg*ODS%dI(gdx`5_^!ac;2mlWv%)chH3EO@cpv^=@P2DF{t7Ju ze{m6^p+sapEsJ;t;KJBTA*CQ}I~aIN6$l*i?d*i1s97onb24Jsr`!nOLDW z3t!osZOy?IVJ=!W-&$a$TMMzOEW^sgdZ)#BlXw_wWFA3`$!i@)G`<2eV=v>|o4>)_ zSOeyjcjFrtox%_E%>I}^+hJY9_o3=>rFmKeSRYuQ;hU{Ttv^|xTVEi~f5Q5A>-+e| z%~E)`5uW-F^v|2tThsj)+OsF=!4%`zsHRG zD)hml=+S)md>=gj7|vpS4wa%O)>@BSpIGax^*FD;Wj$$au+CZgt*7wC&`s86>x%WM z^&-Bm&|3uJr<;RCi1k1CG;1IHENWj7X5A2$=qLJ%+r$8IyBH|$5O<2Z#2_(P48c!* z-Xrc64(m(nFZlNBFcB_>ixFa^xKE4{_lwbDjEE4C_>%Kj5iMe@{}QqIMQta3MLbT7 z7jEG}+-ahS7nAU-;#0&_>m%!zB0(gIB#|sqM5>sEx3n2zrg%Wi5)b10opUUobyB2> zx%k%2e6avuC|QWFSY?Pz>u=Uq*2mVb@GG2)MV5G2ED?{0Y~dA4#WIm2a>a77LaY>d zVwHGQ&3Uk2JxiWD4r6V#AZ<@ z%B^>;U*L-z?^{2!KD2&n{ajRtN>L@M#nWPos1dcIPSlGAu~jsRZDPCFA(}+9Xc4WV z4PPqUDRzl=v0LmBd&NGnUv!8AqEj3chs0rVL_8~wieuuqwO5=F&xvmfpExO=7cYoY z;2jXq< zL-8Z=pW>qUvA86DBHj`ICEgW374M1v7VnFni4Vlj#fRb-;v?}(@v-=oxGa7xej|P> zJ`ukYSH$ndr{WLds`yM?6Mqz+i$94k#Gl2N;xFQ_;&0+B@jv3axFIbmq?AhfNq-q2 zd&%B1PzK3h86x}0P}x_8$$qjwK0!D@-Yy5qJLH}6E;&dJmP6#-@*a7wbjYD{m<*T0 z}6PLLC2yqqK_%PDfIOpu8( zNhZq_nJTBr>2ijgDIdU(Q9meW%Q-Sl&Xx1ze7QiT%Z2hGnISXfBDq**$%o|<`H0Mx zUb$2*lQ}Y1E|)9hN|`5D$wy_rTrCS^plq#=da~&ym~}sTYpwwwN&Bv3RSLJu2$fe(^jfHwMspz@~t*}#o-z25BPr6 zcFZ6j#`9Vep3}agR$H&C0#&HisK->1Dpn<`RIOEyt99xLwO)NoZBS3Djp`}2No_{N zsa#d4N>!z*)zfMVeq+8?)v0>bpth<;wM}hTJ5-ZuRxPSkwW(*+PPI$5tKDjk+N<`d z{i;J9P@U?aI;0M(BkEaoR2@SM>x6nveOvj|N%g#XL7h^k)fshGom1aYFRGW+dG)e- zMSWMjs=Cx`>fhAs>U-)9^?miG`giq~`VVzM{Xo5~euzlef2xb>$Lf;$iF!xazN^`i=Un`UKy)zoLGxK2?8ESJh|gn);*q zT>VLXq5iDCRDV%_Rew`ossB;e)eZd-PJDh?`T6b6HJ;I zki5(bu7DgnNd~dE1Y0`km0}q2AgTogq}YtPOoCE!3QN4pw7j6)ud}^UjE-D84M?#K z=Q0VN)~zIXMR(p-6B}*Pn2>3Byj|_Jt%t1Wu@OAIyH@bZ?!4dhrQRaHm4JX5C3*Qd zxdC}hdd)Cx$TMx2VYeaA_Sy`iHqTCjW_;ZcIb){GTNOOBn<98scRu8S9-2ZPy=7xX zQEqNQzPBJJZ&|=B@3PX8+<<&0A+vgx%kQxfFw6E*J`=xLP~n#k2$*fxFR<&+?olPA zpvOkQY`cDe?d1aRn!@6eqQW&Rb5%;g3YA;1qSqYbheG3rIkq1Pne>^nvb11@x2SY= zzPGfbPhrokfO)otB3r|}9<(7vJvIX7*&2%MWWHUim`U*bZr24DcjrSE^e_-o(qkiF zfo-OQiQfX^a4|OXHe!NFMvq%1k?tH)^yRGY)1TFgd912?hb=E(>uwX^8|D2VDMFswa#B^e* zM*F-^jSfoCT5U7lud}@pQn;&^Hi*qslV-@}0+#XUA?KX%-BJ55Zo z)6{W+D~h~pb5U?NYu>{U$fH7Y@oNGup~D>H_scAvZgo>&F1djDJACk3|uw1D`d{OCIuUDbnE>*O$FrZjBD#o9QDnZ)}zgmNKEyF*^@h{Zw4$)?B z%If{y4)QXZYg`f1Kfu zGyHLeKhE&S8U8rKA7}XE41b*Ak2CynhJU=_A8+`_8~*Wzf4t!zZ}`U>{_%!?yx|{j z_{SUm@rHlA;U91K#~c3fhTm=Y-G<+7_}zxzZTQ`W-);EahSzO)-G= z*KK$`hSy_wJ%-m~cs+*KV|YD=*JIl4G5j9G?=k!y!|yTt9>ec3{2s%fVE7XZe}dsp zF#HLIKf&-P82$vqpJ4bC41a>*PcZxmhCjjZCm8+&!=GsQ6Agc&;ZHRDiH1MX@FyDn zM8ltG_!A9(qTx?8{N`!GnP~VE4S%BHPcr;ThCj*hCmH@E!=GgMlMH{7;ZHLBNrpek z@FyAmB-8#R!=GgMlMH{d;WzgsXR_f>HvGwkKiTl#yk8|7{$#_SZ1|H6f3o3EHvGwk zKiTjn8~zl-pJLjdV)#=Ge~RHxG5jf}{V9e&#qg&X{uINXV)#=Ge~RHxG5jfpKh^N3 z8vaznpKAD14S%ZPPc{6hhCkKtryBlL!=GySQw@Kr;ZHUEsW!jM-1lAPzV9;keV4iK zyP|D=SG3LVinjS((Kf%!-1lA4HowcfySmJM-xY21yUcyx6>amoq7A>f@4L)>-(~Lm zF8jV8lVa;bO8>;9*!L}@sR0l1@i^ddJ9&tY$N`Tt34G}0qf+4GH*@+v5tCw%ccjLi zJ>IcReIcx{BMux?eUIn(|&urW81Xf9`7+JsWAbW_KEuh6Z`D6M>~!hc6+pA+pycC9osg0s{J$- zi|~}LkCd%KO0ObitB}&GNNE=-y^54}kXD!GH%w4w(FF+`5A0O`wEGRBz)U3!aKd;Ce zuqL+{uTA#RghaoT(xO6c#2A?|_C+8zCMGU07gMRLy(PIhfrz8!>bc&PAtfsj%dzvt z!OQd3-pq#-Ls-Gh1K)VjPEE9(gOtueO6R1e*q6lARQr;NG`Y|GWw|+d`T5?c;?>L6 zgr#=}6}aQJ?(MJN%KLZk)9>f{MZHHccJ(**ef?@5kU*=UjE;O=vR@DVMfyE8Hz1Ma z0+Q?`*-ldIB-Ku)*~xS}nPDe0?c@PFnPn#rGU<(1{o-OB!I^FEp2H+?eQr@b@&-i&i6Qwlu$(M}ikI^uv7L?wE=>#x^k@ntAj3%gwMJK^l8Uk7y2egqUy-H~QZa z7vioUhK-mFw&O{rnjK>@2iPBW-VRkU->+vt%RV~4yBUG{6yn~n9sw~^th+_Qb|lR< z*fZW{m$c(?%=f<~Zf7611AELP!ot90x6|w~gT0-IYRT++r_m#y4%u=wV|T7!3o`(!xFwpme50FLN{5U4mQ&of|e_7E%v+!^8s`1WFC_~ z%djpeKR<67&yhaFo0ny~bEtrwbF*kk-m%j&mEyyPlT%>??E`;8#g3g zB72uSZeJ^dcw^$ez~zOdMJA`OF8Wg1yEtzhGeNvhF&i-7mc77E((PoSojhbG8FrFs zCySWa7ifKVq6}uV44pADbk>%^qnezVf;{NP4LOiEO6GFB#d+Ssb$Q-ETN#e_V)@cF zz3q#m&gd5DdUh*y88Tu|cT8OS1V?)F{-F!oY+99}(^e7(XGeF6Aq>3>PSfTXz@zFtXVo=3})vJ-s+bBCauioh{PiZ3u}nJ*}5 zX>z2`&)(yJ!SIs-ej~CSDK+6<-4rrggS9%JV=!89lh3C{gnN@w*FVB1vK`hrIL#O=|MzK{rq3pOKt zeX!q3VNbyQFoZtwe!Xc8JZV``=;LWVE7hCrJ{clz2Wx1ABi=FXCM$g7bw~R8Mnv5a zAL$GGzmEAt(lQ+H7jaTr14lTbe7%#h9jQD?&_Ha=sHvF|zSJke6Q2(g_#QnN`lH8g zcj$vGhAM^M2BX?Qbg?#y0b=Wz z;S*!vUPn~8`(&UPfG)T*;$#TUgPvuL<{20>II+bThc8>7X;bHByr3L@j=?Xek$!_R z6BBVJQLuj!&Wdb(I@`lYC1vM?`}~r;IXKN!l6Nrj*_k-&P|S-SPSxEOAMPGJlm?<4 z@neT(8aa1F_(Jq(x^1%Aan~))u>A*3xiwMY4o7^AJIa(Ba%(x$+<&bJzK|p;sR^GE zo|^6Z|7wpOP9ww7q`~1Zld8{Q?eLH!oy>q&Y-=cn(T4E+}>kl`lXEwzWSw(fj$QsAt(DJA^x9J^`c7R|%|Nx@s# zM*Ne4|5)QlT}z+Gx`)kJ_E`%ua0cVXbF=HsfpcNjGClm%h#5?E9lPobeQ0U8If2pL zH`{sN|C0T`>#I@!%Vf9s`~LrBvVYuXqct;6DLu-0F`j{&4jv;g{BFI3jQM{T{kxuw z_}A;*;*`jLz1}}=UsMFH24f?9QTCk<4^!XijkV9q@HC@`k`=zj7nXu+!>DXLi25RHBM0|%cB3`$DOd_H)TOqrL6BYtuW?BRbx!~X#@{FZ+J literal 0 HcmV?d00001 diff --git a/data/icons.ttf b/data/icons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..86db4361f481b6b04b9c1ebf961d43ab1961321a GIT binary patch literal 25260 zcmc({33MFCeJ5Pi-P7H3-!lLP81!I(0SF8Z;v_+k9O57$5+EUvA~BRiVhDgBNQeMI zh@vir(G{7NCBOZ=URuwxBtJ>c%Sz6GjBQ169PP$&6kE>9{``5pwz3;5*$wSYY_DTy z9W61~-@m#C1S!&1_U(Hg$m*)DtLymJ|E^)2G3I6Gnat*Q?7gGc_-M@o$hnHJZ_nQ5 z*8Tmry}%eB!Tb2cJ-PXM`+NT$?|H^-e?M_%(eT`@-ox15H&MRf==}6ON7nzZ2l4(Z z#yqa+-06Ab`|$ocVtsn{{-awTIUZw7`!r*HPaK=dO{P9__)*4oRinJ~7&5f`^-@&^ZakTrHl;^;oUfyyJzZ~ z&y}J7;aSF{Z_dx1Ui{bpwD1gLBR!1C_s=g(&HwkouRq7w5e4->$7t>j*21 zKIWOtEuLg$j7sT`%Gaj(?96nI=~f9x8I^M6aHbaP%N_jV%!cnjAblBmPnj|QYqp+C z$YnMexi|S6IXW=O-eid@Odef1&JN12vQMHKjp5oKdZ50sTa2X<@O^2_tiwl9(|61^u_6=qS*YFG**tz+w0J!X_tp?FfNf_x*dV)&?PR+!EZV!@^v5Myb6Q7? z9)ri&ofx^tO91W<1ViCSw4}5wR$dXWG!j)9W=*QLZe4vt8l!7wtYv*`TYE=m*M^PV zn|d~H*_zpgvGfmY-!Vv|`2YXUMMIE3VGRVUg4H$yM_gqEg1@8{XgzAJK#bl%+-3#9E%wh0PQ)EnpwV?%!Hsx>6+DPHS^+zOy*2}I4))v( ze#Bd?5I~%0)f_-0&p1{vO*=|VJjGjcUyt>VUHDPA4aS|`!H&SYQ%f3P=k1%73lomVFlW& z{Z^<$e839p5RX}*9&y$Rw4Vp9K)B{kE70EFZ3WufLskHg16P=V_W6hvXrCvn(297{ z3bf}_R-ipUY6aT!X)AOhK4t~l{~0UL{vWpj?f(fYbR(X%!Y0J`Sb^Z;q!l(Jp0fhM z$h;K@Mow8FgLuIT1S6-dKrnKz6$nPoSb<>VJ}VH6oV5bM$o*Cz7$Mq9fnel8D-eu4 zYz4r_6(lJDJ|xCg{#g#nPGHAMcH6Fe^~hKzNNAKx6AH(9JAIG|}4G;crhx{UJ4(s7fK-*_CLG zNT&)dHSN5!n!i)i-u}>`zCugip+kNAo!)WjPupwO6lPaT4)JlKfh%uF=Vb|4yc}41 zBhJ(=_E^Tfv86fXcFB@1DST*GK7wh~=q^cd0;?+0jGfzTJg0HaeZy{tB+D$PVs?I- zSQ6PNSGa9vO^fSmWiyrieesIH9eum{cWujT?&)Z6sIN*?)WmCoq0*>FD{BabG=C%< zQZdQ)Et~ zucrimceP+}5!uM=H%p`oLsf+*s&=<--`={ria$^_gw*nxcwJq0U7gfI&+fXyT{l!{ z9jZE6E~+eVH>(Khzp^9;ESP8pR=krvnepw~DCz3DM5*7-v2+p^nP8>f!F8tUS+`SC z6-gpWH^Vf|b(pzazG0gzVQmjHyWMZcO4orBYpP3|zDc9&s%A5h?ARTndxm#x@5`jB zf+_k-dbG-h8URxRuTsMRu1&nPv+Fm!^S0VlZBo^2*qH`yL1C>wS(Vz%+dDV$t}VQ) ztu<1~@!)ZXUadRC$tqB*HTo`FR@$&XJXKn3|RY zSowyTqNqohs`^#HQ}qWcYM8Ocr`J@=W}M-0vbrW&9n!UU1Mg^0X-Pb4lR!~nJfh)H zq^k{&XdB?EgB~FduWFLE@YXn&J{R#k6Y=cuhWIm{2oHI$y>@iHxce? zZuX1ea7VR*y%G}vniazbn!Rz*g}q|9{54PHg99~37+O0t##i^n#p=wFIR#8%cmkT} ztq5D$KL`gUt)zjkSt>cZc0mrUnKm{Be^L+s2k_zXObqXw4^gh5Bh)Epw|9ih9=%+x zYUZi-&NiYHn;h>u%bo8#BOd+>%;+yXNaKHbgg7UYe!T!#Y6KHH|Ra}bgwn|zK|SO&iUf_9kZO3U8)8=3(5sa%>CO%Gt#*f{ku z0yqmr!?hh7JK6-C0pYBnc+oh=w34+cDAwVOpiE zAJc6~EC{z1x;>tsiTZA8=td7%RzYXi(tu6iSEt#3$oLKnNUCm80q_Ahv38u;W@h*3 zs(r!hmUNc`%cHBu2%!^2&^Rc9#{<~bH0NRFbo!mUV-NWQ+34DLve``8)MW0^o!Pykdxmb?v2AOpI%ELT)HmtcO+deeB?vX82+Wgp9u1@O^}+KrwfykfBC1bki!v@rhXH> z!D(FiwEU`UK;~`F*o}B3pwKbhm5*YJZ$t$+v4Y~T-Pte1%76=^4K0xs|7CQ(%O=;Cno>=HWoI(qF%Qb>G{E`qK`{>Sgp%HxX5)zTj6A?BCP;mQ}~E3yuG-T)qW z`wKPP?xb8MSF`CEkz4rTlWUpVRsl>g_lkSkFC!noon zbiY*2tIIv*7t24%Kd&n4zU9C{2md_ZKFOJTJ1A;(afe7h5ZUILS;oGQfB!V^$euxl15dm*Va=j1!h?7Q1+Qk0? zeUxOv)F&4sI!t5U6K*AHQWH{Z6ID&zM694DA#cHD_7Hcx@A$VwBje~E9}?3Pk3-V! z&=6s+U_y#?YVBN0i*za)5d*FTvFb9BHb12P;0G#@tw$|fRl#oAd`h`0RcW?&f1rAh zZ-XS_K|a-?apI2;6~E`a>G#Slx~Q!ZiP{tqj@BraXvkLhU+A!0wZ7{EQn&GLjk0a! z_~Z}XHH!;Z@jZFv>dMFEXXP|>V-e^q9?dv6bV{-<2r;QhGOL+Ql~tPzk_qNfm1lIQ z6+uLgf~jJVp%@D&Ad?NnYLug>Oqp3zA8bq(%_M$=T8?Hjr4Bo1wJ8E{zsDYNL~IJq zpl&Bwu@g!;1t$jLPe&)gw5ov_3w8pFB&#$qX>C9%m@Sx7O$C79|7tFlfq(5Q+@}`) zsqk3gCn|S+Ii8YIaj6{7^4~2xKANfPS5EqTyInq??us}ZVW;X*W)(G3-XzycgDh9*+ znUFLVua{DpYPF^CpW@-dPr}Fy4^~{MsONY+6~>8XD?gUME`1wVRD-6}3%NQ9jc6r! zbJFEDLvOacE8mJ?-&PWE$)r_Pwev=4u)=NA&_+HN^*d#-RFX|OAMrWBuY;{PR~hz{ z+ig-A;DAqr;$A&wGZ`folmR>Y{v~}eW_1A7?zGjhjZ0%z5}cd(4Ac;#EiH9*<>e(M zJ|94pwY0UgwXSb&YE0KP)HT$vt4-BZC#w=hd1ZNJyrLvl5-Teupz;NM!GPcEal4!j zyRK-8rrNL`vOfWo6b8-bfIzveBNEKl}{+E#E1k z&wS>G&(U8*y0Totzxw?1h4atxuYTse=b!)Kb3FB#&-8sDhtPwxva<5eN-1D00Dbh1 zqRfC31ODomKznS0qz78r3TSEM$LTn&7LulhnK&`~rDS)qv%^M&1(?gjK{p6DZXuo~ zQX2+u>Xm9!5UN3QT8W&uMwHUPAC>G+Ex#Bn=l(C3?5~jy2jg!RS~?bzUxswgceY(_ z+sT{T2l-Zi=&#D_JXPZP`v=?C{gtfQB&nor=gzjkP8uk5O)p{|A=Y8e!YzOv{5M!{ zoDVt)5`X;KNf@V-Fp~X3vZIX-LQ#GvEz;`v-caRtk9TY+L;>){wsa zbLm&o+rUwknQ|=1Z8A<8XHVeMK~9QLm8t%K0+L~u+OX#mA%@4^p&kE#~3d*cyp554hihyLbSUNsm`r?;fj z(#e*G_Nhv_Uf%=}v~1_juYdf^kE`}AUr1-_>ocTP1zuS>E@$OYOtFNuWm+&!8PXRZ z{BdwXoIQ?Jw-kEgG;FAUOCo-c(@tw5w0V9gNFq@i>GMG0H7N3Gg(6Sde~)8n+@WFEGtmjDN0aC$;7w`DLGE&D)4rs1i48CXgTh>bMNi9 z4MJaM1Opn$tkAW2ICO3`kkN>kL_o*Eo7RGLAl|MFsHSs=?U?R~)|hqm;gT}DF8d$ST-;k8-DC4=gCRw+o0Y*B zZQ8f*%)WhRsoWP2$67)3!z0|*g1S zSnBUq^@|jkzDNDhyXY@&Kn+Nz;Kt|CHCcsEuX*8XOTFi z8!-rzoS-Org1%q)=9&_z8YM=A9)-96rIon8+L(?SaLEQ;BO^A{Z&nof>LO0}3`bDO|Mud?d7}bQK+7laLTTStgL_8s1 z;cuXu`>5jP&p$0~ig?5;a{j@s6t?`CLw`|s@cYbIdcLp^C51l`$~<1dueb_l`I7~g zXafmk8^Wuu*B*YDByaI#I%xE-ACzl-{h&WR)Q9$XA6Xg+-s+ZgCJ{{+2JyOWB z+4bpLG^0aBb`N$~bbupO_V9!Ep1$YA)a2cF-m!0ZD3yw)qWBAuMx@I+4qaG9IzF{) z-sw2dI~_MFUp+pw0aPE%Lh-m1+l%96mBSWfwzu9*mc!JN728AYegbIh*FNPjhrS%p z9NeW!Kha!QUs+T8hB9=trsnl;XNn&}NADEV`1D_%5M7_Z<`#yE`KTj3Oj#Hn(uLt- z!SxOP!?h|Vo%?6$QNV--ylL@mA*jWuNSXlSq2wS^3C5=!92>kn_zV?;G0B?MK;#(N z*X+q)O=r-jYUK?O{Ye~%+E&j3Au23?YXpK)YveMo05#zJ9V4>*BY}wgpLqL|5>e)t zXE*JWMmE1#_=><8ycgJF_UI=*adb9LbQ#2X9()U63Q<5Df{0hL z=aQb3ahz8n1BVlSXdU<0z!6QE20P%G831Kz z$fDOUBSKb?g(g+@%ey;Lov9R{s~kri>LW`{3LxnWim5{J7PWu{+JO!L5wWQRMDi7f ze)UnYYx2XIYdf@@-wOD^;1=G)5e@_j?^Jj4_8R$NSRCv4w?xH4v*vK{?=8QGyiik> z=7~f+dR02ySuGugMUvKo_@*C%XZ!(6z?0zA7yT*(5EAanz?hVf+6lV(8SJ1$8hgQ& zgoKb+f$|8N!=eG9xLA*KDg}d%I2IM^9dto`n~qn+#Tu4{WFToP~e{`NVese%Ge55UPsC8Fn>#o|Gt=o2PXl<`9DQntu z_iof}tjeshS-9XYW5IC*Xq(A5F zP10H$0)K7qQzO#8Cx7pW{mSmA`JHPl3ewY~PrdZisCX3KS!-PoUNf*M4NEJ4-4I4u z&3-Qfh?i^?5s!wIE|uY2BiL|4v!t?4GMi+Bs3A*_(-z6|1n)S6WRq9Mv8#S4Id3xBN!yqiuuyu*;?tzNNTft!|d%R|+jx9KV5r4KKeD{y;3WpyhlgW+e9Mcv$F1`~d^foFrZ8E0B=oflD zyVQY$&JXd2AQXL;ACkUr3Pk`1J6Z+O6LTN?(sKN+1z5&AN2t$!8#Gqic4bgxxm6ytKfk z5kW|MroTaFv8D1GTLQd-!+xv>wa#ob8{%D&Ah@5$3HneyD7yhrjSANP*wI6G-I*QU zwR3Rm=AQ1>mgdGpWxPD-7YYqc_9SqhS}O{=Y`Qb~i6AhlX583fI!;E?R_Zxe?- zlms9RH9{T^ec+fo`l+_+;HeNMbnaP zwXyIWyLaCamX=<9^^t)4@BX}Lw>waHzqfy1C}wxqY;88#p?lq-^A&B$VEgEA9dy|5 z+6S?>ukV~E;BnZUZP+4j$bBFYDXk8)?Y$%G((Znkyq2)+tGa+_CIq&KAYX{V{EXl4 z6Pku3Q~*gX{p!ualOSk(grFXT4Q&DNFH0ApAFjxh0jts3A@LtYfErR{M?<0qOIc@X zYKt~K`DI_h@TGl)AA7w+h+pC-@f`9=kq8RBFq4Q^-^+Z?=Ns}uU;9howSN?JGyz>4 zr1zK~I7^UIK}w;#HEod~Mj)wNIc(yt=!RMt8;P9OV4F#)Ds~yx?b;x=5E+^pj*{gY z-YGl+@mGlTsV*pkgw<7>1%;#sq)|rn!nYLuJ-)jy(bC;V|v{;u4$I_}MxZXy{_ctXH| zq@%*(1FSBq@`Mg8JSp8+z_z=(+AykXt1%5DX(U4sUt1ldfy3zomqVT`0_BBoc!&NG z0#3p&|9@g|n8WJetn}8aUzYn3qBQ2hWAqdgEQm?S2Qj@Z1*P!s_}1e1KO(;?ZxHxz zBRj(0Cj6&5?rO8}Ujq1VtBH&Vw-L>h&JzxF$dUuLazcgj8dP{3s1Sy;EF!y}6G-v) zSZ2V&gFsBO!p;M&Q9tMYh5cBV?a27p{yX;W9NaO`)4j2)xiMW|Sy5j0p)eb{^Z@4L zCT@aqjnLC?MrvCmV6+b)H2K|$$>sGxXwol$&?6(sVVkq2^}jtTL>5 z6Toy~!gOKj@z-9vOt|cxkFDaeprcJu0_DJCWu>=5WWln~0iy+|dKHTi%{Be@lE4am z?7@t;1dcK=;{f_V(Mf+sHi&8%{Rz1dZUCfekT4*P=$bwO9~xot6l$4zD0x)Hu1?>q zx~^*nU@FxQQ#%MFp5Cn;9i5?MDwIq*$ciphAmTyv!6Xup4lNN8v<7M!qURP%4>?e< z^mxDK5BR7<|ElnR`YIuk)#Q#T)4Z`%z|OyZu7XxcWBfayRf#2a zvOg1nsZMZXOnMwZ!p=lPf>tf5tiMKBGMj!Rs5@)5ZgJeC(+cpG$uyC5|_mHEhi?sE5YhjR-!Cm9q|hJb53&unhl z=03-qE(chZ^UPs)Iqc`)-Qlw9=X_8cxpeIubNji=>2|?h4+!Rys^XO)Fdg<_1_62Z z?xD_hAE?B>(V+vo4-5|UW_r5Yw{~uAZLY7Ysj95-mHJ8}L6d3(hyybHJZNu(5}W*| zpvvgn%xR0X)Nv~`>$nVN5|C5N08R2&# z@lVIY9X;uH8X&KRp_z+Fj&S@~VZ6-a;x9OTysR)zPyPZjuI0*Y=;fJhcipv3I)%QD zwTBHO+`fFLbP9d6H}vo=_3iP<@-xW3t<>e=K4Cl<763 z&=9-_#aQ&PA40CJXr5Yi&Jo6_D5*H25&6CN@{5sn_e;*WbU51TeaW%>D1Xg}6#fK4 zUp#s_VmwniBK^4Z<&x2wH)DTo`A_`6`J34vS!R&#xgxrW%#Dad9Eq!hWEUx4M zAVid!uBaAHz`SbmMVsMjB?x)cqU0Z%kn=7aYIqKq7MknjlW$H=JW}}F7BGYV#vLrY zP!18q=C2VF2xM}tsv}iyN++L-4Wh{INS1iL6-E%pM)&z*v7+#D{MA?O$1nfC#Clzj zzCzLo{0v-edZ;vf9+F2g&^G#8S*H+9KHA%N4yC%&-Ud;~72aPKFA4bYwo27;ZdVF; zT#?2Z-E^uW&KTF)$jJ``iKsJ#(*uZPei(KVneVBoNhE6OYU*lJiRwgksJ6bu4&P9J zs;j0m3a=~p2z7NvZ4pfdF@gyzMcSl9srRw_Hj#jm-@K#Kz4RWR7uhwxn#2<0H-f+eeu4Bi16*1=L&PJKzo!DTGD~EloA&$a*RB8+6!uEz zeC;L6=a4oc!U7rbrM~S~e_y+rmwJrwkFLH#=X&M$pn(j+|3SU1NxT)>N>$(;P{5F^ zEXQbjrT^;Y!-YxB;gvf*E*+^5PCoRUpO<=MFT6k2e<=okjcZtz9EyZTFS&lee-5?D z#}sebKj_#@>eHwybeQ-`)Us%kg@epVU4B(7bpV+=`BOI8^41kz#j7v3uEHYF z?gON`y!sP*@(1C!KrnR8$0rDnfzM^!E^vX#s*cvmg-pP&<<3|bV%T--=qm$1kTgu9fw9&o%`S$jb>eLJ4-A!dx zRTqUL1!V0kXy$r$JmakAvaP0q=%Yn7tHI=vKl*u4N~o=Y1!Y^#G)>bYVdaIFbk&X3 z;7g*|$OV735*WpG9noYI-n-CtL(xL8EEEM104j94GA4xCMg%O7ZKRT1G+N`5ob6wD zVgLB&dlcJ{>Q~mC>FYi=QZF?P&CX5M4f})9_o4Al`v-fT9X;@w#a@00&;HTd;PEtU z<7!8D)6nt7<3mk#HN(Efi0A#1U|?|Lmj1=hVDRD`kiB9r&TMz43y#u6&(7mK+hC2F z0koI|4{^~7z?o4QD+vX$l`2c}q;`$J5)>U!Eo>9;ZLmCR>6%M4EDehTxz<1t@>Y8y z!gBF)Ji69Gae4X^(#K~AzG3IybQ$On=kfm!AC|z4M=*3V-iYGtcsW^I6|m_o+=|ULM@E-(UC#YR8|T$|o)smPO-> z1@A)e-HRtKa`{u=4=n^P3ckUFPnnTLVt{=t<8P=>R>6Ok54pjGb6whHa(K<4*s`J% zho>sCdJa4rE)er$8cw9+FmpI?HwW;@R-InqSbaka2kPn$U~8-Cb@j6uUuN@$j%cdQ zAKV0;nGG*RY_i`GuEVHNpssz4qS-{r3r z_VQm0x@^zc%5@7A1_zBW{}wp3@2;`+@yS)ZFWI7<-cS1?+IPRpf1#IYpN6jX3R%3b zEO&~S$1jm+b%|_?j^+2MNcu^{DDgb!r3-+jy-N5v$bcu@%ODg9ZzL{@`)|WkW!2+^ z?q!e*&Geew>=!%Q{XV*v(FKiDjYYM{Le+(dJtKX6xl_)z*IfO&X^QHsY0vQ2zPfx+ zT!NEcp@_yIuinAXA+=Sptht?WI-DRaGq`vl6_F0PyI6LLOgWq}VPUgLu)3Hvg*S{@ zoXz+hcB8Va6jq0@BWyXrfIV#@FWuUk8)8;HS3Z7AgG|x$R-p~(0fXD8xEPOQmPWY^9| zYSj|O1@|`CZ72+FWxuZ`J?pQ@1}$jY>$x`^h)9Y#f9eH!8xdd$_uu@7&_p z00!lCD`(hzR~4(KX@@oa#mN6?W5!>vgop#?0UXo62t@n7VixFv3SS9?C59{ z7p88&HaB7)Ics@|fRn25MhedBUZuY?nJhVQjo}h$I&j!;@@Mn1mM`kq|J9-0cxeIx zBk6=OOt65E_~46n!=PvoSAQxzPh`J0a@|+a626TVkJ7?sGLA-w+~BFiJscA3t5E}J zLJ0PNHM%!f#1@it4O>**SPk+d1b1Rlij}~k)Iw;lZWAmDkU2qvfDMlXl`5Ds2bqe1`h=zKRg4KN(ty=T@bes#zusXd=ReBg!oK_zqc;+>-xHxK&L z(w}1A8-2sW7H87k0dZhh@u)jTIQWv!gM9(O1cEeo1pF2S|8KyIr5Ok}w9e!$_G|4f zru7thENG~F3i;%dcN?7I$uFOO$@G(l1hU439-lGsF!6#eRu0T{Jmap5gE6LCEabyb zM9a_!3i}Ir#>0?g**EF<3Z@@lfV>axVw!Y^rlm#}r<m}2?_0mhQZjt#*ynDSbz2u#bz~1G3 z`DM#4wzi_Ti7E)Wa!LL(YfsYbu8foTbHFafW9VyHe$@h2q;nX14t)aRVL~ z+@ETn&Aeybga4j&**#^xi<|G=bwwIO=bh{+H{3}kUhw93k_D?G?j(<6p+Cf(WUCtP zigt7)+ak&82GD$6|a>?97)3D4vBoNX8BF;;~;OQC`E=$v;-kS{AQhD5LjOHDJC`+^3O*C9a z$40W@s0f>-@T?;%xbUnqh*f~Q3}Ila5->R3v!Q88vhc1Wk77aT=;sBl*F~F3NLu|O z1|V=3%4j(Y@#H>8vO?nwiQ;n+W5*4b5zfH-)L2z7FOx9BpTFt-1j4 zGOsLtpyP)xx_?Gg5ApwiC%|!d)a}J9@fhYG+KAtBVoEd0f2lN^RMIM?Xoz}}p}vM+ ziHI3`l(Q?##USBVOyn2LGW;SGw2#1`Q)ZAht*jK&^2L>_a8+aS*Fn;nS5~Nv^eeo7 zXXSs2d@7@FiLkOFJ%aM@n{`D!@l7+YSWo1e^?zB+6EVgs#*9AXUg`rgdDrUu?^X)p zdo(AEuQ)FHo|uOi2lDYfkw@>VVWnW^VgB?D`ZmqESdKY~zcKFMe<^iKufvw#E{`iN zn`%3v2Gkz)kou(hrur-G1)b^Nws+bW?HBDocXT@gt`gTv?$3KvPulaeH{hN0zVEB@ zo$){5zvzD_&>i?>;Gcr;hR%k560QsXedLpoH==Kq)R#O`@Vp{_-w`Z;``%IRqB=dE8j96OQ?yl#Ghhh*l*B0^sVUEeyRwWYPqIC8%+hpd^CxmhE3@8Yq!h0{jH zI68N7acXvUu4!WKo??1*YWm*U+(PlS81J82I6X6W(pcZrQq0;hb#iJUw>ULPy`Mfa z-MYAV)Hu2@caO2%>erZGm^(f-vDkEMadE!8xw+Vqz6ZiRhadd8A3yFhgQYsg7MTG> zejgOE25ZF+UeFJS8F0S1AI~|f)(n0+D92`zLqCPKh*nf`8t)l|qj)=s+$q$UMY@Si z;Casn@<&l)8trG%%fbgrZ|r41YSTAnMDGR^N=+EujkR{5)=5z_Cq^)d@t9*jjh`l( z#%vbx@2D8%f*6&7pRKxnyav{T%8sL-3Dj;9tFnmPZa4=wf8d+N`2ngV1p32u-<$po zK?fj1eE{VqT{OV&_&B(eySN*7+q~QdEsZU~a*+xeVXN zdwC!4=L38@-@ym@ZG0!+#fJdT&WU4F6DJy{?wMb_-+gp;?!LzP+(K@4c52qPxR5)2 z%r5d~XHHJJ=4bCc-8eC`Ffltd>Aq*?7R| zM;2zLj!xuGPwBH$M;EE4T^tljsrSxPa;KRTHC)H0X6K6^mlt!>%Jjm_ zr1R+9?Bvu!(cOw7zW%rR4K=fv#X>8Zo> zxsy|~`su}~`I(c8a~ftsh0@#!dkzCQxrmeN!*p8}Vb4Gxy9qFy+JtR@-9Y_T0k4+d$5>vf$^9Yd zD4Uo_9*HFqd6vzyzGVL;P@BH--o`vn=Z*2Bjd>}ZOe7PHc{y!NUY0{)*4vj4_8H^j zy-QN4uXm|N?#oMk`_3A9R}zW7++Ac*K5BH7H_wtdxKC42^m^AWlj^vfp!Ao`A-8V2XkXHxB5_!2M zJ9_6BD#tF28TpYBWM#53Bfo)C8?sqr$*heL)gjAzGx9A|-a<9s92qmP8W(a#-Z3&Z zjvRx^9F*#$ROfhXJe$qNuv&Rn-$b5`j^)`ds+_<(%>8jn#dqai_pu48@w$y2$z~^W z**tH^W~~`yjY-TW*_&<5+tS8>kymPRn3L8wGM3kpy?H&^iyc6d@y5I=mK!T!OfG3h zdJQV1>Bh|A(-ZXuCi1rW1Pc3%3&sU}YpKOngB7}cYyyC>jBAS_QD%5gg#7t+!(l!%+aQb#bzyM?SGA2G(E#1JC>W#*GW(M&6HQYs?4IyY`JODUb!d@dA2bhOz*mVY}Z~hGnPPpP~?ZwODxcL$JkOJfGy1R=KT$H73e+I$?d_!%2%(JUmO^?% z{-X`CDu8zca||~$=A-E)PH_p=o8r>+l1y<~dP$);mR_<^T%KN1DXvH_X%xrPOFG4s z=_NbG4QZ@~x&C=|94nnPn)3W^IxUU)^qRuRYT+rfuyIXcYPE2|EHu(A?`^o{JTa*+ zm{X;BuAN^3^D{86D$I}KB<4qPHReZg4dzF23iG457W1RH4)ddU9p*=IJ?2MoQ`+be z2dO!2jORxe;}w^ z|CZ#2rFI^sxprbbFoB!48OLGCZD`DQrJJHXjrk3~sVV?_0@XKSi&&(_Xfk#XO2E?I zcHzQ~>j2Wm_c4Ox_VK)m-M;>~;$-m# zlPW2FF$wx2{LdhzS z2sXn8fCB}&VI=4=N7RZ2A>(Ob(re!Wu=Ety!oUb@DQhi~Jy@pAt3`PSkcnYzPwt?P z(k^Z(mWj!jE1hTi#+r;C5Of;7WM-n%)vd^@HF&!XMXS7vxrrZyyz!*9TfqE{`K`sT ziPg8ZYn&LI8>d{{;tcRd6RqO*e6(+DBnFyl^kkcsT6hTOcH4EOqp^|eN_(#>Ew)|T z-;FK$()sR&wH1nuiXZGx=QlN60QeD%UBF4d)!4A1P5BlKaX?I&z&K^Dd=3m+uQ_!B z=Oj*A6HcBvq3!7<2WSmJzkvLI8A$KA8G!wtKryX1;jy0NhFD?^yd<*LIClU6cQ+JQ zWe{(h8WOZ;v@X_cR+r#5EJ4^j_TWx%!h=ouPMq?cx5(dx?szDe??RoSbbceEVOqrj zEVr>8M7X$GyVC^F`C%;cp7bTgwj(iu1gFI9=}TPXj3Oa&_EMc4DB4GLC~*hXp~QZw zLx}@vxYw{gq{ff}ZAU7bzRbf9^pPyy9B zgT|Xzd%aJ*i56$gB(=ETOj7j+(9dSG%LmOQRd~ouQiX?6cgt#j=fs=n@3+h(RX=Yg zsrqlDuP_Gi#O5V6K0aC|BjiY>QAEOR&ixq9Smk)Ss+2!L;mf}P|~gVvcM-~1BOdM}l7 zR!@n`Zm4d|R74diz4r~+u{m=h*WUXE9MLHKhfoNz{-tXEkS>vl+2S8`$SC?(BEaB%02b3^OeW*%Ev&N`!CxjaRs8E{cqQ22qgdj literal 0 HcmV?d00001 diff --git a/data/liberation-mono.ttf b/data/liberation-mono.ttf new file mode 100644 index 0000000000000000000000000000000000000000..61af64ea608fe1eeda010ab3d863a40ba838a6ac GIT binary patch literal 108168 zcmdRWdt4J&+VDANW^#ulKnV9FgoI0g0O5YiAS46<2?)qV1Qk$Fxd?cnR;hRKhSpVU zty=4LwY4=`+iL4px9xUqw-?{tZr^TKSKW5IeYdrByKT4IO8A~L0qb_Z{k{Ku|9lBE znK?6a=A7q#J0Oe@Qo)Wz$my)DtUjzckMQG*p*5nk#Ni}YPz;=xz}RwyxL@BhcS%RYiii&o-ja`y zq`R+oU~v1o1px@}I*w4#Xy4L~zTfZv#~y?&bmL}7u|pZeW5x4u=G|25J{paG#b z4jVR3{Z70+{t$azbOO#Lh|pH}z;mJ#;}1a}Z%w>C@i}{4=*f4@w`XY!c@#$@7aBnv zJgGuf)PxX|#Ap!%=M4K69)l~0JHXkX%ShiZGZ%G|00~FLtdtOruYJBnTwe&0YI zIKG7*fPLrWR)s3i4kUwnW8hnc51;|;k2Xwvk9R}A&!Dwv6nY*-JJEUAhR|ndBbqO? zKLf2_qMxCc;EDrj&>R@)gXlvN2yKfA15ahcsM6v5Fs?#6^fp=pBhx|8r7(+ZoCa?g zLu+6z%W)+76Iz7Aks8Sn;OL$Yo}2-l#T%2~aAEA7FbDd51m3e_@*4wJcEGrQ_y)lY zHcWnZ!VKv5eqsD;;R^i@q8^xm?>h~CDZEGSZvAk_z1vZkNjS{>DD?T`tsnZncRLEb z5tIR=-uZ9aJoG+b<9E=>rel7e~ z0o3o^DgZAPr~|gk0Fm?m*A18oa6XOV9WXb!0fqlnm_0^80NEa)SLh9g!?zkI0aXs- z^JoG^;y>Ul;DXx|@4)?-?kCO1GYVIOz%uXxu^l|rN?Vw z%YdGb!rN~E4yvG6O6>@h!gd_mgP;#OGCDR+xUX0^J3isP%MX-WD&S5!vJupZ8c{tw z(*^g&&qKh4Gf*VV@gVvX@Iz(D0BoaZfJC8RPkck7NEF@sHeoz4CfrS;a5wJuo&Trf zsk?vpg&7JT(m8ps91*+_G=c;vVGK&(ngPJ*(=cKa%qtweVK^Th1BimGMeA`GP)IGR z1q$R~`vdwNHlgo;ZhwhcbO)=2UK!ZaEdu5aANEZ+qel^lWhrHx1AK~r!dK%pcsHIP z;pA83b#jea&5SbJm`9nn*;aN})P|_P>(zRVK1v_0H|taMHhr!>Utg#%(XY`T)Bj9= z(!d!44Z((JgV~U5m}B^f;dnHO7DX$g1EMw2VbQwi_-ISCD|&8phmjanMgvTVm=q?J zDaaIJiZI2P5>4r*eA8mnh-tlPvuT^@LDQqAlcqDK7fcsSubO^sddKv8)5qp~GjE<| zZZpp}cbXS{Pk^ov=!_#U^6y9pc@0MXK8$=ljC=?47>n4ksFA2I^(uX!UaQv&BTv)k z+#UI2|2Fbw!`R)Ct6}7!(NU8lZ;NghMy~%4BX{2&`Iza5>501|e*;GTK8!r~?#MgL z-QVMhiHQ$EQan9TI$`y0@UHhRyK`jx%J@6uZ;!tJ^Y1rr z-~7wXk8j?*dE@5wn;+afa`XP1_uX86Q+G4qrs^hllic|J#yd9--Pm@+b|d9R+>O{9 z(i?^wQ8zRIwrh#kOxL2WX|J(Y|918B ztDj!|o!t)FpcAZxg~0LMpluhUC1Bz7pkCmmevq-0--pmLv>dHKE735z52V)p zXfmo$R3czdqHOJ2OWL@Jq)ts z5wHLbqa)~1kfDzO|Nay`4zlk!I)R=*PlBX>3V8e!$Vw{Fot=oetYyneE$3i>bf8}wWBF6h(u(0_ww z{XNLkKcK7V8u}x;4if(+$kq?hN9fP!WAqpF3Hl$96`u-v_jB|Gx{dw@n)L4=eZNNE zpnrgs^-qu{-=jNd9C^_MMi^rPb{7lMMuf#!f~8o7E}6;|T_9EgKJ4hLf` z4#A-~476ngj>J(|hxOQiqp=akU=uduSR9AraRRpBM4W_^u@$G_RIr9@I2~u;Oq>O_ zQ4Y?z;6iLiB0}vmN`O>;-TT2HDSe-*-+Qm#d+d9X0d2s6)DwfGm4a55gZ%eH z{vdHxV0#6iK+t{~&>33r0YXt2$lVCg3Q=J5=)nPqMn=$#CS*pjC=SJ=1Y`j#GYKVw zoty%?JPp}EdS`&mngwz-2lR6u%0~sL5ZMuria;|KgN5q=U04b>b{U$E%0b^&g663L zja7|m&`gl(b)ai!fo5+6+q)U`V+&~0R@4TP9|;t=38-%u(Ahztsv|&G$AGea3RHCh z=!#O+Q$Sags!jt%odKG94yft{peUdxutoa>PFP4ZKMI6fzj1nD2XPe$*Zu78aqsx^<&y91TVeUN* zZ5}-|Isf$@kDfj^7cTwFojlyx`J+2|-<|y3JF!ZikMffe^$w%n^Hzybe-1ZQH^A}s z5@Vy@b4xg`6pmT5aN-9i1_L~ycZ4h~(R*;4-r;dBTR7@yD@jVkr{%I@V{wNpDG{BP z$>C5AN1ixi-)S6Ih=l_Z=g2)xki?I^*29<_bK5=c>IO$ixWUkvlvw8RH$qQv2^9-n zdPKz@vCyTy%L7A4TlJ?CFO6l!Y7Eipf#1lXK zQ3$}X!;@$%ad<4W*YcXX?T5(VIssFo zqfVpVIodWl_uRzDJfmJ^96ha2jP^MI!pPm=!O;G~)^Lw=TcbzSwh-q|PS#md?g^}J zZtxJ3Q@?O7OdtO2MniVEK@AfS0OEw_|L>O(00O`PFf|zH#J8T~(L6Zuj8r%H&h=w%3Zu&7 z|4q2TI2xeV=U8EkaIYQ)UDn>E_i$#9h(2}i13-oJkx|$I68yjM{oD$N7ns!n`Wz#4 zL;G&sfABc zB7w{L$rr=p5(-ooy+$uFCOur10DTtIHXkfQD9!5|j2*^C<3hcMcQ;TFQSb;*o&<&f zb01d9Ya8x8y9ZbRCS-ui0^}xv>2X@_!jJ;jQ!1QK!5V1hUoV$UUDl6EjO8;&DJG1Q z9U>TcnFmo4=Cjo>ZQymv&qn85BiQCnA3u+t=6TA?3n|-<8q3;8jWZkag}Xt5+#fzn z-yML;ae3{uq(l&A(@q=l=IYZt-aNCZ;k*hV{pQ++GX#_3wrP#0W8hlDc|GU~p_R~9 z+DLEF(-YcL4V*}X`@_%k5bqGKvOLYwaoUF+rE%WEz(t*`XHvgQ@$;>-9KZnLiMC9Hob<)uq6F?}zMyhM~2 zbQg&Ag8f48g;N)rJQr0>pM4cjypGTiH|rJ81Ga)kM+;HpC5VN^E^B9 ztmj#xe8&FF7tb)~upe)E!lfJWjCqL1bIEhX!&pz*Pmv=}d7dJdp1SfBv7WS_B!{2G zm!7!t1SwKtB}#*UU>!oRSHY%-tq(R9f#J(*u=`-!!M=mcLwn7-{Z6wkWgowfz&M`S z8yw-J<4M@-uXg?x*USms^)Z|>hIM1sG15D>W{jYns-60s4DDCHGbF;P-;uI|RBdnF-n*Si z*@l(dbla@k7=D{7(5bqJo#vH&}~|u zuiH3%LU(urR;|~sPg&2Ttix;8Vt%bu;T!-o^a5@5z!ru>>OyTHbz&P+Cjx}F!L?S{ z&QILH;xjrk^bZHTE-=D5r^%(8?M&4*!*3J(2BrnnahR!N)0nz*Sn_OmzD~*D^WZ9k zoXODf=io;h=RAjHya_t2afj=^sGg`Me04^)ldm?#Ip1;P>lL`d8L2CGx^(VyIGk_7 z(*fjVFfbQvrLdiH;_J>YoMgm_gVQv1YOJhNr77#c-_~Dyx*e z%ALyV$_b^|4sBm3nO+2uT6`oJ{G4-m>~!r+i>3UWcmk{lsk_;OH+xJo>7K7{@`yHj zP+e1V!)c6nG;Y|w9ZicY_oU5i@U%rXmV4UafTsr|aG;7j9gL+CBic(5Df+0J_Ptg@L_YoXIc&s4ajNSyZ6re;hz5&N4`7<_%lBTFXssOz-Pf5_kA{l zm;O`mlJEUo1RwcH@X#-SH?jTR3qLwO5B;nX+V+5#^&da@IK&B7fUk8Ke4Xv!OU=Qf zm;tYB5WJXk@NPGIntjDvfj-4&&?^w*yboK*UKqpP|Ip=b@YWWAxAQ#gAEx(^FVSvN zh_6HFhuKqQbc+6CWA__l+n ze*k>O)yK4k@XiB5nK=2ag-Bxx zNnu2+gpFZmv%5J3H=SF??dDE$ABbj)j*FwkpGeXq7o_ddL$YqUzdT*OLVj666g7&= z{u2Lg|Id{p$`4dgss`0nwO-w+_5_3kHQ0K{dLbntWpT=2%H>o^YJ2LL)b~@rNefBao%Tf9%V{5^eQ8tJVr+YC$8DEv z@7r#t%hIFMbJJ_m7pH%cfigleQZif_Z5hKEA7$>&d?NGZ%nvfZ%2H%?XGdq}X1lYy zvo~iS%f66vFvpW~Ip>c#U*#%t<8ljgXXlROrRBNu+VYm=ZOc2F_d>oX|JD4f`Ck^u z3StU!3tlRCui*1SQDIbJdZDXucHv;*XyMVqbA?w5|5W&$U1g86U$S537xE+gUjAwR zRsJgfc@ZfJE=n$P7R@OdEZSCdwCIJRH;evQ^wl)Qw6SU56fZ0uDc)b~DZX5MqxhQ= zSxHn$W=Uts8;)#;+tKM5cI#dU>G9G_rSF!0;zF)q zSBmS+GQO;#tfy>a*}<~s%C1bGUQWux%2Ucq${Wi2$~TuEDSxi~?edSxzpYSI#8l)~ zI4f!@x+_L1-mP?2&Z%5hxuf#&%9kqNtNd<8(2V36t{F`;dS+~#acIVKGv1!@NfoLJ zu1c=rs~W0$s?NAo)ubk^W_nFq&5D{GH3w=QuQ^lmQq9LRRWsvew#{5I^V{0Y+8wp; z*50YBsq3!WR(Gtus}LvTY>gSp{y! zHy&wxxAAIIVpDoke$%^6SDQ;_li3loGiO)Ko;Q2N>>aa@w@h#OY|gUQpw{DUnQc4f zCd^$icVu47ygl>2oqulrrS|Oh3mp|5zv)crT)QA>!P$ig3*TM%d6%Rssw=%~dRI-? z;;tKA-*)fqKGgkq_oeR3i>56)w&=UX0gIy+XD(i~c>Utf7Js$)&XTqz3wxq^{@UBn z+t+)wudvVAH>0n->XE%8haL!fVATVkuVvS&)|%JOUb}bg zm9?L&L+e7;C9iX>Yg@Ns-PpR5>n^Xmy6*ORc74Kn_xj=W$Jf8RA!I}QhBF&J+L*qv zZ{y>eE^qp1v;XG&&E1=y*nD>Ldt2hR^o^Rg>bJhUZSVH%?H}z}x-(_xv7MK9el`{` zmOs`#c5v*?u{*o?T|0LDb@#~bKRp=oVBdqI51xGRvpxIwoZ0iuPp0pc?Csloa-U+~ z;(dqqy}F<5=l3`4@7cd&{}cN!@Bio_$wLVb&3I_(Lq{HZ?V-OO2s%)BVCjJa2VOq# z)x%K_yB=Qk@Ue&AeAs(18H~I`2j4t+=aJk;x*ys9$a{xGhtdxX9(wN3w}&eZ&pW*0 z@Q%aB4!`hd&#|$e9sHT+XYc>)_VI}0DaT8WHy!UgzW(?dC*n@bIkD%&=T8(q8S&(~ zlkF$pd#e7aSD!9^s&GWS9qtmj}38%YHpFG2!*?s1(&$ypie>Msc zninVSTph&P#3=bRM%Mf@Vm9Jd+G!DYHUA7l;1Hc=XfsEf&xl2lck;myhhv-Cpf(xQ zh7zLp#^C+lg;2YZ&o;#`DSU|(V!qrXEZkzZ-csjS z)d4ui+G4wvmYRZ%jE%{#X~^k4A+NsnGTzQS|J{YxU#HeSQ^`CB)&d=8EFZ+|B}6LT zYZYN6!XggT3WRCxHk&mKTU%Og1>{(7`Faz2+_od`hF7ya{svP?){H+u)=*_c5Y$?* zTfy!KhbZjr^N5|e%|GO)c8MZ`Bh8VF2s|S*W&)J{a#j{7iHy*&K~ff@P&R}M)aW$X-L!kCa05ifF!7*&WqgxmXbTEqpnipDs`*+3pJzWb;bQMAxBy_xplK5W>}u{+h*_7QDjdrHs-&Q{fOO2jJ*BuK zA9q{vP{M`;vMhdMJXsdKF`9Jvr}1r%*`7 z#8@omBq0K^wWtBe{eTC%&1$hwkOMgbAwvsbq#sbyV!0*UbE^eN(q^;0l}2%9z15PM zf?9s~K=L`rpNKWajAR^}6~$=P=2-X|levuaLXrg>0d3-BCRQEA;h-p@Rr@nIJ(?!NB;Zo(ND;eD*GxWK$#3lo!3y2t>c$I(lXMytCJ6US{7?>$je>2prI({ zjwjC1l36-0Kb#y(ad+nyEvmHORpleCIozXMM5G?hOU)Tu!VMc{tn7Boyvz*0s%lpi<}cOl!!{ z1ZT{e#?Q*sYBOhf-~V54p}cCD_>6s&tAxB#6?iOP@gV~<*3BR*tG85>j)tLz4Gm1! zOq^rF`g0SXP-I02zXI}Z^96t^QvenP1P2gTS*WqBFr^Tu%|hI&<^YgN`gv8feQhxEw}{<8wco&^=GEAnw88@*c1dhtl$q*8jK2XD`JSL>BX~b%FKAvu zSYTs8y-up?N!3bDPHI&8T)lS|b00jXL2-PrN_1PT(|eC>%JA>M4o| zpR%Wd%;iC8&Z7<{8XUN{gf&q zgA_MX3@J7!2qR@BYveoSL@p6Y6>`px>l2TN$Ha^nI(!aTN-XxHhK<$IVguR*8ny}I z2y_h`35L^KIj@2?4^dTqlw-9(8{Ma-w9aXvByG}iTCp5-iYbd@Y~(POBzZqRzkKh( z&w1#VKRYS-OG-jP{?jA;5ZT8Z zu!8_A_+b{Qz5)5&a%&urZD|394m4oQoWN4=>(JZYaj0*FjPDg@HR*##B6%gl z09C6fUB6(3Dg*@2!t($<7-xn-gJ+NweC5ayN^7@){Qn?~CyZABPXKrj%V7wvfc+}q z0A5O`g>Qd~E#BYJ8nom*o6+y87_5qmuUcAGy0psTZTOTt_KNo( z$4W~d!?IW2#EQc_f7tugn}^?Bou0A!w}%h>W+Xd%VW=9hLuS7fD*6uNQ&3Za{Z$03NFNy?K(~QGk^!ld@fWEehzZJ{+HPQv z`Ow%;jplwEn9ZOdQd4X|tDp-qK%Hk%ntcR6AJ}&Pj%m|(u4)T=9M9dwjK`Ix>-Iz! z)TVu3u}c`&7>p|)aAQWB_}N3E4I+}G$AjSzB3c%f$iHUiKQXHk#fB?UN5HXIK8ah~*fSwi@ zH8m;))1@EAK7}B`z_eu)f)(jgQsUS`W>T54VuNNZaqO|5Zm5kdotu~0;!G5ulk&Ys zySsiiR9L_1*ufD!`R&l$W4qQruwi=steo(u{Kh-_La$rcG&Dc&OXnf>>Xt%PKTrS{nMt$L!@qnXD&17UfR5?J+o-hmNIqr>}fHpSC%wo1Ro5|YP5GRAMW*U8EsC=ZhN3CYe7A)WTpAD zx+z}}s6s<*2k?aqs*mdUj4shi(H0T2MvA3U3GVe1jgccDM2S+-t74&~lO2$7N`+2g zRrD%Yg#yb(B1}zU@H9b7gZiA}etIl0MT<|0W6(buDK;=C&W2I^=M2n z23@aSFM|{q(p=J9(J&fKvb^WE3{xZ%ABs%_dVSbHZyb(`Q^gDzM1bWf%&L5%OTZ_^ ztIy=m;CAu?rbe%JA3JigHWFaP!Q@lWx~7(Bhw|*6%%7JC~iX>S*F;iAS=jbLRLsNOUUxbO_5|}^p>2~67 z9)myAF`dRgIx=yLN|)ZF(e)%~;41?SU5HWPB?zR0V>Hv%L$OEhA^aGXs(2tLr&3TS z)`2kbN^T2BDt%~du?vBQTRCdmJ(TZL+|=Iz>Gm(!q(0I;PHa}jkNh2wUCfUZ`i~u5 z)|oT(?ER~rU7lmD>d4G%u^V#w9$zwWqBqlEZz(8PSZVoVcwu{)bG|(yIJeVX-M|o>I;Ke@4TR-KO4@*WR zWLP{ZCJXe-^_%p}!mt%#o5Oreu~Fmlu8I+2 zL-!(L%95fQ1?(uWH-7LzZE62zRIzsF`kybaUfbykJ{hsRdHRaFRIDj$S(M%O@ZvoC zic`Ix{q0p#*&=7rLRYNOxzLfeU}grnc-s5r^DPEvUsZT>UCH`aAFxihg_jJU=va7S z#We3(PuaTpc}X(|oYMwor9~HafSoVcy^w`vAm$pw2Z*>y+gB=KALf)k``12Y0ox#a zOKo7rX9s^OSi+3bXAcwH=KTp1FxgiFUnpfmAr>rH^`cPfvVm1k_F_IP%7uBg#)UD< zJtW#EK0t%UBkUM^gymTFAos8Y@`Fk++wPkCz`hpCl+jP$O%4CspL#b4w!d!x-)|H= z04gU2(E;#lo`6c-<Sle0b+^ritXeg^wQa?)L7YtFs8K-)dlIF`o%Aui&%9L<+0tR4^{?DIL3pJxSJ3)c9P%fEdA>f$*c%(of0Grg|H26G)vJ*ywvBnGczU zJ$t-p517&a3KJ2oftLv|L82fCt|N{Gm=KQmV8U`iEXS}v07b+>Oil?fgK}!0KSluq zu92k$>;>Chkh}_`Q2i&EWMxR9LL0``1TgvVz(cqf_Z;xfp{WFb2~-NOsld`HbE%S;b%3MXQd)=9ovS*@^vl4dK1

`Y)tRYGe55uWbO8qONcV!Envxw1l6K`JWh(QmWjt-qDE#mTyV6PCq;##CitYnUCh zqAV;-mcUVFSSo;%nrn;rKJ_V@Fe|U-@#qAmJfyg8OFQfl%?*E)|O>s{25J9u+L@}tUi1< zb_)SM8UdtkZ5YlJ+**#>_5SQsU@r^8?mvy6vD6in9vh6YNST~hmSC^X&}tKls^?`V z6j~yroPKb=L@5_V2E`RwLo+(|w5@n?&9uDUqn&x3jn(E-%iP}8WozEtQCa)w|Lk4& z%81=N&zWc9)8oSZ<>86?*wWl&KL&#N@)L<%A!A}oGj&Cawob3uyLqTC zCERL{+2`dFs>=#A=`rqIudjUI#^Y@p|Kh!TdjEIN%nMD(HOw-VWa#>@VDoeTh38{- z_p;00Z+!$&MQGJ5 ztI~%0?ZfZj)!wz7|d)rw$kL^O_$PKk(bqS3@7B9Dj_1;n*R zM8t=;ikbLU5lqSFVF+%c&r+sx15!N@biS+B1qy`p=nt`DoNl&YH6=M}M8Tl}4%v~~ z9TygQRX3d84)2ATX(1?*}_*nP8tDko%P*R3<0K>{;7Mg4!s5wQ$Yup+JX;d1b zafa205mRdzxL~YGrkAD2+GKq)E(Ic;S7bN9*^rf~8dZdARRsd9Xn3L@JZ{x32*`t4 zqE6;MPWn)TA}{30`gOHdB+ghK*+Fa6yinN5iJSQ#%SBM%o?cXBjHMma*>irm*aF9 z&SNkTir*0$(G3j}D20dufj)w!=mVze(M0525Wsf0_g~xQ-GQ?X z{r&N}OW8|L4y`=;?%Tw3+&l4fBj>0*`rXM*msaL{|91?_m9Q}8c`#-JcZY%lB%a~HYm9DJl~D`upvlr?>H+`m)^oeD0W zFCYRAG7WgaK!xonvu`|(92{?FFy}bvZ93q!9fWbb4187q&h=N9l=?fuBticbEW8lVG;50VAFu6E>MF znUTvPH%2}e$woG($atB1DpnNR8W*QmLKK$w2c;C!ssyi?)wgn#as{Hbz{n_ke1r=~ z1fLklmd1^Is5RZy7C(@y&m~p`2=q*Y-fU$|>)@6d8(&+?7p}d$rF~y-dB~IIt-VdF ztBfa3rpzo(_4ED#U*8atnH1Ia0>%&h4Cu8fy>X=@yJw|i)34Tgzw-W7tqql8_mL?Y z07(EeFpJNZH%WBJ3fWa^fN^xU6BhS@)#@i^n);w-0gUJ)tcL~jwbd=gN5md65sRfi z$Y<*7`{wBL`)xu%n__|%d4N&BX#AUt7m4g5=^fw2ImX{0ncuxA;NuOT0U!z(MI^s%2q+9WDOj?BfTyasc1Ax;m1l^#Q}`G6(lwd!`@2s z1z}+%kkC+LTZk2M8Z?+mgE5paGGPA(ljVIC=ihl9=X+lTqWJ#r2M@B4BB3zxOnk^8{u&=^e{7)e%q1P)k{`Kq zl#v3#`grx%0(|!I>4UQMGUAlg%Q|IDyLeE%Ud(Jqco7s>k}_D8M{;C1NQSW&N?0P6;br2DfKe>D2ctPcs)$MO zl}0%nJajcgO>7nl97rG;)ajX7nOPz+aWEvhq{Xle%no4ss5!R$FOKOto4}GeYrSC;96rz>4yDAX>r41k6SuQZ@V&74?|< ziu#6{wX5+ZI3m63HR_$Rvo_$n6UXM*WSl_-Ldp2IEX#0D{E?`@G3QRQ z-IgSCW9*$hfaM)=$+7cnOq(zTpp8zjLpnibt6|0KO1_@TVUiw+mxXQ&CF!AfrFM&! zZRtpPYdKtKEj=t7#^GOPlHr)gEP;gjOpC&B=mE#Udy zt9M~~le+hwY!zZu5XC2IDy0M1PUrfIE7n{Z;Y-$DT=fqudHvA-g9i^i^w=J9;wkTU zryJ)ygSnqQg~`c!?@zr?!0KeN_n+P`;rkf`%zbu5E8xi=(v{78VW$?>wSwVPrfgJp zDH+rxm=H=~{IK#v86G5V`T;kh)*v468WbcBY?U(NyXuk7$7f#xnfgr2Nvjf6B-oYW zy9OoOnz!<~`@Da-h~K>bg;j-@jvf2PTeGst%$%-$c!g`+%Q{KezLTjf$?%sncI=>%^D}*EqjY$fc^+yP^&D-7-zp*2N*P5GC>mHcv4DUPMpZ)LX zd+^hfOM+J~m2exSezw-pS@H#E{(0~}VRFhQdr|FVwTA_f@E$ApfV>D(o<^!b_PJo4yZLU*e9%gI#@+ob-`Ov&dlV`dGpm1`X>COsyPm5#wPo-b(OFf)kqJ0xy^seMo_keXj^eg0 zv*O}wR=N!~cV>hkXGT(fd8$6ZUzd5r(6c)L zpVU4NMRWL)4$Y8egNEr)4k2fpQ+giT$m_3p#jj&t6{+y|Q}`>Q zRJibU&T(frX>LM_H7O;2o|V}s%ma2p3?&U$@M?oZfhtLeitgkJQ~_e-le6?7jM^|N z708p+5H+ey6|M$Bqj1$orA>rfi7KK)guP0JDyd}%RHUa5LE*@avwr@Q2T~cT0Ks#c z2YCcXar8n!9Boz8jsod((b6>dFKST51K=`RjOSoEokEI(q##LfO>|f^ZE#7|K~kw2 zpqpw*os))w($YYJ)dYnF%?S($qJI`?7!#;U!)a;hfl_O9Rdj1K6CE9v8pv3}5RM7M zVQMIv21sjZ*`!)1S_avLsk`3-F}@!|d=l_?!$1f^d324~y&sTx@G(r9VPKO%WC$w7 z@0wu@m|=lXn-{F5sS_w+{_e^`&R?k%tJMK&u~O;Jbzk}I&zDH#9LK6uVt=K-XvwK1 zV5#|wfmB2?g=pc=@w&kDJbRS0qS6^<&$9)3VO`ptpBJr4&9OO(BMb7gw0NhtKR7$D zAhOt5(m9;T6jPp#0bHK|nw6u={A{Td66j!FLG4XEWH6uriHH%F$XU6Fh^1H}<77~p z3o(6!#gJ*h60ro&A>trH#GDM*$RV&VpCjXfWSkr-bM!Jopge~WAt(}Ksa6S*ML=1Z zpM;l(yWro9z=9_%VFP5aT+B}4tOa2ScCD3$QfV1OzYo@vdx6BKj%nm=6Wt`2B$Ipa zzNtsh(jujvfKm9fkxpFsmbVgLeak!Q-TD^3>aBc>DIs`#)wrD$jK4yDLDma2PvLMJ z;2=SJ`Gx7C5>c&)nJvb7;&Pa-I8+=jW@d6YohyMv0^(Gho?{f8SRx2P&I;)R(SMMH ztRMwtQW3+$zcOhKNGxH*6f4g_asim}5+4aAu`D>hFf=(WMXrLVhnUK4B59?fNAPh$@&I;d zpxbhn69mY^FykQy0^X$t8`yQ*m(<%Q)b|H344m$-A!YM5SS~cULuIuurvdK}Vk^-50b=y-!oA*E;-Rhod{kJN zhtUA&iYDk6NQsZ!itsSPIk2n`Djii&DYt>(Owvh~K?M~CDf2uG1kzrhSbPO*AX7mf z(1JBEPB@U8%&|M~oMAGiO4i_Ze;9YFFz$F>EB>;Lsy0Y%!GE`bbs=AK2;Vbg0jHo@ zFm?E017o|_y9-7=YpbYr>$fmsj5gpGAouQoJl=fXx`D$q7epXcwGBZ5V;B6JC0Za3 zm7oxe>JyDX2v;PbVLu-JHC}~ZV2pRJFSq7mOp`Z|;4-o`0 zAe3X@yV}+!;BPm3n#twPg8v-G`wzmu6(b`wcgE2FQbY0e7Q7A0HZyEm4SC7??k_)N zPk$WwMG!noggUFu>p+V?HG{CdLp2Q!DO<6g?@ZOm@$Wtl#SBs{A+GrcxXe{%1lEi-hO z%`2Xh8?KBkwyF6=Gb}Hj_9nZlMfSGAj7AnKQ<^Jk+5xuD0R2w``qaaJ4VlYN6H0MP zY_+y_8&hsXZYdpQ{mh@;n%|_!kISs7nb3%fu)o)`@%5_ zSB1BQ_l1vyUkVq6Q`s019_0!T4{;lU{oR~SPD`E{IS-9cDWL+of`ovNuAuae(v;7< zyw~0bK;867|^oBN=J4mX-K7cV%@w+}?h;C%1cvqIlJuoceul0UeA^e9VRd9q8acZY|== zOQLI|+oPHCwC1!$X-qEsOGc6*!<<+n9ujX5vobb}9cD*aHqe=X+yQtj;0R=s0y6Za zbXi)MCIDI8a*4|1Mw0|#yY)j6JXD+hKoKTdNei(ELt3!bmTpcrPukK#f&5fvWQuK= zIjKiizVQ;?yz;SBf`J@>CQgD7BjYzC3)+eui^@zUSGR+2v+JMkYK3)dAtbYY9+!}o zB*l+?9~kS(w@BHTwA?VfxbMiq)ReB{D+V8FOQ6(1<&03*1oWVXeES&R(H?^#@Lv|+ z7~d7ol*Kg0kfF#8kz{$qrU&;3KmmXpIV<0 zi7{k|#D-)BPcv8aPtR(Zo~AgY;=A`R9C&VZan;6CZR?(0YV(?sJL>Zo;*z9S&cpwx z+qoboG_e3yfi;&|T|0ia{ouQ6vupRgI}(C_6FGg&yg92Y^i*!c{}iJ!OG+1W&LbHp zkW3J?k=RM>9OgI?iHcHN!IA3~yf=>UK_(YnJE10Oy+P|%z|-zXD9zA-#snehtC|5b z0K_C1Y@lUm`5hQ6@Lw6ITc2T=nwD1MOMOLRsF^Q0>-`RklG+b1jdZ(9H36&I5LR zGQ-Zt_W6(a6V@-tZ_sbOAFFl-1Q<9Hh3Pk}*YouC|iL=Mqp z&;z!~B5k0Asp31e@%*zQh6&+oy7-xEo2<_o^4uwT3n~-Oa&LNv(>ju^6&aCk(4f`X8wy8Elgw@>08#@7L~D}}T@&qu@hMTpqSr$f0fM$RLYe*KlQnQ|m{OO!yT z3=ki6%LFYnl~gNfSln@g8` z?;Qf0uLRy33UOZtA2$@ZArRb|FouML$TVToBO~E|InZ=nlui~lGaPB%Axf2-F5Q7w zQ(K5y7=i$}n``4Hixp!tXyG-)c_^#UaWEyN%MRAZ*HjdR1n0Y|;f(oBMMrJnO_P+#PDA#eQ=S(x}L;NF-@W{?b1Q%dMR@s-ik>XZiIk2 zQzmJY5SpafiWnhHBgEL_AjS?$d8MinX)O(0p~Lc1@{4lDm!DAy85$?##sn8ZXL1R@ z!QsL$5371zLgEH;HcAdMbpY}-yFCXo5WcJgO-lg8v!S-1npZYjw@EE3u&n4(wSURk z?Dp`%{z06pVvCR4-kPN4vpB^0{(4$m_$Oce;4yIIba>G z-^IG%NKu^sJHpA0Nn~HgzXMdW9znLizpsMl+d*ICpdIH?!o-zlq)Hd85xl}TO8s2X zIgqgNOLkqfzGI!RGHupAE75`fW4AI@)>i8p>rN}Hvg)lVR>o@03sty;byBzeu+q=& zN8a(f?nhKmOp+mThepRSI#r<3>L-8;;H3po3LFG+sHOjhvM&LQv%1dx@BRPT_kA>y zW;BvU%V^&>OB&f)Ez26omUmgQvE>c$CL3%67I*JF_wjG^Z*5Dj8a^~I^{BigyLUmkPE%M@?2D-ga=Rk>|{s#$)BAD zJ8W9wUlRX(%j4_w3$J*Gf14ry|D znHJ!)wEL7f8VfE53r-c|Gi#6hHfo$f3QnfXFIe-1>+3cwTj0aaWbB(XY0u!!CM#*J z@eM84e_>6*xBN}(dYU%(l|Zv=?^)lJ#ZSac3nDl{RK3R%+yeg-ua|9I2ic zs9sdzi{JB;n>RePtv<5u>DzZdye`^s{bTC99>;hDl!YSpU@X?vTe7-jTZ!CWu@vkw za$^Ro0n8)Ule;JPNUmbc3S{liI-aFCJ0qI7i=Ajx#x*e7 zwpL~5;ImrxLZC4a%&1yi z695yK2mdpt-n-$EwFOmM9=(3+*{!wt*L)58@!zl?Jy_!*sWVn|qxKFhR|4(;SJK>R zIIhE9L#NSh4;i-`4;oJc*yNQ5GwgPof%G_aPgdPj=7;Jg&PKZTf_GSiL(I&&Dr&qw z#Z$JaW$Dp16_aMWQ~NcY&1&SDjFzGC!TM{X@)z``_B{`+NGSX}_2Zic{r;8(?U^kb zI`fP$DKY6u?8RK@Z}rlV*otfYs?+pZAKO~Xc2^v#;9V8VD|l`li)JD`6GyBj%ag?m zdh+w7ZjUF_XzBrWy;}+q;AWCAVqEm$$6_;;ugDS#wSA`i919x(lmT?CXl% za!vC)Z}cC(w#WLIu5`iD(mxa}zP7FH*v=kSvuOWNX?n}1MWMR3Y?Gs~t-P{18gw}d z+BWpv^F(IrH68Af`mp(nr44!M4tuooIvS(zUj9V>FU?Y@n=4|qTmAd}$NjRu09HAz z7CtzQp)+tsETcfo8R-rXG8W|b0dw5v)k|^gHVr{hao%D&h3TxQD5;lYa;sD@hzm>^ zDl$sNjv@kF#!bG)@!hXB-pI};;zR2ShWb1F-p=J?wU0dpm7E0<|9om{ynm6-Xx1D9 z(A{|KUVc`b%P(P0L%_sGpdA$-%s!pX4}?#IxiK6FN5gVM21~PcnoPj$NeBbvxpX3U z-5xXKF)0h`i9iPe!hLDw!NfV^e4)4E?wHb`9qc+^%}{G>Q%}ASFY1{PXc^qvx$3s1 z`AXx|Af0EVH}c(=zOJ5UGpE8`8~9IYj61MjZbzH#(!H_y%M{jQU1WXPErB^k{bvMGZdNIwBiuq<@QngvxaV2xTEtun%>EmU2IsSxAQ4M2JaFg$cRg%i=z+)b)j2cOX0{|A#LA%%9YqPrH&9Jb+3~$CFoyD!Q zz?YMmletL8+&Y#CXTxA&PGN6Uaz~{comaNGqvO%TQ8^kdwnfKutP%)aT}FntFlv`= zwjA#s?-4KeT9{-N!;FE3!^TJU*DBb}f!2i*NcL(Ktvl_bxm^HuXAQnUUqe5of5Pym zn*Zo6d2JZLGbtnuIchvf=#1*Xp;Li;Ha|YCcNdj_(<9YVK(mS#uU}_0irZvNTS- zdrZU+T!;BJNiW5AbSWxYssZ8H$C$iV&(cW0H^NIH>$Py-z$`86H4+>$pd5!SpBvbq z9_o|6*TCT$qg9P!y&B04zIT+;0SALt+f5YtgC<)v8d+zA;*ZEm;ALsAR*`2$0A309 zit)T+0sjwtGHf`k`eTG|Mt(f;O5!`;V`me){{~d|(Kiyi+2icniFRJht%=p_uckho z`djpSKF;}L=ywSBo57&p=Iq|++~YjrlzTE)W^$QUW{KP^^CI5Fxzug$5v)3S(wM}z z+6e?J3mC6t_iyp<^B;pSwZrJ)59#%eARPGEyDu0W-8dzka58=pGdg0xsX1=*Ge50h zi^bmUx7&jbn>l%@t0LSLk#f}ImP4;tXU+z)fRN{a?8dZyVB;wY3#p1*9?Sr>t&BXe zVo$rO_+Llj>u+3~-I(Pncl4hqcP642;bF@P`nc>1hRm0~yZ+(rO^WVzS>AhVg;F+k zOL~7_i^0^~+n>pACH;rN(k>~*7#9Q12_U?@x;))79l+~@Q1^SaI^4jyc2o=ZfnJY0 zw~4~YUm<4!fc|n^u`ykorZwfxN&0h!r{|R1IaMi7j^`f!m8paBqN!#4tz&ZDiDQ@k zUidHG$J|74C#!(3$+_2d)W(y6vD}X_h8y_3SRD=aLWpqF@!_Q0FqOQXEOA3pYv=zix z|2(n0IKI7|jkGSW4S=L4P`9jwjUv!2dcsq>ur~2T!a#NAZ2lMtM>!LESh~yncrld|;1@&Y&}gdC`UM&mE*U17^8R3pltua@+at`T3)D(%K1{3G#m?fl{}?Z8B@NXJfUdqtWhcq}cun@rwsW)JvBHL5Bs;W?z=) zbY3a-0WOThA34ro%)3r1j(NCpKi=61jtroSBx@hm*$`-E#X6u6AJwaidBAc2MVSi( zSv*}(!||_Q>d~}Q&=lFLUxhF58u$Vu2mw3qC_Arz^So4f^Lf{s{`0Ktysqke#+&Cu zmFF|;H=oaZ)6dT5m7Vwh;=J$=YdH&6U=L&)+{76TaCKAE_A z!(#rYOP_ky71Wylc6CVq>Z|rMcl;CEJP|d#_@euT`c~^#u$GaBP`L+Kty)-f*UNsh zty}A6>D#jlOSanylfe&~Pn)?d%FNO1?5G(!#CEBc)z;QmUaz&;v@u_9H~B`nw%EG6 zFa*vFP!^xHy#>t7aan^FNDH&QHMaZazdLoJX|!*iucij;VROg|Fnigg0YphqXboAC_-_Fsw*cuh;q2?WN3K%1TS61|=&i_p5}Gp1{&KYi+V8 z><l=nqxr4R9Y5p`QpD2DkwPemFB#>mYet1<#KfiU3xt z)b9w_t=z3Men@1x>#d#aXHrC$K)jd(YWo#@`_@$CXV~q`CeZ|FnV-1aCi%R&@T?cD7 zY}%M#6wO<=WwiESSJy<%hAkT-h0(k%TgFfoN);F5sYdlFRi;&A9p4W>zE^rKwtd*c zdT~?t6nYvw@}P^!F{J)+<+`d}klzIVkZmAK9C65Ig=w{3J*=!wgU4&tI}KJ>8IYE4 zMbfWvSW?jjiikAu`E{mIuv^HsQM+5RgAu^4_c&z&J|`I!p@86cbch$h=Od^uDnYEI zLPkc*L+L)Lu_!Nz(6^iZG^;88_e1vQC~ zh^j!utW&Tx&d4X8;E&73OMm?AKG}5X4^*FY_VQAt7-walw2o1|Vr{XNoR`(nO$@iiqqQZXxD;_5`G#NN)MokWY!nJHBcvH+U7NngD`olZFW) zcA)6|Ia3DiC4@b$6-equ*wM%`d-MSoqe zamVA^hQG9@-}R`uZt*qP8hynLBL~{r4sCABYFb(o?QIDEjQyr&#m?r&mGeRsgV)Zh z9d6Ip{5aUU9yX2Uh+}0}Nvt%>YA@~Cx~OD%Po2e66&tAP*|VfLJ+`?oRM%B#_ms4k z)%H~7*lj4(Q?jJ1#%3*z#mi4Tc%B%8Cnge2e zRm4K_5#W@L5Cx2eol#&=K)~@ch#AsIF>f##y{$r!VE`f|4oE@C-Sf*YPyOt#lviKG zAKJe%?iP8<*Rjq72L{WC-Ebg&BF@Jb9$v`z_8;x%dwY-e^6}2Yo%}%TM2zq2IM%`U zwH<5Ya@-Z?@{Z+r3Wa!?rxgz5nBCot z_~KA?3k4CkylRiKXmm+8T|k!O2i>n$Q+U^T<3)rbA|jFAzyYm!!yb8q;uR0tPuoAX zU$!gp!1=(%fGh>RZWymBZxAg|h!TW4POm`~RreP>*Qw}6&HsQ-i=E1-Us_+-S{63% zc2zIDX2Gf>%ZrMZ-L`zeHQg2VUB;}^dHIb?YSQG;>PLRQ@5Xn|u37WQJNx$i{E^jb z`i?$3w(;4+eSL?Y-8lB_(LVlJ_l?WS(@W|za*768^J2RmS-bwB?M=B&z4_rlWuC8e z$=-!8Cq905Xy{qyc==`KxUg*5g~Z1%Kl%InySncG{gY39e1B)>{U1Zt{Dhy7r!@CV zQ7}O5e+h(~V22cUn7_jv1|FaS#5NR?1Supw&tTB^Pq|vDhT%+Zw!Ck(7QL@V4+Y9U zD5(8FqjBYi3y|$&(qb`w;Chh^Kp1Nnfw18*>;e~`v`PvwEevyn4<&dAL5pS>m;|s$ zRb$0bmm^NR)LAFcMn7r1=C-a^)-GGR#&n;)eCfXa2c8HOnKKN&df#BLtQ6fnw(rrtKU99F{g5%2(eRd1E|_J*x<8x zSvs{nah}C5BrdRlJK1%uYBrK!2>&S~l2;F0s#UZ^=UjmUR_v7J3Fti zqN(Wn#RWC?nwpC5*Y2pDsO81A#kEE^2?6)3fPh0m5K&>3_(AYhV?l9s^!293*Gr@l zdkHUYDk*6ymUFhG?MpkBCa1k_lafpjIj?J`_qVFP(%!~M&)M1p&j7-ae$@a*Sh2gs zJv!-={d{=QRmku(vKqAEB?ZhSC!=?2m9PJ|n>F!|fAi=;R(0x&n}>dVc4XkI&&QYY z|N0;7&Od=D^Ss=8%l5GYuEb+J-qD@-*^q=xp`U5~P5G&I(5aK=gFO2uv_@H%oFyN@ zor30X;Y*T3-N!Il{x+6}S<#VYLKfzUrzI))G=&CCK)B{SL-q(w+B3E!qlR#biE{&{ z1|$MWp06qOf3EjSK2oxHOB1{}rKO8EH#KcpTykA{d0Sqjtvn;6ye*Q~R-Udjljp0X zZ*$YU&7^W}o|o5Fk&#hBr7AKrE84^!0~HjwU0#Kq&n9h+)!EF-3~{9v{UhE=yTkJJ zm|5knEYr2>PV3~;y0f}>bsxh5B#11bw>$?%9}sRMCb04cVA~dqmSq8z>4r!xr#UUL zC&^GDv_EW4fNO#FoT0WPq80vBVh=lU7dxKVd)L&8yY7M+sh(HK_iFCMJ$}hISMjZ! zdua8OqaqaY{bsv}kDU-7N?6ZW zKJop{7J_aB<%WH%k*BZNuxYTmYhn8e{Sj^HqH7l%x~q0*(=|)H>_?neZE7Bgcl8Wb zw)FP2>#LT>A_sRguOIB`SzNY__BUgdJYRkQ?XHmyke~mzu`D?HIc?bT5^wfza&q(~ zzsczLj=-c0`?OyA4Z^A~#vNUO_D}L7-xOQZpONTT@r%(XhMUe=YHja>4y^=0DR| zBEQKE$~@RX@} z4qk|32N#|!m(7_Th?_MA#E{W_hTPJm9%J9Bz#;%DRhVHBpm88VQ4hjoAnRO*k$kUk zI@dh8Yj7e92>a)sPjB7WvtY+ysqh(TD_UAz*IgfL%xXh18niGzRh<06@XWrr=<=zu?sAVDtdT5V-9z z-|FE`D*)&dd?A-QZ7%vt=1SE_DZg;|wIlH(qcxR?<>Ot-kN)dlwYLBISNXdoD~_&M zdStkAKja(xggwrG#ouyjd7~Kb8xrjddIl_vgA~#C+gO>+)!iOg8UQZB;_CLNrTM&M z8uQ{-c{|GKncj7GS`0R9{Kj;r=05DYGFp-tTUv}1F^togRwPW;Lc-}c3D#65 zWW$4++bB>umW}XU@S45{Mo<9g)dQIbOg|t3(|@qDlq`UkQk6|)>J@ex0%1cG&0;UD z@~|9cu+%MFR#d*cr{1yecf4vFUmu7D9oIQ?D#KG5w8^>jPtfK51-hI|3QL2r^8IPY z(>UD<`JV8RFyE7LB!f%upK+gaUv$fEcTV8_?P`n|_!Nx34{T7^o(+8fPOWLchZ-s- ztU+`M``lSTf{JcdP}AgpsaSva`r$L{s>;{hy?)a@!^QXAxNH38?B=1WJqH!%^3$6e z8aAI^zV!6wrpC>uhrW39j{6o}*O7&*3`ee`JC#M#`c+i^Q2#ro{ZJzb1%TJ-R2So+#GS2)d#2xFEn>|{%A1-Fdp`dXvKmSDJPx7m(D8@a{Zr3N1u-8X z;$)7v*%;zx*(lg~aW*i?FjHj_>iUH0dXPOmH7WUH7LYs5 ztpN{Jf`ebjw*6T`cOLT8T*hGN;Vn_?nmmd;QdnOj?9TnP;QmD?pMz;a2i~U zd9eQshMefbMO$+AiiWswga@qF4Rop}`P<GI>qwEU^$ikZX%!yf-kX)!O@c&LB6JnO{|)bd_@fRygJYWas# z^@ENnRh}9oWtCsG{BWu~!eb<4?FQkIObwE`l;%^PpbpS=Wx5Ze$!D}IE)PjwuwV0f z8NSd^vPsExiFLuyhp$2A+d!&(BsO4Dij)Tx*~d88obaL1WRI*Z6HV z*k2j97ibaX~| zRQ!WBCVo2Ye-lJf(1VCcifnVK|1gVyP>LT-TsZX<`)B@O;u+SJc!}+w`c;qO_IR`> zkXHPm#0E{r{fWUZB+Bkrp0&^KZg(cO(|GJmv=f&S#v@Oxfg9O+43z14mR=e4n8f6Z zaeEBouwKk%L2|9Ugt_!gGP5QRp;He}TI`Z>)>@fcejIt!#N3MqTFthZ(pRfLxmHlW zMb!Vnq|-d}1lq0EPjj!fXN%;<+^0Q{#2#2HXwiR8+O6sn>g?m0AEFOT^Z|}1vEHAV z-G}qk2R5q@bIXr|g?Oe9o6v{p(xMM@%FnEK(FqAXxLSGYgW8_y^_%Pj*x}VDQtKD% zkz_9MI@xh6Jr!HO%X^!b^K$Q~m%F{WxOoPS1^B_V(`h_CtthQ2ZCje+a1i&GkNJGz zplg-Z2=A}zA#v(Qf+0h{fwzL}|E!>}`PiT}#6krSV6My&lk7^7K4CcueT$3~q?<#d z!Hp)$QQHFIJv1UHA6 z>&oO@e^tyi4+`1#)yYt{5d=!pvTbhpab)CEWfeWJJ{X=UeYN^$=9-5{R^qo4quTG_LJxFH4T|Zg@uCN z%gjJ!ya)ppUrkJzFtYws6uk}^9Mgn$4i_1%2TD|czqr$=s2P`m)ft%2zz{6_Fk7EE zx0$VFYqumGW20kkNgNjs7zZ#C~XA2-W4nAoPs?Ge?nCDH}VWD2Ox9?w3UE$a8wD_4+{J$$yseggoxeBtiecTo|08K zqBr?HipJ{#la@;908}BISY)rq*1(N~wgpI9D#?3=U!-Cy^0-}1b zbk+F`%C?iaeFAXFRsNRkPq*$_duMrBJ2+f^IWfNWWO?};!GzR*|CjHbx;x0F{PEt0 z9!e6rbhba#_MH{Ky-P5G9DS(m<)IJmetg%|;Bn?>#wW)4)AQRBNH%~yC3qCX9)Z_Y z$iuU$JPZh#du}p))+)YA`EhAkQXbL+%L18m*6^JAXZ8q7r#+h$xN3P?^J;r$$wPbq zGSUV!u3YnI6Eqj)Dba^{q7UQJ#$=le_>7GPv!YM!a;&ErJ{vnE={2$W0->@ouqSXN zAa8Z~adao6Ua_4WC?b_QozS+k7~0`$N|py>IGbaX;N*80PDJ2|Cw;`hHpGl})sjz;k;y|P^_fF^Sk?lBf+!5XM##_AR4cc;>&sma+l$6Q+-Vt zLT-3jS&d!W5l?g5(gY)3ngD+j6c0KJA;9sDbZyeKRl5vUFI|es2PTZ+Fv{T@>T**>LcAL+IdFCK;_2+*#4P(tg}r)N@^5 z!C}OO=J7I)?mZ%-j*kA;p*J1syv_al)hl$&iLwmIVCqQ8ohOK)+J3tL;XN? z+WyGG#t45Tqopc`vn_@d>^~fXcdV~l+bu#p{dFs26+}6%YRH ze*cdLH_U{J^FfLU{o2Er@7r)6K+H7e8}3z{2{*C7T}%IYeMuTqxQ zwc3s?`sDgV#UQ9CFI7vc>l1aK7Wy-_`(M>|e~0#gi5VSvY}CZ!CTxVSOq!5}5Y3;p zf95_nzFD+MJh#+n5yiz${rqRJUZdEj%tW7IXK_0#x8q~}IB7Q~KW1j1s-HvsQQNnr z5R~J{@JJuT5vNAnX&?GtdJL$t}5MHDlaTpRj{={E>fD5ZQ#5^XbgARwFbqh*PESYXV}*z@5p24 za8&2n^G1m`p`pC%a+u+t1df0t73Eg#e(iB&1~s^}iq264Fbft8cv^Kp!kMe$8D1wc zgaYsY6CPpTXrIvzBkc$~3!6^0r0v{AOojL@;xT9GO$^u`;H)(S=0T_t^F@3*uQPMD zy=^AQMwlu2hORwD`CAqxF4g^g{f+Z~TCya{^mRXb{K;;?Y{3H@9jDK()Ml7AMH(8 z*B)C{T(ahlHQ#-VCY!z{ zwd(uzVDE*yO0Tz=4d00AK@+C2O5aG5%JhR)_bmGutRX;Nz%vVaw4EObC)FQkd{pG5 zO67$kTQKau#4JM?4#!hdFU#*wed{UtyDz+ucF3Nl%`9(!RJXHpt=LxuFK zSZ+t|Q0~TDd0RPKSiY*9n~9iIBxuqR(tAAZa2gkx8x8cG`>>k>w|p_S3EyQ#gM~_7 zAbDT#NnKfi@<2==EzShAQXn2UC-4`bL9qu$#n0ahXaj+&ye_NJXpI$=c3Wfq^loc3 zvoNTHOT>M`rSW=8;x2nQPMoc&XeHq_Qg0E&=Q)i~L`Z1a%RAy%gOZw+ zihWc4l60@|LhZ~4=@*3-N8DcZYJq6(;m$+fzG34NvA#u1%c~aL`t5x`-`~ABzV15? zdqOVS6{A#+QzyU!I2GO5(E(O=H7c>Dc6s|q$G7*N{OO&Y8wT4~9s7?(H^ zGo`Wa=ad!e9(Cu7y8kp;oHtW?R^7Co)wa-jCW{doLl&byO-2jUCz30gbS@EVAlko1 zw0|6`IJGAWAF?eg$1!utap@(B$Ao_F!u>4E#V`HTeaHjH!a$a5`m8BQh;yGToCZ2}iL!y>MK3@pR&#|pwzEe7L z66VN~!M{mwL@G=($-*MvF*nw7>bKKzm~$dE1r-a=o)c%uev%5noD-v|+mqyCnHe)0 zXLZcBXoTG0G-w>rN%v0-Mj2{Twk+54!f$TYU|EYQI;-hGwod@Ig;(AI_2WZtJX=nom%IjOEY7kDJZ>SEXba?QA>5_i#50C z^82V8w>v*94KH5)!DJu{u=}Ka5NAjT{5fx7Z&O~g7H}5($6EHb9Bq*`rah)3Cgd^S zuQ{%fTMjk6$V{6>b?ZZ(mKT{hW^HQnN!4+O z#U7o_ql4=RcDuMni&$gA2u!Kg1U4+_bdoOP{|TcGt8sxuf`75%$h!EUHI>zCZ(Y3p z@Ri&;i57o(Z&k(0j>5wBRpsRis{;I=`d|AR2zEM7{`4fMV>*}pd5WEy>z~+h?SmW3 zK(WLAE6j2uiTALqF?UHjwNopd!4Fjap)X+k@`0uMLTuT>##N158|9AZP;_HdZnUx* zA8t$@_a65Vw_p z0!=WRw5XYdL0wbjfwqy9v?*(a;-WBaK~ki-g1jj44lABKbm<#&iHnq{FICMD6@kUb z2GXpeM#la912d@pnFXN#4Yx|NECEAD4% z-6R*(y8E#jzBJSB|2=6=dTEmKRIQujg4*tWv>Vb?E>2$L#8^O%JrcIC=hR^mF6 zr@4*_3vzPuvJb_>qu~kU@d-x`<>iHl0I6t(04XO6mxG*Bg(oA~M1*7lArdA6kR|ft zmQ{hCd|H7cSwt37e1$DaNFU^OD*6i)N$~&Y=jd_(xcYNsN&G*z{EGi}bK-HZ?Y}mg zHEA0^FwL6uhUO*ri4$%Z{xA;MR>}_rmdPhg#0GXy_6VJ6m0O{lsjUdVJZRR?%W1Q0 zHmCVy+ba7(qWqS25Esfh`+2);_Zpp}IvMyU>qy+k&iT$0%QCZ@obVmtzE43YkhIia zk!2MluoFNY;zk$VLwrLr7-^Rgf+%44Rj`u-b4b9b8oJg!MyWZ@oqGjII?l;krv9kh z`hEPl_mYd!b;uvxn>h84{|NON=25{@l`rj#wTwFtJGsW;aYP(@97i0QS~H+u*`7|X zx6r_|J9F~#@}-;!Iz~JmO=N)Me94GQHuj$F6U6A_1flHY04P#q3VfcT^<+6j>(TgR z+X*M7o*Ot`;fE*O>s;a;EBI=tBbYQw7I<}*tHXyiKYsYo;n`Ex#~+xUvacymA3{s8 zCw_=NGU5LezGB?lS#qC~1D^Tv=lGUYI}*t>VMh}8d`L7hbG>-^caxsTjKykJ{iK7d z^-t^ILI^UPE?4@l)%xjtQS0y1i+i0~|G!U~RLhpIh|Q{>upnyvbjHm1(j}ZQSF3;8 zPRABQKcssXeSl>1&9t7z267&`T9S2Z*?Zf%b-qEr+re=HwVVM=5VtL{=8+bi7lN-v%y+ zI*|slF*y*oAvLgGvH=V9`*o%9vma>87cc(pXJ7ps>zXEV@gmj?a`Y&L;v6bTo}d0~Wc3$K5HAny0;6XPJw_-7sv1aTNQT-%jJ zVou6vPNeb6k6=z91+|!x7cXy~)FKDL^sI1|PY$|)0cfvvF{AnDUdvH1mfa?@Xcgmt zw;lF?lpF*aM&lg1IfvbR61?njy*!I@E(KqmVV$ci1O3QHMN{M*o=rGNQ0mz%bZ-)> znyBasPmQ`i$^1X+834Xp%29-MK>fiwFebI$pUw1y>*U(9}}W^v1OMclw*khR`W4gqz$p=6O0|!u~FR) zaIPCn7K;s<3gn3_+<)SD{NR0;vTQ>Cbe@w-km7B^EgUc@f(_kPoo_>D?t z`1dg|G<}`xWNR2X>t0WvA4&G^00HsCz@&pOjaGr`qrK&B0Ttz79H% z2a@HFp&~jH$&`C6uW-iOA?B527VU<E835Ws84C3s+R(DHt=x0S7L1gJN}F;lxos<|fTO4qWXvkLR>gPkS$_L4yaBhp zefQ$DXkBoFCpX>Jxb1-v_Gn6Vy>zQGGQ+hsay@ZIigClaM?8@=Qh%%}n*wciXBtFbS#*R+TwJHnRqC$T!bRj{ zzX~Uz%3T6J071F~LN^)#euvy75F(Yi-$j#iNjPT3B0)>+3Zj&~gzb@YP2d-+krHLG%v`A>JsDNr!;)f|>h&$8_T)q^RI_x28e@7{Pht&jI zA7AII2weVM^MRLcYOLa=iCvVkfxR%*I_CUxiM`y=`ugCWvwZ)0t3 z9TnaE{t^FK|1*BYFU4cA+NR=oR%W_gQw!Ik)ir_0AHC~JGz?A_8W!41_&TjFC($ni zC{X{XM$aVvMbK-&1WmN2(`c7SO01+DQ7UIS!mt>gmU2FL^-OH&K9!2 zkoKPV+sRa&RNs|tWs5FPovK#!?@5#ck0{Df zdkMFMucU8gwxueZH4bEl5cP@LR67KXgK<9c4_&b)=8OYd1Z5#L4w|O6E5>0F+Au*e zO!#!@8}NP9iO>9QqMi6V#m~_y{Cv6iIm###Vop#Fa+7ovRj1LTEeJzav{$rceDd8-K2ejnC05)wbuYj6KK2x)azi^` zN1tTPQdk2H#1ll)<0vr6ZNOh z#aXNMldhrGPr3$VN2>n(xwr|nerk_e|FpirsD3Fl3yn0Z{iJWG^;7xj`u{XpRCU$% z&(t4B`A4MEXE_s*!hSbsMMG>yh}lE?r0>A7q&|Z& z#52W7oXV_cPQgZroQ26Tgzd3ONT=p$QxCNtW$Km2(EDDanC)Jt+U8XfMDtb#$^3AByLMRf%@lQWK#8qMg3Egd0DeiGPEDm`U&SR>POrjQ)62= z185(!YcZ+y&l8~%#va>C#yvt)jH{%QR`d;-A*uggu{XFLG4Pv=_0|XD}9&v&AR1yo7uuzm4U>)F5>djBY!lAKx80z*JU z2$N$TDeUO@AaE%0Ad`PZ&=ENhK|>HwL8@ovHWt<){Lz(DS5?;{%XgM8%P4U7=9DxS z`VHxXVMR+FLeWoWWMRtQU7a0%n)3pX8Saps0N81aQ7HlYx3vP=Z-VvDqIj5!Q@B~J$<}iqW zG9@`9Bh#QE#wsPIr&RLXup@sWpXZ-E7(E^3QKvRnH&Q^Lget_cmt19r5*WY31N$Pe!Sq9@HgUL*+)?I?eBnXXZWMr zMRw36(ts^ZqrHjQsNCVcrLSKmWIQnL5n3w zUo$Pr%jHWlKl|ToLE<}#FLPN%es^6sT-TlG3Dnn?IUMD+^=XL<@*89!{TEv%VsHJK zHX8_mZGHrzD{A}(?78z{vsx}~W3{o&;{|Mg-|;@aQ31pJ{@UZUaviZaVb&epvE;1J zqgfB&2br!CSF=mb6uIZZ-Y~BwN6HY9vaZ9gmmVFuZTaEB!S#n5YUKv$@QNKPCRXr< z6%8vw-BzovGve*<9_i-Y-J$EsyDk#nZGRUXUp)hncgsI6zg#Yt6Ej13d2OvM7i}6o z)e=h!cee~qZ2Dvq-$WK5kW3BIS4W!oN_kVeUx~aG;aQPUETm0?gPS7qQsaWS*O5Ut zJ8Yz~Bv&PAI`&@_ePn-AuqcW=WOUCX$FuP6h{DM&NBa$%P5_ONC!VMuNL2#qiV7;# z61O5~bEhe%Cn7%H;C;Y-}bn0!j2V*SNovIr+)l z^#vIZ5v_bpoJp_I-`$e_x4dVQeD^d4`${OqR>4H{R*HK~syuEr z_`_H_azS3uOu~;6iTScvoQ<*xpt`j(fh6Qp$XLWdB%^{NzE6xE)A$DYLK4TIyyiZB z-2L&~`if%KEPY%*s-Ms+l%`Zmdy!Du+EdC&M(i}iTgS>otvN`bfg@5Pq#OB}f zUu{t?d`#6+8wZqkB83;7xmyFl9qNxt~T zh1V}C)*o~%8yp&P95fX7Uawpz>s?dQ+S%D!vZl8TpT}j5ng0l9JebxIrL|BHfi1y; z6A2vPJram_`E~M2Vvsl+S8kG5Xn~pq!tO+pO6O>XwO1uNDf<(+a2T&mQH=$H+Ls%+Vi{X z!{K^Zyj1z0KX)%;exN(cK8%Dx0_5_Y>2}|)?;#?lJCO^!rM)P z5UK}S2`MMIgGgwJ6l|)PlYJRo1zWaem)E+Eq*WKCSCnKnW+Zl)ZDT`a{moI6wWO&t zKU!`vVd-4P+W4`CFhv6~yD=09@gR+~#^$kcD;*}e_%3kBmR^?Lntl)|CN=5l#zT^+ z94>)?=Cu8!=d_VlO(k%imHBb_E0=?TJ5&6Ig`X}mATm+3NMYTP9Y zn~Iml7lwU7w^7-laThIAE<{Qq_F!>l$%?LGdK)UvC|=Q3f;rAadtF$|8hC(L#cceT z$k!_JTgWF60RG#U7h6hm9Be_yC~Fwk8oXH9CrtD!8-8UvPQ$6^Cr!i%g;R$pll|n^ zq_(SHX^E0sGb~=&vA14MypyP!gFt3%(uplw5alof8zv&p)Qn>06Q zZr8|~LzL3^x$HbOwQ;2{9ne6n<&LFBR&8uIE;SxD-fMi^_<`|Lqh8HaP20h6hmHDc zI%6=-wB?;jGAZnYG6kQmaJwMtb(q?wHjU`92{XzKwXfZM-|4AG@1k~Yk0kDM63r;& zF#aH)dM9-LT$1r@X(I1(96nVJ;+z)~k;!R771igI;(mfmD2S!YU&x{Z=p5!#deA0R z|Fi5ZgwJR}J0&(EWuqdpdG^VNNTUD<67F7?-@<3UDtui9>%?bHeTvV_n`D5%5c=sk zPewO=eb(Rv_vm|*goMIDQv{SZT7l2P^IL#LF+mb;js?dYdmTp|GTgCxNhhy@n6g2W zh3;i`S&xD>$rN)s4w?B#T*uDo&J!KFq;X(6U$9yY8d)JaDA?+SqZ}83osb{c1F4Gu zt_9F!G1uTafk6qD80w8cG|SH704!#Bjhk)@SwN-9-24I5I0bCE2D+f7H!G)^j2^^V(MMNg3zxv{$BINQ6QUhsRq04Pp$=o; zw-b-N@t=Qus}V1;X8pjWy+K z3XE%<1^8Rzx7#tu{w#mFf5NZWk!Hi+7K=u+SJlM8iCfc3Sb5t#*_EGfkB&GCotYz8 zUu4@O^dN3M1eRAB_OO5irW@Btfnq{3judo0>Btal$$}r5Qnerr1d+I>u-xSD@zI{e zg%eSS_<0Lg$BEy$^QFVxdHpvG1Onc2*XxOj-jP~&{-WKB`gZr_yK6^!6BVz!%DsWW zzzzL*h!~u@fbrC<8hZHGcZ@uD4%ZBTm>zns?&dqrEZp+c4YAk_Piu*@w=FDS9NvC5&{|RLG&$As_sp)8tHEe>od;m>g>vcO$bI zmrXKLR&944be?v~NQmY{&Z1Rpm5KEN`GCGV6~+{&>`;LkzDjTgKps$FsBlRMChRLN zsgP+{>NQxw9)`=ORo1bvnf>}x_I^U^%uaW3=1k9aCVnVa-=$1`w)h_TE2V4uYZaxo zf28CR1~54$gdf)uCLP}kTaEZ0wwmPc3A>;L;|TffgijRf-+_FeVd;mlfn|2qVP~C| zWfnfeHL^GJXeO`DWP8(&rt#`DHIrGBkL`0EbMYn@3kA!9t-*uA(?Lxz1}SR~XNAkd zJAf(HgduQa^YOEAFbv1=>Jf~Spr4@e%JHv`8<`!)P}Ybo+!{U@J{?xJ+r1SC0}#Z6w_2g%nY5lJbMKdXLFNu~tel(~-5bz>{2 z^dko^PQ=sTYr7wvw75G&#rZB)H$Cxl}TEetpT>{Fad=Kl&E{(+M>@a!j*jkBb?Sb}WgBG1- zt<~nX+ALO`Rp`RbgVxi?+q(+ZPsmrhO}3`a5)o8P7LQr^wCvLk7+D%F3hbN-ph3!_eki(Z*iU=JM%2sOtn6 z7p#-p@%v5`RpVc8k8QlDdt3LOPJU1KiH^U*-{S8gU1cns+kIC549LKcQuU(gZPR-u zMZ(J`lwwtn1Cr}alE(6u!X(A6aK$)c16GIhXuG=rEjI_d{F-4r6Kv1yQZ#DzVgsRpDlmrAz8)*p>N4Gj`;wl z0Q2!>^aXu`k#0e(OkNd2f{9jTyK+#`(93D%6$O6`x>Y+!39&;BIS-+%MRSs8I^6_R zEDEV1baWH2`^)m}uT1?1K}40We6~Eb4o1Y7R*BEO7N7elKG!U5ilyz)PKnT=h7$ahY7EI-D5n$e*Ne}iFG$6tdM^g zr$uO=Do=3>#`lo2%2T5Kuw`TB^_TwuA6-8rMHJq@dtZ`DF2DC2vY3GG`Mua6-qcb~ zlPr1(u8K)kolS2oT4js)b!#d-#1+ShH0~AsTY9BmKcce7>GciuIhCUxzbCI^6bxNw zU_&){49J6~!1M=o~pqDfF=spc#9;UBkMYwaN&R8Qj~gF)!TR zAHDQ9(f;usv%Y(Lu$X^u-8WAx`Q|;nl&I$ji6qNk$`du1pu9f zkyPYh7C>Q)2TyC<_2tbKkA@a(>8X0Ks%P_ptVb)hJhrQm-MRGiw>Ps3iQf2$u|~Q4 z(%X$=C*tgziT=&sKD{)t8~s7AL_V7a>F;AV?(-b;sD$BHDoZ&cNEEs!CbTa%bE*>fGVf^gG$R1s@k&F2F^=UXWEF?|!hjS9!m`rim1*vYOT!UPF?o=FezV0!FPWRTKn~(yAyAu^=g= zjgvY=AaGT#9bO|KpADH*zDAS)QCg*uhlJJuY?UvhByiiyF3K=W8{BJ*`u zZ6KI6aLZ6h&+*s(|1~Mvo8rvT9>x6%XAbOhTSQ#3@a+kbKt7jWFSVb=Gb!H`#o38x zgm21m72njY(9_On{s=wo7NMst#iQ`u@Of|s`scOkr!94;{~45R6J>8x%fd-XejdU; zG&eTer#=2COZk1%MA^evlqE-P|1>&MjlUJTqA08Cic4Vur+VEeYjpcmMKKv;_hq!9 zUFel}i+YFtb+%sl0m9%_hxD{w3B6DB5!fX)esk;o$ngl@Uwyoq?=L@I&NoI`GNO}` zKXQ{cU3)-#LaQ9eJ^?UeSdij}y*^(?k6jwA+)>HTRGzDRyYjtCrLvNuIe|^e_IPb| z@p1cMWY09&OX3IePrwNx*bs)H>*N1S@TRa`LrW~1!8u|vQck9%?gBj?;W%U`(FJ7+ z>C8{XZ6fmt$uxOy+Wh6)JKy~4U;eaX$Ff#8SFA3d<=fuU{Gdkmg>s!Qm^^liJoWvI zrs4Uu8wQ)L=8~?l&iSLU&`0%aJMx$tx=jWP`S}b5gkjq^V68mO|a=@Nipfp7q%AeFFal-SJS~z4Oo0fXehKX zBySKbUUE%qN9$0ltmeE$U@Xt@&6{WOb%(=NpqOgywY-*gb*A0bU0XZ9*wQJ1r7oi> zK5w400;F7dai?UVtaGYvpi++$;sG`~ywZQ?G&vpc55h{92fhH<`6-EUl6{L~_@+4q z97KWy042G2aBEUF)olOzjbrEP5!p2P!9QJd|5!~<^FV3CuGRI4PtzNg&+FXWo}JM( zu)L`I`kuVfbq{PC81Kzt_pNwve12Vi!g83S|T1Oq^2$(M<|XLo(?jt}s}iIW4RXCPZd4WoCHPT#wS_*Al&sP`X$Dilf}0 zC`44lb~W2$Z1G?wzx}h%O19s0xb4u-S1Yg;b7=?m^AOgR3%c8vV**8stcz@`jt2) zTf&AFhGLB*RU5ksV+AGMg~VVYA&+=jWxP~VA=%=&0&LUJAhawZepfasKvoVb*=yY0@`@Jce9rkdDVz>~QKK3o$S|R%mlG7xo@}DW^YZID zcCTLG*^;$#&wazYAKy}0(z~IyYDHV5?%H!(?)}+s+x7n=TFYxy&=1zKD4x;ttML5v#F(Fpe3Q>`a*SX)x^~^OXe<_-!^s5wEEUO z>uriXTso<2VL#^S<#9s!dUctZu1X08L6eYU!Oxw^?`jrsa#CW? zz``RcsA_~m2AV9Lu-_DDcAJ7S6or_m)YX9b!)N2O>)4h_%WrHdm~++i`W!cMQr>9t zI4#xlu4yV=zO=73F=54?hrZTnjVDS2sY*F#=Ho|hU(v|6t24_p943FHpr*Ynr)_er zYrHjq|VESu7E{P;7EAD)Uzx}4p$xAnm%o_XpC!IQ)}4I0XmRJCY0 zXGacKV%}J8Y*TD^OqbUxNd+Nmt3*7EzWIoS0;)(~Xktm#?2D>xYBQ-dr&SR3SBo|yzyS`Uv&ZJoXW-;nR9 z?}Sg+?CV58!%?5|uJ0q?MW5_b^Ao7mUJ&)S?Kd*Xc*gji@f_TDL>kVVf_9_7I~sLn zbX%NVGO-bHIFV7WADNB>5x|_G#YqbyAO-?%+K;pe5Zht8AY%oJ(vY{gE|w*GH0ZIc z)PDAFYrnpE;{W{p))T|Esl>#k9SJ%4OSzo!`cBx}@AVNhY$ zR$$j|bx`370MR=g11LJFI8^rp1QL6Ft}eHuLa*w(h*8L0W*Q{S6B-%^!^Csqj{;}G zH1AV@TvEVTyFk+X_O71ED-w$u?pxBg^Q!#R8|=@lcWBwflIzqNWqo`5dFNe_75@l5 z12KKj-~UU{2v%!ydCJi+a=j6 zWwvI{&E%OrvpK#8Kuw=>*tf&S9R&2r%Zbxb9G2ovL|iY-WSL$`MNJS%av=O#-v#Fa z8FFcrafo6ohziR6xWIaoJ~=TjwC>1qC6*s~rtypwkQ}EsfD4eQ5&$qIZ48X_s@&|- zlA3(SI7l)@B?;Gr`EAX)?CY<;YjnGvI)gtHG^Q@TD!;j;XKho!sO;7m4N7kJu7UG+ z@JasqhVee%gr@QC0c&0$tx?;B)SHoAoZW~bCKkWn-s-SqTe!n=!ooW( z12D~?PIi%8(0UX_=eVR6l%g&z!gz>yJjSl<*|LY8C}N zO8p*97p3f|W6yw06+{8#1+Mu8u7_TXHuO~QxM#%TjkqmQOSmexwyng=pYTYaFDT8z&v-T0#3=!dz5 z7OV}jQiq;xJyiAz?@;67$g=GmfZSFwWL`kRg?>sYxU%i|3HYK23X@*ts7N-$X%|~P9DCu z`^q> zk9T2a*kTE17AjIh$6(8F%Z?VgrDb+S8{J1&)LmHfGBcl=R*0W4oD-&z%urXD2${@H zY1ac~!WB|bIuC9+Uh<{i$v}UlQc-po{dM4j?!@BOWiHo;4HEbSi8ao0D z+LtwzE?c}{Y9U)ZiNot0S*drtj=sX499HKPY(c|3y-M%3yPb{rAEgg6I1#Ta3p{5WGC16`HDjyGv2 z#GFnbrkqhcn9Zf7Qn)Q+AfM%Df);uX(b(mV%C^a;vqtsx~11vwS?cXl%=5HZGdXzu&&|zdt%NZN|4h z{PPW6dW+3)zusb0?jri*(!<~rJxV7|)N&x%%cqoGRkox|o)PbhuZ_zSj5CaVMmf^% z=$H_h5$TJ_Qd?KXu?(d1ccMJ5oIz({K~YJ2M#i{&N9$4N2`ItDJ)DAjK(LH<`JIl8 z;x4mLh@lIUeRY&|kcEc028q{W0e_>aoR&#>tTtI%iBo!-H$J+!X-U_lh{E~EgiX(^ zTk+zpv)(AVYEyg5QZ*~m)-|tW%F-z@u55nuu1;@WO)RS^iaOm|}`RgrXErXAq&+>JJor+9BggY^;vgj$*XhO>Y8medu!zM zWs2!46G!GJd9@4DR=?w9ii*8=nXcgUV0>&rj2!A=iX}OfsWTE-q~%a_uSN;6UM2ezIw>ZCtjkXx=UT z^;?%ty0l|DR!v^<GF|x-dZ*@0 zomiFL7+IxxQCC=9dU!+QU3cHQa$>l+HnJgD8V3lQ=%f$(;w<(>Cg|j5wQp)!PubEk zc}WqQTGUg-*X6V6`3v)TBEKP@=LF1WobNe5L#7p{)b?)VqsYaG98n8vQ0Lqk8N~C* zxD{qr*p?075WQ_ygRyqAE8gXB6l;mOv1cGi;e^rVhs5cAc!P*o#J^E$AteKQgJg~Z z!E^%en6^Fm&%_$8nn7w~Z)1iBz zqvf-YhhMvG#(FHbUZs;rp~^4tc4hnR(5f7Q-3mN2psi^E zs{VRS$-Hd0$3`oGX>lDSQn3RCoh>!mHs|l9_WE;6{Dy+!0;8h>b>SQO)R=ty((X?7 z6xU{&xva2Via{@j8Wy$k?}N^T4Gn$ImRi)}rFJ&e)8pZ0L)gGG+N3ZGhov^3F9x#= z)+TImY}M`2ai_K@{o+UzW*GE5t@Vwq1fBOH5=F54sw`QV+PL-9_H|DV*T1;u)@kcH za=o!a-)ru|sE;?^{;x-7SFS-)|3k?o_Z+NT`^)-1=4krb*MtiJ;ah~!LB_XTe-d? z!(gyU?ausj`AC>kx!lHr?VYv(+mP+3?SxHdE6?cG8GWAOZgnB$%d0>@~tZ)w> zDxA4-diPE9%byOGsD;y~u}Qq<(9iB{)2CLkL%R08@9tav+Wjlsw>xHTxV!70|A&!J z9XztOe#XA9%cE|+aYH`eQ zC@ubF{%ifW_!UH>`fL4it)H3vA(UKc^ErJ!WG6YNCQu(EUklw_F0o~vYdyDkrLsC@efu}s_RQvG(^CJ!Gm>o=eujR{2aR2$n}B_AyE<@#d!L)%VA+RSukNs$n=N4rm+Tz? zW&4aBH|g%y@u;ps$3N4tcY!A4Cm~MKvG2rH7YlYcphS}92qm(@M@oe3%gWOG9X2V_ z<@DQ$u0E+G!I=Pjnsbp{oEtXKUIKNc*;*b%CE7)HZqSHJ6QKjHDn2q}ZAbZ(qo7OD(Mk>Y z)dM)=CrL-uYs|rLkeds_1>E5$yGy&-ufZl-Ne^QSJvYBWro<>&+9#VJ7w5Fl9!39a+ z6#Gp>6gIIc{!*}HLS9~7uG?2WV|@0!9X&-Qox?4aJ!%l`X@aB}F|u=4Fqc zS?+b`*5wsVO!$tnH)h^2ue^TMy}h#!Z=d71)jj;^x0mgBdry0Q+u{im7PsZM?|FO2 zvTr{+?7r18XZzvVz4xxFuU)vUwX;2Xb`Pg`rB z{5hh1)|1XXMZvYYX#7&N9{M6^Lik8ffED|SjBPQOrhZ50^pcn5w>MY0mPIC&mQ3gxocToC>#3j1b*X1_XU)E< zXz;dqg?Sz8z25xlC_K~4*MD!@x~MyuARI#Kb+gZ9Dev2};9U2ui>k%koWoo#B>X$O zTFlKRX*6D$lJ}^36B8M8$)kmTOv{@Kj82L4q8e|F%#AFM$h(cKMrPZicSLzK+kp}$ z(A<67&3Bl=ndo@y#jIH@Wr;07ZgB8gFmvvc1|5m!1Rp~1&C$f^#77C;5LIH=wT9=0 zmxtxN0jjpHbT}6{xo*Ho7|{yzpm~^TvhP4?_H(qootRl1?Z|Y8vmP@njzA5RgB^_d zg|9$^A-G08SfUonnALX-kOSEj5~=_I1I5v(E9<#&PV=(P2H(-l*_$3*zVGa9lhoZm z*t_iT(9F87Lfp;%P(VfG(RfQ>8KxdEM8CeQBfgD5*g7hi`PRwEcxfc zua6CZ*_9CI`yA*tU#gP&)rc`WR@SEniWmVgQns4il|7iPWb3o_9;vT@)+Pv{q@bY2 zQ#y!9Amd=R92j(Z$_Djt>cgcaP)-`XlCuG%3U&x1n)58+VW34g?c=gtM`jW&?T1q5 z0eJLEh=cN6)xd2%zj`rZ3Fm;n)rAsvOO`paBrg&USc}-liFtP}u6`^!en!c-`qGY? z2-`Dz|LP{?l~m7D|NY!GlR`S(Zbi12Ejaw)!#qEErf$id^T#h}&PjRWlMus)F~eXW z#_Wd`4mC&hieKR@tIub%xeR^Iz;Iv(r3KFOI{P|Z1E@F@aSSrASIQc6*^p=vz#fvJ z!0gk4l(tDhJ?W#4fErm;BZtQ?0c6Ryl7?{bU-Z!kXppH-QZGIFDDrxJNW)pOhK2*c zEcJOV4T^6~-bSyvdSUYAV*tOw7>M6wNIkDe0kE1fY#O^=avFP)iYWt#-zc0##{mA3 zA{J%fq>ojI2tS8qz$%+GOqRx82;6%)e-W~J%=MKF1*YzIzLJIT*jKTQ3=!(Y(%_IaXP0&JEy4~4$gjA zJC5vPU+7Xh;5}p`tiT*uqy=h|1r{}K>Q(jZJ^eX7&(@bC(0&Nf^*VaE8}asvUT@R& zB25%PEBquJR0bLOqX)QK7zUB-oh)YJPzO@>B! zcKQCnts7H?!|5|~49|+!=P+L2S>1X%Coo=JYNbLLY#Q&7+Oo#J-F}B%KIuM#I8;Zl z*Q7eS5Z7XIm_i2LC(DRj4RxW~1EDRQq5Yv_@PdXi^nC{RfI|*S#sQt%0LZ^l2w#;* z&XvZcQi-?GvO!=x&a(j8_2(hOAeIP7^@%e04I)+TvLU8OCyrgX|JatIspHGsQ+VH# zsec*gE~*$Ghu z*F?5Q?uf`s?VIeo?ed!3?YVd4%1aHK47;%+P8P~wmb{ESZp)5jb4BmfbB=m0JSQ(+ ztT!10#eLp$)S@vS$;!%g!Xp}W{&>np4wQXTmIvj_cU zRdrd%vg)eJ{0E=?egK@h@s+Qvaor{rIi&!@?~ zGOzNsl+7tyRwkGAhL*-R#dpVL6kCUrBRAyrhH_;cLEx8-m&f;JJIkHTPI*6)=5hoS zpFwD;wcY8QxKzJMzgsW2>gVdY9(oWWZcwZ3GnH@(RbEPz=pA(UntgmoC`G5?P1E^& zmLebtKU1^u=TB+nvIdG2i9U=}cRTdNa^PgrBs+MOiiM}CSWNhaPm1f2g_vLpv_olw zYFJUc0TG2Ftzi`^?oW$*X{<*+Y|`Y0AkYUn*3u3aVOiDm3chahiCv3wzZRUlaBJ7h zZF5S`{GhFE?la!Xg*!TD)-9f1 zk~?Kl!?q0vx2>w|s>>>z+B>dk_D%Cjs~7E@*}QCKt;1Z|xpwM;L+d7DT?D_z-u6fb z)peFW3P0e}OugiQC^FR}LTLv?-uJBMtV*+$oxw9s`HNvj@{vx>TRd~%=Ym2`PD@#b z4D!5h7>Qb$lO1CxnZoXLvu$p+3SK-&m%EJYS|eL-WY#ocgFpo`o!nH|{Y0;HoPkFZ z!U38#=-Y)DX+%jAAE>UatF2>?9oH!eEI%JUgJ>5e`Cq!03&*M!7nBt$8@_l|UR$sr zzqI)L{ptNK@>tUuL}$*$KjF+lmIg}4M>!ord6#mKV=ly5hq(wzH>q>By7#!bs9Lxd z1q-84sf|?9#_z~?)H>u1j-3uZ)zRZv>X6fKIo!xvXmUwTCuq`{!Gpb0$O$&+a0doB z4>{e&wD>`arSN4S6bFVj+PuigNj?l5N#OE$f($9-dG!c13k(c!#Jl28olacU-C1z{ z2dNKYRYloWmi#a^$5mEQ>N*WM;|2e??gq9!HM?RW0{4?Kew)E=(I<~0fqM#aVn4=} zAuU&}4+Gh|D!4VcCn&=^{kCd1+ks)UhI`cvqR#xBWaiS1eO96 z0yLISwx{D2C_NAC_2dAiln<1rKy#A`cSb*v)0qBA_4deMRmC4G>+W4YJ$s7U5a^Cy zRgvFNTc2By{N2ykqpbfdo48=d>;jmeocsNG-kJq1)8u{02>%VueHxz)d10d%Go&Qt za{TcQ$Z{`X%ofyhl@~MJ!uLROZESm)gbT`@N zpiK)2PD7gu2n$vvPppY1!6`3|T)07`Hc!4ZD!-jyNJl)A2GE~zxPL&JrB-b->@{$+ zp80z{I|BOy?*-)SKzX1!Am0?Yn{us(EWJiyS=J38p3d*~nxHgPQBDoY`#@$P;!e0b z7`vFrd|?>V5*>kC#pR8;y-QbC{OFz6w-1#q8Jr(~{dM-C(d)Lp`aG{rp4+z0>;Nx% zpXeHWLpn5NqnMkus@Kq`Aa0>AYOFA-M){cWGvPWuqt?I>N|FP28tHFT>r3u~xgI0C zTRJM~%B6RukHB3>oRCb2i8IK9BstKmLGYz>iTaJWl~K```0A+eyWlYvrvDIn+mu)6 zH{G|nSU1SMz_i?@MooQsy_q}uRJenodfNI(N$-N1j|uIb%=zb*FxYG{l11ej;!_~ zzyMRv#`;cUsB$S2F9aWBjQ-!17T?n&Ip0Ql40RauybEI?8FsNcNt4-)CW^F@{JmDI zU1R{)BOuA?;?1rTNQU^XOQBaJ!=vDLhTR7`^4lT9`Uj9a<_d+Gg0qPYj@e7KcoxS+P6YH*h;vv}qiM*G@b69UKOx`+_D%?c4qE+bk z67<^&J5~_(;Id_2wi}BV#}n;3F6dI6J(57!~;yGzx-zBM4t8 zA2cGU%P53~s5Zzm^irNOaoeda|Lf}$KR^Fi>gAT1Uwe=RzCNmUB+tBk>OWK78&aPW z^Q0xYq)XYcJC~}VWdXL@$@Eq>szW*0e#bGbhydwO6h;eLq-p{ollMv;$}@m+3$iz@ zJ!u2DTy?tCb0|t6e_^@Ezfx&B{dY8`_fzf6A7V;AbrozmnA|6^~p_ItxRkA6%JIbTw$XNob7($HskSNi2ntjA{LpYn6 zvm?A9yh>QboY82sB03lyhKWDABl=$STvUOj%+us;=X&Cqb26t)Q#KWZC;en`ZK zwG(h3+Vi4Y>W&=sHFPd(o^xYQsg7TL;MadhOr2jgY4X{=vzU>$LU>sBtj2xV_xQY?eW%Ga4TBD#(=Njt**J zdpI^|PhLjHf{K9-)7Up;uF+^cxMoSmbXA41a}iW|DPm7KG;Z-dS0mwmt?q$GAAP{` z*7L8ueSG!My47peu3O8W{-@OW7Z&v#`}qFkQ3zqrvT9bHdMfo#4Bo8NUsHdeALhsS zVS!bOv5#Gl!X8p5Z86a)~)e2!zritQ8U?Y+9{i&uGb@(uZHW$%~qp5vjIZFMb?}*+q`7@F@NVU3Kkw3-f;hd+}!zx z_)V$vsV_h#$<~Ly7&*iIZ*0u8xKModQA@yOk5zW8y>Hq0!S*6L2VMdFG{83=Ky+NW zG)Jx8oVYc?&7LqIN3u`OgSjiHYbz=7JKM6d#^ncFCI1dTwEEoc{QO{ESHKbM@&h`S zw(@G~2W<}eO{=MwLXH4eNSi=CF-(I{RAV8gJ zQo_l{N0f%UF7%)UF8N`z+KgugocA}Y5m9k8*TeL!4(1>94`XsbWE99K~uVCPxg;}?GS_!e(LK|y}Ln-AY3AAjzm z^v#Mto+zj>+k;NCkHR|U_Xg^USdDBi?awDLir)anvnjaj<@7ygOGZWp zlA&aTx#IG=xZ?CW`SRH2*sTD9<>n+-nYNntm}IhEB|5y6!b4pMR55H=IcZy1Bx_B4 zd;E^LoE3NG5C&V$$tg)2$n3VXZH#PO&5%v+HXbz!^A-i-l8H+X6IY_$7&GObaN z24>YBC@0famd)qLF;ezCA?o48g5hecUIi62q9`OyITp`Aq^LJXwyl1eS+FXxT@hq> znPm%rB+atb%&KIOR!tbTLXK#LS4jfe=ougX;Q52mn)1@%kzi?gP4wXNAG8&+u2+(Z zHzSH_Mciby$jS43&^Nt?wR~DNttx6_Z>PqaqImjg>ebc7$zxOi!D`~EDA>?m@Uc7* z=kTODys>Im6+&(HmT(9#=JDb2fCBmo@(Sc~Pog#C!H=${t=!&>0BgIhkznjR)}iKf zA(o45R$Skaqf>FpNpRekd%BRD(jvtMMJ&4#jqQ(phEaM}k@oRgkYKFey&2Ao4OA4A2{zVHL zXO+75IP#}dPn&CtjZb*@Y)#Bq*<3%rDUQI1qAC3iEnDUxFqLE};%z?AFJZtZn2=Wq zSosd%T}i{>Q7Nf=&iz&YtFzmz{r$AN15usP|qt zgl-9)R`ii_fw7;$mZazR|M^lZpcKk;kLA9^cz%xY^x=yE=}EO_gJq|M3&C)?ncd*n z=it*Ey^hrmd7qK3F>W_%CtruG$A{%2S@&M9Y? z$*(2WBqom~gdLC`&-M$y2P>9}A&y*WUXtBlr}C22u5e*-<mW_tsmf&p&1a@XcJ5Iphi6(dys4xokf@G58c61Cn zhhd?XQUBeP<#MROt{`s?B3uLZGtg=PQWpr8a;uFBB-eZbTOftD5r=~%5dY!L69h}a zTqL5B0bf|}UGk4mg^i_t^FZq71T;SK#oK0|+o9+jZm;?6Px(*%6VxXEg*N%6P*YQV zAXx$ezbQJiyDK-hyL(2I-;5bx(u){Bt(Qe=Qgd~!9DX!rYCURZ&E`+dT!R0dn~mM& zq?nj>KKU}rA~{NnCLwW}36)$s-qt>rUbQHoyR(h!(ZHo;)f>In>%J4?o`yadr15Gtw<`vn-2s-Pw07zSbZ~hAJ!Ld0KG}decEXU7 z4tM|Lt$q>d{yS9IBi9@Huv30JwRt23X#>KCd|cxfB7d)l9f9u>@>?tVa|^Ka0q8%a z(j6~MEoLP|Q~@L{;3X_CiYxLO#>6$o5LI|it)ah#nZ*`oJcuMv@irtk(Ay05V4JPT zr|*ck4TiFEk5rh|<#RiWB3(M8|8k^Yv*@!(S@6@bgas6wkMm#=XiNJc-+mg@MU)05 z$nU1eUWlNw4gzrjoJGnl&0CJIe{jvS+a^!E?i<4oe*D`DHftJG#uN73{ES)*av9ee+v)BFoCnshd2hk5lK@A6Z&$l4qG}mmXTP{(&Xc z#tSdt`C-t+BCN$aF;`@;BfRrU~;T7}e?^ zre|Xy*%QEp$wamn%`!nmb*$U$BO&eiG}*!)Hby|$aby>xoO&ARYJNtx6r_9a;}@QV zl-eP`bfF{pTXvX8m-=-C3z@`=kkq4&Hxq|&(Sx5-tJ_;G4hN$!rPB`C;mAOTP&I-F z)y!DC1k0|z%jdKE#=={LQmQdF&6o%qOB!sitw9{K5BoWwwX=NX)9d21x;pblM)DUf zUt4?6LF}vbIgKSDqr-zeiv9Hy2sy4t_Ob^>KSz0*MH)oyybiJ{b_^Pa#pIoVQBgmP zT#po#az;gs9nG>xc12Eh#SSEHBx@q7Kk1mmAa@fpP8$-(?1?US=15&@$K<-gL_k`S86*r){2HA|JmiRhx2z##DbIhX?=;T0F4$#S_ zjEkiV0E?EuJMz{1#9&l#R*;lHKqfj1NKFVtg%XiC6%I zd6DE()Uo!2thQDv;m8L~!=@dGrlQVLU$x1{2|}zum^agK@k=v*dH?v{bl)b8e5OtM ze|%NP#J;;8vd;wQ0}1JC>c;Dgw;TDE+}m>bG8l2Rau8epWv`-}vz2fsuW4dDeAj56!J#bo~@- zZFfz^xc=Mb?&{e&ziib)`_#?zDrJ2&#T*^R9EB0Zbho->Nu0IB=fpW;Wm_V1 zB7AKrn^xLe%GVXJhJtAYy#=z#!;Da!6_x>`^)Qm&o@8g(dq~I50+#m9yn#HPmscSL zItGKoNOdO%Lyn-&-wn%H6!_*ummU~jOb84;>0}pV(AF3)g2zCZV?r>A!5Z{ZY(Sb9 zVG|t9axvmT&MlLlY z7o4p3TUs5~0Yq?Iv?`r=0uQ`CxQt!PZb7Cv0eFvamE;BPZiD2l<0#3QibkeNb|nd)G{QAG{n8Y>GHQX1GxwTO?(CuEMe9l6ri znx9{<tm2U7KS zdpx=*oDw^tvi9dQL~H-Kx<(=!H(n!YMY_i8 ze-K@=PFP&2LWtR>HwjSU*k_1##b=~d_>9P4gyI(*jMS=CPu6G`pT8DyeN$0`Q!mZL z{BtRU`Tr;E?`)h7*Qpk>KCI{Byb=k3ZGp^oOChX3mU9s%>JgMdu#7~!+0hO!9EAuu#TX%=%1Oh&PW8B8B>kTePPCEyvF z-`aDzs3B*5>qpf~?;UveYlVPqFPs#~clq+-6|s=DhP_=iao+gQ(B^7BeDDz=dAyNo zdGx()<$B%ChWx=Nckl>KYh7l|w6aB4)3_-X`Xt8f#mE<_4Q6ZD$`ymxz;(V39(7bW zh8;T)*YEI{ItDY&0f3SbWA2V@0Ex0)-C**PuiN7o(>sZeYx^`!O~lOch9D-7kVN5- zB>s&tl5%!Qfcl(GKT@lm7oa4%Br2khl|$D!kXdjbpNL!(mF%zJJpgN5Vm_k>^;d8n zAfYtq*x%(fFa96cOY(23p@Uw9%}Vf-_XTg>1Obw`Nf6wmCYT}FN71?XtY!;K^LMz9 zVG$Gj{Yy1#`2E-_)CR?PNO|Kft5^fO193n!tYkErJ5j`u!R?hc@eFh2deqz?eZR(?zEOZY^vNV`?L*K5>`)?U7_L z5Lj$!N;*GZH@>1W z>zi@mOf4>JM~Wmv7k8x1U}H)PL=^!>BD)9f&7KOn{Ke8s`gUrf*yS6 z&t)}|q)kxti5}<%{l#UMS|95>)!TxyE#h{V^c#)CqH*B5>uR*tFN=rJ+9#geD`<8V zjEI6Ki{eyLd8u}XF`k@@{#;gr3G?$!ZGMo24kP|13NC9klF~WdzC_Q`lsCov5IMhm z@vV_q?qw8>HD|Nfd-9EZ7<3gu>dx|$>@5DXlS=tX=@%#EvnOTeN!|NW#W;B2eQXx5 zVDB9}_W$5}(lhKkN)Dfa`#E03etCtxhGUnN!=>rL9iEY|W8c}c2l&6w@wxZE@^dmi zXI9Sr&FAbR*n6)a>ABY26m(+a{Fa3>x8D(|09DDVGbaPaKlAm(hJyhv`wK9QxwivVR|1CVFi1rLCHL^{MC zKzc#W9s=bFbTxf4|Lg zvs05Zw)NbP{*F$AbVNRc zdiJotN)Ms=EBkC>F%N$;^?hb~daTb}dQM)XghjgsY2J%^ogcy8)SL-ZaA}V7@yc)n zpo|B~QL+%mRws2hGpPO#4_;8%T_~M5iUKC zeq^Nku~MC`h!sJlVs6rha4%YsOQXKDO1cO1hYUvu1h`*;YeuZu*!&uF>7^5$qW(a# z9G<sg7YO`6@Bp$sb*|qGIOJuhc;$gKtJN9*uk=fi9@4P~jgs>(m1!00|FUPP zgVd{0nvhOiELQx;BV~aPJZL^+d|h`&GB_#8zZF?B-!SXGZ2*;(H-C=XXeR03C1HzZ za$MHc=;SIn&&Qv&Z?vZlvz6iRgxM$<1C_zf)9t4vl_{tki{^W}Ns9^4!7 z?{o+95LfL_9m4IY7dbg&eMue4$zh2nJgIxwde0LswwNs*>zFI`Na_)7A9t|>@^<+( z_yg<& zg}@F=hQm&!OW{P1$CNY5dkXO9R=B*d-ijoZS7L5P69j+qQ&a)Nrl%qmqrdVq-$=f4 zJo)m8e--~|j0SoDwsIHl6+rw+GrSZlr0votuK>vWfog|Ad5{88`{-dV5(>P4cP3I| z0s7N;dbgS$%F=)GkN(L??^@{rWqdwRUHJ5LzL2kh%S}c(9;e{0Q)QIrX@>~H#(AcV zG`^^gj2pMovteY(iwj0puJqgx95KC^GXmovM;@bfr+Qx6a%xei)fV?oBz%ubP;f+dQXY+#I^jz0VfP3x*5BHd{tPD3F_Bf3*Cn z=JW^XI`2MP7#}Feu-U`-KwgHO-9Oeu&t;z&Z6Yu1V0ZAF*w&1x8|L+FYR%4W-PAL0 z!_+G&Yqn{v z5o$=j^RB{kDPOv^jEg2b?;;An%Tze)SamV5qy6=+P+4#U7?2M zkBxt1`j2(e#}aB_y$2#T0za((QtPx2=~T#zQzmlMHQ>?b+3eKGlW07GijJGIQ~R2+ z1*K15cRL56UCS@;z^;#4%#Onniac6fvf(hcfB>Uo5H{VzRt0HGXmX)*k}66(XVk7i zypSdcJAdr@;KAT`-}*KWi3?<%m%e!I``;hEl8k)uyzaR2W4+aFKt(-C4*?wf8MbXX z1+1Vf6}-e{C-SpPV&9tKWyV}`J&?d6bMJVv=Z=TvE=D_P@@9UTpyXmbmLURim-4U_ zlP0|)Wq}psAn!=*oFv5q=5rFvGy(m;MIsJ_wx||&yUQX{eV6x>M+6oc8kiUtrci<^ zEjA_6h6u&8rV4x0Cv2rCIEYN*k@9%^oE?~nX7M2b{n!*}z$!G`D2lx$Eg5o0S2VI6S4zJjL{zS5m-Im&V`osx& zyYh5u>LWkAIhADc&GH*0U@`#PC1p7jzy|4^7aC+r-uRii0<1K9s65db9ffHl(;u~iabM(qmC2s3@XhY z=I}T?)p;8! zQSSO1%8P@-+A~&#StJ_3C&lWCC9WmYeDq zY@Cv8Ety>6`zHQXEIGWQb^DSw_czQ1HIs5T3==4ge&=_y-{eoJ$uqLLu4`xJ9SMw^ zG;c!auEYCg^xeC>F48c!zCK!&>)m)m&%VQV8HVpmcoI`8Xy27y{9GBq+FLQ(Ez&|n z1v-K-c_B{y_b=dzWICu4iYN06&7pQ-BfB1FS;=r|X{I#PIK6YYx1v>T?P}f8sYP&UsF+*BP3$(WE!Ry#-S-1=G;v6Nypc zIlKfX(3S@8YH3EGGOMRY z{_Bk0SC3C_(6u~y!G6`!tGZknIbK6vVeZ73tEg&Xe(}U2&)jxvNjyKES0Bf&pCHHU zrj>eA%QmDQy85oWu1@WkWw=_WpWR6*KWKj~gbj2F_SXbpZRV^R$Li!Zc^=AiCK6Vd z*y=4-Yv#l%#_HE+MkQpO4rJ!|{h5@^CX)p=1{;I5(T%aH7{KDqF&2ykWBRgcvqpEnSbSEXuz?1EYLfpLg7v-$33$k&6G+pYHzN4C^RWnG0ntVudBI3=3ya*K82dWou7z&YA zRi=kooik>3I%g7Nb2vJgG?R7C?3^hzW{sFpTN6s?h}YZL-7;>ZRjP1S@Ctgfpm3yd zmVQRiS;3+e6?n6v^i=K39jDahR@U088bYTWFUL>mF!v-3iuwPGu=~>y^~qoQg`xsm zosbE!bC6F-NP}a-;FuqBlrN1X)=SHPng_1-^6br*90q!lB9*hn(-zm&4YntWIu_U0 zUfq#6=s=mi?6NF}GpjU`S(@#zE2Gu1Ac zQ95z>NZ+QTOG*k`7u8wX=R9=&TiW@HloZI-@v!bbsR&uHA9+Q})RqKC$_KELIND8= z={CC~p}fq(s5_UyPh(A9yVYxTIwh-W?GlM*bXKHs4nFU6+HiR(?U~8N^B0h|ryN(+ z<_I^3JHtcan~9DYnL2O5aKRW-}i;@!EfZsFwI=;WOEHD*wV}su1s5pJ>ulk8`sSqmzXuwvSj4&=KR0ZUsW4c zy!7>4B)d=PVk>tYB3k$3;T24%2iex@QScK{Buv{N z5X3`MleeKE6NT*E6(gArD*XgDB4sjnraRN<9m&scHXHhlHK#(MSmR)WyZDqN#$u3$ zOtM8XQV0~K#A-%?1mQVObN2KROh>XfgDJK$O~r`YjWIB2k?OySfqgRy3)J+`{J%@s zFo>~dQvXRQ{q6+*pTwtqygk$~*uLZ1$b?0cTLvO~m!nFS$B>bvX( zC0tyZzo6j4zaePv!@{zH#Z|Hsp%>3Dx@SrC55Cp6e_2h<(gS_nYt(Rtx~6OP+U9V$ zd2RC8?GP{_(aO`5w_#(*Medo~U(6x13{~e=XW)s+7!K!pU2h_zaJIYLEjwhSO)0VG z7Zuox^1mw;u!0=v&Eeb~xjZ+wEU)No?(pO|o1XNQpkBHIL;y*sQF{5Xwo41l-d z$V4e}BEtSp-qO%>5S{@<3)6uq(2j(Ds?i%jeK2H*Qc`KKBSY0VR6vnYS`V@+33D-@ zGQd%vo4>x`Htx0BU8^2?nJZ9mT{gYhq`%|vg}FmtXWy5nvB6^|lhLkAm9n`?ZFX*H zajKZ#oGO2R1i(6VFTjE6?jAoZkOmTL!sr0R1D|#bpKi{=cX#1G*fz z_@S~(X@_1=F7=*@+?~a;vcLc{a4sR&^HygXQh z>+@D;5SQl&9gnR`%nyV%s>=uh#6eFecNr~l!1h87>Yp?^Z8^PV5? zNFtb8(?%m(4|b@kV{`unLSVY4Vqh;~e(oo=-A(8X-6oeN)X zXUS#lNGb^YE858$>(3(>V_G}LOYIb@0d%GFOYKyMrvA21^=RvHF}9-@o3yrG)Y^I& zV?!Nbv^A015(67>Fo!fKu`Y>eeZvSv2QQ5i_knVud>567DRz$hDh@bR+~p@d?@P}) zB$xX+gR#E8Vw@+7p(+h4pyR8Gf^B^N9%;;OZ`e6|_Rfa(?8b=vOLie=@uaE4iQL5S z)JcnT=EAnH`Qmrvxe7{|B4d`_>O3yHoDRu41mhSG$=~g-gsjiXf0X-712-+3x(>&o`NZ)wi$`&8H@|N;1FYAA{ zlr=X0(ejhA^!&eIFb0CTfv;MEFAeES3&K-Z-i&>5MPIIXfq5JoCz3g+0k6e*JVVY# zNOGV$jqN7*5SlOk_zp|fS*>7pp#ot0FdlQ)SDbldoj?@lbZkd!Z39(QiE1-3b zqB2(IwE5f1LP$rC9LYQqX=!M4RCSkyLO1#E_8;}1_P^`@$d5FxMa?M0ke3(j0yc)A zKSFpy$VnAsPhp_=1T}jIoC2W<(I@yN>5_mbqYT-P5>r5*X%R^%CQD*IiV%P)qbQ4( zR#RDGwEJv1>+gMe{i^*73c|H>t~+w|(j$400PZ=EJ#|u3sG#hoj_psaDESw2N%O4I zNvmg1DDZ@7T)Q?_Ew>WUpd+CQ^-&EDw~?%sdv%H}0Kp@y9A{@CKlbln>$ zn1A1QQuijN)kUj%)^FNWQL}JL{*p(}lH6p4JbFfVGvX87$VWcwAJu8K{B4oen-J^G zFI8$){(hxa4WdX1{{OElwYqXL+?;tbbDUbG*3Ztn@0EXBHZY4SwaywSyYLeB@~Tw5 zf;z46K(we9LoWd#VC_XM8rYu@`Y50f0bhuq5OS}g`j8(0Rg|^FC~$QM_oJvqBys`> zLmQ+rMBhAG{2>i@pqVEwPZpv?^2i}Dj%kR{Dlgs70MY!6d%!CMK19D%fH zTnGrb3!ud>SECf^Br;5S6bf!y$W%*SyQoKLgoRsXNVN&qbY(LNQKrjKYF*MyWWohO zL0=N#_R^Io;VJcH@a@U_l*t#KM^Wad*O5Sv-)r{k~ADff3M|(%6$Hxu)79T zD~zt1L-$$s0;m~6gcFAVIo7Y0f5Qjw(QF!5)DI8B29IVW1)d=aUu{N9G(2<`DN8Qd z<4G|Xs~?Up%)0oW$_@G+*v@+p*DEpMu`Na=<>^c|k>giiq+fudTYL1154cWBzlG#> zr~}MT=yZmVo_tWvkaft_4o4L1(x{I$8b#FKuZuHC&B#j3_pDC+_7t=KC;P_Db~$)$ za+dBk!iqS&oVXUeiE^0b=Xn$xK7J%pz(`Zq@`YLtK0}~>XXU-{aUeQsM`cc!0 ziqhqi^P5Tnp^~Q5?vfQ#@+K4qe2IyL6ISwBv-Yi?c*}jw%i9a;mhPY5eb>qfw;i0g zyrZyg+1*dwxO2x2=>D~}eJurFXiuy9TZ(R^Gl7Yi|HI1nz%M*6@#8vLE-aP6RDe36 z(16ibFH-d9A5y+|{t&=1_|8KYQ%Z$m1a6^Djf+>xu}|RY15g#GiK~P zvneHUzWBkl_2bt*1Q3(x$H%F9`B%E%fF|GvrHUj8ldQ||W#nZ53#$Km0O=}4F{(gr zp7dxebwXwXXS$Hr{zu$cqhiI zCKWg;dvBPYGu`iQ(#S_HMD^rVn7q=Agm^3xkK+lLl1uN_i`RZvzN^-?+;zX}NtZq<-inDwD}At)K4=rK z3$j}4oG>d^KAYdD0-xDPsFudM__ISLtVDJD+MOlQ5?-QzHsYW^JLu02OZeGlVgXo- zs$UitSHcE^t*<>L1B~-WIN*!P3yOkE!Wqh7^-bsFfaFTk0=Z0Bfg!2MGHf%r(Cl6Q zA*g6svfS5lpkvaS()>vi#z!i5ch9`HRWT^O%BreB%l7K*2~AUj>1*MYA1vyeIX#a) z$3HI)`vX>g%(p+Uyd(tIlEG;=Ru$jp&-NHozo|^z8;E+0CE-BO8i@M#<(JvKVH&8r+I|UPkqE<2ie+# zEI0LwgQI0zwJfJX&Om9{KZ%p;-_13Yj8JL9ZWxDtDj54DF z#xu-!P#RPR??k#r8GsSgcc)*s@V}x)kRZknfBMF4O0koP$M1@3u=uv(@3KlTUQZ1w zA~ONn!ijg`NxAnz22Q>$XW1P`kmBU22mW~A0MP;12>L(ovi_r-5jrgTFX_F6r_?Fv zKi6@s|BBA5Ako?t1JKiXHmvLbSXg!_#PcxT_as)1QxpOU`c4#3by@eniz#;go&Hy0 z?(68}XJYy{q3=&>Q~$>Y*nBqsNb1_N$vva}-;4fFRvKY(Gy!!JQjV*7%MM+d%XSzS zATaI(*FkOg$HGKYD;Ph-_FjY)Z{I5xWqQ3 zsF)4I8jmRRAY169LN%xu*fW%<7A*K#2autkA`~52*ocbIINg9`4Vb$SV#@UQG7>ma zJ$#}jbMUO>1DL$0aYhuY;Wci`A}233Q;fMh1f_3>)WN(CKupTZ&z@!F$?!V>Uf=|U z^HxLJ`^eXn1`zWT2l8fYo*kW75vhz96h|`rp?JWOe87;k>eQ_>-LZg0Z;q9tbdtFJ0sYgTe@5dHb4qRNq=*Wc%b;A;DJhVv^qfRDAXkRC1^G(ptNfMZ z2M73T2hMBQ!;7EOy~Ou}rzH8JBBw6(j=qfJ5WRz_Z04^VKnK70rGnMOeQ8XXPo0!` zN|p`$q7EBhdVyaMeFZI~Z!3fa^q3bW+w@Og@EjmqCodM`(@DWox{JWGeL>%S4&N0W zCU`X6vkLbtqduJ%zNlxqlya$& zN@_%#1X^A(h03pJ^0CV2*NbMfxe)Ux+R^LL4p`(Dx=Za4bo^2~m=qviX<7=!#L$FZ z>JR3|A|+G@C6zW^wN)14EIYW@?_`SW{{f7($ByDI%E> zn}X}n?1<@t5xaxJ`N?IDPHJ=}mKFwnm-4gJooGsIF6Ex{>veJ1S45lWrw%JqrP@(k z&1Sx6Q7%%Xz6q_qs83o(H>~KdmMwseWHFc8zD+-_me(b7F&A8iJE7lSd{Y^su8-2R zn2&tbWVpz2{2Nl*BAwS3DJd2Svw?Os+OC1bA$B(Q2X;5xg5G~oB!8H0PhJAPV3P7x z$Jj(jm;wF&F78X<+bXWTXGZr*wj}R%>^OET?{>UMwrtCGoLJtS4JWp5PI{(5@I6 zSb0=vLZHq>=W&`idlP$a?}TCR_!td>jHP{Ns}#Pd%#VUE@*L38(AJtX87D4G7J^rt zM;Kzt<-8&^k#O4J!!9(wf!`qN5Qhwmq8fZ|GAWbOL3TDmArhz=aAt%GD6B(}p2Fk= zpI=?c&~^$>P}{D^8IOM9(g0S9h)JG^_{NN^Qk7jy49c{{ zjpX98ji4$qJBaC!PtVe&Vv2w;BY2M1Zq?3cy>T*<(^wQH9UXKN$fMEYqSYeCOjGlZ z(rSYFpxp$A;PVg&EkUp#bQSL=PHONG+`h=Pa^LEzVe z9Eu#%LDpM$?fi|$W+CJd85IQ9e}kDL^)LniSq zhPDfrL#CLtAi5BC!KtNF%9N#wB!XFsb`xdi<1z;JBe78iLmYZ1TBpz(+*FVQF=LT@ zmOZ4G#!V`@p&|+w)T*NJY@8;D`cQ1ng4}q6DHO-#u?)-#f8zC$-&W)UMb=Phg0~wN zWiXqm?KZB7MtrWcpVw|eJQD3Dq#0HE(A9vLg#;pGPccV`cH@h*lX@Ax`e0RI(4C14 zm%FAIS*YClP|!OCb*6~TnK#OW=JuZwnz(dpt8t_Ig@ld_q&ThzER?=!Hs(A1%v zB_U=zb(kuHQxF}mj^GaCV=C26TrZshk9cvf?iCOn*xorZAUvEq6Jp?XEGjY%BQ_rH zfH7jtVup>B$6|#*7)3#PTp(11LQIB$R5k%35yF8e2A>6AY0uA9YS+Jc~XH?ii~!0CZN6HHHA^jr>QnxH7>ZXa0xs z@a7M($+tmAyc1Mb$;B<{hj>xI{3`KrFUr8_Hx70Ri=2E#YC4OZgz;-+qJA=&3m!POh=qzqfn$3VNu_MjPii0Wl7%Q-?Jv<+ zXP!_fT`&sH|FGJ|0@5+TpP~=)D~P|?wB_$EnQ@uYu`#HJAw`vv7InfE${)T}RxoC)o&x_W`m6b|pK>Zk)$;9l4SI z)8Xj6)@9q}p(9l1#F6UxZOeDy6rGt>7hNm&i8!wz!_je_?2Vr__u@3vQI%es93-4tV|27M5Dxd6m3@-;LJIuy^f|H%=>UTzk2^ znMWCutxfB8%UitejYp_-xWBijf8DC(9PD1bqPt^37Y7$FY+u||-^RgaXI=Abhn<7A z>I$2+D4&Bl#RWOp88bMTVo6I$PQaus9X2P%n&Ik)g9J=__s$&vo#|V5U9z>mdvUWZ zC&f&*ZYAcF99#3^?tbGH!Qla~fDT-L^%dw{F@DqmoD5yX&<8q7(D(x3 z{*MA`O}2lQT(10L$&zD_O9sm1@(TuKwm9hb=Bi)$zX=<@C4F*Oe0ZAhcvxg;`G&(@ zFTF$gj^EzbNAFO+W0T(-opkGxc## zfjuhh;-B?v`DeX=l_ZAG#KSaOTw<(aiw@)LbuoVbSH>B3&GB~{V9--Kqkl)Jcy!6pC@}EWO53;*<9vG89FxGCk`zVb^YWNa7_=air#-ALa z2}u1$-m=RNPso1}sXxkJzWcFB`J?E$Lw6j7H*1-^g4D0Z)cfx|LX!{4ug<#oswa+O z>X*qUxbe55ReO%&!9()j;u}Y9IZ9J;$>ZnIYJH24Egi7PrUWP8y~&;w--PE{Kdb$`q3L7ymjJj<8M;uZ-4OLJB8gZMo?P%|OwA^P3l6ed8_pZO#E=jz9bSORv2tAOGcn z$BsTDKP2KFc=(ZnN1l`)xarnAe{!#k#zeaPKe+j}yY7+q@7%rTx*KJ|Jz}Z!l4Z`UoF*bgm}3)V^7Yu{lf3Uyo45o5^-vOe-CqDS-Z=cKWHpEVm z4&H*Hfq)&ESei&vXd14?>r)sHf-}$%hx^Yt(FNJl1tTxS-pt6Kh4M7q$=+hJp3CoK-dHj zngPP21ROp~^oTh@`B7#GF;%E@g%Tf*K%F;~jMdpgxsN%dTF8rh4rw9t;Pqz-S&GwL z)({u*5FZ&Nn_yqOjeL(>My@2+knfYdPSn?>jBOz}aJr zPUSBPHtv1s3;9(M_fmWR)ero;{L;*x9s5qozZP-N&G2md>4)-j9scWn`KkPdhYYD+Pku_oJ)PmYABaQe)EarhaU$MOK}4ig+m{2pY{hC zUHgpP7K#q%&T8B^ShfP5ea%blmLR@Jv4K@_z&aEzg|CaqG#fL<$o;z{f5xpXBBQeHBUSny7QY5(9<(Mp3rlYxMNc9#EP7ythaOfQH9RSDhcXIB^4WW0jq-iIuY^MAxDKd5ws7Juj&EWy zT`wGZK!2aKN-wZ1l;iyRM@UbNHLX(O5R)cAwr4@j=D zE2K-5vl~5*rAPh1Qp|(FI*QVS@=Rwl%wOsHP#roJwFcQioK0;vGjJWFcbS1wp^C2w^lTohJ}umXlB;YrUeFmE3^M6ZN5 zs!b4k-8} z<50MKXz?51J~kOHCLL9}wYj;u%j}*7*}3iW`@C)Q7uxNut#%N5dwZFkeXnv^F7D(m ztL$r^Kfle(@7P;gs>;gvvMtDT24T{#q}!nLR03O2?lIsQ=lmJPMa3J7cN9y$qHRUY zm%lBa&B!at+nBc_PfEN$(K&c5C@Q69(0hVTTPZ2WVpQFVl=qf9YDON^G##nQQ>%mF97 z+?OTjJ});6rc(xMf-+{zS~zg|Elall{+`tewB(k{2Nuq%@4WGufq|!Q?CiYp>4AY~ zZtVQDFg<8!5qoKqZMn^3jL)7;dz2nHaF6cnrP`TceUQV?@2 zVOWb5bRlGg6aSWC%bz|y-NAW|MvqSOZeODsR8A!O>OwsUSG2omStfIRhb7#wO>RmD92TiTTt zg(@7@j-`o}i~5?Hakz3q?NpO~OFRBGy)cAAgcEy0%~cj^K;CYQq)uKXJu1z_Dt{BX z@v)UwpLLs6mjmPd128JUX?S12s5!2ErP*iRX4b)0pB^kKD3EFaJQmCSlO&`W06U{I zxbm$NF06*3R9gw|e=s90EunyuFkDYj<}^ve*vK)&W)xBEDR3Xi*sS3T-q@{CHg3dz z65mr36b$Xehb|gdlp08@aW+~Z_k6*~Qu>3OQJMb$!CphxOIdY-1#Gn*@ za(_WjReROCg8S_ES!T(9{i{670*mjf=?}6Az6ZT1{(;O3>5pBhJ zf^iW9{g2~_$xKiSmkJ`{+Kig)OVftC!bV@*9_ybw{r6{HA$~9%8)@}9W;k7QWZxgjHTXSVsN|7aDX5$9wq2iXVyzJJw6>$+6O|H6c zuY8@WDI)^9%dOdYT`k4DZzm_wxBa9Lx@4)5dHf9DSRDVDQ50)*;z;6Q99kqBV|Xpm ze_&cd{aGAkGc_h*Xeexl#Mq41C9#FJ`6~)5md(vBYFSZY?QXV5>!a<>-PV#7Ek)UL zmsJ$3oNuGnq2Q*n`fZ!~OKMj;vvTXZtneF`o8??xThhO2TYcH4;E54_?NLoyj_9?ymGm?o6A^h@D}Z zp_>tr76s>FR{JsGyX@GSW96yur5;0{bF)k2t(fX4uK2huN*uRHR;V6F>t+{bI@${g zogI0ZwZ+r(>n|!ut(cZ4&u%H2Tab{Lk%PMB1sZDCFRF|he=v7$aY~$}G(D@XB-Lcr zHJ5E|E$&{n%3iv-!5$}g)bQl*a9+l4^kWIR%Got5HmfL?TlGgpWu&4aS+Q9x>l#>y z&$@aR_0FQ*I6wCq$k0XkMKr01N|>y2wv}8{!b-BYWbesl%V6i0LyX3ZYha+0lT;6q zz+{G+a+A|za6brI;Qu0212MquRy2ei#`eDZF*rC6MiECr7Cbh`*NPtAu^BM&q!wen$B zMB&FINk`x9c;TUmm67~O104(YUc0=2?bpq;&nqpRhdcXO!SZXRNAg;FYKm&J zqNB5Fi)wmW@_2crJ?wMPm`n;EWmjP%(&UWplQ+v($vSyAXI>0t|CP+M2Rc4Y$l92M7-%!&7MsRb3M z1pVE!95VyY2y8$ z+B-rBgcrDSu5kokgAfO}Sm1#CkVNP0iNejOcpH2#Z40tR8yQW_Nj7dV&nV6u4{Q`| zaE2|?N%9h6AsvsCBzTCjpb;}Nl21iMkgVvFII(0V-lVt@+B$ylqvEnNx+~ zM8S!kD|`v_XHghZlu$WWR^D_B`Fy_PMChgh4MN% z$rtdRPm4{1tAiajnsq8W+gNfcEd_r@aw^Vr$`}_{*};!9iUmWnr6fPF%;ZPpq)f;DdEVCSB!W1^Ko3<bPsRq2Jf&CaUAl1BX=Lviy` zTkZ1N^rn{11-jI#uA21Rx`p{sb#v+(a;>Sx!J5WOm|UBy7FVTaIOfl4T$;+_d-*%t z3v7X|67*!m%)iDN4+li_WW2tIaf3V^W7DyrlkBuePPng9Od^SNIzo<#%ZRha{Uq)g z%sFw?q<@0Ofi}6LOYWc!%#52#;2_h`g&;M&O+XWrQyC8PFz7Pl>R1&!x^vihoo zf9R7^k`0ezr;vTRZ=aifHDUJ9KSpL`S)f-&p}ZNSPw^94jBaGy zkJj|mX^AJ3lH_QdBz`J7I#Yj=$g%Jwp88=@QXG7TMo#~58V1Fo$kRG_cUAk0A3lXb zqT2-P;2^XRMGUux6#c{(@@R!z~o`k6E7;Z1K_W?YJ@fR~)bIMSgm(a?fVluzpQ zW^&R5&!*;BSfLX0hf%y)u^GsnIr8@8#o}KKTS$P}SaO5Yl}w$k$z7juWmc2hIkBA? zq?2pzxMiPb?Y+0(-o1(EqoZ-msndi03wEZ<*rMP`6EFsN%DlC&|IEhv8=m9%a*g&@H>Qp#_B?m)_bY2u*i1^LcT_lv_~nmOIGW7W{~l5pm9QvGp2b&zDPEJaRhVHNw@Za} zq=If#VF_utZ6bdb)_n9+71on9HeH1c4zPzg%l7sGbqk+Fik7%e*0Xsik3H zz#pNtbXC%PuP*!Sll;ZkA z$S+W5rOFpd{6FnkPEoueIei30$rT#(iRNF5Qg;dZTa0Gr_lNMy>4-P41@v`3Ep>pF z`hbsj!cG_M~67;6~)!QgPM)w*TNmQt5W#%`3N)a@VScSWxM zeY8Pvt6`Lu4Ui2F8LEa}E=O6~&f0}i0+pwqC6YzP5K=P&i!9k?w1gwlr&a^lI zjS50i#;HOO-!@iTMY9D_01L7X$HN&V$H$vFRNa8uj(s8@rMHGrd_RcIgE9nB4Ib+i zZS4aS^Z^PlA170O_d%6>K_UQECWiKVoSi|vGA@7 zpzr!Ty&#(55&s5{J6P%;@mja|Hu|gzKHrcRP>B0+ENVVeo%{c#w*S+@a~WKGCbIcj ziaM_=QR0{F6S3Shpt5g_VJCdt}x^D&1gs)I!Jc$*xgIS+xRrTJB_!~RIJFP zk#s6SQnrvxl0~xNKQ))+!49KdE(^Pkc2r&i@3( z-@D0!&>#Ggd_{f=UBj25h5idnjBXr&)(d@f4|$2a0v<>^9pZ+E^5Pu0` z{Q{bbe;~)9jo1%O_0OQYxB+CnQH<3gat{c86UH=vKgv?(PW%VKvyspDi-n3ekag-PlR40#Ys@f(D$28 zQ=tW)1}(>#aI<2endBejKWG-sra3g1=FxmwKnv+Cio?`t2^=U|sg0Jw^5|_^jsp=Y zXeF(p4q8oXXf51n)zLXv=d7nroCx;;ZGdCVCfZC}Xe(`_?Q|ZU4~JU|=^~ut)d4?; zzoLuj5_mG{qTO^UT}GGF6?7$Z^v{yh zz!-Si3^@_H5BL$8MWv}@^g^m_Vz@&LU7zT|#D_tGEIo9NB- zNAwnYE4_{0PVb<1(!1!7>D_Qsa}W6m-A8{)@1^_cee`Gae)<6YIem~mL?5RAM1KJ{ zHjmI>VbA+kdH}m$hsd4uFntWB!jID@=u!G4eTqJfL+PHSzoyU8-_Ymj3-q`2Mfwtb z8RxyeN?*h2X0O8$&YSd~>F?-U^f>)J{R4fQzC-^A-{$YaCCdBsPxJ&mNl(!~(+}ur z`XT)b{fK@{|4Kihf1{t$&*;Cvjm{VJU+KTmztb=2ztgYi*YqFsKj;}c2EC+lIswae zg2BqYok{Q@1Mg=n0!MlonF+pyqF6MGfg_bT7S9q`B1^*2S;;H~2Y#ip87z&Z!@oub zv#?B-#j;rr%Vl{iA1)sX*(~_ZC}t(Blv&B6@V8-OW#lkyG@fVWO% z@3BkSPOLaw#x7^O*%j=t$_ zyN%t>?qGMayV#G}-Rvjq9=4DDl-N`@X07+bWbjhHJ{ zoQ4*)7#=0mwwah*xWb@`T-v-nCDZHi)Q?PkKSV7Di zzj5Im@py&?Aldrd`h_m{Xwah{5P^ANc)EeG3;jZ+fd)h%Eky050sQDMQl1}Dp1&yU z5%W;kh5jPt`5~o&hg`${KybuA-0#t~40&~)A+MoBt-N2Ye1}qbzX+l_`bUSnu94Bf z0oQ0S${&8E?^Mb#qLiUCEL-zP*oD4RDZ_{obSX~-L}2QgYC2P33O09#AutESF7(|B znxF`zZr-Iq-la>GE*(|6bg5daQMFb}m0FF8Kwdfm8BNB!!;m*>X?UHYM#HZROVzF) zRYKG9sS=vDguyGr;B8Z|{$i!B+eKi!SfgFzb`6vV{6pS=v4NLGN#@c(Lqm&*GPpb< zG<5_9T!DTC_D{j)uCN9&2f{7{cPKAwP{T$gY^sricqI=+_4@Gc6~HSPzcMxq4EMVP z80i}F2R#EGpUd1b9PputB08casNSE45iO$39fLkT`jv~NVTp|$gC4JvD9(rE-^fcA zc}b0)pi6FZVHg|Ke58vJr9(b)cRwJBXCyCh4G+68WCqvwy4a#ocF`zX;RE4{oY`WZ zuCw1Sclo@7E?u{4)S#9^x47S@Yr=PNz-Q)oLM4b%6NIjfF0JBbPgo5iPynSlc=-jC zII7$aJt`t)@w~Ji$z?CEjNI!P2)Ya^E@?Y%==e>%U!Y1HnY>X{X+Wvc&?wvLGx(MI z=tlbedc1`Vy2@k`=z^$|ny+pc^>O2iV#t2pz-EpvRGgS|if2}FD!rrL6c2hu0Efy%w{XMhoH(b4Jy~5sk;?gT%`t8X^=yMsx_!41XXFdRh6mvH*5Dod6iXY zc*`_wWg50J4O_W}tz0W{c?gTGTq|d}hOb;JXSs&CT*F+hVYX|S?HXpghS{#Qg4+2YO3|iy(2D2 zeOr`ZxtJ>STSO4KJj5mF zQA`h9yd1&eiGI*G#ATU)$L$~Ljr44FgRLQzg3T@@S8PxTNwwVOXq5(hBQE_g)||l% zTSiCxqT*F$XU%qAY|* zM2NgXMXk^hhcH)!%2N?4Pell`s1|>`QmdebN5o(%T|eM=Z#1A!c_=Ga1AR(35>&5) z5VU$dviLRhZWLi;pKo9QBf!5^-;Ty{*!AsY)s+=WP+4YFZjXQr48akf%R4%(gd^&8 z?~rmm(5L58;($jyk7>j=w0Zp~PzO1r+%o!yJws|_V9*Ehb-6vDv(4ItE-*Tz@5AfY zfJfp#a$p!GmfQoQ>*aor3z_!%T!R>sroqvGN_(E@FjyU=t&KJ@2_r0z6$3p?f{b!w z8)*QGph9wv6;gND?YJ;_giA@D2#B@=oby!_wSWl!luLXO9h>ONI1#5_Wr4kEX>>m6|;);m- aJdFa8m#^_-H;0g?HeZv&!&iQi?*6|EVpiq= literal 0 HcmV?d00001 diff --git a/project.4coder b/project.4coder new file mode 100644 index 00000000..33fbb625 --- /dev/null +++ b/project.4coder @@ -0,0 +1,118 @@ +version(2); +project_name = "The RAD Debugger"; + +indent_width = "2"; +default_tab_width = "2"; + +patterns = +{ + "*.c", + "*.cpp", + "*.h", + "*.inc", + "*.hpp", + "*.bat", + "*.sh", + "*.4coder", + "*.glsl", + "*.bfs", + "*.html", + "*.txt", + "*.ds", + "*.md", + "*.mc", + "*.asm", +}; + +blacklist_patterns = +{ + ".*", + "metagen_base_*", + "metagen_os_*", +}; + +paths = +{ + { .path = ".", .recursive = false, .relative = true, }, + { .path = "src", .recursive = true , .relative = true, }, + { .path = "local", .recursive = true , .relative = true, }, +}; + +load_paths = +{ + .win = paths, + .linux = paths, +}; + +commands = +{ + .rjf_f1 = + { + .win = "build raddbg telemetry", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .rjf_f3 = + { + .win = "pushd build && raddbg.exe && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_raddbg = + { + .win = "build raddbg", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_raddbg_from_pdb = + { + .win = "build raddbg_from_pdb", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_mule_main = + { + .win = "build mule_main", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .run_raddbg = + { + .win = "pushd build && raddbg.exe && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, +}; + +fkey_command = +{ + .F1 = "build_raddbg", + .F3 = "run_raddbg", +}; + +fkey_command_override = +{ + .rjf = + { + .F1 = "rjf_f1", + .F3 = "rjf_f3", + }, +}; diff --git a/src/base/base_arena.c b/src/base/base_arena.c new file mode 100644 index 00000000..d7297f71 --- /dev/null +++ b/src/base/base_arena.c @@ -0,0 +1,316 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// Implementation + +internal Arena * +arena_alloc__sized(U64 init_res, U64 init_cmt) +{ + ProfBeginFunction(); + Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res); + + void *memory; + U64 res; + U64 cmt; + + B32 large_pages = os_large_pages_enabled(); + if (large_pages) { + U64 page_size = os_large_page_size(); + res = AlignPow2(init_res, page_size); + +#if OS_WINDOWS + cmt = res; +#else + cmt AlignPow2(init_cmt, page_size); +#endif + + memory = os_reserve_large(res); + if (!os_commit_large(memory, cmt)) { + memory = 0; + os_release(memory, res); + } + } else { + U64 page_size = os_page_size(); + res = AlignPow2(init_res, page_size); + cmt = AlignPow2(init_cmt, page_size); + + memory = os_reserve(res); + if (!os_commit(memory, cmt)) { + memory = 0; + os_release(memory, res); + } + } + Assert(memory); + + AsanPoisonMemoryRegion(memory, cmt); + AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE); + + Arena *arena = (Arena*)memory; + if (arena) { + arena->prev = 0; + arena->current = arena; + arena->base_pos = 0; + arena->pos = ARENA_HEADER_SIZE; + arena->cmt = cmt; + arena->res = res; + arena->align = 8; +#if ENABLE_DEV + arena->dev = 0; +#endif + arena->grow = 1; + arena->large_pages = large_pages; + } + + ProfEnd(); + return arena; +} + +internal Arena * +arena_alloc(void) +{ + ProfBeginFunction(); + + U64 init_res, init_cmt; + if (os_large_pages_enabled()) { + init_res = ARENA_RESERVE_SIZE_LARGE_PAGES; + init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES; + } else { + init_res = ARENA_RESERVE_SIZE; + init_cmt = ARENA_COMMIT_SIZE; + } + + Arena *arena = arena_alloc__sized(init_res, init_cmt); + + ProfEnd(); + return arena; +} + +internal void +arena_release(Arena *arena) +{ + for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) { + prev = node->prev; + os_release(node, node->res); + } +} + +internal U64 +arena_huge_push_threshold(void) +{ + U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE; + U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1; + return threshold; +} + +internal void * +arena_push__impl(Arena *arena, U64 size) +{ + Arena *current = arena->current; + U64 pos_mem = AlignPow2(current->pos, arena->align); + U64 pos_new = pos_mem + size; + + if (current->res < pos_new && arena->grow) { + Arena *new_block; + + // normal growth path + if (size < arena_huge_push_threshold()) { + new_block = arena_alloc(); + } + // huge growth path + else { + U64 new_block_size = size + ARENA_HEADER_SIZE; + new_block = arena_alloc__sized(new_block_size, new_block_size); + } + + if (new_block) { + new_block->base_pos = current->base_pos + current->res; + SLLStackPush_N(arena->current, new_block, prev); + + current = new_block; + pos_mem = AlignPow2(current->pos, current->align); + pos_new = pos_mem + size; + } + } + + if (current->cmt < pos_new) { + U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size; + B32 is_cmt_ok; + + if (current->large_pages) { + cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES); + cmt_new_clamped = ClampTop(cmt_new_aligned, current->res); + cmt_new_size = cmt_new_clamped - current->cmt; + is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size); + } else { + cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE); + cmt_new_clamped = ClampTop(cmt_new_aligned, current->res); + cmt_new_size = cmt_new_clamped - current->cmt; + is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size); + } + Assert(is_cmt_ok); + + if (is_cmt_ok) { + current->cmt = cmt_new_clamped; + } + } + + void *memory = 0; + + if (current->cmt >= pos_new) { + memory = (U8*)current + pos_mem; + current->pos = pos_new; + AsanUnpoisonMemoryRegion(memory, size); + } + +#if OS_FEATURE_GRAPHICAL + if(Unlikely(memory == 0)) + { + os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure.")); + os_exit_process(1); + } +#endif + + return memory; +} + +internal U64 +arena_pos(Arena *arena) +{ + Arena *current = arena->current; + U64 pos = current->base_pos + current->pos; + return pos; +} + +internal void +arena_pop_to(Arena *arena, U64 big_pos_unclamped) +{ + U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped); + + // unroll the chain + Arena *current = arena->current; + for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) { + prev = current->prev; + os_release(current, current->res); + } + AssertAlways(current); + arena->current = current; + + // compute arena-relative position + U64 new_pos = big_pos - current->base_pos; + AssertAlways(new_pos <= current->pos); + + // poison popped memory block + AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos)); + + // update position + current->pos = new_pos; +} + +internal void +arena_absorb(Arena *arena, Arena *sub) +{ +#if ENABLE_DEV + arena_annotate_absorb__dev(arena, sub); +#endif + + // base adjustment + Arena *current = arena->current; + U64 base_adjust = current->base_pos + current->res; + for (Arena *node = sub->current; node != 0; node = node->prev) { + node->base_pos += base_adjust; + } + + // attach sub to arena + sub->prev = arena->current; + arena->current = sub->current; + sub->current = sub; +} + +//////////////////////////////// +// Wrappers + +internal void * +arena_push(Arena *arena, U64 size) +{ + void *memory = arena_push__impl(arena, size); +#if ENABLE_DEV + arena_annotate_push__dev(arena, size, memory); +#endif + return memory; +} + +internal void * +arena_push_contiguous(Arena *arena, U64 size) +{ + B32 restore = arena->grow; + arena->grow = 0; + void *memory = arena_push(arena, size); + arena->grow = restore; +#if ENABLE_DEV + arena_annotate_push__dev(arena, size, memory); +#endif + return memory; +} + +internal void +arena_push_align(Arena *arena, U64 align) +{ + Assert(IsPow2(align)); + U64 amt = AlignPadPow2(arena->pos, align); + void *ptr = arena_push(arena, amt); + MemoryZero(ptr, amt); +} + +internal void +arena_put_back(Arena *arena, U64 amt) +{ + U64 pos_old = arena_pos(arena); + U64 pos_new = pos_old; + if (amt < pos_old) { + pos_new = pos_old - amt; + } + arena_pop_to(arena, pos_new); +} + +internal void +arena_clear(Arena *arena) +{ + arena_pop_to(arena, 0); +} + +internal Temp +temp_begin(Arena *arena) +{ + U64 pos = arena_pos(arena); + Temp temp = {arena, pos}; + return temp; +} + +internal void +temp_end(Temp temp) +{ + arena_pop_to(temp.arena, temp.pos); +} + +//////////////////////////////// +//~ NOTE(allen): "Mini-Arena" Helper + +internal B32 +ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){ + B32 result = 0; + U8 *cmt = (U8*)*cmtptr; + if (cmt < (U8*)pos){ + U64 cmt_size_raw = (U8*)pos - cmt; + U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size); + if (os_commit(cmt, cmt_size)){ + *cmtptr = cmt + cmt_size; + result = 1; + } + } + else{ + result = 1; + } + return(result); +} + diff --git a/src/base/base_arena.h b/src/base/base_arena.h new file mode 100644 index 00000000..0a9ca92f --- /dev/null +++ b/src/base/base_arena.h @@ -0,0 +1,94 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_ARENA_H +#define BASE_ARENA_H + +//////////////////////////////// +//~ rjf: Constants + +#define ARENA_HEADER_SIZE 128 + +#ifndef ARENA_RESERVE_SIZE +# define ARENA_RESERVE_SIZE MB(64) +#endif +#ifndef ARENA_COMMIT_SIZE +# define ARENA_COMMIT_SIZE KB(64) +#endif + +#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES +# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8) +#endif +#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES +# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2) +#endif + +//////////////////////////////// +//~ rjf: Arena Types + +typedef struct Arena Arena; +struct Arena +{ + struct Arena *prev; + struct Arena *current; + U64 base_pos; + U64 pos; + U64 cmt; + U64 res; + U64 align; + struct ArenaDev *dev; + B8 grow; + B8 large_pages; +}; + +typedef struct Temp Temp; +struct Temp +{ + Arena *arena; + U64 pos; +}; + +//////////////////////////////// +// Implementation + +internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt); + +internal Arena* arena_alloc(void); +internal void arena_release(Arena *arena); + +internal void* arena_push__impl(Arena *arena, U64 size); +internal U64 arena_pos(Arena *arena); +internal void arena_pop_to(Arena *arena, U64 pos); + +internal void arena_absorb(Arena *arena, Arena *sub); + +//////////////////////////////// +// Wrappers + +internal void* arena_push(Arena *arena, U64 size); +internal void* arena_push_contiguous(Arena *arena, U64 size); +internal void arena_clear(Arena *arena); +internal void arena_push_align(Arena *arena, U64 align); +internal void arena_put_back(Arena *arena, U64 amt); + +internal Temp temp_begin(Arena *arena); +internal void temp_end(Temp temp); + +//////////////////////////////// +//~ NOTE(allen): "Mini-Arena" Helper + +internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size); + +//////////////////////////////// +//~ NOTE(allen): Main API Macros + +#if !ENABLE_DEV +# define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) +#else +# define push_array_no_zero(a,T,c) (tctx_write_this_srcloc(), (T*)arena_push((a), sizeof(T)*(c))) +#endif +#define push_array_no_zero__no_annotation(a,T,c) (T*)arena_push__impl((a), sizeof(T)*(c)) + +#define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c)) + +#endif // BASE_ARENA_H diff --git a/src/base/base_arena_dev.c b/src/base/base_arena_dev.c new file mode 100644 index 00000000..94c334bd --- /dev/null +++ b/src/base/base_arena_dev.c @@ -0,0 +1,197 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Dev Arena + +#if ENABLE_DEV + +internal void +arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){ + ArenaDev *dev = arena->dev; + if (dev != 0 && ptr != 0){ + //- read location + char *file_name = 0; + U64 line_number = 0; + tctx_read_srcloc(&file_name, &line_number); + tctx_write_srcloc(0, 0); + + //- profile + ArenaProf *prof = dev->prof; + if (prof != 0){ + // c string -> string + String8 file_name_str = str8_lit("(null)"); + if (file_name != 0){ + file_name_str = str8_cstring(file_name); + } + // record + arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1); + } + } +} + +internal void +arena_annotate_absorb__dev(Arena *arena, Arena *sub){ + ArenaDev *dev = arena->dev; + ArenaDev *sub_dev = sub->dev; + if (dev != 0 && sub_dev != 0){ + //- merge profiles + ArenaProf *prof = dev->prof; + ArenaProf *sub_prof = sub_dev->prof; + if (prof != 0 && sub_prof != 0){ + for (ArenaProfNode *sub_node = sub_prof->first; + sub_node != 0; + sub_node = sub_node->next){ + arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line, + sub_node->size, sub_node->count); + } + } + } + //- release the sub dev memory + if (sub_dev != 0){ + arena_release(sub_dev->arena); + } +} + +internal ArenaDev* +arena_equip__dev(Arena *arena){ + ArenaDev *result = arena->dev; + if (result == 0){ + Arena *dev_arena = arena_alloc(); + ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev)); + MemoryZeroStruct(dev); + dev->arena = dev_arena; + arena->dev = dev; + result = dev; + } + return(result); +} + +internal void +arena_equip_profile__dev(Arena *arena){ + ArenaDev *dev = arena_equip__dev(arena); + if (dev->prof == 0){ + dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf)); + MemoryZeroStruct(dev->prof); + } +} + +internal void +arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){ + Assert(arena != out_arena); + + //- get dev & disable + ArenaDev *dev = arena->dev; + arena->dev = 0; + + //- get prof + ArenaProf *prof = (dev != 0)?dev->prof:0; + + //- not equipped with prof + if (prof == 0){ + str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n")); + } + + //- print prof + if (prof != 0){ + Temp scratch = temp_begin(dev->arena); + + //- make flat array + U64 note_count = prof->count; + ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count); + { + ArenaProfNode **note_ptr = notes; + for (ArenaProfNode *node = prof->first; + node != 0; + node = node->next, note_ptr += 1){ + *note_ptr = node; + } + } + + //- file name size + U64 max_file_name_size = 0; + { + ArenaProfNode **note_ptr = notes; + for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ + max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size); + } + } + + //- sort (> size, < [address]) + for (U64 i = 0; i < note_count; i += 1){ + ArenaProfNode **i_note = notes + i; + ArenaProfNode **min_note = i_note; + for (U64 j = i + 1; j < note_count; j += 1){ + ArenaProfNode **j_note = notes + j; + if ((**j_note).size > (**min_note).size || + ((**j_note).size == (**min_note).size && *j_note < *min_note)){ + min_note = j_note; + } + } + if (min_note != i_note){ + ArenaProfNode *t = *i_note; + *i_note = *min_note; + *min_note = t; + } + } + + //- total size + U64 total_size = 0; + { + ArenaProfNode **note_ptr = notes; + for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ + ArenaProfNode *note = *note_ptr; + total_size += note->size; + } + } + + //- print + { + str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size); + + ArenaProfNode **note_ptr = notes; + for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ + ArenaProfNode *note = *note_ptr; + String8 location = push_str8f(scratch.arena, "%S:%5llu:", + note->file_name, note->line); + F32 percent = 100.f*((F32)note->size)/total_size; + str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n", + max_file_name_size + 7, str8_varg(location), + note->size, percent, note->count); + } + } + + temp_end(scratch); + } + + //- restore dev + arena->dev = dev; +} + +internal void +arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, + U64 size, U64 count){ + // find existing profile node + ArenaProfNode *prof_node = 0; + for (ArenaProfNode *node = prof->first; + node != 0; + node = node->next){ + if (node->line == line && str8_match(file_name, node->file_name, 0)){ + prof_node = node; + break; + } + } + // make new histogram node if necessary + if (prof_node == 0){ + prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node)); + SLLQueuePush(prof->first, prof->last, prof_node); + prof->count += 1; + prof_node->file_name = file_name; + prof_node->line = line; + } + // record this allocation + prof_node->size += size; + prof_node->count += count; +} + +#endif diff --git a/src/base/base_arena_dev.h b/src/base/base_arena_dev.h new file mode 100644 index 00000000..14d16b1d --- /dev/null +++ b/src/base/base_arena_dev.h @@ -0,0 +1,47 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_ARENA_DEV_H +#define BASE_ARENA_DEV_H + +//////////////////////////////// +//~ NOTE(allen): Dev Arena Types + +typedef struct ArenaDev ArenaDev; +struct ArenaDev +{ + Arena *arena; + struct ArenaProf *prof; +}; + +typedef struct ArenaProf ArenaProf; +struct ArenaProf +{ + struct ArenaProfNode *first; + struct ArenaProfNode *last; + U64 count; +}; + +typedef struct ArenaProfNode ArenaProfNode; +struct ArenaProfNode +{ + ArenaProfNode *next; + String8 file_name; + U64 line; + U64 size; + U64 count; +}; + +//////////////////////////////// +//~ NOTE(allen): Dev Arena Functions + +#if ENABLE_DEV +internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr); +internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub); +internal ArenaDev* arena_equip__dev(Arena *arena); +internal void arena_equip_profile__dev(Arena *arena); +internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out); +internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count); +#endif + +#endif // BASE_ARENA_DEV_H diff --git a/src/base/base_bits.c b/src/base/base_bits.c new file mode 100644 index 00000000..98ae781f --- /dev/null +++ b/src/base/base_bits.c @@ -0,0 +1,103 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS) + +internal U64 +count_bits_set16(U16 val) +{ + return __popcnt16(val); +} + +internal U64 +count_bits_set32(U32 val) +{ + return __popcnt(val); +} + +internal U64 +count_bits_set64(U64 val) +{ + return __popcnt64(val); +} + +internal U64 +ctz32(U32 mask) +{ + unsigned long idx; + _BitScanForward(&idx, mask); + return idx; +} + +internal U64 +ctz64(U64 mask) +{ + unsigned long idx; + _BitScanForward64(&idx, mask); + return idx; +} + +internal U64 +clz32(U32 mask) +{ + unsigned long idx; + _BitScanReverse(&idx, mask); + return 31 - idx; +} + +internal U64 +clz64(U64 mask) +{ + unsigned long idx; + _BitScanReverse64(&idx, mask); + return 63 - idx; +} + +#elif COMPILER_CLANG || COMPILER_GCC + +internal U64 +count_bits_set16(U16 val) +{ + NotImplemented; + return 0; +} + +internal U64 +count_bits_set32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +count_bits_set64(U64 val) +{ + NotImplemented; + return 0; +} + +internal U64 +ctz32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +clz32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +clz64(U64 val) +{ + NotImplemented; + return 0; +} + +#else +# error "bits not defined for this target" +#endif + diff --git a/src/base/base_bits.h b/src/base/base_bits.h new file mode 100644 index 00000000..ab9482d3 --- /dev/null +++ b/src/base/base_bits.h @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_BITS_H +#define BASE_BITS_H + +#define ExtractBit(word, idx) (((word) >> (idx)) & 1) + +internal U64 count_bits_set16(U16 val); +internal U64 count_bits_set32(U32 val); +internal U64 count_bits_set64(U64 val); + +internal U64 ctz32(U32 val); +internal U64 ctz64(U64 val); +internal U64 clz32(U32 val); +internal U64 clz64(U64 val); + +#endif // BASE_BITS_H diff --git a/src/base/base_command_line.c b/src/base/base_command_line.c new file mode 100644 index 00000000..2a40b5c8 --- /dev/null +++ b/src/base/base_command_line.c @@ -0,0 +1,229 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ NOTE(rjf): Command Line Option Parsing + +internal U64 +cmd_line_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal CmdLineOpt ** +cmd_line_slot_from_string(CmdLine *cmd_line, String8 string) +{ + CmdLineOpt **slot = 0; + if(cmd_line->option_table_size != 0) + { + U64 hash = cmd_line_hash_from_string(string); + U64 bucket = hash % cmd_line->option_table_size; + slot = &cmd_line->option_table[bucket]; + } + return slot; +} + +internal CmdLineOpt * +cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string) +{ + CmdLineOpt *result = 0; + for(CmdLineOpt *var = *slot; var; var = var->hash_next) + { + if(str8_match(string, var->string, 0)) + { + result = var; + break; + } + } + return result; +} + +internal void +cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var) +{ + SLLQueuePush(list->first, list->last, var); + list->count += 1; +} + +internal CmdLineOpt * +cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values) +{ + CmdLineOpt *var = 0; + CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string); + CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string); + if(existing_var != 0) + { + var = existing_var; + } + else + { + var = push_array(arena, CmdLineOpt, 1); + var->hash_next = *slot; + var->hash = cmd_line_hash_from_string(string); + var->string = push_str8_copy(arena, string); + var->value_strings = values; + StringJoin join = {0}; + join.pre = str8_lit(""); + join.sep = str8_lit(","); + join.post = str8_lit(""); + var->value_string = str8_list_join(arena, &var->value_strings, &join); + *slot = var; + cmd_line_push_opt(&cmd_line->options, var); + } + return var; +} + +internal CmdLine +cmd_line_from_string_list(Arena *arena, String8List command_line) +{ + CmdLine parsed = {0}; + + // NOTE(rjf): Set up config option table. + { + parsed.option_table_size = 4096; + parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size); + } + + // NOTE(rjf): Parse command line. + B32 after_passthrough_option = 0; + for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next) + { + next = node->next; + String8 option_name = node->string; + + // NOTE(rjf): Look at -- or - at the start of an argument to determine if it's + // a flag option. All arguments after a single "--" (with no trailing string + // on the command line will be considered as input files. + B32 is_option = 1; + if(after_passthrough_option == 0) + { + if(str8_match(node->string, str8_lit("--"), 0)) + { + after_passthrough_option = 1; + is_option = 0; + } + else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0)) + { + option_name = str8_skip(option_name, 2); + } + else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0)) + { + option_name = str8_skip(option_name, 1); + } + else + { + is_option = 0; + } + } + else + { + is_option = 0; + } + + // NOTE(rjf): This string is an option. + if(is_option) + { + B32 has_arguments = 0; + U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0); + U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0); + U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2); + String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1); + if(arg_signifier_position < option_name.size) + { + has_arguments = 1; + } + option_name = str8_prefix(option_name, arg_signifier_position); + + String8List arguments = {0}; + + // NOTE(rjf): Parse arguments. + if(has_arguments) + { + for(String8Node *n = node; n; n = n->next) + { + next = n->next; + + String8 string = n->string; + if(n == node) + { + string = arg_portion_this_string; + } + + U8 splits[] = { ',' }; + String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0); + for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next) + { + str8_list_push(arena, &arguments, sub_arg->string); + } + if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) && + (n != node || arg_portion_this_string.size != 0)) + { + break; + } + } + } + + // NOTE(rjf): Register config variable. + cmd_line_insert_opt(arena, &parsed, option_name, arguments); + } + + // NOTE(rjf): Default path, treat as a passthrough config option to be + // handled by tool-specific code. + else if(!str8_match(node->string, str8_lit("--"), 0)) + { + str8_list_push(arena, &parsed.inputs, node->string); + after_passthrough_option = 1; + } + } + + return parsed; +} + +internal CmdLineOpt * +cmd_line_opt_from_string(CmdLine *cmd_line, String8 name) +{ + return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name); +} + +internal String8List +cmd_line_strings(CmdLine *cmd_line, String8 name) +{ + String8List result = {0}; + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + if(var != 0) + { + result = var->value_strings; + } + return result; +} + +internal String8 +cmd_line_string(CmdLine *cmd_line, String8 name) +{ + String8 result = {0}; + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + if(var != 0) + { + result = var->value_string; + } + return result; +} + +internal B32 +cmd_line_has_flag(CmdLine *cmd_line, String8 name) +{ + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + return(var != 0); +} + +internal B32 +cmd_line_has_argument(CmdLine *cmd_line, String8 name) +{ + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + return(var != 0 && var->value_strings.node_count > 0); +} diff --git a/src/base/base_command_line.h b/src/base/base_command_line.h new file mode 100644 index 00000000..bfbc35ef --- /dev/null +++ b/src/base/base_command_line.h @@ -0,0 +1,53 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_COMMAND_LINE_H +#define BASE_COMMAND_LINE_H + +//////////////////////////////// +//~ rjf: Parsed Command Line Types + +typedef struct CmdLineOpt CmdLineOpt; +struct CmdLineOpt +{ + CmdLineOpt *next; + CmdLineOpt *hash_next; + U64 hash; + String8 string; + String8List value_strings; + String8 value_string; +}; + +typedef struct CmdLineOptList CmdLineOptList; +struct CmdLineOptList +{ + U64 count; + CmdLineOpt *first; + CmdLineOpt *last; +}; + +typedef struct CmdLine CmdLine; +struct CmdLine +{ + CmdLineOptList options; + String8List inputs; + U64 option_table_size; + CmdLineOpt **option_table; +}; + +//////////////////////////////// +//~ NOTE(rjf): Command Line Option Parsing + +internal U64 cmd_line_hash_from_string(String8 string); +internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string); +internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string); +internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var); +internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values); +internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments); +internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name); +internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name); +internal String8 cmd_line_string(CmdLine *cmd_line, String8 name); +internal B32 cmd_line_has_flag(CmdLine *cmd_line, String8 name); +internal B32 cmd_line_has_argument(CmdLine *cmd_line, String8 name); + +#endif // BASE_COMMAND_LINE_H diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h new file mode 100644 index 00000000..65f49e7b --- /dev/null +++ b/src/base/base_context_cracking.h @@ -0,0 +1,144 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_CONTEXT_CRACKING_H +#define BASE_CONTEXT_CRACKING_H + +#if defined(__clang__) + +# define COMPILER_CLANG 1 + +# if defined(_WIN32) +# define OS_WINDOWS 1 +# elif defined(__gnu_linux__) || defined(__linux__) +# define OS_LINUX 1 +# elif defined(__APPLE__) && defined(__MACH__) +# define OS_MAC 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) +# define ARCH_X64 1 +# elif defined(i386) || defined(__i386) || defined(__i386__) +# define ARCH_X86 1 +# elif defined(__aarch64__) +# define ARCH_ARM64 1 +# elif defined(__arm__) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + +#elif defined(_MSC_VER) + +# define COMPILER_CL 1 + +# if defined(_WIN32) +# define OS_WINDOWS 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(_M_AMD64) +# define ARCH_X64 1 +# elif defined(_M_IX86) +# define ARCH_X86 1 +# elif defined(_M_ARM64) +# define ARCH_ARM64 1 +# elif defined(_M_ARM) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) + +# define COMPILER_GCC 1 + +# if defined(__gnu_linux__) || defined(__linux__) +# define OS_LINUX 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) +# define ARCH_X64 1 +# elif defined(i386) || defined(__i386) || defined(__i386__) +# define ARCH_X86 1 +# elif defined(__aarch64__) +# define ARCH_ARM64 1 +# elif defined(__arm__) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + +#else +# error This compiler is not supported yet +#endif + +#if defined(ARCH_X64) +# define ARCH_64BIT 1 +#elif defined(ARCH_X86) +# define ARCH_32BIT 1 +#endif + +#if defined(__cplusplus) +# define LANG_CPP 1 +#else +# define LANG_C 1 +#endif + +// zeroify + +#if !defined(ARCH_32BIT) +# define ARCH_32BIT 0 +#endif +#if !defined(ARCH_64BIT) +# define ARCH_64BIT 0 +#endif +#if !defined(ARCH_X64) +# define ARCH_X64 0 +#endif +#if !defined(ARCH_X86) +# define ARCH_X86 0 +#endif +#if !defined(ARCH_ARM64) +# define ARCH_ARM64 0 +#endif +#if !defined(ARCH_ARM32) +# define ARCH_ARM32 0 +#endif +#if !defined(COMPILER_CL) +# define COMPILER_CL 0 +#endif +#if !defined(COMPILER_GCC) +# define COMPILER_GCC 0 +#endif +#if !defined(COMPILER_CLANG) +# define COMPILER_CLANG 0 +#endif +#if !defined(OS_WINDOWS) +# define OS_WINDOWS 0 +#endif +#if !defined(OS_LINUX) +# define OS_LINUX 0 +#endif +#if !defined(OS_MAC) +# define OS_MAC 0 +#endif +#if !defined(LANG_CPP) +# define LANG_CPP 0 +#endif +#if !defined(LANG_C) +# define LANG_C 0 +#endif + +#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86 +# define ARCH_LITTLE_ENDIAN 1 +#else +# error Endianness of this architecture not understood by context cracker +#endif + +#endif // BASE_CONTEXT_CRACKING_H diff --git a/src/base/base_inc.c b/src/base/base_inc.c new file mode 100644 index 00000000..e9824297 --- /dev/null +++ b/src/base/base_inc.c @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Base Includes + +#undef RADDBG_LAYER_COLOR +#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f + +#include "base_types.c" +#include "base_markup.c" +#include "base_arena.c" +#include "base_math.c" +#include "base_string.c" +#include "base_thread_context.c" +#include "base_command_line.c" +#include "base_arena_dev.c" +#include "base_bits.c" diff --git a/src/base/base_inc.h b/src/base/base_inc.h new file mode 100644 index 00000000..2af02635 --- /dev/null +++ b/src/base/base_inc.h @@ -0,0 +1,23 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_INC_H +#define BASE_INC_H + +//////////////////////////////// +//~ rjf: Base Includes + +#include "base_context_cracking.h" +#include "base_types.h" +#include "base_markup.h" +#include "base_ins.h" +#include "base_linked_lists.h" +#include "base_arena.h" +#include "base_math.h" +#include "base_string.h" +#include "base_thread_context.h" +#include "base_command_line.h" +#include "base_arena_dev.h" +#include "base_bits.h" + +#endif // BASE_INC_H diff --git a/src/base/base_ins.h b/src/base/base_ins.h new file mode 100644 index 00000000..9f8d3202 --- /dev/null +++ b/src/base/base_ins.h @@ -0,0 +1,52 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_INS_H +#define BASE_INS_H + +//////////////////////////////// +// NOTE(allen): Implementations of Intrinsics + +#if OS_WINDOWS + +# include +# include +# include +# include + +# if ARCH_X64 +# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(x), 0) +# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x)) +# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x)) +# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c)) +# define ins_atomic_u64_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c) +# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c)) +# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c)) +# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c)) +# endif + +#elif OS_LINUX + +# if ARCH_X64 +# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1) +# endif + +#else +// TODO(allen): +#endif + +//////////////////////////////// +// NOTE(allen): Intrinsic Checks + +#if ARCH_X64 + +# if !defined(ins_atomic_u64_inc_eval) +# error missing: ins_atomic_u64_inc_eval +# endif + +#else +# error the intrinsic set for this arch is not developed +#endif + + +#endif //BASE_INS_H diff --git a/src/base/base_linked_lists.h b/src/base/base_linked_lists.h new file mode 100644 index 00000000..436cedc5 --- /dev/null +++ b/src/base/base_linked_lists.h @@ -0,0 +1,73 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_LINKED_LIST_H +#define BASE_LINKED_LIST_H + +//////////////////////////////// +//~ rjf: Helpers + +#define CheckNil(nil,p) ((p) == 0 || (p) == nil) +#define SetNil(nil,p) ((p) = nil) + +//////////////////////////////// +//~ rjf: Base Macros + +//- rjf: Base Doubly-Linked-List Macros +#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \ +((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\ +CheckNil(nil,p) ? \ +((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\ +((p)==(l)) ? \ +((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\ +(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p)))) +#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev) +#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next) +#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\ +((n) == (l) ? (l) = (l)->prev : (0)),\ +(CheckNil(nil,(n)->prev) ? (0) :\ +((n)->prev->next = (n)->next)),\ +(CheckNil(nil,(n)->next) ? (0) :\ +((n)->next->prev = (n)->prev))) + +//- rjf: Base Singly-Linked-List Queue Macros +#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ +((f)=(l)=(n),SetNil(nil,(n)->next)):\ +((l)->next=(n),(l)=(n),SetNil(nil,(n)->next))) +#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ +((f)=(l)=(n),SetNil(nil,(n)->next)):\ +((n)->next=(f),(f)=(n))) +#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\ +(SetNil(nil,f),SetNil(nil,l)):\ +((f)=(f)->next)) + +//- rjf: Base Singly-Linked-List Stack Macros +#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) +#define SLLStackPop_N(f,next) ((f)=(f)->next) + +//////////////////////////////// +//~ rjf: Convenience Wrappers + +//- rjf: Doubly-Linked-List Wrappers +#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev) +#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev) +#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev) +#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev) +#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev) +#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev) + +//- rjf: Singly-Linked-List Queue Wrappers +#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next) +#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next) +#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next) +#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next) +#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next) +#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next) + +//- rjf: Singly-Linked-List Stack Wrappers +#define SLLStackPush(f,n) SLLStackPush_N(f,n,next) +#define SLLStackPop(f) SLLStackPop_N(f,next) + +#endif //BASE_LINKED_LIST_H diff --git a/src/base/base_markup.c b/src/base/base_markup.c new file mode 100644 index 00000000..7ea8904c --- /dev/null +++ b/src/base/base_markup.c @@ -0,0 +1,2 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) diff --git a/src/base/base_markup.h b/src/base/base_markup.h new file mode 100644 index 00000000..03c1adab --- /dev/null +++ b/src/base/base_markup.h @@ -0,0 +1,79 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_MARKUP_H +#define BASE_MARKUP_H + +//////////////////////////////// +//~ rjf: Zero Settings + +#if !defined(PROFILE_TELEMETRY) +# define PROFILE_TELEMETRY 0 +#endif + +#if !defined(MARKUP_LAYER_COLOR) +# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f +#endif + +//////////////////////////////// +//~ rjf: Third Party Includes + +#if PROFILE_TELEMETRY +# include "rad_tm.h" +# if OS_WINDOWS +# pragma comment(lib, "rad_tm_win64.lib") +# endif +#endif + +//////////////////////////////// +//~ rjf: Telemetry Profile Defines + +#if PROFILE_TELEMETRY +# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__) +# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) +# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0) +# define ProfTick(...) tmTick(0) +# define ProfIsCapturing(...) tmRunning() +# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100) +# define ProfEndCapture(...) tmClose(0) +# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0) +# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) +# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__) +# define ProfEndLockWait(...) tmEndWaitForLock(0) +# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__) +# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) +# define ProfColor(color) tmZoneColorSticky(color) +#endif + +//////////////////////////////// +//~ rjf: Zeroify Undefined Defines + +#if !defined(ProfBegin) +# define ProfBegin(...) (0) +# define ProfBeginDynamic(...) (0) +# define ProfEnd(...) (0) +# define ProfTick(...) (0) +# define ProfIsCapturing(...) (0) +# define ProfBeginCapture(...) (0) +# define ProfEndCapture(...) (0) +# define ProfThreadName(...) (0) +# define ProfMsg(...) (0) +# define ProfBeginLockWait(...) (0) +# define ProfEndLockWait(...) (0) +# define ProfLockTake(...) (0) +# define ProfLockDrop(...) (0) +# define ProfColor(...) (0) +#endif + +//////////////////////////////// +//~ rjf: Helper Wrappers + +#define ProfBeginFunction(...) ProfBegin(this_function_name) +#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd()) + +//////////////////////////////// +//~ rjf: General Markup + +#define ThreadName(...) (ProfThreadName(__VA_ARGS__)) + +#endif // BASE_MARKUP_H diff --git a/src/base/base_math.c b/src/base/base_math.c new file mode 100644 index 00000000..0ddf662f --- /dev/null +++ b/src/base/base_math.c @@ -0,0 +1,607 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Scalar Ops + +internal F32 +mix_1f32(F32 a, F32 b, F32 t) +{ + F32 c = (a + (b-a) * Clamp(0.f, t, 1.f)); + return c; +} + +internal F64 +mix_1f64(F64 a, F64 b, F64 t) +{ + F64 c = (a + (b-a) * Clamp(0.0, t, 1.0)); + return c; +} + +//////////////////////////////// +//~ rjf: Vector Ops + +internal Vec2F32 vec_2f32(F32 x, F32 y) {Vec2F32 v = {x, y}; return v;} +internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x+b.x, a.y+b.y}; return c;} +internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x-b.x, a.y-b.y}; return c;} +internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x*b.x, a.y*b.y}; return c;} +internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x/b.x, a.y/b.y}; return c;} +internal Vec2F32 scale_2f32(Vec2F32 v, F32 s) {Vec2F32 c = {v.x*s, v.y*s}; return c;} +internal F32 dot_2f32(Vec2F32 a, Vec2F32 b) {F32 c = a.x*b.x + a.y*b.y; return c;} +internal F32 length_squared_2f32(Vec2F32 v) {F32 c = v.x*v.x + v.y*v.y; return c;} +internal F32 length_2f32(Vec2F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y); return c;} +internal Vec2F32 normalize_2f32(Vec2F32 v) {v = scale_2f32(v, 1.f/length_2f32(v)); return v;} +internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t) {Vec2F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t)}; return c;} + +internal Vec2S64 vec_2s64(S64 x, S64 y) {Vec2S64 v = {x, y}; return v;} +internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x+b.x, a.y+b.y}; return c;} +internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x-b.x, a.y-b.y}; return c;} +internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x*b.x, a.y*b.y}; return c;} +internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x/b.x, a.y/b.y}; return c;} +internal Vec2S64 scale_2s64(Vec2S64 v, S64 s) {Vec2S64 c = {v.x*s, v.y*s}; return c;} +internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;} +internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;} +internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;} +internal Vec2S64 normalize_2s64(Vec2S64 v) {v = scale_2s64(v, (S64)(1.f/length_2s64(v))); return v;} +internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} + +internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;} +internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x+b.x, a.y+b.y}; return c;} +internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x-b.x, a.y-b.y}; return c;} +internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x*b.x, a.y*b.y}; return c;} +internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x/b.x, a.y/b.y}; return c;} +internal Vec2S32 scale_2s32(Vec2S32 v, S32 s) {Vec2S32 c = {v.x*s, v.y*s}; return c;} +internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;} +internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;} +internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;} +internal Vec2S32 normalize_2s32(Vec2S32 v) {v = scale_2s32(v, (S32)(1.f/length_2s32(v))); return v;} +internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} + +internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;} +internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x+b.x), (S16)(a.y+b.y)}; return c;} +internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x-b.x), (S16)(a.y-b.y)}; return c;} +internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x*b.x), (S16)(a.y*b.y)}; return c;} +internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x/b.x), (S16)(a.y/b.y)}; return c;} +internal Vec2S16 scale_2s16(Vec2S16 v, S16 s) {Vec2S16 c = {(S16)(v.x*s), (S16)(v.y*s)}; return c;} +internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;} +internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;} +internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;} +internal Vec2S16 normalize_2s16(Vec2S16 v) {v = scale_2s16(v, (S16)(1.f/length_2s16(v))); return v;} +internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} + +internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;} +internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;} +internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x-b.x, a.y-b.y, a.z-b.z}; return c;} +internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x*b.x, a.y*b.y, a.z*b.z}; return c;} +internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x/b.x, a.y/b.y, a.z/b.z}; return c;} +internal Vec3F32 scale_3f32(Vec3F32 v, F32 s) {Vec3F32 c = {v.x*s, v.y*s, v.z*s}; return c;} +internal F32 dot_3f32(Vec3F32 a, Vec3F32 b) {F32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;} +internal F32 length_squared_3f32(Vec3F32 v) {F32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;} +internal F32 length_3f32(Vec3F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y + v.z*v.z); return c;} +internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;} +internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;} +internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;} + +internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;} +internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;} +internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x-b.x, a.y-b.y, a.z-b.z}; return c;} +internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x*b.x, a.y*b.y, a.z*b.z}; return c;} +internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x/b.x, a.y/b.y, a.z/b.z}; return c;} +internal Vec3S32 scale_3s32(Vec3S32 v, S32 s) {Vec3S32 c = {v.x*s, v.y*s, v.z*s}; return c;} +internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;} +internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;} +internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;} +internal Vec3S32 normalize_3s32(Vec3S32 v) {v = scale_3s32(v, (S32)(1.f/length_3s32(v))); return v;} +internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;} +internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;} + +internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w) {Vec4F32 v = {x, y, z, w}; return v;} +internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w}; return c;} +internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w}; return c;} +internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return c;} +internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return c;} +internal Vec4F32 scale_4f32(Vec4F32 v, F32 s) {Vec4F32 c = {v.x*s, v.y*s, v.z*s, v.w*s}; return c;} +internal F32 dot_4f32(Vec4F32 a, Vec4F32 b) {F32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;} +internal F32 length_squared_4f32(Vec4F32 v) {F32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;} +internal F32 length_4f32(Vec4F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); return c;} +internal Vec4F32 normalize_4f32(Vec4F32 v) {v = scale_4f32(v, 1.f/length_4f32(v)); return v;} +internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t) {Vec4F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t), mix_1f32(a.w, b.w, t)}; return c;} + +internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w) {Vec4S32 v = {x, y, z, w}; return v;} +internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w}; return c;} +internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w}; return c;} +internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return c;} +internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return c;} +internal Vec4S32 scale_4s32(Vec4S32 v, S32 s) {Vec4S32 c = {v.x*s, v.y*s, v.z*s, v.w*s}; return c;} +internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;} +internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;} +internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;} +internal Vec4S32 normalize_4s32(Vec4S32 v) {v = scale_4s32(v, (S32)(1.f/length_4s32(v))); return v;} +internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;} + +//////////////////////////////// +//~ rjf: Matrix Ops + +internal Mat3x3F32 +mat_3x3f32(F32 diagonal) +{ + Mat3x3F32 result = {0}; + result.v[0][0] = diagonal; + result.v[1][1] = diagonal; + result.v[2][2] = diagonal; + return result; +} + +internal Mat3x3F32 +make_translate_3x3f32(Vec2F32 delta) +{ + Mat3x3F32 mat = mat_3x3f32(1.f); + mat.v[2][0] = delta.x; + mat.v[2][1] = delta.y; + return mat; +} + +internal Mat3x3F32 +mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b) +{ + Mat3x3F32 c = {0}; + for(int j = 0; j < 3; j += 1) + { + for(int i = 0; i < 3; i += 1) + { + c.v[i][j] = (a.v[0][j]*b.v[i][0] + + a.v[1][j]*b.v[i][1] + + a.v[2][j]*b.v[i][2]); + } + } + return c; +} + +internal Mat4x4F32 +mat_4x4f32(F32 diagonal) +{ + Mat4x4F32 result = {0}; + result.v[0][0] = diagonal; + result.v[1][1] = diagonal; + result.v[2][2] = diagonal; + result.v[3][3] = diagonal; + return result; +} + +internal Mat4x4F32 +make_translate_4x4f32(Vec3F32 delta) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + result.v[3][0] = delta.x; + result.v[3][1] = delta.y; + result.v[3][2] = delta.z; + return result; +} + +internal Mat4x4F32 +make_scale_4x4f32(Vec3F32 scale) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + result.v[0][0] = scale.x; + result.v[1][1] = scale.y; + result.v[2][2] = scale.z; + return result; +} + +internal Mat4x4F32 +make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + F32 tan_theta_over_2 = tan_f32(fov / 2); + result.v[0][0] = 1.f / tan_theta_over_2; + result.v[1][1] = aspect_ratio / tan_theta_over_2; + result.v[2][3] = 1.f; + result.v[2][2] = -(near_z + far_z) / (near_z - far_z); + result.v[3][2] = (2.f * near_z * far_z) / (near_z - far_z); + result.v[3][3] = 0.f; + return result; +} + +internal Mat4x4F32 +make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + + result.v[0][0] = 2.f / (right - left); + result.v[1][1] = 2.f / (top - bottom); + result.v[2][2] = 2.f / (far_z - near_z); + result.v[3][3] = 1.f; + + result.v[3][0] = (left + right) / (left - right); + result.v[3][1] = (bottom + top) / (bottom - top); + result.v[3][2] = (near_z + far_z) / (near_z - far_z); + + return result; +} + +internal Mat4x4F32 +make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up) +{ + Mat4x4F32 result; + Vec3F32 f = normalize_3f32(sub_3f32(eye, center)); + Vec3F32 s = normalize_3f32(cross_3f32(f, up)); + Vec3F32 u = cross_3f32(s, f); + result.v[0][0] = s.x; + result.v[0][1] = u.x; + result.v[0][2] = -f.x; + result.v[0][3] = 0.0f; + result.v[1][0] = s.y; + result.v[1][1] = u.y; + result.v[1][2] = -f.y; + result.v[1][3] = 0.0f; + result.v[2][0] = s.z; + result.v[2][1] = u.z; + result.v[2][2] = -f.z; + result.v[2][3] = 0.0f; + result.v[3][0] = -dot_3f32(s, eye); + result.v[3][1] = -dot_3f32(u, eye); + result.v[3][2] = dot_3f32(f, eye); + result.v[3][3] = 1.0f; + return result; +} + +internal Mat4x4F32 +make_rotate_4x4f32(Vec3F32 axis, F32 turns) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + axis = normalize_3f32(axis); + F32 sin_theta = sin_f32(turns); + F32 cos_theta = cos_f32(turns); + F32 cos_value = 1.f - cos_theta; + result.v[0][0] = (axis.x * axis.x * cos_value) + cos_theta; + result.v[0][1] = (axis.x * axis.y * cos_value) + (axis.z * sin_theta); + result.v[0][2] = (axis.x * axis.z * cos_value) - (axis.y * sin_theta); + result.v[1][0] = (axis.y * axis.x * cos_value) - (axis.z * sin_theta); + result.v[1][1] = (axis.y * axis.y * cos_value) + cos_theta; + result.v[1][2] = (axis.y * axis.z * cos_value) + (axis.x * sin_theta); + result.v[2][0] = (axis.z * axis.x * cos_value) + (axis.y * sin_theta); + result.v[2][1] = (axis.z * axis.y * cos_value) - (axis.x * sin_theta); + result.v[2][2] = (axis.z * axis.z * cos_value) + cos_theta; + return result; +} + +internal Mat4x4F32 +mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b) +{ + Mat4x4F32 c = {0}; + for(int j = 0; j < 4; j += 1) + { + for(int i = 0; i < 4; i += 1) + { + c.v[i][j] = (a.v[0][j]*b.v[i][0] + + a.v[1][j]*b.v[i][1] + + a.v[2][j]*b.v[i][2] + + a.v[3][j]*b.v[i][3]); + } + } + return c; +} + +internal Mat4x4F32 +scale_4x4f32(Mat4x4F32 m, F32 scale) +{ + for(int j = 0; j < 4; j += 1) + { + for(int i = 0; i < 4; i += 1) + { + m.v[i][j] *= scale; + } + } + return m; +} + +internal Mat4x4F32 +inverse_4x4f32(Mat4x4F32 m) +{ + F32 coef00 = m.v[2][2] * m.v[3][3] - m.v[3][2] * m.v[2][3]; + F32 coef02 = m.v[1][2] * m.v[3][3] - m.v[3][2] * m.v[1][3]; + F32 coef03 = m.v[1][2] * m.v[2][3] - m.v[2][2] * m.v[1][3]; + F32 coef04 = m.v[2][1] * m.v[3][3] - m.v[3][1] * m.v[2][3]; + F32 coef06 = m.v[1][1] * m.v[3][3] - m.v[3][1] * m.v[1][3]; + F32 coef07 = m.v[1][1] * m.v[2][3] - m.v[2][1] * m.v[1][3]; + F32 coef08 = m.v[2][1] * m.v[3][2] - m.v[3][1] * m.v[2][2]; + F32 coef10 = m.v[1][1] * m.v[3][2] - m.v[3][1] * m.v[1][2]; + F32 coef11 = m.v[1][1] * m.v[2][2] - m.v[2][1] * m.v[1][2]; + F32 coef12 = m.v[2][0] * m.v[3][3] - m.v[3][0] * m.v[2][3]; + F32 coef14 = m.v[1][0] * m.v[3][3] - m.v[3][0] * m.v[1][3]; + F32 coef15 = m.v[1][0] * m.v[2][3] - m.v[2][0] * m.v[1][3]; + F32 coef16 = m.v[2][0] * m.v[3][2] - m.v[3][0] * m.v[2][2]; + F32 coef18 = m.v[1][0] * m.v[3][2] - m.v[3][0] * m.v[1][2]; + F32 coef19 = m.v[1][0] * m.v[2][2] - m.v[2][0] * m.v[1][2]; + F32 coef20 = m.v[2][0] * m.v[3][1] - m.v[3][0] * m.v[2][1]; + F32 coef22 = m.v[1][0] * m.v[3][1] - m.v[3][0] * m.v[1][1]; + F32 coef23 = m.v[1][0] * m.v[2][1] - m.v[2][0] * m.v[1][1]; + + Vec4F32 fac0 = { coef00, coef00, coef02, coef03 }; + Vec4F32 fac1 = { coef04, coef04, coef06, coef07 }; + Vec4F32 fac2 = { coef08, coef08, coef10, coef11 }; + Vec4F32 fac3 = { coef12, coef12, coef14, coef15 }; + Vec4F32 fac4 = { coef16, coef16, coef18, coef19 }; + Vec4F32 fac5 = { coef20, coef20, coef22, coef23 }; + + Vec4F32 vec0 = { m.v[1][0], m.v[0][0], m.v[0][0], m.v[0][0] }; + Vec4F32 vec1 = { m.v[1][1], m.v[0][1], m.v[0][1], m.v[0][1] }; + Vec4F32 vec2 = { m.v[1][2], m.v[0][2], m.v[0][2], m.v[0][2] }; + Vec4F32 vec3 = { m.v[1][3], m.v[0][3], m.v[0][3], m.v[0][3] }; + + Vec4F32 inv0 = add_4f32(sub_4f32(mul_4f32(vec1, fac0), mul_4f32(vec2, fac1)), mul_4f32(vec3, fac2)); + Vec4F32 inv1 = add_4f32(sub_4f32(mul_4f32(vec0, fac0), mul_4f32(vec2, fac3)), mul_4f32(vec3, fac4)); + Vec4F32 inv2 = add_4f32(sub_4f32(mul_4f32(vec0, fac1), mul_4f32(vec1, fac3)), mul_4f32(vec3, fac5)); + Vec4F32 inv3 = add_4f32(sub_4f32(mul_4f32(vec0, fac2), mul_4f32(vec1, fac4)), mul_4f32(vec2, fac5)); + + Vec4F32 sign_a = { +1, -1, +1, -1 }; + Vec4F32 sign_b = { -1, +1, -1, +1 }; + + Mat4x4F32 inverse; + for(U32 i = 0; i < 4; i += 1) + { + inverse.v[0][i] = inv0.v[i] * sign_a.v[i]; + inverse.v[1][i] = inv1.v[i] * sign_b.v[i]; + inverse.v[2][i] = inv2.v[i] * sign_a.v[i]; + inverse.v[3][i] = inv3.v[i] * sign_b.v[i]; + } + + Vec4F32 row0 = { inverse.v[0][0], inverse.v[1][0], inverse.v[2][0], inverse.v[3][0] }; + Vec4F32 m0 = { m.v[0][0], m.v[0][1], m.v[0][2], m.v[0][3] }; + Vec4F32 dot0 = mul_4f32(m0, row0); + F32 dot1 = (dot0.x + dot0.y) + (dot0.z + dot0.w); + + F32 one_over_det = 1 / dot1; + + return scale_4x4f32(inverse, one_over_det); +} + +internal Mat4x4F32 +derotate_4x4f32(Mat4x4F32 mat) +{ + Vec3F32 scale = + { + length_3f32(v3f32(mat.v[0][0], mat.v[0][1], mat.v[0][2])), + length_3f32(v3f32(mat.v[1][0], mat.v[1][1], mat.v[1][2])), + length_3f32(v3f32(mat.v[2][0], mat.v[2][1], mat.v[2][2])), + }; + mat.v[0][0] = scale.x; + mat.v[1][0] = 0.f; + mat.v[2][0] = 0.f; + mat.v[0][1] = 0.f; + mat.v[1][1] = scale.y; + mat.v[2][1] = 0.f; + mat.v[0][2] = 0.f; + mat.v[1][2] = 0.f; + mat.v[2][2] = scale.z; + return mat; +} + +//////////////////////////////// +//~ rjf: Range Ops + +internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;} +internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;} +internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;} +internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;} +internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal U32 dim_1u32(Rng1U32 r) {U32 c = r.max-r.min; return c;} +internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1S32 rng_1s32(S32 min, S32 max) {Rng1S32 r = {min, max}; if(r.min > r.max) { Swap(S32, r.min, r.max); } return r;} +internal Rng1S32 shift_1s32(Rng1S32 r, S32 x) {r.min += x; r.max += x; return r;} +internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;} +internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;} +internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal S32 dim_1s32(Rng1S32 r) {S32 c = r.max-r.min; return c;} +internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1U64 rng_1u64(U64 min, U64 max) {Rng1U64 r = {min, max}; if(r.min > r.max) { Swap(U64, r.min, r.max); } return r;} +internal Rng1U64 shift_1u64(Rng1U64 r, U64 x) {r.min += x; r.max += x; return r;} +internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;} +internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;} +internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal U64 dim_1u64(Rng1U64 r) {U64 c = r.max-r.min; return c;} +internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1S64 rng_1s64(S64 min, S64 max) {Rng1S64 r = {min, max}; if(r.min > r.max) { Swap(S64, r.min, r.max); } return r;} +internal Rng1S64 shift_1s64(Rng1S64 r, S64 x) {r.min += x; r.max += x; return r;} +internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;} +internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;} +internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal S64 dim_1s64(Rng1S64 r) {S64 c = r.max-r.min; return c;} +internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1F32 rng_1f32(F32 min, F32 max) {Rng1F32 r = {min, max}; if(r.min > r.max) { Swap(F32, r.min, r.max); } return r;} +internal Rng1F32 shift_1f32(Rng1F32 r, F32 x) {r.min += x; r.max += x; return r;} +internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;} +internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;} +internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal F32 dim_1f32(Rng1F32 r) {F32 c = r.max-r.min; return c;} +internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max) {Rng2S16 r = {min, max}; return r;} +internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x) {r.min = add_2s16(r.min, x); r.max = add_2s16(r.max, x); return r;} +internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;} +internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;} +internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(r.max.x-r.min.x), (S16)(r.max.y-r.min.y)}; return dim;} +internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max) {Rng2S32 r = {min, max}; return r;} +internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x) {r.min = add_2s32(r.min, x); r.max = add_2s32(r.max, x); return r;} +internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;} +internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} +internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max) {Rng2S64 r = {min, max}; return r;} +internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x) {r.min = add_2s64(r.min, x); r.max = add_2s64(r.max, x); return r;} +internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;} +internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} +internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max) {Rng2F32 r = {min, max}; return r;} +internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x) {r.min = add_2f32(r.min, x); r.max = add_2f32(r.max, x); return r;} +internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;} +internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} +internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +//////////////////////////////// +//~ rjf: Miscellaneous Ops + +internal Vec3F32 +hsv_from_rgb(Vec3F32 rgb) +{ + F32 c_max = Max(rgb.x, Max(rgb.y, rgb.z)); + F32 c_min = Min(rgb.x, Min(rgb.y, rgb.z)); + F32 delta = c_max - c_min; + F32 h = ((delta == 0.f) ? 0.f : + (c_max == rgb.x) ? mod_f32((rgb.y - rgb.z)/delta + 6.f, 6.f) : + (c_max == rgb.y) ? (rgb.z - rgb.x)/delta + 2.f : + (c_max == rgb.z) ? (rgb.x - rgb.y)/delta + 4.f : + 0.f); + F32 s = (c_max == 0.f) ? 0.f : (delta/c_max); + F32 v = c_max; + Vec3F32 hsv = {h/6.f, s, v}; + return hsv; +} + +internal Vec3F32 +rgb_from_hsv(Vec3F32 hsv) +{ + F32 h = mod_f32(hsv.x * 360.f, 360.f); + F32 s = hsv.y; + F32 v = hsv.z; + + F32 c = v*s; + F32 x = c*(1.f - abs_f32(mod_f32(h/60.f, 2.f) - 1.f)); + F32 m = v - c; + + F32 r = 0; + F32 g = 0; + F32 b = 0; + + if ((h >= 0.f && h < 60.f) || (h >= 360.f && h < 420.f)){ + r = c; + g = x; + b = 0; + } + else if (h >= 60.f && h < 120.f){ + r = x; + g = c; + b = 0; + } + else if (h >= 120.f && h < 180.f){ + r = 0; + g = c; + b = x; + } + else if (h >= 180.f && h < 240.f){ + r = 0; + g = x; + b = c; + } + else if (h >= 240.f && h < 300.f){ + r = x; + g = 0; + b = c; + } + else if ((h >= 300.f && h <= 360.f) || (h >= -60.f && h <= 0.f)){ + r = c; + g = 0; + b = x; + } + + Vec3F32 rgb = {r + m, g + m, b + m}; + return(rgb); +} + +internal Vec4F32 +hsva_from_rgba(Vec4F32 rgba) +{ + Vec3F32 rgb = v3f32(rgba.x, rgba.y, rgba.z); + Vec3F32 hsv = hsv_from_rgb(rgb); + Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); + return hsva; +} + +internal Vec4F32 +rgba_from_hsva(Vec4F32 hsva) +{ + Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z); + Vec3F32 rgb = rgb_from_hsv(hsv); + Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, hsva.w); + return rgba; +} + +internal Vec4F32 +rgba_from_u32(U32 hex) +{ + Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f, + ((hex&0x00ff0000)>>16)/255.f, + ((hex&0x0000ff00)>> 8)/255.f, + ((hex&0x000000ff)>> 0)/255.f); + return result; +} + +internal U32 +u32_from_rgba(Vec4F32 rgba) +{ + U32 result = 0; + result |= ((U32)((U8)(rgba.x*255.f))) << 24; + result |= ((U32)((U8)(rgba.y*255.f))) << 16; + result |= ((U32)((U8)(rgba.z*255.f))) << 8; + result |= ((U32)((U8)(rgba.w*255.f))) << 0; + return result; +} + +//////////////////////////////// +//~ rjf: List Type Functions + +internal void +rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng) +{ + Rng1S64Node *n = push_array(arena, Rng1S64Node, 1); + MemoryCopyStruct(&n->v, &rng); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal Rng1S64Array +rng1s64_array_from_list(Arena *arena, Rng1S64List *list) +{ + Rng1S64Array arr = {0}; + arr.count = list->count; + arr.v = push_array_no_zero(arena, Rng1S64, arr.count); + U64 idx = 0; + for(Rng1S64Node *n = list->first; n != 0; n = n->next) + { + arr.v[idx] = n->v; + idx += 1; + } + return arr; +} diff --git a/src/base/base_math.h b/src/base/base_math.h new file mode 100644 index 00000000..b0c9d15d --- /dev/null +++ b/src/base/base_math.h @@ -0,0 +1,648 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_MATH_H +#define BASE_MATH_H + +//////////////////////////////// +//~ rjf: Vector Types + +//- rjf: 2-vectors + +typedef union Vec2F32 Vec2F32; +union Vec2F32 +{ + struct + { + F32 x; + F32 y; + }; + F32 v[2]; +}; + +typedef union Vec2S64 Vec2S64; +union Vec2S64 +{ + struct + { + S64 x; + S64 y; + }; + S64 v[2]; +}; + +typedef union Vec2S32 Vec2S32; +union Vec2S32 +{ + struct + { + S32 x; + S32 y; + }; + S32 v[2]; +}; + +typedef union Vec2S16 Vec2S16; +union Vec2S16 +{ + struct + { + S16 x; + S16 y; + }; + S16 v[2]; +}; + +//- rjf: 3-vectors + +typedef union Vec3F32 Vec3F32; +union Vec3F32 +{ + struct + { + F32 x; + F32 y; + F32 z; + }; + struct + { + Vec2F32 xy; + F32 _z0; + }; + struct + { + F32 _x0; + Vec2F32 yz; + }; + F32 v[3]; +}; + +typedef union Vec3S32 Vec3S32; +union Vec3S32 +{ + struct + { + S32 x; + S32 y; + S32 z; + }; + struct + { + Vec2S32 xy; + S32 _z0; + }; + struct + { + S32 _x0; + Vec2S32 yz; + }; + S32 v[3]; +}; + +//- rjf: 4-vectors + +typedef union Vec4F32 Vec4F32; +union Vec4F32 +{ + struct + { + F32 x; + F32 y; + F32 z; + F32 w; + }; + struct + { + Vec2F32 xy; + Vec2F32 zw; + }; + struct + { + Vec3F32 xyz; + F32 _z0; + }; + struct + { + F32 _x0; + Vec3F32 yzw; + }; + F32 v[4]; +}; + +typedef union Vec4S32 Vec4S32; +union Vec4S32 +{ + struct + { + S32 x; + S32 y; + S32 z; + S32 w; + }; + struct + { + Vec2S32 xy; + Vec2S32 zw; + }; + struct + { + Vec3S32 xyz; + S32 _z0; + }; + struct + { + S32 _x0; + Vec3S32 yzw; + }; + S32 v[4]; +}; + +//////////////////////////////// +//~ rjf: Matrix Types + +typedef struct Mat3x3F32 Mat3x3F32; +struct Mat3x3F32 +{ + F32 v[3][3]; +}; + +typedef struct Mat4x4F32 Mat4x4F32; +struct Mat4x4F32 +{ + F32 v[4][4]; +}; + +//////////////////////////////// +//~ rjf: Range Types + +//- rjf: 1-range + +typedef union Rng1U32 Rng1U32; +union Rng1U32 +{ + struct + { + U32 min; + U32 max; + }; + U32 v[2]; +}; + +typedef union Rng1S32 Rng1S32; +union Rng1S32 +{ + struct + { + S32 min; + S32 max; + }; + S32 v[2]; +}; + +typedef union Rng1U64 Rng1U64; +union Rng1U64 +{ + struct + { + U64 min; + U64 max; + }; + U64 v[2]; +}; + +typedef union Rng1S64 Rng1S64; +union Rng1S64 +{ + struct + { + S64 min; + S64 max; + }; + S64 v[2]; +}; + +typedef union Rng1F32 Rng1F32; +union Rng1F32 +{ + struct + { + F32 min; + F32 max; + }; + F32 v[2]; +}; + +//- rjf: 2-range (rectangles) + +typedef union Rng2S16 Rng2S16; +union Rng2S16 +{ + struct + { + Vec2S16 min; + Vec2S16 max; + }; + struct + { + Vec2S16 p0; + Vec2S16 p1; + }; + struct + { + S16 x0; + S16 y0; + S16 x1; + S16 y1; + }; + Vec2S16 v[2]; +}; + +typedef union Rng2S32 Rng2S32; +union Rng2S32 +{ + struct + { + Vec2S32 min; + Vec2S32 max; + }; + struct + { + Vec2S32 p0; + Vec2S32 p1; + }; + struct + { + S32 x0; + S32 y0; + S32 x1; + S32 y1; + }; + Vec2S32 v[2]; +}; + +typedef union Rng2F32 Rng2F32; +union Rng2F32 +{ + struct + { + Vec2F32 min; + Vec2F32 max; + }; + struct + { + Vec2F32 p0; + Vec2F32 p1; + }; + struct + { + F32 x0; + F32 y0; + F32 x1; + F32 y1; + }; + Vec2F32 v[2]; +}; + +typedef union Rng2S64 Rng2S64; +union Rng2S64 +{ + struct + { + Vec2S64 min; + Vec2S64 max; + }; + struct + { + Vec2S64 p0; + Vec2S64 p1; + }; + struct + { + S64 x0; + S64 y0; + S64 x1; + S64 y1; + }; + Vec2S64 v[2]; +}; + +//////////////////////////////// +//~ rjf: List Types + +typedef struct Rng1S64Node Rng1S64Node; +struct Rng1S64Node +{ + Rng1S64Node *next; + Rng1S64 v; +}; + +typedef struct Rng1S64List Rng1S64List; +struct Rng1S64List +{ + Rng1S64Node *first; + Rng1S64Node *last; + U64 count; +}; + +typedef struct Rng1S64Array Rng1S64Array; +struct Rng1S64Array +{ + Rng1S64 *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Scalar Ops + +#define abs_s64(v) (S64)llabs(v) + +#define sqrt_f32(v) sqrtf(v) +#define mod_f32(a, b) fmodf((a), (b)) +#define pow_f32(b, e) powf((b), (e)) +#define ceil_f32(v) ceilf(v) +#define floor_f32(v) floorf(v) +#define round_f32(v) roundf(v) +#define abs_f32(v) fabsf(v) +#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f) +#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f) +#define degrees_from_turns_f32(v) ((v)*360.f) +#define turns_from_degrees_f32(v) ((v)/360.f) +#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v))) +#define radians_from_degrees_f32(v) (radians_from_turns_f32(turns_from_degrees_f32(v))) +#define sin_f32(v) sinf(radians_from_turns_f32(v)) +#define cos_f32(v) cosf(radians_from_turns_f32(v)) +#define tan_f32(v) tanf(radians_from_turns_f32(v)) + +#define sqrt_f64(v) sqrt(v) +#define mod_f64(a, b) fmod((a), (b)) +#define pow_f64(b, e) pow((b), (e)) +#define ceil_f64(v) ceil(v) +#define floor_f64(v) floor(v) +#define round_f64(v) round(v) +#define abs_f64(v) fabs(v) +#define radians_from_turns_f64(v) ((v)*2*3.1415926535897) +#define turns_from_radians_f64(v) ((v)/2*3.1415926535897) +#define degrees_from_turns_f64(v) ((v)*360.0) +#define turns_from_degrees_f64(v) ((v)/360.0) +#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v))) +#define radians_from_degrees_f64(v) (radians_from_turns_f64(turns_from_degrees_f64(v))) +#define sin_f64(v) sin(radians_from_turns_f64(v)) +#define cos_f64(v) cos(radians_from_turns_f64(v)) +#define tan_f64(v) tan(radians_from_turns_f64(v)) + +internal F32 mix_1f32(F32 a, F32 b, F32 t); +internal F64 mix_1f64(F64 a, F64 b, F64 t); + +//////////////////////////////// +//~ rjf: Vector Ops + +#define v2f32(x, y) vec_2f32((x), (y)) +internal Vec2F32 vec_2f32(F32 x, F32 y); +internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 scale_2f32(Vec2F32 v, F32 s); +internal F32 dot_2f32(Vec2F32 a, Vec2F32 b); +internal F32 length_squared_2f32(Vec2F32 v); +internal F32 length_2f32(Vec2F32 v); +internal Vec2F32 normalize_2f32(Vec2F32 v); +internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t); + +#define v2s64(x, y) vec_2s64((x), (y)) +internal Vec2S64 vec_2s64(S64 x, S64 y); +internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 scale_2s64(Vec2S64 v, S64 s); +internal S64 dot_2s64(Vec2S64 a, Vec2S64 b); +internal S64 length_squared_2s64(Vec2S64 v); +internal S64 length_2s64(Vec2S64 v); +internal Vec2S64 normalize_2s64(Vec2S64 v); +internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t); + +#define v2s32(x, y) vec_2s32((x), (y)) +internal Vec2S32 vec_2s32(S32 x, S32 y); +internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 scale_2s32(Vec2S32 v, S32 s); +internal S32 dot_2s32(Vec2S32 a, Vec2S32 b); +internal S32 length_squared_2s32(Vec2S32 v); +internal S32 length_2s32(Vec2S32 v); +internal Vec2S32 normalize_2s32(Vec2S32 v); +internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t); + +#define v2s16(x, y) vec_2s16((x), (y)) +internal Vec2S16 vec_2s16(S16 x, S16 y); +internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 scale_2s16(Vec2S16 v, S16 s); +internal S16 dot_2s16(Vec2S16 a, Vec2S16 b); +internal S16 length_squared_2s16(Vec2S16 v); +internal S16 length_2s16(Vec2S16 v); +internal Vec2S16 normalize_2s16(Vec2S16 v); +internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t); + +#define v3f32(x, y, z) vec_3f32((x), (y), (z)) +internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z); +internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 scale_3f32(Vec3F32 v, F32 s); +internal F32 dot_3f32(Vec3F32 a, Vec3F32 b); +internal F32 length_squared_3f32(Vec3F32 v); +internal F32 length_3f32(Vec3F32 v); +internal Vec3F32 normalize_3f32(Vec3F32 v); +internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t); +internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b); + +#define v3s32(x, y, z) vec_3s32((x), (y), (z)) +internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z); +internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 scale_3s32(Vec3S32 v, S32 s); +internal S32 dot_3s32(Vec3S32 a, Vec3S32 b); +internal S32 length_squared_3s32(Vec3S32 v); +internal S32 length_3s32(Vec3S32 v); +internal Vec3S32 normalize_3s32(Vec3S32 v); +internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t); +internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b); + +#define v4f32(x, y, z, w) vec_4f32((x), (y), (z), (w)) +internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w); +internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 scale_4f32(Vec4F32 v, F32 s); +internal F32 dot_4f32(Vec4F32 a, Vec4F32 b); +internal F32 length_squared_4f32(Vec4F32 v); +internal F32 length_4f32(Vec4F32 v); +internal Vec4F32 normalize_4f32(Vec4F32 v); +internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t); + +#define v4s32(x, y, z, w) vec_4s32((x), (y), (z), (w)) +internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w); +internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 scale_4s32(Vec4S32 v, S32 s); +internal S32 dot_4s32(Vec4S32 a, Vec4S32 b); +internal S32 length_squared_4s32(Vec4S32 v); +internal S32 length_4s32(Vec4S32 v); +internal Vec4S32 normalize_4s32(Vec4S32 v); +internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t); + +//////////////////////////////// +//~ rjf: Matrix Ops + +internal Mat3x3F32 mat_3x3f32(F32 diagonal); +internal Mat3x3F32 make_translate_3x3f32(Vec2F32 delta); +internal Mat3x3F32 mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b); + +internal Mat4x4F32 mat_4x4f32(F32 diagonal); +internal Mat4x4F32 make_translate_4x4f32(Vec3F32 delta); +internal Mat4x4F32 make_scale_4x4f32(Vec3F32 scale); +internal Mat4x4F32 make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z); +internal Mat4x4F32 make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z); +internal Mat4x4F32 make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up); +internal Mat4x4F32 make_rotate_4x4f32(Vec3F32 axis, F32 turns); +internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b); +internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale); +internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m); +internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat); + +//////////////////////////////// +//~ rjf: Range Ops + +#define r1u32(min, max) rng_1u32((min), (max)) +internal Rng1U32 rng_1u32(U32 min, U32 max); +internal Rng1U32 shift_1u32(Rng1U32 r, U32 x); +internal Rng1U32 pad_1u32(Rng1U32 r, U32 x); +internal U32 center_1u32(Rng1U32 r); +internal B32 contains_1u32(Rng1U32 r, U32 x); +internal U32 dim_1u32(Rng1U32 r); +internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b); +internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b); +internal U32 clamp_1u32(Rng1U32 r, U32 v); + +#define r1s32(min, max) rng_1s32((min), (max)) +internal Rng1S32 rng_1s32(S32 min, S32 max); +internal Rng1S32 shift_1s32(Rng1S32 r, S32 x); +internal Rng1S32 pad_1s32(Rng1S32 r, S32 x); +internal S32 center_1s32(Rng1S32 r); +internal B32 contains_1s32(Rng1S32 r, S32 x); +internal S32 dim_1s32(Rng1S32 r); +internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b); +internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b); +internal S32 clamp_1s32(Rng1S32 r, S32 v); + +#define r1u64(min, max) rng_1u64((min), (max)) +internal Rng1U64 rng_1u64(U64 min, U64 max); +internal Rng1U64 shift_1u64(Rng1U64 r, U64 x); +internal Rng1U64 pad_1u64(Rng1U64 r, U64 x); +internal U64 center_1u64(Rng1U64 r); +internal B32 contains_1u64(Rng1U64 r, U64 x); +internal U64 dim_1u64(Rng1U64 r); +internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b); +internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b); +internal U64 clamp_1u64(Rng1U64 r, U64 v); + +#define r1s64(min, max) rng_1s64((min), (max)) +internal Rng1S64 rng_1s64(S64 min, S64 max); +internal Rng1S64 shift_1s64(Rng1S64 r, S64 x); +internal Rng1S64 pad_1s64(Rng1S64 r, S64 x); +internal S64 center_1s64(Rng1S64 r); +internal B32 contains_1s64(Rng1S64 r, S64 x); +internal S64 dim_1s64(Rng1S64 r); +internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b); +internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b); +internal S64 clamp_1s64(Rng1S64 r, S64 v); + +#define r1f32(min, max) rng_1f32((min), (max)) +internal Rng1F32 rng_1f32(F32 min, F32 max); +internal Rng1F32 shift_1f32(Rng1F32 r, F32 x); +internal Rng1F32 pad_1f32(Rng1F32 r, F32 x); +internal F32 center_1f32(Rng1F32 r); +internal B32 contains_1f32(Rng1F32 r, F32 x); +internal F32 dim_1f32(Rng1F32 r); +internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b); +internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b); +internal F32 clamp_1f32(Rng1F32 r, F32 v); + +#define r2s16(min, max) rng_2s16((min), (max)) +#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w))) +internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max); +internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x); +internal Rng2S16 pad_2s16(Rng2S16 r, S16 x); +internal Vec2S16 center_2s16(Rng2S16 r); +internal B32 contains_2s16(Rng2S16 r, Vec2S16 x); +internal Vec2S16 dim_2s16(Rng2S16 r); +internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b); +internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b); +internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v); + +#define r2s32(min, max) rng_2s32((min), (max)) +#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w))) +internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max); +internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x); +internal Rng2S32 pad_2s32(Rng2S32 r, S32 x); +internal Vec2S32 center_2s32(Rng2S32 r); +internal B32 contains_2s32(Rng2S32 r, Vec2S32 x); +internal Vec2S32 dim_2s32(Rng2S32 r); +internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b); +internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b); +internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v); + +#define r2s64(min, max) rng_2s64((min), (max)) +#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w))) +internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max); +internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x); +internal Rng2S64 pad_2s64(Rng2S64 r, S64 x); +internal Vec2S64 center_2s64(Rng2S64 r); +internal B32 contains_2s64(Rng2S64 r, Vec2S64 x); +internal Vec2S64 dim_2s64(Rng2S64 r); +internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b); +internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b); +internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v); + +#define r2f32(min, max) rng_2f32((min), (max)) +#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w))) +internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max); +internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x); +internal Rng2F32 pad_2f32(Rng2F32 r, F32 x); +internal Vec2F32 center_2f32(Rng2F32 r); +internal B32 contains_2f32(Rng2F32 r, Vec2F32 x); +internal Vec2F32 dim_2f32(Rng2F32 r); +internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b); +internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b); +internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v); + +//////////////////////////////// +//~ rjf: Miscellaneous Ops + +internal Vec3F32 hsv_from_rgb(Vec3F32 rgb); +internal Vec3F32 rgb_from_hsv(Vec3F32 hsv); +internal Vec4F32 hsva_from_rgba(Vec4F32 rgba); +internal Vec4F32 rgba_from_hsva(Vec4F32 hsva); +internal Vec4F32 rgba_from_u32(U32 hex); +internal U32 u32_from_rgba(Vec4F32 rgba); + +#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f } + +//////////////////////////////// +//~ rjf: List Type Functions + +internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); +internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); + +#endif // BASE_MATH_H diff --git a/src/base/base_string.c b/src/base/base_string.c new file mode 100644 index 00000000..ac974599 --- /dev/null +++ b/src/base/base_string.c @@ -0,0 +1,1878 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Third Party Includes + +#if !SUPPLEMENT_UNIT +# define STB_SPRINTF_IMPLEMENTATION +# define STB_SPRINTF_STATIC +# include "third_party/stb/stb_sprintf.h" +#endif + +//////////////////////////////// +//~ NOTE(allen): String <-> Integer Tables + +read_only global U8 integer_symbols[16] = { + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', +}; + +// NOTE(allen): Includes reverses for uppercase and lowercase hex. +read_only global U8 integer_symbol_reverse[128] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +}; + +read_only global U8 base64[64] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '_', '$', +}; + +read_only global U8 base64_reverse[128] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32, + 0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, + 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF, +}; + +//////////////////////////////// +//~ rjf: Character Classification & Conversion Functions + +internal B32 +char_is_space(U8 c){ + return(c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'); +} + +internal B32 +char_is_upper(U8 c){ + return('A' <= c && c <= 'Z'); +} + +internal B32 +char_is_lower(U8 c){ + return('a' <= c && c <= 'z'); +} + +internal B32 +char_is_alpha(U8 c){ + return(char_is_upper(c) || char_is_lower(c)); +} + +internal B32 +char_is_slash(U8 c){ + return(c == '/' || c == '\\'); +} + +internal B32 +char_is_digit(U8 c, U32 base){ + B32 result = 0; + if (0 < base && base <= 16){ + U8 val = integer_symbol_reverse[c]; + if (val < base){ + result = 1; + } + } + return(result); +} + +internal U8 +char_to_lower(U8 c){ + if (char_is_upper(c)){ + c += ('a' - 'A'); + } + return(c); +} + +internal U8 +char_to_upper(U8 c){ + if (char_is_lower(c)){ + c += ('A' - 'a'); + } + return(c); +} + +internal U8 +char_to_correct_slash(U8 c){ + if(char_is_slash(c)){ + c = '/'; + } + return(c); +} + +//////////////////////////////// +//~ rjf: C-String Measurement + +internal U64 +cstring8_length(U8 *c){ + U8 *p = c; + for (;*p != 0; p += 1); + return(p - c); +} + +internal U64 +cstring16_length(U16 *c){ + U16 *p = c; + for (;*p != 0; p += 1); + return(p - c); +} + +internal U64 +cstring32_length(U32 *c){ + U32 *p = c; + for (;*p != 0; p += 1); + return(p - c); +} + +//////////////////////////////// +//~ rjf: String Constructors + +internal String8 +str8(U8 *str, U64 size){ + String8 result = {str, size}; + return(result); +} + +internal String8 +str8_range(U8 *first, U8 *one_past_last){ + String8 result = {first, (U64)(one_past_last - first)}; + return(result); +} + +internal String8 +str8_zero(void){ + String8 result = {0}; + return(result); +} + +internal String16 +str16(U16 *str, U64 size){ + String16 result = {str, size}; + return(result); +} + +internal String16 +str16_range(U16 *first, U16 *one_past_last){ + String16 result = {first, (U64)(one_past_last - first)}; + return(result); +} + +internal String16 +str16_zero(void){ + String16 result = {0}; + return(result); +} + +internal String32 +str32(U32 *str, U64 size){ + String32 result = {str, size}; + return(result); +} + +internal String32 +str32_range(U32 *first, U32 *one_past_last){ + String32 result = {first, (U64)(one_past_last - first)}; + return(result); +} + +internal String32 +str32_zero(void){ + String32 result = {0}; + return(result); +} + +internal String8 +str8_cstring(char *c){ + String8 result = {(U8*)c, cstring8_length((U8*)c)}; + return(result); +} + +internal String16 +str16_cstring(U16 *c){ + String16 result = {(U16*)c, cstring16_length((U16*)c)}; + return(result); +} + +internal String32 +str32_cstring(U32 *c){ + String32 result = {(U32*)c, cstring32_length((U32*)c)}; + return(result); +} + +internal String8 +str8_cstring_capped(void *cstr, void *cap) +{ + char *ptr = (char*)cstr; + char *opl = (char*)cap; + for (;ptr < opl && *ptr != 0; ptr += 1); + U64 size = (U64)(ptr - (char *)cstr); + String8 result = {(U8*)cstr, size}; + return(result); +} + +//////////////////////////////// +//~ rjf: String Stylization + +internal String8 +upper_from_str8(Arena *arena, String8 string) +{ + string = push_str8_copy(arena, string); + for(U64 idx = 0; idx < string.size; idx += 1) + { + string.str[idx] = char_to_upper(string.str[idx]); + } + return string; +} + +internal String8 +lower_from_str8(Arena *arena, String8 string) +{ + string = push_str8_copy(arena, string); + for(U64 idx = 0; idx < string.size; idx += 1) + { + string.str[idx] = char_to_lower(string.str[idx]); + } + return string; +} + +internal String8 +backslashed_from_str8(Arena *arena, String8 string) +{ + string = push_str8_copy(arena, string); + for(U64 idx = 0; idx < string.size; idx += 1) + { + string.str[idx] = char_is_slash(string.str[idx]) ? '\\' : string.str[idx]; + } + return string; +} + +//////////////////////////////// +//~ rjf: String Matching + +internal B32 +str8_match(String8 a, String8 b, StringMatchFlags flags){ + B32 result = 0; + if (a.size == b.size || (flags & StringMatchFlag_RightSideSloppy)){ + B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive); + B32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive); + U64 size = Min(a.size, b.size); + result = 1; + for (U64 i = 0; i < size; i += 1){ + U8 at = a.str[i]; + U8 bt = b.str[i]; + if (case_insensitive){ + at = char_to_upper(at); + bt = char_to_upper(bt); + } + if (slash_insensitive){ + at = char_to_correct_slash(at); + bt = char_to_correct_slash(bt); + } + if (at != bt){ + result = 0; + break; + } + } + } + return(result); +} + +internal U64 +str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags){ + U8 *p = string.str + start_pos; + U64 stop_offset = Max(string.size + 1, needle.size) - needle.size; + U8 *stop_p = string.str + stop_offset; + if (needle.size > 0){ + U8 *string_opl = string.str + string.size; + String8 needle_tail = str8_skip(needle, 1); + StringMatchFlags adjusted_flags = flags | StringMatchFlag_RightSideSloppy; + U8 needle_first_char_adjusted = needle.str[0]; + if(adjusted_flags & StringMatchFlag_CaseInsensitive){ + needle_first_char_adjusted = char_to_upper(needle_first_char_adjusted); + } + for (;p < stop_p; p += 1){ + U8 haystack_char_adjusted = *p; + if(adjusted_flags & StringMatchFlag_CaseInsensitive){ + haystack_char_adjusted = char_to_upper(haystack_char_adjusted); + } + if (haystack_char_adjusted == needle_first_char_adjusted){ + if (str8_match(str8_range(p + 1, string_opl), needle_tail, adjusted_flags)){ + break; + } + } + } + } + U64 result = string.size; + if (p < stop_p){ + result = (U64)(p - string.str); + } + return(result); +} + +internal B32 +str8_ends_with(String8 string, String8 end, StringMatchFlags flags){ + String8 postfix = str8_postfix(string, end.size); + B32 is_match = str8_match(end, postfix, flags); + return is_match; +} + +//////////////////////////////// +//~ rjf: String Slicing + +internal String8 +str8_substr(String8 str, Rng1U64 range){ + range.min = ClampTop(range.min, str.size); + range.max = ClampTop(range.max, str.size); + str.str += range.min; + str.size = dim_1u64(range); + return(str); +} + +internal String8 +str8_prefix(String8 str, U64 size){ + str.size = ClampTop(size, str.size); + return(str); +} + +internal String8 +str8_skip(String8 str, U64 amt){ + amt = ClampTop(amt, str.size); + str.str += amt; + str.size -= amt; + return(str); +} + +internal String8 +str8_postfix(String8 str, U64 size){ + size = ClampTop(size, str.size); + str.str = (str.str + str.size) - size; + str.size = size; + return(str); +} + +internal String8 +str8_chop(String8 str, U64 amt){ + amt = ClampTop(amt, str.size); + str.size -= amt; + return(str); +} + +internal String8 +str8_skip_chop_whitespace(String8 string){ + U8 *first = string.str; + U8 *opl = first + string.size; + for (;first < opl; first += 1){ + if (!char_is_space(*first)){ + break; + } + } + for (;opl > first;){ + opl -= 1; + if (!char_is_space(*opl)){ + opl += 1; + break; + } + } + String8 result = str8_range(first, opl); + return(result); +} + +//////////////////////////////// +//~ rjf: String Formatting & Copying + +internal String8 +push_str8_cat(Arena *arena, String8 s1, String8 s2){ + String8 str; + str.size = s1.size + s2.size; + str.str = push_array_no_zero(arena, U8, str.size + 1); + MemoryCopy(str.str, s1.str, s1.size); + MemoryCopy(str.str + s1.size, s2.str, s2.size); + str.str[str.size] = 0; + return(str); +} + +internal String8 +push_str8_copy(Arena *arena, String8 s){ + //ProfBeginFunction(); + String8 str; + str.size = s.size; + str.str = push_array_no_zero(arena, U8, str.size + 1); + MemoryCopy(str.str, s.str, s.size); + str.str[str.size] = 0; + //ProfEnd(); + return(str); +} + +internal String8 +push_str8fv(Arena *arena, char *fmt, va_list args){ + va_list args2; + va_copy(args2, args); + U32 needed_bytes = raddbg_vsnprintf(0, 0, fmt, args) + 1; + String8 result = {0}; + result.str = push_array_no_zero(arena, U8, needed_bytes); + result.size = raddbg_vsnprintf((char*)result.str, needed_bytes, fmt, args2); + result.str[result.size] = 0; + va_end(args2); + return(result); +} + +internal String8 +push_str8f(Arena *arena, char *fmt, ...){ + va_list args; + va_start(args, fmt); + String8 result = push_str8fv(arena, fmt, args); + va_end(args); + return(result); +} + +//////////////////////////////// +//~ rjf: String <=> Integer Conversions + +//- rjf: string -> integer + +internal S64 +sign_from_str8(String8 string, String8 *string_tail){ + // count negative signs + U64 neg_count = 0; + U64 i = 0; + for (; i < string.size; i += 1){ + if (string.str[i] == '-'){ + neg_count += 1; + } + else if (string.str[i] != '+'){ + break; + } + } + + // output part of string after signs + *string_tail = str8_skip(string, i); + + // output integer sign + S64 sign = (neg_count & 1)?-1:+1; + return(sign); +} + +internal B32 +str8_is_integer(String8 string, U32 radix){ + B32 result = 0; + if (string.size > 0){ + if (1 < radix && radix <= 16){ + result = 1; + for (U64 i = 0; i < string.size; i += 1){ + U8 c = string.str[i]; + if (!(c < 0x80) || integer_symbol_reverse[c] >= radix){ + result = 0; + break; + } + } + } + } + return(result); +} + +internal U64 +u64_from_str8(String8 string, U32 radix){ + U64 x = 0; + if (1 < radix && radix <= 16){ + for (U64 i = 0; i < string.size; i += 1){ + x *= radix; + x += integer_symbol_reverse[string.str[i]&0x7F]; + } + } + return(x); +} + +internal S64 +s64_from_str8(String8 string, U32 radix){ + S64 sign = sign_from_str8(string, &string); + S64 x = (S64)u64_from_str8(string, radix) * sign; + return(x); +} + +internal B32 +try_u64_from_str8_c_rules(String8 string, U64 *x){ + B32 is_integer = 0; + if (str8_is_integer(string, 10)){ + is_integer = 1; + *x = u64_from_str8(string, 10); + } + else{ + String8 hex_string = str8_skip(string, 2); + if (str8_match(str8_prefix(string, 2), str8_lit("0x"), 0) && + str8_is_integer(hex_string, 0x10)){ + is_integer = 1; + *x = u64_from_str8(hex_string, 0x10); + } + else if (str8_match(str8_prefix(string, 2), str8_lit("0b"), 0) && + str8_is_integer(hex_string, 2)){ + is_integer = 1; + *x = u64_from_str8(hex_string, 2); + } + else{ + String8 oct_string = str8_skip(string, 1); + if (str8_match(str8_prefix(string, 1), str8_lit("0"), 0) && + str8_is_integer(hex_string, 010)){ + is_integer = 1; + *x = u64_from_str8(oct_string, 010); + } + } + } + return(is_integer); +} + +internal B32 +try_s64_from_str8_c_rules(String8 string, S64 *x){ + String8 string_tail = {0}; + S64 sign = sign_from_str8(string, &string_tail); + U64 x_u64 = 0; + B32 is_integer = try_u64_from_str8_c_rules(string_tail, &x_u64); + *x = x_u64*sign; + return(is_integer); +} + +//- rjf: string -> integer (base64 & base16) + +internal U64 +base64_size_from_data_size(U64 size_in_bytes){ + U64 bits = size_in_bytes*8; + U64 base64_size = (bits + 5)/6; + return(base64_size); +} + +internal U64 +base64_from_data(U8 *dst, U8 *src, U64 src_size){ + U8 *dst_base = dst; + U8 *opl = src + src_size; + U32 bit_num = 0; + if (src < opl){ + U8 byte = *src; + for (;;){ + U32 x = 0; + for (U32 i = 0; i < 6; i += 1){ + x |= ((byte >> bit_num) & 1) << i; + bit_num += 1; + if (bit_num == 8){ + bit_num = 0; + src += 1; + byte = (src < opl)?(*src):0; + } + } + *dst = base64[x]; + dst += 1; + if (src >= opl){ + break; + } + } + } + return(dst - dst_base); +} + +internal U64 +base16_size_from_data_size(U64 size_in_bytes){ + U64 base16_size = size_in_bytes*2; + return(base16_size); +} + +internal U64 +base16_from_data(U8 *dst, U8 *src, U64 src_size){ + U8 *dst_base = dst; + U8 *opl = src + src_size; + for (;src < opl;){ + U8 byte = *src; + *dst = integer_symbols[byte & 0xF]; + dst += 1; + *dst = integer_symbols[byte >> 4]; + dst += 1; + src += 1; + } + return(dst - dst_base); +} + +//- rjf: integer -> string + +internal String8 +str8_from_memory_size(Arena *arena, U64 z){ + String8 result = {0}; + if (z < KB(1)){ + result = push_str8f(arena, "%llu b", z); + } + else if (z < MB(1)){ + result = push_str8f(arena, "%llu.%02llu Kb", z/KB(1), ((100*z)/KB(1))%100); + } + else if (z < GB(1)){ + result = push_str8f(arena, "%llu.%02llu Mb", z/MB(1), ((100*z)/MB(1))%100); + } + else{ + result = push_str8f(arena, "%llu.%02llu Gb", z/GB(1), ((100*z)/GB(1))%100); + } + return(result); +} + +internal String8 +str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator) +{ + String8 result = {0}; + { + // rjf: prefix + String8 prefix = {0}; + switch(radix) + { + case 16:{prefix = str8_lit("0x");}break; + case 8: {prefix = str8_lit("0o");}break; + case 2: {prefix = str8_lit("0b");}break; + } + + // rjf: determine # of chars between separators + U8 digit_group_size = 3; + switch(radix) + { + default:break; + case 2: + case 8: + case 16: + {digit_group_size = 4;}break; + } + + // rjf: prep + U64 needed_leading_0s = 0; + { + U64 needed_digits = 1; + { + U64 u64_reduce = u64; + for(;;) + { + u64_reduce /= radix; + if(u64_reduce == 0) + { + break; + } + needed_digits += 1; + } + } + needed_leading_0s = (min_digits > needed_digits) ? min_digits - needed_digits : 0; + U64 needed_separators = 0; + if(digit_group_separator != 0) + { + needed_separators = (needed_digits+needed_leading_0s)/digit_group_size; + if(needed_separators > 0 && (needed_digits+needed_leading_0s)%digit_group_size == 0) + { + needed_separators -= 1; + } + } + result.size = prefix.size + needed_leading_0s + needed_separators + needed_digits; + result.str = push_array_no_zero(arena, U8, result.size + 1); + result.str[result.size] = 0; + } + + // rjf: fill contents + { + U64 u64_reduce = u64; + U64 digits_until_separator = digit_group_size; + for(U64 idx = 0; idx < result.size; idx += 1) + { + if(digits_until_separator == 0 && digit_group_separator != 0) + { + result.str[result.size - idx - 1] = digit_group_separator; + digits_until_separator = digit_group_size+1; + } + else + { + result.str[result.size - idx - 1] = char_to_lower(integer_symbols[u64_reduce%radix]); + u64_reduce /= radix; + } + digits_until_separator -= 1; + if(u64_reduce == 0) + { + break; + } + } + for(U64 leading_0_idx = 0; leading_0_idx < needed_leading_0s; leading_0_idx += 1) + { + result.str[prefix.size + leading_0_idx] = '0'; + } + } + + // rjf: fill prefix + if(prefix.size != 0) + { + MemoryCopy(result.str, prefix.str, prefix.size); + } + } + return result; +} + +internal String8 +str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator) +{ + String8 result = {0}; + // TODO(rjf): preeeeetty sloppy... + if(s64 < 0) + { + Temp scratch = scratch_begin(&arena, 1); + String8 numeric_part = str8_from_u64(scratch.arena, (U64)(-s64), radix, min_digits, digit_group_separator); + result = push_str8f(arena, "-%S", numeric_part); + scratch_end(scratch); + } + else + { + result = str8_from_u64(arena, (U64)s64, radix, min_digits, digit_group_separator); + } + return result; +} + +//////////////////////////////// +//~ rjf: String <=> Float Conversions + +internal F64 +f64_from_str8(String8 string) +{ + // TODO(rjf): crappy implementation for now that just uses atof. + F64 result = 0; + if(string.size > 0) + { + // rjf: find starting pos of numeric string, as well as sign + F64 sign = +1.0; + //U64 first_numeric = 0; + if(string.str[0] == '-') + { + //first_numeric = 1; + sign = -1.0; + } + else if(string.str[0] == '+') + { + //first_numeric = 1; + sign = 1.0; + } + + // rjf: gather numerics + U64 num_valid_chars = 0; + char buffer[64]; + for(U64 idx = 0; idx < string.size && num_valid_chars < sizeof(buffer)-1; idx += 1) + { + if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.') + { + buffer[num_valid_chars] = string.str[idx]; + num_valid_chars += 1; + } + } + + // rjf: null-terminate (the reason for all of this!!!!!!) + buffer[num_valid_chars] = 0; + + // rjf: do final conversion + result = sign * atof(buffer); + } + return result; +} + +//////////////////////////////// +//~ rjf: String List Construction Functions + +internal String8Node* +str8_list_push_node(String8List *list, String8Node *node){ + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size += node->string.size; + return(node); +} + +internal String8Node* +str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string){ + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size += string.size; + node->string = string; + return(node); +} + +internal String8Node* +str8_list_push_node_front(String8List *list, String8Node *node){ + SLLQueuePushFront(list->first, list->last, node); + list->node_count += 1; + list->total_size += node->string.size; + return(node); +} + +internal String8Node* +str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string){ + SLLQueuePushFront(list->first, list->last, node); + list->node_count += 1; + list->total_size += string.size; + node->string = string; + return(node); +} + +internal String8Node* +str8_list_push(Arena *arena, String8List *list, String8 string){ + String8Node *node = push_array_no_zero(arena, String8Node, 1); + str8_list_push_node_set_string(list, node, string); + return(node); +} + +internal String8Node* +str8_list_push_front(Arena *arena, String8List *list, String8 string){ + String8Node *node = push_array_no_zero(arena, String8Node, 1); + str8_list_push_node_front_set_string(list, node, string); + return(node); +} + +internal void +str8_list_concat_in_place(String8List *list, String8List *to_push){ + if(to_push->node_count != 0){ + if (list->last){ + list->node_count += to_push->node_count; + list->total_size += to_push->total_size; + list->last->next = to_push->first; + list->last = to_push->last; + } + else{ + *list = *to_push; + } + MemoryZeroStruct(to_push); + } +} + +internal String8Node* +str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){ + String8Node *node = push_array_no_zero(arena, String8Node, 1); + U64 new_size = list->total_size + min; + U64 increase_size = 0; + if (align > 1){ + // NOTE(allen): assert is power of 2 + Assert(((align - 1) & align) == 0); + U64 mask = align - 1; + new_size += mask; + new_size &= (~mask); + increase_size = new_size - list->total_size; + } + local_persist const U8 zeroes_buffer[64] = {0}; + Assert(increase_size <= ArrayCount(zeroes_buffer)); + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size = new_size; + node->string.str = (U8*)zeroes_buffer; + node->string.size = increase_size; + return(node); +} + +internal String8Node* +str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...){ + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(arena, fmt, args); + String8Node *result = str8_list_push(arena, list, string); + va_end(args); + return(result); +} + +internal String8Node* +str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...){ + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(arena, fmt, args); + String8Node *result = str8_list_push_front(arena, list, string); + va_end(args); + return(result); +} + +internal String8List +str8_list_copy(Arena *arena, String8List *list){ + String8List result = {0}; + for (String8Node *node = list->first; + node != 0; + node = node->next){ + String8Node *new_node = push_array_no_zero(arena, String8Node, 1); + String8 new_string = push_str8_copy(arena, node->string); + str8_list_push_node_set_string(&result, new_node, new_string); + } + return(result); +} + +internal String8List +str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags){ + String8List list = {0}; + + B32 keep_empties = (flags & StringSplitFlag_KeepEmpties); + + U8 *ptr = string.str; + U8 *opl = string.str + string.size; + for (;ptr < opl;){ + U8 *first = ptr; + for (;ptr < opl; ptr += 1){ + U8 c = *ptr; + B32 is_split = 0; + for (U64 i = 0; i < split_char_count; i += 1){ + if (split_chars[i] == c){ + is_split = 1; + break; + } + } + if (is_split){ + break; + } + } + + String8 string = str8_range(first, ptr); + if (keep_empties || string.size > 0){ + str8_list_push(arena, &list, string); + } + ptr += 1; + } + + return(list); +} + +internal String8List +str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags){ + String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); + return list; +} + +internal String8List +str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags){ + String8List result = {0}; + for (String8Node *node = list.first; node != 0; node = node->next){ + String8List split = str8_split_by_string_chars(arena, node->string, split_chars, flags); + str8_list_concat_in_place(&result, &split); + } + return result; +} + +internal String8 +str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params){ + StringJoin join = {0}; + if (optional_params != 0){ + MemoryCopyStruct(&join, optional_params); + } + + U64 sep_count = 0; + if (list->node_count > 0){ + sep_count = list->node_count - 1; + } + + String8 result; + result.size = join.pre.size + join.post.size + sep_count*join.sep.size + list->total_size; + U8 *ptr = result.str = push_array_no_zero(arena, U8, result.size + 1); + + MemoryCopy(ptr, join.pre.str, join.pre.size); + ptr += join.pre.size; + for (String8Node *node = list->first; + node != 0; + node = node->next){ + MemoryCopy(ptr, node->string.str, node->string.size); + ptr += node->string.size; + if (node->next != 0){ + MemoryCopy(ptr, join.sep.str, join.sep.size); + ptr += join.sep.size; + } + } + MemoryCopy(ptr, join.post.str, join.post.size); + ptr += join.post.size; + + *ptr = 0; + + return(result); +} + +internal void +str8_list_from_flags(Arena *arena, String8List *list, + U32 flags, String8 *flag_string_table, U32 flag_string_count){ + for (U32 i = 0; i < flag_string_count; i += 1){ + U32 flag = (1 << i); + if (flags & flag){ + str8_list_push(arena, list, flag_string_table[i]); + } + } +} + +//////////////////////////////// +//~ rjf; String Arrays + +internal String8Array +str8_array_from_list(Arena *arena, String8List *list) +{ + String8Array array; + array.count = list->node_count; + array.strings = push_array_no_zero(arena, String8, array.count); + U64 idx = 0; + for(String8Node *n = list->first; n != 0; n = n->next, idx += 1) + { + array.strings[idx] = n->string; + } + return array; +} + +internal String8Array +str8_array_reserve(Arena *arena, U64 count) +{ + String8Array arr; + arr.count = 0; + arr.strings = push_array(arena, String8, count); + return arr; +} + +//////////////////////////////// +//~ rjf: String Path Helpers + +internal String8 +str8_chop_last_slash(String8 string){ + if (string.size > 0){ + U8 *ptr = string.str + string.size - 1; + for (;ptr >= string.str; ptr -= 1){ + if (*ptr == '/' || *ptr == '\\'){ + break; + } + } + if (ptr >= string.str){ + string.size = (U64)(ptr - string.str); + } + else{ + string.size = 0; + } + } + return(string); +} + +internal String8 +str8_skip_last_slash(String8 string){ + if (string.size > 0){ + U8 *ptr = string.str + string.size - 1; + for (;ptr >= string.str; ptr -= 1){ + if (*ptr == '/' || *ptr == '\\'){ + break; + } + } + if (ptr >= string.str){ + ptr += 1; + string.size = (U64)(string.str + string.size - ptr); + string.str = ptr; + } + } + return(string); +} + +internal String8 +str8_chop_last_dot(String8 string) +{ + String8 result = string; + U64 p = string.size; + for (;p > 0;){ + p -= 1; + if (string.str[p] == '.'){ + result = str8_prefix(string, p); + break; + } + } + return(result); +} + +internal String8 +str8_skip_last_dot(String8 string){ + String8 result = string; + U64 p = string.size; + for (;p > 0;){ + p -= 1; + if (string.str[p] == '.'){ + result = str8_skip(string, p + 1); + break; + } + } + return(result); +} + +internal PathStyle +path_style_from_str8(String8 string){ + PathStyle result = PathStyle_Relative; + if (string.size >= 1 && string.str[0] == '/'){ + result = PathStyle_UnixAbsolute; + } + else if (string.size >= 2 && + char_is_alpha(string.str[0]) && + string.str[1] == ':'){ + if (string.size == 2 || + char_is_slash(string.str[2])){ + result = PathStyle_WindowsAbsolute; + } + } + return(result); +} + +internal String8List +str8_split_path(Arena *arena, String8 string){ + String8List result = str8_split(arena, string, (U8*)"/\\", 2, 0); + return(result); +} + +internal void +str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){ + Temp scratch = scratch_begin(0, 0); + + String8MetaNode *stack = 0; + String8MetaNode *free_meta_node = 0; + String8Node *first = path->first; + + MemoryZeroStruct(path); + for (String8Node *node = first, *next = 0; + node != 0; + node = next){ + // save next now + next = node->next; + + // cases: + if (node == first && style == PathStyle_WindowsAbsolute){ + goto save_without_stack; + } + if (node->string.size == 1 && node->string.str[0] == '.'){ + goto do_nothing; + } + if (node->string.size == 2 && node->string.str[0] == '.' && node->string.str[1] == '.'){ + if (stack != 0){ + goto eliminate_stack_top; + } + else{ + goto save_without_stack; + } + } + goto save_with_stack; + + + // handlers: + save_with_stack: + { + str8_list_push_node(path, node); + + String8MetaNode *stack_node = free_meta_node; + if (stack_node != 0){ + SLLStackPop(free_meta_node); + } + else{ + stack_node = push_array_no_zero(scratch.arena, String8MetaNode, 1); + } + SLLStackPush(stack, stack_node); + stack_node->node = node; + + continue; + } + + save_without_stack: + { + str8_list_push_node(path, node); + + continue; + } + + eliminate_stack_top: + { + path->node_count -= 1; + path->total_size -= stack->node->string.size; + + SLLStackPop(stack); + + if (stack == 0){ + path->last = path->first; + } + else{ + path->last = stack->node; + } + continue; + } + + do_nothing: continue; + } + scratch_end(scratch); +} + +internal String8 +str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){ + StringJoin params = {0}; + switch (style){ + case PathStyle_Relative: + case PathStyle_WindowsAbsolute: + { + params.sep = str8_lit("/"); + }break; + + case PathStyle_UnixAbsolute: + { + params.pre = str8_lit("/"); + params.sep = str8_lit("/"); + }break; + } + + String8 result = str8_list_join(arena, path, ¶ms); + return(result); +} + +internal String8TxtPtPair +str8_txt_pt_pair_from_string(String8 string) +{ + String8TxtPtPair pair = {0}; + { + String8 file_part = {0}; + String8 line_part = {0}; + String8 col_part = {0}; + + // rjf: grab file part + for(U64 idx = 0; idx <= string.size; idx += 1) + { + U8 byte = (idx < string.size) ? (string.str[idx]) : 0; + U8 next_byte = ((idx+1 < string.size) ? (string.str[idx+1]) : 0); + if(byte == ':' && next_byte != '/' && next_byte != '\\') + { + file_part = str8_prefix(string, idx); + line_part = str8_skip(string, idx+1); + break; + } + else if(byte == 0) + { + file_part = string; + break; + } + } + + // rjf: grab line/column + { + U64 colon_pos = str8_find_needle(line_part, 0, str8_lit(":"), 0); + if(colon_pos < line_part.size) + { + col_part = str8_skip(line_part, colon_pos+1); + line_part = str8_prefix(line_part, colon_pos); + } + } + + // rjf: convert line/column strings to numerics + U64 line = 0; + U64 column = 0; + try_u64_from_str8_c_rules(line_part, &line); + try_u64_from_str8_c_rules(col_part, &column); + + // rjf: fill + pair.string = file_part; + pair.pt = txt_pt((S64)line, (S64)column); + if(pair.pt.line == 0) { pair.pt.line = 1; } + if(pair.pt.column == 0) { pair.pt.column = 1; } + } + return pair; +} + +//////////////////////////////// +//~ rjf: UTF-8 & UTF-16 Decoding/Encoding + +read_only global U8 utf8_class[32] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, +}; + +internal UnicodeDecode +utf8_decode(U8 *str, U64 max){ + UnicodeDecode result = {1, max_U32}; + U8 byte = str[0]; + U8 byte_class = utf8_class[byte >> 3]; + switch (byte_class) + { + case 1: + { + result.codepoint = byte; + }break; + case 2: + { + if (2 < max) + { + U8 cont_byte = str[1]; + if (utf8_class[cont_byte >> 3] == 0) + { + result.codepoint = (byte & bitmask5) << 6; + result.codepoint |= (cont_byte & bitmask6); + result.inc = 2; + } + } + }break; + case 3: + { + if (2 < max) + { + U8 cont_byte[2] = {str[1], str[2]}; + if (utf8_class[cont_byte[0] >> 3] == 0 && + utf8_class[cont_byte[1] >> 3] == 0) + { + result.codepoint = (byte & bitmask4) << 12; + result.codepoint |= ((cont_byte[0] & bitmask6) << 6); + result.codepoint |= (cont_byte[1] & bitmask6); + result.inc = 3; + } + } + }break; + case 4: + { + if (3 < max) + { + U8 cont_byte[3] = {str[1], str[2], str[3]}; + if (utf8_class[cont_byte[0] >> 3] == 0 && + utf8_class[cont_byte[1] >> 3] == 0 && + utf8_class[cont_byte[2] >> 3] == 0) + { + result.codepoint = (byte & bitmask3) << 18; + result.codepoint |= ((cont_byte[0] & bitmask6) << 12); + result.codepoint |= ((cont_byte[1] & bitmask6) << 6); + result.codepoint |= (cont_byte[2] & bitmask6); + result.inc = 4; + } + } + } + } + return(result); +} + +internal UnicodeDecode +utf16_decode(U16 *str, U64 max){ + UnicodeDecode result = {1, max_U32}; + result.codepoint = str[0]; + result.inc = 1; + if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000){ + result.codepoint = ((str[0] - 0xD800) << 10) | (str[1] - 0xDC00); + result.inc = 2; + } + return(result); +} + +internal U32 +utf8_encode(U8 *str, U32 codepoint){ + U32 inc = 0; + if (codepoint <= 0x7F){ + str[0] = (U8)codepoint; + inc = 1; + } + else if (codepoint <= 0x7FF){ + str[0] = (bitmask2 << 6) | ((codepoint >> 6) & bitmask5); + str[1] = bit8 | (codepoint & bitmask6); + inc = 2; + } + else if (codepoint <= 0xFFFF){ + str[0] = (bitmask3 << 5) | ((codepoint >> 12) & bitmask4); + str[1] = bit8 | ((codepoint >> 6) & bitmask6); + str[2] = bit8 | ( codepoint & bitmask6); + inc = 3; + } + else if (codepoint <= 0x10FFFF){ + str[0] = (bitmask4 << 3) | ((codepoint >> 18) & bitmask3); + str[1] = bit8 | ((codepoint >> 12) & bitmask6); + str[2] = bit8 | ((codepoint >> 6) & bitmask6); + str[3] = bit8 | ( codepoint & bitmask6); + inc = 4; + } + else{ + str[0] = '?'; + inc = 1; + } + return(inc); +} + +internal U32 +utf16_encode(U16 *str, U32 codepoint){ + U32 inc = 1; + if (codepoint == max_U32){ + str[0] = (U16)'?'; + } + else if (codepoint < 0x10000){ + str[0] = (U16)codepoint; + } + else{ + U32 v = codepoint - 0x10000; + str[0] = safe_cast_u16(0xD800 + (v >> 10)); + str[1] = safe_cast_u16(0xDC00 + (v & bitmask10)); + inc = 2; + } + return(inc); +} + +internal U32 +utf8_from_utf32_single(U8 *buffer, U32 character){ + return(utf8_encode(buffer, character)); +} + +//////////////////////////////// +//~ rjf: Unicode String Conversions + +internal String8 +str8_from_16(Arena *arena, String16 in){ + U64 cap = in.size*3; + U8 *str = push_array_no_zero(arena, U8, cap + 1); + U16 *ptr = in.str; + U16 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for (;ptr < opl; ptr += consume.inc){ + consume = utf16_decode(ptr, opl - ptr); + size += utf8_encode(str + size, consume.codepoint); + } + str[size] = 0; + arena_put_back(arena, (cap - size)); + return(str8(str, size)); +} + +internal String16 +str16_from_8(Arena *arena, String8 in){ + U64 cap = in.size*2; + U16 *str = push_array_no_zero(arena, U16, cap + 1); + U8 *ptr = in.str; + U8 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for (;ptr < opl; ptr += consume.inc){ + consume = utf8_decode(ptr, opl - ptr); + size += utf16_encode(str + size, consume.codepoint); + } + str[size] = 0; + arena_put_back(arena, (cap - size)*2); + return(str16(str, size)); +} + +internal String8 +str8_from_32(Arena *arena, String32 in){ + U64 cap = in.size*4; + U8 *str = push_array_no_zero(arena, U8, cap + 1); + U32 *ptr = in.str; + U32 *opl = ptr + in.size; + U64 size = 0; + for (;ptr < opl; ptr += 1){ + size += utf8_encode(str + size, *ptr); + } + str[size] = 0; + arena_put_back(arena, (cap - size)); + return(str8(str, size)); +} + +internal String32 +str32_from_8(Arena *arena, String8 in){ + U64 cap = in.size; + U32 *str = push_array_no_zero(arena, U32, cap + 1); + U8 *ptr = in.str; + U8 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for (;ptr < opl; ptr += consume.inc){ + consume = utf8_decode(ptr, opl - ptr); + str[size] = consume.codepoint; + size += 1; + } + str[size] = 0; + arena_put_back(arena, (cap - size)*4); + return(str32(str, size)); +} + +//////////////////////////////// +//~ rjf: Basic Types & Space Enum -> String Conversions + +internal String8 +string_from_dimension(Dimension dimension){ + local_persist String8 strings[] = { + str8_lit_comp("X"), + str8_lit_comp("Y"), + str8_lit_comp("Z"), + str8_lit_comp("W"), + }; + String8 result = str8_lit("error"); + if ((U32)dimension < 4){ + result = strings[dimension]; + } + return(result); +} + +internal String8 +string_from_side(Side side){ + local_persist String8 strings[] = { + str8_lit_comp("Min"), + str8_lit_comp("Max"), + }; + String8 result = str8_lit("error"); + if ((U32)side < 2){ + result = strings[side]; + } + return(result); +} + +internal String8 +string_from_operating_system(OperatingSystem os){ + local_persist String8 strings[] = { + str8_lit_comp("Null"), + str8_lit_comp("Windows"), + str8_lit_comp("Linux"), + str8_lit_comp("Mac"), + }; + String8 result = str8_lit("error"); + if (os < OperatingSystem_COUNT){ + result = strings[os]; + } + return(result); +} + +internal String8 +string_from_architecture(Architecture arch){ + local_persist String8 strings[] = { + str8_lit_comp("Null"), + str8_lit_comp("x64"), + str8_lit_comp("x86"), + str8_lit_comp("arm64"), + str8_lit_comp("arm32"), + }; + String8 result = str8_lit("error"); + if (arch < Architecture_COUNT){ + result = strings[arch]; + } + return(result); +} + +//////////////////////////////// +//~ rjf: Time Types -> String + +internal String8 +string_from_week_day(WeekDay week_day){ + local_persist String8 strings[] = { + str8_lit_comp("Sun"), + str8_lit_comp("Mon"), + str8_lit_comp("Tue"), + str8_lit_comp("Wed"), + str8_lit_comp("Thu"), + str8_lit_comp("Fri"), + str8_lit_comp("Sat"), + }; + String8 result = str8_lit("Err"); + if ((U32)week_day < WeekDay_COUNT){ + result = strings[week_day]; + } + return(result); +} + +internal String8 +string_from_month(Month month){ + local_persist String8 strings[] = { + str8_lit_comp("Jan"), + str8_lit_comp("Feb"), + str8_lit_comp("Mar"), + str8_lit_comp("Apr"), + str8_lit_comp("May"), + str8_lit_comp("Jun"), + str8_lit_comp("Jul"), + str8_lit_comp("Aug"), + str8_lit_comp("Sep"), + str8_lit_comp("Oct"), + str8_lit_comp("Nov"), + str8_lit_comp("Dec"), + }; + String8 result = str8_lit("Err"); + if ((U32)month < Month_COUNT){ + result = strings[month]; + } + return(result); +} + +internal String8 +push_date_time_string(Arena *arena, DateTime *date_time){ + char *mon_str = (char*)string_from_month(date_time->month).str; + U32 adjusted_hour = date_time->hour%12; + if (adjusted_hour == 0){ + adjusted_hour = 12; + } + char *ampm = "am"; + if (date_time->hour >= 12){ + ampm = "pm"; + } + String8 result = push_str8f(arena, "%d %s %d, %02d:%02d:%02d %s", + date_time->day, mon_str, date_time->year, + adjusted_hour, date_time->min, date_time->sec, ampm); + return(result); +} + +internal String8 +push_file_name_date_time_string(Arena *arena, DateTime *date_time){ + char *mon_str = (char*)string_from_month(date_time->month).str; + String8 result = push_str8f(arena, "%d-%s-%0d--%02d-%02d-%02d", + date_time->year, mon_str, date_time->day, + date_time->hour, date_time->min, date_time->sec); + return(result); +} + +internal String8 +string_from_elapsed_time(Arena *arena, DateTime dt){ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (dt.year){ + str8_list_pushf(scratch.arena, &list, "%dy", dt.year); + str8_list_pushf(scratch.arena, &list, "%um", dt.mon); + str8_list_pushf(scratch.arena, &list, "%ud", dt.day); + } else if (dt.mon){ + str8_list_pushf(scratch.arena, &list, "%um", dt.mon); + str8_list_pushf(scratch.arena, &list, "%ud", dt.day); + } else if (dt.day){ + str8_list_pushf(scratch.arena, &list, "%ud", dt.day); + } + str8_list_pushf(scratch.arena, &list, "%u:%u:%u:%u ms", dt.hour, dt.min, dt.sec, dt.msec); + StringJoin join = { str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }; + String8 result = str8_list_join(arena, &list, &join); + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: String <-> Color + +internal String8 +hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba) +{ + String8 hex_string = push_str8f(arena, "%02x%02x%02x%02x", (U8)(rgba.x*255.f), (U8)(rgba.y*255.f), (U8)(rgba.z*255.f), (U8)(rgba.w*255.f)); + return hex_string; +} + +internal Vec4F32 +rgba_from_hex_string_4f32(String8 hex_string) +{ + U8 byte_text[8] = {0}; + U64 byte_text_idx = 0; + for(U64 idx = 0; idx < hex_string.size && byte_text_idx < ArrayCount(byte_text); idx += 1) + { + if(char_is_digit(hex_string.str[idx], 16)) + { + byte_text[byte_text_idx] = char_to_lower(hex_string.str[idx]); + byte_text_idx += 1; + } + } + U8 byte_vals[4] = {0}; + for(U64 idx = 0; idx < 4; idx += 1) + { + byte_vals[idx] = (U8)u64_from_str8(str8(&byte_text[idx*2], 2), 16); + } + Vec4F32 rgba = v4f32(byte_vals[0]/255.f, byte_vals[1]/255.f, byte_vals[2]/255.f, byte_vals[3]/255.f); + return rgba; +} + +//////////////////////////////// +//~ NOTE(allen): Serialization Helpers + +internal void +str8_serial_begin(Arena *arena, String8List *srl){ + String8Node *node = push_array(arena, String8Node, 1); + node->string.str = push_array_no_zero(arena, U8, 0); + srl->first = srl->last = node; + srl->node_count = 1; + srl->total_size = 0; +} + +internal String8 +str8_serial_end(Arena *arena, String8List *srl){ + U64 size = srl->total_size; + U8 *out = push_array_no_zero(arena, U8, size); + str8_serial_write_to_dst(srl, out); + String8 result = str8(out, size); + return result; +} + +internal void +str8_serial_write_to_dst(String8List *srl, void *out){ + U8 *ptr = (U8*)out; + for (String8Node *node = srl->first; + node != 0; + node = node->next){ + U64 size = node->string.size; + MemoryCopy(ptr, node->string.str, size); + ptr += size; + } +} + +internal U64 +str8_serial_push_align(Arena *arena, String8List *srl, U64 align){ + Assert(IsPow2(align)); + + U64 pos = srl->total_size; + U64 new_pos = AlignPow2(pos, align); + U64 size = (new_pos - pos); + + if(size != 0) + { + U8 *buf = push_array(arena, U8, size); + + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += size; + srl->total_size += size; + } + else{ + str8_list_push(arena, srl, str8(buf, size)); + } + } + return size; +} + +internal void * +str8_serial_push_size(Arena *arena, String8List *srl, U64 size) +{ + void *result = 0; + if(size != 0) + { + U8 *buf = push_array_no_zero(arena, U8, size); + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += size; + srl->total_size += size; + } + else{ + str8_list_push(arena, srl, str8(buf, size)); + } + result = buf; + } + return result; +} + +internal void * +str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size){ + void *result = str8_serial_push_size(arena, srl, size); + if(result != 0) + { + MemoryCopy(result, data, size); + } + return result; +} + +internal void +str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first){ + for (String8Node *node = first; + node != 0; + node = node->next){ + str8_serial_push_data(arena, srl, node->string.str, node->string.size); + } +} + +internal void +str8_serial_push_u64(Arena *arena, String8List *srl, U64 x){ + U8 *buf = push_array_no_zero(arena, U8, 8); + MemoryCopy(buf, &x, 8); + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += 8; + srl->total_size += 8; + } + else{ + str8_list_push(arena, srl, str8(buf, 8)); + } +} + +internal void +str8_serial_push_u32(Arena *arena, String8List *srl, U32 x){ + U8 *buf = push_array_no_zero(arena, U8, 4); + MemoryCopy(buf, &x, 4); + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += 4; + srl->total_size += 4; + } + else{ + str8_list_push(arena, srl, str8(buf, 4)); + } +} + +internal void +str8_serial_push_u16(Arena *arena, String8List *srl, U16 x){ + str8_serial_push_data(arena, srl, &x, sizeof(x)); +} + +internal void +str8_serial_push_u8(Arena *arena, String8List *srl, U8 x){ + str8_serial_push_data(arena, srl, &x, sizeof(x)); +} + +internal void +str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str){ + str8_serial_push_data(arena, srl, str.str, str.size); + str8_serial_push_u8(arena, srl, 0); +} + +internal void +str8_serial_push_string(Arena *arena, String8List *srl, String8 str){ + str8_serial_push_data(arena, srl, str.str, str.size); +} + +//////////////////////////////// +//~ rjf: Deserialization Helpers + +internal U64 +str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity) +{ + U64 bytes_left = string.size-Min(off, string.size); + U64 actually_readable_size = Min(bytes_left, read_size); + U64 legally_readable_size = actually_readable_size - actually_readable_size%granularity; + if(legally_readable_size > 0) + { + MemoryCopy(read_dst, string.str+off, legally_readable_size); + } + return legally_readable_size; +} + +internal U64 +str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val) +{ + U64 cursor = off; + for (;;) { + U16 val = 0; + str8_deserial_read_struct(string, cursor, &val); + if (val == scan_val) { + break; + } + cursor += sizeof(val); + } + return cursor; +} + +internal void * +str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size) +{ + void *raw_ptr = 0; + if (off + size <= string.size) { + raw_ptr = string.str + off; + } + return raw_ptr; +} + +internal U64 +str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out) +{ + U64 cstr_size = 0; + if (off < string.size) { + U8 *ptr = string.str + off; + U8 *cap = string.str + string.size; + *cstr_out = str8_cstring_capped(ptr, cap); + cstr_size = (cstr_out->size + 1); + } + return cstr_size; +} + +internal U64 +str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out) +{ + U64 null_off = str8_deserial_find_first_match(string, off, 0); + U64 size = null_off - off; + U16 *str = (U16 *)str8_deserial_get_raw_ptr(string, off, size); + U64 count = size / sizeof(*str); + *str_out = str16(str, count); + + U64 read_size_with_null = size + sizeof(*str); + return read_size_with_null; +} + +internal U64 +str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out) +{ + Rng1U64 range = rng_1u64(off, off + size); + *block_out = str8_substr(string, range); + return block_out->size; +} diff --git a/src/base/base_string.h b/src/base/base_string.h new file mode 100644 index 00000000..cb443c18 --- /dev/null +++ b/src/base/base_string.h @@ -0,0 +1,351 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_STRING_H +#define BASE_STRING_H + +//////////////////////////////// +//~ rjf: Third Party Includes + +#define STB_SPRINTF_DECORATE(name) raddbg_##name +#include "third_party/stb/stb_sprintf.h" + +//////////////////////////////// +//~ rjf: String Types + +typedef struct String8 String8; +struct String8 +{ + U8 *str; + U64 size; +}; + +typedef struct String16 String16; +struct String16 +{ + U16 *str; + U64 size; +}; + +typedef struct String32 String32; +struct String32 +{ + U32 *str; + U64 size; +}; + +//////////////////////////////// +//~ rjf: String List & Array Types + +typedef struct String8Node String8Node; +struct String8Node +{ + String8Node *next; + String8 string; +}; + +typedef struct String8MetaNode String8MetaNode; +struct String8MetaNode +{ + String8MetaNode *next; + String8Node *node; +}; + +typedef struct String8List String8List; +struct String8List +{ + String8Node *first; + String8Node *last; + U64 node_count; + U64 total_size; +}; + +typedef struct String8Array String8Array; +struct String8Array +{ + String8 *strings; + U64 count; +}; + +//////////////////////////////// +//~ rjf: String Matching, Splitting, & Joining Types + +typedef U32 StringMatchFlags; +enum +{ + StringMatchFlag_CaseInsensitive = (1 << 0), + StringMatchFlag_RightSideSloppy = (1 << 1), + StringMatchFlag_SlashInsensitive = (1 << 2), +}; + +typedef U32 StringSplitFlags; +enum +{ + StringSplitFlag_KeepEmpties = (1 << 0), +}; + +typedef enum PathStyle +{ + PathStyle_Relative, + PathStyle_WindowsAbsolute, + PathStyle_UnixAbsolute, + +#if OS_WINDOWS + PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute +#elif OS_LINUX + PathStyle_SystemAbsolute = PathStyle_UnixAbsolute +#else +# error "absolute path style is undefined for this OS" +#endif +} +PathStyle; + +typedef struct StringJoin StringJoin; +struct StringJoin +{ + String8 pre; + String8 sep; + String8 post; +}; + +//////////////////////////////// +//~ rjf: String Pair Types + +typedef struct String8TxtPtPair String8TxtPtPair; +struct String8TxtPtPair +{ + String8 string; + TxtPt pt; +}; + +//////////////////////////////// +//~ rjf: UTF Decoding Types + +typedef struct UnicodeDecode UnicodeDecode; +struct UnicodeDecode +{ + U32 inc; + U32 codepoint; +}; + +//////////////////////////////// +//~ rjf: Character Classification & Conversion Functions + +internal B32 char_is_space(U8 c); +internal B32 char_is_upper(U8 c); +internal B32 char_is_lower(U8 c); +internal B32 char_is_alpha(U8 c); +internal B32 char_is_slash(U8 c); +internal B32 char_is_digit(U8 c, U32 base); +internal U8 char_to_lower(U8 c); +internal U8 char_to_upper(U8 c); +internal U8 char_to_correct_slash(U8 c); + +//////////////////////////////// +//~ rjf: C-String Measurement + +internal U64 cstring8_length(U8 *c); +internal U64 cstring16_length(U16 *c); +internal U64 cstring32_length(U32 *c); + +//////////////////////////////// +//~ rjf: String Constructors + +#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1) +#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,} +#define str8_varg(S) (int)((S).size), ((S).str) + +#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C)) +#define str8_array_fixed(S) str8((U8*)(S), sizeof(S)) +#define str8_struct(S) str8((U8*)(S), sizeof(*(S))) + +internal String8 str8(U8 *str, U64 size); +internal String8 str8_range(U8 *first, U8 *one_past_last); +internal String8 str8_zero(void); +internal String16 str16(U16 *str, U64 size); +internal String16 str16_range(U16 *first, U16 *one_past_last); +internal String16 str16_zero(void); +internal String32 str32(U32 *str, U64 size); +internal String32 str32_range(U32 *first, U32 *one_past_last); +internal String32 str32_zero(void); +internal String8 str8_cstring(char *c); +internal String16 str16_cstring(U16 *c); +internal String32 str32_cstring(U32 *c); +internal String8 str8_cstring_capped(void *cstr, void *cap); + +//////////////////////////////// +//~ rjf: String Stylization + +internal String8 upper_from_str8(Arena *arena, String8 string); +internal String8 lower_from_str8(Arena *arena, String8 string); +internal String8 backslashed_from_str8(Arena *arena, String8 string); + +//////////////////////////////// +//~ rjf: String Matching + +internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags); +internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); +internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags); + +//////////////////////////////// +//~ rjf: String Slicing + +internal String8 str8_substr(String8 str, Rng1U64 range); +internal String8 str8_prefix(String8 str, U64 size); +internal String8 str8_skip(String8 str, U64 amt); +internal String8 str8_postfix(String8 str, U64 size); +internal String8 str8_chop(String8 str, U64 amt); +internal String8 str8_skip_chop_whitespace(String8 string); + +//////////////////////////////// +//~ rjf: String Formatting & Copying + +internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2); +internal String8 push_str8_copy(Arena *arena, String8 s); +internal String8 push_str8fv(Arena *arena, char *fmt, va_list args); +internal String8 push_str8f(Arena *arena, char *fmt, ...); + +//////////////////////////////// +//~ rjf: String <=> Integer Conversions + +//- rjf: string -> integer +internal S64 sign_from_str8(String8 string, String8 *string_tail); +internal B32 str8_is_integer(String8 string, U32 radix); +internal U64 u64_from_str8(String8 string, U32 radix); +internal S64 s64_from_str8(String8 string, U32 radix); +internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x); +internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x); + +//- rjf: string -> integer (base64 & base16) +internal U64 base64_size_from_data_size(U64 size_in_bytes); +internal U64 base64_from_data(U8 *dst, U8 *src, U64 src_size); +internal U64 base16_size_from_data_size(U64 size_in_bytes); +internal U64 base16_from_data(U8 *dst, U8 *src, U64 src_size); + +//- rjf: integer -> string +internal String8 str8_from_memory_size(Arena *arena, U64 z); +internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); +internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator); + +//////////////////////////////// +//~ rjf: String <=> Float Conversions + +internal F64 f64_from_str8(String8 string); + +//////////////////////////////// +//~ rjf: String List Construction Functions + +internal String8Node* str8_list_push_node(String8List *list, String8Node *node); +internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string); +internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node); +internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string); +internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string); +internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string); +internal void str8_list_concat_in_place(String8List *list, String8List *to_push); +internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align); +internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...); +internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...); +internal String8List str8_list_copy(Arena *arena, String8List *list); +#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero()) + +//////////////////////////////// +//~ rjf: String Splitting & Joining + +internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags); +internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags); +internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags); +internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params); +internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count); + +//////////////////////////////// +//~ rjf; String Arrays + +internal String8Array str8_array_from_list(Arena *arena, String8List *list); +internal String8Array str8_array_reserve(Arena *arena, U64 count); + +//////////////////////////////// +//~ rjf: String Path Helpers + +internal String8 str8_chop_last_slash(String8 string); +internal String8 str8_skip_last_slash(String8 string); +internal String8 str8_chop_last_dot(String8 string); +internal String8 str8_skip_last_dot(String8 string); + +internal PathStyle path_style_from_str8(String8 string); +internal String8List str8_split_path(Arena *arena, String8 string); +internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style); +internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style); + +internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string); + +//////////////////////////////// +//~ rjf: UTF-8 & UTF-16 Decoding/Encoding + +internal UnicodeDecode utf8_decode(U8 *str, U64 max); +internal UnicodeDecode utf16_decode(U16 *str, U64 max); +internal U32 utf8_encode(U8 *str, U32 codepoint); +internal U32 utf16_encode(U16 *str, U32 codepoint); +internal U32 utf8_from_utf32_single(U8 *buffer, U32 character); + +//////////////////////////////// +//~ rjf: Unicode String Conversions + +internal String8 str8_from_16(Arena *arena, String16 in); +internal String16 str16_from_8(Arena *arena, String8 in); +internal String8 str8_from_32(Arena *arena, String32 in); +internal String32 str32_from_8(Arena *arena, String8 in); + +//////////////////////////////// +//~ rjf: Basic Types & Space Enum -> String Conversions + +internal String8 string_from_dimension(Dimension dimension); +internal String8 string_from_side(Side side); +internal String8 string_from_operating_system(OperatingSystem os); +internal String8 string_from_architecture(Architecture arch); + +//////////////////////////////// +//~ rjf: Time Types -> String + +internal String8 string_from_week_day(WeekDay week_day); +internal String8 string_from_month(Month month); +internal String8 push_date_time_string(Arena *arena, DateTime *date_time); +internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time); +internal String8 string_from_elapsed_time(Arena *arena, DateTime dt); + +//////////////////////////////// +//~ rjf: String <-> Color + +internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba); +internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string); + +//////////////////////////////// +//~ NOTE(allen): Serialization Helpers + +internal void str8_serial_begin(Arena *arena, String8List *srl); +internal String8 str8_serial_end(Arena *arena, String8List *srl); +internal void str8_serial_write_to_dst(String8List *srl, void *out); +internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 align); +internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size); +internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size); +internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first); +internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x); +internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x); +internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x); +internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x); +internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str); +internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str); +#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count)) +#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1) + +//////////////////////////////// +//~ rjf: Deserialization Helpers + +internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity); +internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val); +internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out); +internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out); +internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out); +#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr))) +#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr))) + +#endif // BASE_STRING_H diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c new file mode 100644 index 00000000..1efd6e60 --- /dev/null +++ b/src/base/base_thread_context.c @@ -0,0 +1,78 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Thread Context Functions + +C_LINKAGE thread_static TCTX* tctx_thread_local; +#if !SUPPLEMENT_UNIT +C_LINKAGE thread_static TCTX* tctx_thread_local = 0; +#endif + +internal void +tctx_init_and_equip(TCTX *tctx){ + MemoryZeroStruct(tctx); + Arena **arena_ptr = tctx->arenas; + for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){ + *arena_ptr = arena_alloc(); + } + tctx_thread_local = tctx; +} + +internal TCTX* +tctx_get_equipped(void){ + return(tctx_thread_local); +} + +internal Arena* +tctx_get_scratch(Arena **conflicts, U64 count){ + TCTX *tctx = tctx_get_equipped(); + + Arena *result = 0; + Arena **arena_ptr = tctx->arenas; + for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){ + Arena **conflict_ptr = conflicts; + B32 has_conflict = 0; + for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){ + if (*arena_ptr == *conflict_ptr){ + has_conflict = 1; + break; + } + } + if (!has_conflict){ + result = *arena_ptr; + break; + } + } + + return(result); +} + +internal void +tctx_set_thread_name(String8 string){ + TCTX *tctx = tctx_get_equipped(); + U64 size = ClampTop(string.size, sizeof(tctx->thread_name)); + MemoryCopy(tctx->thread_name, string.str, size); + tctx->thread_name_size = size; +} + +internal String8 +tctx_get_thread_name(void){ + TCTX *tctx = tctx_get_equipped(); + String8 result = str8(tctx->thread_name, tctx->thread_name_size); + return(result); +} + +internal void +tctx_write_srcloc(char *file_name, U64 line_number){ + TCTX *tctx = tctx_get_equipped(); + tctx->file_name = file_name; + tctx->line_number = line_number; +} + +internal void +tctx_read_srcloc(char **file_name, U64 *line_number){ + TCTX *tctx = tctx_get_equipped(); + *file_name = tctx->file_name; + *line_number = tctx->line_number; +} diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h new file mode 100644 index 00000000..ce05d47f --- /dev/null +++ b/src/base/base_thread_context.h @@ -0,0 +1,40 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_THREAD_CONTEXT_H +#define BASE_THREAD_CONTEXT_H + +//////////////////////////////// +// NOTE(allen): Thread Context + +typedef struct TCTX TCTX; +struct TCTX +{ + Arena *arenas[2]; + + U8 thread_name[32]; + U64 thread_name_size; + + char *file_name; + U64 line_number; +}; + +//////////////////////////////// +// NOTE(allen): Thread Context Functions + +internal void tctx_init_and_equip(TCTX *tctx); +internal TCTX* tctx_get_equipped(void); + +internal Arena* tctx_get_scratch(Arena **conflicts, U64 count); + +internal void tctx_set_thread_name(String8 name); +internal String8 tctx_get_thread_name(void); + +internal void tctx_write_srcloc(char *file_name, U64 line_number); +internal void tctx_read_srcloc(char **file_name, U64 *line_number); +#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__) + +#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count))) +#define scratch_end(scratch) temp_end(scratch) + +#endif //BASE_THREAD_CONTEXT_H diff --git a/src/base/base_types.c b/src/base/base_types.c new file mode 100644 index 00000000..9627f478 --- /dev/null +++ b/src/base/base_types.c @@ -0,0 +1,454 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ Safe Casts + +internal U16 +safe_cast_u16(U32 x) +{ + AssertAlways(x <= max_U16); + U16 result = (U16)x; + return result; +} + +internal U32 +safe_cast_u32(U64 x) +{ + AssertAlways(x <= max_U32); + U32 result = (U32)x; + return result; +} + +internal S32 +safe_cast_s32(S64 x) +{ + AssertAlways(x <= max_S32); + S32 result = (S32)x; + return result; +} + +//////////////////////////////// +//~ rjf: Large Base Type Functions + +internal U128 +u128_zero(void) +{ + U128 v = {0}; + return v; +} + +internal U128 +u128_make(U64 v0, U64 v1) +{ + U128 v = {v0, v1}; + return v; +} + +internal B32 +u128_match(U128 a, U128 b) +{ + return MemoryMatchStruct(&a, &b); +} + +//////////////////////////////// +//~ rjf: Bit Patterns + +internal U32 +u32_from_u64_saturate(U64 x){ + U32 x32 = (x > max_U32)?max_U32:(U32)x; + return(x32); +} + +internal U64 +u64_up_to_pow2(U64 x){ + if (x == 0){ + x = 1; + } + else{ + x -= 1; + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + x |= (x >> 32); + x += 1; + } + return(x); +} + +internal S32 +extend_sign32(U32 x, U32 size){ + U32 high_bit = size * 8; + U32 shift = 32 - high_bit; + S32 result = ((S32)x << shift) >> shift; + return result; +} + +internal S64 +extend_sign64(U64 x, U64 size){ + U64 high_bit = size * 8; + U64 shift = 64 - high_bit; + S64 result = ((S64)x << shift) >> shift; + return result; +} + +internal F32 +inf32(void){ + union { U32 u; F32 f; } x; + x.u = exponent32; + return(x.f); +} + +internal F32 +neg_inf32(void){ + union { U32 u; F32 f; } x; + x.u = sign32 | exponent32; + return(x.f); +} + +internal U16 +bswap_u16(U16 x) +{ + U16 result = (((x & 0xFF00) >> 8) | + ((x & 0x00FF) << 8)); + return result; +} + +internal U32 +bswap_u32(U32 x) +{ + U32 result = (((x & 0xFF000000) >> 24) | + ((x & 0x00FF0000) >> 8) | + ((x & 0x0000FF00) << 8) | + ((x & 0x000000FF) << 24)); + return result; +} + +internal U64 +bswap_u64(U64 x) +{ + // TODO(nick): naive bswap, replace with something that is faster like an intrinsic + U64 result = (((x & 0xFF00000000000000ULL) >> 56) | + ((x & 0x00FF000000000000ULL) >> 40) | + ((x & 0x0000FF0000000000ULL) >> 24) | + ((x & 0x000000FF00000000ULL) >> 8) | + ((x & 0x00000000FF000000ULL) << 8) | + ((x & 0x0000000000FF0000ULL) << 24) | + ((x & 0x000000000000FF00ULL) << 40) | + ((x & 0x00000000000000FFULL) << 56)); + return result; +} + +//////////////////////////////// +//~ rjf: Enum -> Sign + +internal S32 +sign_from_side_S32(Side side){ + return((side == Side_Min)?-1:1); +} + +internal F32 +sign_from_side_F32(Side side){ + return((side == Side_Min)?-1.f:1.f); +} + +//////////////////////////////// +//~ rjf: Memory Functions + +internal B32 +memory_is_zero(void *ptr, U64 size){ + B32 result = 1; + + // break down size + U64 extra = (size&0x7); + U64 count8 = (size >> 3); + + // check with 8-byte stride + U64 *p64 = (U64*)ptr; + if(result) + { + for (U64 i = 0; i < count8; i += 1, p64 += 1){ + if (*p64 != 0){ + result = 0; + goto done; + } + } + } + + // check extra + if(result) + { + U8 *p8 = (U8*)p64; + for (U64 i = 0; i < extra; i += 1, p8 += 1){ + if (*p8 != 0){ + result = 0; + goto done; + } + } + } + + done:; + return(result); +} + +//////////////////////////////// +//~ rjf: Text 2D Coordinate/Range Functions + +internal TxtPt +txt_pt(S64 line, S64 column) +{ + TxtPt p = {0}; + p.line = line; + p.column = column; + return p; +} + +internal B32 +txt_pt_match(TxtPt a, TxtPt b) +{ + return a.line == b.line && a.column == b.column; +} + +internal B32 +txt_pt_less_than(TxtPt a, TxtPt b) +{ + B32 result = 0; + if(a.line < b.line) + { + result = 1; + } + else if(a.line == b.line) + { + result = a.column < b.column; + } + return result; +} + +internal TxtPt +txt_pt_min(TxtPt a, TxtPt b) +{ + TxtPt result = b; + if(txt_pt_less_than(a, b)) + { + result = a; + } + return result; +} + +internal TxtPt +txt_pt_max(TxtPt a, TxtPt b) +{ + TxtPt result = a; + if(txt_pt_less_than(a, b)) + { + result = b; + } + return result; +} + +internal TxtRng +txt_rng(TxtPt min, TxtPt max) +{ + TxtRng range = {0}; + if(txt_pt_less_than(min, max)) + { + range.min = min; + range.max = max; + } + else + { + range.min = max; + range.max = min; + } + return range; +} + +internal TxtRng +txt_rng_intersect(TxtRng a, TxtRng b) +{ + TxtRng result = {0}; + result.min = txt_pt_max(a.min, b.min); + result.max = txt_pt_min(a.max, b.max); + if(txt_pt_less_than(result.max, result.min)) + { + MemoryZeroStruct(&result); + } + return result; +} + +internal TxtRng +txt_rng_union(TxtRng a, TxtRng b) +{ + TxtRng result = {0}; + result.min = txt_pt_min(a.min, b.min); + result.max = txt_pt_max(a.max, b.max); + return result; +} + +//////////////////////////////// +//~ rjf: Toolchain/Environment Enum Functions + +internal U64 +bit_size_from_arch(Architecture arch) +{ + // TODO(rjf): metacode + U64 arch_bitsize = 0; + switch(arch) + { + case Architecture_x64: arch_bitsize = 64; break; + case Architecture_x86: arch_bitsize = 32; break; + case Architecture_arm64: arch_bitsize = 64; break; + case Architecture_arm32: arch_bitsize = 32; break; + default: break; + } + return arch_bitsize; +} + +internal U64 +max_instruction_size_from_arch(Architecture arch) +{ + // TODO(rjf): make this real + return 64; +} + +internal OperatingSystem +operating_system_from_context(void){ + OperatingSystem os = OperatingSystem_Null; +#if OS_WINDOWS + os = OperatingSystem_Windows; +#elif OS_LINUX + os = OperatingSystem_Linux; +#elif OS_MAC + os = OperatingSystem_Mac; +#endif + return os; +} + +internal Architecture +architecture_from_context(void){ + Architecture arch = Architecture_Null; +#if ARCH_X64 + arch = Architecture_x64; +#elif ARCH_X86 + arch = Architecture_x86; +#elif ARCH_ARM64 + arch = Architecture_arm64; +#elif ARCH_ARM32 + arch = Architecture_arm32; +#endif + return arch; +} + +internal Compiler +compiler_from_context(void){ + Compiler compiler = Compiler_Null; +#if COMPILER_CL + compiler = Compiler_cl; +#elif COMPILER_GCC + compiler = Compiler_gcc; +#elif COMPILER_CLANG + compiler = Compiler_clang; +#endif + return compiler; +} + +//////////////////////////////// +//~ rjf: Time Functions + +internal DenseTime +dense_time_from_date_time(DateTime date_time){ + DenseTime result = 0; + result += date_time.year; + result *= 12; + result += date_time.mon; + result *= 31; + result += date_time.day; + result *= 24; + result += date_time.hour; + result *= 60; + result += date_time.min; + result *= 61; + result += date_time.sec; + result *= 1000; + result += date_time.msec; + return(result); +} + +internal DateTime +date_time_from_dense_time(DenseTime time){ + DateTime result = {0}; + result.msec = time%1000; + time /= 1000; + result.sec = time%61; + time /= 61; + result.min = time%60; + time /= 60; + result.hour = time%24; + time /= 24; + result.day = time%31; + time /= 31; + result.mon = time%12; + time /= 12; + Assert(time <= max_U32); + result.year = (U32)time; + return(result); +} + +internal DateTime +date_time_from_micro_seconds(U64 time){ + DateTime result = {0}; + result.micro_sec = time%1000; + time /= 1000; + result.msec = time%1000; + time /= 1000; + result.sec = time%60; + time /= 60; + result.min = time%60; + time /= 60; + result.hour = time%24; + time /= 24; + result.day = time%31; + time /= 31; + result.mon = time%12; + time /= 12; + Assert(time <= max_U32); + result.year = (U32)time; + return(result); +} + +//////////////////////////////// +//~ rjf: Non-Fancy Ring Buffer Reads/Writes + +internal U64 +ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size) +{ + Assert(src_data_size <= ring_size); + { + U64 ring_off = ring_pos%ring_size; + U64 bytes_before_split = ring_size-ring_off; + U64 pre_split_bytes = Min(bytes_before_split, src_data_size); + U64 pst_split_bytes = src_data_size-pre_split_bytes; + void *pre_split_data = src_data; + void *pst_split_data = ((U8 *)src_data + pre_split_bytes); + MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes); + MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes); + } + return src_data_size; +} + +internal U64 +ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size) +{ + Assert(read_size <= ring_size); + { + U64 ring_off = ring_pos%ring_size; + U64 bytes_before_split = ring_size-ring_off; + U64 pre_split_bytes = Min(bytes_before_split, read_size); + U64 pst_split_bytes = read_size-pre_split_bytes; + MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes); + MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes); + } + return read_size; +} diff --git a/src/base/base_types.h b/src/base/base_types.h new file mode 100644 index 00000000..37b5734b --- /dev/null +++ b/src/base/base_types.h @@ -0,0 +1,683 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_TYPES_H +#define BASE_TYPES_H + +//////////////////////////////// +//~ rjf: Foreign Includes + +#include +#include +#include +#include +#include + +//////////////////////////////// +//~ rjf: Build Configuration + +#if !defined(ENABLE_DEV) +# define ENABLE_DEV 0 +#endif + +#if !defined(SUPPLEMENT_UNIT) +# define SUPPLEMENT_UNIT 0 +#endif + +//////////////////////////////// +//~ rjf: Codebase Keywords + +#define internal static +#define global static +#define local_persist static + +#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS) +# pragma section(".rdata$", read) +# define read_only __declspec(allocate(".rdata$")) +#elif (COMPILER_CLANG && OS_LINUX) +# define read_only __attribute__((section(".rodata"))) +#else +// NOTE(rjf): I don't know of a useful way to do this in GCC land. +// __attribute__((section(".rodata"))) looked promising, but it introduces a +// strange warning about malformed section attributes, and it doesn't look +// like writing to that section reliably produces access violations, strangely +// enough. (It does on Clang) +# define read_only +#endif + +//////////////////////////////// +//~ rjf: Memory Operation Macros + +#define MemoryCopy(dst, src, size) memmove((dst), (src), (size)) +#define MemorySet(dst, byte, size) memset((dst), (byte), (size)) +#define MemoryCompare(a, b, size) memcmp((a), (b), (size)) +#define MemoryStrlen(ptr) strlen(ptr) + +#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d))) +#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d)) +#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c)) + +#define MemoryZero(s,z) memset((s),0,(z)) +#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s))) +#define MemoryZeroArray(a) MemoryZero((a),sizeof(a)) +#define MemoryZeroTyped(m,c) MemoryZero((m),sizeof(*(m))*(c)) + +#define MemoryMatch(a,b,z) (MemoryCompare((a),(b),(z)) == 0) +#define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a))) +#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a)) + +#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) ) +#define MemoryConsume(T,p,e) \ +( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) ) + +//////////////////////////////// +//~ rjf: Units + +#define KB(n) (((U64)(n)) << 10) +#define MB(n) (((U64)(n)) << 20) +#define GB(n) (((U64)(n)) << 30) +#define TB(n) (((U64)(n)) << 40) +#define Thousand(n) ((n)*1000) +#define Million(n) ((n)*1000000) +#define Billion(n) ((n)*1000000000) + +//////////////////////////////// +//~ rjf: Asserts + +#if COMPILER_CL +# define Trap() __debugbreak() +#elif COMPILER_CLANG || COMPILER_GCC +# define Trap() __builtin_trap() +# else +# error "undefined trap" +#endif + +#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0) +#if !defined(NDEBUG) +# define Assert(x) AssertAlways(x) +#else +# define Assert(x) (void)(x) +#endif +#define AssertImplies(a,b) Assert(!(a) || b) +#define AssertIff(a,b) Assert(!!(a) == !!(b)) +#define InvalidPath Assert(!"Invalid Path!") +#define NotImplemented Assert(!"Not Implemented!") + +#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1] + +//////////////////////////////// +//~ rjf: Branch Predictor Hints + +#if defined(__clang__) +# define Expect(expr, val) __builtin_expect((expr), (val)) +#else +# define Expect(expr, val) (expr) +#endif + +#define Likely(expr) Expect(expr,1) +#define Unlikely(expr) Expect(expr,0) + +//////////////////////////////// +//~ rjf: Misc. Helper Macros + +#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) + +#define Stmnt(S) do{ S }while(0) + +#define Stringify_(S) #S +#define Stringify(S) Stringify_(S) + +#define Glue_(A,B) A##B +#define Glue(A,B) Glue_(A,B) + +#define Min(A,B) ( ((A)<(B))?(A):(B) ) +#define Max(A,B) ( ((A)>(B))?(A):(B) ) + +#define ClampTop(A,X) Min(A,X) +#define ClampBot(X,B) Max(X,B) +#define Clamp(A,X,B) ( ((X)<(A))?(A):((X)>(B))?(B):(X) ) + +#define PtrClampTop(A,X) ClampTop(A,X) +#define PtrClampBot(X,B) ClampBot(X,B) +#define PtrClamp(A,X,B) Clamp(A,X,B) + +#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b)) + +#define Swap(T,a,b) Stmnt( T t__ = a; a = b; b = t__; ) + +#if ARCH_64BIT +# define IntFromPtr(ptr) ((U64)(ptr)) +#elif ARCH_32BIT +# define IntFromPtr(ptr) ((U32)(ptr)) +#else +# error missing ptr cast for this architecture +#endif + +#define PtrFromInt(i) (void*)((U8*)0 + (i)) + +#define Member(T,m) (((T*)0)->m) +#define OffsetOf(T,m) IntFromPtr(&Member(T,m)) +#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off))) +#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m)) + +#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b)); +#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1))) +#define AlignDownPow2(x,b) ((x)&(~((b) - 1))) +#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1)) +#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0) +#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0) + +#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end)) +#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end)) + +#define B8 S8 +#define B32 rrbool + +#if LANG_CPP +# define zero_struct {} +#else +# define zero_struct {0} +#endif + +#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015 +# define this_function_name "unknown" +#else +# define this_function_name __func__ +#endif + +#if LANG_CPP +# define C_LINKAGE_BEGIN extern "C"{ +# define C_LINKAGE_END } +# define C_LINKAGE extern "C" +#else +# define C_LINKAGE_BEGIN +# define C_LINKAGE_END +# define C_LINKAGE +#endif + +#if COMPILER_CL +# define thread_static __declspec(thread) +#elif COMPILER_CLANG || COMPILER_GCC +# define thread_static __thread +#endif + +#if OS_WINDOWS +# define shared_function C_LINKAGE __declspec(dllexport) +#else +# define shared_function C_LINKAGE +#endif + +//////////////////////////////// +//~ ASAN + +#if COMPILER_CL +# if defined(__SANITIZE_ADDRESS__) +# define ASAN_ENABLED 1 +# define NO_ASAN __declspec(no_sanitize_address) +# else +# define NO_ASAN +# endif +#elif COMPILER_CLANG +# if defined(__has_feature) +# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define ASAN_ENABLED 1 +# endif +# endif +# define NO_ASAN __attribute__((no_sanitize("address"))) +#else +# error "NO_ASAN is not defined" +#endif + +#if ASAN_ENABLED + +#pragma comment(lib, "clang_rt.asan-x86_64.lib") + +C_LINKAGE_BEGIN +void __asan_poison_memory_region(void const volatile *addr, size_t size); +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +C_LINKAGE_END + +# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size)) +# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size)) +#else +# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) +# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) + +#endif + +//////////////////////////////// +//~ rjf: Base Types + +typedef uint8_t U8; +typedef uint16_t U16; +typedef uint32_t U32; +typedef uint64_t U64; +typedef int8_t S8; +typedef int16_t S16; +typedef int32_t S32; +typedef int64_t S64; +typedef S8 B8; +typedef S16 B16; +typedef S32 B32; +typedef S64 B64; +typedef float F32; +typedef double F64; + +//////////////////////////////// +//~ rjf: Large Base Types + +typedef struct U128 U128; +struct U128 +{ + U64 u64[2]; +}; + +//////////////////////////////// +//~ rjf: Basic Types & Spaces + +typedef void VoidProc(void); + +typedef enum Dimension +{ + Dimension_X, + Dimension_Y, + Dimension_Z, + Dimension_W, +} +Dimension; + +typedef enum Side +{ + Side_Invalid = -1, + Side_Min, + Side_Max, + Side_COUNT, +} +Side; +#define side_flip(s) ((Side)(!(s))) + +typedef enum Axis2 +{ + Axis2_Invalid = -1, + Axis2_X, + Axis2_Y, + Axis2_COUNT, +} +Axis2; +#define axis2_flip(a) ((Axis2)(!(a))) + +typedef enum Corner +{ + Corner_Invalid = -1, + Corner_00, + Corner_01, + Corner_10, + Corner_11, + Corner_COUNT +} +Corner; + +//////////////////////////////// +//~ rjf: Toolchain/Environment Enums + +typedef enum OperatingSystem +{ + OperatingSystem_Null, + OperatingSystem_Windows, + OperatingSystem_Linux, + OperatingSystem_Mac, + OperatingSystem_COUNT, +} +OperatingSystem; + +typedef enum Architecture +{ + Architecture_Null, + Architecture_x64, + Architecture_x86, + Architecture_arm64, + Architecture_arm32, + Architecture_COUNT, +} +Architecture; + +typedef enum Compiler +{ + Compiler_Null, + Compiler_cl, + Compiler_gcc, + Compiler_clang, + Compiler_COUNT, +} +Compiler; + +//////////////////////////////// +//~ rjf: Text 2D Coordinates & Ranges + +typedef struct TxtPt TxtPt; +struct TxtPt +{ + S64 line; + S64 column; +}; + +typedef struct TxtRng TxtRng; +struct TxtRng +{ + TxtPt min; + TxtPt max; +}; + +//////////////////////////////// +//~ NOTE(allen): Constants + +global U32 sign32 = 0x80000000; +global U32 exponent32 = 0x7F800000; +global U32 mantissa32 = 0x007FFFFF; + +global F32 big_golden32 = 1.61803398875f; +global F32 small_golden32 = 0.61803398875f; + +global F32 pi32 = 3.1415926535897f; + +global F64 machine_epsilon64 = 4.94065645841247e-324; + +global U64 max_U64 = 0xffffffffffffffffull; +global U32 max_U32 = 0xffffffff; +global U16 max_U16 = 0xffff; +global U8 max_U8 = 0xff; + +global S64 max_S64 = (S64)0x7fffffffffffffffull; +global S32 max_S32 = (S32)0x7fffffff; +global S16 max_S16 = (S16)0x7fff; +global S8 max_S8 = (S8)0x7f; + +global S64 min_S64 = (S64)0xffffffffffffffffull; +global S32 min_S32 = (S32)0xffffffff; +global S16 min_S16 = (S16)0xffff; +global S8 min_S8 = (S8)0xff; + +global const U32 bitmask1 = 0x00000001; +global const U32 bitmask2 = 0x00000003; +global const U32 bitmask3 = 0x00000007; +global const U32 bitmask4 = 0x0000000f; +global const U32 bitmask5 = 0x0000001f; +global const U32 bitmask6 = 0x0000003f; +global const U32 bitmask7 = 0x0000007f; +global const U32 bitmask8 = 0x000000ff; +global const U32 bitmask9 = 0x000001ff; +global const U32 bitmask10 = 0x000003ff; +global const U32 bitmask11 = 0x000007ff; +global const U32 bitmask12 = 0x00000fff; +global const U32 bitmask13 = 0x00001fff; +global const U32 bitmask14 = 0x00003fff; +global const U32 bitmask15 = 0x00007fff; +global const U32 bitmask16 = 0x0000ffff; +global const U32 bitmask17 = 0x0001ffff; +global const U32 bitmask18 = 0x0003ffff; +global const U32 bitmask19 = 0x0007ffff; +global const U32 bitmask20 = 0x000fffff; +global const U32 bitmask21 = 0x001fffff; +global const U32 bitmask22 = 0x003fffff; +global const U32 bitmask23 = 0x007fffff; +global const U32 bitmask24 = 0x00ffffff; +global const U32 bitmask25 = 0x01ffffff; +global const U32 bitmask26 = 0x03ffffff; +global const U32 bitmask27 = 0x07ffffff; +global const U32 bitmask28 = 0x0fffffff; +global const U32 bitmask29 = 0x1fffffff; +global const U32 bitmask30 = 0x3fffffff; +global const U32 bitmask31 = 0x7fffffff; +global const U32 bitmask32 = 0xffffffff; + +global const U64 bitmask33 = 0x00000001ffffffffull; +global const U64 bitmask34 = 0x00000003ffffffffull; +global const U64 bitmask35 = 0x00000007ffffffffull; +global const U64 bitmask36 = 0x0000000fffffffffull; +global const U64 bitmask37 = 0x0000001fffffffffull; +global const U64 bitmask38 = 0x0000003fffffffffull; +global const U64 bitmask39 = 0x0000007fffffffffull; +global const U64 bitmask40 = 0x000000ffffffffffull; +global const U64 bitmask41 = 0x000001ffffffffffull; +global const U64 bitmask42 = 0x000003ffffffffffull; +global const U64 bitmask43 = 0x000007ffffffffffull; +global const U64 bitmask44 = 0x00000fffffffffffull; +global const U64 bitmask45 = 0x00001fffffffffffull; +global const U64 bitmask46 = 0x00003fffffffffffull; +global const U64 bitmask47 = 0x00007fffffffffffull; +global const U64 bitmask48 = 0x0000ffffffffffffull; +global const U64 bitmask49 = 0x0001ffffffffffffull; +global const U64 bitmask50 = 0x0003ffffffffffffull; +global const U64 bitmask51 = 0x0007ffffffffffffull; +global const U64 bitmask52 = 0x000fffffffffffffull; +global const U64 bitmask53 = 0x001fffffffffffffull; +global const U64 bitmask54 = 0x003fffffffffffffull; +global const U64 bitmask55 = 0x007fffffffffffffull; +global const U64 bitmask56 = 0x00ffffffffffffffull; +global const U64 bitmask57 = 0x01ffffffffffffffull; +global const U64 bitmask58 = 0x03ffffffffffffffull; +global const U64 bitmask59 = 0x07ffffffffffffffull; +global const U64 bitmask60 = 0x0fffffffffffffffull; +global const U64 bitmask61 = 0x1fffffffffffffffull; +global const U64 bitmask62 = 0x3fffffffffffffffull; +global const U64 bitmask63 = 0x7fffffffffffffffull; +global const U64 bitmask64 = 0xffffffffffffffffull; + +global const U32 bit1 = (1<<0); +global const U32 bit2 = (1<<1); +global const U32 bit3 = (1<<2); +global const U32 bit4 = (1<<3); +global const U32 bit5 = (1<<4); +global const U32 bit6 = (1<<5); +global const U32 bit7 = (1<<6); +global const U32 bit8 = (1<<7); +global const U32 bit9 = (1<<8); +global const U32 bit10 = (1<<9); +global const U32 bit11 = (1<<10); +global const U32 bit12 = (1<<11); +global const U32 bit13 = (1<<12); +global const U32 bit14 = (1<<13); +global const U32 bit15 = (1<<14); +global const U32 bit16 = (1<<15); +global const U32 bit17 = (1<<16); +global const U32 bit18 = (1<<17); +global const U32 bit19 = (1<<18); +global const U32 bit20 = (1<<19); +global const U32 bit21 = (1<<20); +global const U32 bit22 = (1<<21); +global const U32 bit23 = (1<<22); +global const U32 bit24 = (1<<23); +global const U32 bit25 = (1<<24); +global const U32 bit26 = (1<<25); +global const U32 bit27 = (1<<26); +global const U32 bit28 = (1<<27); +global const U32 bit29 = (1<<28); +global const U32 bit30 = (1<<29); +global const U32 bit31 = (1<<30); +global const U32 bit32 = (1<<31); + +global const U64 bit33 = (1ull<<32); +global const U64 bit34 = (1ull<<33); +global const U64 bit35 = (1ull<<34); +global const U64 bit36 = (1ull<<35); +global const U64 bit37 = (1ull<<36); +global const U64 bit38 = (1ull<<37); +global const U64 bit39 = (1ull<<38); +global const U64 bit40 = (1ull<<39); +global const U64 bit41 = (1ull<<40); +global const U64 bit42 = (1ull<<41); +global const U64 bit43 = (1ull<<42); +global const U64 bit44 = (1ull<<43); +global const U64 bit45 = (1ull<<44); +global const U64 bit46 = (1ull<<45); +global const U64 bit47 = (1ull<<46); +global const U64 bit48 = (1ull<<47); +global const U64 bit49 = (1ull<<48); +global const U64 bit50 = (1ull<<49); +global const U64 bit51 = (1ull<<50); +global const U64 bit52 = (1ull<<51); +global const U64 bit53 = (1ull<<52); +global const U64 bit54 = (1ull<<53); +global const U64 bit55 = (1ull<<54); +global const U64 bit56 = (1ull<<55); +global const U64 bit57 = (1ull<<56); +global const U64 bit58 = (1ull<<57); +global const U64 bit59 = (1ull<<58); +global const U64 bit60 = (1ull<<59); +global const U64 bit61 = (1ull<<60); +global const U64 bit62 = (1ull<<61); +global const U64 bit63 = (1ull<<62); +global const U64 bit64 = (1ull<<63); + +//////////////////////////////// +//~ allen: Time + +typedef enum WeekDay +{ + WeekDay_Sun, + WeekDay_Mon, + WeekDay_Tue, + WeekDay_Wed, + WeekDay_Thu, + WeekDay_Fri, + WeekDay_Sat, + WeekDay_COUNT, +} +WeekDay; + +typedef enum Month +{ + Month_Jan, + Month_Feb, + Month_Mar, + Month_Apr, + Month_May, + Month_Jun, + Month_Jul, + Month_Aug, + Month_Sep, + Month_Oct, + Month_Nov, + Month_Dec, + Month_COUNT, +} +Month; + +typedef struct DateTime DateTime; +struct DateTime +{ + U16 micro_sec; // [0,999] + U16 msec; // [0,999] + U16 sec; // [0,60] + U16 min; // [0,59] + U16 hour; // [0,24] + U16 day; // [0,30] + union{ + WeekDay week_day; + U32 wday; + }; + union{ + Month month; + U32 mon; + }; + U32 year; // 1 = 1 CE, 0 = 1 BC +}; + +typedef U64 DenseTime; + +//////////////////////////////// +//~ allen: Files + +typedef U32 FilePropertyFlags; +enum +{ + FilePropertyFlag_IsFolder = (1 << 0), +}; + +typedef struct FileProperties FileProperties; +struct FileProperties +{ + U64 size; + DenseTime modified; + DenseTime created; + FilePropertyFlags flags; +}; + +//////////////////////////////// +//~ Safe Casts + +internal U16 safe_cast_u16(U32 x); +internal U32 safe_cast_u32(U64 x); +internal S32 safe_cast_s32(S64 x); + +//////////////////////////////// +//~ rjf: Large Base Type Functions + +internal U128 u128_zero(void); +internal U128 u128_make(U64 v0, U64 v1); +internal B32 u128_match(U128 a, U128 b); + +//////////////////////////////// +//~ rjf: Bit Patterns + +internal U32 u32_from_u64_saturate(U64 x); +internal U64 u64_up_to_pow2(U64 x); +internal S32 extend_sign32(U32 x, U32 size); +internal S64 extend_sign64(U64 x, U64 size); + +internal F32 inf32(void); +internal F32 neg_inf32(void); + +internal U16 bswap_u16(U16 x); +internal U32 bswap_u32(U32 x); +internal U64 bswap_u64(U64 x); + +//////////////////////////////// +//~ rjf: Enum -> Sign + +internal S32 sign_from_side_S32(Side side); +internal F32 sign_from_side_F32(Side side); + +//////////////////////////////// +//~ rjf: Memory Functions + +internal B32 memory_is_zero(void *ptr, U64 size); + +//////////////////////////////// +//~ rjf: Text 2D Coordinate/Range Functions + +internal TxtPt txt_pt(S64 line, S64 column); +internal B32 txt_pt_match(TxtPt a, TxtPt b); +internal B32 txt_pt_less_than(TxtPt a, TxtPt b); +internal TxtPt txt_pt_min(TxtPt a, TxtPt b); +internal TxtPt txt_pt_max(TxtPt a, TxtPt b); +internal TxtRng txt_rng(TxtPt min, TxtPt max); +internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b); +internal TxtRng txt_rng_union(TxtRng a, TxtRng b); + +//////////////////////////////// +//~ rjf: Toolchain/Environment Enum Functions + +internal U64 bit_size_from_arch(Architecture arch); +internal U64 max_instruction_size_from_arch(Architecture arch); + +internal OperatingSystem operating_system_from_context(void); +internal Architecture architecture_from_context(void); +internal Compiler compiler_from_context(void); + +//////////////////////////////// +//~ rjf: Time Functions + +internal DenseTime dense_time_from_date_time(DateTime date_time); +internal DateTime date_time_from_dense_time(DenseTime time); +internal DateTime date_time_from_micro_seconds(U64 time); + +//////////////////////////////// +//~ rjf: Non-Fancy Ring Buffer Reads/Writes + +internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size); +internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size); +#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr))) +#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr))) + +#endif // BASE_TYPES_H diff --git a/src/coff/coff.c b/src/coff/coff.c new file mode 100644 index 00000000..8220cfab --- /dev/null +++ b/src/coff/coff.c @@ -0,0 +1,1119 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal B32 +coff_is_big_obj(String8 data) +{ + B32 is_big_obj = 0; + if (data.size >= sizeof(COFF_HeaderBigObj)) { + COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)(data.str); + is_big_obj = big_header->sig1 == COFF_MachineType_UNKNOWN && + big_header->sig2 == max_U16 && + big_header->version >= COFF_MIN_BIG_OBJ_VERSION && + MemoryCompare(big_header->magic, coff_big_obj_magic, sizeof(big_header->magic)) == 0; + } + return is_big_obj; +} + +internal B32 +coff_is_obj(String8 data) +{ + B32 is_obj = 0; + + if (data.size >= sizeof(COFF_Header)) { + COFF_Header *header = (COFF_Header*)(data.str); + + // validate machine + B32 is_machine_type_valid = 0; + switch (header->machine) { + case COFF_MachineType_UNKNOWN: + case COFF_MachineType_X86: case COFF_MachineType_X64: + case COFF_MachineType_ARM33: case COFF_MachineType_ARM: + case COFF_MachineType_ARM64: case COFF_MachineType_ARMNT: + case COFF_MachineType_EBC: case COFF_MachineType_IA64: + case COFF_MachineType_M32R: case COFF_MachineType_MIPS16: + case COFF_MachineType_MIPSFPU:case COFF_MachineType_MIPSFPU16: + case COFF_MachineType_POWERPC:case COFF_MachineType_POWERPCFP: + case COFF_MachineType_R4000: case COFF_MachineType_RISCV32: + case COFF_MachineType_RISCV64:case COFF_MachineType_RISCV128: + case COFF_MachineType_SH3: case COFF_MachineType_SH3DSP: + case COFF_MachineType_SH4: case COFF_MachineType_SH5: + case COFF_MachineType_THUMB: case COFF_MachineType_WCEMIPSV2: + { + is_machine_type_valid = 1; + }break; + } + + if (is_machine_type_valid) { + // validate section count + U64 section_count = header->section_count; + U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader); + if (data.size >= section_hdr_opl_off) { + + COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(data.str + sizeof(*header)); + COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count; + + // validate section ranges + B32 is_sect_range_valid = 1; + for (COFF_SectionHeader *sec_hdr = section_hdrs; + sec_hdr < section_hdr_opl; + sec_hdr += 1) { + if (!(sec_hdr->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA)) { + U64 min = sec_hdr->foff; + U64 max = min + sec_hdr->fsize; + if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= data.size)) { + is_sect_range_valid = 0; + break; + } + } + } + + if (is_sect_range_valid) { + // validate symbol table + U64 symbol_table_off = header->symbol_table_foff; + U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count; + U64 symbol_table_opl_off = symbol_table_off + symbol_table_size; + + // don't validate symbol table when there is none + if (symbol_table_off == 0 && symbol_table_size == 0) { + symbol_table_off = section_hdr_opl_off; + symbol_table_opl_off = section_hdr_opl_off; + } + + is_obj = (section_hdr_opl_off <= symbol_table_off && + symbol_table_off <= symbol_table_opl_off && + symbol_table_opl_off <= data.size); + } + } + } + } + + return is_obj; +} + +internal COFF_HeaderInfo +coff_header_info_from_data(String8 data) +{ + COFF_HeaderInfo info = {0}; + if (coff_is_big_obj(data)) { + COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)data.str; + info.machine = big_header->machine; + info.section_array_off = sizeof(COFF_HeaderBigObj); + info.section_count_no_null = big_header->section_count; + info.string_table_off = big_header->pointer_to_symbol_table + sizeof(COFF_Symbol32) * big_header->number_of_symbols; + info.symbol_size = sizeof(COFF_Symbol32); + info.symbol_off = big_header->pointer_to_symbol_table; + info.symbol_count = big_header->number_of_symbols; + } else if (coff_is_obj(data)) { + COFF_Header *header = (COFF_Header*)data.str; + info.machine = header->machine; + info.section_array_off = sizeof(COFF_Header); + info.section_count_no_null = header->section_count; + info.string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16) * header->symbol_count; + info.symbol_size = sizeof(COFF_Symbol16); + info.symbol_off = header->symbol_table_foff; + info.symbol_count = header->symbol_count; + } + return info; +} + +internal U64 +coff_align_size_from_section_flags(COFF_SectionFlags flags) +{ + U32 align = 0; + U32 align_index = COFF_SectionFlags_Extract_ALIGN(flags); + switch (align_index) { + default: break; + case 0: align = 1; break; // alignment isn't specified, default to 1 + case COFF_SectionAlign_1BYTES: align = 1; break; + case COFF_SectionAlign_2BYTES: align = 2; break; + case COFF_SectionAlign_4BYTES: align = 4; break; + case COFF_SectionAlign_8BYTES: align = 8; break; + case COFF_SectionAlign_16BYTES: align = 16; break; + case COFF_SectionAlign_32BYTES: align = 32; break; + case COFF_SectionAlign_64BYTES: align = 64; break; + case COFF_SectionAlign_128BYTES: align = 128; break; + case COFF_SectionAlign_256BYTES: align = 256; break; + case COFF_SectionAlign_512BYTES: align = 512; break; + case COFF_SectionAlign_1024BYTES: align = 1024; break; + case COFF_SectionAlign_2048BYTES: align = 2048; break; + case COFF_SectionAlign_4096BYTES: align = 4096; break; + case COFF_SectionAlign_8192BYTES: align = 8192; break; + } + return align; +} + +internal COFF_SymbolValueInterpType +coff_interp_symbol(COFF_Symbol32 *symbol) +{ + if (symbol->storage_class == COFF_SymStorageClass_SECTION && symbol->section_number == COFF_SYMBOL_UNDEFINED_SECTION) { + return COFF_SymbolValueInterp_UNDEFINED; + } + if (symbol->storage_class == COFF_SymStorageClass_EXTERNAL && symbol->value == 0 && symbol->section_number == COFF_SYMBOL_UNDEFINED_SECTION) { + return COFF_SymbolValueInterp_UNDEFINED; + } + if (symbol->storage_class == COFF_SymStorageClass_EXTERNAL && symbol->value != 0 && symbol->section_number == COFF_SYMBOL_UNDEFINED_SECTION) { + return COFF_SymbolValueInterp_COMMON; + } + if (symbol->section_number == COFF_SYMBOL_ABS_SECTION) { + return COFF_SymbolValueInterp_ABS; + } + if (symbol->section_number == COFF_SYMBOL_DEBUG_SECTION) { + return COFF_SymbolValueInterp_DEBUG; + } + if (symbol->storage_class == COFF_SymStorageClass_WEAK_EXTERNAL) { + return COFF_SymbolValueInterp_WEAK; + } + return COFF_SymbolValueInterp_REGULAR; +} + +internal U64 +coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff) +{ + U64 foff = 0; + for(U64 sect_idx = 0; sect_idx < section_count; sect_idx += 1) + { + COFF_SectionHeader *sect = §ions[sect_idx]; + if(sect->voff <= voff && voff < sect->voff+sect->vsize) + { + if(!(sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA)) + { + foff = sect->foff + (voff - sect->voff); + } + break; + } + } + return foff; +} + +internal COFF_SectionHeader * +coff_section_header_from_num(String8 data, U64 section_headers_off, U64 n) +{ + COFF_SectionHeader *result = &coff_section_header_nil; + if(1 <= n && section_headers_off + n*sizeof(COFF_SectionHeader) <= data.size) + { + result = (COFF_SectionHeader*)(data.str + section_headers_off + (n-1)*sizeof(COFF_SectionHeader)); + } + return result; +} + +internal String8 +coff_section_header_get_name(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base) +{ + U64 size = 0; + for (; size < sizeof(header->name); size += 1) { + if (header->name[size] == '\0') { + break; + } + } + String8 name = str8(header->name, size); + + if (name.str[0] == '/') { + String8 ascii_name_offset = str8_skip(name, 1); + U64 name_offset = u64_from_str8(ascii_name_offset, 10); + + name_offset += string_table_base; + if (name_offset < coff_data.size) { + char *ptr = (char *)coff_data.str + name_offset; + name = str8_cstring(ptr); + } + } + + return name; +} + +internal void +coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_out) +{ + // dollar sign has multiple interpretations that depend on the type of the section. + // 1. when section contains code/data it indicates section precedence + // 2. when section starts with .debug it indicates type of data inside the section + // T: Types + // S: Symbols + // P: Precompiled types + // F: FPO data + // H: Clang extension produced with /debug:ghash, array of type hashes + *name_out = full_name; + *postfix_out = str8_lit(""); + for (U64 i = 0; i < full_name.size; ++i) { + if (full_name.str[i] == '$') { + *name_out = str8(full_name.str, i); + *postfix_out = str8(full_name.str + i + 1, full_name.size - i - 1); + + // TLS sections don't have a postfix but we still have to sort them based + // on dollar sign so they are sloted between CRT's _tls_start and _tls_end sections. + if (str8_match(*name_out, str8_lit(".tls"), 0) && postfix_out->size == 0) { + *postfix_out = str8_lit("$"); + } + + break; + } + } +} + +internal COFF_RelocNode * +coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc) +{ + COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1); + node->data = reloc; + SLLQueuePush(list->first, list->last, node); + ++list->count; + return node; +} + +//////////////////////////////// + +internal String8 +coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolName *name) +{ + String8 name_str = str8_lit(""); + if (name->long_name.zeroes == 0) { + U64 string_table_offset = string_table_base_offset + name->long_name.string_table_offset; + str8_deserial_read_cstr(data, string_table_offset, &name_str); + } else { + U32 i; + for (i = 0; i < sizeof(name->short_name); ++i) { + if (name->short_name[i] == '\0') { + break; + } + } + name_str = str8(name->short_name, i); + } + return name_str; +} + +internal void +coff_symbol32_from_coff_symbol16(COFF_Symbol32 *sym32, COFF_Symbol16 *sym16) +{ + sym32->name = sym16->name; + sym32->value = sym16->value; + if (sym16->section_number == COFF_SYMBOL_DEBUG_SECTION_16) { + sym32->section_number = COFF_SYMBOL_DEBUG_SECTION; + } else if (sym16->section_number == COFF_SYMBOL_ABS_SECTION_16) { + sym32->section_number = COFF_SYMBOL_ABS_SECTION; + } else { + sym32->section_number = (U32)sym16->section_number; + } + sym32->type.v = sym16->type.v; + sym32->storage_class = sym16->storage_class; + sym32->aux_symbol_count = sym16->aux_symbol_count; +} + +internal COFF_Symbol32Array +coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count) +{ + COFF_Symbol32Array result; + result.count = symbol_count; + result.v = push_array_no_zero(arena, COFF_Symbol32, result.count); + + COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)(data.str + symbol_array_off); + for (U64 isymbol = 0; isymbol < symbol_count; isymbol += 1) { + // read header symbol + COFF_Symbol16 *sym16 = &sym16_arr[isymbol]; + + // convert to 32bit + COFF_Symbol32 *sym32 = &result.v[isymbol]; + coff_symbol32_from_coff_symbol16(sym32, sym16); + + if (isymbol + 1 + sym16->aux_symbol_count > symbol_count) { + Assert(!"aux symbols out of bounds"); + } + + // copy aux symbols + for (U64 iaux = 0; iaux < sym16->aux_symbol_count; iaux += 1) { + COFF_Symbol16 *aux16 = sym16 + iaux + 1; + COFF_Symbol32 *aux32 = sym32 + iaux + 1; // 32bit COFF uses 16bit aux symbols + MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16)); + } + + // take into account aux symbols + isymbol += sym32->aux_symbol_count; + } + + return result; +} + +internal COFF_Symbol32Array +coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count) +{ + COFF_Symbol32Array result; + result.count = symbol_count; + result.v = (COFF_Symbol32 *)(data.str + symbol_array_off); + return result; +} + +internal COFF_Symbol32Array +coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_off, U64 symbol_count, U64 symbol_size) +{ + COFF_Symbol32Array result = {0}; + switch (symbol_size) { + case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_off, symbol_count); break; + case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_off, symbol_count); break; + } + return result; +} + +internal COFF_Symbol16Node * +coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol) +{ + COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1); + node->next = 0; + node->data = symbol; + SLLQueuePush(list->first, list->last, node); + list->count += 1; + return node; +} + +internal COFF_RelocInfo +coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header) +{ + COFF_RelocInfo result = {0}; + if (header->flags & COFF_SectionFlag_LNK_NRELOC_OVFL && header->reloc_count == max_U16) { + COFF_Reloc counter; + U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter); + if (read_size == sizeof(counter) && counter.apply_off > 0) { + result.array_off = header->relocs_foff + sizeof(COFF_Reloc); + result.count = counter.apply_off - 1; // exclude counter entry + } + } else { + result.array_off = header->relocs_foff; + result.count = header->reloc_count; + } + return result; +} + +internal U64 +coff_word_size_from_machine(COFF_MachineType machine) +{ + U64 result = 0; + switch (machine) { + case COFF_MachineType_X64: result = 8; break; + case COFF_MachineType_X86: result = 4; break; + } + return result; +} + +internal String8 +coff_make_import_lookup(Arena *arena, U16 hint, String8 name) +{ + U64 buffer_size = sizeof(hint) + (name.size + 1); + U8 *buffer = push_array(arena, U8, buffer_size); + *(U16*)buffer = hint; + MemoryCopy(buffer + sizeof(hint), name.str, name.size); + buffer[buffer_size - 1] = 0; + String8 result = str8(buffer, buffer_size); + return result; +} + +internal U32 +coff_make_ordinal_32(U16 hint) +{ + U32 ordinal = (1 << 31) | hint; + return ordinal; +} + +internal U64 +coff_make_ordinal_64(U16 hint) +{ + U64 ordinal = (1ULL << 63) | hint; + return ordinal; +} + +//////////////////////////////// + +internal B32 +coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b) +{ + B32 is_equal = 0; + if (a.type == b.type) { + switch (a.type) { + case COFF_ResourceIDType_NULL: break; + case COFF_ResourceIDType_NUMBER: is_equal = (a.u.number == b.u.number); break; + case COFF_ResourceIDType_STRING: is_equal = str8_match(a.u.string, b.u.string, 0); break; + default: Assert(!"invalid resource id type"); + } + } + return is_equal; +} + +internal COFF_ResourceID +coff_resource_id_copy(Arena *arena, COFF_ResourceID id) +{ + COFF_ResourceID result = zero_struct; + switch (id.type) { + case COFF_ResourceIDType_NULL: break; + case COFF_ResourceIDType_NUMBER: { + result.type = COFF_ResourceIDType_NUMBER; + result.u.number = id.u.number; + } break; + case COFF_ResourceIDType_STRING: { + result.type = COFF_ResourceIDType_STRING; + result.u.string = id.u.string; + } break; + default: Assert(!"invalid resource id type"); + } + return result; +} + +internal COFF_ResourceID +coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16) +{ + COFF_ResourceID id; + id.type = id_16->type; + switch (id_16->type) { + case COFF_ResourceIDType_NULL: break; + case COFF_ResourceIDType_NUMBER: { + id.u.number = id_16->u.number; + } break; + case COFF_ResourceIDType_STRING: { + id.u.string = str8_from_16(arena, id_16->u.string); + } break; + default: Assert(!"invalid resource id type"); + } + return id; +} + +internal U64 +coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out) +{ + U64 cursor = off; + + U16 flag = 0; + str8_deserial_read_struct(data, cursor, &flag); + + B32 is_number = flag == max_U16; + if (is_number) { + cursor += sizeof(flag); + id_out->type = COFF_ResourceIDType_NUMBER; + cursor += str8_deserial_read_struct(data, cursor, &id_out->u.number); + } else { + id_out->type = COFF_ResourceIDType_STRING; + cursor += str8_deserial_read_windows_utf16_string16(data, cursor, &id_out->u.string); + } + + U64 read_size = cursor - off; + return read_size; +} + +internal U64 +coff_read_resource(String8 raw_res, U64 off, Arena *arena, COFF_Resource *res_out) +{ + // parse header + COFF_ResourceHeaderPrefix prefix; MemoryZeroStruct(&prefix); + U64 cursor = str8_deserial_read_struct(raw_res, off, &prefix); + String8 header_data = str8_substr(raw_res, rng_1u64(off, off + prefix.header_size)); + + COFF_ResourceID_16 type_16; MemoryZeroStruct(&type_16); + cursor += coff_read_resource_id(header_data, cursor, &type_16); + cursor = AlignPow2(cursor, COFF_RES_ALIGN); + + COFF_ResourceID_16 name_16; MemoryZeroStruct(&name_16); + cursor += coff_read_resource_id(header_data, cursor, &name_16); + cursor = AlignPow2(cursor, COFF_RES_ALIGN); + + U32 data_version = 0; + cursor += str8_deserial_read_struct(header_data, cursor, &data_version); + + COFF_ResourceMemoryFlags memory_flags = 0; + cursor += str8_deserial_read_struct(header_data, cursor, &memory_flags); + + U16 language_id = 0; + cursor += str8_deserial_read_struct(header_data, cursor, &language_id); + + U32 version = 0; + cursor += str8_deserial_read_struct(header_data, cursor, &version); + + U32 characteristics = 0; + cursor += str8_deserial_read_struct(header_data, cursor, &characteristics); + + String8 data; + cursor += str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &data); + + // was resource parsed? + Assert(cursor >= prefix.data_size + prefix.header_size); + + // fill out result + res_out->type = coff_convert_resource_id(arena, &type_16); + res_out->name = coff_convert_resource_id(arena, &name_16); + res_out->language_id = language_id; + res_out->data_version = data_version; + res_out->version = version; + res_out->memory_flags = memory_flags; + res_out->data = data; + + U64 resource_size = AlignPow2(prefix.data_size + prefix.header_size, COFF_RES_ALIGN); + return resource_size; +} + +internal COFF_ResourceList +coff_resource_list_from_data(Arena *arena, String8 data) +{ + COFF_ResourceList list; MemoryZeroStruct(&list); + for (U64 cursor = 0, stride; cursor < data.size; cursor += stride) { + COFF_ResourceNode *node = push_array(arena, COFF_ResourceNode, 1); + stride = coff_read_resource(data, cursor, arena, &node->data); + list.count += 1; + SLLQueuePush(list.first, list.last, node); + } + return list; +} + +//////////////////////////////// + +internal COFF_DataType +coff_data_type_from_data(String8 data) +{ + B32 is_big_obj = coff_is_big_obj(data); + if (is_big_obj) { + return COFF_DataType_BIG_OBJ; + } + + B32 is_import = coff_is_import(data); + if (is_import) { + return COFF_DataType_IMPORT; + } + + return COFF_DataType_OBJ; +} + +internal B32 +coff_is_import(String8 data) +{ + B32 is_import = 0; + if (data.size >= sizeof(U16)*2) { + U16 *sig1 = (U16*)data.str; + U16 *sig2 = sig1 + 1; + is_import = *sig1 == COFF_MachineType_UNKNOWN && *sig2 == 0xffff; + } + return is_import; +} + +internal B32 +coff_is_archive(String8 data) +{ + U64 sig = 0; + str8_deserial_read_struct(data, 0, &sig); + B32 is_archive = sig == COFF_ARCHIVE_SIG; + return is_archive; +} + +internal B32 +coff_is_thin_archive(String8 data) +{ + U64 sig = 0; + str8_deserial_read_struct(data, 0, &sig); + B32 is_archive = sig == COFF_THIN_ARCHIVE_SIG; + return is_archive; +} + +internal U64 +coff_read_archive_member_header(String8 data, U64 offset, COFF_ArchiveMemberHeader *header_out) +{ +#define NAME_SIZE 16 +#define DATE_SIZE 12 +#define USER_ID_SIZE 6 +#define GROUP_ID_SIZE 6 +#define MODE_SIZE 8 +#define SIZE_SIZE 10 +#define TOTAL_SIZE (NAME_SIZE + DATE_SIZE + USER_ID_SIZE + GROUP_ID_SIZE + MODE_SIZE + SIZE_SIZE) + + if (str8_deserial_get_raw_ptr(data, offset, TOTAL_SIZE) == NULL) { + return 0; + } + + U64 read_offset = offset; + + U8 *name = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, NAME_SIZE); + read_offset += NAME_SIZE; + + U8 *date = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, DATE_SIZE); + read_offset += DATE_SIZE; + + U8 *user_id = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, USER_ID_SIZE); + read_offset += USER_ID_SIZE; + + U8 *group_id = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, GROUP_ID_SIZE); + read_offset += GROUP_ID_SIZE; + + U8 *mode = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, MODE_SIZE); + read_offset += MODE_SIZE; + + U8 *size = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, SIZE_SIZE); + read_offset += SIZE_SIZE; + + U8 end[] = { 0, 0 }; + read_offset += str8_deserial_read_array(data, read_offset, &end[0], ArrayCount(end)); + + U64 i; + for (i = 0; i < NAME_SIZE; ++i) { + if (name[i] == ' ') { + break; + } + } + header_out->name = str8(name, i); + header_out->date = (U32)s64_from_str8(str8(date, DATE_SIZE), 10); + header_out->user_id = (U32)s64_from_str8(str8(user_id, USER_ID_SIZE), 10); + header_out->group_id = (U32)s64_from_str8(str8(group_id, GROUP_ID_SIZE), 10); + header_out->mode = str8(mode, MODE_SIZE); + for (i = 0; i < SIZE_SIZE; ++i) { + if (size[i] == ' ') { + break; + } + } + header_out->size = (U32)s64_from_str8(str8(size, i), 10); + header_out->is_end_correct = (end[0] == '`' && end[1] == '\n'); + + U64 result = (read_offset - offset); + return result; + +#undef NAME_SIZE +#undef DATE_SIZE +#undef USER_ID_SIZE +#undef GROUP_ID_SIZE +#undef MODE_SIZE +#undef SIZE_SIZE +#undef TOTAL_SIZE +} + +internal COFF_ArchiveMember +coff_read_archive_member(String8 data, U64 offset) +{ + COFF_ArchiveMember member; MemoryZeroStruct(&member); + coff_archive_member_iter_next(data, &offset, &member); + return member; +} + +internal COFF_ArchiveMember +coff_archive_member_from_data(String8 data) +{ + return coff_read_archive_member(data, 0); +} + +internal U64 +coff_read_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out) +{ + U64 cursor = offset; + + cursor += str8_deserial_read_struct(data, cursor, &header_out->sig1); + cursor += str8_deserial_read_struct(data, cursor, &header_out->sig2); + cursor += str8_deserial_read_struct(data, cursor, &header_out->version); + cursor += str8_deserial_read_struct(data, cursor, &header_out->machine); + cursor += str8_deserial_read_struct(data, cursor, &header_out->time_stamp); + cursor += str8_deserial_read_struct(data, cursor, &header_out->data_size); + cursor += str8_deserial_read_struct(data, cursor, &header_out->hint); + + U16 flags = 0; + cursor += str8_deserial_read_struct(data, cursor, &flags); + header_out->type = COFF_IMPORT_HEADER_GET_TYPE(flags); + header_out->name_type = COFF_IMPORT_HEADER_GET_NAME_TYPE(flags); + + header_out->func_name = str8(0,0); + cursor += str8_deserial_read_cstr(data, cursor, &header_out->func_name); + + header_out->dll_name = str8(0,0); + cursor += str8_deserial_read_cstr(data, cursor, &header_out->dll_name); + + Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size); + + U64 read_size = cursor - offset; + return read_size; +} + +internal COFF_ImportHeader +coff_archive_import_from_data(String8 data) +{ + COFF_ImportHeader header; MemoryZeroStruct(&header); + coff_read_archive_import(data, 0, &header); + return header; +} + +internal String8 +coff_read_archive_long_name(String8 long_names, String8 name) +{ + String8 result = name; + if (name.size > 0 && name.str[0] == '/') { + String8 offset_str = str8(name.str + 1, name.size - 1); + U64 offset = u64_from_str8(offset_str, 10); + if (offset < long_names.size) { + U8 *ptr = long_names.str + offset; + U8 *opl = long_names.str + long_names.size; + for (; ptr < opl; ++ptr) { + if (*ptr == '\0' || *ptr == '\n') { + break; + } + } + result = str8_range(long_names.str + offset, ptr); + } + } + return result; +} + +internal U64 +coff_archive_member_iter_init(String8 data) +{ + U64 cursor = 0; + U64 sig = 0; + cursor += str8_deserial_read_struct(data, cursor, &sig); + if (sig != COFF_ARCHIVE_SIG) { + cursor = data.size; + } + return cursor; +} + +internal B32 +coff_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out) +{ + B32 is_parsed; + + COFF_ArchiveMemberHeader header; + U64 header_read_size = coff_read_archive_member_header(data, *offset, &header); + + if (header_read_size && header.is_end_correct) { + Rng1U64 data_range = rng_1u64(*offset + header_read_size, *offset + header_read_size + header.size); + + member_out->header = header; + member_out->offset = *offset; + member_out->data = str8_substr(data, data_range); + + *offset += header_read_size; + *offset += member_out->header.size; + *offset = AlignPow2(*offset, COFF_ARCHIVE_ALIGN); + + is_parsed = 1; + } else { + MemoryZeroStruct(&member_out->header); + member_out->offset = max_U64; + member_out->data = str8(0,0); + + is_parsed = 0; + } + + return is_parsed; +} + +internal B32 +coff_get_first_archive_member(COFF_ArchiveMember *member, COFF_ArchiveFirstMember *first_out) +{ + B32 is_header = str8_match(member->header.name, str8_lit("/"), 0); + if (is_header) { + U64 cursor = 0; + + U32 symbol_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); + +#if ARCH_LITTLE_ENDIAN + symbol_count = bswap_u32(symbol_count); +#endif + + Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32)); + cursor += dim_1u64(member_offsets_range); + + Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); + cursor += dim_1u64(string_table_range); + + first_out->symbol_count = symbol_count; + first_out->member_offsets = str8_substr(member->data, member_offsets_range); + first_out->string_table = str8_substr(member->data, string_table_range); + } + return is_header; +} + +internal B32 +coff_get_second_archive_member(COFF_ArchiveMember *member, COFF_ArchiveSecondMember *second_out) +{ + B32 is_header = str8_match(member->header.name, str8_lit("/"), 0); + if (is_header) { + U64 cursor = 0; + + U32 member_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &member_count); + + Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32)); + cursor += dim_1u64(member_offsets_range); + + U32 symbol_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); + + Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16)); + cursor += dim_1u64(symbol_indices_range); + + Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); + + second_out->member_count = member_count; + second_out->symbol_count = symbol_count; + second_out->member_offsets = str8_substr(member->data, member_offsets_range); + second_out->symbol_indices = str8_substr(member->data, symbol_indices_range); + second_out->string_table = str8_substr(member->data, string_table_range); + } + return is_header; +} + +internal void +coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node) +{ + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal COFF_ArchiveParse +coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) +{ + COFF_ArchiveMember first_header; MemoryZeroStruct(&first_header); + COFF_ArchiveMember second_header; MemoryZeroStruct(&second_header); + COFF_ArchiveMember long_names_member; MemoryZeroStruct(&long_names_member); + + if (member_list.count) { + if (str8_match(member_list.first->data.header.name, str8_lit("/"), 0)) { + first_header = member_list.first->data; + SLLQueuePop(member_list.first, member_list.last); + member_list.count -= 1; + + if (member_list.count && str8_match(member_list.first->data.header.name, str8_lit("/"), 0)) { + second_header = member_list.first->data; + SLLQueuePop(member_list.first, member_list.last); + member_list.count -= 1; + } + + if (member_list.count && str8_match(member_list.first->data.header.name, str8_lit("//"), 0)) { + long_names_member = member_list.first->data; + SLLQueuePop(member_list.first, member_list.last); + member_list.count -= 1; + } + } + } + + COFF_ArchiveFirstMember first_member; MemoryZeroStruct(&first_member); + coff_get_first_archive_member(&first_header, &first_member); + + COFF_ArchiveSecondMember second_member; MemoryZeroStruct(&second_member); + coff_get_second_archive_member(&second_header, &second_member); + + COFF_ArchiveParse parse; MemoryZeroStruct(&parse); + parse.first_member = first_member; + parse.second_member = second_member; + parse.long_names = long_names_member.data; + + return parse; +} + +internal COFF_ArchiveParse +coff_archive_from_data(Arena *arena, String8 data) +{ + COFF_ArchiveMemberList list; MemoryZeroStruct(&list); + COFF_ArchiveMemberNode node_arr[3]; MemoryZeroStruct(&node_arr[0]); + U64 cursor = coff_archive_member_iter_init(data); + for (U64 i = 0; i < ArrayCount(node_arr); i += 1) { + COFF_ArchiveMemberNode *node = &node_arr[i]; + if (!coff_archive_member_iter_next(data, &cursor, &node->data)) { + break; + } + coff_archive_member_list_push_node(&list, node); + } + return coff_archive_parse_from_member_list(list); +} + +internal U64 +coff_thin_archive_member_iter_init(String8 data) +{ + U64 cursor = 0; + U64 sig = 0; + cursor += str8_deserial_read_struct(data, cursor, &sig); + if (sig != COFF_THIN_ARCHIVE_SIG) { + cursor = data.size; + } + return cursor; +} + +internal B32 +coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out) +{ + B32 is_parsed = 0; + + U64 header_size = coff_read_archive_member_header(data, *offset, &member_out->header); + if (header_size) { + member_out->offset = *offset; + *offset += header_size; + if (str8_match(member_out->header.name, str8_lit("/"), 0) || str8_match(member_out->header.name, str8_lit("//"), 0)) { + Rng1U64 data_range = rng_1u64(*offset, *offset + member_out->header.size); + member_out->data = str8_substr(data, data_range); + *offset += member_out->header.size; + } else { + // size field in non-header members means size of stand-alone obj + member_out->data = str8(0,0); + } + *offset = AlignPow2(*offset, COFF_ARCHIVE_ALIGN); + is_parsed = 1; + } + + return is_parsed; +} + +internal COFF_ArchiveParse +coff_thin_archive_from_data(Arena *arena, String8 data) +{ + COFF_ArchiveMemberList list; MemoryZeroStruct(&list); + COFF_ArchiveMemberNode node_arr[3]; MemoryZeroStruct(&node_arr[0]); + U64 cursor = coff_thin_archive_member_iter_init(data); + for (U64 i = 0; i < ArrayCount(node_arr); i += 1) { + COFF_ArchiveMemberNode *node = &node_arr[i]; + if (!coff_thin_archive_member_iter_next(data, &cursor, &node->data)) { + break; + } + coff_archive_member_list_push_node(&list, node); + } + return coff_archive_parse_from_member_list(list); +} + +internal COFF_ArchiveType +coff_archive_type_from_data(String8 data) +{ + if (coff_is_archive(data)) { + return COFF_Archive_Regular; + } else if (coff_is_thin_archive(data)) { + return COFF_Archive_Thin; + } + return COFF_Archive_Null; +} + +internal COFF_ArchiveParse +coff_archive_parse_from_data(Arena *arena, String8 data) +{ + COFF_ArchiveType type = coff_archive_type_from_data(data); + switch (type) { + case COFF_Archive_Null: break; + case COFF_Archive_Regular: return coff_archive_from_data(arena, data); + case COFF_Archive_Thin: return coff_thin_archive_from_data(arena, data); + } + COFF_ArchiveParse null_parse; MemoryZeroStruct(&null_parse); + return null_parse; +} + +//////////////////////////////// + +internal String8 +coff_string_from_comdat_select_type(COFF_ComdatSelectType select) +{ + String8 result = str8(0,0); + switch (select) { + case COFF_ComdatSelectType_NULL: result = str8_lit("NULL"); break; + case COFF_ComdatSelectType_NODUPLICATES: result = str8_lit("NODUPLICATES"); break; + case COFF_ComdatSelectType_ANY: result = str8_lit("ANY"); break; + case COFF_ComdatSelectType_SAME_SIZE: result = str8_lit("SAME_SIZE"); break; + case COFF_ComdatSelectType_EXACT_MATCH: result = str8_lit("EXACT_MATCH"); break; + case COFF_ComdatSelectType_ASSOCIATIVE: result = str8_lit("ASSOCIATIVE"); break; + case COFF_ComdatSelectType_LARGEST: result = str8_lit("LARGEST"); break; + } + return result; +} + +internal String8 +coff_string_from_machine_type(COFF_MachineType machine) +{ + String8 result = str8(0,0); + switch (machine) { + case COFF_MachineType_UNKNOWN: result = str8_lit("UNKNOWN"); break; + case COFF_MachineType_X86: result = str8_lit("X86"); break; + case COFF_MachineType_X64: result = str8_lit("X64"); break; + case COFF_MachineType_ARM33: result = str8_lit("ARM33"); break; + case COFF_MachineType_ARM: result = str8_lit("ARM"); break; + case COFF_MachineType_ARM64: result = str8_lit("ARM64"); break; + case COFF_MachineType_ARMNT: result = str8_lit("ARMNT"); break; + case COFF_MachineType_EBC: result = str8_lit("EBC"); break; + case COFF_MachineType_IA64: result = str8_lit("IA64"); break; + case COFF_MachineType_M32R: result = str8_lit("M32R"); break; + case COFF_MachineType_MIPS16: result = str8_lit("MIPS16"); break; + case COFF_MachineType_MIPSFPU: result = str8_lit("MIPSFPU"); break; + case COFF_MachineType_MIPSFPU16: result = str8_lit("MIPSFPU16"); break; + case COFF_MachineType_POWERPC: result = str8_lit("POWERPC"); break; + case COFF_MachineType_POWERPCFP: result = str8_lit("POWERPCFP"); break; + case COFF_MachineType_R4000: result = str8_lit("R4000"); break; + case COFF_MachineType_RISCV32: result = str8_lit("RISCV32"); break; + case COFF_MachineType_RISCV64: result = str8_lit("RISCV64"); break; + case COFF_MachineType_RISCV128: result = str8_lit("RISCV128"); break; + case COFF_MachineType_SH3: result = str8_lit("SH3"); break; + case COFF_MachineType_SH3DSP: result = str8_lit("SH3DSP"); break; + case COFF_MachineType_SH4: result = str8_lit("SH4"); break; + case COFF_MachineType_SH5: result = str8_lit("SH5"); break; + case COFF_MachineType_THUMB: result = str8_lit("THUMB"); break; + case COFF_MachineType_WCEMIPSV2: result = str8_lit("WCEMIPSV2"); break; + } + return result; +} + +internal String8 +coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + if (flags & COFF_SectionFlag_TYPE_NO_PAD) { + str8_list_pushf(scratch.arena, &list, "TYPE_NO_PAD"); + } + if (flags & COFF_SectionFlag_CNT_CODE) { + str8_list_pushf(scratch.arena, &list, "CNT_CODE"); + } + if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) { + str8_list_pushf(scratch.arena, &list, "CNT_INITIALIZED_DATA"); + } + if (flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) { + str8_list_pushf(scratch.arena, &list, "CNT_UNINITIALIZED_DATA"); + } + if (flags & COFF_SectionFlag_LNK_OTHER) { + str8_list_pushf(scratch.arena, &list, "LNK_OTHER"); + } + if (flags & COFF_SectionFlag_LNK_INFO) { + str8_list_pushf(scratch.arena, &list, "LNK_INFO"); + } + if (flags & COFF_SectionFlag_LNK_COMDAT) { + str8_list_pushf(scratch.arena, &list, "LNK_COMDAT"); + } + if (flags & COFF_SectionFlag_GPREL) { + str8_list_pushf(scratch.arena, &list, "GPREL"); + } + if (flags & COFF_SectionFlag_MEM_16BIT) { + str8_list_pushf(scratch.arena, &list, "MEM_16BIT"); + } + if (flags & COFF_SectionFlag_MEM_LOCKED) { + str8_list_pushf(scratch.arena, &list, "MEM_LOCKED"); + } + if (flags & COFF_SectionFlag_MEM_PRELOAD) { + str8_list_pushf(scratch.arena, &list, "MEM_PRELOAD"); + } + if (flags & COFF_SectionFlag_LNK_NRELOC_OVFL) { + str8_list_pushf(scratch.arena, &list, "LNK_NRELOC_OVFL"); + } + if (flags & COFF_SectionFlag_MEM_DISCARDABLE) { + str8_list_pushf(scratch.arena, &list, "MEM_DISCARDABLE"); + } + if (flags & COFF_SectionFlag_MEM_NOT_CACHED) { + str8_list_pushf(scratch.arena, &list, "MEM_NOT_CACHED"); + } + if (flags & COFF_SectionFlag_MEM_NOT_PAGED) { + str8_list_pushf(scratch.arena, &list, "MEM_NOT_PAGED"); + } + if (flags & COFF_SectionFlag_MEM_SHARED) { + str8_list_pushf(scratch.arena, &list, "MEM_SHARED"); + } + if (flags & COFF_SectionFlag_MEM_EXECUTE) { + str8_list_pushf(scratch.arena, &list, "MEM_EXECUTE"); + } + if (flags & COFF_SectionFlag_MEM_READ) { + str8_list_pushf(scratch.arena, &list, "MEM_READ"); + } + if (flags & COFF_SectionFlag_MEM_WRITE) { + str8_list_pushf(scratch.arena, &list, "MEM_WRITE"); + } + + U64 align = COFF_SectionFlags_Extract_ALIGN(flags); + if (align) { + str8_list_pushf(scratch.arena, &list, "ALIGN=%u", align); + } + + StringJoin join = {0}; + join.sep = str8_lit(", "); + String8 result = str8_list_join(arena, &list, &join); + + scratch_end(scratch); + return result; +} + diff --git a/src/coff/coff.h b/src/coff/coff.h new file mode 100644 index 00000000..6563a4b0 --- /dev/null +++ b/src/coff/coff.h @@ -0,0 +1,872 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef COFF_H +#define COFF_H + +typedef U32 COFF_TimeStamp; + +//////////////////////////////// +//~ rjf: Coff Format Types + +#pragma pack(push,1) + +typedef U16 COFF_Flags; +enum +{ + COFF_Flag_RELOC_STRIPPED = (1 << 0), + COFF_Flag_EXECUTABLE_IMAGE = (1 << 1), + COFF_Flag_LINE_NUMS_STRIPPED = (1 << 2), + COFF_Flag_SYM_STRIPPED = (1 << 3), + COFF_Flag_RESERVED_0 = (1 << 4), + COFF_Flag_LARGE_ADDRESS_AWARE = (1 << 5), + COFF_Flag_RESERVED_1 = (1 << 6), + COFF_Flag_RESERVED_2 = (1 << 7), + COFF_Flag_32BIT_MACHINE = (1 << 8), + COFF_Flag_DEBUG_STRIPPED = (1 << 9), + COFF_Flag_REMOVABLE_RUN_FROM_SWAP = (1 << 10), + COFF_Flag_NET_RUN_FROM_SWAP = (1 << 11), + COFF_Flag_SYSTEM = (1 << 12), + COFF_Flag_DLL = (1 << 13), + COFF_Flag_UP_SYSTEM_ONLY = (1 << 14), + COFF_Flag_BYTES_RESERVED_HI = (1 << 15), +}; + +typedef U16 COFF_MachineType; +enum +{ + COFF_MachineType_UNKNOWN = 0x0, + COFF_MachineType_X86 = 0x14c, + COFF_MachineType_X64 = 0x8664, + COFF_MachineType_ARM33 = 0x1d3, + COFF_MachineType_ARM = 0x1c0, + COFF_MachineType_ARM64 = 0xaa64, + COFF_MachineType_ARMNT = 0x1c4, + COFF_MachineType_EBC = 0xebc, + COFF_MachineType_IA64 = 0x200, + COFF_MachineType_M32R = 0x9041, + COFF_MachineType_MIPS16 = 0x266, + COFF_MachineType_MIPSFPU = 0x366, + COFF_MachineType_MIPSFPU16 = 0x466, + COFF_MachineType_POWERPC = 0x1f0, + COFF_MachineType_POWERPCFP = 0x1f1, + COFF_MachineType_R4000 = 0x166, + COFF_MachineType_RISCV32 = 0x5032, + COFF_MachineType_RISCV64 = 0x5064, + COFF_MachineType_RISCV128 = 0x5128, + COFF_MachineType_SH3 = 0x1a2, + COFF_MachineType_SH3DSP = 0x1a3, + COFF_MachineType_SH4 = 0x1a6, + COFF_MachineType_SH5 = 0x1a8, + COFF_MachineType_THUMB = 0x1c2, + COFF_MachineType_WCEMIPSV2 = 0x169, + COFF_MachineType_COUNT = 25 +}; + +typedef struct COFF_Header COFF_Header; +struct COFF_Header +{ + COFF_MachineType machine; + U16 section_count; + COFF_TimeStamp time_stamp; + U32 symbol_table_foff; + U32 symbol_count; + U16 optional_header_size; + COFF_Flags flags; +}; + +typedef U32 COFF_SectionAlign; +enum +{ + COFF_SectionAlign_1BYTES = 0x1, + COFF_SectionAlign_2BYTES = 0x2, + COFF_SectionAlign_4BYTES = 0x3, + COFF_SectionAlign_8BYTES = 0x4, + COFF_SectionAlign_16BYTES = 0x5, + COFF_SectionAlign_32BYTES = 0x6, + COFF_SectionAlign_64BYTES = 0x7, + COFF_SectionAlign_128BYTES = 0x8, + COFF_SectionAlign_256BYTES = 0x9, + COFF_SectionAlign_512BYTES = 0xA, + COFF_SectionAlign_1024BYTES = 0xB, + COFF_SectionAlign_2048BYTES = 0xC, + COFF_SectionAlign_4096BYTES = 0xD, + COFF_SectionAlign_8192BYTES = 0xE, + COFF_SectionAlign_COUNT = 14 +}; + +typedef U32 COFF_SectionFlags; +enum +{ + COFF_SectionFlag_TYPE_NO_PAD = (1 << 3), + COFF_SectionFlag_CNT_CODE = (1 << 5), + COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6), + COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7), + COFF_SectionFlag_LNK_OTHER = (1 << 8), + COFF_SectionFlag_LNK_INFO = (1 << 9), + COFF_SectionFlag_LNK_REMOVE = (1 << 11), + COFF_SectionFlag_LNK_COMDAT = (1 << 12), + COFF_SectionFlag_GPREL = (1 << 15), + COFF_SectionFlag_MEM_16BIT = (1 << 17), + COFF_SectionFlag_MEM_LOCKED = (1 << 18), + COFF_SectionFlag_MEM_PRELOAD = (1 << 19), + COFF_SectionFlag_ALIGN_SHIFT = 20, COFF_SectionFlag_ALIGN_MASK = 0xf, + COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24), + COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25), + COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26), + COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27), + COFF_SectionFlag_MEM_SHARED = (1 << 28), + COFF_SectionFlag_MEM_EXECUTE = (1 << 29), + COFF_SectionFlag_MEM_READ = (1 << 30), + COFF_SectionFlag_MEM_WRITE = (1 << 31), +}; +#define COFF_SectionFlags_Extract_ALIGN(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_ALIGN_SHIFT) & COFF_SectionFlag_ALIGN_MASK) +#define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL) + +typedef struct COFF_SectionHeader COFF_SectionHeader; +struct COFF_SectionHeader +{ + U8 name[8]; + U32 vsize; + U32 voff; + U32 fsize; + U32 foff; + U32 relocs_foff; + U32 lines_foff; + U16 reloc_count; + U16 line_count; + COFF_SectionFlags flags; +}; + +typedef U16 COFF_RelocTypeX64; +enum +{ + COFF_RelocTypeX64_ABS = 0x0, + COFF_RelocTypeX64_ADDR64 = 0x1, + COFF_RelocTypeX64_ADDR32 = 0x2, + COFF_RelocTypeX64_ADDR32NB = 0x3, + // NB => No Base + COFF_RelocTypeX64_REL32 = 0x4, + COFF_RelocTypeX64_REL32_1 = 0x5, + COFF_RelocTypeX64_REL32_2 = 0x6, + COFF_RelocTypeX64_REL32_3 = 0x7, + COFF_RelocTypeX64_REL32_4 = 0x8, + COFF_RelocTypeX64_REL32_5 = 0x9, + COFF_RelocTypeX64_SECTION = 0xA, + COFF_RelocTypeX64_SECREL = 0xB, + COFF_RelocTypeX64_SECREL7 = 0xC, + // TODO(nick): MSDN doesn't specify size for CLR token + COFF_RelocTypeX64_TOKEN = 0xD, + COFF_RelocTypeX64_SREL32 = 0xE, + // TODO(nick): MSDN doesn't specify size for PAIR + COFF_RelocTypeX64_PAIR = 0xF, + COFF_RelocTypeX64_SSPAN32 = 0x10, + COFF_RelocTypeX64_COUNT = 17 +}; + +typedef U16 COFF_RelocTypeX86; +enum +{ + COFF_RelocTypeX86_ABS = 0x0, + // relocation is ignored + COFF_RelocTypeX86_DIR16 = 0x1, + // no support + COFF_RelocTypeX86_REL16 = 0x2, + // no support + COFF_RelocTypeX86_UNKNOWN0 = 0x3, + COFF_RelocTypeX86_UNKNOWN2 = 0x4, + COFF_RelocTypeX86_UNKNOWN3 = 0x5, + COFF_RelocTypeX86_DIR32 = 0x6, + // 32-bit virtual address + COFF_RelocTypeX86_DIR32NB = 0x7, + // 32-bit virtual offset + COFF_RelocTypeX86_SEG12 = 0x9, + // no support + COFF_RelocTypeX86_SECTION = 0xA, + // 16-bit section index, used for debug info purposes + COFF_RelocTypeX86_SECREL = 0xB, + // 32-bit offset from start of a section + COFF_RelocTypeX86_TOKEN = 0xC, + // CLR token? (for managed languages) + COFF_RelocTypeX86_SECREL7 = 0xD, + // 7-bit offset from the base of the section that contains the target. + COFF_RelocTypeX86_UNKNOWN4 = 0xE, + COFF_RelocTypeX86_UNKNOWN5 = 0xF, + COFF_RelocTypeX86_UNKNOWN6 = 0x10, + COFF_RelocTypeX86_UNKNOWN7 = 0x11, + COFF_RelocTypeX86_UNKNOWN8 = 0x12, + COFF_RelocTypeX86_UNKNOWN9 = 0x13, + COFF_RelocTypeX86_REL32 = 0x14, + COFF_RelocTypeX86_COUNT = 20 +}; + +typedef U16 COFF_RelocTypeARM; +enum +{ + COFF_RelocTypeARM_ABS = 0x0, + COFF_RelocTypeARM_ADDR32 = 0x1, + COFF_RelocTypeARM_ADDR32NB = 0x2, + COFF_RelocTypeARM_BRANCH24 = 0x3, + COFF_RelocTypeARM_BRANCH11 = 0x4, + COFF_RelocTypeARM_UNKNOWN1 = 0x5, + COFF_RelocTypeARM_UNKNOWN2 = 0x6, + COFF_RelocTypeARM_UNKNOWN3 = 0x7, + COFF_RelocTypeARM_UNKNOWN4 = 0x8, + COFF_RelocTypeARM_UNKNOWN5 = 0x9, + COFF_RelocTypeARM_REL32 = 0xA, + COFF_RelocTypeARM_SECTION = 0xE, + COFF_RelocTypeARM_SECREL = 0xF, + COFF_RelocTypeARM_MOV32 = 0x10, + COFF_RelocTypeARM_THUMB_MOV32 = 0x11, + COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12, + COFF_RelocTypeARM_UNUSED = 0x13, + COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14, + COFF_RelocTypeARM_THUMB_BLX23 = 0x15, + COFF_RelocTypeARM_PAIR = 0x16, + COFF_RelocTypeARM_COUNT = 20 +}; + +typedef U16 COFF_RelocTypeARM64; +enum +{ + COFF_RelocTypeARM64_ABS = 0x0, + COFF_RelocTypeARM64_ADDR32 = 0x1, + COFF_RelocTypeARM64_ADDR32NB = 0x2, + COFF_RelocTypeARM64_BRANCH26 = 0x3, + COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4, + COFF_RelocTypeARM64_REL21 = 0x5, + COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6, + COFF_RelocTypeARM64_SECREL = 0x8, + COFF_RelocTypeARM64_SECREL_LOW12A = 0x9, + COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA, + COFF_RelocTypeARM64_SECREL_LOW12L = 0xB, + COFF_RelocTypeARM64_TOKEN = 0xC, + COFF_RelocTypeARM64_SECTION = 0xD, + COFF_RelocTypeARM64_ADDR64 = 0xE, + COFF_RelocTypeARM64_BRANCH19 = 0xF, + COFF_RelocTypeARM64_BRANCH14 = 0x10, + COFF_RelocTypeARM64_REL32 = 0x11, + COFF_RelocTypeARM64_COUNT = 17 +}; + +typedef U8 COFF_SymType; +enum +{ + COFF_SymType_NULL, + COFF_SymType_VOID, + COFF_SymType_CHAR, + COFF_SymType_SHORT, + COFF_SymType_INT, + COFF_SymType_LONG, + COFF_SymType_FLOAT, + COFF_SymType_DOUBLE, + COFF_SymType_STRUCT, + COFF_SymType_UNION, + COFF_SymType_ENUM, + COFF_SymType_MOE, + // member of enumeration + COFF_SymType_BYTE, + COFF_SymType_WORD, + COFF_SymType_UINT, + COFF_SymType_DWORD, + COFF_SymType_COUNT = 16 +}; + +typedef U8 COFF_SymStorageClass; +enum +{ + COFF_SymStorageClass_END_OF_FUNCTION = 0xff, + COFF_SymStorageClass_NULL = 0, + COFF_SymStorageClass_AUTOMATIC = 1, + COFF_SymStorageClass_EXTERNAL = 2, + COFF_SymStorageClass_STATIC = 3, + COFF_SymStorageClass_REGISTER = 4, + COFF_SymStorageClass_EXTERNAL_DEF = 5, + COFF_SymStorageClass_LABEL = 6, + COFF_SymStorageClass_UNDEFINED_LABEL = 7, + COFF_SymStorageClass_MEMBER_OF_STRUCT = 8, + COFF_SymStorageClass_ARGUMENT = 9, + COFF_SymStorageClass_STRUCT_TAG = 10, + COFF_SymStorageClass_MEMBER_OF_UNION = 11, + COFF_SymStorageClass_UNION_TAG = 12, + COFF_SymStorageClass_TYPE_DEFINITION = 13, + COFF_SymStorageClass_UNDEFINED_STATIC = 14, + COFF_SymStorageClass_ENUM_TAG = 15, + COFF_SymStorageClass_MEMBER_OF_ENUM = 16, + COFF_SymStorageClass_REGISTER_PARAM = 17, + COFF_SymStorageClass_BIT_FIELD = 18, + COFF_SymStorageClass_BLOCK = 100, + COFF_SymStorageClass_FUNCTION = 101, + COFF_SymStorageClass_END_OF_STRUCT = 102, + COFF_SymStorageClass_FILE = 103, + COFF_SymStorageClass_SECTION = 104, + COFF_SymStorageClass_WEAK_EXTERNAL = 105, + COFF_SymStorageClass_CLR_TOKEN = 107, + COFF_SymStorageClass_COUNT = 27 +}; + +typedef U16 COFF_SymSecNumber; +enum +{ + COFF_SymSecNumber_NUMBER_UNDEFINED = 0, + COFF_SymSecNumber_ABSOLUTE = 0xffff, + COFF_SymSecNumber_DEBUG = 0xfffe, + COFF_SymSecNumber_COUNT = 3 +}; + +typedef U8 COFF_SymDType; +enum +{ + COFF_SymDType_NULL = 0, + COFF_SymDType_PTR = 16, + COFF_SymDType_FUNC = 32, + COFF_SymDType_ARRAY = 48, + COFF_SymDType_COUNT = 4 +}; + +typedef U32 COFF_WeakExtType; +enum +{ + COFF_WeakExtType_NOLIBRARY = 1, + COFF_WeakExtType_SEARCH_LIBRARY = 2, + COFF_WeakExtType_SEARCH_ALIAS = 3, + COFF_WeakExtType_COUNT = 3 +}; + +typedef U32 COFF_ImportHeaderType; +enum +{ + COFF_ImportHeaderType_CODE = 0, + COFF_ImportHeaderType_DATA = 1, + COFF_ImportHeaderType_CONST = 2, + COFF_ImportHeaderType_COUNT = 3 +}; + +typedef U32 COFF_ImportHeaderNameType; +enum +{ + COFF_ImportHeaderNameType_ORDINAL = 0, + COFF_ImportHeaderNameType_NAME = 1, + COFF_ImportHeaderNameType_NAME_NOPREFIX = 2, + COFF_ImportHeaderNameType_UNDECORATE = 3, + COFF_ImportHeaderNameType_COUNT = 4 +}; + +#define COFF_IMPORT_HEADER_TYPE_MASK 0x03 +#define COFF_IMPORT_HEADER_TYPE_SHIFT 0 +#define COFF_IMPORT_HEADER_NAME_TYPE_MASK 0x1c +#define COFF_IMPORT_HEADER_NAME_TYPE_SHIFT 2 +#define COFF_IMPORT_HEADER_GET_TYPE(x) (((x) & COFF_IMPORT_HEADER_TYPE_MASK) >> COFF_IMPORT_HEADER_TYPE_SHIFT) +#define COFF_IMPORT_HEADER_GET_NAME_TYPE(x) (((x) & COFF_IMPORT_HEADER_NAME_TYPE_MASK) >> COFF_IMPORT_HEADER_NAME_TYPE_SHIFT) +typedef struct COFF_ImportHeader +{ + U16 sig1; + U16 sig2; + U16 version; + U16 machine; + COFF_TimeStamp time_stamp; + U32 data_size; + U16 hint; + U16 type; + U16 name_type; + // type : 2 + // name type : 3 + // reserved : 11 + //U16 flags; + String8 func_name; + String8 dll_name; +} COFF_ImportHeader; + +typedef U8 COFF_ComdatSelectType; +enum +{ + COFF_ComdatSelectType_NULL = 0, + // Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown. + COFF_ComdatSelectType_NODUPLICATES = 1, + // Select any symbol, even if there are multiple definitions. (we default to first declaration) + COFF_ComdatSelectType_ANY = 2, + // Sections that symbols reference must match in size, otherwise multiply definition error is thrown. + COFF_ComdatSelectType_SAME_SIZE = 3, + // Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown. + COFF_ComdatSelectType_EXACT_MATCH = 4, + // Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number') + COFF_ComdatSelectType_ASSOCIATIVE = 5, + // Linker selects section with largest size. + COFF_ComdatSelectType_LARGEST = 6, + COFF_ComdatSelectType_COUNT = 7 +}; + +#define COFF_MIN_BIG_OBJ_VERSION 2 + +global U8 coff_big_obj_magic[] = +{ + 0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B, + 0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8, +}; + +typedef struct COFF_HeaderBigObj COFF_HeaderBigObj; +struct COFF_HeaderBigObj +{ + U16 sig1; // COFF_MachineType_UNKNOWN + U16 sig2; // U16_MAX + U16 version; + U16 machine; + U32 time_stamp; + U8 magic[16]; + U32 unused[4]; + U32 section_count; + U32 pointer_to_symbol_table; + U32 number_of_symbols; +}; + +// Special values for section number field in coff symbol +#define COFF_SYMBOL_UNDEFINED_SECTION 0 +#define COFF_SYMBOL_ABS_SECTION ((U32)-1) +#define COFF_SYMBOL_DEBUG_SECTION ((U32)-2) +#define COFF_SYMBOL_ABS_SECTION_16 ((U16)-1) +#define COFF_SYMBOL_DEBUG_SECTION_16 ((U16)-2) + +typedef union COFF_SymbolName COFF_SymbolName; +union COFF_SymbolName +{ + U8 short_name[8]; + struct + { + // if this field is filled with zeroes we have a long name, + // which means name is stored in the string table + // and we need to use the offset to look it up... + U32 zeroes; + U32 string_table_offset; + }long_name; +}; + +typedef struct COFF_Symbol16 COFF_Symbol16; +struct COFF_Symbol16 +{ + COFF_SymbolName name; + U32 value; + U16 section_number; + union + { + struct + { + COFF_SymDType msb; + COFF_SymType lsb; + }u; + U16 v; + }type; + COFF_SymStorageClass storage_class; + U8 aux_symbol_count; +}; + +typedef struct COFF_Symbol32 COFF_Symbol32; +struct COFF_Symbol32 +{ + COFF_SymbolName name; + U32 value; + U32 section_number; + union + { + struct + { + COFF_SymDType msb; + COFF_SymType lsb; + }u; + U16 v; + }type; + COFF_SymStorageClass storage_class; + U8 aux_symbol_count; +}; + +// Auxilary symbols are allocated with fixed size so that symbol table could be maintaned as array of regular size. +#define COFF_AUX_SYMBOL_SIZE 18 + +// storage class: FUNCTION +typedef struct COFF_SymbolFunc +{ + U8 unused[4]; + U16 ln; + U8 unused2[2]; + U32 ptr_to_next_func; + U8 unused3[2]; +} COFF_SymbolFunc; + +// storage class: WEAK_EXTERNAL +typedef struct COFF_SymbolWeakExt +{ + U32 tag_index; + U32 characteristics; + U8 unused[10]; +} COFF_SymbolWeakExt; + +typedef struct COFF_SymbolFile +{ + char name[18]; +} COFF_SymbolFile; + +// provides information about section to which symbol refers to. +// storage class: STATIC +typedef struct COFF_SymbolSecDef +{ + U32 length; + U16 number_of_relocations; + U16 number_of_ln; + U32 check_sum; + U16 number; // one-based section index + U8 selection; + U8 unused[3]; +} COFF_SymbolSecDef; + +// specifies how section data should be modified when placed in the image file. +typedef struct COFF_Reloc COFF_Reloc; +struct COFF_Reloc +{ + U32 apply_off; // section relative offset where relocation is placed + U32 isymbol; // zero based index into coff symbol table + U16 type; // relocation type that depends on the arch +}; + +#pragma pack(pop) + +// feature flags in absolute symbol @feat.00 +enum +{ + COFF_FeatFlag_HAS_SAFE_SEH = (1 << 0), // /safeseh + COFF_FeatFlag_UNKNOWN_4 = (1 << 4), + COFF_FeatFlag_GUARD_STACK = (1 << 8), // /GS + COFF_FeatFlag_SDL = (1 << 9), // /sdl + COFF_FeatFlag_GUARD_CF = (1 << 11), // /guard:cf + COFF_FeatFlag_GUARD_EH_CONT = (1 << 14), // /guard:ehcont + COFF_FeatFlag_NO_RTTI = (1 << 17), // /GR- + COFF_FeatFlag_KERNEL = (1 << 30), // /kernel +}; +typedef U32 COFF_FeatFlags; + +//////////////////////////////// + +#define COFF_RES_ALIGN 4u + +typedef struct COFF_ResourceHeaderPrefix +{ + U32 data_size; + U32 header_size; +} COFF_ResourceHeaderPrefix; + +typedef U16 COFF_ResourceMemoryFlags; +enum +{ + COFF_ResourceMemoryFlag_MOVEABLE = 0x10, + COFF_ResourceMemoryFlag_PURE = 0x20, + COFF_ResourceMemoryFlag_PRELOAD = 0x40, + COFF_ResourceMemoryFlag_DISCARDABLE = 0x1000, +}; + +typedef enum +{ + COFF_ResourceIDType_NULL, + COFF_ResourceIDType_NUMBER, + COFF_ResourceIDType_STRING, + COFF_ResourceIDType_COUNT +} COFF_ResourceIDType; + +typedef struct COFF_ResourceID_16 +{ + COFF_ResourceIDType type; + union + { + U16 number; + String16 string; + } u; +} COFF_ResourceID_16; + +typedef struct COFF_ResourceID +{ + COFF_ResourceIDType type; + union + { + U16 number; + String8 string; + } u; +} COFF_ResourceID; + +typedef struct COFF_Resource +{ + COFF_ResourceID type; + COFF_ResourceID name; + U16 language_id; + U32 data_version; + U32 version; + COFF_ResourceMemoryFlags memory_flags; + String8 data; +} COFF_Resource; + +typedef struct COFF_ResourceDataEntry +{ + U32 data_voff; + U32 data_size; + U32 code_page; + U32 reserved; +} COFF_ResourceDataEntry; + +typedef struct COFF_ResourceDirTable +{ + U32 characteristics; + COFF_TimeStamp time_stamp; + U16 major_version; + U16 minor_version; + U16 name_entry_count; + U16 id_entry_count; +} COFF_ResourceDirTable; + +#define COFF_RESOURCE_SUB_DIR_FLAG (1u << 31u) +typedef struct COFF_ResourceDirEntry +{ + union { + U32 offset; + U32 id; + } name; + union { + U32 data_entry_offset; + U32 sub_dir_offset; + } id; +} COFF_ResourceDirEntry; + +//////////////////////////////// + +// !\n +#define COFF_ARCHIVE_SIG 0x0A3E686372613C21ULL +// !\n +#define COFF_THIN_ARCHIVE_SIG 0xA3E6E6968743C21ULL + +#define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15 + +#define COFF_ARCHIVE_ALIGN 2 + +typedef struct COFF_ArchiveMemberHeader +{ + String8 name; // padded to 16 bytes with spaces + U32 date; // unix time + U32 user_id; // unix artifact that does not have meaning on windows + U32 group_id; // unix artifact that does not have meaning on windows + String8 mode; // octal representation the members file mode + U32 size; // size of the member data, not including header + B32 is_end_correct; // set to true if found correct signature after header +} COFF_ArchiveMemberHeader; + +//////////////////////////////// +// Helpers + +enum +{ + COFF_DataType_NULL, + COFF_DataType_BIG_OBJ, + COFF_DataType_OBJ, + COFF_DataType_IMPORT, +}; +typedef U32 COFF_DataType; + +typedef struct COFF_HeaderInfo +{ + COFF_MachineType machine; + U64 section_array_off; + U64 section_count_no_null; + U64 string_table_off; + U64 symbol_size; + U64 symbol_off; + U64 symbol_count; +} COFF_HeaderInfo; + +enum +{ + // symbol has section and offset. + COFF_SymbolValueInterp_REGULAR, + + // symbol is overridable + COFF_SymbolValueInterp_WEAK, + + // symbol doesn't have a reference section. + COFF_SymbolValueInterp_UNDEFINED, + + // symbol has no section but still has size. + COFF_SymbolValueInterp_COMMON, + + // symbol has an absolute (non-relocatable) value and is not an address. + COFF_SymbolValueInterp_ABS, + + // symbol is used to provide general type of debugging information. + COFF_SymbolValueInterp_DEBUG +}; +typedef U32 COFF_SymbolValueInterpType; + +typedef struct COFF_Symbol16Node +{ + struct COFF_Symbol16Node *next; + COFF_Symbol16 data; +} COFF_Symbol16Node; + +typedef struct COFF_Symbol16List +{ + U64 count; + COFF_Symbol16Node *first; + COFF_Symbol16Node *last; +} COFF_Symbol16List; + +typedef struct COFF_Symbol32Array +{ + U64 count; + COFF_Symbol32 *v; +} COFF_Symbol32Array; + +typedef struct COFF_RelocNode +{ + struct COFF_RelocNode *next; + COFF_Reloc data; +} COFF_RelocNode; + +typedef struct COFF_RelocList +{ + U64 count; + COFF_RelocNode *first; + COFF_RelocNode *last; +} COFF_RelocList; + +typedef struct COFF_RelocArray +{ + U64 count; + COFF_Reloc *v; +} COFF_RelocArray; + +typedef struct COFF_RelocInfo +{ + U64 array_off; + U64 count; +} COFF_RelocInfo; + +typedef struct COFF_ResourceNode +{ + struct COFF_ResourceNode *next; + COFF_Resource data; +} COFF_ResourceNode; + +typedef struct COFF_ResourceList +{ + U64 count; + COFF_ResourceNode *first; + COFF_ResourceNode *last; +} COFF_ResourceList; + +//////////////////////////////// + +typedef struct COFF_ArchiveMember +{ + COFF_ArchiveMemberHeader header; + U64 offset; + String8 data; +} COFF_ArchiveMember; + +typedef struct COFF_ArchiveFirstMember +{ + U32 symbol_count; + String8 member_offsets; + String8 string_table; +} COFF_ArchiveFirstMember; + +typedef struct COFF_ArchiveSecondMember +{ + U32 member_count; + U32 symbol_count; + String8 member_offsets; + String8 symbol_indices; + String8 string_table; +} COFF_ArchiveSecondMember; + +typedef struct COFF_ArchiveMemberNode +{ + struct COFF_ArchiveMemberNode *next; + COFF_ArchiveMember data; +} COFF_ArchiveMemberNode; + +typedef struct COFF_ArchiveMemberList +{ + U64 count; + COFF_ArchiveMemberNode *first; + COFF_ArchiveMemberNode *last; +} COFF_ArchiveMemberList; + +typedef enum +{ + COFF_Archive_Null, + COFF_Archive_Regular, + COFF_Archive_Thin +} COFF_ArchiveType; + +typedef struct COFF_ArchiveParse +{ + COFF_ArchiveFirstMember first_member; + COFF_ArchiveSecondMember second_member; + String8 long_names; +} COFF_ArchiveParse; + +//////////////////////////////// +//~ rjf: Globals + +read_only global COFF_SectionHeader coff_section_header_nil = {0}; + +//////////////////////////////// +//~ rjf: Helper Functions + +internal B32 coff_is_big_obj(String8 data); +internal B32 coff_is_obj(String8 data); +internal COFF_HeaderInfo coff_header_info_from_data(String8 data); +internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags); +internal COFF_SymbolValueInterpType coff_interp_symbol(COFF_Symbol32 *symbol); + +internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff); +internal COFF_SectionHeader *coff_section_header_from_num(String8 data, U64 section_headers_off, U64 n); +internal String8 coff_section_header_get_name(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base); +internal void coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_out); + +internal String8 coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolName *name); +internal void coff_symbol32_from_coff_symbol16(COFF_Symbol32 *sym32, COFF_Symbol16 *sym16); +internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); +internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); +internal COFF_Symbol32Array coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_off, U64 symbol_count, U64 symbol_size); +internal COFF_Symbol16Node * coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol); +internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header); + +internal U64 coff_word_size_from_machine(COFF_MachineType machine); +internal String8 coff_make_import_lookup(Arena *arena, U16 hint, String8 name); +internal U32 coff_make_ordinal_32(U16 hint); +internal U64 coff_make_ordinal_64(U16 hint); + +internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b); +internal COFF_ResourceID coff_resource_id_copy(Arena *arena, COFF_ResourceID id); +internal COFF_ResourceID coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16); +internal U64 coff_read_resource_id(String8 res, U64 off, COFF_ResourceID_16 *id_out); +internal U64 coff_read_resource(String8 data, U64 off, Arena *arena, COFF_Resource *res_out); +internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data); + +internal COFF_DataType coff_data_type_from_data(String8 data); +internal B32 coff_is_import(String8 data); +internal B32 coff_is_archive(String8 data); +internal B32 coff_is_thin_archive(String8 data); +internal U64 coff_read_archive_member_header(String8 data, U64 offset, COFF_ArchiveMemberHeader *header_out); +internal COFF_ArchiveMember coff_read_archive_member(String8 data, U64 offset); +internal U64 coff_read_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out); +internal String8 coff_read_archive_long_name(String8 long_names, String8 name); +internal COFF_ArchiveMember coff_archive_member_from_data(String8 data); +internal U64 coff_archive_member_iter_init(String8 data); +internal B32 coff_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); +internal COFF_ArchiveParse coff_archive_parse_from_member_list(COFF_ArchiveMemberList list); +internal COFF_ArchiveParse coff_archive_from_data(Arena *arena, String8 data); +internal U64 coff_thin_archive_member_iter_init(String8 data); +internal B32 coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); +internal COFF_ArchiveParse coff_thin_archive_from_data(Arena *arena, String8 data); +internal COFF_ArchiveType coff_archive_type_from_data(String8 data); +internal COFF_ArchiveParse coff_archive_parse_from_data(Arena *arena, String8 data); + +internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select); +internal String8 coff_string_from_machine_type(COFF_MachineType machine); +internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags); + +#endif //COFF_H diff --git a/src/ctrl/ctrl.mc b/src/ctrl/ctrl.mc new file mode 100644 index 00000000..7cd8f7d9 --- /dev/null +++ b/src/ctrl/ctrl.mc @@ -0,0 +1,84 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Tables + +@table(name lower_name code default display_string) +CTRL_ExceptionCodeKindTable: +{ + {Win32CtrlC win32_ctrl_c 0x40010005 1 "(Win32) Control-C" } + {Win32CtrlBreak win32_ctrl_break 0x40010008 1 "(Win32) Control-Break" } + {Win32WinRTOriginateError win32_win_rt_originate_error 0x40080201 0 "(Win32) WinRT Originate Error" } + {Win32WinRTTransformError win32_win_rt_transform_error 0x40080202 0 "(Win32) WinRT Transform Error" } + {Win32RPCCallCancelled win32_rpc_call_cancelled 0x0000071a 0 "(Win32) RPC Call Cancelled" } + {Win32DatatypeMisalignment win32_datatype_misalignment 0x80000002 0 "(Win32) Data Type Misalignment" } + {Win32AccessViolation win32_access_violation 0xc0000005 1 "(Win32) Access Violation" } + {Win32InPageError win32_in_page_error 0xc0000006 0 "(Win32) In Page Error" } + {Win32InvalidHandle win32_invalid_handle 0xc0000008 1 "(Win32) Invalid Handle Specified" } + {Win32NotEnoughQuota win32_not_enough_quota 0xc0000017 0 "(Win32) Not Enough Quota" } + {Win32IllegalInstruction win32_illegal_instruction 0xc000001d 0 "(Win32) Illegal Instruction" } + {Win32CannotContinueException win32_cannot_continue_exception 0xc0000025 0 "(Win32) Cannot Continue From Exception" } + {Win32InvalidExceptionDisposition win32_invalid_exception_disposition 0xc0000026 0 "(Win32) Invalid Exception Disposition Returned By Handler" } + {Win32ArrayBoundsExceeded win32_array_bounds_exceeded 0xc000008c 0 "(Win32) Array Bounds Exceeded" } + {Win32FloatingPointDenormalOperand win32_floating_point_denormal_operand 0xc000008d 0 "(Win32) Floating-Point Denormal Operand" } + {Win32FloatingPointDivisionByZero win32_floating_point_division_by_zero 0xc000008e 0 "(Win32) Floating-Point Division By Zero" } + {Win32FloatingPointInexactResult win32_floating_point_inexact_result 0xc000008f 0 "(Win32) Floating-Point Inexact Result" } + {Win32FloatingPointInvalidOperation win32_floating_point_invalid_operation 0xc0000090 0 "(Win32) Floating-Point Invalid Operation" } + {Win32FloatingPointOverflow win32_floating_point_overflow 0xc0000091 0 "(Win32) Floating-Point Overflow" } + {Win32FloatingPointStackCheck win32_floating_point_stack_check 0xc0000092 0 "(Win32) Floating-Point Stack Check" } + {Win32FloatingPointUnderflow win32_floating_point_underflow 0xc0000093 0 "(Win32) Floating-Point Underflow" } + {Win32IntegerDivisionByZero win32_integer_division_by_zero 0xc0000094 0 "(Win32) Integer Division By Zero" } + {Win32IntegerOverflow win32_integer_overflow 0xc0000095 0 "(Win32) Integer Overflow" } + {Win32PrivilegedInstruction win32_privileged_instruction 0xc0000096 0 "(Win32) Privileged Instruction" } + {Win32StackOverflow win32_stack_overflow 0xc00000fd 0 "(Win32) Stack Overflow" } + {Win32UnableToLocateDLL win32_unable_to_locate_dll 0xc0000135 0 "(Win32) Unable To Locate DLL" } + {Win32OrdinalNotFound win32_ordinal_not_found 0xc0000138 0 "(Win32) Ordinal Not Found" } + {Win32EntryPointNotFound win32_entry_point_not_found 0xc0000139 0 "(Win32) Entry Point Not Found" } + {Win32DLLInitializationFailed win32_dll_initialization_failed 0xc0000142 0 "(Win32) DLL Initialization Failed" } + {Win32FloatingPointSSEMultipleFaults win32_floating_point_sse_multiple_faults 0xc00002b4 0 "(Win32) Floating Point SSE Multiple Faults" } + {Win32FloatingPointSSEMultipleTraps win32_floating_point_sse_multiple_traps 0xc00002b5 0 "(Win32) Floating Point SSE Multiple Traps" } + {Win32AssertionFailed win32_assertion_failed 0xc0000420 1 "(Win32) Assertion Failed" } + {Win32ModuleNotFound win32_module_not_found 0xc06d007e 0 "(Win32) Module Not Found" } + {Win32ProcedureNotFound win32_procedure_not_found 0xc06d007f 0 "(Win32) Procedure Not Found" } + {Win32SanitizerErrorDetected win32_sanitizer_error_detected 0xe073616e 1 "(Win32) Sanitizer Error Detected" } + {Win32SanitizerRawAccessViolation win32_sanitizer_raw_access_violation 0xe0736171 0 "(Win32) Sanitizer Raw Access Violation" } +} + +//////////////////////////////// +//~ rjf: Generators + +@table_gen_enum CTRL_ExceptionCodeKind: +{ + `CTRL_ExceptionCodeKind_Null,`; + @expand(CTRL_ExceptionCodeKindTable a) `CTRL_ExceptionCodeKind_$(a.name),`; + `CTRL_ExceptionCodeKind_COUNT`; +} + +@table_gen_data(type:U32, fallback:0) +ctrl_exception_code_kind_code_table: +{ + `0,`; + @expand(CTRL_ExceptionCodeKindTable a) `$(a.code),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +ctrl_exception_code_kind_display_string_table: +{ + `{0},`; + @expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +ctrl_exception_code_kind_lowercase_code_string_table: +{ + `{0},`; + @expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)"),`; +} + +@table_gen_data(type:B8, fallback:0) +ctrl_exception_code_kind_default_enable_table: +{ + `0,`; + @expand(CTRL_ExceptionCodeKindTable a) `$(a.default),`; +} diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c new file mode 100644 index 00000000..7ef616da --- /dev/null +++ b/src/ctrl/ctrl_core.c @@ -0,0 +1,3020 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +ctrl_init(CTRL_WakeupFunctionType *wakeup_hook) +{ + Arena *arena = arena_alloc(); + ctrl_state = push_array(arena, CTRL_State, 1); + ctrl_state->arena = arena; + ctrl_state->wakeup_hook = wakeup_hook; + for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) + { + String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); + U64 reg_count = regs_reg_code_count_from_architecture(arch); + String8 *alias_names = regs_alias_code_string_table_from_architecture(arch); + U64 alias_count = regs_alias_code_count_from_architecture(arch); + ctrl_state->arch_string2reg_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); + ctrl_state->arch_string2alias_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); + for(U64 idx = 1; idx < reg_count; idx += 1) + { + eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2reg_tables[arch], reg_names[idx], idx); + } + for(U64 idx = 1; idx < alias_count; idx += 1) + { + eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2alias_tables[arch], alias_names[idx], idx); + } + } + ctrl_state->process_memory_cache.slots_count = 256; + ctrl_state->process_memory_cache.slots = push_array(arena, CTRL_ProcessMemoryCacheSlot, ctrl_state->process_memory_cache.slots_count); + ctrl_state->process_memory_cache.stripes_count = 8; + ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) + { + ctrl_state->process_memory_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + } + ctrl_state->u2c_ring_size = KB(64); + ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); + ctrl_state->u2c_ring_mutex = os_mutex_alloc(); + ctrl_state->u2c_ring_cv = os_condition_variable_alloc(); + ctrl_state->c2u_ring_size = KB(64); + ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); + ctrl_state->c2u_ring_mutex = os_mutex_alloc(); + ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); + ctrl_state->demon_event_arena = arena_alloc(); + ctrl_state->user_entry_point_arena = arena_alloc(); + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) + { + if(ctrl_exception_code_kind_default_enable_table[k]) + { + ctrl_state->exception_code_filters[k/64] |= 1ull<<(k%64); + } + } + ctrl_state->u2ms_ring_size = KB(64); + ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); + ctrl_state->u2ms_ring_mutex = os_mutex_alloc(); + ctrl_state->u2ms_ring_cv = os_condition_variable_alloc(); + ctrl_state->ctrl_thread = os_launch_thread(ctrl_thread__entry_point, 0, 0); + ctrl_state->ms_thread_count = Min(4, os_logical_core_count()-1); + ctrl_state->ms_threads = push_array(arena, OS_Handle, ctrl_state->ms_thread_count); + for(U64 idx = 0; idx < ctrl_state->ms_thread_count; idx += 1) + { + ctrl_state->ms_threads[idx] = os_launch_thread(ctrl_mem_stream_thread__entry_point, (void *)idx, 0); + } +} + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal U64 +ctrl_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal CTRL_EventCause +ctrl_event_cause_from_demon_event_kind(DEMON_EventKind event_kind) +{ + CTRL_EventCause cause = CTRL_EventCause_Null; + switch(event_kind) + { + default:{}break; + case DEMON_EventKind_Error: {cause = CTRL_EventCause_Error;}break; + case DEMON_EventKind_Exception:{cause = CTRL_EventCause_InterruptedByException;}break; + case DEMON_EventKind_Trap: {cause = CTRL_EventCause_InterruptedByTrap;}break; + case DEMON_EventKind_Halt: {cause = CTRL_EventCause_InterruptedByHalt;}break; + } + return cause; +} + +internal B32 +ctrl_handle_match(CTRL_Handle a, CTRL_Handle b) +{ + return MemoryMatchStruct(&a, &b); +} + +//////////////////////////////// +//~ rjf: Ctrl <-> Demon Handle Translation Functions + +internal DEMON_Handle +ctrl_demon_handle_from_ctrl(CTRL_Handle h) +{ + DEMON_Handle result = h.u64[0]; + return result; +} + +internal CTRL_Handle +ctrl_handle_from_demon(DEMON_Handle h) +{ + CTRL_Handle result = {h}; + return result; +} + +//////////////////////////////// +//~ rjf: Machine/Handle Pair Type Functions + +internal void +ctrl_machine_id_handle_pair_list_push(Arena *arena, CTRL_MachineIDHandlePairList *list, CTRL_MachineIDHandlePair *pair) +{ + CTRL_MachineIDHandlePairNode *n = push_array(arena, CTRL_MachineIDHandlePairNode, 1); + MemoryCopyStruct(&n->v, pair); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal CTRL_MachineIDHandlePairList +ctrl_machine_id_handle_pair_list_copy(Arena *arena, CTRL_MachineIDHandlePairList *src) +{ + CTRL_MachineIDHandlePairList dst = {0}; + for(CTRL_MachineIDHandlePairNode *n = src->first; n != 0; n = n->next) + { + ctrl_machine_id_handle_pair_list_push(arena, &dst, &n->v); + } + return dst; +} + +//////////////////////////////// +//~ rjf: Trap Type Functions + +internal void +ctrl_trap_list_push(Arena *arena, CTRL_TrapList *list, CTRL_Trap *trap) +{ + CTRL_TrapNode *node = push_array(arena, CTRL_TrapNode, 1); + MemoryCopyStruct(&node->v, trap); + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal CTRL_TrapList +ctrl_trap_list_copy(Arena *arena, CTRL_TrapList *src) +{ + CTRL_TrapList dst = {0}; + for(CTRL_TrapNode *src_n = src->first; src_n != 0; src_n = src_n->next) + { + ctrl_trap_list_push(arena, &dst, &src_n->v); + } + return dst; +} + +//////////////////////////////// +//~ rjf: User Breakpoint Type Functions + +internal void +ctrl_user_breakpoint_list_push(Arena *arena, CTRL_UserBreakpointList *list, CTRL_UserBreakpoint *bp) +{ + CTRL_UserBreakpointNode *n = push_array(arena, CTRL_UserBreakpointNode, 1); + MemoryCopyStruct(&n->v, bp); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal CTRL_UserBreakpointList +ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src) +{ + CTRL_UserBreakpointList dst = {0}; + for(CTRL_UserBreakpointNode *src_n = src->first; src_n != 0; src_n = src_n->next) + { + CTRL_UserBreakpoint dst_bp = zero_struct; + MemoryCopyStruct(&dst_bp, &src_n->v); + dst_bp.string = push_str8_copy(arena, src_n->v.string); + dst_bp.condition = push_str8_copy(arena, src_n->v.condition); + ctrl_user_breakpoint_list_push(arena, &dst, &dst_bp); + } + return dst; +} + +internal void +ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DEMON_Handle module, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out) +{ + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + String8 exe_path = demon_full_path_from_module(scratch.arena, module); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + U64 base_vaddr = demon_base_vaddr_from_module(module); + for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) + { + CTRL_UserBreakpoint *bp = &n->v; + switch(bp->kind) + { + default:{}break; + + //- rjf: file:line-based breakpoints + case CTRL_UserBreakpointKind_FileNameAndLineColNumber: + { + // rjf: unpack & normalize + TxtPt pt = bp->pt; + String8 filename = bp->string; + String8 filename_normalized = push_str8_copy(scratch.arena, filename); + for(U64 idx = 0; idx < filename_normalized.size; idx += 1) + { + filename_normalized.str[idx] = char_to_lower(filename_normalized.str[idx]); + filename_normalized.str[idx] = char_to_correct_slash(filename_normalized.str[idx]); + } + + // rjf: filename -> src_id + U32 src_id = 0; + { + RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_NormalSourcePaths); + if(mapptr != 0) + { + RADDBG_ParsedNameMap map = {0}; + raddbg_name_map_parse(rdbg, mapptr, &map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, filename_normalized.str, filename_normalized.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + if(id_count > 0) + { + src_id = ids[0]; + } + } + } + } + + // rjf: src_id * pt -> push + if(0 < src_id && src_id < rdbg->source_file_count) + { + RADDBG_SourceFile *src = rdbg->source_files + src_id; + RADDBG_ParsedLineMap line_map = {0}; + raddbg_line_map_from_source_file(rdbg, src, &line_map); + U32 voff_count = 0; + U64 *voffs = raddbg_line_voffs_from_num(&line_map, pt.line, &voff_count); + for(U32 i = 0; i < voff_count; i += 1) + { + U64 vaddr = voffs[i] + base_vaddr; + DEMON_Trap trap = {process, vaddr, (U64)bp}; + demon_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } + }break; + + //- rjf: symbol:voff-based breakpoints + case CTRL_UserBreakpointKind_SymbolNameAndOffset: + { + String8 symbol_name = bp->string; + U64 voff = bp->u64; + if(rdbg != 0 && rdbg->procedures != 0) + { + RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Procedures); + if(mapptr != 0) + { + RADDBG_ParsedNameMap map = {0}; + raddbg_name_map_parse(rdbg, mapptr, &map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, symbol_name.str, symbol_name.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + for(U32 match_i = 0; match_i < id_count; match_i += 1) + { + U64 proc_voff = raddbg_first_voff_from_proc(rdbg, ids[match_i]); + U64 proc_vaddr = proc_voff + base_vaddr; + DEMON_Trap trap = {process, proc_vaddr + voff, (U64)bp}; + demon_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } + } + } + }break; + } + } + dbgi_scope_close(scope); + scratch_end(scratch); +} + +internal void +ctrl_append_resolved_process_user_bp_traps(Arena *arena, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out) +{ + for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) + { + CTRL_UserBreakpoint *bp = &n->v; + if(bp->kind == CTRL_UserBreakpointKind_VirtualAddress) + { + DEMON_Trap trap = {process, bp->u64, (U64)bp}; + demon_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } +} + +//////////////////////////////// +//~ rjf: Message Type Functions + +//- rjf: deep copying + +internal void +ctrl_msg_deep_copy(Arena *arena, CTRL_Msg *dst, CTRL_Msg *src) +{ + MemoryCopyStruct(dst, src); + dst->path = push_str8_copy(arena, src->path); + dst->strings = str8_list_copy(arena, &src->strings); + dst->cmd_line_string_list = str8_list_copy(arena, &src->cmd_line_string_list); + dst->env_string_list = str8_list_copy(arena, &src->env_string_list); + dst->traps = ctrl_trap_list_copy(arena, &src->traps); + dst->user_bps = ctrl_user_breakpoint_list_copy(arena, &src->user_bps); + dst->freeze_state_threads = ctrl_machine_id_handle_pair_list_copy(arena, &src->freeze_state_threads); +} + +//- rjf: list building + +internal CTRL_Msg * +ctrl_msg_list_push(Arena *arena, CTRL_MsgList *list) +{ + CTRL_MsgNode *n = push_array(arena, CTRL_MsgNode, 1); + SLLQueuePush(list->first, list->last, n); + list->count += 1; + CTRL_Msg *msg = &n->v; + return msg; +} + +//- rjf: serialization + +internal String8 +ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List msgs_srlzed = {0}; + str8_serial_begin(scratch.arena, &msgs_srlzed); + { + // rjf: write message count + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msgs->count); + + // rjf: write all message data + for(CTRL_MsgNode *msg_n = msgs->first; msg_n != 0; msg_n = msg_n->next) + { + CTRL_Msg *msg = &msg_n->v; + + // rjf: write flat parts + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->kind); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->msg_id); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->machine_id); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->entity); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->parent); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->entity_id); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->exit_code); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->env_inherit); + str8_serial_push_array (scratch.arena, &msgs_srlzed, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters)); + + // rjf: write path string + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->path.size); + str8_serial_push_data(scratch.arena, &msgs_srlzed, msg->path.str, msg->path.size); + + // rjf: write general string list + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->strings.node_count); + for(String8Node *n = msg->strings.first; n != 0; n = n->next) + { + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &n->string.size); + str8_serial_push_data(scratch.arena, &msgs_srlzed, n->string.str, n->string.size); + } + + // rjf: write command line string list + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->cmd_line_string_list.node_count); + for(String8Node *n = msg->cmd_line_string_list.first; n != 0; n = n->next) + { + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &n->string.size); + str8_serial_push_data(scratch.arena, &msgs_srlzed, n->string.str, n->string.size); + } + + // rjf: write environment string list + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->env_string_list.node_count); + for(String8Node *n = msg->env_string_list.first; n != 0; n = n->next) + { + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &n->string.size); + str8_serial_push_data(scratch.arena, &msgs_srlzed, n->string.str, n->string.size); + } + + // rjf: write trap list + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->traps.count); + for(CTRL_TrapNode *n = msg->traps.first; n != 0; n = n->next) + { + CTRL_Trap *trap = &n->v; + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &trap->flags); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &trap->vaddr); + } + + // rjf: write user breakpoint list + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->user_bps.count); + for(CTRL_UserBreakpointNode *n = msg->user_bps.first; n != 0; n = n->next) + { + CTRL_UserBreakpoint *bp = &n->v; + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->kind); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->string.size); + str8_serial_push_data(scratch.arena, &msgs_srlzed, bp->string.str, bp->string.size); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->pt); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->u64); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->condition.size); + str8_serial_push_data(scratch.arena, &msgs_srlzed, bp->condition.str, bp->condition.size); + } + + // rjf: write freeze state thread list + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->freeze_state_threads.count); + for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) + { + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &n->v); + } + + // rjf: write freeze state + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->freeze_state_is_frozen); + } + } + String8 string = str8_serial_end(arena, &msgs_srlzed); + scratch_end(scratch); + return string; +} + +internal CTRL_MsgList +ctrl_msg_list_from_serialized_string(Arena *arena, String8 string) +{ + CTRL_MsgList msgs = {0}; + { + U64 read_off = 0; + + // rjf: read message count + U64 msg_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &msg_count); + + // rjf: read data for all messages + for(U64 msg_idx = 0; msg_idx < msg_count; msg_idx += 1) + { + // rjf: construct message + CTRL_MsgNode *msg_node = push_array(arena, CTRL_MsgNode, 1); + SLLQueuePush(msgs.first, msgs.last, msg_node); + msgs.count += 1; + CTRL_Msg *msg = &msg_node->v; + + // rjf: read flat data + read_off += str8_deserial_read_struct(string, read_off, &msg->kind); + read_off += str8_deserial_read_struct(string, read_off, &msg->msg_id); + read_off += str8_deserial_read_struct(string, read_off, &msg->machine_id); + read_off += str8_deserial_read_struct(string, read_off, &msg->entity); + read_off += str8_deserial_read_struct(string, read_off, &msg->parent); + read_off += str8_deserial_read_struct(string, read_off, &msg->entity_id); + read_off += str8_deserial_read_struct(string, read_off, &msg->exit_code); + read_off += str8_deserial_read_struct(string, read_off, &msg->env_inherit); + read_off += str8_deserial_read_array (string, read_off, &msg->exception_code_filters[0], ArrayCount(msg->exception_code_filters)); + + // rjf: read path string + read_off += str8_deserial_read_struct(string, read_off, &msg->path.size); + msg->path.str = push_array_no_zero(arena, U8, msg->path.size); + read_off += str8_deserial_read(string, read_off, msg->path.str, msg->path.size, 1); + + // rjf: read general string list + U64 string_list_string_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &string_list_string_count); + for(U64 idx = 0; idx < string_list_string_count; idx += 1) + { + String8 str = {0}; + read_off += str8_deserial_read_struct(string, read_off, &str.size); + str.str = push_array_no_zero(arena, U8, str.size); + read_off += str8_deserial_read(string, read_off, str.str, str.size, 1); + str8_list_push(arena, &msg->strings, str); + } + + // rjf: read command line string list + U64 cmd_line_string_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &cmd_line_string_count); + for(U64 idx = 0; idx < cmd_line_string_count; idx += 1) + { + String8 cmd_line_str = {0}; + read_off += str8_deserial_read_struct(string, read_off, &cmd_line_str.size); + cmd_line_str.str = push_array_no_zero(arena, U8, cmd_line_str.size); + read_off += str8_deserial_read(string, read_off, cmd_line_str.str, cmd_line_str.size, 1); + str8_list_push(arena, &msg->cmd_line_string_list, cmd_line_str); + } + + // rjf: read environment string list + U64 env_string_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &env_string_count); + for(U64 idx = 0; idx < env_string_count; idx += 1) + { + String8 env_str = {0}; + read_off += str8_deserial_read_struct(string, read_off, &env_str.size); + env_str.str = push_array_no_zero(arena, U8, env_str.size); + read_off += str8_deserial_read(string, read_off, env_str.str, env_str.size, 1); + str8_list_push(arena, &msg->env_string_list, env_str); + } + + // rjf: read trap list + U64 trap_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &trap_count); + for(U64 idx = 0; idx < trap_count; idx += 1) + { + CTRL_TrapNode *n = push_array(arena, CTRL_TrapNode, 1); + SLLQueuePush(msg->traps.first, msg->traps.last, n); + msg->traps.count += 1; + CTRL_Trap *trap = &n->v; + read_off += str8_deserial_read_struct(string, read_off, &trap->flags); + read_off += str8_deserial_read_struct(string, read_off, &trap->vaddr); + } + + // rjf: read user breakpoint list + U64 user_bp_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &user_bp_count); + for(U64 idx = 0; idx < user_bp_count; idx += 1) + { + CTRL_UserBreakpointNode *n = push_array(arena, CTRL_UserBreakpointNode, 1); + SLLQueuePush(msg->user_bps.first, msg->user_bps.last, n); + msg->user_bps.count += 1; + CTRL_UserBreakpoint *bp = &n->v; + read_off += str8_deserial_read_struct(string, read_off, &bp->kind); + read_off += str8_deserial_read_struct(string, read_off, &bp->string.size); + bp->string.str = push_array_no_zero(arena, U8, bp->string.size); + read_off += str8_deserial_read(string, read_off, bp->string.str, bp->string.size, 1); + read_off += str8_deserial_read_struct(string, read_off, &bp->pt); + read_off += str8_deserial_read_struct(string, read_off, &bp->u64); + read_off += str8_deserial_read_struct(string, read_off, &bp->condition.size); + bp->condition.str = push_array_no_zero(arena, U8, bp->condition.size); + read_off += str8_deserial_read(string, read_off, bp->condition.str, bp->condition.size, 1); + } + + // rjf: read freeze state thread list + U64 frozen_thread_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &frozen_thread_count); + for(U64 idx = 0; idx < frozen_thread_count; idx += 1) + { + CTRL_MachineIDHandlePair pair = {0}; + read_off += str8_deserial_read_struct(string, read_off, &pair); + ctrl_machine_id_handle_pair_list_push(arena, &msg->freeze_state_threads, &pair); + } + + // rjf: read freeze state + read_off += str8_deserial_read_struct(string, read_off, &msg->freeze_state_is_frozen); + } + } + return msgs; +} + +//////////////////////////////// +//~ rjf: Event Type Functions + +//- rjf: list building + +internal CTRL_Event * +ctrl_event_list_push(Arena *arena, CTRL_EventList *list) +{ + CTRL_EventNode *n = push_array(arena, CTRL_EventNode, 1); + SLLQueuePush(list->first, list->last, n); + list->count += 1; + CTRL_Event *event = &n->v; + return event; +} + +internal void +ctrl_event_list_concat_in_place(CTRL_EventList *dst, CTRL_EventList *to_push) +{ + if(dst->last == 0) + { + MemoryCopyStruct(dst, to_push); + } + else if(to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->count += to_push->count; + } + MemoryZeroStruct(to_push); +} + +//- rjf: serialization + +internal String8 +ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List srl = {0}; + str8_serial_begin(scratch.arena, &srl);; + { + str8_serial_push_struct(scratch.arena, &srl, &event->kind); + str8_serial_push_struct(scratch.arena, &srl, &event->cause); + str8_serial_push_struct(scratch.arena, &srl, &event->exception_kind); + str8_serial_push_struct(scratch.arena, &srl, &event->msg_id); + str8_serial_push_struct(scratch.arena, &srl, &event->machine_id); + str8_serial_push_struct(scratch.arena, &srl, &event->entity); + str8_serial_push_struct(scratch.arena, &srl, &event->parent); + str8_serial_push_struct(scratch.arena, &srl, &event->arch); + str8_serial_push_struct(scratch.arena, &srl, &event->u64_code); + str8_serial_push_struct(scratch.arena, &srl, &event->entity_id); + str8_serial_push_struct(scratch.arena, &srl, &event->vaddr_rng); + str8_serial_push_struct(scratch.arena, &srl, &event->rip_vaddr); + str8_serial_push_struct(scratch.arena, &srl, &event->stack_base); + str8_serial_push_struct(scratch.arena, &srl, &event->tls_root); + str8_serial_push_struct(scratch.arena, &srl, &event->exception_code); + str8_serial_push_struct(scratch.arena, &srl, &event->string.size); + str8_serial_push_data(scratch.arena, &srl, event->string.str, event->string.size); + } + String8 string = str8_serial_end(arena, &srl); + scratch_end(scratch); + return string; +} + +internal CTRL_Event +ctrl_event_from_serialized_string(Arena *arena, String8 string) +{ + CTRL_Event event = zero_struct; + { + U64 read_off = 0; + read_off += str8_deserial_read_struct(string, read_off, &event.kind); + read_off += str8_deserial_read_struct(string, read_off, &event.cause); + read_off += str8_deserial_read_struct(string, read_off, &event.exception_kind); + read_off += str8_deserial_read_struct(string, read_off, &event.msg_id); + read_off += str8_deserial_read_struct(string, read_off, &event.machine_id); + read_off += str8_deserial_read_struct(string, read_off, &event.entity); + read_off += str8_deserial_read_struct(string, read_off, &event.parent); + read_off += str8_deserial_read_struct(string, read_off, &event.arch); + read_off += str8_deserial_read_struct(string, read_off, &event.u64_code); + read_off += str8_deserial_read_struct(string, read_off, &event.entity_id); + read_off += str8_deserial_read_struct(string, read_off, &event.vaddr_rng); + read_off += str8_deserial_read_struct(string, read_off, &event.rip_vaddr); + read_off += str8_deserial_read_struct(string, read_off, &event.stack_base); + read_off += str8_deserial_read_struct(string, read_off, &event.tls_root); + read_off += str8_deserial_read_struct(string, read_off, &event.exception_code); + read_off += str8_deserial_read_struct(string, read_off, &event.string.size); + event.string.str = push_array_no_zero(arena, U8, event.string.size); + read_off += str8_deserial_read(string, read_off, event.string.str, event.string.size, 1); + } + return event; +} + +//////////////////////////////// +//~ rjf: Shared Functions + +//- rjf: run index + +internal U64 +ctrl_run_idx(void) +{ + U64 result = ins_atomic_u64_eval(&ctrl_state->run_idx); + return result; +} + +internal U64 +ctrl_memgen_idx(void) +{ + U64 result = ins_atomic_u64_eval(&ctrl_state->memgen_idx); + return result; +} + +//- rjf: halt everything + +internal void +ctrl_halt(void) +{ + demon_halt(0, 0); +} + +//- rjf: entity introspection + +internal U32 +ctrl_id_from_machine_entity(CTRL_MachineID id, DEMON_Handle handle) +{ + U32 result = 0; + return result; +} + +//- rjf: exe -> dbg path mapping + +internal String8 +ctrl_inferred_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 result = {0}; + { + // TODO(rjf): do preliminary header parse of EXE if possible, look for connected debug info path + } + scratch_end(scratch); + return result; +} + +internal String8 +ctrl_forced_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) +{ + String8 result = {0}; + // TODO(rjf) + return result; +} + +internal String8 +ctrl_natural_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) +{ + String8 exe_extension = str8_skip_last_dot(exe_path); + String8 dbg_extension = {0}; + if(str8_match(exe_extension, str8_lit("exe"), 0)) {dbg_extension = str8_lit("pdb");} + if(str8_match(exe_extension, str8_lit("elf"), 0)) {dbg_extension = str8_lit("debug");} + String8 result = {0}; + if(dbg_extension.size != 0) + { + result = push_str8f(arena, "%S.%S", str8_chop_last_dot(exe_path), dbg_extension); + } + return result; +} + +internal String8 +ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 forced_og_dbg_path = ctrl_forced_og_dbg_path_from_exe_path(scratch.arena, exe_path); + String8 inferred_og_dbg_path = ctrl_inferred_og_dbg_path_from_exe_path(scratch.arena, exe_path); + String8 natural_og_dbg_path = ctrl_natural_og_dbg_path_from_exe_path(scratch.arena, exe_path); + String8 og_dbg_path = forced_og_dbg_path.size?forced_og_dbg_path : inferred_og_dbg_path.size?inferred_og_dbg_path : natural_og_dbg_path; + og_dbg_path = push_str8_copy(arena, og_dbg_path); + scratch_end(scratch); + return og_dbg_path; +} + +//- rjf: handle -> arch + +internal Architecture +ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle) +{ + return demon_arch_from_object(ctrl_demon_handle_from_ctrl(handle)); +} + +//- rjf: process memory reading/writing + +internal U64 +ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst) +{ + U64 actual_bytes_read = demon_read_memory(ctrl_demon_handle_from_ctrl(process), dst, range.min, dim_1u64(range)); + return actual_bytes_read; +} + +internal String8 +ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range) +{ + String8 result = {0}; + if(range.max > range.min && + dim_1u64(range) <= MB(256) && + range.min <= 0x000FFFFFFFFFFFFFull && + range.max <= 0x000FFFFFFFFFFFFFull) + { + HS_Scope *scope = hs_scope_open(); + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + + //- rjf: unpack address range + Rng1U64 page_range = r1u64(AlignDownPow2(range.min, KB(4)), AlignPow2(range.max, KB(4))); + + //- rjf: setup output memory for read + void *read_out = push_array(arena, U8, dim_1u64(page_range)); + + //- rjf: unpack process/machine params + U64 hash = ctrl_hash_from_string(str8_struct(&process)); + U64 slot_idx = hash%cache->slots_count; + U64 stripe_idx = slot_idx%cache->stripes_count; + CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; + + //- rjf: cache lookup & fill loop + for(U64 page_vaddr = page_range.min; page_vaddr < page_range.max; page_vaddr += KB(4)) + { + // rjf: unpack page base address + U64 lvl5_idx = (page_vaddr&0x00000000000FF000ull) >> 12; + U64 lvl4_idx = (page_vaddr&0x000000000FF00000ull) >> 20; + U64 lvl3_idx = (page_vaddr&0x0000000FF0000000ull) >> 28; + U64 lvl2_idx = (page_vaddr&0x00000FF000000000ull) >> 36; + U64 lvl1_idx = (page_vaddr&0x000FF00000000000ull) >> 44; + + // rjf: try to find node & read from it + B32 node_found = 0; + B32 page_found = 0; + B32 page_stale = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + CTRL_ProcessMemoryCacheNode *node = 0; + for(CTRL_ProcessMemoryCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(process, n->process) && n->machine_id == machine_id) + { + node = n; + break; + } + } + if(node != 0) + { + node_found = 1; + CTRL_ProcessMemoryCacheNode1 *node1 = node->children[lvl1_idx]; + CTRL_ProcessMemoryCacheNode2 *node2 = node1 ? node1->children[lvl2_idx] : 0; + CTRL_ProcessMemoryCacheNode3 *node3 = node2 ? node2->children[lvl3_idx] : 0; + CTRL_ProcessMemoryCacheNode4 *node4 = node3 ? node3->children[lvl4_idx] : 0; + U128 page_hash = node4 ? node4->page_hashes[lvl5_idx] : u128_zero(); + B32 stale = (node4 && node4->page_memgen_idxs[lvl5_idx] < ctrl_memgen_idx()); + if(!u128_match(page_hash, u128_zero())) + { + page_stale = stale; + String8 page_data = hs_data_from_hash(scope, page_hash); + if(page_data.size >= KB(4)) + { + page_found = 1; + MemoryCopy((U8*)read_out + (page_vaddr-page_range.min), page_data.str, KB(4)); + } + else + { + page_stale = 1; + } + } + } + } + + // rjf: either node or page not found? -> need a hard-lock & fill + if(!node_found || !page_found || page_stale) OS_MutexScopeW(stripe->rw_mutex) + { + CTRL_ProcessMemoryCacheNode *node = 0; + for(CTRL_ProcessMemoryCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(process, n->process) && n->machine_id == machine_id) + { + node = n; + break; + } + } + if(node == 0) + { + Arena *node_arena = arena_alloc(); + node = push_array(node_arena, CTRL_ProcessMemoryCacheNode, 1); + node->arena = node_arena; + node->machine_id = machine_id; + node->process = process; + node->range_hash_slots_count = 1024; + node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count); + DLLPushBack(slot->first, slot->last, node); + } + if(!page_found || page_stale) + { + CTRL_ProcessMemoryCacheNode1 *node1 = node->children[lvl1_idx]; + if(node1 == 0) + { + node1 = push_array(node->arena, CTRL_ProcessMemoryCacheNode1, 1); + node->children[lvl1_idx] = node1; + } + CTRL_ProcessMemoryCacheNode2 *node2 = node1->children[lvl2_idx]; + if(node2 == 0) + { + node2 = push_array(node->arena, CTRL_ProcessMemoryCacheNode2, 1); + node1->children[lvl2_idx] = node2; + } + CTRL_ProcessMemoryCacheNode3 *node3 = node2->children[lvl3_idx]; + if(node3 == 0) + { + node3 = push_array(node->arena, CTRL_ProcessMemoryCacheNode3, 1); + node2->children[lvl3_idx] = node3; + } + CTRL_ProcessMemoryCacheNode4 *node4 = node3->children[lvl4_idx]; + if(node4 == 0) + { + node4 = push_array(node->arena, CTRL_ProcessMemoryCacheNode4, 1); + node3->children[lvl4_idx] = node4; + } + Arena *page_arena = arena_alloc__sized(KB(8), KB(8)); + void *page_base = push_array_no_zero(page_arena, U8, KB(4)); + U64 actual_read_size = ctrl_process_read(machine_id, process, r1u64(page_vaddr, page_vaddr+KB(4)), page_base); + if(actual_read_size >= KB(4)) + { + node4->page_memgen_idxs[lvl5_idx] = ctrl_memgen_idx(); + if(page_stale) + { + MemoryCopy((U8*)read_out + (page_vaddr-page_range.min), page_base, KB(4)); + } + U64 page_key_data[] = + { + (U64)machine_id, + (U64)process.u64[0], + page_vaddr, + page_vaddr+KB(4), + }; + U128 page_key = hs_hash_from_data(str8((U8 *)page_key_data, sizeof(page_key_data))); + U128 page_hash = hs_submit_data(page_key, &page_arena, str8((U8 *)page_base, KB(4))); + node4->page_hashes[lvl5_idx] = page_hash; + } + else + { + arena_release(page_arena); + } + } + } + } + + //- rjf: fill result by skipping/chopping read memory + U64 byte_in_page_idx = (range.min&0x0000000000000FFFull) >> 0; + result.str = (U8*)read_out + byte_in_page_idx; + result.size = dim_1u64(range); + hs_scope_close(scope); + } + return result; +} + +internal String8 +ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit, U64 endt_us) +{ + String8 result = ctrl_query_cached_data_from_process_vaddr_range(arena, machine_id, process, r1u64(vaddr, vaddr+limit)); + for(U64 idx = 0; idx < result.size; idx += 1) + { + if(result.str[idx] == 0) + { + result.size = idx; + break; + } + } + return result; +} + +internal B32 +ctrl_process_write_data(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, String8 data) +{ + ProfBeginFunction(); + B32 result = demon_write_memory(ctrl_demon_handle_from_ctrl(process), vaddr, data.str, data.size); + if(result) + { + ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); + } + ProfEnd(); + return result; +} + +internal U128 +ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated) +{ + U128 result = {0}; + U64 size = dim_1u64(range); + if(size != 0) + { + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + U64 process_hash = ctrl_hash_from_string(str8_struct(&process)); + U64 process_slot_idx = process_hash%cache->slots_count; + U64 process_stripe_idx = process_slot_idx%cache->stripes_count; + CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx]; + CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; + U64 range_hash = ctrl_hash_from_string(str8_struct(&range)); + + //- rjf: try to read from cache + B32 is_good = 0; + B32 is_stale = 0; + OS_MutexScopeR(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + { + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + { + if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) + { + result = range_n->hash; + is_good = 1; + is_stale = range_n->memgen_idx < ctrl_memgen_idx(); + goto read_cache__break_all; + } + } + } + } + read_cache__break_all:; + } + + //- rjf: not good -> create process cache node if necessary + if(!is_good) + { + OS_MutexScopeW(process_stripe->rw_mutex) + { + B32 process_node_exists = 0; + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + { + process_node_exists = 1; + break; + } + } + if(!process_node_exists) + { + Arena *node_arena = arena_alloc(); + CTRL_ProcessMemoryCacheNode *node = push_array(node_arena, CTRL_ProcessMemoryCacheNode, 1); + node->arena = node_arena; + node->machine_id = machine_id; + node->process = process; + node->range_hash_slots_count = 1024; + node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count); + DLLPushBack(process_slot->first, process_slot->last, node); + } + } + } + + //- rjf: not good -> create range node if necessary + if(!is_good) + { + OS_MutexScopeW(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + { + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + B32 range_node_exists = 0; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + { + if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) + { + range_node_exists = 1; + break; + } + } + if(!range_node_exists) + { + CTRL_ProcessMemoryRangeHashNode *range_n = push_array(n->arena, CTRL_ProcessMemoryRangeHashNode, 1); + SLLQueuePush(range_slot->first, range_slot->last, range_n); + range_n->vaddr_range = range; + range_n->zero_terminated = zero_terminated; + break; + } + } + } + } + } + + //- rjf: not good, or is stale -> submit hash request + if(!is_good || is_stale) + { + ctrl_u2ms_enqueue_req(machine_id, process, range, zero_terminated, 0); + } + } + return result; +} + +//- rjf: register reading/writing + +internal void * +ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) +{ + void *regs = demon_read_regs(ctrl_demon_handle_from_ctrl(thread)); + return regs; +} + +internal B32 +ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block) +{ + B32 good = demon_write_regs(ctrl_demon_handle_from_ctrl(thread), block); + return good; +} + +internal U64 +ctrl_rip_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) +{ + U64 result = 0; + void *regs = ctrl_reg_block_from_thread(machine_id, thread); + if(regs != 0) + { + Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); + result = regs_rip_from_arch_block(arch, regs); + } + return result; +} + +internal B32 +ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip) +{ + B32 result = 0; + void *regs = ctrl_reg_block_from_thread(machine_id, thread); + if(regs != 0) + { + Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); + regs_arch_block_write_rip(arch, regs, rip); + ctrl_thread_write_reg_block(machine_id, thread, regs); + result = 1; + } + return result; +} + +internal U64 +ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) +{ + U64 result = 0; + DEMON_Handle demon_handle = ctrl_demon_handle_from_ctrl(thread); + result = demon_tls_root_vaddr_from_thread(demon_handle); + return result; +} + +//- rjf: name -> register/alias hash tables, for eval + +internal EVAL_String2NumMap * +ctrl_string2reg_from_arch(Architecture arch) +{ + return &ctrl_state->arch_string2reg_tables[arch]; +} + +internal EVAL_String2NumMap * +ctrl_string2alias_from_arch(Architecture arch) +{ + return &ctrl_state->arch_string2alias_tables[arch]; +} + +//////////////////////////////// +//~ rjf: User -> Ctrl Communication + +internal B32 +ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us) +{ + Temp scratch = scratch_begin(0, 0); + String8 msgs_srlzed_baked = ctrl_serialized_string_from_msg_list(scratch.arena, msgs); + B32 good = 0; + OS_MutexScope(ctrl_state->u2c_ring_mutex) for(;;) + { + U64 unconsumed_size = (ctrl_state->u2c_ring_write_pos-ctrl_state->u2c_ring_read_pos); + U64 available_size = ctrl_state->u2c_ring_size-unconsumed_size; + if(available_size >= sizeof(U64) + msgs_srlzed_baked.size) + { + ctrl_state->u2c_ring_write_pos += ring_write_struct(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, &msgs_srlzed_baked.size); + ctrl_state->u2c_ring_write_pos += ring_write(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_write_pos, msgs_srlzed_baked.str, msgs_srlzed_baked.size); + ctrl_state->u2c_ring_write_pos += 7; + ctrl_state->u2c_ring_write_pos -= ctrl_state->u2c_ring_write_pos%8; + good = 1; + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, endt_us); + } + if(good) + { + os_condition_variable_broadcast(ctrl_state->u2c_ring_cv); + } + scratch_end(scratch); + return good; +} + +internal CTRL_MsgList +ctrl_u2c_pop_msgs(Arena *arena) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 msgs_srlzed_baked = {0}; + OS_MutexScope(ctrl_state->u2c_ring_mutex) for(;;) + { + U64 unconsumed_size = (ctrl_state->u2c_ring_write_pos-ctrl_state->u2c_ring_read_pos); + if(unconsumed_size >= sizeof(U64)) + { + U64 size_to_decode = 0; + ctrl_state->u2c_ring_read_pos += ring_read_struct(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_read_pos, &size_to_decode); + msgs_srlzed_baked.size = size_to_decode; + msgs_srlzed_baked.str = push_array_no_zero(scratch.arena, U8, msgs_srlzed_baked.size); + ctrl_state->u2c_ring_read_pos += ring_read(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_read_pos, msgs_srlzed_baked.str, size_to_decode); + ctrl_state->u2c_ring_read_pos += 7; + ctrl_state->u2c_ring_read_pos -= ctrl_state->u2c_ring_read_pos%8; + break; + } + os_condition_variable_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ctrl_state->u2c_ring_cv); + CTRL_MsgList msgs = ctrl_msg_list_from_serialized_string(arena, msgs_srlzed_baked); + scratch_end(scratch); + return msgs; +} + +//////////////////////////////// +//~ rjf: Ctrl -> User Communication + +internal void +ctrl_c2u_push_events(CTRL_EventList *events) +{ + if(events->count != 0) ProfScope("ctrl_c2u_push_events") + { + for(CTRL_EventNode *n = events->first; n != 0; n = n ->next) + { + Temp scratch = scratch_begin(0, 0); + String8 event_srlzed = ctrl_serialized_string_from_event(scratch.arena, &n->v); + OS_MutexScope(ctrl_state->c2u_ring_mutex) for(;;) + { + U64 unconsumed_size = (ctrl_state->c2u_ring_write_pos-ctrl_state->c2u_ring_read_pos); + U64 available_size = ctrl_state->c2u_ring_size-unconsumed_size; + if(available_size >= sizeof(U64) + event_srlzed.size) + { + ctrl_state->c2u_ring_write_pos += ring_write_struct(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, &event_srlzed.size); + ctrl_state->c2u_ring_write_pos += ring_write(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, event_srlzed.str, event_srlzed.size); + ctrl_state->c2u_ring_write_pos += 7; + ctrl_state->c2u_ring_write_pos -= ctrl_state->c2u_ring_write_pos%8; + break; + } + os_condition_variable_wait(ctrl_state->c2u_ring_cv, ctrl_state->c2u_ring_mutex, os_now_microseconds()+100); + } + os_condition_variable_broadcast(ctrl_state->c2u_ring_cv); + if(ctrl_state->wakeup_hook != 0) + { + ctrl_state->wakeup_hook(); + } + scratch_end(scratch); + } + } +} + +internal CTRL_EventList +ctrl_c2u_pop_events(Arena *arena) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + CTRL_EventList events = {0}; + OS_MutexScope(ctrl_state->c2u_ring_mutex) for(;;) + { + U64 unconsumed_size = (ctrl_state->c2u_ring_write_pos-ctrl_state->c2u_ring_read_pos); + if(unconsumed_size >= sizeof(U64)) + { + U64 size_to_decode = 0; + ctrl_state->c2u_ring_read_pos += ring_read_struct(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_read_pos, &size_to_decode); + String8 event_srlzed = {0}; + event_srlzed.size = size_to_decode; + event_srlzed.str = push_array_no_zero(scratch.arena, U8, event_srlzed.size); + ctrl_state->c2u_ring_read_pos += ring_read(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_read_pos, event_srlzed.str, event_srlzed.size); + ctrl_state->c2u_ring_read_pos += 7; + ctrl_state->c2u_ring_read_pos -= ctrl_state->c2u_ring_read_pos%8; + CTRL_Event *new_event = ctrl_event_list_push(arena, &events); + *new_event = ctrl_event_from_serialized_string(arena, event_srlzed); + } + else + { + break; + } + } + os_condition_variable_broadcast(ctrl_state->c2u_ring_cv); + scratch_end(scratch); + ProfEnd(); + return events; +} + +//////////////////////////////// +//~ rjf: User -> Memory Stream Communication + +internal B32 +ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) +{ + B32 good = 0; + OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) + { + U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; + U64 available_size = ctrl_state->u2ms_ring_size-unconsumed_size; + if(available_size >= sizeof(machine_id)+sizeof(process)+sizeof(vaddr_range)) + { + good = 1; + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &machine_id); + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &process); + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &vaddr_range); + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &zero_terminated); + break; + } + if(os_now_microseconds() >= endt_us) {break;} + os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); + } + os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); + return good; +} + +internal void +ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) +{ + OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) + { + U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; + if(unconsumed_size >= sizeof(*out_machine_id)+sizeof(*out_process)+sizeof(*out_vaddr_range)) + { + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_machine_id); + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_process); + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_vaddr_range); + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_zero_terminated); + break; + } + os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); +} + +//////////////////////////////// +//~ rjf: Control-Thread-Only Functions + +//- rjf: entry point + +internal void +ctrl_thread__entry_point(void *p) +{ + TCTX tctx_; + tctx_init_and_equip(&tctx_); + ThreadName("[ctrl] thread"); + ProfBeginFunction(); + demon_primary_thread_begin(); + Temp scratch = scratch_begin(0, 0); + for(;;) + { + temp_end(scratch); + + //- rjf: get next messages + CTRL_MsgList msgs = ctrl_u2c_pop_msgs(scratch.arena); + + //- rjf: process messages + { + demon_exclusive_mode_begin(); + B32 done = 0; + for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next) + { + CTRL_Msg *msg = &msg_n->v; + MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); + switch(msg->kind) + { + case CTRL_MsgKind_Null: + case CTRL_MsgKind_COUNT:{}break; + + //- rjf: target operations + case CTRL_MsgKind_LaunchAndHandshake:{ctrl_thread__launch_and_handshake(msg);}break; + case CTRL_MsgKind_LaunchAndInit: {ctrl_thread__launch_and_init (msg);}break; + case CTRL_MsgKind_Attach: {ctrl_thread__attach (msg);}break; + case CTRL_MsgKind_Kill: {ctrl_thread__kill (msg);}break; + case CTRL_MsgKind_Detach: {ctrl_thread__detach (msg);}break; + case CTRL_MsgKind_Run: {ctrl_thread__run (msg); done = 1;}break; + case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (msg); done = 1;}break; + + //- rjf: configuration + case CTRL_MsgKind_SetUserEntryPoints: + { + arena_clear(ctrl_state->user_entry_point_arena); + MemoryZeroStruct(&ctrl_state->user_entry_points); + for(String8Node *n = msg->strings.first; n != 0; n = n->next) + { + str8_list_push(ctrl_state->user_entry_point_arena, &ctrl_state->user_entry_points, n->string); + } + }break; + } + } + demon_exclusive_mode_end(); + } + } + scratch_end(scratch); + ProfEnd(); +} + +//- rjf: attached process running/event gathering + +internal DEMON_Event * +ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_ctrls, CTRL_Spoof *spoof) +{ + ProfBeginFunction(); + DEMON_Event *event = push_array(arena, DEMON_Event, 1); + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: loop -> try to get event, run, repeat + ProfScope("loop -> try to get event, run, repeat") for(B32 got_event = 0; got_event == 0;) + { + //- rjf: get next event + ProfScope("get next event") + { + // rjf: grab first event + DEMON_EventNode *next_event_node = ctrl_state->first_demon_event_node; + + // rjf: determine if we should filter + B32 should_filter_event = 0; + if(next_event_node != 0) + { + DEMON_Event *ev = &next_event_node->v; + switch(ev->kind) + { + default:{}break; + case DEMON_EventKind_Exception: + { + // NOTE(rjf): first chance exceptions -> try ignoring + should_filter_event = (ev->exception_repeated == 0 && (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)); + + // rjf: exception code -> kind + CTRL_ExceptionCodeKind code_kind = CTRL_ExceptionCodeKind_Null; + if(should_filter_event) + { + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) + { + if(ctrl_exception_code_kind_code_table[k] == ev->code) + { + code_kind = k; + break; + } + } + } + + // rjf: exception code kind -> shouldn't stop? if so, do not filter + if(should_filter_event) + { + B32 shouldnt_filter = !!(ctrl_state->exception_code_filters[code_kind/64] & (1ull<<(code_kind%64))); + if(should_filter_event && shouldnt_filter) + { + should_filter_event = 0; + } + } + }break; + } + } + + // rjf: good event & unfiltered? -> pop from queue & grab as result + if(next_event_node != 0 && !should_filter_event) + { + got_event = 1; + SLLQueuePop(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node); + MemoryCopyStruct(event, &next_event_node->v); + event->string = push_str8_copy(arena, event->string); + run_ctrls->ignore_previous_exception = 1; + } + + // rjf: good event but filtered? pop from queue + if(next_event_node != 0 && should_filter_event) + { + SLLQueuePop(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node); + run_ctrls->ignore_previous_exception = 0; + } + } + + //- rjf: no event -> demon_run for a new one + if(got_event == 0) ProfScope("no event -> demon_run for a new one") + { + // rjf: prep spoof + B32 do_spoof = (spoof != 0 && run_ctrls->single_step_thread == 0); + U64 spoof_old_ip_value = 0; + U64 size_of_spoof = 0; + if(do_spoof) ProfScope("prep spoof") + { + Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(spoof->process)); + demon_read_memory(ctrl_demon_handle_from_ctrl(spoof->process), &spoof_old_ip_value, spoof->vaddr, sizeof(spoof_old_ip_value)); + size_of_spoof = bit_size_from_arch(arch)/8; + } + + // rjf: set spoof + if(do_spoof) ProfScope("set spoof") + { + demon_write_memory(ctrl_demon_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof->new_ip_value, size_of_spoof); + } + + // rjf: run for new events + ProfScope("run for new events") + { + DEMON_EventList events = demon_run(scratch.arena, run_ctrls); + for(DEMON_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next) + { + DEMON_EventNode *dst_n = ctrl_state->free_demon_event_node; + if(dst_n != 0) + { + SLLStackPop(ctrl_state->free_demon_event_node); + } + else + { + dst_n = push_array(ctrl_state->demon_event_arena, DEMON_EventNode, 1); + } + MemoryCopyStruct(&dst_n->v, &src_n->v); + dst_n->v.string = push_str8_copy(ctrl_state->demon_event_arena, dst_n->v.string); + SLLQueuePush(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node, dst_n); + } + } + + // rjf: unset spoof + if(do_spoof) ProfScope("unset spoof") + { + demon_write_memory(ctrl_demon_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof_old_ip_value, size_of_spoof); + } + + // rjf: inc run idx & memgen idx + { + ins_atomic_u64_inc_eval(&ctrl_state->run_idx); + ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); + } + } + } + + //- rjf: push ctrl events associated with this demon event + CTRL_EventList evts = {0}; + ProfScope("push ctrl events associated with this demon event") switch(event->kind) + { + default:{}break; + case DEMON_EventKind_CreateProcess: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_NewProc; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->process); + out_evt->arch = demon_arch_from_object(event->process); + out_evt->entity_id = event->code; + ctrl_state->process_counter += 1; + }break; + case DEMON_EventKind_CreateThread: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_NewThread; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->thread); + out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->arch = demon_arch_from_object(event->process); + out_evt->entity_id = event->code; + out_evt->stack_base = demon_stack_base_vaddr_from_thread(event->thread); + out_evt->tls_root = demon_tls_root_vaddr_from_thread(event->thread); + out_evt->rip_vaddr = event->instruction_pointer; + }break; + case DEMON_EventKind_LoadModule: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + String8 module_path = event->string; + dbgi_binary_open(module_path); + out_evt->kind = CTRL_EventKind_NewModule; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->module); + out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->arch = demon_arch_from_object(event->module); + out_evt->entity_id = event->code; + out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); + out_evt->rip_vaddr = demon_base_vaddr_from_module(event->module); + out_evt->string = module_path; + }break; + case DEMON_EventKind_ExitProcess: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_EndProc; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->process); + out_evt->u64_code = event->code; + ctrl_state->process_counter -= 1; + }break; + case DEMON_EventKind_ExitThread: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_EndThread; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->thread); + out_evt->entity_id = event->code; + }break; + case DEMON_EventKind_UnloadModule: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + String8 module_path = event->string; + dbgi_binary_close(module_path); + out_evt->kind = CTRL_EventKind_EndModule; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->module); + }break; + case DEMON_EventKind_DebugString: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_DebugString; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->thread); + out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->string = event->string; + }break; + case DEMON_EventKind_SetThreadName: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_ThreadName; + out_evt->msg_id = msg->msg_id; + out_evt->machine_id = CTRL_MachineID_Client; + out_evt->entity = ctrl_handle_from_demon(event->thread); + out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->string = event->string; + }break; + } + ctrl_c2u_push_events(&evts); + + //- rjf: clear process memory cache, if we've just started a lone process + if(event->kind == DEMON_EventKind_CreateProcess && ctrl_state->process_counter == 1) + { + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) + { + U64 stripe_idx = slot_idx%cache->stripes_count; + CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + arena_clear(n->arena); + } + } + MemoryZeroStruct(slot); + } + } + + //- rjf: out of queued up demon events -> clear event arena + if(ctrl_state->first_demon_event_node == 0) + { + ctrl_state->free_demon_event_node = 0; + arena_clear(ctrl_state->demon_event_arena); + } + + scratch_end(scratch); + ProfEnd(); + return(event); +} + +//- rjf: eval helpers + +internal B32 +ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size) +{ + DEMON_Handle process = (DEMON_Handle)u; + U64 read_size = demon_read_memory(process, out, addr, size); + B32 result = (read_size == size); + return result; +} + +//- rjf: msg kind implementations + +internal void +ctrl_thread__launch_and_handshake(CTRL_Msg *msg) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + + //- rjf: launch + OS_LaunchOptions opts = {0}; + { + opts.cmd_line = msg->cmd_line_string_list; + opts.path = msg->path; + opts.env = msg->env_string_list; + opts.inherit_env = msg->env_inherit; + } + U32 id = demon_launch_process(&opts); + + //- rjf: run to handshake + DEMON_Event *stop_event = 0; + if(id != 0) + { + // rjf: prep run controls + DEMON_Handle unfrozen_process = 0; + DEMON_RunCtrls run_ctrls = {0}; + { + run_ctrls.run_entities_are_unfrozen = 1; + run_ctrls.run_entities_are_processes = 1; + run_ctrls.run_entities = &unfrozen_process; + run_ctrls.run_entity_count = 0; + } + + // rjf: run until handshake-signifying events + for(B32 done = 0; done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_CreateProcess: + { + unfrozen_process = event->process; + run_ctrls.run_entity_count = 1; + }break; + case DEMON_EventKind_Error: + case DEMON_EventKind_Breakpoint: + case DEMON_EventKind_Exception: + case DEMON_EventKind_ExitProcess: + case DEMON_EventKind_HandshakeComplete: + { + done = 1; + stop_event = event; + }break; + } + } + } + + //- rjf: record bad stop + if(stop_event == 0 && id == 0) + { + CTRL_EventList evts = {0}; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Error; + event->cause = CTRL_EventCause_Error; + ctrl_c2u_push_events(&evts); + } + + //- rjf: push request resolution event + { + CTRL_EventList evts = {0}; + CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); + evt->kind = CTRL_EventKind_LaunchAndHandshakeDone; + evt->machine_id= CTRL_MachineID_Client; + evt->msg_id = msg->msg_id; + evt->entity_id = id; + ctrl_c2u_push_events(&evts); + } + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +internal void +ctrl_thread__launch_and_init(CTRL_Msg *msg) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + + //- rjf: launch + OS_LaunchOptions opts = {0}; + { + opts.cmd_line = msg->cmd_line_string_list; + opts.path = msg->path; + opts.env = msg->env_string_list; + opts.inherit_env = msg->env_inherit; + } + U32 id = demon_launch_process(&opts); + + //- rjf: run to initialization (entry point) + DEMON_Event *stop_event = 0; + if(id != 0) + { + DEMON_Handle unfrozen_process[8] = {0}; + DEMON_TrapChunkList demon_traps = {0}; + U64 entry_vaddr = 0; + DEMON_Handle entry_vaddr_proc = 0; + DEMON_RunCtrls run_ctrls = {0}; + run_ctrls.run_entities_are_unfrozen = 1; + run_ctrls.run_entities_are_processes = 1; + for(B32 done = 0; done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + switch(event->kind) + { + default:{}break; + + // rjf: new process -> freeze process + case DEMON_EventKind_CreateProcess: + if(run_ctrls.run_entity_count < ArrayCount(unfrozen_process)) + { + unfrozen_process[run_ctrls.run_entity_count] = event->process; + run_ctrls.run_entities = &unfrozen_process[0]; + run_ctrls.run_entity_count += 1; + }break; + + // rjf: breakpoint -> if it's the entry point, we're done. otherwise, keep going + case DEMON_EventKind_Breakpoint: + if(event->instruction_pointer == entry_vaddr) + { + done = 1; + stop_event = event; + }break; + + // rjf: exception -> done + case DEMON_EventKind_Exception: + { + done = 1; + stop_event = event; + }break; + + // rjf: process ended? -> remove from unfrozen processes. zero processes -> done. + case DEMON_EventKind_ExitProcess: + { + for(U64 idx = 0; idx < run_ctrls.run_entity_count; idx += 1) + { + if(run_ctrls.run_entities[idx] == event->process && + idx+1 < run_ctrls.run_entity_count) + { + MemoryCopy(run_ctrls.run_entities+idx, run_ctrls.run_entities+idx+1, sizeof(DEMON_Handle)*(run_ctrls.run_entity_count-(idx+1))); + break; + } + } + run_ctrls.run_entity_count -= 1; + if(run_ctrls.run_entity_count == 0) + { + done = 1; + stop_event = event; + } + }break; + + // rjf: done with handshake -> ready to find entry point. search launched processes + case DEMON_EventKind_HandshakeComplete: + { + // rjf: find entry point vaddr + for(U64 process_idx = 0; process_idx < run_ctrls.run_entity_count; process_idx += 1) + { + DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, run_ctrls.run_entities[process_idx]); + if(modules.count == 0) { continue; } + DEMON_Handle module = modules.handles[0]; + String8 exe_path = demon_full_path_from_module(scratch.arena, module); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + RADDBG_NameMap *unparsed_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Procedures); + if(rdbg->procedures != 0 && unparsed_map != 0) + { + // rjf: grab parsed name map + RADDBG_ParsedNameMap map = {0}; + raddbg_name_map_parse(rdbg, unparsed_map, &map); + + // rjf: grab entry point symbol names we might want to run to + String8 default_entry_points[] = + { + str8_lit("WinMain"), + str8_lit("wWinMain"), + str8_lit("main"), + str8_lit("wmain"), + str8_lit("WinMainCRTStartup"), + str8_lit("wWinMainCRTStartup"), + }; + + // rjf: find voff for one of the custom entry points attached to this msg + U64 voff = 0; + if(voff == 0) + { + for(String8Node *n = msg->strings.first; n != 0; n = n->next) + { + U32 procedure_id = 0; + { + String8 name = n->string; + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + if(id_count > 0) + { + procedure_id = ids[0]; + } + } + } + if(procedure_id != 0) + { + voff = raddbg_first_voff_from_proc(rdbg, procedure_id); + break; + } + } + } + + // rjf: find voff for one of the user's custom entry points + if(voff == 0) + { + for(String8Node *n = ctrl_state->user_entry_points.first; n != 0; n = n->next) + { + U32 procedure_id = 0; + { + String8 name = n->string; + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + if(id_count > 0) + { + procedure_id = ids[0]; + } + } + } + if(procedure_id != 0) + { + voff = raddbg_first_voff_from_proc(rdbg, procedure_id); + break; + } + } + } + + // rjf: find voff for one of the default entry points + if(voff == 0) + { + for(U64 idx = 0; voff == 0 && idx < ArrayCount(default_entry_points); idx += 1) + { + U32 procedure_id = 0; + { + String8 name = default_entry_points[idx]; + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + if(id_count > 0) + { + procedure_id = ids[0]; + } + } + } + if(procedure_id != 0) + { + voff = raddbg_first_voff_from_proc(rdbg, procedure_id); + break; + } + } + } + + // rjf: nonzero voff? => store + if(voff != 0) + { + U64 base_vaddr = demon_base_vaddr_from_module(module); + entry_vaddr = base_vaddr + voff; + entry_vaddr_proc = run_ctrls.run_entities[process_idx]; + } + } + + // rjf: found entry point -> insert into trap controls + if(entry_vaddr != 0) + { + DEMON_Trap trap = {entry_vaddr_proc, entry_vaddr}; + demon_trap_chunk_list_push(scratch.arena, &demon_traps, 256, &trap); + run_ctrls.traps = demon_traps; + } + + // rjf: no entry point found -> done + else + { + done = 1; + stop_event = event; + } + } + }break; + } + } + } + + //- rjf: record bad stop + if(stop_event == 0 && id == 0) + { + CTRL_EventList evts = {0}; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Error; + event->cause = CTRL_EventCause_Error; + ctrl_c2u_push_events(&evts); + } + + //- rjf: push request resolution event + { + CTRL_EventList evts = {0}; + CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); + evt->kind = CTRL_EventKind_LaunchAndInitDone; + evt->machine_id= CTRL_MachineID_Client; + evt->msg_id = msg->msg_id; + evt->entity_id = id; + ctrl_c2u_push_events(&evts); + } + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +internal void +ctrl_thread__attach(CTRL_Msg *msg) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + + //- rjf: attach + B32 attach_successful = demon_attach_process(msg->entity_id); + + //- rjf: run to handshake + if(attach_successful) + { + DEMON_Handle unfrozen_process = 0; + DEMON_RunCtrls run_ctrls = {0}; + run_ctrls.run_entities_are_unfrozen = 1; + run_ctrls.run_entities_are_processes = 1; + for(B32 done = 0; done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_CreateProcess: + { + unfrozen_process = event->process; + run_ctrls.run_entities = &unfrozen_process; + run_ctrls.run_entity_count = 1; + }break; + case DEMON_EventKind_HandshakeComplete: + { + done = 1; + }break; + } + } + } + + //- rjf: push request resolution event + { + CTRL_EventList evts = {0}; + CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); + evt->kind = CTRL_EventKind_AttachDone; + evt->machine_id= CTRL_MachineID_Client; + evt->msg_id = msg->msg_id; + evt->entity_id = !!attach_successful * msg->entity_id; + ctrl_c2u_push_events(&evts); + } + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +internal void +ctrl_thread__kill(CTRL_Msg *msg) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + DEMON_Handle process = ctrl_demon_handle_from_ctrl(msg->entity); + U32 exit_code = msg->exit_code; + + //- rjf: send kill + B32 kill_worked = demon_kill_process(process, exit_code); + + //- rjf: wait for process to be dead + if(demon_object_exists(process) && kill_worked) + { + DEMON_RunCtrls run_ctrls = {0}; + run_ctrls.run_entities_are_unfrozen = 1; + run_ctrls.run_entities_are_processes = 1; + run_ctrls.run_entities = &process; + run_ctrls.run_entity_count = 1; + for(B32 done = 0; done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + if(event->kind == DEMON_EventKind_ExitProcess && event->process == process) + { + done = 1; + } + } + } + + //- rjf: push request resolution event + { + CTRL_EventList evts = {0}; + CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); + evt->kind = CTRL_EventKind_KillDone; + evt->machine_id= CTRL_MachineID_Client; + evt->msg_id = msg->msg_id; + if(kill_worked) + { + evt->entity = msg->entity; + } + ctrl_c2u_push_events(&evts); + } + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +internal void +ctrl_thread__detach(CTRL_Msg *msg) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + DEMON_Handle process = ctrl_demon_handle_from_ctrl(msg->entity); + + //- rjf: detach + B32 detach_worked = demon_detach_process(process); + + //- rjf: wait for process to be dead + if(demon_object_exists(process) && detach_worked) + { + DEMON_RunCtrls run_ctrls = {0}; + run_ctrls.run_entities_are_unfrozen = 1; + run_ctrls.run_entities_are_processes = 1; + run_ctrls.run_entities = &process; + run_ctrls.run_entity_count = 1; + for(B32 done = 0; done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + if(event->kind == DEMON_EventKind_ExitProcess && event->process == process) + { + done = 1; + } + } + } + + //- rjf: push request resolution event + { + CTRL_EventList evts = {0}; + CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); + evt->kind = CTRL_EventKind_DetachDone; + evt->machine_id= CTRL_MachineID_Client; + evt->msg_id = msg->msg_id; + if(detach_worked) + { + evt->entity = msg->entity; + } + ctrl_c2u_push_events(&evts); + } + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +internal void +ctrl_thread__run(CTRL_Msg *msg) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + DEMON_Event *stop_event = 0; + CTRL_EventCause stop_cause = CTRL_EventCause_Null; + DEMON_Handle target_thread = ctrl_demon_handle_from_ctrl(msg->entity); + DEMON_Handle target_process = ctrl_demon_handle_from_ctrl(msg->parent); + U64 spoof_ip_vaddr = 911; + + //- rjf: gather processes + DEMON_HandleArray processes = demon_all_processes(scratch.arena); + + //- rjf: gather all initial breakpoints + DEMON_TrapChunkList user_traps = {0}; + { + // rjf: resolve module-dependent user bps + for(U64 process_idx = 0; process_idx < processes.count; process_idx += 1) + { + DEMON_Handle process = processes.handles[process_idx]; + DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, process); + for(U64 module_idx = 0; module_idx < modules.count; module_idx += 1) + { + DEMON_Handle module = modules.handles[module_idx]; + ctrl_append_resolved_module_user_bp_traps(scratch.arena, process, module, &msg->user_bps, &user_traps); + } + } + + // rjf: push virtual-address user breakpoints per-process + for(U64 process_idx = 0; process_idx < processes.count; process_idx += 1) + { + ctrl_append_resolved_process_user_bp_traps(scratch.arena, processes.handles[process_idx], &msg->user_bps, &user_traps); + } + } + + //- rjf: single step "stuck threads" + // + // "Stuck threads" are threads that are already on a User BP and would hit + // it immediately if resumed with all User BPs enabled. To get them "unstuck" + // we just need to single step them to get them off their current instruction. + // + // This only applies to threads OTHER THAN the target thread. If the target + // thread is on a user breakpoint, then we need to let trap net logic run, + // which may include features put on a trap net trap at the same address as + // the user breakpoint. + // + B32 target_thread_is_on_user_bp_and_trap_net_trap = 0; + if(stop_event == 0) + { + // rjf: gather stuck threads + DEMON_HandleList stuck_threads = {0}; + for(U64 i = 0; i < processes.count; i += 1) + { + DEMON_Handle process = processes.handles[i]; + DEMON_HandleArray threads = demon_threads_from_process(scratch.arena, process); + for(U64 j = 0; j < threads.count; j += 1) + { + DEMON_Handle thread = threads.handles[j]; + U64 rip = demon_read_ip(thread); + + // rjf: determine if thread is frozen + B32 thread_is_frozen = !msg->freeze_state_is_frozen; + for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) + { + if(ctrl_demon_handle_from_ctrl(n->v.handle) == thread) + { + thread_is_frozen ^= 1; + break; + } + } + + // rjf: not frozen? -> check if stuck & gather if so + if(thread_is_frozen == 0) + { + for(DEMON_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + { + B32 is_on_user_bp = 0; + for(DEMON_Trap *trap_ptr = n->v; trap_ptr < n->v+n->count; trap_ptr += 1) + { + if(trap_ptr->process == process && trap_ptr->address == rip) + { + is_on_user_bp = 1; + } + } + + B32 is_on_net_trap = 0; + for(CTRL_TrapNode *n = msg->traps.first; n != 0; n = n->next) + { + if(n->v.vaddr == rip) + { + is_on_net_trap = 1; + } + } + + if(is_on_user_bp && (!is_on_net_trap || thread != target_thread)) + { + demon_handle_list_push(scratch.arena, &stuck_threads, thread); + } + + if(is_on_user_bp && is_on_net_trap && thread == target_thread) + { + target_thread_is_on_user_bp_and_trap_net_trap = 1; + } + } + } + } + } + + // rjf: actually step stuck threads + for(DEMON_HandleNode *node = stuck_threads.first; + node != 0; + node = node->next) + { + DEMON_RunCtrls run_ctrls = {0}; + run_ctrls.single_step_thread = node->v; + for(B32 done = 0; done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop; + case DEMON_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop; + case DEMON_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop; + case DEMON_EventKind_Halt: stop_cause = CTRL_EventCause_InterruptedByHalt; goto stop; + stop:; + { + stop_event = event; + done = 1; + }break; + case DEMON_EventKind_SingleStep: + { + done = 1; + }break; + } + } + } + } + + //- rjf: resolve trap net + DEMON_TrapChunkList trap_net_traps = {0}; + for(CTRL_TrapNode *node = msg->traps.first; + node != 0; + node = node->next) + { + DEMON_Trap trap = {target_process, node->v.vaddr}; + demon_trap_chunk_list_push(scratch.arena, &trap_net_traps, 256, &trap); + } + + //- rjf: join user breakpoints and trap net traps + DEMON_TrapChunkList joined_traps = {0}; + { + demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &user_traps); + demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &trap_net_traps); + } + + //- rjf: record start + if(stop_event == 0) + { + CTRL_EventList evts = {0}; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Started; + ctrl_c2u_push_events(&evts); + } + + //- rjf: run loop + if(stop_event == 0) + { + U64 sp_check_value = demon_read_sp(target_thread); + B32 spoof_mode = 0; + CTRL_Spoof spoof = {0}; + U64 spoof_1_return_ip = 0; + + for(;;) + { + //- rjf: choose low level traps + DEMON_TrapChunkList *trap_list = &joined_traps; + if(spoof_mode) + { + trap_list = &user_traps; + } + + //- rjf: choose spoof + CTRL_Spoof *run_spoof = 0; + if(spoof_mode) + { + run_spoof = &spoof; + } + + //- rjf: setup run controls + DEMON_RunCtrls run_ctrls = {0}; + run_ctrls.ignore_previous_exception = 1; + run_ctrls.run_entity_count = msg->freeze_state_threads.count; + run_ctrls.run_entities = push_array(scratch.arena, DEMON_Handle, run_ctrls.run_entity_count); + run_ctrls.run_entities_are_unfrozen = !msg->freeze_state_is_frozen; + { + U64 idx = 0; + for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) + { + run_ctrls.run_entities[idx] = ctrl_demon_handle_from_ctrl(n->v.handle); + idx += 1; + } + } + run_ctrls.traps = *trap_list; + + //- rjf: get an event + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, run_spoof); + + //- rjf: determine event handling + B32 hard_stop = 0; + CTRL_EventCause hard_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + B32 use_stepping_logic = 0; + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_Error: + case DEMON_EventKind_Halt: + case DEMON_EventKind_SingleStep: + case DEMON_EventKind_Trap: + { + hard_stop = 1; + }break; + case DEMON_EventKind_Exception: + case DEMON_EventKind_Breakpoint: + { + use_stepping_logic = 1; + }break; + case DEMON_EventKind_CreateProcess: + { + DEMON_TrapChunkList new_traps = {0}; + ctrl_append_resolved_process_user_bp_traps(scratch.arena, event->process, &msg->user_bps, &new_traps); + demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + }break; + case DEMON_EventKind_LoadModule: + { + DEMON_TrapChunkList new_traps = {0}; + ctrl_append_resolved_module_user_bp_traps(scratch.arena, event->process, event->module, &msg->user_bps, &new_traps); + demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + }break; + } + + //- rjf: unpack info about thread attached to event + Architecture arch = demon_arch_from_object(event->thread); + U64 reg_size = regs_block_size_from_architecture(arch); + void *thread_regs_block = demon_read_regs(event->thread); + U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block); + DEMON_Handle module = 0; + U64 thread_rip_voff = 0; + { + Temp temp = temp_begin(scratch.arena); + DEMON_HandleArray modules = demon_modules_from_process(temp.arena, event->process); + if(modules.count != 0) + { + for(U64 idx = 0; idx < modules.count; idx += 1) + { + Rng1U64 vaddr_range = demon_vaddr_range_from_module(modules.handles[idx]); + if(contains_1u64(vaddr_range, thread_rip_vaddr)) + { + module = modules.handles[idx]; + thread_rip_voff = thread_rip_vaddr - vaddr_range.min; + break; + } + } + } + temp_end(temp); + } + + //////////////////////////////// + //- rjf: stepping logic -// + //{ + + //- rjf: handle if hitting a spoof or baked in trap + B32 hit_spoof = 0; + B32 exception_stop = 0; + if(use_stepping_logic) + { + if(event->kind == DEMON_EventKind_Exception) + { + // rjf: spoof check + if(spoof_mode && + target_process == event->process && + target_thread == event->thread && + spoof.new_ip_value == event->instruction_pointer) + { + hit_spoof = 1; + } + + // rjf: other exceptions cause stop + if(!hit_spoof) + { + exception_stop = 1; + use_stepping_logic = 0; + } + } + } + + //- TODO(rjf): Jeff is hitting a bug where a spoof IP (911) has been + // hit by a thread, !!!BUT!!! we seemingly don't catch that until a + // subsequent run of this loop, probably because there are other + // events in the queue that we report first, losing all state about + // spoof mode. + // + // I'm throwing in some detection for this case, so that we can diagnose + // it further from there. + // + if(event->kind == DEMON_EventKind_Exception && + event->instruction_pointer == 911 && + (hit_spoof == 0 || spoof_mode == 0)) + { + os_graphical_message(1, str8_lit("RADDBG INTERNAL DEVELOPMENT MESSAGE"), str8_lit("a bad, rare bug that Jeff found has been detected to occur - attach with debugger now")); + } + + //- rjf: handle spoof hit + if(hit_spoof) + { + // rjf: restore 1 ip + demon_write_ip(target_thread, spoof_1_return_ip); + + // rjf: clear spoof mode + spoof_mode = 0; + MemoryZeroStruct(&spoof); + + // rjf: skip remainder of handling + use_stepping_logic = 0; + } + + //- rjf: for breakpoint events, gather bp info + B32 hit_user_bp = 0; + B32 hit_trap_net_bp = 0; + B32 hit_conditional_bp_but_filtered = 0; + CTRL_TrapFlags hit_trap_flags = 0; + if(use_stepping_logic) + { + if(event->kind == DEMON_EventKind_Breakpoint) + { + Temp temp = temp_begin(scratch.arena); + String8List conditions = {0}; + + // rjf: user breakpoints + for(DEMON_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + { + DEMON_Trap *trap = n->v; + DEMON_Trap *opl = n->v + n->count; + for(;trap < opl; trap += 1) + { + if(trap->process == event->process && + trap->address == event->instruction_pointer && + (event->thread != target_thread || !target_thread_is_on_user_bp_and_trap_net_trap)) + { + CTRL_UserBreakpoint *user_bp = (CTRL_UserBreakpoint *)trap->id; + hit_user_bp = 1; + if(user_bp != 0 && user_bp->condition.size != 0) + { + str8_list_push(temp.arena, &conditions, user_bp->condition); + } + } + } + } + + // rjf: evaluate hit stop conditions + if(conditions.node_count != 0) + { + String8 exe_path = demon_full_path_from_module(temp.arena, module); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) + { + String8 string = condition_n->string; + EVAL_ParseCtx parse_ctx = zero_struct; + { + parse_ctx.arch = arch; + parse_ctx.ip_voff = thread_rip_voff; + parse_ctx.rdbg = rdbg; + parse_ctx.type_graph = tg_graph_begin(bit_size_from_arch(arch)/8, 256); + parse_ctx.regs_map = ctrl_string2reg_from_arch(arch); + parse_ctx.reg_alias_map = ctrl_string2alias_from_arch(arch); + parse_ctx.locals_map = eval_push_locals_map_from_raddbg_voff(temp.arena, rdbg, thread_rip_voff); + parse_ctx.member_map = eval_push_member_map_from_raddbg_voff(temp.arena, rdbg, thread_rip_voff); + } + EVAL_TokenArray tokens = eval_token_array_from_text(temp.arena, string); + EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(temp.arena, &parse_ctx, string, &tokens); + EVAL_ErrorList errors = parse.errors; + B32 parse_has_expr = (parse.expr != &eval_expr_nil); + B32 parse_is_type = (parse_has_expr && parse.expr->kind == EVAL_ExprKind_TypeIdent); + EVAL_IRTreeAndType ir_tree_and_type = {&eval_irtree_nil}; + if(parse_has_expr && errors.count == 0) + { + ir_tree_and_type = eval_irtree_and_type_from_expr(temp.arena, parse_ctx.type_graph, rdbg, parse.expr, &errors); + } + EVAL_OpList op_list = {0}; + if(parse_has_expr && ir_tree_and_type.tree != &eval_irtree_nil) + { + eval_oplist_from_irtree(scratch.arena, ir_tree_and_type.tree, &op_list); + } + String8 bytecode = {0}; + if(parse_has_expr && parse_is_type == 0 && op_list.encoded_size != 0) + { + bytecode = eval_bytecode_from_oplist(scratch.arena, &op_list); + } + EVAL_Result eval = {0}; + if(bytecode.size != 0) + { + U64 module_base = demon_base_vaddr_from_module(module); + U64 tls_base = 0; // TODO(rjf) + EVAL_Machine machine = {0}; + machine.u = (void *)event->process; + machine.arch = arch; + machine.memory_read = ctrl_eval_memory_read; + machine.reg_data = thread_regs_block; + machine.reg_size = reg_size; + machine.module_base = &module_base; + machine.tls_base = &tls_base; + eval = eval_interpret(&machine, bytecode); + } + if(eval.bad_eval == 0 && eval.value.u64 == 0) + { + hit_user_bp = 0; + hit_conditional_bp_but_filtered = 1; + } + else + { + hit_user_bp = 1; + hit_conditional_bp_but_filtered = 0; + break; + } + } + } + + // rjf: gather trap net hits + if(!hit_user_bp && event->process == target_process) + { + for(CTRL_TrapNode *node = msg->traps.first; + node != 0; + node = node->next) + { + if(node->v.vaddr == event->instruction_pointer) + { + hit_trap_net_bp = 1; + hit_trap_flags |= node->v.flags; + } + } + } + + temp_end(temp); + } + } + + //- rjf: hit conditional user bp but filtered -> single step + B32 cond_bp_single_step_stop = 0; + CTRL_EventCause cond_bp_single_step_stop_cause = CTRL_EventCause_Null; + if(hit_conditional_bp_but_filtered) + { + DEMON_RunCtrls single_step_ctrls = {0}; + single_step_ctrls.single_step_thread = event->thread; + for(B32 single_step_done = 0; single_step_done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_Error: + case DEMON_EventKind_Exception: + case DEMON_EventKind_Halt: + case DEMON_EventKind_Trap: + { + cond_bp_single_step_stop = 1; + single_step_done = 1; + use_stepping_logic = 0; + cond_bp_single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + }break; + case DEMON_EventKind_SingleStep: + { + single_step_done = 1; + cond_bp_single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + }break; + } + } + } + + //- rjf: user breakpoints on *any thread* cause a stop + B32 user_bp_stop = 0; + if(use_stepping_logic && hit_user_bp) + { + user_bp_stop = 1; + use_stepping_logic = 0; + } + + //- rjf: trap net on off-target threads are ignored + B32 step_past_trap_net = 0; + if(use_stepping_logic && hit_trap_net_bp) + { + if(event->thread != target_thread) + { + step_past_trap_net = 1; + use_stepping_logic = 0; + } + } + + //- rjf: trap net on on-target threads trigger trap net logic + B32 use_trap_net_logic = 0; + if(use_stepping_logic && hit_trap_net_bp) + { + if(event->thread == target_thread) + { + use_trap_net_logic = 1; + } + } + + //- rjf: trap net logic: stack pointer check + B32 stack_pointer_matches = 0; + if(use_trap_net_logic) + { + U64 sp = demon_read_sp(target_thread); + stack_pointer_matches = (sp == sp_check_value); + } + + //- rjf: trap net logic: single step after hit + B32 single_step_stop = 0; + CTRL_EventCause single_step_stop_cause = CTRL_EventCause_Null; + if(use_trap_net_logic) + { + if(hit_trap_flags & CTRL_TrapFlag_SingleStepAfterHit) + { + DEMON_RunCtrls single_step_ctrls = {0}; + single_step_ctrls.single_step_thread = target_thread; + for(B32 single_step_done = 0; single_step_done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_Error: + case DEMON_EventKind_Exception: + case DEMON_EventKind_Halt: + case DEMON_EventKind_Trap: + { + single_step_stop = 1; + single_step_done = 1; + use_stepping_logic = 0; + use_trap_net_logic = 0; + single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + }break; + case DEMON_EventKind_SingleStep: + { + single_step_done = 1; + single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + }break; + } + } + } + } + + //- rjf: trap net logic: begin spoof mode + B32 begin_spoof_mode = 0; + if(use_trap_net_logic) + { + if(hit_trap_flags & CTRL_TrapFlag_BeginSpoofMode) + { + // rjf: setup spoof mode + begin_spoof_mode = 1; + + U64 spoof_sp = demon_read_sp(target_thread); + spoof_mode = 1; + spoof.process = ctrl_handle_from_demon(target_process); + spoof.vaddr = spoof_sp; + spoof.new_ip_value = spoof_ip_vaddr; + + // rjf: remember 1 return ip + demon_read_memory(target_process, &spoof_1_return_ip, spoof_sp, sizeof(spoof_1_return_ip)); + } + } + + //- rjf: trap net logic: save stack pointer + B32 save_stack_pointer = 0; + if(use_trap_net_logic) + { + if(hit_trap_flags & CTRL_TrapFlag_SaveStackPointer) + { + if(stack_pointer_matches) + { + save_stack_pointer = 1; + sp_check_value = demon_read_sp(target_thread); + } + } + } + + //- rjf: trap net logic: end stepping + B32 trap_net_stop = 0; + if(use_trap_net_logic) + { + if(hit_trap_flags & CTRL_TrapFlag_EndStepping) + { + if((hit_trap_flags & CTRL_TrapFlag_IgnoreStackPointerCheck) || + stack_pointer_matches) + { + trap_net_stop = 1; + use_trap_net_logic = 0; + } + } + } + + //} + //- rjf: stepping logic -// + //////////////////////////////// + + //- rjf: handle step past trap net + B32 step_past_trap_net_stop = 0; + CTRL_EventCause step_past_trap_net_stop_cause = CTRL_EventCause_Null; + if(step_past_trap_net) + { + DEMON_RunCtrls single_step_ctrls = {0}; + single_step_ctrls.single_step_thread = event->thread; + for(B32 single_step_done = 0; single_step_done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_Error: + case DEMON_EventKind_Exception: + case DEMON_EventKind_Halt: + case DEMON_EventKind_Trap: + { + step_past_trap_net_stop = 1; + single_step_done = 1; + step_past_trap_net_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + }break; + case DEMON_EventKind_SingleStep: + { + single_step_done = 1; + step_past_trap_net_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + }break; + } + } + } + + //- rjf: loop exit condition + CTRL_EventCause stage_stop_cause = CTRL_EventCause_Null; + if(hard_stop) + { + stage_stop_cause = hard_stop_cause; + } + else if(cond_bp_single_step_stop) + { + stage_stop_cause = cond_bp_single_step_stop_cause; + } + else if(single_step_stop) + { + stage_stop_cause = single_step_stop_cause; + } + else if(step_past_trap_net_stop) + { + stage_stop_cause = step_past_trap_net_stop_cause; + } + else if(exception_stop) + { + stage_stop_cause = CTRL_EventCause_InterruptedByException; + } + else if(user_bp_stop) + { + stage_stop_cause = CTRL_EventCause_UserBreakpoint; + } + else if(trap_net_stop) + { + stage_stop_cause = CTRL_EventCause_Finished; + } + if(stage_stop_cause != CTRL_EventCause_Null) + { + stop_event = event; + stop_cause = stage_stop_cause; + break; + } + } + + //- rjf: unstick silently-hit spoofs + if(stop_event != 0 && stop_event->thread != target_thread && spoof_mode != 0) + { + U64 target_thread_rip = demon_read_ip(target_thread); + if(target_thread_rip == spoof.new_ip_value) + { + // rjf: restore 1 ip + demon_write_ip(target_thread, spoof_1_return_ip); + } + } + } + + //- rjf: record stop + if(stop_event != 0) + { + CTRL_EventList evts = {0}; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Stopped; + event->cause = stop_cause; + event->machine_id = CTRL_MachineID_Client; + event->entity = ctrl_handle_from_demon(stop_event->thread); + event->parent = ctrl_handle_from_demon(stop_event->process); + event->exception_code = stop_event->code; + event->vaddr_rng = r1u64(stop_event->address, stop_event->address); + event->rip_vaddr = stop_event->instruction_pointer; + ctrl_c2u_push_events(&evts); + } + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +internal void +ctrl_thread__single_step(CTRL_Msg *msg) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + + //- rjf: record start + { + CTRL_EventList evts = {0}; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Started; + ctrl_c2u_push_events(&evts); + } + + //- rjf: single step + DEMON_Event *stop_event = 0; + CTRL_EventCause stop_cause = CTRL_EventCause_Null; + { + DEMON_RunCtrls run_ctrls = {0}; + run_ctrls.single_step_thread = ctrl_demon_handle_from_ctrl(msg->entity); + for(B32 done = 0; done == 0;) + { + DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + switch(event->kind) + { + default:{}break; + case DEMON_EventKind_Error: {stop_cause = CTRL_EventCause_Error;}goto end_single_step; + case DEMON_EventKind_Exception: {stop_cause = CTRL_EventCause_InterruptedByException;}goto end_single_step; + case DEMON_EventKind_Halt: {stop_cause = CTRL_EventCause_InterruptedByHalt;}goto end_single_step; + case DEMON_EventKind_Trap: {stop_cause = CTRL_EventCause_InterruptedByTrap;}goto end_single_step; + case DEMON_EventKind_SingleStep: {stop_cause = CTRL_EventCause_Finished;}goto end_single_step; + case DEMON_EventKind_Breakpoint: {stop_cause = CTRL_EventCause_UserBreakpoint;}goto end_single_step; + end_single_step: + { + stop_event = event; + done = 1; + }break; + } + } + } + + //- rjf: record stop + if(stop_event != 0) + { + CTRL_EventList evts = {0}; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Stopped; + event->cause = stop_cause; + event->machine_id = CTRL_MachineID_Client; + event->entity = ctrl_handle_from_demon(stop_event->thread); + event->parent = ctrl_handle_from_demon(stop_event->process); + event->exception_code = stop_event->code; + event->vaddr_rng = r1u64(stop_event->address, stop_event->address); + event->rip_vaddr = stop_event->instruction_pointer; + ctrl_c2u_push_events(&evts); + } + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Memory-Stream-Thread-Only Functions + +//- rjf: entry point + +internal void +ctrl_mem_stream_thread__entry_point(void *p) +{ + TCTX tctx_ = {0}; + tctx_init_and_equip(&tctx_); + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + for(;;) + { + //- rjf: unpack next request + CTRL_MachineID machine_id = 0; + CTRL_Handle process = {0}; + Rng1U64 vaddr_range = {0}; + B32 zero_terminated = 0; + ctrl_u2ms_dequeue_req(&machine_id, &process, &vaddr_range, &zero_terminated); + + //- rjf: unpack process memory cache key + U64 process_hash = ctrl_hash_from_string(str8_struct(&process)); + U64 process_slot_idx = process_hash%cache->slots_count; + U64 process_stripe_idx = process_slot_idx%cache->stripes_count; + CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx]; + CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; + + //- rjf: unpack address range hash cache key + U64 range_hash = ctrl_hash_from_string(str8_struct(&vaddr_range)); + + //- rjf: take task + B32 got_task = 0; + OS_MutexScopeR(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + { + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + { + if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated) + { + got_task = !ins_atomic_u32_eval_cond_assign(&range_n->is_taken, 1, 0); + goto take_task__break_all; + } + } + } + } + take_task__break_all:; + } + + //- rjf: task was taken -> read memory + U64 range_size = 0; + Arena *range_arena = 0; + void *range_base = 0; + U64 zero_terminated_size = 0; + U64 memgen_idx = ctrl_memgen_idx(); + if(got_task) + { + range_size = dim_1u64(vaddr_range); + U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, KB(64)); + range_arena = arena_alloc__sized(range_size+ARENA_HEADER_SIZE, range_size+ARENA_HEADER_SIZE); + range_base = push_array_no_zero(range_arena, U8, range_size); + U64 bytes_read = ctrl_process_read(machine_id, process, vaddr_range, range_base); + if(bytes_read == 0) + { + arena_release(range_arena); + range_base = 0; + range_size = 0; + range_arena = 0; + } + else if(bytes_read < range_size) + { + MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); + } + zero_terminated_size = range_size; + if(zero_terminated) + { + for(U64 idx = 0; idx < bytes_read; idx += 1) + { + if(((U8 *)range_base)[idx] == 0) + { + zero_terminated_size = idx; + break; + } + } + } + } + + //- rjf: determine key for this region + U64 key_hash_data[] = + { + (U64)machine_id, + (U64)process.u64[0], + vaddr_range.min, + vaddr_range.min + zero_terminated_size, + }; + U128 key = hs_hash_from_data(str8((U8 *)key_hash_data, sizeof(key_hash_data))); + + //- rjf: read successful -> submit to hash store + U128 hash = {0}; + if(got_task && range_base != 0) + { + hash = hs_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size)); + } + + //- rjf: commit hash to cache + if(got_task) OS_MutexScopeW(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + { + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + { + if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated) + { + if(!u128_match(u128_zero(), hash)) + { + range_n->hash = hash; + range_n->memgen_idx = memgen_idx; + } + ins_atomic_u32_eval_assign(&range_n->is_taken, 0); + goto commit__break_all; + } + } + } + } + commit__break_all:; + } + } +} diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h new file mode 100644 index 00000000..1f40004b --- /dev/null +++ b/src/ctrl/ctrl_core.h @@ -0,0 +1,601 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CTRL_CORE_H +#define CTRL_CORE_H + +//////////////////////////////// +//~ rjf: ID Types + +typedef U64 CTRL_MsgID; +typedef U64 CTRL_MachineID; + +#define CTRL_MachineID_Client (1) + +//////////////////////////////// +//~ rjf: Handle Type + +typedef struct CTRL_Handle CTRL_Handle; +struct CTRL_Handle +{ + U64 u64[1]; +}; + +//////////////////////////////// +//~ rjf: Machine/Handle Pair Types + +typedef struct CTRL_MachineIDHandlePair CTRL_MachineIDHandlePair; +struct CTRL_MachineIDHandlePair +{ + CTRL_MachineID machine_id; + CTRL_Handle handle; +}; + +typedef struct CTRL_MachineIDHandlePairNode CTRL_MachineIDHandlePairNode; +struct CTRL_MachineIDHandlePairNode +{ + CTRL_MachineIDHandlePairNode *next; + CTRL_MachineIDHandlePair v; +}; + +typedef struct CTRL_MachineIDHandlePairList CTRL_MachineIDHandlePairList; +struct CTRL_MachineIDHandlePairList +{ + CTRL_MachineIDHandlePairNode *first; + CTRL_MachineIDHandlePairNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Trap Types + +typedef U32 CTRL_TrapFlags; +enum +{ + CTRL_TrapFlag_IgnoreStackPointerCheck = (1<<0), + CTRL_TrapFlag_SingleStepAfterHit = (1<<1), + CTRL_TrapFlag_SaveStackPointer = (1<<2), + CTRL_TrapFlag_BeginSpoofMode = (1<<3), + CTRL_TrapFlag_EndStepping = (1<<4), +}; + +typedef struct CTRL_Trap CTRL_Trap; +struct CTRL_Trap +{ + CTRL_TrapFlags flags; + U64 vaddr; +}; + +typedef struct CTRL_TrapNode CTRL_TrapNode; +struct CTRL_TrapNode +{ + CTRL_TrapNode *next; + CTRL_Trap v; +}; + +typedef struct CTRL_TrapList CTRL_TrapList; +struct CTRL_TrapList +{ + CTRL_TrapNode *first; + CTRL_TrapNode *last; + U64 count; +}; + +typedef struct CTRL_Spoof CTRL_Spoof; +struct CTRL_Spoof +{ + CTRL_Handle process; + U64 vaddr; + U64 new_ip_value; +}; + +//////////////////////////////// +//~ rjf: User Breakpoint Types + +typedef enum CTRL_UserBreakpointKind +{ + CTRL_UserBreakpointKind_FileNameAndLineColNumber, + CTRL_UserBreakpointKind_SymbolNameAndOffset, + CTRL_UserBreakpointKind_VirtualAddress, + CTRL_UserBreakpointKind_COUNT +} +CTRL_UserBreakpointKind; + +typedef struct CTRL_UserBreakpoint CTRL_UserBreakpoint; +struct CTRL_UserBreakpoint +{ + CTRL_UserBreakpointKind kind; + String8 string; + TxtPt pt; + U64 u64; + String8 condition; +}; + +typedef struct CTRL_UserBreakpointNode CTRL_UserBreakpointNode; +struct CTRL_UserBreakpointNode +{ + CTRL_UserBreakpointNode *next; + CTRL_UserBreakpoint v; +}; + +typedef struct CTRL_UserBreakpointList CTRL_UserBreakpointList; +struct CTRL_UserBreakpointList +{ + CTRL_UserBreakpointNode *first; + CTRL_UserBreakpointNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/ctrl.meta.h" + +//////////////////////////////// +//~ rjf: Message Types + +typedef enum CTRL_MsgKind +{ + CTRL_MsgKind_Null, + CTRL_MsgKind_LaunchAndHandshake, + CTRL_MsgKind_LaunchAndInit, + CTRL_MsgKind_Attach, + CTRL_MsgKind_Kill, + CTRL_MsgKind_Detach, + CTRL_MsgKind_Run, + CTRL_MsgKind_SingleStep, + CTRL_MsgKind_SetUserEntryPoints, + CTRL_MsgKind_COUNT, +} +CTRL_MsgKind; + +typedef struct CTRL_Msg CTRL_Msg; +struct CTRL_Msg +{ + CTRL_MsgKind kind; + CTRL_MsgID msg_id; + CTRL_MachineID machine_id; + CTRL_Handle entity; + CTRL_Handle parent; + U32 entity_id; + U32 exit_code; + B32 env_inherit; + U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; + String8 path; + String8List strings; + String8List cmd_line_string_list; + String8List env_string_list; + CTRL_TrapList traps; + CTRL_UserBreakpointList user_bps; + CTRL_MachineIDHandlePairList freeze_state_threads; // NOTE(rjf): can be frozen or unfrozen, depending on `freeze_state_is_frozen` + B32 freeze_state_is_frozen; +}; + +typedef struct CTRL_MsgNode CTRL_MsgNode; +struct CTRL_MsgNode +{ + CTRL_MsgNode *next; + CTRL_Msg v; +}; + +typedef struct CTRL_MsgList CTRL_MsgList; +struct CTRL_MsgList +{ + CTRL_MsgNode *first; + CTRL_MsgNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Event Types + +typedef enum CTRL_EventKind +{ + CTRL_EventKind_Null, + CTRL_EventKind_Error, + + //- rjf: starts/stops + CTRL_EventKind_Started, + CTRL_EventKind_Stopped, + + //- rjf: entity creation/deletion + CTRL_EventKind_NewProc, + CTRL_EventKind_NewThread, + CTRL_EventKind_NewModule, + CTRL_EventKind_EndProc, + CTRL_EventKind_EndThread, + CTRL_EventKind_EndModule, + + //- rjf: debug strings + CTRL_EventKind_DebugString, + CTRL_EventKind_ThreadName, + + //- rjf: memory + CTRL_EventKind_MemReserve, + CTRL_EventKind_MemCommit, + CTRL_EventKind_MemDecommit, + CTRL_EventKind_MemRelease, + + //- rjf: ctrl requests + CTRL_EventKind_LaunchAndHandshakeDone, + CTRL_EventKind_LaunchAndInitDone, + CTRL_EventKind_AttachDone, + CTRL_EventKind_KillDone, + CTRL_EventKind_DetachDone, + + CTRL_EventKind_COUNT +} +CTRL_EventKind; + +typedef enum CTRL_EventCause +{ + CTRL_EventCause_Null, + CTRL_EventCause_Error, + CTRL_EventCause_Finished, + CTRL_EventCause_UserBreakpoint, + CTRL_EventCause_InterruptedByTrap, + CTRL_EventCause_InterruptedByException, + CTRL_EventCause_InterruptedByHalt, + CTRL_EventCause_COUNT +} +CTRL_EventCause; + +typedef enum CTRL_ExceptionKind +{ + CTRL_ExceptionKind_Null, + CTRL_ExceptionKind_MemoryRead, + CTRL_ExceptionKind_MemoryWrite, + CTRL_ExceptionKind_MemoryExecute, + CTRL_ExceptionKind_CppThrow, + CTRL_ExceptionKind_COUNT +} +CTRL_ExceptionKind; + +typedef struct CTRL_Event CTRL_Event; +struct CTRL_Event +{ + CTRL_EventKind kind; + CTRL_EventCause cause; + CTRL_ExceptionKind exception_kind; + CTRL_MsgID msg_id; + CTRL_MachineID machine_id; + CTRL_Handle entity; + CTRL_Handle parent; + Architecture arch; + U64 u64_code; + U32 entity_id; + Rng1U64 vaddr_rng; + U64 rip_vaddr; + U64 stack_base; + U64 tls_root; + U32 exception_code; + String8 string; +}; + +typedef struct CTRL_EventNode CTRL_EventNode; +struct CTRL_EventNode +{ + CTRL_EventNode *next; + CTRL_Event v; +}; + +typedef struct CTRL_EventList CTRL_EventList; +struct CTRL_EventList +{ + CTRL_EventNode *first; + CTRL_EventNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Process Memory Cache Types + +// NOTE(rjf): +// +// Process memory is cached with a 5-level page table. Each level has 256 +// slots, and is indexed into with 8 bits. Each index is extracted from a +// virtual address in the following manner: +// +// |1------||2------||3------||4------||5------||byte-n-page| +// xxxxxxxx xxxx0000 00000000 00000000 00000000 00000000 0000xxxx xxxxxxxx +// +// The top 12 bits are not used (a 52-bit address space is supported at most). +// The next 8 most-significant-bits are used to index into the level 1 table. +// The next 8 are used to index into the level 2. Then the level 3. Then the +// level 4. At the level 4 table, instead of pointing to other tables, each +// slot points at the base address of a cached 4KB page. The next 8 bits are +// used to index into that table. The final 12 bits in the address are used +// to refer to unique bytes within each page. + +typedef struct CTRL_ProcessMemoryCacheNode4 CTRL_ProcessMemoryCacheNode4; +struct CTRL_ProcessMemoryCacheNode4 +{ + U64 page_memgen_idxs[256]; + U128 page_hashes[256]; +}; + +typedef struct CTRL_ProcessMemoryCacheNode3 CTRL_ProcessMemoryCacheNode3; +struct CTRL_ProcessMemoryCacheNode3 +{ + CTRL_ProcessMemoryCacheNode4 *children[256]; +}; + +typedef struct CTRL_ProcessMemoryCacheNode2 CTRL_ProcessMemoryCacheNode2; +struct CTRL_ProcessMemoryCacheNode2 +{ + CTRL_ProcessMemoryCacheNode3 *children[256]; +}; + +typedef struct CTRL_ProcessMemoryCacheNode1 CTRL_ProcessMemoryCacheNode1; +struct CTRL_ProcessMemoryCacheNode1 +{ + CTRL_ProcessMemoryCacheNode2 *children[256]; +}; + +typedef struct CTRL_ProcessMemoryRangeHashNode CTRL_ProcessMemoryRangeHashNode; +struct CTRL_ProcessMemoryRangeHashNode +{ + CTRL_ProcessMemoryRangeHashNode *next; + Rng1U64 vaddr_range; + B32 zero_terminated; + U128 hash; + U64 memgen_idx; + B32 is_taken; +}; + +typedef struct CTRL_ProcessMemoryRangeHashSlot CTRL_ProcessMemoryRangeHashSlot; +struct CTRL_ProcessMemoryRangeHashSlot +{ + CTRL_ProcessMemoryRangeHashNode *first; + CTRL_ProcessMemoryRangeHashNode *last; +}; + +typedef struct CTRL_ProcessMemoryCacheNode CTRL_ProcessMemoryCacheNode; +struct CTRL_ProcessMemoryCacheNode +{ + CTRL_ProcessMemoryCacheNode *next; + CTRL_ProcessMemoryCacheNode *prev; + Arena *arena; + CTRL_MachineID machine_id; + CTRL_Handle process; + CTRL_ProcessMemoryCacheNode1 *children[256]; + U64 range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_hash_slots; +}; + +typedef struct CTRL_ProcessMemoryCacheSlot CTRL_ProcessMemoryCacheSlot; +struct CTRL_ProcessMemoryCacheSlot +{ + CTRL_ProcessMemoryCacheNode *first; + CTRL_ProcessMemoryCacheNode *last; +}; + +typedef struct CTRL_ProcessMemoryCacheStripe CTRL_ProcessMemoryCacheStripe; +struct CTRL_ProcessMemoryCacheStripe +{ + OS_Handle rw_mutex; +}; + +typedef struct CTRL_ProcessMemoryCache CTRL_ProcessMemoryCache; +struct CTRL_ProcessMemoryCache +{ + U64 slots_count; + CTRL_ProcessMemoryCacheSlot *slots; + U64 stripes_count; + CTRL_ProcessMemoryCacheStripe *stripes; +}; + +//////////////////////////////// +//~ rjf: Wakeup Hook Function Types + +#define CTRL_WAKEUP_FUNCTION_DEF(name) void name(void) +typedef CTRL_WAKEUP_FUNCTION_DEF(CTRL_WakeupFunctionType); + +//////////////////////////////// +//~ rjf: Main State Types + +typedef struct CTRL_State CTRL_State; +struct CTRL_State +{ + Arena *arena; + CTRL_WakeupFunctionType *wakeup_hook; + U64 run_idx; + U64 memgen_idx; + + // rjf: name -> register/alias hash tables for eval + EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT]; + EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT]; + + // rjf: process memory cache + CTRL_ProcessMemoryCache process_memory_cache; + + // rjf: user -> ctrl msg ring buffer + U64 u2c_ring_size; + U8 *u2c_ring_base; + U64 u2c_ring_write_pos; + U64 u2c_ring_read_pos; + OS_Handle u2c_ring_mutex; + OS_Handle u2c_ring_cv; + + // rjf: ctrl -> user event ring buffer + U64 c2u_ring_size; + U8 *c2u_ring_base; + U64 c2u_ring_write_pos; + U64 c2u_ring_read_pos; + OS_Handle c2u_ring_mutex; + OS_Handle c2u_ring_cv; + + // rjf: ctrl thread state + OS_Handle ctrl_thread; + Arena *demon_event_arena; + DEMON_EventNode *first_demon_event_node; + DEMON_EventNode *last_demon_event_node; + DEMON_EventNode *free_demon_event_node; + Arena *user_entry_point_arena; + String8List user_entry_points; + U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; + U64 process_counter; + + // rjf: user -> memstream ring buffer + U64 u2ms_ring_size; + U8 *u2ms_ring_base; + U64 u2ms_ring_write_pos; + U64 u2ms_ring_read_pos; + OS_Handle u2ms_ring_mutex; + OS_Handle u2ms_ring_cv; + + // rjf: memory stream threads + U64 ms_thread_count; + OS_Handle *ms_threads; +}; + +//////////////////////////////// +//~ rjf: Globals + +global CTRL_State *ctrl_state = 0; + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void ctrl_init(CTRL_WakeupFunctionType *wakeup_hook); + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal U64 ctrl_hash_from_string(String8 string); +internal CTRL_EventCause ctrl_event_cause_from_demon_event_kind(DEMON_EventKind event_kind); +internal B32 ctrl_handle_match(CTRL_Handle a, CTRL_Handle b); + +//////////////////////////////// +//~ rjf: Ctrl <-> Demon Handle Translation Functions + +internal DEMON_Handle ctrl_demon_handle_from_ctrl(CTRL_Handle h); +internal CTRL_Handle ctrl_handle_from_demon(DEMON_Handle h); + +//////////////////////////////// +//~ rjf: Machine/Handle Pair Type Functions + +internal void ctrl_machine_id_handle_pair_list_push(Arena *arena, CTRL_MachineIDHandlePairList *list, CTRL_MachineIDHandlePair *pair); +internal CTRL_MachineIDHandlePairList ctrl_machine_id_handle_pair_list_copy(Arena *arena, CTRL_MachineIDHandlePairList *src); + +//////////////////////////////// +//~ rjf: Trap Type Functions + +internal void ctrl_trap_list_push(Arena *arena, CTRL_TrapList *list, CTRL_Trap *trap); +internal CTRL_TrapList ctrl_trap_list_copy(Arena *arena, CTRL_TrapList *src); + +//////////////////////////////// +//~ rjf: User Breakpoint Type Functions + +internal void ctrl_user_breakpoint_list_push(Arena *arena, CTRL_UserBreakpointList *list, CTRL_UserBreakpoint *bp); +internal CTRL_UserBreakpointList ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src); +internal void ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DEMON_Handle module, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out); +internal void ctrl_append_resolved_process_user_bp_traps(Arena *arena, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out); + +//////////////////////////////// +//~ rjf: Message Type Functions + +//- rjf: deep copying +internal void ctrl_msg_deep_copy(Arena *arena, CTRL_Msg *dst, CTRL_Msg *src); + +//- rjf: list building +internal CTRL_Msg *ctrl_msg_list_push(Arena *arena, CTRL_MsgList *list); + +//- rjf: serialization +internal String8 ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs); +internal CTRL_MsgList ctrl_msg_list_from_serialized_string(Arena *arena, String8 string); + +//////////////////////////////// +//~ rjf: Event Type Functions + +//- rjf: list building +internal CTRL_Event *ctrl_event_list_push(Arena *arena, CTRL_EventList *list); +internal void ctrl_event_list_concat_in_place(CTRL_EventList *dst, CTRL_EventList *to_push); + +//- rjf: serialization +internal String8 ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event); +internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 string); + +//////////////////////////////// +//~ rjf: Shared Functions + +//- rjf: run index +internal U64 ctrl_run_idx(void); +internal U64 ctrl_memgen_idx(void); + +//- rjf: halt everything +internal void ctrl_halt(void); + +//- rjf: exe -> dbg path mapping +internal String8 ctrl_inferred_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); +internal String8 ctrl_forced_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); +internal String8 ctrl_natural_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); +internal String8 ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); + +//- rjf: handle -> arch +internal Architecture ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle); + +//- rjf: process memory reading/writing +internal U64 ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst); +internal String8 ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range); +internal String8 ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit); +internal B32 ctrl_process_write_data(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, String8 data); +internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated); + +//- rjf: register reading/writing +internal void *ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); +internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block); +internal U64 ctrl_rip_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); +internal B32 ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip); +internal U64 ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); + +//- rjf: name -> register/alias hash tables, for eval +internal EVAL_String2NumMap *ctrl_string2reg_from_arch(Architecture arch); +internal EVAL_String2NumMap *ctrl_string2alias_from_arch(Architecture arch); + +//////////////////////////////// +//~ rjf: User -> Ctrl Communication + +internal B32 ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us); +internal CTRL_MsgList ctrl_u2c_pop_msgs(Arena *arena); + +//////////////////////////////// +//~ rjf: Ctrl -> User Communication + +internal void ctrl_c2u_push_events(CTRL_EventList *events); +internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); + +//////////////////////////////// +//~ rjf: User -> Memory Stream Communication + +internal B32 ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); +internal void ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); + +//////////////////////////////// +//~ rjf: Control-Thread-Only Functions + +//- rjf: entry point +internal void ctrl_thread__entry_point(void *p); + +//- rjf: attached process running/event gathering +internal DEMON_Event *ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_ctrls, CTRL_Spoof *spoof); + +//- rjf: eval helpers +internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size); + +//- rjf: msg kind implementations +internal void ctrl_thread__launch_and_handshake(CTRL_Msg *msg); +internal void ctrl_thread__launch_and_init(CTRL_Msg *msg); +internal void ctrl_thread__attach(CTRL_Msg *msg); +internal void ctrl_thread__kill(CTRL_Msg *msg); +internal void ctrl_thread__detach(CTRL_Msg *msg); +internal void ctrl_thread__run(CTRL_Msg *msg); +internal void ctrl_thread__single_step(CTRL_Msg *msg); + +//////////////////////////////// +//~ rjf: Memory-Stream-Thread-Only Functions + +//- rjf: entry point +internal void ctrl_mem_stream_thread__entry_point(void *p); + +#endif //CTRL_CORE_H diff --git a/src/ctrl/ctrl_inc.c b/src/ctrl/ctrl_inc.c new file mode 100644 index 00000000..cdbe3eda --- /dev/null +++ b/src/ctrl/ctrl_inc.c @@ -0,0 +1,4 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "ctrl_core.c" diff --git a/src/ctrl/ctrl_inc.h b/src/ctrl/ctrl_inc.h new file mode 100644 index 00000000..e485f6d0 --- /dev/null +++ b/src/ctrl/ctrl_inc.h @@ -0,0 +1,77 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CTRL_INC_H +#define CTRL_INC_H + +//////////////////////////////// +//~ NOTE(rjf): Control Layer Overview (2023/8/29) +// +// This layer's purpose is to provide access to the asynchronously-running, low +// level parts of a debugger, running on the debugger client. This primarily +// consists of process control, using the Demon layer (the lower level +// abstraction layer for process control, across multiple OSes), but including +// higher-level concepts, like stepping, breakpoint resolution, conditional +// breakpoint evaluation, and so on. Right now, this just includes process +// control *local to the debugger client machine*. But in the future, this can +// also include communication to multiple target machines, all running their +// own process controller, using the Demon layer. +// +// This part of a debugger must run asynchronously to prevent blocking the UI - +// ideally our debugger is designed such that, if targets are running, the +// debugger frontend is still usable for a variety of purposes. So, in short, +// the asynchronously-running "control thread", implemented by this layer, is +// tasked with communicating with a separately executing "user thread". This +// communication happens in two directions - `user -> ctrl`, and the reverse, +// `ctrl -> user`. +// +// In the case of `user -> ctrl` communication, this is done with a ring buffer +// of "messages" (`CTRL_Msg`), pushed via `ctrl_u2c_push_msgs`. These messages +// include commands like: launching targets, attaching to targets, killing +// targets, detaching from targets, stepping/running, or single stepping. +// +// In the case of `ctrl -> user` communication, this is done with a ring buffer +// of "events" (`CTRL_Event`), popped via `ctrl_c2u_pop_events`. These events +// include information about what happened during the execution of targets - +// including: process/module/thread creation, process/module/thread deletion, +// debug strings, thread name events, memory allocation events, and stop events +// (where stops can be caused by: user breakpoints, traps set for stepping, +// exceptions, halts, or errors). +// +// The various stepping algorithms are implemented with two concepts: (a) the +// "trap net", and (b) "spoofs". +// +// A "trap net" is a term which refers to a set of addresses paired with a set +// of behavioral flags. Before targets run, trap instructions are written to +// these addresses. After targets stop, these addresses are reset to their +// original bytes. These trap instructions cause the debugger's targets to +// stop executing, and based on which behavioral flags are associated with +// the instruction causing the stop, the control thread may adjust parameters +// used for running, then continue execution, or it will not resume target +// execution, and will report stopped events. These behavioral flags can +// include: single-stepping the stopped thread to execute the instruction at +// the trap location, saving a stack pointer "check value" (where this check +// value is compared against when making decisions about whether to continue +// running or not), and so on. It's complicated to unpack why exactly these +// behaviors are useful, but the TL;DR of it is that they are used for a +// variety of stepping behaviors. For example, when doing a "step into" step, +// a `call` instruction can have a trap set at it, and will be marked with +// a "single-step-after" trap flag, as well as the "end stepping" trap flag, +// such that the step operation will complete after the `call` has executed. +// +// A "spoof" is a feature the control layer uses to detect when some thread +// returns from a particular sub-callstack. This is useful when implementing +// "step over" in functions that may be recursive. In short, unlike a trap, +// which writes a trap instruction (like `int3`) into an instruction stream, +// a spoof overwrites a *return address* on some thread's *stack*. This return +// address is not a valid address for executing code -- it is simply a value +// that the debugger can recognize, such that it is notified when the thread +// returns from some level in a callstack. When the thread exits some function, +// it will return to the "spoofed" address, and it will immediately hit an +// exception, because the spoofed address will not be a valid address for +// code execution. At that point, the debugger can move the thread back to +// the pre-spoof return address, and resume execution. + +#include "ctrl_core.h" + +#endif //CTRL_INC_H diff --git a/src/ctrl/generated/ctrl.meta.c b/src/ctrl/generated/ctrl.meta.c new file mode 100644 index 00000000..b9d27fe6 --- /dev/null +++ b/src/ctrl/generated/ctrl.meta.c @@ -0,0 +1,5 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + diff --git a/src/ctrl/generated/ctrl.meta.h b/src/ctrl/generated/ctrl.meta.h new file mode 100644 index 00000000..5a5347ed --- /dev/null +++ b/src/ctrl/generated/ctrl.meta.h @@ -0,0 +1,216 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef CTRL_META_H +#define CTRL_META_H + +typedef enum CTRL_ExceptionCodeKind +{ +CTRL_ExceptionCodeKind_Null, +CTRL_ExceptionCodeKind_Win32CtrlC, +CTRL_ExceptionCodeKind_Win32CtrlBreak, +CTRL_ExceptionCodeKind_Win32WinRTOriginateError, +CTRL_ExceptionCodeKind_Win32WinRTTransformError, +CTRL_ExceptionCodeKind_Win32RPCCallCancelled, +CTRL_ExceptionCodeKind_Win32DatatypeMisalignment, +CTRL_ExceptionCodeKind_Win32AccessViolation, +CTRL_ExceptionCodeKind_Win32InPageError, +CTRL_ExceptionCodeKind_Win32InvalidHandle, +CTRL_ExceptionCodeKind_Win32NotEnoughQuota, +CTRL_ExceptionCodeKind_Win32IllegalInstruction, +CTRL_ExceptionCodeKind_Win32CannotContinueException, +CTRL_ExceptionCodeKind_Win32InvalidExceptionDisposition, +CTRL_ExceptionCodeKind_Win32ArrayBoundsExceeded, +CTRL_ExceptionCodeKind_Win32FloatingPointDenormalOperand, +CTRL_ExceptionCodeKind_Win32FloatingPointDivisionByZero, +CTRL_ExceptionCodeKind_Win32FloatingPointInexactResult, +CTRL_ExceptionCodeKind_Win32FloatingPointInvalidOperation, +CTRL_ExceptionCodeKind_Win32FloatingPointOverflow, +CTRL_ExceptionCodeKind_Win32FloatingPointStackCheck, +CTRL_ExceptionCodeKind_Win32FloatingPointUnderflow, +CTRL_ExceptionCodeKind_Win32IntegerDivisionByZero, +CTRL_ExceptionCodeKind_Win32IntegerOverflow, +CTRL_ExceptionCodeKind_Win32PrivilegedInstruction, +CTRL_ExceptionCodeKind_Win32StackOverflow, +CTRL_ExceptionCodeKind_Win32UnableToLocateDLL, +CTRL_ExceptionCodeKind_Win32OrdinalNotFound, +CTRL_ExceptionCodeKind_Win32EntryPointNotFound, +CTRL_ExceptionCodeKind_Win32DLLInitializationFailed, +CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleFaults, +CTRL_ExceptionCodeKind_Win32FloatingPointSSEMultipleTraps, +CTRL_ExceptionCodeKind_Win32AssertionFailed, +CTRL_ExceptionCodeKind_Win32ModuleNotFound, +CTRL_ExceptionCodeKind_Win32ProcedureNotFound, +CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected, +CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation, +CTRL_ExceptionCodeKind_COUNT +} CTRL_ExceptionCodeKind; + +U32 ctrl_exception_code_kind_code_table[] = +{ +0, +0x40010005, +0x40010008, +0x40080201, +0x40080202, +0x0000071a, +0x80000002, +0xc0000005, +0xc0000006, +0xc0000008, +0xc0000017, +0xc000001d, +0xc0000025, +0xc0000026, +0xc000008c, +0xc000008d, +0xc000008e, +0xc000008f, +0xc0000090, +0xc0000091, +0xc0000092, +0xc0000093, +0xc0000094, +0xc0000095, +0xc0000096, +0xc00000fd, +0xc0000135, +0xc0000138, +0xc0000139, +0xc0000142, +0xc00002b4, +0xc00002b5, +0xc0000420, +0xc06d007e, +0xc06d007f, +0xe073616e, +0xe0736171, +}; + +String8 ctrl_exception_code_kind_display_string_table[] = +{ +{0}, +str8_lit_comp("(Win32) Control-C"), +str8_lit_comp("(Win32) Control-Break"), +str8_lit_comp("(Win32) WinRT Originate Error"), +str8_lit_comp("(Win32) WinRT Transform Error"), +str8_lit_comp("(Win32) RPC Call Cancelled"), +str8_lit_comp("(Win32) Data Type Misalignment"), +str8_lit_comp("(Win32) Access Violation"), +str8_lit_comp("(Win32) In Page Error"), +str8_lit_comp("(Win32) Invalid Handle Specified"), +str8_lit_comp("(Win32) Not Enough Quota"), +str8_lit_comp("(Win32) Illegal Instruction"), +str8_lit_comp("(Win32) Cannot Continue From Exception"), +str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"), +str8_lit_comp("(Win32) Array Bounds Exceeded"), +str8_lit_comp("(Win32) Floating-Point Denormal Operand"), +str8_lit_comp("(Win32) Floating-Point Division By Zero"), +str8_lit_comp("(Win32) Floating-Point Inexact Result"), +str8_lit_comp("(Win32) Floating-Point Invalid Operation"), +str8_lit_comp("(Win32) Floating-Point Overflow"), +str8_lit_comp("(Win32) Floating-Point Stack Check"), +str8_lit_comp("(Win32) Floating-Point Underflow"), +str8_lit_comp("(Win32) Integer Division By Zero"), +str8_lit_comp("(Win32) Integer Overflow"), +str8_lit_comp("(Win32) Privileged Instruction"), +str8_lit_comp("(Win32) Stack Overflow"), +str8_lit_comp("(Win32) Unable To Locate DLL"), +str8_lit_comp("(Win32) Ordinal Not Found"), +str8_lit_comp("(Win32) Entry Point Not Found"), +str8_lit_comp("(Win32) DLL Initialization Failed"), +str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"), +str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"), +str8_lit_comp("(Win32) Assertion Failed"), +str8_lit_comp("(Win32) Module Not Found"), +str8_lit_comp("(Win32) Procedure Not Found"), +str8_lit_comp("(Win32) Sanitizer Error Detected"), +str8_lit_comp("(Win32) Sanitizer Raw Access Violation"), +}; + +String8 ctrl_exception_code_kind_lowercase_code_string_table[] = +{ +{0}, +str8_lit_comp("win32_ctrl_c"), +str8_lit_comp("win32_ctrl_break"), +str8_lit_comp("win32_win_rt_originate_error"), +str8_lit_comp("win32_win_rt_transform_error"), +str8_lit_comp("win32_rpc_call_cancelled"), +str8_lit_comp("win32_datatype_misalignment"), +str8_lit_comp("win32_access_violation"), +str8_lit_comp("win32_in_page_error"), +str8_lit_comp("win32_invalid_handle"), +str8_lit_comp("win32_not_enough_quota"), +str8_lit_comp("win32_illegal_instruction"), +str8_lit_comp("win32_cannot_continue_exception"), +str8_lit_comp("win32_invalid_exception_disposition"), +str8_lit_comp("win32_array_bounds_exceeded"), +str8_lit_comp("win32_floating_point_denormal_operand"), +str8_lit_comp("win32_floating_point_division_by_zero"), +str8_lit_comp("win32_floating_point_inexact_result"), +str8_lit_comp("win32_floating_point_invalid_operation"), +str8_lit_comp("win32_floating_point_overflow"), +str8_lit_comp("win32_floating_point_stack_check"), +str8_lit_comp("win32_floating_point_underflow"), +str8_lit_comp("win32_integer_division_by_zero"), +str8_lit_comp("win32_integer_overflow"), +str8_lit_comp("win32_privileged_instruction"), +str8_lit_comp("win32_stack_overflow"), +str8_lit_comp("win32_unable_to_locate_dll"), +str8_lit_comp("win32_ordinal_not_found"), +str8_lit_comp("win32_entry_point_not_found"), +str8_lit_comp("win32_dll_initialization_failed"), +str8_lit_comp("win32_floating_point_sse_multiple_faults"), +str8_lit_comp("win32_floating_point_sse_multiple_traps"), +str8_lit_comp("win32_assertion_failed"), +str8_lit_comp("win32_module_not_found"), +str8_lit_comp("win32_procedure_not_found"), +str8_lit_comp("win32_sanitizer_error_detected"), +str8_lit_comp("win32_sanitizer_raw_access_violation"), +}; + +B8 ctrl_exception_code_kind_default_enable_table[] = +{ +0, +1, +1, +0, +0, +0, +0, +1, +0, +1, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +1, +0, +0, +1, +0, +}; + + +#endif // CTRL_META_H diff --git a/src/dasm/dasm.c b/src/dasm/dasm.c new file mode 100644 index 00000000..b456629b --- /dev/null +++ b/src/dasm/dasm.c @@ -0,0 +1,539 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +dasm_init(void) +{ + Arena *arena = arena_alloc(); + dasm_shared = push_array(arena, DASM_Shared, 1); + dasm_shared->arena = arena; + dasm_shared->entity_map.slots_count = 1024; + dasm_shared->entity_map.slots = push_array(arena, DASM_EntitySlot, dasm_shared->entity_map.slots_count); + dasm_shared->entity_map_stripes.count = 64; + dasm_shared->entity_map_stripes.v = push_array(arena, DASM_Stripe, dasm_shared->entity_map_stripes.count); + for(U64 idx = 0; idx < dasm_shared->entity_map_stripes.count; idx += 1) + { + dasm_shared->entity_map_stripes.v[idx].arena = arena_alloc(); + dasm_shared->entity_map_stripes.v[idx].rw_mutex = os_rw_mutex_alloc(); + dasm_shared->entity_map_stripes.v[idx].cv = os_condition_variable_alloc(); + } + dasm_shared->u2d_ring_mutex = os_mutex_alloc(); + dasm_shared->u2d_ring_cv = os_condition_variable_alloc(); + dasm_shared->u2d_ring_size = KB(64); + dasm_shared->u2d_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2d_ring_size); + dasm_shared->decode_thread_count = Max(1, os_logical_core_count()-1); + dasm_shared->decode_threads = push_array(arena, OS_Handle, dasm_shared->decode_thread_count); + for(U64 idx = 0; idx < dasm_shared->decode_thread_count; idx += 1) + { + dasm_shared->decode_threads[idx] = os_launch_thread(dasm_decode_thread_entry_point, (void *)idx, 0); + } +} + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +dasm_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +//////////////////////////////// +//~ rjf: Instruction Type Functions + +internal void +dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst) +{ + DASM_InstChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, DASM_InstChunkNode, 1); + node->v = push_array_no_zero(arena, DASM_Inst, cap); + node->cap = cap; + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + } + MemoryCopyStruct(&node->v[node->count], inst); + node->count += 1; + list->inst_count += 1; +} + +internal DASM_InstArray +dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list) +{ + DASM_InstArray array = {0}; + array.count = list->inst_count; + array.v = push_array_no_zero(arena, DASM_Inst, array.count); + U64 idx = 0; + for(DASM_InstChunkNode *n = list->first; n != 0; n = n->next) + { + MemoryCopy(array.v+idx, n->v, sizeof(DASM_Inst)*n->count); + idx += n->count; + } + return array; +} + +internal U64 +dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off) +{ + U64 result = 0; + for(U64 idx = 0; idx < array->count; idx += 1) + { + if(array->v[idx].off == off) + { + result = idx; + break; + } + } + return result; +} + +internal U64 +dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx) +{ + U64 off = 0; + if(idx < array->count) + { + off = array->v[idx].off; + } + return off; +} + +//////////////////////////////// +//~ rjf: Disassembly Functions + +#include "third_party/udis86/config.h" +#include "third_party/udis86/udis86.h" +#include "third_party/udis86/libudis86/decode.c" +#include "third_party/udis86/libudis86/itab.c" +#include "third_party/udis86/libudis86/syn-att.c" +#include "third_party/udis86/libudis86/syn-intel.c" +#include "third_party/udis86/libudis86/syn.c" +#include "third_party/udis86/libudis86/udis86.c" + +internal DASM_InstChunkList +dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data) +{ + DASM_InstChunkList inst_list = {0}; + switch(arch) + { + default:{}break; + + //- rjf: x86/x64 decoding + case Architecture_x64: + case Architecture_x86: + { + // rjf: grab context + struct ud udc; + ud_init(&udc); + ud_set_mode(&udc, bit_size_from_arch(arch)); + ud_set_pc(&udc, addr); + ud_set_input_buffer(&udc, data.str, data.size); + ud_set_vendor(&udc, UD_VENDOR_ANY); + ud_set_syntax(&udc, UD_SYN_INTEL); + + // rjf: disassemble + U64 byte_process_start_off = 0; + for(U64 off = 0; off < data.size;) + { + // rjf: disassemble one instruction + U64 size = ud_disassemble(&udc); + if(size == 0) + { + break; + } + + // rjf: analyze + struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0); + U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0; + + // rjf: push + String8 string = push_str8f(arena, "%s", udc.asm_buf); + DASM_Inst inst = {string, off, rel_voff}; + dasm_inst_chunk_list_push(arena, &inst_list, 1024, &inst); + + // rjf: increment + off += size; + if(bytes_processed_counter != 0 && (off-byte_process_start_off >= 1000)) + { + ins_atomic_u64_add_eval(bytes_processed_counter, (off-byte_process_start_off)); + byte_process_start_off = off; + } + } + }break; + } + return inst_list; +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +//- rjf: opening handles & correllation with module + +internal DASM_Handle +dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range) +{ + DASM_Handle result = {0}; + if(machine != 0 && process.u64[0] != 0) + { + U64 hash = dasm_hash_from_string(str8_struct(&process)); + U64 slot_idx = hash%dasm_shared->entity_map.slots_count; + U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; + DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + DASM_Entity *entity = 0; + for(DASM_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->machine_id == machine && + ctrl_handle_match(e->process, process) && + MemoryMatchStruct(&e->vaddr_range, &vaddr_range)) + { + entity = e; + break; + } + } + if(entity == 0) + { + entity = push_array(stripe->arena, DASM_Entity, 1); + SLLQueuePush(slot->first, slot->last, entity); + entity->machine_id = machine; + entity->process = process; + entity->vaddr_range= vaddr_range; + entity->id = ins_atomic_u64_inc_eval(&dasm_shared->entity_id_gen); + entity->decode_inst_arena = arena_alloc__sized(MB(256), KB(64)); + entity->decode_string_arena = arena_alloc__sized(GB(1), KB(64)); + } + result.u64[0] = hash; + result.u64[1] = entity->id; + } + } + return result; +} + +//- rjf: asking for top-level info of a handle + +internal DASM_BinaryInfo +dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle) +{ + DASM_BinaryInfo info = {0}; + { + U64 hash = handle.u64[0]; + U64 id = handle.u64[1]; + U64 slot_idx = hash%dasm_shared->entity_map.slots_count; + U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; + DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + DASM_Entity *entity = 0; + for(DASM_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + info.machine_id = entity->machine_id; + info.process = entity->process; + info.vaddr_range = entity->vaddr_range; + info.bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed); + info.bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); + } + } + } + return info; +} + +//- rjf: asking for decoded instructions + +internal DASM_InstArray +dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us) +{ + DASM_InstArray result = {0}; + { + U64 hash = handle.u64[0]; + U64 id = handle.u64[1]; + U64 slot_idx = hash%dasm_shared->entity_map.slots_count; + U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; + DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; + B32 sent = 0; + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + DASM_Entity *entity = 0; + for(DASM_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + U64 last_time_sent_us = 0; + if(entity != 0) + { + U64 bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed); + U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); + last_time_sent_us = ins_atomic_u64_eval(&entity->last_time_sent_us); + if(bytes_processed == bytes_to_process && bytes_processed != 0) + { + result.count = entity->decode_inst_array.count; + result.v = push_array_no_zero(arena, DASM_Inst, result.count); + MemoryCopy(result.v, entity->decode_inst_array.v, sizeof(DASM_Inst)*result.count); + for(U64 idx = 0; idx < result.count; idx += 1) + { + result.v[idx].string = push_str8_copy(arena, result.v[idx].string); + } + break; + } + } + if(!sent && entity != 0 && last_time_sent_us+10000 <= os_now_microseconds()) + { + DASM_DecodeRequest req = {handle}; + sent = dasm_u2d_enqueue_request(&req, endt_us); + ins_atomic_u64_eval_assign(&entity->last_time_sent_us, os_now_microseconds()); + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Decode Threads + +internal B32 +dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us) +{ + B32 result = 0; + OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;) + { + U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos); + U64 available_size = (dasm_shared->u2d_ring_size-unconsumed_size); + if(available_size >= sizeof(*req)) + { + result = 1; + dasm_shared->u2d_ring_write_pos += ring_write_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_write_pos, req); + dasm_shared->u2d_ring_write_pos += 7; + dasm_shared->u2d_ring_write_pos -= dasm_shared->u2d_ring_write_pos%8; + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, endt_us); + } + if(result) + { + os_condition_variable_broadcast(dasm_shared->u2d_ring_cv); + } + return result; +} + +internal DASM_DecodeRequest +dasm_u2d_dequeue_request(void) +{ + DASM_DecodeRequest req = {0}; + OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;) + { + U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos); + if(unconsumed_size >= sizeof(DASM_DecodeRequest)) + { + dasm_shared->u2d_ring_read_pos += ring_read_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_read_pos, &req); + dasm_shared->u2d_ring_read_pos += 7; + dasm_shared->u2d_ring_read_pos -= dasm_shared->u2d_ring_read_pos%8; + break; + } + os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, max_U64); + } + os_condition_variable_broadcast(dasm_shared->u2d_ring_cv); + return req; +} + +internal void +dasm_decode_thread_entry_point(void *p) +{ + TCTX tctx_; + tctx_init_and_equip(&tctx_); + for(;;) + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: get next request & unpack + DASM_DecodeRequest req = dasm_u2d_dequeue_request(); + DASM_Handle handle = req.handle; + U64 hash = handle.u64[0]; + U64 id = handle.u64[1]; + U64 slot_idx = hash%dasm_shared->entity_map.slots_count; + U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; + DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; + + //- rjf: request -> ctrl info + B32 is_first_to_task = 0; + CTRL_MachineID ctrl_machine_id = 0; + CTRL_Handle ctrl_process = {0}; + Rng1U64 vaddr_range = {0}; + Architecture arch = Architecture_Null; + U64 *bytes_processed_counter = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + DASM_Entity *entity = 0; + for(DASM_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + U64 initial_working_count = ins_atomic_u32_eval_cond_assign(&entity->working_count, 1, 0); + if(initial_working_count == 0) + { + is_first_to_task = 1; + ctrl_machine_id = entity->machine_id; + ctrl_process = entity->process; + vaddr_range = entity->vaddr_range; + arch = ctrl_arch_from_handle(ctrl_machine_id, ctrl_process); + bytes_processed_counter = &entity->bytes_processed; + U64 bytes_to_process = dim_1u64(vaddr_range); + ins_atomic_u64_eval_assign(&entity->bytes_processed, 0); + ins_atomic_u64_eval_assign(&entity->bytes_to_process, bytes_to_process); + } + } + } + + //- rjf: bad handle or machine id -> bad task + B32 good_task = (is_first_to_task && ctrl_process.u64[0] != 0 && ctrl_machine_id != 0 && arch != Architecture_Null && bytes_processed_counter != 0); + + //- rjf: good task -> clear entity's info + if(good_task) + { + OS_MutexScopeW(stripe->rw_mutex) + { + DASM_Entity *entity = 0; + for(DASM_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + arena_clear(entity->decode_inst_arena); + arena_clear(entity->decode_string_arena); + MemoryZeroStruct(&entity->decode_inst_array); + } + } + } + + //- rjf: good task -> read process memory & decode instructions - stop each + // 4k and write into cache, so users can read incremental results + if(good_task) + { + U64 chunk_size = KB(4); + for(U64 off = 0; vaddr_range.min+off < vaddr_range.max; off += chunk_size) + { + Rng1U64 chunk_vaddr_range = r1u64(vaddr_range.min+off, vaddr_range.min+off+chunk_size); + chunk_vaddr_range.min = ClampTop(chunk_vaddr_range.min, vaddr_range.max); + chunk_vaddr_range.max = ClampTop(chunk_vaddr_range.max, vaddr_range.max); + + //- rjf: read next chunk & decode + String8 data = {0}; + DASM_InstChunkList inst_list = {0}; + if(good_task) + { + data.str = push_array_no_zero(scratch.arena, U8, dim_1u64(chunk_vaddr_range)); + data.size = ctrl_process_read(ctrl_machine_id, ctrl_process, chunk_vaddr_range, data.str); + if(data.size != 0) + { + inst_list = dasm_inst_chunk_list_from_arch_addr_data(scratch.arena, bytes_processed_counter, arch, chunk_vaddr_range.min, data); + } + } + + //- rjf: write into cache + { + OS_MutexScopeW(stripe->rw_mutex) + { + DASM_Entity *entity = 0; + for(DASM_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + DASM_Inst *new_chunk_base = push_array(entity->decode_inst_arena, DASM_Inst, inst_list.inst_count); + U64 off = 0; + for(DASM_InstChunkNode *node = inst_list.first; node != 0; node = node->next) + { + MemoryCopy(new_chunk_base+off, node->v, sizeof(DASM_Inst)*node->count); + off += node->count; + } + for(U64 idx = 0; idx < inst_list.inst_count; idx += 1) + { + new_chunk_base[idx].string = push_str8_copy(entity->decode_string_arena, new_chunk_base[idx].string); + } + entity->decode_inst_array.count += inst_list.inst_count; + if(entity->decode_inst_array.v == 0) + { + entity->decode_inst_array.v = new_chunk_base; + } + } + } + os_condition_variable_broadcast(stripe->cv); + } + } + } + + //- rjf: mark task as complete + if(good_task) + { + OS_MutexScopeR(stripe->rw_mutex) + { + DASM_Entity *entity = 0; + for(DASM_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); + ins_atomic_u64_eval_assign(&entity->bytes_processed, bytes_to_process); + ins_atomic_u64_eval_assign(&entity->working_count, 0); + } + } + } + + scratch_end(scratch); + } +} diff --git a/src/dasm/dasm.h b/src/dasm/dasm.h new file mode 100644 index 00000000..e8352ee0 --- /dev/null +++ b/src/dasm/dasm.h @@ -0,0 +1,206 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DASM_H +#define DASM_H + +//////////////////////////////// +//~ rjf: Handle Type + +typedef struct DASM_Handle DASM_Handle; +struct DASM_Handle +{ + U64 u64[2]; +}; + +//////////////////////////////// +//~ rjf: Instruction Types + +typedef struct DASM_Inst DASM_Inst; +struct DASM_Inst +{ + String8 string; + U64 off; + U64 addr; +}; + +typedef struct DASM_InstChunkNode DASM_InstChunkNode; +struct DASM_InstChunkNode +{ + DASM_InstChunkNode *next; + DASM_Inst *v; + U64 cap; + U64 count; +}; + +typedef struct DASM_InstChunkNode DASM_InstChunkNode; +struct DASM_InstChunkList +{ + DASM_InstChunkNode *first; + DASM_InstChunkNode *last; + U64 node_count; + U64 inst_count; +}; + +typedef struct DASM_InstArray DASM_InstArray; +struct DASM_InstArray +{ + DASM_Inst *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Striped Access Types + +typedef struct DASM_Stripe DASM_Stripe; +struct DASM_Stripe +{ + Arena *arena; + OS_Handle cv; + OS_Handle rw_mutex; +}; + +typedef struct DASM_StripeTable DASM_StripeTable; +struct DASM_StripeTable +{ + U64 count; + DASM_Stripe *v; +}; + +//////////////////////////////// +//~ rjf: Entity Cache Types + +typedef struct DASM_Entity DASM_Entity; +struct DASM_Entity +{ + DASM_Entity *next; + + // rjf: key info + CTRL_MachineID machine_id; + CTRL_Handle process; + Rng1U64 vaddr_range; + U64 id; + + // rjf: top-level info + U64 last_time_sent_us; + U64 working_count; + U64 bytes_processed; + U64 bytes_to_process; + + // rjf: decoded instruction data + Arena *decode_inst_arena; + Arena *decode_string_arena; + DASM_InstArray decode_inst_array; +}; + +typedef struct DASM_EntitySlot DASM_EntitySlot; +struct DASM_EntitySlot +{ + DASM_Entity *first; + DASM_Entity *last; +}; + +typedef struct DASM_EntityMap DASM_EntityMap; +struct DASM_EntityMap +{ + U64 slots_count; + DASM_EntitySlot *slots; +}; + +//////////////////////////////// +//~ rjf: Introspection Info Types + +typedef struct DASM_BinaryInfo DASM_BinaryInfo; +struct DASM_BinaryInfo +{ + CTRL_MachineID machine_id; + CTRL_Handle process; + Rng1U64 vaddr_range; + U64 bytes_processed; + U64 bytes_to_process; +}; + +//////////////////////////////// +//~ rjf: Decode Request Types + +typedef struct DASM_DecodeRequest DASM_DecodeRequest; +struct DASM_DecodeRequest +{ + DASM_Handle handle; +}; + +//////////////////////////////// +//~ rjf: Shared State + +typedef struct DASM_Shared DASM_Shared; +struct DASM_Shared +{ + Arena *arena; + + // rjf: entity table + DASM_EntityMap entity_map; + DASM_StripeTable entity_map_stripes; + U64 entity_id_gen; + + // rjf: user -> decode ring + OS_Handle u2d_ring_mutex; + OS_Handle u2d_ring_cv; + U64 u2d_ring_size; + U8 *u2d_ring_base; + U64 u2d_ring_write_pos; + U64 u2d_ring_read_pos; + + // rjf: decode threads + U64 decode_thread_count; + OS_Handle *decode_threads; +}; + +//////////////////////////////// +//~ rjf: Globals + +global DASM_Shared *dasm_shared = 0; + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void dasm_init(void); + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 dasm_hash_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Instruction Type Functions + +internal void dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst); +internal DASM_InstArray dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list); +internal U64 dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off); +internal U64 dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx); + +//////////////////////////////// +//~ rjf: Disassembly Functions + +internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data); + +//////////////////////////////// +//~ rjf: Cache Lookups + +//- rjf: opening handles & correllation with module +internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range); + +//- rjf: asking for top-level info of a handle +internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle); + +//- rjf: asking for decoded instructions +internal DASM_InstArray dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us); + +//////////////////////////////// +//~ rjf: Decode Threads + +internal B32 dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us); +internal DASM_DecodeRequest dasm_u2d_dequeue_request(void); + +internal void dasm_decode_thread_entry_point(void *p); + +#endif //DASM_H diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c new file mode 100644 index 00000000..99bcbef6 --- /dev/null +++ b/src/dbgi/dbgi.c @@ -0,0 +1,888 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +dbgi_init(void) +{ + Arena *arena = arena_alloc(); + dbgi_shared = push_array(arena, DBGI_Shared, 1); + dbgi_shared->arena = arena; + dbgi_shared->force_slots_count = 1024; + dbgi_shared->force_stripes_count = 64; + dbgi_shared->force_slots = push_array(arena, DBGI_ForceSlot, dbgi_shared->force_slots_count); + dbgi_shared->force_stripes = push_array(arena, DBGI_ForceStripe, dbgi_shared->force_stripes_count); + for(U64 idx = 0; idx < dbgi_shared->force_stripes_count; idx += 1) + { + dbgi_shared->force_stripes[idx].arena = arena_alloc(); + dbgi_shared->force_stripes[idx].rw_mutex = os_rw_mutex_alloc(); + dbgi_shared->force_stripes[idx].cv = os_condition_variable_alloc(); + } + dbgi_shared->binary_slots_count = 1024; + dbgi_shared->binary_stripes_count = 64; + dbgi_shared->binary_slots = push_array(arena, DBGI_BinarySlot, dbgi_shared->binary_slots_count); + dbgi_shared->binary_stripes = push_array(arena, DBGI_BinaryStripe, dbgi_shared->binary_stripes_count); + for(U64 idx = 0; idx < dbgi_shared->binary_stripes_count; idx += 1) + { + dbgi_shared->binary_stripes[idx].arena = arena_alloc(); + dbgi_shared->binary_stripes[idx].rw_mutex = os_rw_mutex_alloc(); + dbgi_shared->binary_stripes[idx].cv = os_condition_variable_alloc(); + } + dbgi_shared->u2p_ring_mutex = os_mutex_alloc(); + dbgi_shared->u2p_ring_cv = os_condition_variable_alloc(); + dbgi_shared->u2p_ring_size = KB(64); + dbgi_shared->u2p_ring_base = push_array_no_zero(arena, U8, dbgi_shared->u2p_ring_size); + dbgi_shared->p2u_ring_mutex = os_mutex_alloc(); + dbgi_shared->p2u_ring_cv = os_condition_variable_alloc(); + dbgi_shared->p2u_ring_size = KB(64); + dbgi_shared->p2u_ring_base = push_array_no_zero(arena, U8, dbgi_shared->p2u_ring_size); + dbgi_shared->parse_thread_count = Max(os_logical_core_count()-1, 1); + dbgi_shared->parse_threads = push_array(arena, OS_Handle, dbgi_shared->parse_thread_count); + for(U64 idx = 0; idx < dbgi_shared->parse_thread_count; idx += 1) + { + dbgi_shared->parse_threads[idx] = os_launch_thread(dbgi_parse_thread_entry_point, (void *)idx, 0); + } + dbgi_shared->evictor_thread = os_launch_thread(dbgi_evictor_thread_entry_point, 0, 0); +} + +//////////////////////////////// +//~ rjf: Thread-Context Idempotent Initialization + +internal void +dbgi_ensure_tctx_inited(void) +{ + if(dbgi_tctx == 0) + { + Arena *arena = arena_alloc(); + dbgi_tctx = push_array(arena, DBGI_ThreadCtx, 1); + dbgi_tctx->arena = arena; + } +} + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 +dbgi_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +//////////////////////////////// +//~ rjf: Forced Override Cache Functions + +internal void +dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path) +{ + U64 hash = dbgi_hash_from_string(exe_path); + U64 slot_idx = hash%dbgi_shared->force_slots_count; + U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; + DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; + DBGI_ForceStripe *stripe = &dbgi_shared->force_stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + DBGI_ForceNode *node = 0; + for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->exe_path, exe_path, 0)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(stripe->arena, DBGI_ForceNode, 1); + SLLQueuePush(slot->first, slot->first, node); + node->exe_path = push_str8_copy(stripe->arena, exe_path); + node->dbg_path_cap = 1024; + node->dbg_path_base = push_array_no_zero(stripe->arena, U8, node->dbg_path_cap); + } + String8 dbg_path_clamped = dbg_path; + dbg_path_clamped.size = Min(dbg_path_clamped.size, node->dbg_path_cap); + MemoryCopy(node->dbg_path_base, dbg_path_clamped.str, dbg_path_clamped.size); + node->dbg_path_size = dbg_path_clamped.size; + } +} + +internal String8 +dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path) +{ + String8 result = {0}; + U64 hash = dbgi_hash_from_string(exe_path); + U64 slot_idx = hash%dbgi_shared->force_slots_count; + U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; + DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; + DBGI_ForceStripe *stripe = &dbgi_shared->force_stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + DBGI_ForceNode *node = 0; + for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) + { + if(str8_match(exe_path, n->exe_path, 0)) + { + node = n; + break; + } + } + if(node != 0) + { + String8 dbg_path = str8(node->dbg_path_base, node->dbg_path_size); + result = push_str8_copy(arena, dbg_path); + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Scope Functions + +internal DBGI_Scope * +dbgi_scope_open(void) +{ + dbgi_ensure_tctx_inited(); + DBGI_Scope *scope = dbgi_tctx->free_scope; + if(scope != 0) + { + SLLStackPop(dbgi_tctx->free_scope); + MemoryZeroStruct(scope); + } + else + { + scope = push_array(dbgi_tctx->arena, DBGI_Scope, 1); + } + return scope; +} + +internal void +dbgi_scope_close(DBGI_Scope *scope) +{ + for(DBGI_TouchedBinary *tb = scope->first_tb, *next = 0; tb != 0; tb = next) + { + next = tb->next; + ins_atomic_u64_dec_eval(&tb->binary->scope_touch_count); + SLLStackPush(dbgi_tctx->free_tb, tb); + } + SLLStackPush(dbgi_tctx->free_scope, scope); +} + +internal void +dbgi_scope_touch_binary__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_Binary *binary) +{ + DBGI_TouchedBinary *tb = dbgi_tctx->free_tb; + ins_atomic_u64_inc_eval(&binary->scope_touch_count); + if(tb != 0) + { + SLLStackPop(dbgi_tctx->free_tb); + } + else + { + tb = push_array(dbgi_tctx->arena, DBGI_TouchedBinary, 1); + } + tb->binary = binary; + SLLQueuePush(scope->first_tb, scope->last_tb, tb); +} + +//////////////////////////////// +//~ rjf: Binary Cache Functions + +internal void +dbgi_binary_open(String8 exe_path) +{ + Temp scratch = scratch_begin(0, 0); + exe_path = path_normalized_from_string(scratch.arena, exe_path); + U64 hash = dbgi_hash_from_string(exe_path); + U64 slot_idx = hash%dbgi_shared->binary_slots_count; + U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; + DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; + DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; + B32 is_new = 0; + OS_MutexScopeW(stripe->rw_mutex) + { + DBGI_Binary *binary = 0; + for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0)) + { + binary = bin; + break; + } + } + if(binary == 0) + { + binary = push_array(stripe->arena, DBGI_Binary, 1); + SLLQueuePush(slot->first, slot->last, binary); + binary->exe_path = push_str8_copy(stripe->arena, exe_path); + binary->gen += 1; + } + binary->refcount += 1; + is_new = (binary->refcount == 1); + } + if(is_new) + { + dbgi_u2p_enqueue_exe_path(exe_path, 0); + } + scratch_end(scratch); +} + +internal void +dbgi_binary_close(String8 exe_path) +{ + Temp scratch = scratch_begin(0, 0); + exe_path = path_normalized_from_string(scratch.arena, exe_path); + U64 hash = dbgi_hash_from_string(exe_path); + U64 slot_idx = hash%dbgi_shared->binary_slots_count; + U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; + DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; + DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + DBGI_Binary *binary = 0; + for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0)) + { + binary = bin; + break; + } + } + if(binary != 0 && binary->refcount>0) + { + binary->refcount -= 1; + } + } + scratch_end(scratch); +} + +internal DBGI_Parse * +dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us) +{ + Temp scratch = scratch_begin(0, 0); + exe_path = path_normalized_from_string(scratch.arena, exe_path); + DBGI_Parse *parse = &dbgi_parse_nil; + { + U64 hash = dbgi_hash_from_string(exe_path); + U64 slot_idx = hash%dbgi_shared->binary_slots_count; + U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; + DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; + DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; + B32 sent = 0; + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + DBGI_Binary *binary = 0; + for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0)) + { + binary = bin; + break; + } + } + if(binary != 0 && !(binary->flags & DBGI_BinaryFlag_ParseInFlight)) + { + if(binary->parse.gen == binary->gen) + { + dbgi_scope_touch_binary__stripe_mutex_r_guarded(scope, binary); + parse = &binary->parse; + break; + } + else if(!sent && + os_now_microseconds() >= ins_atomic_u64_eval(&binary->last_time_enqueued_for_parse_us)+1000000 && + dbgi_u2p_enqueue_exe_path(exe_path, endt_us)) + { + sent = 1; + ins_atomic_u64_eval_assign(&binary->last_time_enqueued_for_parse_us, os_now_microseconds()); + } + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + } + scratch_end(scratch); + return parse; +} + +//////////////////////////////// +//~ rjf: Analysis Threads + +internal B32 +dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us) +{ + B32 sent = 0; + OS_MutexScope(dbgi_shared->u2p_ring_mutex) for(;;) + { + U64 unconsumed_size = (dbgi_shared->u2p_ring_write_pos-dbgi_shared->u2p_ring_read_pos); + U64 available_size = dbgi_shared->u2p_ring_size-unconsumed_size; + U64 needed_size = sizeof(U64)+exe_path.size; + needed_size += 7; + needed_size -= needed_size%8; + if(available_size >= needed_size) + { + dbgi_shared->u2p_ring_write_pos += ring_write_struct(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_write_pos, &exe_path.size); + dbgi_shared->u2p_ring_write_pos += ring_write(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_write_pos, exe_path.str, exe_path.size); + dbgi_shared->u2p_ring_write_pos += 7; + dbgi_shared->u2p_ring_write_pos -= dbgi_shared->u2p_ring_write_pos%8; + sent = 1; + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(dbgi_shared->u2p_ring_cv, dbgi_shared->u2p_ring_mutex, endt_us); + } + os_condition_variable_broadcast(dbgi_shared->u2p_ring_cv); + return sent; +} + +internal String8 +dbgi_u2p_dequeue_exe_path(Arena *arena) +{ + String8 result = {0}; + OS_MutexScope(dbgi_shared->u2p_ring_mutex) for(;;) + { + U64 unconsumed_size = (dbgi_shared->u2p_ring_write_pos-dbgi_shared->u2p_ring_read_pos); + if(unconsumed_size != 0) + { + dbgi_shared->u2p_ring_read_pos += ring_read_struct(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_read_pos, &result.size); + result.str = push_array_no_zero(arena, U8, result.size); + dbgi_shared->u2p_ring_read_pos += ring_read(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_read_pos, result.str, result.size); + dbgi_shared->u2p_ring_read_pos += 7; + dbgi_shared->u2p_ring_read_pos -= dbgi_shared->u2p_ring_read_pos%8; + break; + } + os_condition_variable_wait(dbgi_shared->u2p_ring_cv, dbgi_shared->u2p_ring_mutex, max_U64); + } + os_condition_variable_broadcast(dbgi_shared->u2p_ring_cv); + return result; +} + +internal void +dbgi_p2u_push_event(DBGI_Event *event) +{ + OS_MutexScope(dbgi_shared->p2u_ring_mutex) for(;;) + { + U64 unconsumed_size = (dbgi_shared->p2u_ring_write_pos-dbgi_shared->p2u_ring_read_pos); + U64 available_size = dbgi_shared->p2u_ring_size-unconsumed_size; + U64 needed_size = sizeof(DBGI_EventKind) + sizeof(U64) + event->string.size; + if(available_size >= needed_size) + { + dbgi_shared->p2u_ring_write_pos += ring_write_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, &event->kind); + dbgi_shared->p2u_ring_write_pos += ring_write_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, &event->string.size); + dbgi_shared->p2u_ring_write_pos += ring_write(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, event->string.str, event->string.size); + dbgi_shared->p2u_ring_write_pos += 7; + dbgi_shared->p2u_ring_write_pos -= dbgi_shared->p2u_ring_write_pos%8; + break; + } + os_condition_variable_wait(dbgi_shared->p2u_ring_cv, dbgi_shared->p2u_ring_mutex, max_U64); + } + os_condition_variable_broadcast(dbgi_shared->p2u_ring_cv); +} + +internal DBGI_EventList +dbgi_p2u_pop_events(Arena *arena, U64 endt_us) +{ + DBGI_EventList events = {0}; + OS_MutexScope(dbgi_shared->p2u_ring_mutex) for(;;) + { + U64 unconsumed_size = (dbgi_shared->p2u_ring_write_pos-dbgi_shared->p2u_ring_read_pos); + if(unconsumed_size >= sizeof(DBGI_EventKind) + sizeof(U64)) + { + DBGI_EventNode *n = push_array(arena, DBGI_EventNode, 1); + SLLQueuePush(events.first, events.last, n); + events.count += 1; + dbgi_shared->p2u_ring_read_pos += ring_read_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, &n->v.kind); + dbgi_shared->p2u_ring_read_pos += ring_read_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, &n->v.string.size); + n->v.string.str = push_array_no_zero(arena, U8, n->v.string.size); + dbgi_shared->p2u_ring_read_pos += ring_read(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); + dbgi_shared->p2u_ring_read_pos += 7; + dbgi_shared->p2u_ring_read_pos -= dbgi_shared->p2u_ring_read_pos%8; + } + else if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(dbgi_shared->p2u_ring_cv, dbgi_shared->p2u_ring_mutex, endt_us); + } + os_condition_variable_broadcast(dbgi_shared->p2u_ring_cv); + return events; +} + +internal void +dbgi_parse_thread_entry_point(void *p) +{ + TCTX tctx_; + tctx_init_and_equip(&tctx_); + ProfThreadName("[dbgi] parse #%I64U", (U64)p); + for(;;) + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: grab next path & unpack + String8 exe_path = dbgi_u2p_dequeue_exe_path(scratch.arena); + ProfBegin("begin task for \"%.*s\"", str8_varg(exe_path)); + U64 hash = dbgi_hash_from_string(exe_path); + U64 slot_idx = hash%dbgi_shared->binary_slots_count; + U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; + DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; + DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; + + //- rjf: determine if binary's analysis work is taken by another thread. + // if not, take it + B32 task_is_taken_by_other_thread = 0; + OS_MutexScopeW(stripe->rw_mutex) + { + DBGI_Binary *binary = 0; + for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0)) + { + binary = bin; + break; + } + } + if(binary == 0 || binary->flags&DBGI_BinaryFlag_ParseInFlight) + { + task_is_taken_by_other_thread = 1; + } + else if(binary != 0) + { + binary->flags |= DBGI_BinaryFlag_ParseInFlight; + } + } + + //- rjf: is the work taken? -> abort + B32 do_task = 1; + if(task_is_taken_by_other_thread) + { + do_task = 0; + } + + //- rjf: open exe file & map into address space + OS_Handle exe_file = {0}; + FileProperties exe_file_props = {0}; + OS_Handle exe_file_map = {0}; + void *exe_file_base = 0; + if(do_task) + { + exe_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, exe_path); + exe_file_props = os_properties_from_file(exe_file); + exe_file_map = os_file_map_open(OS_AccessFlag_Read, exe_file); + exe_file_base = os_file_map_view_open(exe_file_map, OS_AccessFlag_Read, r1u64(0, exe_file_props.size)); + } + + //- rjf: parse exe file info + Arena *parse_arena = 0; + PE_BinInfo exe_pe_info = {0}; + String8 exe_dbg_path_embedded = {0}; + if(do_task) + { + parse_arena = arena_alloc(); + if(exe_file_props.size >= 2 && *(U16 *)exe_file_base == PE_DOS_MAGIC) + { + String8 exe_data = str8((U8 *)exe_file_base, exe_file_props.size); + exe_pe_info = pe_bin_info_from_data(parse_arena, exe_data); + exe_dbg_path_embedded = str8_cstring_capped((char *)exe_data.str+exe_pe_info.dbg_path_off, (char *)exe_data.str+exe_pe_info.dbg_path_off+Min(exe_data.size-exe_pe_info.dbg_path_off, 4096)); + } + } + + //- rjf: determine O.G. (may or may not be RADDBG) dbg path + String8 og_dbg_path = {0}; + if(do_task) ProfScope("determine O.G. dbg path") + { + String8 forced_og_dbg_path = dbgi_forced_dbg_path_from_exe_path(scratch.arena, exe_path); + if(forced_og_dbg_path.size != 0) + { + og_dbg_path = forced_og_dbg_path; + } + else + { + String8 possible_og_dbg_paths[] = + { + /* inferred: */ exe_dbg_path_embedded, + /* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(exe_path)), + /* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", exe_path), + }; + for(U64 idx = 0; idx < ArrayCount(possible_og_dbg_paths); idx += 1) + { + FileProperties props = os_properties_from_file_path(possible_og_dbg_paths[idx]); + if(props.modified != 0 && props.size != 0) + { + og_dbg_path = possible_og_dbg_paths[idx]; + break; + } + } + } + } + + //- rjf: analyze O.G. dbg file + B32 og_dbg_format_is_known = 0; + B32 og_dbg_is_pe = 0; + B32 og_dbg_is_pdb = 0; + B32 og_dbg_is_elf = 0; + B32 og_dbg_is_raddbg = 0; + FileProperties og_dbg_props = {0}; + if(do_task) ProfScope("analyze O.G. dbg file") + { + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, og_dbg_path); + OS_Handle file_map = os_file_map_open(OS_AccessFlag_Read, file); + FileProperties props = og_dbg_props = os_properties_from_file(file); + void *base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, props.size)); + String8 data = str8((U8 *)base, props.size); + if(!og_dbg_format_is_known) + { + String8 msf20_magic = str8_lit("Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"); + String8 msf70_magic = str8_lit("Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"); + String8 msfxx_magic = str8_lit("Microsoft C/C++"); + if((data.size >= msf20_magic.size && str8_match(data, msf20_magic, StringMatchFlag_RightSideSloppy)) || + (data.size >= msf70_magic.size && str8_match(data, msf70_magic, StringMatchFlag_RightSideSloppy)) || + (data.size >= msfxx_magic.size && str8_match(data, msfxx_magic, StringMatchFlag_RightSideSloppy))) + { + og_dbg_format_is_known = 1; + og_dbg_is_pdb = 1; + } + } + if(!og_dbg_format_is_known) + { + if(data.size >= 8 && *(U64 *)data.str == RADDBG_MAGIC_CONSTANT) + { + og_dbg_format_is_known = 1; + og_dbg_is_raddbg = 1; + } + } + if(!og_dbg_format_is_known) + { + if(data.size >= 4 && + data.str[0] == 0x7f && + data.str[1] == 'E' && + data.str[2] == 'L' && + data.str[3] == 'F') + { + og_dbg_format_is_known = 1; + og_dbg_is_elf = 1; + } + } + if(!og_dbg_format_is_known) + { + if(data.size >= 2 && *(U16 *)data.str == PE_DOS_MAGIC) + { + og_dbg_format_is_known = 1; + og_dbg_is_pe = 1; + } + } + os_file_map_view_close(file_map, base); + os_file_map_close(file_map); + os_file_close(file); + } + + //- rjf: given O.G. path & analysis, determine RADDBG file path + String8 raddbg_path = {0}; + if(do_task) + { + if(og_dbg_is_raddbg) + { + raddbg_path = og_dbg_path; + } + else if(og_dbg_format_is_known && og_dbg_is_pdb) + { + raddbg_path = push_str8f(scratch.arena, "%S.raddbg", str8_chop_last_dot(og_dbg_path)); + } + } + + //- rjf: check if raddbg file is up-to-date + B32 raddbg_file_is_up_to_date = 0; + if(do_task) + { + if(raddbg_path.size != 0) + { + FileProperties props = os_properties_from_file_path(raddbg_path); + raddbg_file_is_up_to_date = (props.modified > og_dbg_props.modified); + } + } + + //- rjf: raddbg file not up-to-date? we need to generate it + if(do_task) + { + if(!raddbg_file_is_up_to_date) ProfScope("generate raddbg file") + { + if(og_dbg_is_pdb) + { + // rjf: push conversion task begin event + { + DBGI_Event event = {DBGI_EventKind_ConversionStarted}; + event.string = raddbg_path; + dbgi_p2u_push_event(&event); + } + + // rjf: kick off process + OS_Handle process = {0}; + { + OS_LaunchOptions opts = {0}; + opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); + opts.inherit_env = 1; + opts.consoleless = 1; + str8_list_pushf(scratch.arena, &opts.cmd_line, "raddbg"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--convert"); + //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--exe:%S", exe_path); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_dbg_path); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", raddbg_path); + os_launch_process(&opts, &process); + } + + // rjf: wait for process to complete + { + U64 start_wait_t = os_now_microseconds(); + for(;;) + { + B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); + if(wait_done) + { + raddbg_file_is_up_to_date = 1; + break; + } + if(os_now_microseconds()-start_wait_t > 10000000 && og_dbg_props.size < MB(64)) + { + os_graphical_message(1, str8_lit("RADDBG INTERNAL DEVELOPMENT MESSAGE"), str8_lit("this is taking a while... indicative of something that seemed like a bug that Jeff hit before. attach with debugger now & see where the callstack is?")); + } + } + } + + // rjf: push conversion task end event + { + DBGI_Event event = {DBGI_EventKind_ConversionEnded}; + event.string = raddbg_path; + dbgi_p2u_push_event(&event); + } + } + else + { + // NOTE(rjf): we cannot convert from this O.G. debug info format right now. + // rjf: push conversion task failure event + { + DBGI_Event event = {DBGI_EventKind_ConversionFailureUnsupportedFormat}; + event.string = raddbg_path; + dbgi_p2u_push_event(&event); + } + } + } + } + + //- rjf: open raddbg file & gather info + OS_Handle raddbg_file = {0}; + OS_Handle raddbg_file_map = {0}; + FileProperties raddbg_file_props = {0}; + void *raddbg_file_base = 0; + if(do_task && raddbg_file_is_up_to_date) + { + raddbg_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, raddbg_path); + raddbg_file_map = os_file_map_open(OS_AccessFlag_Read, raddbg_file); + raddbg_file_props = os_properties_from_file(raddbg_file); + raddbg_file_base = os_file_map_view_open(raddbg_file_map, OS_AccessFlag_Read, r1u64(0, raddbg_file_props.size)); + } + + //- rjf: cache write, step 0: busy-loop-wait for all scope touches to be done + if(do_task) ProfScope("cache write, step 0: busy-loop-wait for all scope touches to be done") + { + for(B32 done = 0; done == 0;) + { + OS_MutexScopeR(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0) && + bin->scope_touch_count == 0) + { + done = 1; + break; + } + } + } + } + + //- rjf: cache write, step 1: check if either EXE or raddbg file is new. if + // so, clear all old results & store new top-level info + B32 raddbg_or_exe_file_is_updated = 0; + if(do_task) ProfScope("cache write, step 1: check if raddbg is new & clear") + { + OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0)) + { + if(bin->parse.dbg_props.modified != raddbg_file_props.modified || + bin->parse.exe_props.modified != exe_file_props.modified) + { + raddbg_or_exe_file_is_updated = 1; + + // rjf: clean up old stuff + if(bin->parse.arena != 0) { arena_release(bin->parse.arena); } + if(bin->parse.exe_base != 0) {os_file_map_view_close(bin->exe_file_map, bin->parse.exe_base);} + if(!os_handle_match(os_handle_zero(), bin->exe_file_map)) {os_file_map_close(bin->exe_file_map);} + if(!os_handle_match(os_handle_zero(), bin->exe_file)) {os_file_close(bin->exe_file);} + if(bin->parse.dbg_base != 0) {os_file_map_view_close(bin->dbg_file_map, bin->parse.dbg_base);} + if(!os_handle_match(os_handle_zero(), bin->dbg_file_map)) {os_file_map_close(bin->dbg_file_map);} + if(!os_handle_match(os_handle_zero(), bin->dbg_file)) {os_file_close(bin->dbg_file);} + MemoryZeroStruct(&bin->parse); + bin->last_time_enqueued_for_parse_us = 0; + + // rjf: store new handles & props + bin->exe_file = exe_file; + bin->exe_file_map = exe_file_map; + bin->parse.exe_base = exe_file_base; + bin->parse.exe_props = exe_file_props; + bin->dbg_file = raddbg_file; + bin->dbg_file_map = raddbg_file_map; + bin->parse.dbg_base = raddbg_file_base; + bin->parse.dbg_props = raddbg_file_props; + bin->gen += 1; + } + break; + } + } + } + + //- rjf: raddbg file or exe is not new? cache can stay unmodified, close + // handles & skip to end. + if(do_task) if(!raddbg_or_exe_file_is_updated) if(raddbg_file_is_up_to_date) + { + os_file_map_view_close(raddbg_file_map, raddbg_file_base); + os_file_map_close(raddbg_file_map); + os_file_close(raddbg_file); + os_file_map_view_close(exe_file_map, exe_file_base); + os_file_map_close(exe_file_map); + os_file_close(exe_file); + do_task = 0; + } + + //- rjf: parse raddbg info + RADDBG_Parsed raddbg_parsed = {0}; + U64 arch_addr_size = 8; + if(do_task) + { + RADDBG_ParseStatus parse_status = raddbg_parse((U8 *)raddbg_file_base, raddbg_file_props.size, &raddbg_parsed); + if(raddbg_parsed.top_level_info != 0) + { + arch_addr_size = raddbg_addr_size_from_arch(raddbg_parsed.top_level_info->architecture); + } + } + + //- rjf: cache write, step 2: store parse artifacts + B32 parse_store_good = 0; + if(do_task) ProfScope("cache write, step 2: store parse") + { + OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0)) + { + String8 dbg_path = og_dbg_path; + if(dbg_path.size == 0) + { + dbg_path = exe_dbg_path_embedded; + } + if(dbg_path.size == 0) + { + dbg_path = push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(exe_path)); + } + parse_store_good = 1; + bin->parse.arena = parse_arena; + bin->parse.dbg_path = push_str8_copy(parse_arena, dbg_path); + MemoryCopyStruct(&bin->parse.pe, &exe_pe_info); + MemoryCopyStruct(&bin->parse.rdbg, &raddbg_parsed); + bin->parse.gen = bin->gen; + break; + } + } + } + + //- rjf: bad parse store? abort + if(do_task && !parse_store_good) + { + arena_release(parse_arena); + } + + //- rjf: cache write, step 3: mark binary work as complete + if(!task_is_taken_by_other_thread) ProfScope("cache write, step 4: mark binary work as complete") + { + OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(str8_match(bin->exe_path, exe_path, 0)) + { + bin->flags &= ~DBGI_BinaryFlag_ParseInFlight; + break; + } + } + os_condition_variable_broadcast(stripe->cv); + } + + ProfEnd(); + scratch_end(scratch); + } +} + +//////////////////////////////// +//~ rjf: Evictor Thread + +internal void +dbgi_evictor_thread_entry_point(void *p) +{ + TCTX tctx_; + tctx_init_and_equip(&tctx_); + ProfThreadName("[dbgi] evictor"); + for(;;) + { + ProfBegin("eviction scan"); + U64 slots_per_stripe = dbgi_shared->binary_slots_count/dbgi_shared->binary_stripes_count; + for(U64 stripe_idx = 0; stripe_idx < dbgi_shared->binary_stripes_count; stripe_idx += 1) + { + DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; + for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) + { + U64 slot_idx = slots_per_stripe*stripe_idx + slot_in_stripe_idx; + DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; + B32 slot_needs_work = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(bin->refcount == 0 && bin->scope_touch_count == 0 && bin->flags == 0 && bin->gen > 1) + { + slot_needs_work = 1; + break; + } + } + } + if(slot_needs_work) ProfScope("eviction task (slot %I64u)", slot_idx) OS_MutexScopeW(stripe->rw_mutex) + { + for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + { + if(bin->refcount == 0 && bin->scope_touch_count == 0 && bin->flags == 0) + { + if(bin->parse.arena != 0) { arena_release(bin->parse.arena); } + if(bin->parse.exe_base != 0) { os_file_map_view_close(bin->exe_file_map, bin->parse.exe_base); } + if(!os_handle_match(os_handle_zero(), bin->exe_file_map)) { os_file_map_close(bin->exe_file_map); } + if(!os_handle_match(os_handle_zero(), bin->exe_file)) { os_file_close(bin->exe_file); } + if(bin->parse.dbg_base != 0) { os_file_map_view_close(bin->dbg_file_map, bin->parse.dbg_base); } + if(!os_handle_match(os_handle_zero(), bin->dbg_file_map)) { os_file_map_close(bin->dbg_file_map); } + if(!os_handle_match(os_handle_zero(), bin->dbg_file)) { os_file_close(bin->dbg_file); } + bin->exe_file_map = bin->exe_file = os_handle_zero(); + bin->dbg_file_map = bin->dbg_file = os_handle_zero(); + MemoryZeroStruct(&bin->parse); + bin->last_time_enqueued_for_parse_us = 0; + bin->gen = 1; + } + } + } + } + } + ProfEnd(); + os_sleep_milliseconds(250); + } +} diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h new file mode 100644 index 00000000..9c9039cc --- /dev/null +++ b/src/dbgi/dbgi.h @@ -0,0 +1,262 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DBGI_H +#define DBGI_H + +//////////////////////////////// +//~ rjf: Info Bundle Types + +typedef struct DBGI_Parse DBGI_Parse; +struct DBGI_Parse +{ + U64 gen; + Arena *arena; + void *exe_base; + FileProperties exe_props; + String8 dbg_path; + void *dbg_base; + FileProperties dbg_props; + PE_BinInfo pe; + RADDBG_Parsed rdbg; +}; + +//////////////////////////////// +//~ rjf: Exe -> Debug Forced Override Cache Types + +typedef struct DBGI_ForceNode DBGI_ForceNode; +struct DBGI_ForceNode +{ + DBGI_ForceNode *next; + String8 exe_path; + U64 dbg_path_cap; + U64 dbg_path_size; + U8 *dbg_path_base; +}; + +typedef struct DBGI_ForceSlot DBGI_ForceSlot; +struct DBGI_ForceSlot +{ + DBGI_ForceNode *first; + DBGI_ForceNode *last; +}; + +typedef struct DBGI_ForceStripe DBGI_ForceStripe; +struct DBGI_ForceStripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Binary Cache State Types + +typedef U32 DBGI_BinaryFlags; +enum +{ + DBGI_BinaryFlag_ParseInFlight = (1<<0), +}; + +typedef struct DBGI_Binary DBGI_Binary; +struct DBGI_Binary +{ + // rjf: links & metadata + DBGI_Binary *next; + String8 exe_path; + U64 refcount; + U64 scope_touch_count; + U64 last_time_enqueued_for_parse_us; + DBGI_BinaryFlags flags; + U64 gen; + + // rjf: exe handles + OS_Handle exe_file; + OS_Handle exe_file_map; + + // rjf: debug handles + OS_Handle dbg_file; + OS_Handle dbg_file_map; + + // rjf: analysis results + DBGI_Parse parse; +}; + +typedef struct DBGI_BinarySlot DBGI_BinarySlot; +struct DBGI_BinarySlot +{ + DBGI_Binary *first; + DBGI_Binary *last; +}; + +typedef struct DBGI_BinaryStripe DBGI_BinaryStripe; +struct DBGI_BinaryStripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Weak Access Scope Types + +typedef struct DBGI_TouchedBinary DBGI_TouchedBinary; +struct DBGI_TouchedBinary +{ + DBGI_TouchedBinary *next; + DBGI_Binary *binary; +}; + +typedef struct DBGI_Scope DBGI_Scope; +struct DBGI_Scope +{ + DBGI_Scope *next; + DBGI_TouchedBinary *first_tb; + DBGI_TouchedBinary *last_tb; +}; + +typedef struct DBGI_ThreadCtx DBGI_ThreadCtx; +struct DBGI_ThreadCtx +{ + Arena *arena; + DBGI_Scope *free_scope; + DBGI_TouchedBinary *free_tb; +}; + +//////////////////////////////// +//~ rjf: Event Types + +typedef enum DBGI_EventKind +{ + DBGI_EventKind_Null, + DBGI_EventKind_ConversionStarted, + DBGI_EventKind_ConversionEnded, + DBGI_EventKind_ConversionFailureUnsupportedFormat, + DBGI_EventKind_COUNT +} +DBGI_EventKind; + +typedef struct DBGI_Event DBGI_Event; +struct DBGI_Event +{ + DBGI_EventKind kind; + String8 string; +}; + +typedef struct DBGI_EventNode DBGI_EventNode; +struct DBGI_EventNode +{ + DBGI_EventNode *next; + DBGI_Event v; +}; + +typedef struct DBGI_EventList DBGI_EventList; +struct DBGI_EventList +{ + DBGI_EventNode *first; + DBGI_EventNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Cross-Thread Shared State + +typedef struct DBGI_Shared DBGI_Shared; +struct DBGI_Shared +{ + // rjf: arena + Arena *arena; + + // rjf: forced override table + U64 force_slots_count; + U64 force_stripes_count; + DBGI_ForceSlot *force_slots; + DBGI_ForceStripe *force_stripes; + + // rjf: binary table + U64 binary_slots_count; + U64 binary_stripes_count; + DBGI_BinarySlot *binary_slots; + DBGI_BinaryStripe *binary_stripes; + + // rjf: user -> parse ring + OS_Handle u2p_ring_mutex; + OS_Handle u2p_ring_cv; + U64 u2p_ring_size; + U8 *u2p_ring_base; + U64 u2p_ring_write_pos; + U64 u2p_ring_read_pos; + + // rjf: parse -> user event ring + OS_Handle p2u_ring_mutex; + OS_Handle p2u_ring_cv; + U64 p2u_ring_size; + U8 *p2u_ring_base; + U64 p2u_ring_write_pos; + U64 p2u_ring_read_pos; + + // rjf: threads + U64 parse_thread_count; + OS_Handle *parse_threads; + OS_Handle evictor_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +global DBGI_Shared *dbgi_shared = 0; +thread_static DBGI_ThreadCtx *dbgi_tctx = 0; +global DBGI_Parse dbgi_parse_nil = {0}; + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void dbgi_init(void); + +//////////////////////////////// +//~ rjf: Thread-Context Idempotent Initialization + +internal void dbgi_ensure_tctx_inited(void); + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 dbgi_hash_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Forced Override Cache Functions + +internal void dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path); +internal String8 dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path); + +//////////////////////////////// +//~ rjf: Scope Functions + +internal DBGI_Scope *dbgi_scope_open(void); +internal void dbgi_scope_close(DBGI_Scope *scope); +internal void dbgi_scope_touch_binary__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_Binary *binary); + +//////////////////////////////// +//~ rjf: Binary Cache Functions + +internal void dbgi_binary_open(String8 exe_path); +internal void dbgi_binary_close(String8 exe_path); +internal DBGI_Parse *dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us); + +//////////////////////////////// +//~ rjf: Parse Threads + +internal B32 dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us); +internal String8 dbgi_u2p_dequeue_exe_path(Arena *arena); + +internal void dbgi_p2u_push_event(DBGI_Event *event); +internal DBGI_EventList dbgi_p2u_pop_events(Arena *arena, U64 endt_us); + +internal void dbgi_parse_thread_entry_point(void *p); + +//////////////////////////////// +//~ rjf: Evictor Thread + +internal void dbgi_evictor_thread_entry_point(void *p); + +#endif //DBGI_H diff --git a/src/demon/demon_accel.c b/src/demon/demon_accel.c new file mode 100644 index 00000000..2db93c6a --- /dev/null +++ b/src/demon/demon_accel.c @@ -0,0 +1,235 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//- allen: Acceleration Layer Functions + +//- accel helpers +internal DEMON_AccelModule* +demon_accel_module_alloc(void){ + DEMON_AccelModule *result = demon_free_module_accel; + if (result != 0){ + SLLStackPop(demon_free_module_accel); + } + else{ + result = push_array_no_zero(demon_ent_arena, DEMON_AccelModule, 1); + } + MemoryZeroStruct(result); + return(result); +} + +internal void +demon_accel_module_free(DEMON_AccelModule *module){ + SLLStackPush(demon_free_module_accel, module); +} + +internal DEMON_AccelThread* +demon_accel_thread_alloc(void){ + DEMON_AccelThread *result = demon_free_thread_accel; + if (result != 0){ + SLLStackPop(demon_free_thread_accel); + } + else{ + result = push_array_no_zero(demon_ent_arena, DEMON_AccelThread, 1); + } + MemoryZeroStruct(result); + return(result); +} + +internal void +demon_accel_thread_free(DEMON_AccelThread *thread){ + SLLStackPush(demon_free_thread_accel, thread); +} + +internal DEMON_AccelThread* +demon_accel_from_thread(DEMON_Entity *thread){ + DEMON_AccelThread *accel = (DEMON_AccelThread*)thread->accel; + if (accel == 0){ + accel = demon_accel_thread_alloc(); + thread->accel = accel; + } + return(accel); +} + +//- operations on demon objects +internal String8 +demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module){ + DEMON_AccelModule *accel = (DEMON_AccelModule*)module->accel; + + String8 result = {0}; + + // first time + if (accel == 0){ + result = demon_os_full_path_from_module(arena, module); + + // build chain + DEMON_AccelModule *last_accel = 0; + + U8 *ptr = result.str; + U8 *opl = result.str + result.size; + for (;ptr < opl;){ + U64 size = (U64)(ptr - opl); + U64 clamped_size = ClampTop(result.size, sizeof(Member(DEMON_AccelModule, buf))); + + DEMON_AccelModule *node = demon_accel_module_alloc(); + SLLQueuePush(accel, last_accel, node); + node->total_size = result.size; + MemoryCopy(node->buf, ptr, clamped_size); + + ptr += clamped_size; + } + + // store in module + module->accel = accel; + } + + // read from accel + else{ + U64 size = accel->total_size; + U8 *str = push_array_no_zero(arena, U8, size + 1); + + // copy chain contents to buffer + U8 *ptr = str; + for (DEMON_AccelModule *node = accel; + node != 0; + node = node->next){ + U64 total_size = node->total_size; + U64 clamped_size = ClampTop(total_size, sizeof(node->buf)); + MemoryCopy(ptr, node->buf, clamped_size); + ptr += clamped_size; + } + *ptr = 0; + + // fill result + result.str = str; + result.size = size; + } + + return(result); +} + +internal U64 +demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread){ + // get accel data + DEMON_AccelThread *accel = demon_accel_from_thread(thread); + + // fill stack base + if (!accel->has_stack_base){ + accel->has_stack_base = 1; + accel->stack_base = demon_os_stack_base_vaddr_from_thread(thread); + } + + return(accel->stack_base); +} + +internal U64 +demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread){ + // get accel data + DEMON_AccelThread *accel = demon_accel_from_thread(thread); + + // fill tls root + if (!accel->has_tls_root){ + accel->has_tls_root = 1; + accel->tls_root = demon_os_tls_root_vaddr_from_thread(thread); + } + + return(accel->tls_root); +} + +internal void* +demon_accel_read_regs(DEMON_Entity *thread){ + // get accel data + DEMON_AccelThread *accel = demon_accel_from_thread(thread); + + // update reg cache + if (accel->reg_cache_time != demon_time){ + accel->reg_cache_time = demon_time; + B32 success = 0; + switch (thread->arch){ + case Architecture_x86:{success = demon_os_read_regs_x86(thread, &accel->regs.x86);}break; + case Architecture_x64:{success = demon_os_read_regs_x64(thread, &accel->regs.x64);}break; + } + if (!success){ + MemoryZeroStruct(&accel->regs); + } + } + + return(&accel->regs); +} + +internal void +demon_accel_write_regs(DEMON_Entity *thread, void *data){ + // get accel data + DEMON_AccelThread *accel = demon_accel_from_thread(thread); + + // low level write + B32 success = 0; + U64 data_size = 0; + switch (thread->arch){ + case Architecture_x86: + { + data_size = sizeof(REGS_RegBlockX86); + success = demon_os_write_regs_x86(thread, (REGS_RegBlockX86*)data); + }break; + case Architecture_x64: + { + data_size = sizeof(REGS_RegBlockX64); + success = demon_os_write_regs_x64(thread, (REGS_RegBlockX64*)data); + }break; + } + + // update cache + if (success){ + accel->reg_cache_time = demon_time; + MemoryCopy(&accel->regs, data, data_size); + } +} + +internal void +demon_accel_low_level_write_regs(DEMON_Entity *thread){ + // NOTE(allen): This is a tricky one. It's just a way to enable some internal + // optimizations. Instead of forcing the user to pass in register data + // to write out and copy to the cache, the "user" is other demon code that + // knows what it's doing. So it grabs the cache memory (through a call to + // `demon_accel_read_regs`) modifies it in place and then calls this. + // So we just have to write the cache contents directly out to OS. + + // get accel data + DEMON_AccelThread *accel = demon_accel_from_thread(thread); + switch (thread->arch){ + case Architecture_x86: + { + demon_os_write_regs_x86(thread, &accel->regs.x86); + }break; + case Architecture_x64: + { + demon_os_write_regs_x64(thread, &accel->regs.x64); + }break; + } +} + + +//- entity accel free +internal void +demon_accel_free(DEMON_Entity *entity){ + switch (entity->kind){ + case DEMON_EntityKind_Module: + { + if (entity->accel != 0){ + for (DEMON_AccelModule *node = (DEMON_AccelModule*)entity->accel, *next = 0; + node != 0; + node = next){ + next = node->next; + demon_accel_module_free(node); + } + } + }break; + + case DEMON_EntityKind_Thread: + { + if (entity->accel != 0){ + demon_accel_thread_free((DEMON_AccelThread*)entity->accel); + } + }break; + } +} diff --git a/src/demon/demon_accel.h b/src/demon/demon_accel.h new file mode 100644 index 00000000..863f028d --- /dev/null +++ b/src/demon/demon_accel.h @@ -0,0 +1,66 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_ACCEL_H +#define DEMON_ACCEL_H + +//////////////////////////////// +//~ allen: Acceleration Data + +typedef struct DEMON_AccelModule DEMON_AccelModule; +struct DEMON_AccelModule +{ + DEMON_AccelModule *next; + U64 total_size; + U8 buf[240]; +}; + +typedef union DEMON_AccelThread DEMON_AccelThread; +union DEMON_AccelThread +{ + DEMON_AccelThread *next; + struct{ + B32 has_stack_base; + B32 has_tls_root; + U64 stack_base; + U64 tls_root; + + U64 reg_cache_time; + union{ + REGS_RegBlockX64 x64; + REGS_RegBlockX86 x86; + } regs; + }; +}; + +//////////////////////////////// +//~ allen: Acceleration Globals + +global DEMON_AccelModule *demon_free_module_accel = 0; +global DEMON_AccelThread *demon_free_thread_accel = 0; + +//////////////////////////////// +//~ allen: Acceleration Layer Functions + +//- accel helpers +internal DEMON_AccelModule *demon_accel_module_alloc(void); +internal void demon_accel_module_free(DEMON_AccelModule *module); + +internal DEMON_AccelThread *demon_accel_thread_alloc(void); +internal void demon_accel_thread_free(DEMON_AccelThread *thread); +internal DEMON_AccelThread *demon_accel_from_thread(DEMON_Entity *thread); + +//- operations on demon objects +internal String8 demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module); +internal U64 demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread); +internal U64 demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread); + +internal void* demon_accel_read_regs(DEMON_Entity *thread); +internal void demon_accel_write_regs(DEMON_Entity *thread, void *data); + +internal void demon_accel_low_level_write_regs(DEMON_Entity *thread); + +//- entity accel free +internal void demon_accel_free(DEMON_Entity *entity); + +#endif //DEMON_ACCEL_H diff --git a/src/demon/demon_common.c b/src/demon/demon_common.c new file mode 100644 index 00000000..15e7df8a --- /dev/null +++ b/src/demon/demon_common.c @@ -0,0 +1,270 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): State Safety Helper + +internal B32 +demon_access_begin(void){ + B32 result = 0; + if (demon_primary_thread){ + Assert(demon_run_state); + result = 1; + } + else{ + os_mutex_take(demon_state_mutex); + if (demon_run_state){ + os_mutex_drop(demon_state_mutex); + } + else{ + result = 1; + } + } + return(result); +} + +internal void +demon_access_end(void){ + if (!demon_primary_thread){ + os_mutex_drop(demon_state_mutex); + } +} + +//////////////////////////////// +// NOTE(allen): Entity System + +internal void +demon_common_init(void){ + // access control mechanism + demon_state_mutex = os_mutex_alloc(); + + // time + demon_time = 1; + + // setup arena + demon_ent_arena = arena_alloc(); + + // setup map + demon_ent_map = push_array(demon_ent_arena, DEMON_Map, 1); + demon_ent_map->bucket_count = 4093; + demon_ent_map->buckets = push_array(demon_ent_arena, DEMON_MapSlot*, demon_ent_map->bucket_count); + + // setup entity memory + U64 reserve_size_unaligned = (DEMON_ENTITY_CAP)*sizeof(DEMON_Entity); + U64 reserve_size = AlignPow2(reserve_size_unaligned, DEMON_ENTITY_CMT_SIZE); + demon_ent_cmt = demon_ent_pos = demon_ent_base = (DEMON_Entity*)os_reserve(reserve_size); + demon_ent_opl = demon_ent_base + (reserve_size/sizeof(DEMON_Entity)); + + Assert(demon_ent_base != 0); + + // setup root + demon_ent_root = demon_ent_alloc(); + demon_ent_root->kind = DEMON_EntityKind_Root; +} + +internal DEMON_Entity* +demon_ent_alloc(void){ + DEMON_Entity *result = demon_ent_free; + if (result != 0){ + SLLStackPop(demon_ent_free); + } + else{ + if (demon_ent_pos < demon_ent_opl){ + if (ensure_commit(&demon_ent_cmt, demon_ent_pos + 1, DEMON_ENTITY_CMT_SIZE)){ + result = demon_ent_pos; + demon_ent_pos += 1; + } + } + } + if (result != 0){ + U32 gen = result->gen; + MemoryZeroStruct(result); + result->gen = gen; + } + return(result); +} + +//- handle <-> entity pointer + +internal DEMON_Entity* +demon_ent_ptr_from_handle(DEMON_Handle handle){ + Assert(demon_ent_base != 0); + DEMON_Entity *result = 0; + U32 index = (U32)(handle & 0xFFFFFFFF); + U64 count = (U64)(demon_ent_pos - demon_ent_base); + if (0 < index && index < count){ + DEMON_Entity *entity = demon_ent_base + index; + U32 gen = (U32)(handle >> 32); + if (gen == entity->gen){ + result = entity; + } + } + return(result); +} + +internal DEMON_Handle +demon_ent_handle_from_ptr(DEMON_Entity *entity){ + Assert(demon_ent_base != 0); + DEMON_Handle result = {0}; + if (demon_ent_base < entity && entity < demon_ent_pos){ + U32 index = (U32)(entity - demon_ent_base); + U64 gen = entity->gen; + result = (gen << 32) | index; + } + return(result); +} + +//- high level entity alloc,init,release + +internal DEMON_Entity* +demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id){ + Assert(demon_ent_base != 0); + DEMON_Entity *result = demon_ent_alloc(); + if (result != 0){ + result->kind = kind; + result->id = id; + result->arch = parent->arch; + result->parent = parent; + DLLPushBack(parent->first, parent->last, result); + demon_ent_map_save(kind, id, result); + } + return(result); +} + +internal void +demon_ent_release_single(DEMON_Entity *entity){ + switch (entity->kind){ + case DEMON_EntityKind_Process: demon_proc_count -= 1; break; + case DEMON_EntityKind_Thread: demon_thread_count -= 1; break; + case DEMON_EntityKind_Module: demon_module_count -= 1; break; + } + demon_accel_free(entity); + demon_os_entity_cleanup(entity); + DEMON_MapRef ref = demon_ent_map_find(entity->kind, entity->id); + demon_ent_map_erase(ref); + entity->gen += 1; +} + +internal void +demon_ent_release_children(DEMON_Entity *root){ + Assert(demon_ent_base != 0); + if (root->first != 0){ + for (DEMON_Entity *node = root->first; + node != 0; + node = node->next){ + demon_ent_release_children(node); + demon_ent_release_single(node); + } + root->last->next = demon_ent_free; + demon_ent_free = root->first; + root->first = 0; + root->last = 0; + } +} + +internal void +demon_ent_release_root_and_children(DEMON_Entity *root){ + Assert(demon_ent_base != 0); + Assert(root->parent != 0); + + // release children + demon_ent_release_children(root); + + // release root + DEMON_Entity *parent = root->parent; + demon_ent_release_single(root); + DLLRemove(parent->first, parent->last, root); + SLLStackPush(demon_ent_free, root); +} + +//- entity map + +internal U64 +demon_ent_map_hash(U16 kind, U64 id){ + U64 result = ((U64)kind << 32) ^ id; + return(result); +} + +internal void +demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity){ + Assert(demon_ent_base != 0); + DEMON_Map *map = demon_ent_map; + + // allocate a new slot + DEMON_MapSlot *slot = map->free_slots; + if (slot != 0){ + SLLStackPop(map->free_slots); + } + else{ + slot = push_array_no_zero(demon_ent_arena, DEMON_MapSlot, 1); + } + + // fill slot + slot->kind = kind; + slot->id = id; + slot->entity = entity; + + // insert into bucket + U64 hash = demon_ent_map_hash(kind, id); + U64 bucket_index = hash%map->bucket_count; + SLLStackPush(map->buckets[bucket_index], slot); +} + +internal DEMON_MapRef +demon_ent_map_find(U16 kind, U64 id){ + Assert(demon_ent_base != 0); + DEMON_Map *map = demon_ent_map; + + // scan bucket + DEMON_MapRef result = {0}; + U64 hash = demon_ent_map_hash(kind, id); + U64 bucket_index = hash%map->bucket_count; + for (DEMON_MapSlot **ptr = &map->buckets[bucket_index], *slot = 0; + *ptr != 0; + ptr = &slot->next){ + slot = *ptr; + if (slot->kind == kind && slot->id == id){ + result.slot = slot; + result.ptr_to_slot = ptr; + break; + } + } + + return(result); +} + +internal DEMON_Entity* +demon_ent_map_entity_from_id(U16 kind, U64 id){ + DEMON_Entity *result = 0; + DEMON_MapRef ref = demon_ent_map_find(kind, id); + if (ref.slot != 0){ + result = ref.slot->entity; + } + return(result); +} + +internal void +demon_ent_map_erase(DEMON_MapRef ref){ + Assert(demon_ent_base != 0); + DEMON_Map *map = demon_ent_map; + + // move slot to free list + if (ref.slot != 0){ + *ref.ptr_to_slot = ref.slot->next; + SLLStackPush(map->free_slots, ref.slot); + } +} + +//////////////////////////////// +// NOTE(allen): Event Helpers + +internal DEMON_Event* +demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind){ + DEMON_EventNode *n = push_array(arena, DEMON_EventNode, 1); + DEMON_Event *result = &n->v; + SLLQueuePush(list->first, list->last, n); + list->count += 1; + result->kind = kind; + return(result); +} + diff --git a/src/demon/demon_common.h b/src/demon/demon_common.h new file mode 100644 index 00000000..4375f079 --- /dev/null +++ b/src/demon/demon_common.h @@ -0,0 +1,150 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_COMMON_H +#define DEMON_COMMON_H + +//////////////////////////////// +//~ allen: DEMON Entity System + +typedef enum DEMON_EntityKind +{ + DEMON_EntityKind_NULL, + + DEMON_EntityKind_Root, + DEMON_EntityKind_Process, + DEMON_EntityKind_Thread, + DEMON_EntityKind_Module, + + DEMON_EntityKind_COUNT +} +DEMON_EntityKind; + +typedef struct DEMON_Entity DEMON_Entity; +struct DEMON_Entity +{ + // TODO(allen): these could be U32s + DEMON_Entity *next; + DEMON_Entity *prev; + DEMON_Entity *parent; + DEMON_Entity *first; + DEMON_Entity *last; + + U16 kind; + U16 arch; + U32 gen; + U64 id; + U64 addr_range_dim; + + // each OS backend decides how to use `ext` for each entity kind + union{ + void *ext; + U64 ext_u64; + }; + + // the accel layer attaches some extra information to some entities + void *accel; +}; + +//- id -> entity map +typedef struct DEMON_MapSlot DEMON_MapSlot; +struct DEMON_MapSlot +{ + DEMON_MapSlot *next; + U16 kind; + U64 id; + DEMON_Entity *entity; +}; + +typedef struct DEMON_Map DEMON_Map; +struct DEMON_Map +{ + DEMON_MapSlot **buckets; + U64 bucket_count; + DEMON_MapSlot *free_slots; +}; + +typedef struct DEMON_MapRef DEMON_MapRef; +struct DEMON_MapRef +{ + DEMON_MapSlot *slot; + DEMON_MapSlot **ptr_to_slot; +}; + +//- rjf: entity extrusive list + +typedef struct DEMON_EntityNode DEMON_EntityNode; +struct DEMON_EntityNode +{ + DEMON_EntityNode *next; + DEMON_Entity *entity; +}; + +//////////////////////////////// +//~ allen: Demon Globals + +thread_static B32 demon_primary_thread = 0; +global B32 demon_run_state = 0; +global OS_Handle demon_state_mutex = {0}; + +global U64 demon_time = 0; + +global Arena *demon_ent_arena = 0; +global DEMON_Map *demon_ent_map = 0; + +global DEMON_Entity *demon_ent_free = 0; +global DEMON_Entity *demon_ent_root = 0; + +global DEMON_Entity *demon_ent_base = 0; +global DEMON_Entity *demon_ent_pos = 0; +global DEMON_Entity *demon_ent_opl = 0; +global void *demon_ent_cmt = 0; + +global U64 demon_proc_count = 0; +global U64 demon_thread_count = 0; +global U64 demon_module_count = 0; + +#if !defined(DEMON_ENTITY_CMT_SIZE) +# define DEMON_ENTITY_CMT_SIZE KB(64) +#endif +#if !defined(DEMON_ENTITY_CAP) +# define DEMON_ENTITY_CAP 65536 +#endif + +StaticAssert(IsPow2(DEMON_ENTITY_CMT_SIZE), check_demon_entity_cmt_size); + +//////////////////////////////// +//~ allen: State Safety Helper + +internal B32 demon_access_begin(void); +internal void demon_access_end(void); + +//////////////////////////////// +//~ allen: Entity System + +internal void demon_common_init(void); +internal DEMON_Entity* demon_ent_alloc(void); + +//- handle <-> entity pointer +internal DEMON_Entity* demon_ent_ptr_from_handle(DEMON_Handle handle); +internal DEMON_Handle demon_ent_handle_from_ptr(DEMON_Entity *entity); + +//- high level entity alloc,init,release +internal DEMON_Entity* demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id); +internal void demon_ent_release_single(DEMON_Entity *entity); +internal void demon_ent_release_children(DEMON_Entity *root); +internal void demon_ent_release_root_and_children(DEMON_Entity *root); + +//- entity map +internal U64 demon_ent_map_hash(U16 kind, U64 id); +internal void demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity); +internal DEMON_MapRef demon_ent_map_find(U16 kind, U64 id); +internal DEMON_Entity* demon_ent_map_entity_from_id(U16 kind, U64 id); +internal void demon_ent_map_erase(DEMON_MapRef map_ref); + +//////////////////////////////// +//~ allen: Event Helpers + +internal DEMON_Event* demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind); + +#endif //DEMON_COMMON_H diff --git a/src/demon/demon_core.c b/src/demon/demon_core.c new file mode 100644 index 00000000..43077629 --- /dev/null +++ b/src/demon/demon_core.c @@ -0,0 +1,871 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +demon_init(void){ + demon_common_init(); + demon_os_init(); +} + +//////////////////////////////// +//~ rjf: Basic Type Functions + +//- rjf: stringizing + +internal String8 +demon_string_from_event_kind(DEMON_EventKind kind){ + String8 result = str8_lit("unknown"); + switch (kind){ + default: break; + case DEMON_EventKind_Error: result = str8_lit("Error"); break; + case DEMON_EventKind_HandshakeComplete: result = str8_lit("HandshakeComplete"); break; + case DEMON_EventKind_CreateProcess: result = str8_lit("CreateProcess"); break; + case DEMON_EventKind_ExitProcess: result = str8_lit("ExitProcess"); break; + case DEMON_EventKind_CreateThread: result = str8_lit("CreateThread"); break; + case DEMON_EventKind_ExitThread: result = str8_lit("ExitThread"); break; + case DEMON_EventKind_LoadModule: result = str8_lit("LoadModule"); break; + case DEMON_EventKind_UnloadModule: result = str8_lit("UnloadModule"); break; + case DEMON_EventKind_Breakpoint: result = str8_lit("Breakpoint"); break; + case DEMON_EventKind_Trap: result = str8_lit("Trap"); break; + case DEMON_EventKind_SingleStep: result = str8_lit("SingleStep"); break; + case DEMON_EventKind_Exception: result = str8_lit("Exception"); break; + case DEMON_EventKind_Halt: result = str8_lit("Halt"); break; + case DEMON_EventKind_Memory: result = str8_lit("Memory"); break; + case DEMON_EventKind_DebugString: result = str8_lit("DebugString"); break; + case DEMON_EventKind_SetThreadName: result = str8_lit("SetThreadName"); break; + } + return(result); +} + +internal String8 +demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind){ + String8 result = str8_lit("unknown"); + switch (kind){ + default: break; + case DEMON_MemoryEventKind_Commit: result = str8_lit("Commit"); break; + case DEMON_MemoryEventKind_Reserve: result = str8_lit("Reserve"); break; + case DEMON_MemoryEventKind_Decommit: result = str8_lit("Decommit"); break; + case DEMON_MemoryEventKind_Release: result = str8_lit("Release"); break; + } + return(result); +} + +internal String8 +demon_string_from_exception_kind(DEMON_ExceptionKind kind){ + String8 result = str8_lit("unknown"); + switch (kind){ + default: break; + case DEMON_ExceptionKind_MemoryRead: result = str8_lit("MemoryRead"); break; + case DEMON_ExceptionKind_MemoryWrite: result = str8_lit("MemoryWrite"); break; + case DEMON_ExceptionKind_MemoryExecute: result = str8_lit("MemoryExecute"); break; + case DEMON_ExceptionKind_CppThrow: result = str8_lit("CppThrow"); break; + } + return(result); +} + +internal void +demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event){ + B32 need_exception_info = (event->kind == DEMON_EventKind_Exception || + event->kind == DEMON_EventKind_Breakpoint || + event->kind == DEMON_EventKind_Halt || + event->kind == DEMON_EventKind_SingleStep); + + // allen: kind + String8 kind_string = demon_string_from_event_kind(event->kind); + str8_list_pushf(arena, out, "%S: { (%i)", kind_string, event->kind); + + // rjf: basics + { + str8_list_pushf(arena, out, " process: (%I64x)", event->process); + str8_list_pushf(arena, out, " thread: (%I64x)", event->thread); + str8_list_pushf(arena, out, " module: (%I64x)", event->module); + str8_list_pushf(arena, out, " address: (%I64x)", event->address, event->address); + str8_list_pushf(arena, out, " size: (0x%I64x, %I64u)", event->size, event->size); + } + + // rjf: string + if (event->string.size != 0){ + str8_list_pushf(arena, out, " string: \"%S\"", event->string); + } + + // rjf: exception info + if (need_exception_info){ + str8_list_pushf(arena, out, " code: (0x%x, %i)", event->code, event->code); + str8_list_pushf(arena, out, " flags: (0x%x, %i)", event->flags, event->flags); + str8_list_pushf(arena, out, " signo: (0x%x, %i)", event->signo, event->signo); + str8_list_pushf(arena, out, " sigcode: (0x%x, %i)", event->sigcode, event->sigcode); + } + + // rjf: need error info + if (event->kind == DEMON_EventKind_Error){ + str8_list_pushf(arena, out, " error_kind: (0x%x, %i)", event->error_kind, event->error_kind); + } + + // rjf: memory event kind info + if (event->memory_kind != DEMON_MemoryEventKind_Null){ + String8 memory_kind_string = demon_string_from_memory_event_kind(event->memory_kind); + str8_list_pushf(arena, out, " memory_kind: (%S, %i)", + memory_kind_string, event->memory_kind); + } + + // rjf: exception kind + if (need_exception_info){ + String8 exception_kind_string = demon_string_from_exception_kind(event->exception_kind); + str8_list_pushf(arena, out, " exception_kind: (%S, %i)", + exception_kind_string, event->exception_kind); + } + + // rjf: instruction ptr + if (event->instruction_pointer != 0){ + str8_list_pushf(arena, out, " instruction_pointer: (%I64x)", event->instruction_pointer); + } + + // rjf: stack ptr + if (event->stack_pointer != 0){ + str8_list_pushf(arena, out, " stack_pointer: (%I64x)", event->stack_pointer); + } + + str8_list_pushf(arena, out, " user_data: (0x%I64x, %I64u)", + event->user_data, event->user_data); + str8_list_pushf(arena, out, "}"); +} + +//- rjf: trap chunk lists + +internal void +demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap) +{ + DEMON_TrapChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, DEMON_TrapChunkNode, 1); + node->cap = cap; + node->v = push_array_no_zero(arena, DEMON_Trap, node->cap); + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + } + MemoryCopyStruct(&node->v[node->count], trap); + node->count += 1; + list->trap_count += 1; +} + +internal void +demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push) +{ + if(dst->last == 0) + { + MemoryCopyStruct(dst, to_push); + } + else if(to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->node_count += to_push->node_count; + dst->trap_count += to_push->trap_count; + } + MemoryZeroStruct(to_push); +} + +internal void +demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push) +{ + for(DEMON_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next) + { + DEMON_TrapChunkNode *dst_n = push_array(arena, DEMON_TrapChunkNode, 1); + dst_n->v = src_n->v; + dst_n->cap = src_n->cap; + dst_n->count = src_n->count; + SLLQueuePush(dst->first, dst->last, dst_n); + dst->node_count += 1; + dst->trap_count += dst_n->count; + } +} + +//- rjf: handle lists + +internal void +demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle) +{ + DEMON_HandleNode *node = push_array(arena, DEMON_HandleNode, 1); + SLLQueuePush(list->first, list->last, node); + node->v = handle; + list->count += 1; +} + +internal DEMON_HandleArray +demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list) +{ + DEMON_HandleArray array = {0}; + array.count = list->count; + array.handles = push_array_no_zero(arena, DEMON_Handle, array.count); + U64 idx = 0; + for(DEMON_HandleNode *n = list->first; n != 0; n = n->next, idx += 1) + { + array.handles[idx] = n->v; + } + return array; +} + +internal DEMON_HandleArray +demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src) +{ + DEMON_HandleArray dst = {0}; + dst.count = src->count; + dst.handles = push_array_no_zero(arena, DEMON_Handle, dst.count); + MemoryCopy(dst.handles, src->handles, sizeof(DEMON_Handle)*dst.count); + return dst; +} + +//////////////////////////////// +//~ rjf: Primary Thread & Exclusive Mode Controls + +internal void +demon_primary_thread_begin(void){ + demon_primary_thread = 1; +} + +internal void +demon_exclusive_mode_begin(void){ + Assert(demon_primary_thread); + os_mutex_take(demon_state_mutex); + demon_run_state = 1; + os_mutex_drop(demon_state_mutex); +} + +internal void +demon_exclusive_mode_end(void){ + Assert(demon_primary_thread); + os_mutex_take(demon_state_mutex); + demon_run_state = 0; + os_mutex_drop(demon_state_mutex); +} + +//////////////////////////////// +//~ rjf: Running/Halting + +internal DEMON_EventList +demon_run(Arena *arena, DEMON_RunCtrls *ctrls) +{ + Assert(demon_primary_thread); + Temp scratch = scratch_begin(&arena, 1); + + // convert controls to os controls + B32 full_conversion = 1; + DEMON_OS_RunCtrls os_ctrls = {0}; + { + // convert single_step_thread + if (ctrls->single_step_thread != 0){ + DEMON_Entity *sst_entity = demon_ent_ptr_from_handle(ctrls->single_step_thread); + if (sst_entity != 0 && + sst_entity->kind == DEMON_EntityKind_Thread){ + os_ctrls.single_step_thread = sst_entity; + } + else{ + full_conversion = 0; + goto finish_conversion; + } + } + + // convert exception handling flag + os_ctrls.ignore_previous_exception = ctrls->ignore_previous_exception; + + // convert fronzen threads + os_ctrls.run_entities_are_unfrozen = ctrls->run_entities_are_unfrozen; + os_ctrls.run_entities_are_processes = ctrls->run_entities_are_processes; + os_ctrls.run_entity_count = ctrls->run_entity_count; + os_ctrls.run_entities = push_array_no_zero(scratch.arena, DEMON_Entity*, ctrls->run_entity_count); + { + DEMON_EntityKind expected_entity_kind = DEMON_EntityKind_Thread; + if (os_ctrls.run_entities_are_processes){ + expected_entity_kind = DEMON_EntityKind_Process; + } + + DEMON_Handle *src = ctrls->run_entities; + DEMON_Entity **dst = os_ctrls.run_entities; + for (U64 i = 0; i < ctrls->run_entity_count; i += 1, src += 1, dst += 1){ + DEMON_Entity *frozen_thread = demon_ent_ptr_from_handle(*src); + if (frozen_thread != 0 && + frozen_thread->kind == expected_entity_kind){ + *dst = frozen_thread; + } + else{ + full_conversion = 0; + goto finish_conversion; + } + } + } + + // convert traps + os_ctrls.traps = push_array_no_zero(scratch.arena, DEMON_OS_Trap, ctrls->traps.trap_count); + { + DEMON_OS_Trap *dst = os_ctrls.traps; + + for (DEMON_TrapChunkNode *node = ctrls->traps.first; + node != 0; + node = node->next){ + DEMON_Trap *src = node->v; + U64 node_trap_count = node->count; + for (U64 i = 0; i < node_trap_count; i += 1, src += 1){ + if (src->process != 0){ + DEMON_Entity *trap_process = demon_ent_ptr_from_handle(src->process); + if (trap_process != 0 && + trap_process->kind == DEMON_EntityKind_Process){ + dst->process = trap_process; + dst->address = src->address; + dst += 1; + } + else{ + full_conversion = 0; + goto finish_conversion; + } + } + } + } + + os_ctrls.trap_count = (U64)(dst - os_ctrls.traps); + } + + finish_conversion:; + } + + // call the OS implementation of run + DEMON_EventList result = {0}; + if (full_conversion){ + result = demon_os_run(arena, &os_ctrls); + } + else{ + DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error); + event->error_kind = DEMON_ErrorKind_InvalidHandle; + } + + scratch_end(scratch); + return(result); +} + +internal void +demon_halt(U64 code, U64 user_data){ + demon_os_halt(code, user_data); +} + +internal U64 +demon_get_time_counter(void){ + return(demon_time); +} + +//////////////////////////////// +//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting + +internal U32 +demon_launch_process(OS_LaunchOptions *options){ + Assert(demon_primary_thread); + U32 result = demon_os_launch_process(options); + return(result); +} + +internal B32 +demon_attach_process(U32 pid){ + Assert(demon_primary_thread); + B32 result = demon_os_attach_process(pid); + return(result); +} + +internal B32 +demon_kill_process(DEMON_Handle process, U32 exit_code){ + Assert(demon_primary_thread); + B32 result = 0; + DEMON_Entity *entity = demon_ent_ptr_from_handle(process); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Process){ + result = demon_os_kill_process(entity, exit_code); + } + return(result); +} + +internal B32 +demon_detach_process(DEMON_Handle process){ + Assert(demon_primary_thread); + B32 result = 0; + DEMON_Entity *entity = demon_ent_ptr_from_handle(process); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Process){ + result = demon_os_detach_process(entity); + } + return(result); +} + +//////////////////////////////// +//~ rjf: Entity Functions + +//- rjf: basics + +internal B32 +demon_object_exists(DEMON_Handle object){ + B32 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(object); + result = (entity != 0); + demon_access_end(); + } + return(result); +} + +//- rjf: introspection + +internal Architecture +demon_arch_from_object(DEMON_Handle object){ + Architecture result = Architecture_Null; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(object); + if (entity != 0){ + result = (Architecture)entity->arch; + } + demon_access_end(); + } + return(result); +} + +internal U64 +demon_base_vaddr_from_module(DEMON_Handle module){ + U64 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(module); + if (entity != 0 && entity->kind == DEMON_EntityKind_Module){ + result = entity->id; + } + demon_access_end(); + } + return(result); +} + +internal Rng1U64 +demon_vaddr_range_from_module(DEMON_Handle module) +{ + Rng1U64 result = {0}; + if(demon_access_begin()) + { + DEMON_Entity *entity = demon_ent_ptr_from_handle(module); + if(entity != 0 && entity->kind == DEMON_EntityKind_Module) + { + result = r1u64(entity->id, entity->id+entity->addr_range_dim); + } + demon_access_end(); + } + return(result); +} + +internal String8 +demon_full_path_from_module(Arena *arena, DEMON_Handle module){ + String8 result = {0}; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(module); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Module){ + result = demon_accel_full_path_from_module(arena, entity); + } + demon_access_end(); + } + return(result); +} + +internal U64 +demon_stack_base_vaddr_from_thread(DEMON_Handle thread){ + U64 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); + if (entity != 0 && entity->kind == DEMON_EntityKind_Thread){ + result = demon_accel_stack_base_vaddr_from_thread(entity); + } + demon_access_end(); + } + return(result); +} + +internal U64 +demon_tls_root_vaddr_from_thread(DEMON_Handle handle){ + U64 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(handle); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Thread){ + result = demon_accel_tls_root_vaddr_from_thread(entity); + } + demon_access_end(); + } + return(result); +} + +internal DEMON_HandleArray +demon_all_processes(Arena *arena){ + DEMON_HandleArray result = {0}; + + if (demon_access_begin()){ + DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_proc_count); + DEMON_Handle *handle_opl = handles + demon_proc_count; + DEMON_Handle *handle_ptr = handles; + + for (DEMON_Entity *process = demon_ent_root->first; + process != 0 && handle_ptr < handle_opl; + process = process->next){ + if (process->kind == DEMON_EntityKind_Process){ + *handle_ptr = demon_ent_handle_from_ptr(process); + handle_ptr += 1; + } + } + + result.handles = handles; + result.count = (U64)(handle_ptr - handles); + + U64 unused_count = demon_proc_count - result.count; + arena_put_back(arena, sizeof(DEMON_Handle)*unused_count); + demon_access_end(); + } + + return(result); +} + +internal DEMON_HandleArray +demon_threads_from_process(Arena *arena, DEMON_Handle process){ + DEMON_HandleArray result = {0}; + + if (demon_access_begin()){ + DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_thread_count); + DEMON_Handle *handle_opl = handles + demon_thread_count; + DEMON_Handle *handle_ptr = handles; + + DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process); + + if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){ + for (DEMON_Entity *thread = process_ptr->first; + thread != 0 && handle_ptr < handle_opl; + thread = thread->next){ + if (thread->kind == DEMON_EntityKind_Thread){ + *handle_ptr = demon_ent_handle_from_ptr(thread); + handle_ptr += 1; + } + } + } + + result.handles = handles; + result.count = (U64)(handle_ptr - handles); + + U64 unused_count = demon_thread_count - result.count; + arena_put_back(arena, sizeof(DEMON_Handle)*unused_count); + demon_access_end(); + } + + return(result); +} + +internal DEMON_HandleArray +demon_modules_from_process(Arena *arena, DEMON_Handle process){ + DEMON_HandleArray result = {0}; + + if (demon_access_begin()){ + DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_module_count); + DEMON_Handle *handle_opl = handles + demon_module_count; + DEMON_Handle *handle_ptr = handles; + + DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process); + + if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){ + for (DEMON_Entity *module = process_ptr->first; + module != 0 && handle_ptr < handle_opl; + module = module->next){ + if (module->kind == DEMON_EntityKind_Module){ + *handle_ptr = demon_ent_handle_from_ptr(module); + handle_ptr += 1; + } + } + } + + result.handles = handles; + result.count = (U64)(handle_ptr - handles); + + U64 unused_count = demon_module_count - result.count; + arena_put_back(arena, sizeof(DEMON_Handle)*unused_count); + demon_access_end(); + } + + return(result); +} + +//- rjf: target process memory allocation/protection + +internal U64 +demon_reserve_memory(DEMON_Handle process, U64 size){ + U64 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(process); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Process){ + result = demon_os_reserve_memory(entity, size); + } + demon_access_end(); + } + return(result); +} + +internal B32 +demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags){ + B32 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(process); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Process){ + demon_os_set_memory_protect_flags(entity, page_vaddr, size, flags); + result = 1; + } + demon_access_end(); + } + return(result); +} + +internal B32 +demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size){ + B32 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(process); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Process){ + demon_os_release_memory(entity, vaddr, size); + result = 1; + } + demon_access_end(); + } + return(result); +} + +//- rjf: target process memory reading/writing + +internal U64 +demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size){ + U64 bytes_read = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(process); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Process){ + bytes_read = demon_os_read_memory(entity, dst, src_address, size); + } + demon_access_end(); + } + return(bytes_read); +} + +internal B32 +demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size){ + B32 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(process); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Process){ + result = demon_os_write_memory(entity, dst_address, src, size); + } + demon_access_end(); + } + return(result); +} + +#define READ_BLOCK_SIZE 4096 + +internal U64 +demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size){ + // Algorithm: + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // ^ ^ ^ + // MIN MAX SMAX + // [MIN,MAX) - range attempting to read + // [MAX,SMAX) - range not yet proven to be impossible to read + + Assert(src_address%READ_BLOCK_SIZE == 0); + Assert(size%READ_BLOCK_SIZE == 0); + + U64 read_size = 0; + U64 min = 0; + U64 max = size; + U64 smax = max; + + for (;;){ + if (max <= min){ + break; + } + + // attempt to read range + U64 attempt_size = max - min; + B32 success = demon_read_memory(process, (U8*)dst + min, src_address + min, attempt_size); + + if (success){ + // increase successful read size + read_size += attempt_size; + // adjust range up + min = max; + max = smax; + } + else{ + // mark this point as too far + smax = max - READ_BLOCK_SIZE; + // bisect the range for the next read attempt + U64 mid = (min + max)/2; + U64 aligned_mid = AlignDownPow2(mid, READ_BLOCK_SIZE); + max = aligned_mid; + } + } + + U64 result = read_size; + return(result); +} + +internal U64 +demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size){ + U64 read_size = 0; + + if (demon_access_begin()){ + B32 done = 0; + U64 read_opl = src_address + size; + + // pre-aligned part -- [SRC,PRE_OPL) + U64 src_block_opl = AlignPow2(src_address, READ_BLOCK_SIZE); + U64 pre_opl = Min(src_block_opl, read_opl); + if(src_address < pre_opl) + { + U64 attempt_size = pre_opl - src_address; + if(!demon_read_memory(process, dst, src_address, attempt_size)) + { + done = 1; + } + else + { + read_size += attempt_size; + } + } + + // aligned part -- [PRE_OPL,POST_FIRST) + U64 read_opl_block_base = AlignDownPow2(read_opl, READ_BLOCK_SIZE); + U64 post_first = Max(read_opl_block_base, pre_opl); + if (!done && pre_opl < post_first){ + U64 off = pre_opl - src_address; + U64 attempt_size = post_first - pre_opl; + U64 actual_size = demon_read_memory_amap_aligned(process, (U8*)dst + off, + pre_opl, attempt_size); + read_size += actual_size; + if (actual_size < attempt_size){ + done = 1; + } + } + + // post-aligned part -- [POST_FIRST,READ_OPL) + if (!done && post_first < read_opl){ + U64 off = post_first - src_address; + U64 attempt_size = read_opl - post_first; + if (!demon_read_memory(process, (U8*)dst + off, post_first, attempt_size)){ + done = 1; + } + else + { + read_size += attempt_size; + } + } + + demon_access_end(); + } + + U64 result = read_size; + return(result); +} + +#undef READ_BLOCK_SIZE + +//- rjf: thread registers reading/writing + +internal void* +demon_read_regs(DEMON_Handle thread){ + void *result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Thread){ + result = demon_accel_read_regs(entity); + } + demon_access_end(); + } + return(result); +} + +internal B32 +demon_write_regs(DEMON_Handle thread, void *data){ + B32 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Thread){ + demon_accel_write_regs(entity, data); + result = 1; + } + demon_access_end(); + } + return(result); +} + +internal U64 +demon_read_ip(DEMON_Handle thread){ + U64 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Thread){ + void *regs = demon_accel_read_regs(entity); + result = regs_rip_from_arch_block((Architecture)entity->arch, regs); + } + demon_access_end(); + } + return(result); +} + +internal U64 +demon_read_sp(DEMON_Handle thread){ + U64 result = 0; + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Thread){ + void *regs = demon_accel_read_regs(entity); + result = regs_rsp_from_arch_block((Architecture)entity->arch, regs); + } + demon_access_end(); + } + return(result); +} + +internal void +demon_write_ip(DEMON_Handle thread, U64 ip){ + if (demon_access_begin()){ + DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); + if (entity != 0 && + entity->kind == DEMON_EntityKind_Thread){ + void *regs = demon_accel_read_regs(entity); + regs_arch_block_write_rip((Architecture)entity->arch, regs, ip); + demon_accel_write_regs(entity, regs); + } + demon_access_end(); + } +} + +//////////////////////////////// +//~ rjf: Process Listing + +internal void +demon_proc_iter_begin(DEMON_ProcessIter *iter){ + demon_os_proc_iter_begin(iter); +} + +internal B32 +demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out){ + return(demon_os_proc_iter_next(arena, iter, info_out)); +} + +internal void +demon_proc_iter_end(DEMON_ProcessIter *iter){ + demon_os_proc_iter_end(iter); +} diff --git a/src/demon/demon_core.h b/src/demon/demon_core.h new file mode 100644 index 00000000..f164fcd1 --- /dev/null +++ b/src/demon/demon_core.h @@ -0,0 +1,293 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_CORE_H +#define DEMON_CORE_H + +//////////////////////////////// +//~ allen: Demon Low Level Entities + +typedef U64 DEMON_Handle; + +typedef struct DEMON_HandleNode DEMON_HandleNode; +struct DEMON_HandleNode +{ + DEMON_HandleNode *next; + DEMON_Handle v; +}; + +typedef struct DEMON_HandleList DEMON_HandleList; +struct DEMON_HandleList +{ + DEMON_HandleNode *first; + DEMON_HandleNode *last; + U64 count; +}; + +typedef struct DEMON_HandleArray DEMON_HandleArray; +struct DEMON_HandleArray +{ + DEMON_Handle *handles; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Memory Protection Flags + +typedef U32 DEMON_MemoryProtectFlags; +enum{ + DEMON_MemoryProtectFlag_Read = (1<<0), + DEMON_MemoryProtectFlag_Write = (1<<1), + DEMON_MemoryProtectFlag_Execute = (1<<2), +}; + +//////////////////////////////// +//~ allen: Demon Event Types + +typedef enum DEMON_EventKind +{ + DEMON_EventKind_Null, + DEMON_EventKind_Error, + DEMON_EventKind_HandshakeComplete, + DEMON_EventKind_CreateProcess, + DEMON_EventKind_ExitProcess, + DEMON_EventKind_CreateThread, + DEMON_EventKind_ExitThread, + DEMON_EventKind_LoadModule, + DEMON_EventKind_UnloadModule, + DEMON_EventKind_Breakpoint, + DEMON_EventKind_Trap, + DEMON_EventKind_SingleStep, + DEMON_EventKind_Exception, + DEMON_EventKind_Halt, + DEMON_EventKind_Memory, + DEMON_EventKind_DebugString, + DEMON_EventKind_SetThreadName, + DEMON_EventKind_COUNT +} +DEMON_EventKind; + +typedef enum DEMON_ErrorKind +{ + DEMON_ErrorKind_Null, + DEMON_ErrorKind_NotInitialized, + DEMON_ErrorKind_NotAttached, + DEMON_ErrorKind_UnexpectedFailure, + DEMON_ErrorKind_InvalidHandle, +} +DEMON_ErrorKind; + +typedef enum DEMON_MemoryEventKind +{ + DEMON_MemoryEventKind_Null, + DEMON_MemoryEventKind_Commit, + DEMON_MemoryEventKind_Reserve, + DEMON_MemoryEventKind_Decommit, + DEMON_MemoryEventKind_Release, + DEMON_MemoryEventKind_COUNT +} +DEMON_MemoryEventKind; + +typedef enum DEMON_ExceptionKind +{ + DEMON_ExceptionKind_Null, + DEMON_ExceptionKind_MemoryRead, + DEMON_ExceptionKind_MemoryWrite, + DEMON_ExceptionKind_MemoryExecute, + DEMON_ExceptionKind_CppThrow, + DEMON_ExceptionKind_COUNT +} +DEMON_ExceptionKind; + +typedef struct DEMON_Event DEMON_Event; +struct DEMON_Event +{ + // TODO(allen): condense + DEMON_EventKind kind; + DEMON_ErrorKind error_kind; + DEMON_MemoryEventKind memory_kind; + DEMON_ExceptionKind exception_kind; + DEMON_Handle process; + DEMON_Handle thread; + DEMON_Handle module; + U64 address; + U64 size; + String8 string; + U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully) + U32 flags; + S32 signo; + S32 sigcode; + U64 instruction_pointer; + U64 stack_pointer; + U64 user_data; + B32 exception_repeated; +}; + +typedef struct DEMON_EventNode DEMON_EventNode; +struct DEMON_EventNode +{ + DEMON_EventNode *next; + DEMON_Event v; +}; + +typedef struct DEMON_EventList DEMON_EventList; +struct DEMON_EventList +{ + DEMON_EventNode *first; + DEMON_EventNode *last; + U64 count; +}; + +//////////////////////////////// +//~ allen: Demon Run Control Types + +typedef struct DEMON_Trap DEMON_Trap; +struct DEMON_Trap +{ + DEMON_Handle process; + U64 address; + U64 id; +}; + +typedef struct DEMON_TrapChunkNode DEMON_TrapChunkNode; +struct DEMON_TrapChunkNode +{ + DEMON_TrapChunkNode *next; + DEMON_Trap *v; + U64 cap; + U64 count; +}; + +typedef struct DEMON_TrapChunkList DEMON_TrapChunkList; +struct DEMON_TrapChunkList +{ + DEMON_TrapChunkNode *first; + DEMON_TrapChunkNode *last; + U64 node_count; + U64 trap_count; +}; + +typedef struct DEMON_RunCtrls DEMON_RunCtrls; +struct DEMON_RunCtrls +{ + DEMON_Handle single_step_thread; + B8 ignore_previous_exception; + B8 run_entities_are_unfrozen; + B8 run_entities_are_processes; + DEMON_Handle *run_entities; + U64 run_entity_count; + DEMON_TrapChunkList traps; +}; + +//////////////////////////////// +//~ allen: Demon Process Listing + +typedef struct DEMON_ProcessIter DEMON_ProcessIter; +struct DEMON_ProcessIter +{ + U64 v[2]; +}; + +typedef struct DEMON_ProcessInfo DEMON_ProcessInfo; +struct DEMON_ProcessInfo +{ + String8 name; + U32 pid; +}; + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void demon_init(void); + +//////////////////////////////// +//~ rjf: Basic Type Functions + +//- rjf: stringizing +internal String8 demon_string_from_event_kind(DEMON_EventKind kind); +internal String8 demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind); +internal String8 demon_string_from_exception_kind(DEMON_ExceptionKind kind); +internal void demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event); + +//- rjf: trap chunk lists +internal void demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap); +internal void demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push); +internal void demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push); + +//- rjf: handle lists +internal void demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle); +internal DEMON_HandleArray demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list); +internal DEMON_HandleArray demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src); + +//////////////////////////////// +//~ rjf: Primary Thread & Exclusive Mode Controls + +internal void demon_primary_thread_begin(void); +internal void demon_exclusive_mode_begin(void); +internal void demon_exclusive_mode_end(void); + +//////////////////////////////// +//~ rjf: Running/Halting + +internal DEMON_EventList demon_run(Arena *arena, DEMON_RunCtrls *ctrls); +internal void demon_halt(U64 code, U64 user_data); +internal U64 demon_get_time_counter(void); + +//////////////////////////////// +//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting + +internal U32 demon_launch_process(OS_LaunchOptions *options); +internal B32 demon_attach_process(U32 pid); +internal B32 demon_kill_process(DEMON_Handle process, U32 exit_code); +internal B32 demon_detach_process(DEMON_Handle process); + +//////////////////////////////// +//~ rjf: Entity Functions + +//- rjf: basics +internal B32 demon_object_exists(DEMON_Handle object); + +//- rjf: introspection +internal Architecture demon_arch_from_object(DEMON_Handle object); +internal U64 demon_base_vaddr_from_module(DEMON_Handle module); +internal Rng1U64 demon_vaddr_range_from_module(DEMON_Handle module); +internal String8 demon_full_path_from_module(Arena *arena, DEMON_Handle module); +internal U64 demon_stack_base_vaddr_from_thread(DEMON_Handle thread); +internal U64 demon_tls_root_vaddr_from_thread(DEMON_Handle thread); +internal DEMON_HandleArray demon_all_processes(Arena *arena); +internal DEMON_HandleArray demon_threads_from_process(Arena *arena, DEMON_Handle process); +internal DEMON_HandleArray demon_modules_from_process(Arena *arena, DEMON_Handle process); + +//- rjf: target process memory allocation/protection +internal U64 demon_reserve_memory(DEMON_Handle process, U64 size); +internal B32 demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags); +internal B32 demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size); + +//- rjf: target process memory reading/writing +internal U64 demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size); +internal B32 demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size); +internal U64 demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size); +internal U64 demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size); + +//- rjf: thread registers reading/writing +// IMPORTANT(allen): This API is _trusting_ you. You should never modify the data pointed +// at by that void pointer! It is pointing to the internal cache of the registers, so it +// will become invalid after a call to demon_write_regs, or demon_run. Use it to read +// what you need and be done ASAP and we can avoid an extra copy baked into the API. +internal void *demon_read_regs(DEMON_Handle thread); +internal B32 demon_write_regs(DEMON_Handle thread, void *data); +// TODO(allen): These might be a bad idea when we try to extend to ARM +// They make sense for x86/x64 abstraction, which often needs identical +// code paths except for these parts. Revisit this when ARM is integrated. +internal U64 demon_read_ip(DEMON_Handle thread); +internal U64 demon_read_sp(DEMON_Handle thread); +internal void demon_write_ip(DEMON_Handle thread, U64 ip); + +//////////////////////////////// +//~ rjf: Process Listing + +internal void demon_proc_iter_begin(DEMON_ProcessIter *iter); +internal B32 demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out); +internal void demon_proc_iter_end(DEMON_ProcessIter *iter); + +#endif //DEMON_CORE_H diff --git a/src/demon/demon_inc.c b/src/demon/demon_inc.c new file mode 100644 index 00000000..36c7a743 --- /dev/null +++ b/src/demon/demon_inc.c @@ -0,0 +1,14 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "demon_core.c" +#include "demon_common.c" +#include "demon_accel.c" + +#if OS_WINDOWS +# include "win32/demon_os_win32.c" +#elif OS_LINUX +# include "linux/demon_os_linux.c" +#else +# error No Demon Implementation for This OS +#endif diff --git a/src/demon/demon_inc.h b/src/demon/demon_inc.h new file mode 100644 index 00000000..daf2f65d --- /dev/null +++ b/src/demon/demon_inc.h @@ -0,0 +1,20 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_INC_H +#define DEMON_INC_H + +#include "demon_core.h" +#include "demon_common.h" +#include "demon_accel.h" +#include "demon_os.h" + +#if OS_WINDOWS +# include "win32/demon_os_win32.h" +#elif OS_LINUX +# include "linux/demon_os_linux.h" +#else +# error No Demon Implementation for This OS +#endif + +#endif //DEMON_INC_H diff --git a/src/demon/demon_os.h b/src/demon/demon_os.h new file mode 100644 index 00000000..1b0bc593 --- /dev/null +++ b/src/demon/demon_os.h @@ -0,0 +1,92 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_OS_H +#define DEMON_OS_H + +// NOTE(allen): +// These are the functions that the OS backends actually implement. +// Demon objects go through a handle validation layer but it is a lot more +// convenient in the OS backends to implement these versions which take the +// already validated DEMON_Entity*. These are also more convenient to call from +// the backend layer, which lets us avoid converting back and forth between +// handles and pointers a lot. + +//////////////////////////////// +//~ NOTE(allen): Demon OS Run Control Types + +typedef struct DEMON_OS_Trap DEMON_OS_Trap; +struct DEMON_OS_Trap +{ + DEMON_Entity *process; + U64 address; +}; + +typedef struct DEMON_OS_RunCtrls DEMON_OS_RunCtrls; +struct DEMON_OS_RunCtrls +{ + DEMON_Entity *single_step_thread; + B8 ignore_previous_exception; + B8 run_entities_are_unfrozen; + B8 run_entities_are_processes; + DEMON_Entity **run_entities; + U64 run_entity_count; + DEMON_OS_Trap *traps; + U64 trap_count; +}; + +//////////////////////////////// +//~ rjf: @demon_os_hooks Main Layer Initialization + +internal void demon_os_init(void); + +//////////////////////////////// +//~ rjf: @demon_os_hooks Running/Halting + +internal DEMON_EventList demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls); +internal void demon_os_halt(U64 code, U64 user_data); + +//////////////////////////////// +//~ rjf: @demon_os_hooks Target Process Launching/Attaching/Killing/Detaching/Halting + +internal U32 demon_os_launch_process(OS_LaunchOptions *options); +internal B32 demon_os_attach_process(U32 pid); +internal B32 demon_os_kill_process(DEMON_Entity *process, U32 exit_code); +internal B32 demon_os_detach_process(DEMON_Entity *process); + +//////////////////////////////// +//~ rjf: @demon_os_hooks Entity Functions + +//- rjf: cleanup +internal void demon_os_entity_cleanup(DEMON_Entity *entity); + +//- rjf: introspection +internal String8 demon_os_full_path_from_module(Arena *arena, DEMON_Entity *module); +internal U64 demon_os_stack_base_vaddr_from_thread(DEMON_Entity *thread); +internal U64 demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread); + +//- rjf: target process memory allocation/protection +internal U64 demon_os_reserve_memory(DEMON_Entity *process, U64 size); +internal void demon_os_set_memory_protect_flags(DEMON_Entity *process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags); +internal void demon_os_release_memory(DEMON_Entity *process, U64 vaddr, U64 size); + +//- rjf: target process memory reading/writing +internal U64 demon_os_read_memory(DEMON_Entity *process, void *dst, U64 src_address, U64 size); +internal B32 demon_os_write_memory(DEMON_Entity *process, U64 dst_address, void *src, U64 size); +#define demon_os_read_struct(p,dst,src) demon_os_read_memory((p), (dst), (src), sizeof(*(dst))) +#define demon_os_write_struct(p,dst,src) demon_os_write_memory((p), (dst), (src), sizeof(*(src))) + +//- rjf: thread registers reading/writing +internal B32 demon_os_read_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *dst); +internal B32 demon_os_write_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *src); +internal B32 demon_os_read_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *dst); +internal B32 demon_os_write_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *src); + +//////////////////////////////// +//~ rjf: @demon_os_hooks Process Listing + +internal void demon_os_proc_iter_begin(DEMON_ProcessIter *iter); +internal B32 demon_os_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out); +internal void demon_os_proc_iter_end(DEMON_ProcessIter *iter); + +#endif //DEMON_OS_H diff --git a/src/demon/linux/demon_os_linux.c b/src/demon/linux/demon_os_linux.c new file mode 100644 index 00000000..0c92f461 --- /dev/null +++ b/src/demon/linux/demon_os_linux.c @@ -0,0 +1,2106 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +// TODO(allen): run controls: ignore_previous_exception + +//////////////////////////////// +//~ allen: Elf Parsing Code + +#include "syms/syms_elf_inc.c" + +//////////////////////////////// +//~ rjf: Globals + +global B32 demon_lnx_already_has_halt_injection = false; +global U64 demon_lnx_halt_code = 0; +global U64 demon_lnx_halt_user_data = 0; + +global B32 demon_lnx_new_process_pending = false; + +global Arena *demon_lnx_event_arena = 0; +global DEMON_EventList demon_lnx_queued_events = {0}; + +global U32 demon_lnx_ptrace_options = (PTRACE_O_TRACEEXIT| + PTRACE_O_EXITKILL| + PTRACE_O_TRACEFORK| + PTRACE_O_TRACEVFORK| + PTRACE_O_TRACECLONE); + +//////////////////////////////// +//~ rjf: Helpers + +internal DEMON_LNX_ThreadExt* +demon_lnx_thread_ext(DEMON_Entity *entity){ + DEMON_LNX_ThreadExt *result = (DEMON_LNX_ThreadExt*)&entity->ext; + return(result); +} + +internal B32 +demon_lnx_attach_pid(Arena *arena, pid_t pid, DEMON_LNX_AttachNode **new_node){ + B32 result = false; + + int attach_result = ptrace(PTRACE_ATTACH, pid, 0, 0); + if (attach_result == -1){ + // TODO(allen): attach denied + } + else{ + // return a new attachment node as soon as the ptrace exists. we use these nodes + // for cleanup on failure *and* for initializing on success. either way we need + // to see all new attachments whether or not they fully initialized correctly. + DEMON_LNX_AttachNode *proc_attachment = push_array_no_zero(arena, DEMON_LNX_AttachNode, 1); + proc_attachment->next = 0; + proc_attachment->pid = pid; + *new_node = proc_attachment; + + int status = 0; + pid_t wait_id = waitpid(pid, &status, __WALL); + // NOTE(allen): if wait_id != pid we don't know what that means; study that case before + // deciding how error handling around it works. + if (wait_id == pid){ + int setoptions_result = ptrace(PTRACE_SETOPTIONS, pid, 0, PtrFromInt(demon_lnx_ptrace_options)); + if (setoptions_result == -1){ + // TODO(allen): setup failed + } + else{ + result = true; + } + } + } + + return(result); +} + +internal String8 +demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid){ + // get symbolic path + Temp scratch = scratch_begin(&arena, 1); + String8 exe_symbol_path = push_str8f(scratch.arena, "/proc/%d/exe", pid); + + // try to read the link for a bit + Temp restore_point = temp_begin(arena); + B32 got_final_result = false; + U8 *buffer = 0; + int size = 0; + S64 cap = PATH_MAX; + for (S64 r = 0; r < 4; cap *= 2, r += 1){ + temp_end(restore_point); + buffer = push_array_no_zero(arena, U8, cap); + size = readlink((char*)exe_symbol_path.str, (char*)buffer, cap); + if (size < cap){ + got_final_result = true; + break; + } + } + + // finalize result + String8 result = {0}; + if (!got_final_result || size == -1){ + temp_end(restore_point); + } + else{ + arena_put_back(arena, (cap - size - 1)); + result = str8(buffer, size + 1); + } + + scratch_end(scratch); + return(result); +} + +internal int +demon_lnx_open_memory_fd_for_pid(pid_t pid){ + Temp scratch = scratch_begin(0, 0); + String8 memory_path = push_str8f(scratch.arena, "/proc/%i/mem", pid); + int result = open((char*)memory_path.str, O_RDWR); + scratch_end(scratch); + return(result); +} + +internal Architecture +demon_lnx_arch_from_pid(pid_t pid){ + Temp scratch = scratch_begin(0, 0); + Architecture result = Architecture_Null; + + // exe path + String8 exe_path = demon_lnx_executable_path_from_pid(scratch.arena, pid); + + // handle to exe + int exe_fd = -1; + if (exe_path.size != 0){ + exe_fd = open((char*)exe_path.str, O_RDONLY); + } + + // elf identification + B32 is_elf = false; + U8 e_ident[SYMS_ElfIdentifier_NIDENT] = {0}; + if (exe_fd >= 0){ + if (pread(exe_fd, e_ident, sizeof(e_ident), 0) == sizeof(e_ident)){ + is_elf = (e_ident[SYMS_ElfIdentifier_MAG0] == 0x7f && + e_ident[SYMS_ElfIdentifier_MAG1] == 'E' && + e_ident[SYMS_ElfIdentifier_MAG2] == 'L' && + e_ident[SYMS_ElfIdentifier_MAG3] == 'F'); + } + } + + // elf class + U8 elf_class = 0; + if (is_elf){ + elf_class = e_ident[SYMS_ElfIdentifier_CLASS]; + } + + // exe header data + SYMS_ElfEhdr64 ehdr = {0}; + switch (elf_class){ + case 1: + { + SYMS_ElfEhdr32 ehdr32 = {0}; + if (pread(exe_fd, &ehdr32, sizeof(ehdr32), 0) == sizeof(ehdr32)){ + ehdr = syms_elf_ehdr64_from_ehdr32(ehdr32); + } + }break; + + case 2: + { + pread(exe_fd, &ehdr, sizeof(ehdr), 0); + }break; + } + + // determine machine type + switch (ehdr.e_machine){ + case SYMS_ElfMachineKind_386: + { + result = Architecture_x86; + }break; + + case SYMS_ElfMachineKind_ARM: + { + result = Architecture_arm32; + }break; + + case SYMS_ElfMachineKind_X86_64: + { + result = Architecture_x64; + }break; + + case SYMS_ElfMachineKind_AARCH64: + { + result = Architecture_arm64; + }break; + } + + scratch_end(scratch); + return(result); +} + +internal DEMON_LNX_ProcessAux +demon_lnx_aux_from_pid(pid_t pid, Architecture arch){ + DEMON_LNX_ProcessAux result = {0}; + B32 addr_32bit = (arch == Architecture_x86 || arch == Architecture_arm32); + + // open aux data + Temp scratch = scratch_begin(0, 0); + String8 auxv_symbol_path = push_str8f(scratch.arena, "/proc/%d/auxv", pid); + int aux_fd = open((char*)auxv_symbol_path.str, O_RDONLY); + + // scan aux data + if (aux_fd >= 0){ + for (;;){ + result.filled = true; + + // read next aux + U64 type = 0; + U64 val = 0; + if (addr_32bit){ + SYMS_ElfAuxv32 aux; + if (read(aux_fd, &aux, sizeof(aux)) != sizeof(aux)){ + goto brkloop; + } + type = aux.a_type; + val = aux.a_val; + } + else{ + SYMS_ElfAuxv64 aux; + if (read(aux_fd, &aux, sizeof(aux)) != sizeof(aux)){ + goto brkloop; + } + type = aux.a_type; + val = aux.a_val; + } + + // place value in result + switch (type){ + default:break; + case SYMS_ElfAuxType_NULL: goto brkloop; break; + case SYMS_ElfAuxType_PHNUM: result.phnum = val; break; + case SYMS_ElfAuxType_PHENT: result.phent = val; break; + case SYMS_ElfAuxType_PHDR: result.phdr = val; break; + case SYMS_ElfAuxType_EXECFN: result.execfn = val; break; + } + } + brkloop:; + + close(aux_fd); + } + + scratch_end(scratch); + return(result); +} + +internal DEMON_LNX_PhdrInfo +demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit, U64 phvaddr, U64 phentsize, U64 phcount){ + DEMON_LNX_PhdrInfo result = {0}; + result.range.min = max_U64; + + // how much phdr will we read? + U64 phdr_size_expected = (is_32bit?sizeof(SYMS_ElfPhdr32):sizeof(SYMS_ElfPhdr64)); + U64 phdr_stride = (phentsize?phentsize:phdr_size_expected); + U64 phdr_read_size = ClampTop(phdr_stride, phdr_size_expected); + + // scan table + U64 va = phvaddr; + for (U64 i = 0; i < phcount; i += 1, va += phdr_stride){ + + // get type and range + SYMS_ElfPKind p_type = 0; + U64 p_vaddr = 0; + U64 p_memsz = 0; + + if (is_32bit){ + SYMS_ElfPhdr32 phdr32 = {0}; + demon_lnx_read_memory(memory_fd, &phdr32, va, phdr_read_size); + p_type = phdr32.p_type; + p_vaddr = phdr32.p_vaddr; + p_memsz = phdr32.p_memsz; + } + else{ + SYMS_ElfPhdr64 phdr64 = {0}; + demon_lnx_read_memory(memory_fd, &phdr64, va, phdr_read_size); + p_type = phdr64.p_type; + p_vaddr = phdr64.p_vaddr; + p_memsz = phdr64.p_memsz; + } + + // save useful info + switch (p_type){ + case SYMS_ElfPKind_Dynamic: + { + result.dynamic = p_vaddr; + }break; + case SYMS_ElfPKind_Load: + { + U64 min = p_vaddr; + U64 max = p_vaddr + p_memsz; + result.range.min = Min(result.range.min, min); + result.range.max = Max(result.range.max, max); + }break; + } + } + + return(result); +} + +internal DEMON_LNX_ModuleNode* +demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process){ + Architecture arch = (Architecture)process->arch; + B32 is_32bit = (arch == Architecture_x86 || arch == Architecture_arm32); + int memory_fd = (int)process->ext_u64; + + // aux from pid + DEMON_LNX_ProcessAux aux = demon_lnx_aux_from_pid((pid_t)process->id, arch); + + // extract info from program headers + DEMON_LNX_PhdrInfo phdr_info = demon_lnx_phdr_info_from_memory(memory_fd, is_32bit, + aux.phdr, aux.phent, aux.phnum); + + // linkmap first from memory space & dyn address + U64 first_linkmap_va = 0; + if (phdr_info.dynamic != 0){ + U64 off = phdr_info.dynamic; + for (;;){ + SYMS_ElfDyn64 dyn = {0}; + if (is_32bit){ + SYMS_ElfDyn32 dyn32 = {0}; + demon_lnx_read_memory(memory_fd, &dyn32, off, sizeof(dyn32)); + dyn.tag = dyn32.tag; + dyn.val = dyn32.val; + off += sizeof(dyn32); + } + else{ + demon_lnx_read_memory(memory_fd, &dyn, off, sizeof(dyn)); + off += sizeof(dyn); + } + + if (dyn.tag == SYMS_ElfDynTag_NULL){ + break; + } + + if (dyn.tag == SYMS_ElfDynTag_PLTGOT){ + // True for x86 and x64 + // vas[0] virtual address of .dynamic + // vas[2] callback for resolving function address of relocation and if successful jumps to it. + // + // Code that sets up PLTGOT is in glibc/sysdeps/x86_64/dl_machine.h -> elf_machine_runtime_setup + U64 vas_off = dyn.val; + U64 vas[3] = {0}; + demon_lnx_read_memory(memory_fd, vas, vas_off, sizeof(vas)); + first_linkmap_va = vas[1]; + break; + } + } + } + + // setup output list + DEMON_LNX_ModuleNode *first = 0; + DEMON_LNX_ModuleNode *last = 0; + + // main module + { + DEMON_LNX_ModuleNode *node = push_array(arena, DEMON_LNX_ModuleNode, 1); + SLLQueuePush(first, last, node); + node->vaddr = phdr_info.range.min; + node->size = phdr_info.range.max - phdr_info.range.min; + node->name = aux.execfn; + } + + // iterate link maps + if (first_linkmap_va != 0){ + U64 linkmap_va = first_linkmap_va; + + for (;;){ + SYMS_ElfLinkMap64 linkmap = {0}; + if (is_32bit){ + // TOOD(nick): endian awarness + SYMS_ElfLinkMap32 linkmap32 = {0}; + demon_lnx_read_memory(memory_fd, &linkmap32, linkmap_va, sizeof(linkmap32)); + linkmap.base = linkmap32.base; + linkmap.name = linkmap32.name; + linkmap.ld = linkmap32.ld; + linkmap.next = linkmap32.next; + } + else{ + demon_lnx_read_memory(memory_fd, &linkmap, linkmap_va, sizeof(linkmap)); + } + + if (linkmap.base != 0){ + // find phdrs for this module + SYMS_U64 phvaddr = 0; + SYMS_U64 phentsize = 0; + SYMS_U64 phcount = 0; + + if (is_32bit){ + SYMS_ElfEhdr32 ehdr = {0}; + demon_lnx_read_memory(memory_fd, &ehdr, linkmap.base, sizeof(ehdr)); + phvaddr = ehdr.e_phoff + linkmap.base; + phentsize = ehdr.e_phentsize; + phcount = ehdr.e_phnum; + } + else{ + SYMS_ElfEhdr64 ehdr = {0}; + demon_lnx_read_memory(memory_fd, &ehdr, linkmap.base, sizeof(ehdr)); + phvaddr = ehdr.e_phoff + linkmap.base; + phentsize = ehdr.e_phentsize; + phcount = ehdr.e_phnum; + } + + // extract info from phdrs + DEMON_LNX_PhdrInfo module_phdr_info = demon_lnx_phdr_info_from_memory(memory_fd, is_32bit, + phvaddr, phentsize, phcount); + + // save module node + DEMON_LNX_ModuleNode *node = push_array(arena, DEMON_LNX_ModuleNode, 1); + SLLQueuePush(first, last, node); + node->vaddr = linkmap.base; + node->size = module_phdr_info.range.max - module_phdr_info.range.min; + node->name = linkmap.name; + } + + linkmap_va = linkmap.next; + if (linkmap_va == 0){ + break; + } + } + } + + return(first); +} + +internal U64 +demon_lnx_read_memory(int memory_fd, void *dst, U64 src, U64 size){ + U64 bytes_read = 0; + U8 *ptr = (U8*)dst; + U8 *opl = ptr + size; + U64 cursor = src; + for (;ptr < opl;){ + size_t to_read = (size_t)(opl - ptr); + ssize_t actual_read = pread(memory_fd, ptr, to_read, cursor); + if (actual_read == -1){ + break; + } + ptr += actual_read; + cursor += actual_read; + bytes_read += actual_read; + } + return(bytes_read); +} + +internal B32 +demon_lnx_write_memory(int memory_fd, U64 dst, void *src, U64 size){ + B32 result = true; + U8 *ptr = (U8*)src; + U8 *opl = ptr + size; + U64 cursor = dst; + for (;ptr < opl;){ + size_t to_write = (size_t)(opl - ptr); + ssize_t actual_write = pwrite(memory_fd, ptr, to_write, cursor); + if (actual_write == -1){ + result = false; + break; + } + ptr += actual_write; + cursor += actual_write; + } + return(result); +} + +internal String8 +demon_lnx_read_memory_str(Arena *arena, int memory_fd, U64 address){ + // TODO(allen): this could be done better with a demon_lnx_read_memory + // that returns a read amount instead of a success/fail. + + // scan piece by piece + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + U64 max_cap = 256; + U64 cap = max_cap; + U64 read_p = address; + for (;;){ + U8 *block = push_array(scratch.arena, U8, cap); + for (;cap > 0;){ + if (demon_lnx_read_memory(memory_fd, block, read_p, cap)){ + break; + } + cap /= 2; + } + read_p += cap; + + U64 block_opl = 0; + for (;block_opl < cap; block_opl += 1){ + if (block[block_opl] == 0){ + break; + } + } + + if (block_opl > 0){ + str8_list_push(scratch.arena, &list, str8(block, block_opl)); + } + + if (block_opl < cap || cap == 0){ + break; + } + } + + // assemble results + String8 result = str8_list_join(arena, &list, 0); + scratch_end(scratch); + return(result); +} + +internal void +demon_lnx_regs_x64_from_usr_regs_x64(SYMS_RegX64 *dst, DEMON_LNX_UserRegsX64 *src){ + dst->rax.u64 = src->rax; + dst->rcx.u64 = src->rcx; + dst->rdx.u64 = src->rdx; + dst->rbx.u64 = src->rbx; + dst->rsp.u64 = src->rsp; + dst->rbp.u64 = src->rbp; + dst->rsi.u64 = src->rsi; + dst->rdi.u64 = src->rdi; + dst->r8.u64 = src->r8; + dst->r9.u64 = src->r9; + dst->r10.u64 = src->r10; + dst->r11.u64 = src->r11; + dst->r12.u64 = src->r12; + dst->r13.u64 = src->r13; + dst->r14.u64 = src->r14; + dst->r15.u64 = src->r15; + dst->cs.u16 = src->cs; + dst->ds.u16 = src->ds; + dst->es.u16 = src->es; + dst->fs.u16 = src->fs; + dst->gs.u16 = src->gs; + dst->ss.u16 = src->ss; + dst->fsbase.u64 = src->fsbase; + dst->gsbase.u64 = src->gsbase; + dst->rip.u64 = src->rip; + dst->rflags.u64 = src->rflags; +} + +internal void +demon_lnx_usr_regs_x64_from_regs_x64(DEMON_LNX_UserRegsX64 *dst, SYMS_RegX64 *src){ + dst->rax = src->rax.u64; + dst->rcx = src->rcx.u64; + dst->rdx = src->rdx.u64; + dst->rbx = src->rbx.u64; + dst->rsp = src->rsp.u64; + dst->rbp = src->rbp.u64; + dst->rsi = src->rsi.u64; + dst->rdi = src->rdi.u64; + dst->r8 = src->r8.u64; + dst->r9 = src->r9.u64; + dst->r10 = src->r10.u64; + dst->r11 = src->r11.u64; + dst->r12 = src->r12.u64; + dst->r13 = src->r13.u64; + dst->r14 = src->r14.u64; + dst->r15 = src->r15.u64; + dst->cs = src->cs.u16; + dst->ds = src->ds.u16; + dst->es = src->es.u16; + dst->fs = src->fs.u16; + dst->gs = src->gs.u16; + dst->ss = src->ss.u16; + dst->fsbase = src->fsbase.u64; + dst->gsbase = src->gsbase.u64; + dst->rip = src->rip.u64; + dst->rflags = src->rflags.u64; +} + +//////////////////////////////// + +internal String8 +demon_lnx_read_int_string(Arena *arena, int fd, int radix){ + String8 integer = str8(0,0); + + int to_read = 0; + int to_seek = 0; + for (;;){ + char b = 0; + if (read(fd, &b, sizeof(b)) == 0){ + break; + } + to_seek += 1; + if ( ! char_is_digit(b, radix)){ + break; + } + to_read += 1; + } + + if (lseek(fd, -to_seek, SEEK_CUR) != -1) { + char *buf = push_array_no_zero(arena, char, to_read + 1); + read(fd, buf, to_read); + buf[to_read] = '\0'; + integer = str8((U8*)buf, (U64)to_read); + } + + return(integer); +} + +internal U64 +demon_lnx_read_u64(int fd, int radix){ + Temp scratch = scratch_begin(0, 0); + String8 integer = demon_lnx_read_int_string(scratch.arena, fd, radix); + U64 result = u64_from_str8(integer, radix); + scratch_end(scratch); + return(result); +} + +internal S64 +demon_lnx_read_s64(int fd, int radix){ + Temp scratch = scratch_begin(0, 0); + String8 integer = demon_lnx_read_int_string(scratch.arena, fd, radix); + S64 result = s64_from_str8(integer, radix); + scratch_end(scratch); + return(result); +} + +internal B32 +demon_lnx_read_expect(int fd, char expect){ + char got = 0; + read(fd, &got, sizeof(got)); + B32 result = (got == expect); + if (!result){ + lseek(fd, -1, SEEK_CUR); + } + return(result); +} + +internal int +demon_lnx_read_whitespace(int fd){ + int whitespace_size = 0; + for (;;){ + if (!demon_lnx_read_expect(fd, ' ')){ + if (!demon_lnx_read_expect(fd, '\t')){ + break; + } + } + whitespace_size += 1; + } + return whitespace_size; +} + +internal String8 +demon_lnx_read_string(Arena *arena, int fd){ + String8 result = str8(0,0); + + int to_read = 0; + int to_seek = 0; + for (;;){ + char b = 0; + if (read(fd, &b, sizeof(b)) == 0) { + break; + } + to_seek += 1; + if (b == '\0' || b == '\n'){ + break; + } + to_read += 1; + } + + if (to_seek > 0 && lseek(fd, -to_seek, SEEK_CUR) != -1){ + char *buf = push_array_no_zero(arena, char, to_read + 1); + read(fd, buf, to_read); + buf[to_read] = '\0'; + result = str8((U8*)buf, to_read); + } + + return(result); +} + +internal int +demon_lnx_open_maps(pid_t pid){ + Temp scratch = scratch_begin(0, 0); + String8 path = push_str8f(scratch.arena, "/proc/%d/maps", pid); + int maps = open((char*)path.str, O_RDONLY); + scratch_end(scratch); + return(maps); +} + +internal B32 +demon_lnx_next_map(Arena *arena, int maps, DEMON_LNX_MapsEntry *entry_out){ + B32 is_parsed = false; + MemoryZeroStruct(entry_out); + do{ + U64 address_lo = 0; + U64 address_hi = 0; + DEMON_LNX_PermFlags perms = 0; + U64 offset = 0; + U64 dev_major = 0; + U64 dev_minor = 0; + U64 inode = 0; + String8 pathname = str8(0,0); + + // address range + address_lo = demon_lnx_read_u64(maps, 16); + if (!demon_lnx_read_expect(maps, '-')){ + break; + } + address_hi = demon_lnx_read_u64(maps, 16); + if (demon_lnx_read_whitespace(maps) == 0){ + break; + } + + // permission flags + char b; + if (read(maps, &b, sizeof(b)) == 0){ + break; + } + if (b=='r'){ + perms |= DEMON_LNX_PermFlags_Read; + } + if (read(maps, &b, sizeof(b)) == 0){ + break; + } + if (b=='w'){ + perms |= DEMON_LNX_PermFlags_Write; + } + if (read(maps, &b, sizeof(b)) == 0){ + break; + } + if (b=='x'){ + perms |= DEMON_LNX_PermFlags_Exec; + } + if (read(maps, &b, sizeof(b)) == 0){ + break; + } + if (b == 'p'){ + perms |= DEMON_LNX_PermFlags_Private; + } + if (demon_lnx_read_whitespace(maps) == 0){ + break; + } + + // offset + offset = demon_lnx_read_u64(maps, 16); + if (demon_lnx_read_whitespace(maps) == 0){ + break; + } + + // dev + dev_major = demon_lnx_read_u64(maps, 10); + if (!demon_lnx_read_expect(maps, ':')){ + break; + } + dev_minor = demon_lnx_read_u64(maps, 10); + if (demon_lnx_read_whitespace(maps) == 0){ + break; + } + + // inode + inode = demon_lnx_read_u64(maps, 10); + if (demon_lnx_read_whitespace(maps) == 10){ + break; + } + + // pathname + pathname = demon_lnx_read_string(arena, maps); + + // emit entry if en + b = 0; + read(maps, &b, sizeof(b)); + if (b != '\n' && b != '\0') { + break; + } + + // fill result + entry_out->address_lo = address_lo; + entry_out->address_hi = address_hi; + entry_out->perms = perms; + entry_out->offset = offset; + entry_out->dev_major = (U32)dev_major; + entry_out->dev_minor = (U32)dev_minor; + entry_out->inode = inode; + entry_out->pathname = pathname; + entry_out->type = DEMON_LNX_MapsEntryType_Null; + entry_out->stack_tid = 0; + + if (str8_match(pathname, str8_lit("/"), StringMatchFlag_RightSideSloppy)){ + entry_out->type = DEMON_LNX_MapsEntryType_Path; + } else if (str8_match(pathname, str8_lit("[heap]"), 0)){ + entry_out->type = DEMON_LNX_MapsEntryType_Heap; + } else if (str8_match(pathname, str8_lit("[stack]"), 0)){ + entry_out->type = DEMON_LNX_MapsEntryType_Stack; + } else if (str8_match(pathname, str8_lit("[stack:"), StringMatchFlag_RightSideSloppy)){ + entry_out->type = DEMON_LNX_MapsEntryType_Stack; + String8 tid = str8_substr(pathname, r1u64(7, pathname.size - 8)); + entry_out->stack_tid = (pid_t)u64_from_str8(tid, 10); + } + + is_parsed = true; + }while(0); + return(is_parsed); +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Main Layer Initialization + +internal void +demon_os_init(void){ + demon_lnx_event_arena = arena_alloc(); +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Running/Halting + +internal DEMON_EventList +demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls){ + DEMON_EventList result = {0}; + + if (demon_ent_root == 0){ + demon_push_event(arena, &result, DEMON_EventKind_NotInitialized); + } + else if (demon_ent_root->first == 0 && !demon_lnx_new_process_pending){ + demon_push_event(arena, &result, DEMON_EventKind_NotAttached); + } + else{ + Temp scratch = scratch_begin(&arena, 1); + + // use queued events if there are any + if (demon_lnx_queued_events.first != 0){ + // copy event queue + for (DEMON_Event *node = demon_lnx_queued_events.first; + node != 0; + node = node->next){ + DEMON_Event *copy = push_array_no_zero(arena, DEMON_Event, 1); + MemoryCopyStruct(copy, node); + SLLQueuePush(result.first, result.last, copy); + } + result.count = demon_lnx_queued_events.count; + + // zero stored queue + MemoryZeroStruct(&demon_lnx_queued_events); + arena_clear(demon_lnx_event_arena); + } + + // get the single step thread (if any) + DEMON_Entity *single_step_thread = controls->single_step_thread; + + // do setup + B32 did_setup = false; + U8 *trap_swap_bytes = 0; + + if (result.first == 0){ + // TODO(allen): per-Architecture implementation of single steps + // set single step bit + if (single_step_thread != 0){ + switch (single_step_thread->arch){ + case Architecture_x86: + { + // TODO(allen): possibly buggy + SYMS_RegX86 regs = {0}; + demon_os_read_regs_x86(single_step_thread, ®s); + regs.eflags.u32 |= 0x100; + demon_os_write_regs_x86(single_step_thread, ®s); + }break; + + case Architecture_x64: + { + // TODO(allen): possibly buggy + SYMS_RegX64 regs = {0}; + demon_os_read_regs_x64(single_step_thread, ®s); + regs.rflags.u64 |= 0x100; + demon_os_write_regs_x64(single_step_thread, ®s); + }break; + } + } + + // TODO(allen): per-Architecture implementation of traps + trap_swap_bytes = push_array_no_zero(scratch.arena, U8, controls->trap_count); + + { + DEMON_OS_Trap *trap = controls->traps; + for (U64 i = 0; i < controls->trap_count; i += 1, trap += 1){ + if (demon_os_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)){ + U8 int3 = 0xCC; + demon_os_write_memory(trap->process, trap->address, &int3, 1); + } + else{ + trap_swap_bytes[i] = 0xCC; + } + } + } + + did_setup = true; + } + + // do run + B32 did_run = false; + if (did_setup){ + // continue non-frozen threads + DEMON_LNX_EntityNode *resume_threads = 0; + for (DEMON_Entity *process = demon_ent_root->first; + process != 0; + process = process->next){ + if (process->kind == DEMON_EntityKind_Process){ + + // determine if this process is frozen + B32 process_is_frozen = false; + if (controls->run_entities_are_processes){ + for (U64 i = 0; i < controls->run_entity_count; i += 1){ + if (controls->run_entities[i] == process){ + process_is_frozen = true; + break; + } + } + } + + for (DEMON_Entity *thread = process->first; + thread != 0; + thread = thread->next){ + if (thread->kind == DEMON_EntityKind_Thread){ + // determine if this thread is frozen + B32 is_frozen = false; + + if (controls->single_step_thread != 0 && + controls->single_step_thread != thread){ + is_frozen = true; + } + else{ + + if (controls->run_entities_are_processes){ + is_frozen = process_is_frozen; + } + else{ + for (U64 i = 0; i < controls->run_entity_count; i += 1){ + if (controls->run_entities[i] == thread){ + is_frozen = true; + break; + } + } + } + + if (controls->run_entities_are_unfrozen){ + is_frozen = !is_frozen; + } + } + + // continue if not frozen + if (!is_frozen){ + errno = 0; + ptrace(PTRACE_CONT, (pid_t)thread->id, 0, 0); + DEMON_LNX_EntityNode *thread_node = push_array_no_zero(scratch.arena, DEMON_LNX_EntityNode, 1); + SLLStackPush(resume_threads, thread_node); + thread_node->entity = thread; + } + } + } + } + } + + // get next stop + wait_for_stop: + B32 did_dummy_stop = false; + int status = 0; + pid_t wait_id = waitpid(-1, &status, __WALL); + + // increment demon time + demon_time += 1; + + // handle devent + DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, wait_id); + if (thread == 0){ + if (wait_id >= 0){ + // TODO(allen): this isn't a great situation! From what I can tell there's no + // options that I am super happy with for going from unknown tid -> pid. + // We can parse it out of /proc//status; but I don't want to do that until + // I'm forced to, because it seems like this shouldn't happen if the ptrace + // API works correctly and we don't have any bugs in our demon entity system. + } + } + else{ + B32 thread_exit = false; + U64 exit_code = 0; + + DEMON_Entity *process = thread->parent; + // NOTE(allen): hitting this assert should never ever be possible, if our entities + // are wired up correctly. it doesn't matter what ptrace or waitpid are doing. + Assert(process != 0); + + // read register info + U64 instruction_pointer = 0; + union{ SYMS_RegX86 x86; SYMS_RegX64 x64; } regs = {0}; + + switch (thread->arch){ + case Architecture_x86: + { + demon_os_read_regs_x86(thread, ®s.x86); + instruction_pointer = regs.x86.eip.u32; + }break; + + case Architecture_x64: + { + demon_os_read_regs_x64(thread, ®s.x64); + instruction_pointer = regs.x64.rip.u64; + }break; + } + + // check stop status + if (WIFEXITED(status)){ + thread_exit = true; + } + if (WIFSIGNALED(status)){ + exit_code = WTERMSIG(status); + thread_exit = true; + } + + // extra event list + DEMON_EventList stop_events = {0}; + + if (WIFSTOPPED(status)){ + switch (WSTOPSIG(status)){ + case SIGTRAP: + { + switch (status >> 8){ + case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)): + { + // TODO(allen): (not sure actually, study this part) + thread_exit = true; + }break; + + case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)): + { + // new thread coming + unsigned long new_tid = 0; + int get_message_result = ptrace(PTRACE_GETEVENTMSG, wait_id, 0, &new_tid); + if (get_message_result == -1){ + // TODO(allen): this isn't right, time to give up on getting this process. + // this will likely lead to getting unrecognized wait_id s later. So we need + // this stuff in the log to make sense of it still. + } + else{ + // thread entity + DEMON_Entity *new_thread = demon_ent_new(process, DEMON_EntityKind_Thread, new_tid); + demon_thread_count += 1; + DEMON_LNX_ThreadExt *thread_ext = demon_lnx_thread_ext(new_thread); + thread_ext->expecting_dummy_sigstop = true; + + // thread event + DEMON_Event *e = demon_push_event(arena, &stop_events, DEMON_EventKind_CreateThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(new_thread); + } + }break; + + case (SIGTRAP | (PTRACE_EVENT_FORK << 8)): + case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): + { + // new process coming + unsigned long new_pid = 0; + int get_message_result = ptrace(PTRACE_GETEVENTMSG, wait_id, 0, &new_pid); + if (get_message_result == -1){ + // TODO(allen): this isn't right, time to give up on getting this process. + // this will likely lead to getting unrecognized wait_id s later. So we need + // this stuff in the log to make sense of it still. + } + else{ + Architecture arch = demon_lnx_arch_from_pid(new_pid); + + // process entity + DEMON_Entity *new_process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, new_pid); + new_process->arch = arch; + new_process->ext_u64 = demon_lnx_open_memory_fd_for_pid(new_pid); + + demon_lnx_new_process_pending = false; + + // thread entity + DEMON_Entity *new_thread = demon_ent_new(new_process, DEMON_EntityKind_Thread, new_pid); + demon_thread_count += 1; + DEMON_LNX_ThreadExt *thread_ext = demon_lnx_thread_ext(new_thread); + thread_ext->expecting_dummy_sigstop = true; + + // process event + { + DEMON_Event *e = demon_push_event(arena, &stop_events, DEMON_EventKind_CreateProcess); + e->process = demon_ent_handle_from_ptr(new_process); + } + + // thread event + { + DEMON_Event *e = demon_push_event(arena, &stop_events, DEMON_EventKind_CreateThread); + e->process = demon_ent_handle_from_ptr(new_process); + e->thread = demon_ent_handle_from_ptr(new_thread); + } + } + }break; + + default: + { + // check single step + DEMON_EventKind e_kind = DEMON_EventKind_Trap; + if (thread == single_step_thread){ + e_kind = DEMON_EventKind_SingleStep; + } + + // check bp + if (e_kind == DEMON_EventKind_Trap){ + DEMON_OS_Trap *trap = controls->traps; + for (U64 i = 0; i < controls->trap_count; i += 1, trap += 1){ + if (trap->process == process && trap->address == instruction_pointer - 1){ + e_kind = DEMON_EventKind_Breakpoint; + break; + } + } + } + + // adjust ip after breakpoint + if (e_kind == DEMON_EventKind_Breakpoint){ + // TODO(allen): possibly buggy + switch (thread->arch){ + case Architecture_x86: + { + instruction_pointer -= 1; + regs.x86.eip.u32 = instruction_pointer; + demon_os_write_regs_x86(thread, ®s.x86); + }break; + + case Architecture_x64: + { + instruction_pointer -= 1; + regs.x64.rip.u64 = instruction_pointer; + demon_os_write_regs_x64(thread, ®s.x64); + }break; + } + } + + // event + DEMON_Event *e = demon_push_event(arena, &stop_events, e_kind); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->instruction_pointer = instruction_pointer; + }break; + } + }break; + + case SIGSTOP: + { + // TODO(allen): we need to figure out how we want to tell apart: + // SIGSTOP All-Stop, SIGSTOP Halt, SIGSTOP "User" + // what we're doing right now == big-time race conditions + + DEMON_LNX_ThreadExt *thread_ext = demon_lnx_thread_ext(thread); + + if (thread_ext->expecting_dummy_sigstop){ + thread_ext->expecting_dummy_sigstop = false; + did_dummy_stop = true; + } + else if (demon_lnx_already_has_halt_injection){ + DEMON_Event *e = demon_push_event(arena, &stop_events, DEMON_EventKind_Halt); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->instruction_pointer = instruction_pointer; + } + else{ + // TODO(allen): a signal we don't want to mess with (except to record that it happened maybe) + // we should "hand it back" + } + }break; + + default: + { +#if 0 + // these are a little special. the program cannot continue after these + // unless the user first does something to change the state (move the IP, change a variable, w/e) + case SIGABRT:case SIGFPE:case SIGSEGV: +#endif + + // event + DEMON_Event *e = demon_push_event(arena, &stop_events, DEMON_EventKind_Exception); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->instruction_pointer = instruction_pointer; + e->signo = WSTOPSIG(status); + }break; + } + } + + // entity cleanup + if (thread_exit){ + if (thread->id == process->id){ + // generate events for threads & modules + for (DEMON_Entity *entity = process->first; + entity != 0; + entity = entity->next){ + if (entity->kind == DEMON_EntityKind_Thread){ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(entity); + } + else{ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_UnloadModule); + e->process = demon_ent_handle_from_ptr(process); + e->module = demon_ent_handle_from_ptr(entity); + } + } + + // exit event + DEMON_Event *e = demon_push_event(arena, &stop_events, DEMON_EventKind_ExitProcess); + e->process = demon_ent_handle_from_ptr(process); + e->code = exit_code; + + // free entity + demon_ent_release_root_and_children(process); + } + else{ + // exit event + DEMON_Event *e = demon_push_event(arena, &stop_events, DEMON_EventKind_ExitThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->code = exit_code; + + // free entity + demon_ent_release_root_and_children(thread); + } + } + + // update all module lists (for each process ...) + DEMON_EventList module_change_events = {0}; + + for (DEMON_Entity *proc_node = demon_ent_root->first; + proc_node != 0; + proc_node = proc_node->next){ + DEMON_LNX_ModuleNode *first_module = demon_lnx_module_list_from_process(scratch.arena, proc_node); + + DEMON_LNX_EntityNode *first_unloaded = 0; + DEMON_LNX_EntityNode *last_unloaded = 0; + + // compute the delta (mark known modules, save list of unloaded modules) + for (DEMON_Entity *entity = proc_node->first; + entity != 0; + entity = entity->next){ + if (entity->kind == DEMON_EntityKind_Module){ + U64 base = entity->id; + U64 name = entity->ext_u64; + B32 still_exists = false; + for (DEMON_LNX_ModuleNode *module_node = first_module; + module_node != 0; + module_node = module_node->next){ + if (module_node->vaddr == base && module_node->name == name){ + module_node->already_known = true; + still_exists = true; + break; + } + } + if (!still_exists){ + DEMON_LNX_EntityNode *node = push_array_no_zero(scratch.arena, DEMON_LNX_EntityNode, 1); + SLLQueuePush(first_unloaded, last_unloaded, node); + node->entity = entity; + } + } + } + + // handle unloads + for (DEMON_LNX_EntityNode *unloaded_node = first_unloaded; + unloaded_node != 0; + unloaded_node = unloaded_node->next){ + DEMON_Entity *module = unloaded_node->entity; + + // event + { + DEMON_Event *e = demon_push_event(arena, &module_change_events, DEMON_EventKind_UnloadModule); + e->process = demon_ent_handle_from_ptr(proc_node); + e->module = demon_ent_handle_from_ptr(module); + } + + // free entity + demon_ent_release_root_and_children(module); + } + + // handle loads + for (DEMON_LNX_ModuleNode *module_node = first_module; + module_node != 0; + module_node = module_node->next){ + if (!module_node->already_known){ + // entity + DEMON_Entity *module = demon_ent_new(proc_node, DEMON_EntityKind_Module, module_node->vaddr); + demon_module_count += 1; + module->ext_u64 = module_node->name; + + // event + { + DEMON_Event *e = demon_push_event(arena, &module_change_events, DEMON_EventKind_LoadModule); + e->process = demon_ent_handle_from_ptr(proc_node); + e->module = demon_ent_handle_from_ptr(module); + e->address = module_node->vaddr; + e->size = module_node->size; + } + } + } + } + + // concat the events list (with module changes first) + result.count = module_change_events.count + stop_events.count; + result.first = module_change_events.first; + result.last = module_change_events.last; + if (stop_events.first != 0){ + if (result.first != 0){ + result.last->next = stop_events.first; + result.last = stop_events.last; + } + else{ + result.first = stop_events.first; + result.last = stop_events.last; + } + } + } + + // do we have a reason to keep going? + B32 skip_this_stop = false; + if (did_dummy_stop && result.count == 0){ + skip_this_stop = true; + } + + // ignore this stop, resume and wait again + if (skip_this_stop){ + if (wait_id != 0){ + ptrace(PTRACE_CONT, (pid_t)wait_id, 0, 0); + } + goto wait_for_stop; + } + + // stop all running threads + for (DEMON_LNX_EntityNode *node = resume_threads; + node != 0; + node = node->next){ + DEMON_Entity *thread = node->entity; + pid_t thread_id = (pid_t)thread->id; + if (thread_id != wait_id){ + union sigval sv = {0}; + sigqueue(thread_id, SIGSTOP, sv); + + DEMON_LNX_ThreadExt *thread_ext = demon_lnx_thread_ext(thread); + thread_ext->expecting_dummy_sigstop = true; + } + } + + did_run = true; + } + + // cleanup + if (did_run){ + // TODO(allen): per-Architecture + // unset traps + { + DEMON_OS_Trap *trap = controls->traps; + for (U64 i = 0; i < controls->trap_count; i += 1, trap += 1){ + U8 og_byte = trap_swap_bytes[i]; + if (og_byte != 0xCC){ + demon_os_write_memory(trap->process, trap->address, &og_byte, 1); + } + } + } + + // TODO(allen): per-Architecture + // unset single step bit + // the single step bit is automatically unset whenever we single step + // but if *something else* happened, it will still be there ready to + // confound us later; so here we're just being sure it's taken out. + if (single_step_thread != 0){ + // TODO(allen): possibly buggy + switch (single_step_thread->arch){ + case Architecture_x86: + { + SYMS_RegX86 regs = {0}; + demon_os_read_regs_x86(single_step_thread, ®s); + regs.eflags.u32 &= ~0x100; + demon_os_write_regs_x86(single_step_thread, ®s); + }break; + + case Architecture_x64: + { + SYMS_RegX64 regs = {0}; + demon_os_read_regs_x64(single_step_thread, ®s); + regs.rflags.u64 &= ~0x100; + demon_os_write_regs_x64(single_step_thread, ®s); + }break; + } + } + } + + scratch_end(scratch); + } + + return(result); +} + +internal void +demon_os_halt(U64 code, U64 user_data){ + if (demon_ent_root != 0 && !demon_lnx_already_has_halt_injection){ + DEMON_Entity *process = demon_ent_root->first; + if (process != 0){ + demon_lnx_already_has_halt_injection = true; + demon_lnx_halt_code = code; + demon_lnx_halt_user_data = user_data; + union sigval sv = {0}; + if (sigqueue(process->id, SIGSTOP, sv) == -1){ + demon_lnx_already_has_halt_injection = false; + } + } + } +} + +// NOTE(allen): siginfo hint from old code: +#if 0 +{ + switch (siginfo.si_code){ + // SI_KERNEL (hit int3; 0xCC) + case 0x80: + { + // TODO(allen): breakpoint event + }break; + + // TRAP_UNK, TRAP_HWBKPT, TRAP_BRKPT, TRAP_TRACE + case 0x5: case 0x4: case 0x1: case 0x2: + { + // TODO(allen): breakpoint event (?) + }break; + + case 0x3: case 0x0: + { + // TODO(allen): do nothing I guess? + }break; + } +} +#endif + +//////////////////////////////// +//~ rjf: @demon_os_hooks Target Process Launching/Attaching/Killing/Detaching/Halting + +internal U32 +demon_os_launch_process(OS_LaunchOptions *options){ + U32 result = 0; + Temp scratch = scratch_begin(0, 0); + + // arrange options + char *binary = 0; + char **args = 0; + if (options->cmd_line.node_count > 0){ + args = push_array_no_zero(scratch.arena, char*, options->cmd_line.node_count + 1); + char **arg_ptr = args; + for (String8Node *node = options->cmd_line.first; + node != 0; + node = node->next, arg_ptr += 1){ + String8 string = push_str8_copy(scratch.arena, node->string); + *arg_ptr = (char*)string.str; + } + *arg_ptr = 0; + binary = args[0]; + } + + char *path = 0; + { + String8 string = push_str8_copy(scratch.arena, options->path); + path = (char*)string.str; + } + + char **env = 0; + if (options->env.node_count > 0){ + env = push_array_no_zero(scratch.arena, char*, options->env.node_count + 1); + char **env_ptr = env; + for (String8Node *node = options->env.first; + node != 0; + node = node->next, env_ptr += 1){ + String8 string = push_str8_copy(scratch.arena, node->string); + *env_ptr = (char*)string.str; + } + *env_ptr = 0; + } + + // fork + if (binary != 0){ + pid_t pid = fork(); + if (pid == -1){ + // TODO(allen): fork error + } + else if (pid == 0){ + // NOTE(allen): child process + int ptrace_result = ptrace(PTRACE_TRACEME, 0, 0, 0); + if (ptrace_result != -1){ + int chdir_result = chdir(path); + if (chdir_result != -1){ + execve(binary, args, env); + } + } + // failed to init fully; abort so the parent can clean up the child + abort(); + } + else{ + // NOTE(allen): parent process + + // wait for child + int status = 0; + pid_t wait_id = waitpid(pid, &status, __WALL); + + // determine child launch status + enum{ + LaunchCode_Null, + LaunchCode_FailBeforePtrace, + LaunchCode_FailAfterPtrace, + LaunchCode_Success, + }; + U32 launch_result = LaunchCode_Null; + // NOTE(allen): if wait_id != pid we don't know what that means; study that case before + // deciding how error handling around it works. + if (wait_id == pid){ + if (WIFSTOPPED(status)){ + if (WSTOPSIG(status) == SIGTRAP){ + launch_result = LaunchCode_Success; + } + else{ + launch_result = LaunchCode_FailAfterPtrace; + } + } + else{ + launch_result = LaunchCode_FailBeforePtrace; + } + } + + // handle launch result + switch (launch_result){ + default: + { + // TODO(allen): error that we do not understand + }break; + + case LaunchCode_FailBeforePtrace: + { + // TODO(allen): child ptrace init failed + }break; + + case LaunchCode_FailAfterPtrace: + { + // need to specifically pull the exit status out of the child + // or it will sit around as a zombie forever since it is ptraced. + B32 cleanup_good = false; + int detach_result = ptrace(PTRACE_DETACH, pid, 0, (void*)SIGCONT); + if (detach_result != -1){ + int status_cleanup = 0; + pid_t wait_id_cleanup = waitpid(pid, &status_cleanup, __WALL); + if (wait_id_cleanup == pid){ + cleanup_good = true; + } + } + if (cleanup_good){ + // TODO(allen): child init failed + } + else{ + // TODO(allen): child init failed; something went wrong and a process may have leaked + } + }break; + + case LaunchCode_Success: + { + int setoptions_result = ptrace(PTRACE_SETOPTIONS, pid, 0, PtrFromInt(demon_lnx_ptrace_options)); + if (setoptions_result == -1){ + // TODO(allen): ptrace setup failed; need to kill the child and clean it up + } + else{ + result = pid; + + Architecture arch = demon_lnx_arch_from_pid(pid); + + // process entity + DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, pid); + demon_proc_count += 1; + process->arch = arch; + process->ext_u64 = demon_lnx_open_memory_fd_for_pid(pid); + + // thread entity + DEMON_Entity *thread = demon_ent_new(process, DEMON_EntityKind_Thread, pid); + demon_thread_count += 1; + + // process event + { + DEMON_Event *e = demon_push_event(demon_lnx_event_arena, &demon_lnx_queued_events, + DEMON_EventKind_CreateProcess); + e->process = demon_ent_handle_from_ptr(process); + } + + // thread event + { + DEMON_Event *e = demon_push_event(demon_lnx_event_arena, &demon_lnx_queued_events, + DEMON_EventKind_CreateThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + } + + // get module list + DEMON_LNX_ModuleNode *module_list = demon_lnx_module_list_from_process(scratch.arena, process); + + // for each module ... + for (DEMON_LNX_ModuleNode *node = module_list; + node != 0; + node = node->next){ + // module entity + DEMON_Entity *module = demon_ent_new(process, DEMON_EntityKind_Module, node->vaddr); + demon_module_count += 1; + module->ext_u64 = node->name; + + // event + { + DEMON_Event *e = demon_push_event(demon_lnx_event_arena, &demon_lnx_queued_events, + DEMON_EventKind_LoadModule); + e->process = demon_ent_handle_from_ptr(process); + e->module = demon_ent_handle_from_ptr(module); + e->address = node->vaddr; + e->size = node->size; + } + } + + // handshake event + { + DEMON_Event *e = demon_push_event(demon_lnx_event_arena, &demon_lnx_queued_events, + DEMON_EventKind_HandshakeComplete); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + } + } + }break; + } + } + } + + scratch_end(scratch); + return(result); +} + +internal B32 +demon_os_attach_process(U32 pid){ + B32 result = false; + + Temp scratch = scratch_begin(0, 0); + DEMON_LNX_AttachNode *attachments = 0; + DEMON_LNX_AttachNode *the_process = 0; + + // TODO(allen): double check that this logic only lets us + // "attach" when pid is the id of the main thread of a process. + + // attach this process + B32 attached_proc = false; + if (kill(pid, 0) == -1){ + // TODO(allen): process does not exist + } + else{ + attached_proc = demon_lnx_attach_pid(scratch.arena, pid, &the_process); + if (the_process != 0){ + SLLStackPush(attachments, the_process); + } + } + + // open thread list + if (attached_proc){ + String8 threads_path = push_str8f(scratch.arena, "/proc/%d/task", pid); + DIR *proc_dir = opendir((char*)threads_path.str); + if (proc_dir == 0){ + // TODO(allen): could not read proc threads somehow; no good! + } + else{ + + // attach all threads + B32 attached_all_threads = true; + for (;;){ + struct dirent *entry = readdir(proc_dir); + if (entry == 0){ + break; + } + + String8 name = str8_cstring(entry->d_name); + if (str8_is_integer(name, 10)){ + pid_t tid = u64_from_str8(name, 10); + if (tid != pid){ + DEMON_LNX_AttachNode *new_attachment = 0; + B32 attached_this_thread = demon_lnx_attach_pid(scratch.arena, tid, &new_attachment); + if (new_attachment != 0){ + SLLStackPush(attachments, new_attachment); + } + if (!attached_this_thread){ + attached_all_threads = false; + break; + } + } + } + } + closedir(proc_dir); + + if (attached_all_threads){ + result = true; + } + } + } + + // initialize new entities on success + if (result){ + Architecture arch = demon_lnx_arch_from_pid(the_process->pid); + + // process entity + DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, the_process->pid); + demon_proc_count += 1; + process->arch = arch; + process->ext_u64 = demon_lnx_open_memory_fd_for_pid(the_process->pid); + + // process event + { + DEMON_Event *e = demon_push_event(demon_lnx_event_arena, &demon_lnx_queued_events, + DEMON_EventKind_CreateProcess); + e->process = demon_ent_handle_from_ptr(process); + } + + // TODO(allen): happens on windows here? + + for (DEMON_LNX_AttachNode *node = attachments; + node != 0; + node = node->next){ + DEMON_Entity *thread = demon_ent_new(process, DEMON_EntityKind_Thread, node->pid); + demon_thread_count += 1; + + // thread event + { + DEMON_Event *e = demon_push_event(demon_lnx_event_arena, &demon_lnx_queued_events, + DEMON_EventKind_CreateThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + } + } + + // TODO(allen): sync modules in process + } + + // cleanup on failure + else{ + for (DEMON_LNX_AttachNode *node = attachments; + node != 0; + node = node->next){ + ptrace(PTRACE_DETACH, node->pid, 0, (void*)SIGCONT); + } + } + + scratch_end(scratch); + return(result); +} + +internal B32 +demon_os_kill_process(DEMON_Entity *process, U32 exit_code){ + B32 result = false; + if (process != 0){ + if (kill(process->id, SIGKILL) != -1){ + result = true; + } + } + return(result); +} + +internal B32 +demon_os_detach_process(DEMON_Entity *process){ + B32 result = false; + if (process != 0){ + int detach_result = ptrace(PTRACE_DETACH, process->id, 0, 0); + result = (detach_result != -1); + } + return(0); +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Entity Functions + +//- rjf: cleanup + +internal void +demon_os_entity_cleanup(DEMON_Entity *entity) +{ + // NOTE(rjf): no-op +} + +//- rjf: introspection + +internal String8 +demon_os_full_path_from_module(Arena *arena, DEMON_Entity *module){ + DEMON_Entity *process = module->parent; + int memory_fd = (int)process->ext_u64; + U64 name_va = module->ext_u64; + String8 result = demon_lnx_read_memory_str(arena, memory_fd, name_va); + return(result); +} + +internal U64 +demon_os_stack_base_vaddr_from_thread(DEMON_Entity *thread){ + Temp scratch = scratch_begin(0, 0); + + U64 stack_base = 0; + + DEMON_Entity *process = thread->parent; + + // id for main thread is zero + B32 is_main_thread = (thread->id == process->id); + pid_t match_tid = is_main_thread ? 0 : thread->id; + + // open /proc/$pid/maps + int maps = demon_lnx_open_maps(process->id); + + // look for entry with stack markings and matching thread id + for (;;){ + DEMON_LNX_MapsEntry e; + Temp temp = temp_begin(scratch.arena); + if (!demon_lnx_next_map(temp.arena, maps, &e)){ + break; + } + if (e.type == DEMON_LNX_MapsEntryType_Stack && e.stack_tid == match_tid){ + stack_base = e.address_lo; + break; + } + temp_end(temp); + } + + scratch_end(scratch); + return(stack_base); +} + +internal U64 +demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread){ + U64 result = 0; + switch (thread->arch){ + case Architecture_x64: + case Architecture_x86: + { + U32 fsbase = 0; + pid_t tid = (pid_t)thread->id; + if (ptrace(PT_GETFSBASE, tid, (void*)&fsbase, 0) != -1){ + result = (U64)fsbase; + } + if (thread->arch == Architecture_x64){ + result += 8; + } + else{ + result += 4; + } + }break; + } + return(result); +} + +//- rjf: target process memory allocation/protection + +internal U64 +demon_os_reserve_memory(DEMON_Entity *process, U64 size){ + U64 result = 0; + NotImplemented; + return(result); +} + +internal void +demon_os_set_memory_protect_flags(DEMON_Entity *process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags){ + NotImplemented; +} + +internal void +demon_os_release_memory(DEMON_Entity *process, U64 vaddr, U64 size){ + NotImplemented; +} + +//- rjf: target process memory reading/writing + +internal U64 +demon_os_read_memory(DEMON_Entity *process, void *dst, U64 src_address, U64 size){ + int memory_fd = (int)process->ext_u64; + U64 result = demon_lnx_read_memory(memory_fd, dst, src_address, size); + return(result); +} + +internal B32 +demon_os_write_memory(DEMON_Entity *process, U64 dst_address, void *src, U64 size){ + int memory_fd = (int)process->ext_u64; + B32 result = demon_lnx_write_memory(memory_fd, dst_address, src, size); + return(result); +} + +//- rjf: thread registers reading/writing + +internal B32 +demon_os_read_regs_x86(DEMON_Entity *thread, SYMS_RegX86 *dst){ + B32 result = false; + NotImplemented; + return(result); +} + +internal B32 +demon_os_write_regs_x86(DEMON_Entity *thread, SYMS_RegX86 *src){ + B32 result = false; + NotImplemented; + return(result); +} + +internal B32 +demon_os_read_regs_x64(DEMON_Entity *thread, SYMS_RegX64 *dst){ + pid_t tid = (pid_t)thread->id; + + // gpr + B32 got_gpr = false; + DEMON_LNX_UserX64 ctx = {0}; + struct iovec iov_gpr = {0}; + iov_gpr.iov_len = sizeof(ctx); + iov_gpr.iov_base = &ctx; + if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &iov_gpr) != -1){ + demon_lnx_regs_x64_from_usr_regs_x64(dst, &ctx.regs); + got_gpr = true; + } + + // fpr + B32 got_fpr = false; + if (got_gpr){ + B32 got_xsave = false; + { + U8 xsave_buffer[KB(4)]; + struct iovec iov_xsave = {0}; + iov_xsave.iov_len = sizeof(xsave_buffer); + iov_xsave.iov_base = xsave_buffer; + if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_X86_XSTATE, &iov_xsave) != -1){ + SYMS_XSave *xsave = (SYMS_XSave*)xsave_buffer; + syms_x64_regs__set_full_regs_from_xsave_legacy(dst, &xsave->legacy); + + // TODO(allen): this is a lie; ymm can technically move around + // we need some more low-level-assembly-fu to do this hardcore. + B32 has_ymm_registers = ((xsave->header.xstate_bv & 4) != 0); + if (has_ymm_registers){ + syms_x64_regs__set_full_regs_from_xsave_avx_extension(dst, xsave->ymmh); + } + + got_xsave = true; + } + } + + B32 got_fxsave = false; + if (!got_xsave){ + SYMS_XSaveLegacy fxsave = {0}; + struct iovec iov_fxsave = {0}; + iov_fxsave.iov_len = sizeof(fxsave); + iov_fxsave.iov_base = &fxsave; + if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, &iov_fxsave) != -1){ + syms_x64_regs__set_full_regs_from_xsave_legacy(dst, &fxsave); + got_fxsave = true; + } + } + + if (got_xsave || got_fxsave){ + got_fpr = true; + } + } + + // debug + B32 got_debug = false; + if (got_fpr){ + got_debug = true; + SYMS_Reg32 *dr_d = &dst->dr0; + for (U32 i = 0; i < 8; i += 1, dr_d += 1){ + if (i != 4 && i != 5){ + U64 offset = OffsetOf(DEMON_LNX_UserX64, u_debugreg[i]); + errno = 0; + int peek_result = ptrace(PTRACE_PEEKUSER, tid, PtrFromInt(offset), 0); + if (errno == 0){ + dr_d->u32 = (U32)peek_result; + } + else{ + got_debug = false; + } + } + } + } + + // got everything + B32 result = got_debug; + return(result); +} + +internal B32 +demon_os_write_regs_x64(DEMON_Entity *thread, SYMS_RegX64 *src){ + pid_t tid = (pid_t)thread->id; + + // gpr + DEMON_LNX_UserX64 ctx = {0}; + demon_lnx_usr_regs_x64_from_regs_x64(&ctx.regs, src); + + struct iovec iov_gpr = {0}; + iov_gpr.iov_base = &ctx; + iov_gpr.iov_len = sizeof(ctx); + int gpr_result = ptrace(PTRACE_SETREGSET, tid, (void*)NT_PRSTATUS, &iov_gpr); + B32 gpr_success = (gpr_result != -1); + + // fpr + int xsave_result = 0; + int fxsave_result = 0; + + { + U8 xsave_buffer[KB(4)] = {0}; + SYMS_XSave *xsave = (SYMS_XSave*)xsave_buffer; + syms_x64_regs__set_xsave_legacy_from_full_regs(&xsave->legacy, src); + + xsave->header.xstate_bv = 7; + + // TODO(allen): this is a lie; ymm can technically move around + // we need some more low-level-assembly-fu to do this hardcore. + syms_x64_regs__set_xsave_avx_extension_from_full_regs(xsave->ymmh, src); + + { + struct iovec iov_xsave = {0}; + iov_xsave.iov_base = &xsave; + iov_xsave.iov_len = sizeof(xsave); + xsave_result = ptrace(PTRACE_SETREGSET, tid, (void*)NT_X86_XSTATE, &iov_xsave); + } + + if (xsave_result == -1){ + struct iovec iov_fxsave = {0}; + iov_fxsave.iov_base = &xsave->legacy; + iov_fxsave.iov_len = sizeof(xsave->legacy); + fxsave_result = ptrace(PTRACE_SETREGSET, tid, (void*)NT_FPREGSET, &iov_fxsave); + } + } + + B32 fpr_success = (xsave_result != -1 || fxsave_result != -1); + + // debug + B32 dr_success = true; + { + SYMS_Reg32 *dr_s = &src->dr0; + for (U32 i = 0; i < 8; i += 1, dr_s += 1){ + if (i != 4 && i != 5){ + U64 offset = OffsetOf(DEMON_LNX_UserX64, u_debugreg[i]); + errno = 0; + int poke_result = ptrace(PTRACE_POKEUSER, tid, PtrFromInt(offset), dr_s->u32); + if (poke_result == -1){ + dr_success = false; + } + } + } + } + + // assemble result + B32 result = (gpr_success && fpr_success && dr_success); + + return(result); +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Process Listing + +internal void +demon_os_proc_iter_begin(DEMON_ProcessIter *iter){ + DIR *dir = opendir("/proc"); + MemoryZeroStruct(iter); + iter->v[0] = IntFromPtr(dir); +} + +internal B32 +demon_os_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out){ + // scan for a process id + B32 got_pid = false; + String8 pid_string = {0}; + + DIR *dir = (DIR*)PtrFromInt(iter->v[0]); + if (dir != 0 && iter->v[1] == 0){ + for (;;){ + struct dirent *d = readdir(dir); + if (d == 0){ + break; + } + + // check file name is integer + String8 file_name = str8_cstring((char*)d->d_name); + B32 is_integer = str8_is_integer(file_name, 10); + + // break on integers (which represent processes) + if (is_integer){ + got_pid = true; + pid_string = file_name; + break; + } + } + } + + // mark iterator dead if nothing found + if (!got_pid){ + iter->v[1] = 1; + } + + // if got process id convert pid -> process info + B32 result = false; + if (got_pid){ + // determine the name we will report + pid_t pid = u64_from_str8(pid_string, 10); + String8 name = demon_lnx_executable_path_from_pid(arena, pid); + if (name.size == 0){ + name = str8_lit(""); + } + + // finish conversion + info_out->name = name; + info_out->pid = pid; + result = true; + } + + return(result); +} + +internal void +demon_os_proc_iter_end(DEMON_ProcessIter *iter){ + DIR *dir = (DIR*)PtrFromInt(iter->v[0]); + if (dir != 0){ + closedir(dir); + } + MemoryZeroStruct(iter); +} diff --git a/src/demon/linux/demon_os_linux.h b/src/demon/linux/demon_os_linux.h new file mode 100644 index 00000000..4e039e35 --- /dev/null +++ b/src/demon/linux/demon_os_linux.h @@ -0,0 +1,222 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_OS_LINUX_H +#define DEMON_OS_LINUX_H + +// TODO(allen): Potential Upgrades: +// +// memory fd upgrade - Right now for each process we hold open a file +// descriptor for the process's memory (/proc/%d/mem) for the entire lifetime +// of the process; it could be opened and closed with some kind of LRU cache +// to put a finite cap on the number of handles the demon holds +// + +//////////////////////////////// +//~ NOTE(allen): Get The Linux Includes + +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////// +//~ NOTE(allen): Linux Demon Types + +//- entities + +// Demon Linux Entity Extensions +// Process: ext_u64 set to memory file descriptor +// Thread : ext_u64 cast to DEMON_LNX_ThreadExt +// Module : ext_u64 set to U64 (address of name) + +struct DEMON_LNX_ThreadExt{ + B32 expecting_dummy_sigstop; +}; +StaticAssert(sizeof(DEMON_LNX_ThreadExt) <= sizeof(Member(DEMON_Entity, ext_u64)), check_demon_lnx_thread_ext); + +//- helpers + +struct DEMON_LNX_AttachNode{ + DEMON_LNX_AttachNode *next; + pid_t pid; +}; + +struct DEMON_LNX_ProcessAux{ + B32 filled; + U64 phnum; + U64 phent; + U64 phdr; + U64 execfn; +}; + +struct DEMON_LNX_PhdrInfo{ + Rng1U64 range; + U64 dynamic; +}; + +struct DEMON_LNX_ModuleNode{ + DEMON_LNX_ModuleNode *next; + U64 vaddr; + U64 size; + U64 name; + U64 already_known; +}; + +struct DEMON_LNX_EntityNode{ + DEMON_LNX_EntityNode *next; + DEMON_Entity *entity; +}; + +//////////////////////////////// +//~ NOTE(allen): Linux Demon Register Layouts + +// these are defined in but only for one architecture at a time +// (and we can't really trick it into giving us both in any obvious way) +// we define them here so that we have them all "at once" + +struct DEMON_LNX_UserRegsX64{ + U64 r15; + U64 r14; + U64 r13; + U64 r12; + U64 rbp; + U64 rbx; + U64 r11; + U64 r10; + U64 r9; + U64 r8; + U64 rax; + U64 rcx; + U64 rdx; + U64 rsi; + U64 rdi; + U64 orig_rax; + U64 rip; + U64 cs; + U64 rflags; + U64 rsp; + U64 ss; + U64 fsbase; + U64 gsbase; + U64 ds; + U64 es; + U64 fs; + U64 gs; +}; + +struct DEMON_LNX_UserX64{ + DEMON_LNX_UserRegsX64 regs; + S32 u_fpvalid, _pad0; + SYMS_XSaveLegacy i387; + U64 u_tsize, u_dsize, u_ssize, start_code, start_stack; + U64 signal; + S32 reserved, _pad1; + U64 u_ar0, u_fpstate; + U64 magic; + U8 u_comm[32]; + U64 u_debugreg[8]; +}; + +struct DEMON_LNX_UserRegsX86{ + U32 ebx; + U32 ecx; + U32 edx; + U32 esi; + U32 edi; + U32 ebp; + U32 eax; + U32 ds; + U32 es; + U32 fs; + U32 gs; + U32 orig_eax; + U32 eip; + U32 cs; + U32 eflags; + U32 sp; + U32 ss; +}; + +struct DEMON_LNX_UserX86{ + DEMON_LNX_UserRegsX86 regs; + S32 u_fpvalid; + SYMS_FSave i387; + U32 u_tsize, u_dsize, u_ssize, start_code, start_stack; + S32 signal, reserved; + U32 u_ar0, u_fpstate; + U32 magic; + U8 u_comm[32]; + U32 u_debugreg[8]; +}; + +//////////////////////////////// + +enum +{ + DEMON_LNX_PermFlags_Read = (1 << 0), + DEMON_LNX_PermFlags_Write = (1 << 1), + DEMON_LNX_PermFlags_Exec = (1 << 2), + DEMON_LNX_PermFlags_Private = (1 << 3) +}; +typedef int DEMON_LNX_PermFlags; + +enum +{ + DEMON_LNX_MapsEntryType_Null, + DEMON_LNX_MapsEntryType_Path, + DEMON_LNX_MapsEntryType_Heap, + DEMON_LNX_MapsEntryType_Stack, + DEMON_LNX_MapsEntryType_VDSO, +}; +typedef int DEMON_LNX_MapsEntryType; + +struct DEMON_LNX_MapsEntry +{ + U64 address_lo; + U64 address_hi; + DEMON_LNX_PermFlags perms; + U64 offset; + U32 dev_major; + U32 dev_minor; + U64 inode; + String8 pathname; + DEMON_LNX_MapsEntryType type; + pid_t stack_tid; +}; + +//////////////////////////////// +//~ rjf: Helpers + +internal DEMON_LNX_ThreadExt* demon_lnx_thread_ext(DEMON_Entity *entity); + +internal B32 demon_lnx_attach_pid(Arena *arena, pid_t pid, DEMON_LNX_AttachNode **new_node); + +internal String8 demon_lnx_executable_path_from_pid(Arena *arena, pid_t pid); +internal int demon_lnx_open_memory_fd_for_pid(pid_t pid); + +internal Architecture demon_lnx_arch_from_pid(pid_t pid); +internal DEMON_LNX_ProcessAux demon_lnx_aux_from_pid(pid_t pid, Architecture arch); +internal DEMON_LNX_PhdrInfo demon_lnx_phdr_info_from_memory(int memory_fd, B32 is_32bit, + U64 phvaddr, U64 phstride, U64 phcount); +internal DEMON_LNX_ModuleNode* demon_lnx_module_list_from_process(Arena *arena, DEMON_Entity *process); + +internal U64 demon_lnx_read_memory(int memory_fd, void *dst, U64 src, U64 size); +internal B32 demon_lnx_write_memory(int memory_fd, U64 dst, void *src, U64 size); +internal String8 demon_lnx_read_memory_str(Arena *arena, int memory_fd, U64 address); + +internal void demon_lnx_regs_x64_from_usr_regs_x64(SYMS_RegX64 *dst, DEMON_LNX_UserRegsX64 *src); +internal void demon_lnx_usr_regs_x64_from_regs_x64(DEMON_LNX_UserRegsX64 *dst, SYMS_RegX64 *src); + +internal String8 demon_lnx_read_int_string(int fd); +internal B32 demon_lnx_read_expect(int fd, char expect); +internal int demon_lnx_read_whitespace(int fd); +internal String8 demon_lnx_read_string(Arena *arena, int fd); + +internal int demon_lnx_open_maps(pid_t pid); +internal B32 demon_lnx_next_map(Arena *arena, int maps, DEMON_LNX_MapsEntry *entry_out); + +#endif //DEMON_OS_LINUX_H diff --git a/src/demon/test/demon_attach.cpp b/src/demon/test/demon_attach.cpp new file mode 100644 index 00000000..ca9fb1ea --- /dev/null +++ b/src/demon/test/demon_attach.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +// exe // + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "demon/demon_inc.h" +#include "syms_helpers/syms_internal_overrides.h" +#include "syms/syms_inc.h" +#include "syms_helpers/syms_helpers.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "demon/demon_inc.c" +#include "syms_helpers/syms_internal_overrides.c" +#include "syms/syms_inc.c" +#include "syms_helpers/syms_helpers.c" + +int +main(int argument_count, char **arguments) +{ + os_init(argument_count, arguments); + Arena *arena = arena_alloc(); + demon_init(); + + //- rjf: find PID of mule_loop.exe + String8 attach_process_name = str8_lit("mule_loop.exe"); + U32 pid = 0; + { + DEMON_ProcessIter it = {0}; + demon_proc_iter_begin(&it); + for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(arena, &it, &info);) + { + if(str8_match(info.name, attach_process_name, 0)) + { + pid = info.pid; + break; + } + } + demon_proc_iter_end(&it); + } + + //- rjf: attach + B32 attach_good = demon_attach_process(pid); + + //- rjf: get events + DEMON_RunCtrls ctrls = {0}; + DEMON_EventList events = demon_run(arena, ctrls); + for(DEMON_Event *event = events.first; event != 0; event = event->next) + { + int x = 0; + } + +#if 0 + //- rjf: try to break in the loop + DEMON_RunCtrls ctrls = {0}; + DEMON_Trap trap = {0}; + { + U64 loop_bp = 0x0000000140001074; + ctrls.trap_count = 1; + ctrls.traps = &trap; + } +#endif +} diff --git a/src/demon/test/demon_regs_test.cpp b/src/demon/test/demon_regs_test.cpp new file mode 100644 index 00000000..c5ef06b5 --- /dev/null +++ b/src/demon/test/demon_regs_test.cpp @@ -0,0 +1,166 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "demon/demon_inc.h" +#include "syms_helpers/syms_internal_overrides.h" +#include "syms/syms_inc.h" +#include "syms_helpers/syms_helpers.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "demon/demon_inc.c" +#include "syms_helpers/syms_internal_overrides.c" +#include "syms/syms_inc.c" +#include "syms_helpers/syms_helpers.c" + +internal SYMS_String8 +file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){ + String8 data = os_read_file(arena, str8_from_syms(file_name)); + SYMS_String8 result = syms_from_str8(data); + return(result); +} + +int +main(int argument_count, char **arguments) +{ + os_init(argument_count, arguments); + Temp scratch = scratch_begin(0, 0); + + // setup + demon_init(); + + // parse arguments + String8 executable_file_name = {0}; + U64 bp_address = 0; + + { + String8List command_line_arguments = os_get_command_line_arguments(); + CmdLine cmd_line = cmd_line_from_string_list(scratch.arena, command_line_arguments); + if (cmd_line.inputs.first != 0){ + executable_file_name = cmd_line.inputs.first->string; + } + String8 bp_string = cmd_line_string(cmd_line, str8_lit("bp")); + try_u64_from_str8_c_rules(bp_string, &bp_address); + } + + // check parameters + if (bp_address == 0 || executable_file_name.size == 0){ + printf("bad parameters\n"); + exit(0); + } + + // demon launch + OS_LaunchOptions launch_opts = {0}; + str8_list_push(scratch.arena, &launch_opts.cmd_line, executable_file_name); + launch_opts.path = os_get_path(scratch.arena, OS_SystemPath_Current); + U32 process_id = demon_launch_process(&launch_opts); + if (process_id == 0){ + printf("could not launch: '%.*s'\n", str8_varg(executable_file_name)); + exit(0); + } + + // demon loop + { + DEMON_Handle process = 0; + DEMON_Handle thread = 0; + + B32 hit_bp = false; + U64 single_step_counter = 0; + + U64 counter = 0; + for (;;){ + Temp temp = temp_begin(scratch.arena); + + DEMON_RunCtrls run_controls = {0}; + DEMON_Trap traps[1]; + + if (!hit_bp){ + if (process != 0){ + run_controls.trap_count = 1; + run_controls.traps = traps; + run_controls.traps[0].process = process; + run_controls.traps[0].address = bp_address; + } + } + else{ + run_controls.single_step_thread = thread; + } + + DEMON_EventList events = demon_run(temp.arena, run_controls); + + for (DEMON_Event *event = events.first; + event != 0; + event = event->next, counter += 1){ + // update tracking state + switch (event->kind){ + case DEMON_EventKind_CreateProcess: + { + process = event->process; + }break; + + case DEMON_EventKind_ExitProcess: + { + if (event->process == process){ + process = 0; + } + }break; + + case DEMON_EventKind_CreateThread: + { + thread = event->thread; + }break; + + case DEMON_EventKind_Breakpoint: + { + hit_bp = true; + }break; + + case DEMON_EventKind_SingleStep: + { + single_step_counter += 1; + + SYMS_RegX64 regs1 = {0}; + demon_read_x64_regs(thread, ®s1); + demon_write_x64_regs(thread, ®s1); + SYMS_RegX64 regs2 = {0}; + demon_read_x64_regs(thread, ®s2); + if (!MemoryMatchStruct(®s1, ®s2)){ + printf("mismatch at single_step_counter=%llu\n", single_step_counter); + } + + if (single_step_counter == 1000){ + goto end_loop; + } + }break; + + case DEMON_EventKind_NotAttached: + { + fprintf(stderr, "not attached - exiting\n"); + goto end_loop; + }break; + + case DEMON_EventKind_NotInitialized: + case DEMON_EventKind_UnexpectedFailure: + { + fprintf(stderr, "unexpected error - exiting\n"); + goto end_loop; + }break; + } + } + + goto end_it; + end_loop: + temp_end(temp); + goto loop_exit; + end_it:; + } + + loop_exit:; + } + + printf("[done]\n"); + scratch_end(scratch); +} + diff --git a/src/demon/test/demon_scratch.cpp b/src/demon/test/demon_scratch.cpp new file mode 100644 index 00000000..beb1cc40 --- /dev/null +++ b/src/demon/test/demon_scratch.cpp @@ -0,0 +1,250 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "demon/demon_inc.h" +#include "syms_helpers/syms_internal_overrides.h" +#include "syms/syms_inc.h" +#include "syms_helpers/syms_helpers.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "demon/demon_inc.c" +#include "syms_helpers/syms_internal_overrides.c" +#include "syms/syms_inc.c" +#include "syms_helpers/syms_helpers.c" + +internal SYMS_String8 +file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){ + String8 data = os_read_file(arena, str8_from_syms(file_name)); + SYMS_String8 result = syms_from_str8(data); + return(result); +} + +int +main(int argument_count, char **arguments) +{ + os_init(argument_count, arguments); + demon_init(); + + String8Node node[2]; + +#define TARGET_EXE "C:\\devel\\projects\\debugger\\build\\mule_unwind_20210511_clang11_lldlink.exe" + + OS_LaunchOptions options = {0}; +#if OS_WINDOWS + str8_list_push(&options.cmd_line, &node[0], str8_lit(TARGET_EXE)); + options.path = str8_lit("C:\\devel\\projects\\debugger\\build\\"); +#else + str8_list_push(&options.cmd_line, &node[0], str8_lit("/home/allenw/projects_copy/debugger/build/mule_main")); + options.path = str8_lit("/home/allenw/projects_copy/debugger/build/"); +#endif + U32 process_id = demon_launch_process(&options); + if (process_id == 0){ + printf("Could not launch process\n"); + exit(1); + } + +#if OS_WINDOWS + U64 bp_addr = 0x140001134; +#else + U64 bp_addr = 0x400918; +#endif + + DEMON_Handle process = 0; + DEMON_Handle thread = 0; + DEMON_Handle module = 0; + U64 module_base = 0; + SYMS_Group *group = 0; + + B32 hit_bp = false; + U64 counter = 0; + + for (;;){ + DEMON_RunCtrls run_controls = {0}; + DEMON_Trap trap_memory[2]; + + DEMON_Trap *trap_ptr = trap_memory; + if (process != 0 && !hit_bp){ + trap_ptr->process = process; + trap_ptr->address = bp_addr; + trap_ptr += 1; + } + run_controls.traps = trap_memory; + run_controls.trap_count = (U64)(trap_ptr - trap_memory); + + Temp scratch = scratch_begin(0, 0); + DEMON_EventList events = demon_run(scratch.arena, run_controls); + + for (DEMON_Event *event = events.first; + event != 0; + event = event->next){ + printf("STEP[%05llx] -- ", counter); + counter += 1; + + switch (event->kind){ + case DEMON_EventKind_NotInitialized: + { + printf("Not Initialized\n"); + exit(1); + }break; + + case DEMON_EventKind_NotAttached: + { + printf("Not Attached\n"); + exit(1); + }break; + + case DEMON_EventKind_UnexpectedFailure: + { + printf("Unexpected Failure\n"); + exit(1); + }break; + + case DEMON_EventKind_CreateProcess: + { + printf("Create Process\n"); + if (process == 0){ + process = event->process; + } + }break; + + case DEMON_EventKind_CreateThread: + { + printf("Create Thread\n"); + if (thread == 0){ + thread = event->thread; + } + }break; + + case DEMON_EventKind_LoadModule: + { + Temp temp = temp_begin(scratch.arena); + String8 file_name = demon_full_path_from_module(scratch.arena, event->module); + printf("Load Module: %.*s\n", str8_varg(file_name)); + if (module == 0 && str8_match(file_name, str8_lit(TARGET_EXE), 0)){ + module = event->module; + module_base = event->address; + + // setup syms group + group = syms_group_alloc(); + + SYMS_FileLoadCtx ctx = {0}; + ctx.file_load_func = file_load_func_for_syms; + + SYMS_String8List file_names = {0}; + syms_string_list_push(group->arena, &file_names, syms_from_str8(file_name)); + + SYMS_FileInfOptions opts = {0}; + + SYMS_FileInfResult inf_result = syms_file_inf_infer_from_file_list(group->arena, ctx, file_names, &opts); + syms_group_init(group, &inf_result.data_parsed); + } + temp_end(temp); + }break; + + case DEMON_EventKind_ExitProcess: + { + printf("Exit Process\n"); + exit(0); + }break; + + case DEMON_EventKind_ExitThread: + { + printf("Exit Thread\n"); + }break; + + case DEMON_EventKind_UnloadModule: + { + printf("Unload Module\n"); + }break; + + case DEMON_EventKind_Breakpoint: + { + Architecture arch = demon_arch_from_object(event->process); + U64 ip = event->instruction_pointer; + printf("Breakpoint: %llx\n", ip); + + hit_bp = true; + + //- unwind + + // setup bin + SYMS_String8 bin_data = group->bin_data; + SYMS_BinAccel *generic_bin = group->bin; + SYMS_PeBinAccel *pe_bin = 0; + if (generic_bin->format == SYMS_FileFormat_PE){ + pe_bin = (SYMS_PeBinAccel*)generic_bin; + } + + if (pe_bin != 0){ + // read regs + SYMS_RegX64 regs = {0}; + demon_read_x64_regs(event->thread, ®s); + + // read stack + SYMS_U64 sp = regs.rsp.u64; + SYMS_U64 sp_rounded_down = sp&~(KB(4) - 1); + + SYMS_String8 stack_memory = {0}; + stack_memory.size = KB(8); + stack_memory.str = push_array_no_zero(scratch.arena, U8, stack_memory.size); + + SYMS_U64 stack_memory_addr = sp_rounded_down; + stack_memory.size = demon_read_memory_amap(event->process, stack_memory.str, + stack_memory_addr, stack_memory.size); + + // unwind loop + U64 counter = 1; + for (;; counter += 1){ + printf("%02llu: ip=%llx; sp=%llx\n", counter, regs.rip.u64, regs.rsp.u64); + SYMS_MemoryView memview = syms_memory_view_make(stack_memory, stack_memory_addr); + SYMS_UnwindResult unwind_result = syms_unwind_pe_x64(bin_data, pe_bin, module_base, &memview, ®s); + if (unwind_result.dead){ + break; + } + } + } + }break; + + case DEMON_EventKind_Trap: + { + Architecture arch = demon_arch_from_object(event->process); + U64 ip = event->instruction_pointer; + printf("Trap: %llx\n", ip); + }break; + + case DEMON_EventKind_SingleStep: + { + printf("Single Step: %llx\n", event->instruction_pointer); + }break; + + case DEMON_EventKind_Exception: + { + printf("Exception: %llx\n", event->instruction_pointer); + }break; + + case DEMON_EventKind_Halt: + { + printf("Halt\n"); + }break; + + case DEMON_EventKind_Memory: + { + printf("Memory\n"); + }break; + + default: + { + printf("Unhandled Event\n"); + exit(1); + }break; + } + } + scratch_end(scratch); + } + + printf("Done\n"); +} + diff --git a/src/demon/test/demon_win32_freeze_test.cpp b/src/demon/test/demon_win32_freeze_test.cpp new file mode 100644 index 00000000..86b564ba --- /dev/null +++ b/src/demon/test/demon_win32_freeze_test.cpp @@ -0,0 +1,935 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +// NOTE(rjf): (18 October 2021) Notes on Win32 process halting via +// DebugBreakProcess: +// +// Calling DebugBreakProcess seems to cause a few events to come back: +// 1. Thread Creation Event +// 2. Breakpoint Event (with the thread matching that of #1) +// 3. Thread Exiting Event (matching #1) +// +// Having done this experiment on a single-threaded program (mule_loop.exe), +// I can only infer that what is happening here is that when DebugBreakProcess +// is called, it first injects a thread into the target process that runs +// code with an int3. This is very similar to the old approach that Demon +// took. +// +// It's going to be difficult to distinguish between these CreateThreads and +// ExitThreads from others (not caused by halting), even though we can match +// the hit breakpoint to the associated thread. +// +// What could be possible (in order to distinguish the hit breakpoint as a +// halt event, instead of an arbitrary breakpoint) is looking at the breakpoint +// address. This injected thread has a breakpoint that's different from the +// initial breakpoint that the kernel automatically hits when a process is +// first being debugged. +// +// With DebugBreakProcess: +// - first breakpoint that is hit: 0x7ff8ad9806b0 in kernel code +// - last breakpoint that is hit: 0x7ff8ad950860 in kernel code (halt) +// +// Without DebugBreakProcess: +// - first breakpoint that is hit: 0x7ff8ad9806b0 +// + +// NOTE(rjf): (18 October 2021) Notes on suspending processes via +// NtSuspendProcess: +// +// NtSuspendProcess is an undocumented API that is exported by ntdll. It is +// fairly simple but could be unstable. To call it, the main trick is that +// you need a handle with certain privileges (PROCESS_SUSPEND_RESUME), so +// you can't just take any handle and use it. +// +// To use it, we can manually load it from ntdll, grab an elevated handle +// for a given process HANDLE, and then call it. We can resume, then, with +// NtResumeProcess. +// +// Other than this, our options seem to more-or-less lie in individually +// suspending all of the threads in the process-to-be-halted. + +#include + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "syms_helpers/syms_internal_overrides.h" +#include "syms/syms_inc.h" +#include "syms_helpers/syms_helpers.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "syms_helpers/syms_internal_overrides.c" +#include "syms/syms_inc.c" +#include "syms_helpers/syms_helpers.c" + +typedef LONG NtSuspendProcessFunction(HANDLE ProcessHandle); +global NtSuspendProcessFunction *NtSuspendProcess = 0; + +//////////////////////////////// +// NOTE(allen): Win32 Demon Exceptions + +#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u +#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u +#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u +#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u +#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu +#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u +#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u +#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du +#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu +#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu +#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u +#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u +#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u +#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u +#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u +#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u +#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u +#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du +#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u +#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u +#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u +#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu +#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u +#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u +#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u +#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u +#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u +#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u +#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au +#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u +#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u +#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u +#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u +#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u +#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u +#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u +#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u +#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u + +//////////////////////////////// +// NOTE(allen): Win32 Demon Register API Codes + +#define DEMON_W32_CTX_X86 0x00010000 +#define DEMON_W32_CTX_X64 0x00100000 + +#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 +#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 +#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 +#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 +#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 +#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 +#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 + +#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ +DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ +DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ +DEMON_W32_CTX_INTEL_EXTENDED) +#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ +DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ +DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ +DEMON_W32_CTX_INTEL_DEBUG) + +struct TEST_DebugEvent +{ + String8 name; + U64 process_id; + U64 thread_id; + HANDLE process; + HANDLE thread; + U64 addr; + DEBUG_EVENT evt; +}; + +struct TEST_Trap +{ + HANDLE process; + U64 address; +}; + +internal U16 +test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) +{ + U16 result = 0; + U32 top = (fxsave->StatusWord >> 11) & 7; + for (U32 fpr = 0; fpr < 8; fpr += 1){ + U32 tag = 3; + if (fxsave->TagWord & (1 << fpr)){ + U32 st = (fpr - top)&7; + + SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16]; + U16 exponent = fp->sign1_exp15 & bitmask15; + U64 integer_part = fp->int1_frac63 >> 63; + U64 fraction_part = fp->int1_frac63 & bitmask63; + + // tag: 0 - normal; 1 - zero; 2 - special + tag = 2; + if (exponent == 0){ + if (integer_part == 0 && fraction_part == 0){ + tag = 1; + } + } + else if (exponent != bitmask15 && integer_part != 0){ + tag = 0; + } + } + result |= tag << (2 * fpr); + } + return(result); +} + +internal U16 +test_w32_xsave_tag_word_from_real_tag_word(U16 ftw) +{ + U16 compact = 0; + for (U32 fpr = 0; fpr < 8; fpr++){ + U32 tag = (ftw >> (fpr * 2)) & 3; + if (tag != 3){ + compact |= (1 << fpr); + } + } + return(compact); +} + +internal B32 +test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst) +{ + Temp scratch = scratch_begin(0, 0); + + // NOTE(allen): Check available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + // NOTE(allen): Setup the context + CONTEXT *ctx = 0; + U32 ctx_flags = DEMON_W32_CTX_X64_ALL; + if (avx_enabled){ + ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ + void *ctx_memory = push_array(scratch.arena, U8, size); + if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ + ctx = 0; + } + } + + B32 avx_available = false; + + if (ctx != 0){ + // NOTE(allen): Finish Context Setup + if (avx_enabled){ + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + + // NOTE(allen): Determine what features are available on this particular ctx + // TODO(allen): Experiment carefully with this nonsense. + // Does avx_enabled = avx_available in all circumstances or not? + DWORD64 xstate_flags = 0; + if (GetXStateFeaturesMask(ctx, &xstate_flags)){ + if (xstate_flags & XSTATE_MASK_AVX){ + avx_available = true; + } + } + } + + // get thread context + HANDLE thread_handle = thread; + if (!GetThreadContext(thread_handle, ctx)){ + ctx = 0; + } + + B32 result = false; + if (ctx != 0){ + result = true; + + // NOTE(allen): Convert CONTEXT -> SYMS_RegX64 + dst->rax.u64 = ctx->Rax; + dst->rcx.u64 = ctx->Rcx; + dst->rdx.u64 = ctx->Rdx; + dst->rbx.u64 = ctx->Rbx; + dst->rsp.u64 = ctx->Rsp; + dst->rbp.u64 = ctx->Rbp; + dst->rsi.u64 = ctx->Rsi; + dst->rdi.u64 = ctx->Rdi; + dst->r8.u64 = ctx->R8; + dst->r9.u64 = ctx->R9; + dst->r10.u64 = ctx->R10; + dst->r11.u64 = ctx->R11; + dst->r12.u64 = ctx->R12; + dst->r13.u64 = ctx->R13; + dst->r14.u64 = ctx->R14; + dst->r15.u64 = ctx->R15; + dst->rip.u64 = ctx->Rip; + dst->cs.u16 = ctx->SegCs; + dst->ds.u16 = ctx->SegDs; + dst->es.u16 = ctx->SegEs; + dst->fs.u16 = ctx->SegFs; + dst->gs.u16 = ctx->SegGs; + dst->ss.u16 = ctx->SegSs; + dst->dr0.u32 = ctx->Dr0; + dst->dr1.u32 = ctx->Dr1; + dst->dr2.u32 = ctx->Dr2; + dst->dr3.u32 = ctx->Dr3; + dst->dr6.u32 = ctx->Dr6; + dst->dr7.u32 = ctx->Dr7; + + // NOTE(allen): This bit is "supposed to always be 1" I guess. + // TODO(allen): Not sure what this is all about but I haven't investigated it yet. + // This might be totally not necessary or something. + dst->rflags.u64 = ctx->EFlags | 0x2; + + XSAVE_FORMAT *xsave = &ctx->FltSave; + dst->fcw.u16 = xsave->ControlWord; + dst->fsw.u16 = xsave->StatusWord; + dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave); + dst->fop.u16 = xsave->ErrorOpcode; + dst->fcs.u16 = xsave->ErrorSelector; + dst->fds.u16 = xsave->DataSelector; + dst->fip.u32 = xsave->ErrorOffset; + dst->fdp.u32 = xsave->DataOffset; + dst->mxcsr.u32 = xsave->MxCsr; + dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; + + M128A *float_s = xsave->FloatRegisters; + SYMS_Reg80 *float_d = &dst->fpr0; + for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, sizeof(*float_d)); + } + + if (!avx_available){ + M128A *xmm_s = xsave->XmmRegisters; + SYMS_Reg256 *xmm_d = &dst->ymm0; + for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); + } + } + + if (avx_available){ + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + SYMS_Reg256 *ymm_d = &dst->ymm0; + for (DWORD i = 0; + i < count; + i += 1, part0 += 1, part1 += 1, ymm_d += 1){ + // TODO(allen): Are we writing these out in the right order? Seems weird right? + ymm_d->u64[3] = part0->Low; + ymm_d->u64[2] = part0->High; + ymm_d->u64[1] = part1->Low; + ymm_d->u64[0] = part1->High; + } + } + + } + + scratch_end(scratch); + return(result); +} + +internal B32 +test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src) +{ + Temp scratch = scratch_begin(0, 0); + + // NOTE(allen): Check available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + // NOTE(allen): Setup the context + CONTEXT *ctx = 0; + U32 ctx_flags = DEMON_W32_CTX_X64_ALL; + if (avx_enabled){ + ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ + void *ctx_memory = push_array(scratch.arena, U8, size); + if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ + ctx = 0; + } + } + + B32 avx_available = false; + + if (ctx != 0){ + // NOTE(allen): Finish Context Setup + if (avx_enabled){ + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + + // NOTE(allen): Determine what features are available on this particular ctx + // TODO(allen): Experiment carefully with this nonsense. + // Does avx_enabled = avx_available in all circumstances or not? + DWORD64 xstate_flags = 0; + if (GetXStateFeaturesMask(ctx, &xstate_flags)){ + if (xstate_flags & XSTATE_MASK_AVX){ + avx_available = true; + } + } + } + + B32 result = false; + if (ctx != 0){ + // NOTE(allen): Convert SYMS_RegX64 -> CONTEXT + ctx->ContextFlags = ctx_flags; + + ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; + + ctx->Rax = src->rax.u64; + ctx->Rcx = src->rcx.u64; + ctx->Rdx = src->rdx.u64; + ctx->Rbx = src->rbx.u64; + ctx->Rsp = src->rsp.u64; + ctx->Rbp = src->rbp.u64; + ctx->Rsi = src->rsi.u64; + ctx->Rdi = src->rdi.u64; + ctx->R8 = src->r8.u64; + ctx->R9 = src->r9.u64; + ctx->R10 = src->r10.u64; + ctx->R11 = src->r11.u64; + ctx->R12 = src->r12.u64; + ctx->R13 = src->r13.u64; + ctx->R14 = src->r14.u64; + ctx->R15 = src->r15.u64; + ctx->Rip = src->rip.u64; + ctx->SegCs = src->cs.u16; + ctx->SegDs = src->ds.u16; + ctx->SegEs = src->es.u16; + ctx->SegFs = src->fs.u16; + ctx->SegGs = src->gs.u16; + ctx->SegSs = src->ss.u16; + ctx->Dr0 = src->dr0.u32; + ctx->Dr1 = src->dr1.u32; + ctx->Dr2 = src->dr2.u32; + ctx->Dr3 = src->dr3.u32; + ctx->Dr6 = src->dr6.u32; + ctx->Dr7 = src->dr7.u32; + + ctx->EFlags = src->rflags.u64; + + XSAVE_FORMAT *fxsave = &ctx->FltSave; + fxsave->ControlWord = src->fcw.u16; + fxsave->StatusWord = src->fsw.u16; + fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); + fxsave->ErrorOpcode = src->fop.u16; + fxsave->ErrorSelector = src->fcs.u16; + fxsave->DataSelector = src->fds.u16; + fxsave->ErrorOffset = src->fip.u32; + fxsave->DataOffset = src->fdp.u32; + + M128A *float_d = fxsave->FloatRegisters; + SYMS_Reg80 *float_s = &src->fpr0; + for (U32 n = 0; + n < 8; + n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, 10); + } + + if (!avx_available){ + M128A *xmm_d = fxsave->XmmRegisters; + SYMS_Reg256 *xmm_s = &src->ymm0; + for (U32 n = 0; + n < 8; + n += 1, xmm_d += 1, xmm_s += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); + } + } + + if (avx_available){ + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + SYMS_Reg256 *ymm_d = &src->ymm0; + for (DWORD i = 0; + i < count; + i += 1, part0 += 1, part1 += 1, ymm_d += 1){ + // TODO(allen): Are we writing these out in the right order? Seems weird right? + part0->Low = ymm_d->u64[3]; + part0->High = ymm_d->u64[2]; + part1->Low = ymm_d->u64[1]; + part1->High = ymm_d->u64[0]; + } + } + + //- set thread context + HANDLE thread_handle = thread; + if (SetThreadContext(thread_handle, ctx)){ + result = true; + } + } + + scratch_end(scratch); + return(result); +} + +internal B32 +test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size) +{ + B32 result = true; + U8 *ptr = (U8*)dst; + U8 *opl = ptr + size; + U64 cursor = src_address; + for (;ptr < opl;){ + SIZE_T to_read = (SIZE_T)(opl - ptr); + SIZE_T actual_read = 0; + if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ + result = false; + break; + } + ptr += actual_read; + cursor += actual_read; + } + return(result); +} + +internal B32 +test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size) +{ + B32 result = true; + U8 *ptr = (U8*)src; + U8 *opl = ptr + size; + U64 cursor = dst_address; + for (;ptr < opl;){ + SIZE_T to_write = (SIZE_T)(opl - ptr); + SIZE_T actual_write = 0; + if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ + result = false; + break; + } + ptr += actual_write; + cursor += actual_write; + } + return(result); +} + +internal B32 +test_launch_process(OS_LaunchOptions *options) +{ + B32 result = false; + Temp scratch = scratch_begin(0, 0); + + StringJoin join_params = {0}; + join_params.pre = str8_lit("\""); + join_params.sep = str8_lit("\" \""); + join_params.post = str8_lit("\""); + String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); + + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + String8 env = str8_list_join(scratch.arena, &options->env, &join_params2); + + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = str16_from_8(scratch.arena, env); + + DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE; + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, + &startup_info, &process_info)) + { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + result = true; + } + + scratch_end(scratch); + return(result); +} + +global HANDLE g_process_1 = 0; +global DWORD g_process_id_1 = 0; +global U64 g_process_injection_addr_1 = 0; +global HANDLE g_process_2 = 0; +global DWORD g_process_id_2 = 0; + +internal B32 +test_w32_inject_thread(HANDLE process, U64 start_address) +{ + B32 result = false; + LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)start_address; + HANDLE thread = CreateRemoteThread(process, 0, 0, start, 0, 0, 0); + if(thread != 0) + { + CloseHandle(thread); + result = true; + } + return result; +} + +internal void +test_halt(void) +{ + test_w32_inject_thread(g_process_1, g_process_injection_addr_1); +} + +internal TEST_DebugEvent +test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps) +{ + Temp scratch = scratch_begin(0, 0); + TEST_DebugEvent result = {0}; + + //- rjf: freeze thread + if(suspend_thread) + { + DWORD result = SuspendThread(suspend_thread); + DWORD error = GetLastError(); + int x = 0; + } + + //- rjf: write traps + U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count); + { + TEST_Trap *trap = traps; + for(U64 i = 0; i < traps_count; i += 1, trap += 1) + { + if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)) + { + U8 int3 = 0xCC; + test_w32_write_memory(trap->process, trap->address, &int3, 1); + } + else + { + trap_swap_bytes[i] = 0xCC; + } + } + } + + //- rjf: set single step bit + if(step_thread != 0) + { + SYMS_RegX64 regs = {0}; + test_w32_read_x64_regs(step_thread, ®s); + regs.rflags.u64 |= 0x100; + test_w32_write_x64_regs(step_thread, ®s); + } + + //- rjf: continue + local_persist B32 need_resume = 0; + local_persist DWORD resume_pid = 0; + local_persist DWORD resume_tid = 0; + + if(need_resume) + { + need_resume = 0; + ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE); + } + + //- rjf: get event + DEBUG_EVENT evt = {0}; + if(WaitForDebugEvent(&evt, INFINITE)) + { + need_resume = 1; + resume_pid = evt.dwProcessId; + resume_tid = evt.dwThreadId; + result.evt = evt; + + switch(evt.dwDebugEventCode) + { + default:break; + + case CREATE_PROCESS_DEBUG_EVENT: + { + result.name = str8_lit("create process"); + result.process_id = evt.dwProcessId; + result.process = evt.u.CreateProcessInfo.hProcess; + result.thread_id = evt.dwThreadId; + result.thread = evt.u.CreateProcessInfo.hThread; + if(g_process_1 == 0) + { + g_process_1 = result.process; + g_process_id_1 = result.process_id; + + // injection memory + { + U8 injection_code[64]; + injection_code[0] = 0xCC; + injection_code[1] = 0xC3; + for (U64 i = 2; i < 64; i += 1){ + injection_code[i] = 0xCC; + } + + U64 injection_size = 64; + U64 injection_address = (U64)VirtualAllocEx(g_process_1, 0, injection_size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE); + test_w32_write_memory(g_process_1, injection_address, injection_code, sizeof(injection_code)); + g_process_injection_addr_1 = injection_address; + } + + + } + else + { + g_process_2 = result.process; + g_process_id_2 = result.process_id; + } + }break; + + case EXIT_PROCESS_DEBUG_EVENT: + { + result.name = str8_lit("exit process"); + result.process_id = evt.dwProcessId; + }break; + + case CREATE_THREAD_DEBUG_EVENT: + { + result.name = str8_lit("create thread"); + result.thread_id = evt.dwThreadId; + result.thread = evt.u.CreateThread.hThread; + }break; + + case EXIT_THREAD_DEBUG_EVENT: + { + result.name = str8_lit("exit thread"); + result.thread_id = evt.dwThreadId; + }break; + + case LOAD_DLL_DEBUG_EVENT: + { + result.name = str8_lit("load dll"); + }break; + + case UNLOAD_DLL_DEBUG_EVENT: + { + result.name = str8_lit("unload dll"); + }break; + + case EXCEPTION_DEBUG_EVENT: + { + result.name = str8_lit("exception"); + + EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; + EXCEPTION_RECORD *exception = &edi->ExceptionRecord; + + switch(exception->ExceptionCode) + { + case DEMON_W32_EXCEPTION_BREAKPOINT: + { + result.name = str8_lit("breakpoint"); + result.addr = (U64)exception->ExceptionAddress; + }break; + + case DEMON_W32_EXCEPTION_SINGLE_STEP: + { + result.name = str8_lit("single_step"); + }break; + + case DEMON_W32_EXCEPTION_THROW: + { + result.name = str8_lit("exception throw"); + }break; + + case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: + case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: + { + result.name = str8_lit("exception access violation"); + }break; + + default: + { + }break; + } + + }break; + + case OUTPUT_DEBUG_STRING_EVENT: + { + Temp scratch = scratch_begin(0, 0); + result.name = str8_lit("output debug string"); + + U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; + U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; + + // TODO(allen): is the string in UTF-8 or UTF-16? + + U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1); + test_w32_read_memory(g_process_id_1 == evt.dwProcessId ? g_process_1 : g_process_2, buffer, string_address, string_size); + buffer[string_size] = 0; + + printf("%s\n", buffer); + scratch_end(scratch); + }break; + + case RIP_EVENT: + { + result.name = str8_lit("rip event"); + }break; + + } + } + + //- rjf: set single step bit + if(step_thread != 0) + { + SYMS_RegX64 regs = {0}; + test_w32_read_x64_regs(step_thread, ®s); + regs.rflags.u64 &= ~0x100; + test_w32_write_x64_regs(step_thread, ®s); + } + + //- rjf: unset traps + { + TEST_Trap *trap = traps; + for(U64 i = 0; i < traps_count; i += 1, trap += 1) + { + U8 og_byte = trap_swap_bytes[i]; + if(og_byte != 0xCC) + { + test_w32_write_memory(trap->process, trap->address, &og_byte, 1); + } + } + } + + //- rjf: resume thread + if(suspend_thread) + { + ResumeThread(suspend_thread); + } + + scratch_end(scratch); + return result; +} + +internal DWORD +test_halter_thread(void *params) +{ + HANDLE original_process_handle = params; + Sleep(1500); + test_halt(); +#if 0 + DWORD process_id = GetProcessId(original_process_handle); + HANDLE elevated_process_handle = OpenProcess(PROCESS_SUSPEND_RESUME, 0, process_id); + LONG result = NtSuspendProcess(elevated_process_handle); + CloseHandle(elevated_process_handle); + DebugBreakProcess(process); +#endif + return 0; +} + +int +main(int argument_count, char **arguments) +{ + os_init(argument_count, arguments); + Arena *arena = arena_alloc(); + + NtSuspendProcess = (NtSuspendProcessFunction *)GetProcAddress(GetModuleHandle("ntdll"), "NtSuspendProcess"); + + // rjf: launch + { + OS_LaunchOptions opts = {0}; + opts.path = os_get_path(arena, OS_SystemPath_Current); + str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop.exe")); + B32 launch_good = test_launch_process(&opts); + int x = 0; + } + + // rjf: get process/thread handles + HANDLE process = 0; + HANDLE thread1 = 0; + U64 thread1_id = 0; + { + for(TEST_DebugEvent evt = {0};;) + { + evt = test_run_process(0, 0, 0, 0); + if(evt.process) + { + process = evt.process; + } + if(evt.thread) + { + thread1 = evt.thread; + thread1_id = evt.thread_id; + } + if(process != 0 && thread1 != 0) + { + break; + } + } + } + + // rjf: get first breakpoint + { + for(TEST_DebugEvent evt = {0};;) + { + evt = test_run_process(0, 0, 0, 0); + if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + break; + } + } + } + + // rjf: launch halter thread + DWORD halter_id = 0; + { + CreateThread(0, 0, test_halter_thread, process, 0, &halter_id); + } + + // rjf: run + wait for event + for(;;) + { + TEST_DebugEvent evt = test_run_process(0, 0, 0, 0); + int x = 0; + } + +#if 0 + //- rjf: run until 2nd thread starts up + HANDLE thread2 = 0; + U64 thread2_id = 0; + { + for(TEST_DebugEvent evt = {0};;) + { + evt = test_run_process(0, 0, 0, 0/*ArrayCount(traps), traps*/); + if(evt.thread) + { + thread2 = evt.thread; + thread2_id = evt.thread_id; + break; + } + } + } + + //- rjf: wait for first output string + { + for(TEST_DebugEvent evt = {0};;) + { + evt = test_run_process(0, 0, 0, 0); + if(evt.evt.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) + { + break; + } + } + } + + //- rjf: wait for bps + { + // U64 thread1_stop_vaddr = 0x0000000140001119; + // U64 thread2_stop_vaddr = 0x00000001400010C8; + // TEST_Trap traps[] = + { + // {process, thread1_stop_vaddr}, + //{process, thread2_stop_vaddr}, + }; + TEST_DebugEvent evt = {0}; + //for(;;) + { + evt = test_run_process(0, thread2, 0, 0/*ArrayCount(traps), traps*/); + int x = 0; + } + for(;;) {} + } +#endif +} diff --git a/src/demon/test/demon_win32_thread_test.cpp b/src/demon/test/demon_win32_thread_test.cpp new file mode 100644 index 00000000..6ecd4780 --- /dev/null +++ b/src/demon/test/demon_win32_thread_test.cpp @@ -0,0 +1,874 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "syms_helpers/syms_internal_overrides.h" +#include "syms/syms_inc.h" +#include "syms_helpers/syms_helpers.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "syms_helpers/syms_internal_overrides.c" +#include "syms/syms_inc.c" +#include "syms_helpers/syms_helpers.c" + +//////////////////////////////// +// NOTE(allen): Win32 Demon Exceptions + +#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u +#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u +#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u +#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u +#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu +#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u +#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u +#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du +#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu +#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu +#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u +#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u +#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u +#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u +#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u +#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u +#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u +#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du +#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u +#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u +#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u +#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu +#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u +#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u +#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u +#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u +#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u +#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u +#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au +#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u +#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u +#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u +#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u +#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u +#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u +#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u +#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u +#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u + +//////////////////////////////// +// NOTE(allen): Win32 Demon Register API Codes + +#define DEMON_W32_CTX_X86 0x00010000 +#define DEMON_W32_CTX_X64 0x00100000 + +#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 +#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 +#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 +#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 +#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 +#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 +#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 + +#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ +DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ +DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ +DEMON_W32_CTX_INTEL_EXTENDED) +#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ +DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ +DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ +DEMON_W32_CTX_INTEL_DEBUG) + +struct TEST_DebugEvent +{ + String8 name; + U64 process_id; + U64 thread_id; + HANDLE process; + HANDLE thread; + U64 addr; + DEBUG_EVENT evt; +}; + +struct TEST_Trap +{ + HANDLE process; + U64 address; +}; + +internal U16 +test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) +{ + U16 result = 0; + U32 top = (fxsave->StatusWord >> 11) & 7; + for (U32 fpr = 0; fpr < 8; fpr += 1){ + U32 tag = 3; + if (fxsave->TagWord & (1 << fpr)){ + U32 st = (fpr - top)&7; + + SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16]; + U16 exponent = fp->sign1_exp15 & bitmask15; + U64 integer_part = fp->int1_frac63 >> 63; + U64 fraction_part = fp->int1_frac63 & bitmask63; + + // tag: 0 - normal; 1 - zero; 2 - special + tag = 2; + if (exponent == 0){ + if (integer_part == 0 && fraction_part == 0){ + tag = 1; + } + } + else if (exponent != bitmask15 && integer_part != 0){ + tag = 0; + } + } + result |= tag << (2 * fpr); + } + return(result); +} + +internal U16 +test_w32_xsave_tag_word_from_real_tag_word(U16 ftw) +{ + U16 compact = 0; + for (U32 fpr = 0; fpr < 8; fpr++){ + U32 tag = (ftw >> (fpr * 2)) & 3; + if (tag != 3){ + compact |= (1 << fpr); + } + } + return(compact); +} + +internal B32 +test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst) +{ + Temp scratch = scratch_begin(0, 0); + + // NOTE(allen): Check available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + // NOTE(allen): Setup the context + CONTEXT *ctx = 0; + U32 ctx_flags = DEMON_W32_CTX_X64_ALL; + if (avx_enabled){ + ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ + void *ctx_memory = push_array(scratch.arena, U8, size); + if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ + ctx = 0; + } + } + + B32 avx_available = false; + + if (ctx != 0){ + // NOTE(allen): Finish Context Setup + if (avx_enabled){ + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + + // NOTE(allen): Determine what features are available on this particular ctx + // TODO(allen): Experiment carefully with this nonsense. + // Does avx_enabled = avx_available in all circumstances or not? + DWORD64 xstate_flags = 0; + if (GetXStateFeaturesMask(ctx, &xstate_flags)){ + if (xstate_flags & XSTATE_MASK_AVX){ + avx_available = true; + } + } + } + + // get thread context + HANDLE thread_handle = thread; + if (!GetThreadContext(thread_handle, ctx)){ + ctx = 0; + } + + B32 result = false; + if (ctx != 0){ + result = true; + + // NOTE(allen): Convert CONTEXT -> SYMS_RegX64 + dst->rax.u64 = ctx->Rax; + dst->rcx.u64 = ctx->Rcx; + dst->rdx.u64 = ctx->Rdx; + dst->rbx.u64 = ctx->Rbx; + dst->rsp.u64 = ctx->Rsp; + dst->rbp.u64 = ctx->Rbp; + dst->rsi.u64 = ctx->Rsi; + dst->rdi.u64 = ctx->Rdi; + dst->r8.u64 = ctx->R8; + dst->r9.u64 = ctx->R9; + dst->r10.u64 = ctx->R10; + dst->r11.u64 = ctx->R11; + dst->r12.u64 = ctx->R12; + dst->r13.u64 = ctx->R13; + dst->r14.u64 = ctx->R14; + dst->r15.u64 = ctx->R15; + dst->rip.u64 = ctx->Rip; + dst->cs.u16 = ctx->SegCs; + dst->ds.u16 = ctx->SegDs; + dst->es.u16 = ctx->SegEs; + dst->fs.u16 = ctx->SegFs; + dst->gs.u16 = ctx->SegGs; + dst->ss.u16 = ctx->SegSs; + dst->dr0.u32 = ctx->Dr0; + dst->dr1.u32 = ctx->Dr1; + dst->dr2.u32 = ctx->Dr2; + dst->dr3.u32 = ctx->Dr3; + dst->dr6.u32 = ctx->Dr6; + dst->dr7.u32 = ctx->Dr7; + + // NOTE(allen): This bit is "supposed to always be 1" I guess. + // TODO(allen): Not sure what this is all about but I haven't investigated it yet. + // This might be totally not necessary or something. + dst->rflags.u64 = ctx->EFlags | 0x2; + + XSAVE_FORMAT *xsave = &ctx->FltSave; + dst->fcw.u16 = xsave->ControlWord; + dst->fsw.u16 = xsave->StatusWord; + dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave); + dst->fop.u16 = xsave->ErrorOpcode; + dst->fcs.u16 = xsave->ErrorSelector; + dst->fds.u16 = xsave->DataSelector; + dst->fip.u32 = xsave->ErrorOffset; + dst->fdp.u32 = xsave->DataOffset; + dst->mxcsr.u32 = xsave->MxCsr; + dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; + + M128A *float_s = xsave->FloatRegisters; + SYMS_Reg80 *float_d = &dst->fpr0; + for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, sizeof(*float_d)); + } + + if (!avx_available){ + M128A *xmm_s = xsave->XmmRegisters; + SYMS_Reg256 *xmm_d = &dst->ymm0; + for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); + } + } + + if (avx_available){ + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + SYMS_Reg256 *ymm_d = &dst->ymm0; + for (DWORD i = 0; + i < count; + i += 1, part0 += 1, part1 += 1, ymm_d += 1){ + // TODO(allen): Are we writing these out in the right order? Seems weird right? + ymm_d->u64[3] = part0->Low; + ymm_d->u64[2] = part0->High; + ymm_d->u64[1] = part1->Low; + ymm_d->u64[0] = part1->High; + } + } + + } + + scratch_end(scratch); + return(result); +} + +internal B32 +test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src) +{ + Temp scratch = scratch_begin(0, 0); + + // NOTE(allen): Check available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + // NOTE(allen): Setup the context + CONTEXT *ctx = 0; + U32 ctx_flags = DEMON_W32_CTX_X64_ALL; + if (avx_enabled){ + ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ + void *ctx_memory = push_array(scratch.arena, U8, size); + if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ + ctx = 0; + } + } + + B32 avx_available = false; + + if (ctx != 0){ + // NOTE(allen): Finish Context Setup + if (avx_enabled){ + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + + // NOTE(allen): Determine what features are available on this particular ctx + // TODO(allen): Experiment carefully with this nonsense. + // Does avx_enabled = avx_available in all circumstances or not? + DWORD64 xstate_flags = 0; + if (GetXStateFeaturesMask(ctx, &xstate_flags)){ + if (xstate_flags & XSTATE_MASK_AVX){ + avx_available = true; + } + } + } + + B32 result = false; + if (ctx != 0){ + // NOTE(allen): Convert SYMS_RegX64 -> CONTEXT + ctx->ContextFlags = ctx_flags; + + ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; + + ctx->Rax = src->rax.u64; + ctx->Rcx = src->rcx.u64; + ctx->Rdx = src->rdx.u64; + ctx->Rbx = src->rbx.u64; + ctx->Rsp = src->rsp.u64; + ctx->Rbp = src->rbp.u64; + ctx->Rsi = src->rsi.u64; + ctx->Rdi = src->rdi.u64; + ctx->R8 = src->r8.u64; + ctx->R9 = src->r9.u64; + ctx->R10 = src->r10.u64; + ctx->R11 = src->r11.u64; + ctx->R12 = src->r12.u64; + ctx->R13 = src->r13.u64; + ctx->R14 = src->r14.u64; + ctx->R15 = src->r15.u64; + ctx->Rip = src->rip.u64; + ctx->SegCs = src->cs.u16; + ctx->SegDs = src->ds.u16; + ctx->SegEs = src->es.u16; + ctx->SegFs = src->fs.u16; + ctx->SegGs = src->gs.u16; + ctx->SegSs = src->ss.u16; + ctx->Dr0 = src->dr0.u32; + ctx->Dr1 = src->dr1.u32; + ctx->Dr2 = src->dr2.u32; + ctx->Dr3 = src->dr3.u32; + ctx->Dr6 = src->dr6.u32; + ctx->Dr7 = src->dr7.u32; + + ctx->EFlags = src->rflags.u64; + + XSAVE_FORMAT *fxsave = &ctx->FltSave; + fxsave->ControlWord = src->fcw.u16; + fxsave->StatusWord = src->fsw.u16; + fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); + fxsave->ErrorOpcode = src->fop.u16; + fxsave->ErrorSelector = src->fcs.u16; + fxsave->DataSelector = src->fds.u16; + fxsave->ErrorOffset = src->fip.u32; + fxsave->DataOffset = src->fdp.u32; + + M128A *float_d = fxsave->FloatRegisters; + SYMS_Reg80 *float_s = &src->fpr0; + for (U32 n = 0; + n < 8; + n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, 10); + } + + if (!avx_available){ + M128A *xmm_d = fxsave->XmmRegisters; + SYMS_Reg256 *xmm_s = &src->ymm0; + for (U32 n = 0; + n < 8; + n += 1, xmm_d += 1, xmm_s += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); + } + } + + if (avx_available){ + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + SYMS_Reg256 *ymm_d = &src->ymm0; + for (DWORD i = 0; + i < count; + i += 1, part0 += 1, part1 += 1, ymm_d += 1){ + // TODO(allen): Are we writing these out in the right order? Seems weird right? + part0->Low = ymm_d->u64[3]; + part0->High = ymm_d->u64[2]; + part1->Low = ymm_d->u64[1]; + part1->High = ymm_d->u64[0]; + } + } + + //- set thread context + HANDLE thread_handle = thread; + if (SetThreadContext(thread_handle, ctx)){ + result = true; + } + } + + scratch_end(scratch); + return(result); +} + +internal B32 +test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size) +{ + B32 result = true; + U8 *ptr = (U8*)dst; + U8 *opl = ptr + size; + U64 cursor = src_address; + for (;ptr < opl;){ + SIZE_T to_read = (SIZE_T)(opl - ptr); + SIZE_T actual_read = 0; + if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ + result = false; + break; + } + ptr += actual_read; + cursor += actual_read; + } + return(result); +} + +internal B32 +test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size) +{ + B32 result = true; + U8 *ptr = (U8*)src; + U8 *opl = ptr + size; + U64 cursor = dst_address; + for (;ptr < opl;){ + SIZE_T to_write = (SIZE_T)(opl - ptr); + SIZE_T actual_write = 0; + if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ + result = false; + break; + } + ptr += actual_write; + cursor += actual_write; + } + return(result); +} + +internal B32 +test_launch_process(OS_LaunchOptions *options) +{ + B32 result = false; + Temp scratch = scratch_begin(0, 0); + + StringJoin join_params = {0}; + join_params.pre = str8_lit("\""); + join_params.sep = str8_lit("\" \""); + join_params.post = str8_lit("\""); + String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); + + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + String8 env = str8_list_join(scratch.arena, &options->env, &join_params2); + + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = str16_from_8(scratch.arena, env); + + DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE; + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, + &startup_info, &process_info)) + { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + result = true; + } + + scratch_end(scratch); + return(result); +} + +global HANDLE g_process = 0; +global DWORD g_process_id = 0; +global HANDLE g_thread1 = 0; +global DWORD g_thread1_id = 0; +global HANDLE g_thread2 = 0; +global DWORD g_thread2_id = 0; + +internal TEST_DebugEvent +test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps) +{ + Temp scratch = scratch_begin(0, 0); + TEST_DebugEvent result = {0}; + + //- rjf: freeze thread + if(suspend_thread) + { + DWORD result = SuspendThread(suspend_thread); + DWORD error = GetLastError(); + int x = 0; + } + + //- rjf: write traps + U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count); + { + TEST_Trap *trap = traps; + for(U64 i = 0; i < traps_count; i += 1, trap += 1) + { + if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)) + { + U8 int3 = 0xCC; + test_w32_write_memory(trap->process, trap->address, &int3, 1); + } + else + { + trap_swap_bytes[i] = 0xCC; + } + } + } + + //- rjf: set single step bit + if(step_thread != 0) + { + SYMS_RegX64 regs = {0}; + test_w32_read_x64_regs(step_thread, ®s); + regs.rflags.u64 |= 0x100; + test_w32_write_x64_regs(step_thread, ®s); + } + + //- rjf: continue + local_persist B32 need_resume = 0; + local_persist DWORD resume_pid = 0; + local_persist DWORD resume_tid = 0; + + if(need_resume) + { + need_resume = 0; + ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE); + } + + //- rjf: get event + DEBUG_EVENT evt = {0}; + if(WaitForDebugEvent(&evt, INFINITE)) + { + need_resume = 1; + resume_pid = evt.dwProcessId; + resume_tid = evt.dwThreadId; + result.evt = evt; + + switch(evt.dwDebugEventCode) + { + default:break; + + case CREATE_PROCESS_DEBUG_EVENT: + { + result.name = str8_lit("create process"); + result.process_id = evt.dwProcessId; + result.process = evt.u.CreateProcessInfo.hProcess; + result.thread_id = evt.dwThreadId; + result.thread = evt.u.CreateProcessInfo.hThread; + if(g_process == 0) + { + g_process = result.process; + g_process_id = result.process_id; + } + if(g_thread1 == 0) + { + g_thread1 = result.thread; + g_thread1_id = result.thread_id; + } + }break; + + case EXIT_PROCESS_DEBUG_EVENT: + { + result.name = str8_lit("exit process"); + result.process_id = evt.dwProcessId; + }break; + + case CREATE_THREAD_DEBUG_EVENT: + { + result.name = str8_lit("create thread"); + result.thread_id = evt.dwThreadId; + result.thread = evt.u.CreateThread.hThread; + g_thread2 = result.thread; + g_thread2_id = result.thread_id; + }break; + + case EXIT_THREAD_DEBUG_EVENT: + { + result.name = str8_lit("exit thread"); + result.thread_id = evt.dwThreadId; + }break; + + case LOAD_DLL_DEBUG_EVENT: + { + result.name = str8_lit("load dll"); + }break; + + case UNLOAD_DLL_DEBUG_EVENT: + { + result.name = str8_lit("unload dll"); + }break; + + case EXCEPTION_DEBUG_EVENT: + { + result.name = str8_lit("exception"); + + EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; + EXCEPTION_RECORD *exception = &edi->ExceptionRecord; + + switch(exception->ExceptionCode) + { + case DEMON_W32_EXCEPTION_BREAKPOINT: + { + result.name = str8_lit("breakpoint"); + result.addr = (U64)exception->ExceptionAddress; + + local_persist B32 did_first_bp = 0; + if(did_first_bp != 0) + { + HANDLE thread = evt.dwThreadId == g_thread1_id ? g_thread1 : g_thread2; + SYMS_RegX64 regs = {0}; + test_w32_read_x64_regs(thread, ®s); + regs.rip.u64 = result.addr; + test_w32_write_x64_regs(thread, ®s); + } + did_first_bp = 1; + + }break; + + case DEMON_W32_EXCEPTION_SINGLE_STEP: + { + result.name = str8_lit("single_step"); + }break; + + case DEMON_W32_EXCEPTION_THROW: + { + result.name = str8_lit("exception throw"); + }break; + + case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: + case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: + { + result.name = str8_lit("exception access violation"); + }break; + + default: + { + }break; + } + + }break; + + case OUTPUT_DEBUG_STRING_EVENT: + { + Temp scratch = scratch_begin(0, 0); + result.name = str8_lit("output debug string"); + + U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; + U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; + + // TODO(allen): is the string in UTF-8 or UTF-16? + + U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1); + test_w32_read_memory(g_process, buffer, string_address, string_size); + buffer[string_size] = 0; + + printf("%s\n", buffer); + scratch_end(scratch); + }break; + + case RIP_EVENT: + { + result.name = str8_lit("rip event"); + }break; + + } + } + + //- rjf: set single step bit + if(step_thread != 0) + { + SYMS_RegX64 regs = {0}; + test_w32_read_x64_regs(step_thread, ®s); + regs.rflags.u64 &= ~0x100; + test_w32_write_x64_regs(step_thread, ®s); + } + + //- rjf: unset traps + { + TEST_Trap *trap = traps; + for(U64 i = 0; i < traps_count; i += 1, trap += 1) + { + U8 og_byte = trap_swap_bytes[i]; + if(og_byte != 0xCC) + { + test_w32_write_memory(trap->process, trap->address, &og_byte, 1); + } + } + } + + //- rjf: check for more events + for(int i = 0; i < 100; i += 1) + { + DEBUG_EVENT evt = {0}; + if(WaitForDebugEvent(&evt, 0)) + { + int x = 0; + } + } + + //- rjf: resume thread + if(suspend_thread) + { + ResumeThread(suspend_thread); + } + + scratch_end(scratch); + return result; +} + +int +main(int argument_count, char **arguments) +{ + os_init(argument_count, arguments); + Arena *arena = arena_alloc(); + + U64 before_loop_stop_vaddr = 0x0000000140001089; + U64 inner_loop_stop_vaddr = 0x0000000140001098; + + // rjf: launch + { + OS_LaunchOptions opts = {0}; + opts.path = os_get_path(arena, OS_SystemPath_Current); + str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop_threads_win32.exe")); + B32 launch_good = test_launch_process(&opts); + int x = 0; + } + + // rjf: get process/thread handles + HANDLE process = 0; + HANDLE thread1 = 0; + U64 thread1_id = 0; + { + for(TEST_DebugEvent evt = {0};;) + { + evt = test_run_process(0, 0, 0, 0); + if(evt.process) + { + process = evt.process; + } + if(evt.thread) + { + thread1 = evt.thread; + thread1_id = evt.thread_id; + } + if(process != 0 && thread1 != 0) + { + break; + } + } + } + + // rjf: get first breakpoint + { + for(TEST_DebugEvent evt = {0};;) + { + evt = test_run_process(0, 0, 0, 0); + if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + break; + } + } + } + + //- rjf: run until 2nd thread starts up + HANDLE thread2 = 0; + U64 thread2_id = 0; + { + TEST_Trap traps[] = + { + {process, before_loop_stop_vaddr}, + }; + int trap_count = 0; //ArrayCount(traps); + for(TEST_DebugEvent evt = {0};;) + { + evt = test_run_process(0, 0, trap_count, traps); + if(str8_match(evt.name, str8_lit("breakpoint"), 0)) + { + trap_count = 0; + } + if(evt.thread) + { + thread2 = evt.thread; + thread2_id = evt.thread_id; + break; + } + } + } + + //- rjf: wait for bps + { + Temp scratch = scratch_begin(0, 0); + TEST_Trap traps[] = + { + {process, 0x0000000140001098}, + {process, 0x00000001400010fb}, + {process, 0x00000001400010bc}, + {process, 0x00000001400010d7}, + }; + + for(int i = 0;; i += 1) + { + TEST_DebugEvent evt = test_run_process(0, 0, 1, &traps[i % ArrayCount(traps)]); + + // rjf: check regs + { + U64 rip = 0; + SYMS_RegX64 *regs = push_array(scratch.arena, SYMS_RegX64, 1); + if(evt.evt.dwThreadId == g_thread1_id && test_w32_read_x64_regs(thread1, regs)) + { + rip = regs->rip.u64; + } + if(evt.evt.dwThreadId == g_thread2_id && test_w32_read_x64_regs(thread2, regs)) + { + rip = regs->rip.u64; + } + + for(int i = 0; i < ArrayCount(traps); i += 1) + { + if(traps[i].address == rip) + { + printf("WRONG BP! 0x%I64x\n", rip); + break; + } + } + } + + if(str8_match(evt.name, str8_lit("breakpoint"), 0)) + { + HANDLE step = 0; + HANDLE suspend = 0; + step = evt.evt.dwThreadId == thread2_id ? thread2 : thread1; + suspend = step == thread2 ? thread1 : thread2; + evt = test_run_process(step, suspend, 0, 0); + } + } + scratch_end(scratch); + } + + return 0; +} diff --git a/src/demon/win32/demon_os_win32.c b/src/demon/win32/demon_os_win32.c new file mode 100644 index 00000000..6f5876e0 --- /dev/null +++ b/src/demon/win32/demon_os_win32.c @@ -0,0 +1,2006 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Globals + +global B32 demon_w32_resume_needed = 0; +global DWORD demon_w32_resume_pid = 0; +global DWORD demon_w32_resume_tid = 0; + +global B32 demon_w32_exception_not_handled = 0; +global DEMON_Entity* demon_w32_halter_process = 0; +global DWORD demon_w32_halter_thread_id = 0; + +global B32 demon_w32_new_process_pending = 0; + +global Arena *demon_w32_ext_arena = 0 ; +global DEMON_W32_Ext *demon_w32_proc_ext_free = 0; + +global Arena *demon_w32_detach_proc_arena = 0; +global DEMON_EntityNode *demon_w32_first_detached_proc = 0; +global DEMON_EntityNode *demon_w32_last_detached_proc = 0; + +global String8List demon_w32_environment = {0}; + +//////////////////////////////// +//~ rjf: Helpers + +internal DEMON_W32_Ext* +demon_w32_ext_alloc(void){ + DEMON_W32_Ext *result = demon_w32_proc_ext_free; + if (result != 0){ + SLLStackPop(demon_w32_proc_ext_free); + } + else{ + result = push_array_no_zero(demon_w32_ext_arena, DEMON_W32_Ext, 1); + } + MemoryZeroStruct(result); + return(result); +} + +internal DEMON_W32_Ext* +demon_w32_ext(DEMON_Entity *entity){ + DEMON_W32_Ext *result = (DEMON_W32_Ext*)entity->ext; + return(result); +} + +internal U64 +demon_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size){ + U64 bytes_read = 0; + U8 *ptr = (U8*)dst; + U8 *opl = ptr + size; + U64 cursor = src_address; + for (;ptr < opl;){ + SIZE_T to_read = (SIZE_T)(opl - ptr); + SIZE_T actual_read = 0; + if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ + bytes_read += actual_read; + break; + } + ptr += actual_read; + cursor += actual_read; + bytes_read += actual_read; + } + return bytes_read; +} + +internal B32 +demon_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size){ + B32 result = 1; + U8 *ptr = (U8*)src; + U8 *opl = ptr + size; + U64 cursor = dst_address; + for (;ptr < opl;){ + SIZE_T to_write = (SIZE_T)(opl - ptr); + SIZE_T actual_write = 0; + if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ + result = 0; + break; + } + ptr += actual_write; + cursor += actual_write; + } + return(result); +} + +internal String8 +demon_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address){ + // TODO(allen): this could be done better with a demon_w32_read_memory + // that returns a read amount instead of a success/fail. + + // scan piece by piece + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + U64 max_cap = 256; + U64 cap = max_cap; + U64 read_p = address; + for (;;){ + U8 *block = push_array(scratch.arena, U8, cap); + for (;cap > 0;){ + if (demon_w32_read_memory(process_handle, block, read_p, cap)){ + break; + } + cap /= 2; + } + read_p += cap; + + U64 block_opl = 0; + for (;block_opl < cap; block_opl += 1){ + if (block[block_opl] == 0){ + break; + } + } + + if (block_opl > 0){ + str8_list_push(scratch.arena, &list, str8(block, block_opl)); + } + + if (block_opl < cap || cap == 0){ + break; + } + } + + // assemble results + String8 result = str8_list_join(arena, &list, 0); + scratch_end(scratch); + return(result); +} + +internal String16 +demon_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address){ + // TODO(allen): this could be done better with a demon_w32_read_memory + // that returns a read amount instead of a success/fail. + + // scan piece by piece + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + U64 max_cap = 256; + U64 cap = max_cap; + U64 read_p = address; + for (;;){ + U8 *block = push_array(scratch.arena, U8, cap); + for (;cap > 1;){ + if (demon_w32_read_memory(process_handle, block, read_p, cap)){ + break; + } + cap /= 2; + } + read_p += cap; + + U16 *block16 = (U16*)block; + (void)block16; + U64 block_opl = 0; + for (;block_opl < cap; block_opl += 2){ + if (*(U16*)(block + block_opl) == 0){ + break; + } + } + + if (block_opl > 0){ + str8_list_push(scratch.arena, &list, str8(block, block_opl)); + } + + if (block_opl < cap || cap == 0){ + break; + } + } + + // assemble results + String8 joined = str8_list_join(arena, &list, 0); + String16 result = {(U16*)joined.str, joined.size/2}; + scratch_end(scratch); + return(result); +} + +internal DEMON_W32_ImageInfo +demon_w32_image_info_from_base(HANDLE process_handle, U64 base){ + // find pe offset in dos header + U32 pe_offset = 0; + + { + U64 dos_magic_off = base; + U16 dos_magic = 0; + demon_w32_read_struct(process_handle, &dos_magic, dos_magic_off); + if (dos_magic == DEMON_DOS_MAGIC){ + U64 pe_offset_off = base + OffsetOf(DEMON_DosHeader, coff_file_offset); + demon_w32_read_struct(process_handle, &pe_offset, pe_offset_off); + } + } + + // get coff header + B32 got_coff_header = 0; + U64 coff_header_off = 0; + DEMON_CoffHeader coff_header = {0}; + + if (pe_offset > 0){ + U64 pe_magic_off = base + pe_offset; + U32 pe_magic = 0; + demon_w32_read_struct(process_handle, &pe_magic, pe_magic_off); + if (pe_magic == DEMON_PE_MAGIC){ + coff_header_off = pe_magic_off + sizeof(pe_magic); + if (demon_w32_read_struct(process_handle, &coff_header, coff_header_off)){ + got_coff_header = 1; + } + } + } + + // get arch and size + DEMON_W32_ImageInfo result = zero_struct; + if (got_coff_header){ + U64 optional_size_off = 0; + + Architecture arch = Architecture_Null; + switch (coff_header.machine){ + case DEMON_CoffMachineType_X86: + { + arch = Architecture_x86; + optional_size_off = OffsetOf(DEMON_PeOptionalHeader32, sizeof_image); + }break; + + case DEMON_CoffMachineType_X64: + { + arch = Architecture_x64; + optional_size_off = OffsetOf(DEMON_PeOptionalHeader32Plus, sizeof_image); + }break; + + default: + {}break; + } + + if (arch != Architecture_Null){ + U64 optional_off = coff_header_off + sizeof(coff_header); + U32 size = 0; + if (demon_w32_read_struct(process_handle, &size, optional_off + optional_size_off)){ + result.arch = arch; + result.size = size; + } + } + } + + return(result); +} + +internal DWORD +demon_w32_inject_thread(DEMON_Entity *process, U64 start_address){ + LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)start_address; + DEMON_Entity *entity = process; + DEMON_W32_Ext *process_ext = demon_w32_ext(entity); + DWORD thread_id = 0; + HANDLE thread = CreateRemoteThread(process_ext->proc.handle, 0, 0, start, 0, 0, &thread_id); + if (thread != 0){ + CloseHandle(thread); + } + return(thread_id); +} + +internal U16 +demon_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave){ + U16 result = 0; + U32 top = (fxsave->StatusWord >> 11) & 7; + for (U32 fpr = 0; fpr < 8; fpr += 1){ + U32 tag = 3; + if (fxsave->TagWord & (1 << fpr)){ + U32 st = (fpr - top)&7; + + REGS_Reg80 *fp = (REGS_Reg80*)&fxsave->FloatRegisters[st*16]; + U16 exponent = fp->sign1_exp15 & bitmask15; + U64 integer_part = fp->int1_frac63 >> 63; + U64 fraction_part = fp->int1_frac63 & bitmask63; + + // tag: 0 - normal; 1 - zero; 2 - special + tag = 2; + if (exponent == 0){ + if (integer_part == 0 && fraction_part == 0){ + tag = 1; + } + } + else if (exponent != bitmask15 && integer_part != 0){ + tag = 0; + } + } + result |= tag << (2 * fpr); + } + return(result); +} + +internal U16 +demon_w32_xsave_tag_word_from_real_tag_word(U16 ftw){ + U16 compact = 0; + for (U32 fpr = 0; fpr < 8; fpr++){ + U32 tag = (ftw >> (fpr * 2)) & 3; + if (tag != 3){ + compact |= (1 << fpr); + } + } + return(compact); +} + +internal DWORD +demon_w32_win32_from_memory_protect_flags(DEMON_MemoryProtectFlags flags){ + DWORD result = 0; + switch (flags){ + default: + case DEMON_MemoryProtectFlag_Read|DEMON_MemoryProtectFlag_Write: + case DEMON_MemoryProtectFlag_Write: + { + result = PAGE_READWRITE; + }break; + case DEMON_MemoryProtectFlag_Read|DEMON_MemoryProtectFlag_Write|DEMON_MemoryProtectFlag_Execute: + { + result = PAGE_EXECUTE_READWRITE; + }break; + case DEMON_MemoryProtectFlag_Execute: + { + result = PAGE_EXECUTE; + }break; + case DEMON_MemoryProtectFlag_Read: + { + result = PAGE_READONLY; + }break; + } + return(result); +} + +//////////////////////////////// +//~ rjf: Experiments + +internal void +demon_w32_peak_at_tls(DEMON_Handle thread_handle){ + DEMON_Entity *thread = demon_ent_ptr_from_handle(thread_handle); + if (thread != 0 && thread->kind == DEMON_EntityKind_Thread){ + + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + U64 tlb = thread_ext->thread.thread_local_base; + + U8 buffer[0x1000]; + demon_os_read_memory(thread->parent, buffer, tlb, 0x1000); + + int x = 0; + (void)x; + } +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Main Layer Initialization + +internal void +demon_os_init(void){ + demon_w32_ext_arena = arena_alloc(); + demon_w32_detach_proc_arena = arena_alloc(); + + // rjf: setup environment variables + { + CHAR *this_proc_env = GetEnvironmentStrings(); + U64 start_idx = 0; + for(U64 idx = 0;; idx += 1) + { + if(this_proc_env[idx] == 0) + { + if(start_idx == idx) + { + break; + } + else + { + String8 string = str8((U8 *)this_proc_env + start_idx, idx - start_idx); + str8_list_push(demon_w32_ext_arena, &demon_w32_environment, string); + start_idx = idx+1; + } + } + } + } +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Running/Halting + +internal DEMON_EventList +demon_os_run(Arena *arena, DEMON_OS_RunCtrls *ctrls){ + DEMON_EventList result = {0}; + + if (demon_ent_root == 0){ + DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error); + event->error_kind = DEMON_ErrorKind_NotInitialized; + } + else if (demon_ent_root->first == 0 && !demon_w32_new_process_pending){ + DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error); + event->error_kind = DEMON_ErrorKind_NotAttached; + } + else if(demon_w32_first_detached_proc != 0) + { + for(DEMON_EntityNode *n = demon_w32_first_detached_proc; n != 0; n = n->next) + { + DEMON_Entity *process = n->entity; + + // rjf: push exit thread events + for(DEMON_Entity *child = process->first; child != 0; child = child->next) + { + if(child->kind == DEMON_EntityKind_Thread) + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(child); + } + } + + // rjf: push unload module events + for(DEMON_Entity *child = process->first; child != 0; child = child->next) + { + if(child->kind == DEMON_EntityKind_Module) + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_UnloadModule); + e->process = demon_ent_handle_from_ptr(process); + e->module = demon_ent_handle_from_ptr(child); + } + } + + // rjf: push exit process event + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitProcess); + e->process = demon_ent_handle_from_ptr(process); + e->code = 0; + } + + // rjf: free process + demon_ent_release_root_and_children(process); + } + demon_w32_first_detached_proc = 0; + demon_w32_last_detached_proc = 0; + arena_clear(demon_w32_detach_proc_arena); + } + else{ + Temp scratch = scratch_begin(&arena, 1); + + // get the single step thread (if any) + DEMON_Entity *single_step_thread = ctrls->single_step_thread; + + // TODO(allen): dedup per architecture? + // set single step bit + if (single_step_thread != 0){ + // TODO(allen): possibly buggy + switch (single_step_thread->arch){ + case Architecture_x86: + { + REGS_RegBlockX86 regs = {0}; + demon_os_read_regs_x86(single_step_thread, ®s); + regs.eflags.u32 |= 0x100; + demon_os_write_regs_x86(single_step_thread, ®s); + }break; + + case Architecture_x64: + { + REGS_RegBlockX64 regs = {0}; + demon_os_read_regs_x64(single_step_thread, ®s); + regs.rflags.u64 |= 0x100; + demon_os_write_regs_x64(single_step_thread, ®s); + }break; + } + } + + // TODO(allen): per-Architecture implementation of traps + // set traps + U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, ctrls->trap_count); + + { + DEMON_OS_Trap *trap = ctrls->traps; + for (U64 i = 0; i < ctrls->trap_count; i += 1, trap += 1){ + if (demon_os_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)){ + U8 int3 = 0xCC; + demon_os_write_memory(trap->process, trap->address, &int3, 1); + } + else{ + trap_swap_bytes[i] = 0xCC; + } + } + } + + // determine how to resume from the last event + DWORD resume_code = DBG_CONTINUE; + if (demon_w32_exception_not_handled){ + if (!ctrls->ignore_previous_exception){ + resume_code = DBG_EXCEPTION_NOT_HANDLED; + } + } + demon_w32_exception_not_handled = 0; + + // list threads that run this time + DEMON_W32_EntityNode *first_run_thread = 0; + DEMON_W32_EntityNode *last_run_thread = 0; + + for(DEMON_Entity *process = demon_ent_root->first; + process != 0; + process = process->next){ + if (process->kind == DEMON_EntityKind_Process){ + + // determine if this process is frozen + B32 process_is_frozen = 0; + if (ctrls->run_entities_are_processes){ + for (U64 i = 0; i < ctrls->run_entity_count; i += 1){ + if (ctrls->run_entities[i] == process){ + process_is_frozen = 1; + break; + } + } + } + + for (DEMON_Entity *thread = process->first; + thread != 0; + thread = thread->next){ + if (thread->kind == DEMON_EntityKind_Thread){ + // determine if this thread is frozen + B32 is_frozen = 0; + + if (ctrls->single_step_thread != 0 && + ctrls->single_step_thread != thread){ + is_frozen = 1; + } + else{ + + if (ctrls->run_entities_are_processes){ + is_frozen = process_is_frozen; + } + else{ + for (U64 i = 0; i < ctrls->run_entity_count; i += 1){ + if (ctrls->run_entities[i] == thread){ + is_frozen = 1; + break; + } + } + } + + if (ctrls->run_entities_are_unfrozen){ + is_frozen = !is_frozen; + } + } + + // rjf: disregard all other rules if this is the halter thread + if(demon_w32_halter_thread_id == thread->id) + { + is_frozen = 0; + } + + // add this thread to the list + if (!is_frozen){ + DEMON_W32_EntityNode *node = push_array_no_zero(scratch.arena, DEMON_W32_EntityNode, 1); + SLLQueuePush(first_run_thread, last_run_thread, node); + node->entity = thread; + } + } + } + } + } + + // prep threads that will be allowed to run + for (DEMON_W32_EntityNode *node = first_run_thread; + node != 0; + node = node->next){ + DEMON_Entity *thread = node->entity; + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + DWORD resume_result = ResumeThread(thread_ext->thread.handle); + if (resume_result == max_U32){ + // TODO(allen): Error. Unknown cause (do GetLastError, FromatMessage) + } + else{ + DWORD desired_counter = 0; + DWORD current_counter = resume_result - 1; + if (current_counter != desired_counter){ + // NOTE(rjf): Warning. The user has manually suspended this thread, + // so even though from Demon's perspective it thinks this thread + // should run, it will not, because the user has manually called + // SuspendThread or used CREATE_SUSPENDED or whatever. + } + } + } + + // send last saved continue signal + B32 good_state = 1; + if (demon_w32_resume_needed != 0){ + if (!ContinueDebugEvent(demon_w32_resume_pid, demon_w32_resume_tid, resume_code)){ + good_state = 0; + } + + demon_w32_resume_needed = 0; + demon_w32_resume_pid = 0; + demon_w32_resume_tid = 0; + } + + // wait for a new event from targets + DEBUG_EVENT evt = {0}; + B32 got_new_event = 0; + if (good_state){ + got_new_event = WaitForDebugEvent(&evt, INFINITE); + } + if (got_new_event){ + demon_w32_resume_needed = 1; + demon_w32_resume_pid = evt.dwProcessId; + demon_w32_resume_tid = evt.dwThreadId; + } + + // increment demon time + demon_time += 1; + + // reset all threads to paused state + if (got_new_event){ + for (DEMON_W32_EntityNode *node = first_run_thread; + node != 0; + node = node->next){ + DEMON_Entity *thread = node->entity; + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + DWORD suspend_result = SuspendThread(thread_ext->thread.handle); + if (suspend_result == max_U32){ + // TODO(allen): Error. Unknown cause (do GetLastError, FromatMessage) + // NOTE(allen): This can happen when the event is EXIT_THREAD_DEBUG_EVENT + // or EXIT_PROCESS_DEBUG_EVENT. After such an event SuspendThread + // gives error code 5 (access denied). This has no adverse effects, but if + // want to start reporting errors we should take care to avoid calling + // SuspendThread in that case. + } + else{ + DWORD desired_counter = 1; + DWORD current_counter = suspend_result + 1; + if (current_counter != desired_counter){ + // NOTE(rjf): Warning. We've suspended to something higher than 1. + // In this case, it means the user probably created the thread in + // a suspended state, or they called SuspendThread. + } + } + } + } + + // rjf: process event + if (got_new_event){ + got_new_event = 1; + + switch (evt.dwDebugEventCode){ + case CREATE_PROCESS_DEBUG_EVENT: + { + // pull outs + HANDLE process_handle = evt.u.CreateProcessInfo.hProcess; + HANDLE thread_handle = evt.u.CreateProcessInfo.hThread; + U64 module_base = (U64)evt.u.CreateProcessInfo.lpBaseOfImage; + DEMON_W32_ImageInfo image_info = demon_w32_image_info_from_base(process_handle, module_base); + + // init process entity + DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, evt.dwProcessId); + demon_proc_count += 1; + process->arch = image_info.arch; + DEMON_W32_Ext *process_ext = demon_w32_ext_alloc(); + process->ext = process_ext; + process_ext->proc.handle = process_handle; + + demon_w32_new_process_pending = 0; + + // init new associated entities + DEMON_Entity *thread = demon_ent_new(process, DEMON_EntityKind_Thread, evt.dwThreadId); + demon_thread_count += 1; + DEMON_W32_Ext *thread_ext = demon_w32_ext_alloc(); + thread->ext = thread_ext; + thread_ext->thread.handle = thread_handle; + thread_ext->thread.thread_local_base = (U64)evt.u.CreateProcessInfo.lpThreadLocalBase; + SuspendThread(thread_ext->thread.handle); + + DEMON_Entity *module = demon_ent_new(process, DEMON_EntityKind_Module, module_base); + demon_module_count += 1; + module->addr_range_dim = image_info.size; + DEMON_W32_Ext *module_ext = demon_w32_ext_alloc(); + module->ext = module_ext; + module_ext->module.handle = evt.u.CreateProcessInfo.hFile; + module_ext->module.address_of_name_pointer = (U64)evt.u.CreateProcessInfo.lpImageName; + module_ext->module.is_main = 1; + module_ext->module.name_is_unicode = (evt.u.CreateProcessInfo.fUnicode != 0); + + // injection memory + { + U8 injection_code[DEMON_W32_INJECTED_CODE_SIZE]; + injection_code[0] = 0xC3; + for (U64 i = 1; i < DEMON_W32_INJECTED_CODE_SIZE; i += 1){ + injection_code[i] = 0xCC; + } + + U64 injection_size = DEMON_W32_INJECTED_CODE_SIZE + sizeof(DEMON_W32_InjectedBreak); + U64 injection_address = (U64)VirtualAllocEx(process_ext->proc.handle, 0, injection_size, + MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE); + demon_os_write_memory(process, injection_address, injection_code, sizeof(injection_code)); + process_ext->proc.injection_address = injection_address; + } + + // generate events + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_CreateProcess); + e->process = demon_ent_handle_from_ptr(process); + e->code = evt.dwProcessId; + } + + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_CreateThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->code = evt.dwThreadId; + } + + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_LoadModule); + e->process = demon_ent_handle_from_ptr(process); + e->module = demon_ent_handle_from_ptr(module); + e->address = module_base; + e->size = image_info.size; + e->string = demon_os_full_path_from_module(arena, module); + } + }break; + + case EXIT_PROCESS_DEBUG_EVENT: + { + // get process entity + DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); + + if (process != 0){ + // update halter process pointer + if (process == demon_w32_halter_process){ + demon_w32_halter_process = 0; + } + + // generate events for threads & modules + for (DEMON_Entity *entity = process->first; + entity != 0; + entity = entity->next){ + if (entity->kind == DEMON_EntityKind_Thread){ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(entity); + } + else{ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_UnloadModule); + e->process = demon_ent_handle_from_ptr(process); + e->module = demon_ent_handle_from_ptr(entity); + e->string = demon_os_full_path_from_module(arena, entity); + } + } + + // generate event for self + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitProcess); + e->process = demon_ent_handle_from_ptr(process); + e->code = evt.u.ExitProcess.dwExitCode; + + // free entity + demon_ent_release_root_and_children(process); + + // rjf: detach + { + DWORD pid = evt.dwProcessId; + DebugActiveProcessStop(pid); + } + } + }break; + + case CREATE_THREAD_DEBUG_EVENT: + { + // get process entity + DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); + + if (process != 0){ + // init new entity + DEMON_Entity *thread = demon_ent_new(process, DEMON_EntityKind_Thread, evt.dwThreadId); + demon_thread_count += 1; + DEMON_W32_Ext *thread_ext = demon_w32_ext_alloc(); + thread->ext = thread_ext; + thread_ext->thread.handle = evt.u.CreateThread.hThread; + thread_ext->thread.thread_local_base = (U64)evt.u.CreateThread.lpThreadLocalBase; + DWORD sus_result = SuspendThread(thread_ext->thread.handle); + (void)sus_result; + + // rjf: determine if this is the halter thread + B32 is_halter = (evt.dwThreadId == demon_w32_halter_thread_id); + + // generate event for non-halters + if (is_halter == 0){ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_CreateThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->code = evt.dwThreadId; + } + } + }break; + + case EXIT_THREAD_DEBUG_EVENT: + { + // get thread and process entity + DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); + + if (thread != 0){ + DEMON_Entity *process = thread->parent; + + // rjf: determine if this is the halter thread + B32 is_halter = (evt.dwThreadId == demon_w32_halter_thread_id); + + // rjf: generate a halt event if we're the halter + if (is_halter){ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_Halt); + demon_w32_halter_process = 0; + (void)e; + } + + // rjf: generate normal thread exit event on non-halter-thread exist + if (!is_halter){ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitThread); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->code = evt.u.ExitThread.dwExitCode; + } + + // free entity + demon_ent_release_root_and_children(thread); + } + }break; + + case LOAD_DLL_DEBUG_EVENT: + { + // get process entity + DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); + + if (process != 0){ + // get image info + DEMON_W32_Ext *process_ext = demon_w32_ext(process); + HANDLE process_handle = process_ext->proc.handle; + U64 module_base = (U64)evt.u.LoadDll.lpBaseOfDll; + DEMON_W32_ImageInfo image_info = demon_w32_image_info_from_base(process_handle, module_base); + + // init new entity + DEMON_Entity *module = demon_ent_new(process, DEMON_EntityKind_Module, module_base); + demon_module_count += 1; + DEMON_W32_Ext *module_ext = demon_w32_ext_alloc(); + module->ext = module_ext; + module_ext->module.handle = evt.u.LoadDll.hFile; + module_ext->module.address_of_name_pointer = (U64)evt.u.LoadDll.lpImageName; + module_ext->module.is_main = 0; + module_ext->module.name_is_unicode = (evt.u.LoadDll.fUnicode != 0); + + // generate events + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_LoadModule); + e->process = demon_ent_handle_from_ptr(process); + e->module = demon_ent_handle_from_ptr(module); + e->address = module_base; + e->size = image_info.size; + e->string = demon_os_full_path_from_module(arena, module); + } + } + }break; + + case UNLOAD_DLL_DEBUG_EVENT: + { + // get module and process entity + U64 module_base = (U64)evt.u.UnloadDll.lpBaseOfDll; + DEMON_Entity *module = demon_ent_map_entity_from_id(DEMON_EntityKind_Module, module_base); + + if (module != 0){ + DEMON_Entity *process = module->parent; + + // generate events + { + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_UnloadModule); + e->process = demon_ent_handle_from_ptr(process); + e->module = demon_ent_handle_from_ptr(module); + e->string = demon_os_full_path_from_module(arena, module); + } + + // free entity + demon_ent_release_root_and_children(module); + } + }break; + + case EXCEPTION_DEBUG_EVENT: + { + // NOTE(rjf): Notes on multithreaded breakpoint events + // (2021/11/1): + // + // When many threads are simultaneously running, multiple threads + // may hit a trap "at the same time". When this happens there will be + // multiple events in an internal queue that we cannot see. If there + // is another event in the queue we will not see it until we call + // ContinueDebugEvent again, in a subsequent call to demon_os_run. + // + // When we get a trap event, the instruction pointer stored + // in the event will have the address of the int 3 instruction that + // was hit. Our RIP register, however, will be one byte past that. + // So, to get the behavior we want, we need to set the RIP register + // back to the address of the int 3. + // + // To deal with the fact that we may get breakpoint events later that + // were actually from this run what we do is: + // + // #1. If we get a trap event, and it corresponds to a user submitted + // trap, then we treat it is a breakpoint event. + // #2. If we get a trap event, and it does NOT correspond to a user + // trap in this call: + // #A. If the actual unmodified instruction byte is NOT an int 3, + // then this is a queued event from a previous run that is no + // longer applicable and we skip it. + // #B. If the actual unmodified instruction is an int 3, then this + // becomes a trap event and we do not reset RIP. + + // get thread and process entity + DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); + + if (thread != 0){ + DEMON_Entity *process = thread->parent; + Assert(process->kind == DEMON_EntityKind_Process); + + DEMON_W32_Ext *process_ext = demon_w32_ext(process); + + // TODO(allen): the exception record has two forms, one for 32 bit and one for 64 bit mode. + + EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; + EXCEPTION_RECORD *exception = &edi->ExceptionRecord; + U64 instruction_pointer = (U64)exception->ExceptionAddress; + + // check if first BP + B32 first_bp = 0; + if (exception->ExceptionCode == DEMON_W32_EXCEPTION_BREAKPOINT && + !process_ext->proc.did_first_bp){ + process_ext->proc.did_first_bp = 1; + first_bp = 1; + } + + // rjf: check if trap + B32 is_trap = (!first_bp && exception->ExceptionCode == DEMON_W32_EXCEPTION_BREAKPOINT); + + // rjf: check if this trap is currently registered + B32 hit_user_trap = 0; + if (is_trap){ + DEMON_OS_Trap *trap = ctrls->traps; + for (U64 i = 0; i < ctrls->trap_count; i += 1, trap += 1){ + if (trap->process == process && trap->address == instruction_pointer){ + hit_user_trap = 1; + break; + } + } + } + + // rjf: check if trap is explicit in the actual code memory + B32 hit_explicit_trap = 0; + if (is_trap && !hit_user_trap){ + U8 instruction_byte = 0; + if (demon_os_read_memory(process, &instruction_byte, instruction_pointer, 1)){ + // TODO(rjf): x86/x64 specific check + // TODO(rjf): do we need to check to make sure the instruction + // pointer has not changed? + hit_explicit_trap = (instruction_byte == 0xCC); + } + } + + // rjf: determine whether to roll back instruction pointer + B32 rollback = (is_trap && !hit_explicit_trap); + + // rjf: roll back + if (rollback){ + // TODO(allen): possibly buggy + switch (thread->arch){ + case Architecture_x86: + { + REGS_RegBlockX86 regs = {0}; + demon_os_read_regs_x86(thread, ®s); + regs.eip.u32 = instruction_pointer; + demon_os_write_regs_x86(thread, ®s); + }break; + case Architecture_x64: + { + REGS_RegBlockX64 regs = {0}; + demon_os_read_regs_x64(thread, ®s); + regs.rip.u64 = instruction_pointer; + demon_os_write_regs_x64(thread, ®s); + }break; + } + } + + // allen: if this is not a user trap or explicit trap it's a previous trap + B32 hit_previous_trap = (is_trap && !hit_user_trap && !hit_explicit_trap); + + // determine whether to skip this event + B32 skip_event = (hit_previous_trap); + + // emit event + if (!skip_event){ + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_Exception); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->code = exception->ExceptionCode; + e->flags = exception->ExceptionFlags; + e->instruction_pointer = (U64)exception->ExceptionAddress; + + switch (exception->ExceptionCode){ + case DEMON_W32_EXCEPTION_BREAKPOINT: + { + // rjf: determine event kind + DEMON_EventKind report_event_kind = DEMON_EventKind_Trap; + if (first_bp){ + report_event_kind = DEMON_EventKind_HandshakeComplete; + } + else if (hit_user_trap){ + report_event_kind = DEMON_EventKind_Breakpoint; + } + + // set event kind + e->kind = report_event_kind; + }break; + + case DEMON_W32_EXCEPTION_SINGLE_STEP: + { + e->kind = DEMON_EventKind_SingleStep; + }break; + + case DEMON_W32_EXCEPTION_THROW: + { + U64 exception_sp = 0; + U64 exception_ip = 0; + if (exception->NumberParameters >= 3){ + exception_sp = (U64)exception->ExceptionInformation[1]; + exception_ip = (U64)exception->ExceptionInformation[2]; + } + e->stack_pointer = exception_sp; + e->exception_kind = DEMON_ExceptionKind_CppThrow; + e->exception_repeated = (edi->dwFirstChance == 0); + demon_w32_exception_not_handled = (edi->dwFirstChance != 0); + }break; + + case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: + case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: + { + U64 exception_address = 0; + DEMON_ExceptionKind exception_kind = DEMON_ExceptionKind_Null; + if (exception->NumberParameters >= 2){ + switch (exception->ExceptionInformation[0]){ + case 0: exception_kind = DEMON_ExceptionKind_MemoryRead; break; + case 1: exception_kind = DEMON_ExceptionKind_MemoryWrite; break; + case 8: exception_kind = DEMON_ExceptionKind_MemoryExecute; break; + } + exception_address = exception->ExceptionInformation[1]; + } + + e->address = exception_address; + e->exception_kind = exception_kind; + e->exception_repeated = (edi->dwFirstChance == 0); + demon_w32_exception_not_handled = (edi->dwFirstChance != 0); + }break; + + case DEMON_W32_EXCEPTION_SET_THREAD_NAME: + { + if(exception->NumberParameters >= 2) + { + U64 thread_name_address = exception->ExceptionInformation[1]; + DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); + String8List thread_name_strings = {0}; + { + U64 read_addr = thread_name_address; + U64 total_string_size = 0; + for(;total_string_size < KB(4);) + { + U8 *buffer = push_array_no_zero(scratch.arena, U8, 256); + B32 good_read = demon_os_read_memory(process, buffer, read_addr, 256); + if(good_read) + { + U64 size = 256; + for(U64 idx = 0; idx < 256; idx += 1) + { + if(buffer[idx] == 0) + { + size = idx; + break; + } + } + String8 string_part = str8(buffer, size); + str8_list_push(scratch.arena, &thread_name_strings, string_part); + total_string_size += size; + read_addr += size; + if(size < 256) + { + break; + } + } + } + } + e->kind = DEMON_EventKind_SetThreadName; + e->string = str8_list_join(arena, &thread_name_strings, 0); + } + }break; + + default: + { + demon_w32_exception_not_handled = (edi->dwFirstChance != 0); + }break; + } + } + } + }break; + + case OUTPUT_DEBUG_STRING_EVENT: + { + // get process entity + DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); + DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); + + U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; + U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; + + // TODO(allen): is the string in UTF-8 or UTF-16? + + U8 *buffer = push_array_no_zero(arena, U8, string_size + 1); + demon_os_read_memory(process, buffer, string_address, string_size); + buffer[string_size] = 0; + + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_DebugString); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->string = str8(buffer, string_size); + if(string_size != 0 && buffer[string_size-1] == 0) + { + e->string.size -= 1; + } + }break; + + case RIP_EVENT: + { + DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); + DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); + + // TODO(allen): this is not the right way to handle this event + DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_Exception); + e->process = demon_ent_handle_from_ptr(process); + e->thread = demon_ent_handle_from_ptr(thread); + e->flags = 0; + e->address = 0; + }break; + + default: + { + got_new_event = 0; + }break; + } + } + + // TODO(allen): handle errors? if (!got_new_event) ? if (!good_state) ? + + // TODO(allen): per-Architecture + // unset traps + { + DEMON_OS_Trap *trap = ctrls->traps; + for (U64 i = 0; i < ctrls->trap_count; i += 1, trap += 1){ + U8 og_byte = trap_swap_bytes[i]; + if (og_byte != 0xCC){ + demon_os_write_memory(trap->process, trap->address, &og_byte, 1); + } + } + } + + // TODO(allen): per-Architecture + // unset single step bit + // the single step bit is automatically unset whenever we single step + // but if *something else* happened, it will still be there ready to + // confound us later; so here we're just being sure it's taken out. + if (single_step_thread != 0){ + // TODO(allen): possibly buggy + switch (single_step_thread->arch){ + case Architecture_x86: + { + REGS_RegBlockX86 regs = {0}; + demon_os_read_regs_x86(single_step_thread, ®s); + regs.eflags.u32 &= ~0x100; + demon_os_write_regs_x86(single_step_thread, ®s); + }break; + + case Architecture_x64: + { + REGS_RegBlockX64 regs = {0}; + demon_os_read_regs_x64(single_step_thread, ®s); + regs.rflags.u64 &= ~0x100; + demon_os_write_regs_x64(single_step_thread, ®s); + }break; + } + } + + scratch_end(scratch); + } + + return(result); +} + +internal void +demon_os_halt(U64 code, U64 user_data){ + if (demon_ent_root != 0 && demon_w32_halter_process == 0){ + DEMON_Entity *process = demon_ent_root->first; + if (process != 0){ + DEMON_W32_Ext *process_ext = demon_w32_ext(process); + + demon_w32_halter_process = process; + DEMON_W32_InjectedBreak injection = {code, user_data}; + U64 data_injection_address = process_ext->proc.injection_address + DEMON_W32_INJECTED_CODE_SIZE; + demon_os_write_struct(process, data_injection_address, &injection); + demon_w32_halter_thread_id = demon_w32_inject_thread(process, process_ext->proc.injection_address); + } + } +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Target Process Launching/Attaching/Killing/Detaching/Halting + +internal U32 +demon_os_launch_process(OS_LaunchOptions *options){ + Temp scratch = scratch_begin(0, 0); + + // TODO(allen): maybe a good command line escaper/parser function pair? + String8 cmd = {0}; + if(options->cmd_line.first != 0) + { + String8List args = {0}; + String8 exe_path = options->cmd_line.first->string; + str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); + for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &args, n->string); + } + StringJoin join_params = {0}; + join_params.sep = str8_lit(" "); + cmd = str8_list_join(scratch.arena, &args, &join_params); + } + + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + String8List all_opts = options->env; + if(options->inherit_env != 0) + { + MemoryZeroStruct(&all_opts); + for(String8Node *n = options->env.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for(String8Node *n = demon_w32_environment.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + String8 env = str8_list_join(scratch.arena, &all_opts, &join_params2); + + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = str16_from_8(scratch.arena, env); + + U32 result = 0; + + //- rjf: launch + DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + AllocConsole(); + if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, + &startup_info, &process_info)){ + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + result = process_info.dwProcessId; + demon_w32_new_process_pending = 1; + } + FreeConsole(); + + //- rjf: eliminate all handles which have stuck around from the AllocConsole + { + SetStdHandle(STD_INPUT_HANDLE, 0); + SetStdHandle(STD_OUTPUT_HANDLE, 0); + SetStdHandle(STD_ERROR_HANDLE, 0); + } + + scratch_end(scratch); + return(result); +} + +internal B32 +demon_os_attach_process(U32 pid){ + B32 result = 0; + if (DebugActiveProcess((DWORD)pid)){ + result = 1; + demon_w32_new_process_pending = 1; + } + return(result); +} + +internal B32 +demon_os_kill_process(DEMON_Entity *process, U32 exit_code){ + B32 result = 0; + DEMON_W32_Ext *ext = demon_w32_ext(process); + if (TerminateProcess(ext->proc.handle, exit_code)){ + result = 1; + } + return(result); +} + +internal B32 +demon_os_detach_process(DEMON_Entity *process){ + B32 result = 0; + + // rjf: resume threads + for(DEMON_Entity *child = process->first; child != 0; child = child->next) + { + if(child->kind == DEMON_EntityKind_Thread) + { + DEMON_W32_Ext *thread_ext = demon_w32_ext(child); + DWORD resume_result = ResumeThread(thread_ext->thread.handle); + } + } + + // rjf: detach + { + DWORD pid = (DWORD)process->id; + if(DebugActiveProcessStop(pid)) + { + result = 1; + } + } + + // rjf: push into list + if(result != 0) + { + DEMON_EntityNode *n = push_array(demon_w32_detach_proc_arena, DEMON_EntityNode, 1); + n->entity = process; + SLLQueuePush(demon_w32_first_detached_proc, demon_w32_last_detached_proc, n); + } + + return(result); +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Entity Functions + +//- rjf: cleanup + +internal void +demon_os_entity_cleanup(DEMON_Entity *entity) +{ + if (entity->kind == DEMON_EntityKind_Process){ + DEMON_W32_Ext *ext = demon_w32_ext(entity); + SLLStackPush(demon_w32_proc_ext_free, ext); + } + else if(entity->kind == DEMON_EntityKind_Module) + { + DEMON_W32_Ext *ext = demon_w32_ext(entity); + CloseHandle(ext->module.handle); + } +} + +//- rjf: introspection + +internal String8 +demon_os_full_path_from_module(Arena *arena, DEMON_Entity *module){ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + + // object -> handle + DEMON_W32_Ext *module_ext = (DEMON_W32_Ext*)module->ext; + HANDLE handle = module_ext->module.handle; + + String16 path16 = {0}; + String8 path8 = {0}; + + // handle -> full path + if (handle != 0){ + DWORD cap16 = GetFinalPathNameByHandleW(handle, 0, 0, VOLUME_NAME_DOS); + U16 *buffer16 = push_array_no_zero(scratch.arena, U16, cap16); + DWORD size16 = GetFinalPathNameByHandleW(handle, (WCHAR*)buffer16, cap16, VOLUME_NAME_DOS); + path16 = str16(buffer16, size16); + } + + // fallback (main module only): process -> full path + if (path16.size == 0 && module_ext->module.is_main){ + // process handle + DEMON_Entity *process = module->parent; + DEMON_W32_Ext *process_ext = (DEMON_W32_Ext*)process->ext; + HANDLE process_handle = process_ext->proc.handle; + + DWORD size = KB(4); + U16 *buf = push_array_no_zero(scratch.arena, U16, size); + if (QueryFullProcessImageNameW(process_handle, 0, (WCHAR*)buf, &size)){ + path16 = str16(buf, size); + } + } + + // fallback (any module - no gaurantee): address_of_name -> full path + if (path16.size == 0 && module_ext->module.address_of_name_pointer != 0){ + // process handle + DEMON_Entity *process = module->parent; + DEMON_W32_Ext *process_ext = (DEMON_W32_Ext*)process->ext; + HANDLE process_handle = process_ext->proc.handle; + + // TODO(allen): address size independence + U64 ptr_size = 8; + + U64 name_pointer = 0; + if (demon_w32_read_memory(process_handle, &name_pointer, module_ext->module.address_of_name_pointer, ptr_size)){ + if (name_pointer != 0){ + if (module_ext->module.name_is_unicode){ + path16 = demon_w32_read_memory_str16(scratch.arena, process_handle, name_pointer); + } + else{ + path8 = demon_w32_read_memory_str(scratch.arena, process_handle, name_pointer); + } + } + } + } + + // finalize the result + String8 result = {0}; + + if (path16.size > 0){ + // skip the extended path thing if necessary + if (path16.size >= 4 && + path16.str[0] == L'\\' && + path16.str[1] == L'\\' && + path16.str[2] == L'?' && + path16.str[3] == L'\\'){ + path16.size -= 4; + path16.str += 4; + } + + // convert result + result = str8_from_16(arena, path16); + } + else{ + // skip the extended path thing if necessary + if (path8.size >= 4 && + path8.str[0] == L'\\' && + path8.str[1] == L'\\' && + path8.str[2] == L'?' && + path8.str[3] == L'\\'){ + path8.size -= 4; + path8.str += 4; + } + + // copy the result + result = push_str8_copy(arena, path8); + } + + scratch_end(scratch); + ProfEnd(); + return(result); +} + +internal U64 +demon_os_stack_base_vaddr_from_thread(DEMON_Entity *thread){ + DEMON_Entity *process = thread->parent; + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + U64 tlb = thread_ext->thread.thread_local_base; + + U64 result = 0; + switch (thread->arch){ + case Architecture_x64: + { + U64 stack_base_addr = tlb + 0x8; + demon_os_read_memory(process, &result, stack_base_addr, 8); + }break; + + case Architecture_x86: + { + U64 stack_base_addr = tlb + 0x4; + demon_os_read_memory(process, &result, stack_base_addr, 4); + }break; + } + + return(result); +} + +internal U64 +demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread){ + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + U64 result = thread_ext->thread.thread_local_base; + switch (thread->arch){ + case Architecture_x64: + { + result += 88; + }break; + case Architecture_x86: + { + result += 44; + }break; + } + return(result); +} + +//- rjf: target process memory allocation/protection + +internal U64 +demon_os_reserve_memory(DEMON_Entity *process, U64 size){ + DEMON_W32_Ext *ext = demon_w32_ext(process); + void *ptr = VirtualAllocEx(ext->proc.handle, 0, size, MEM_RESERVE, PAGE_NOACCESS); + U64 result = (U64)ptr; + return(result); +} + +internal void +demon_os_set_memory_protect_flags(DEMON_Entity *process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags){ + DEMON_W32_Ext *ext = demon_w32_ext(process); + DWORD w32_flags = demon_w32_win32_from_memory_protect_flags(flags); + DWORD old_flags = 0; + DWORD alloc_type = (flags == 0 ? MEM_DECOMMIT : MEM_COMMIT); + VirtualAllocEx(ext->proc.handle, (void *)page_vaddr, size, alloc_type, w32_flags); + (void)old_flags; +} + +internal void +demon_os_release_memory(DEMON_Entity *process, U64 vaddr, U64 size){ + DEMON_W32_Ext *ext = demon_w32_ext(process); + VirtualFreeEx(ext->proc.handle, (void *)vaddr, 0, MEM_RELEASE); +} + +//- rjf: target process memory reading/writing + +internal U64 +demon_os_read_memory(DEMON_Entity *process, void *dst, U64 src_address, U64 size){ + DEMON_W32_Ext *process_ext = demon_w32_ext(process); + HANDLE handle = process_ext->proc.handle; + U64 result = demon_w32_read_memory(handle, dst, src_address, size); + return(result); +} + +internal B32 +demon_os_write_memory(DEMON_Entity *process, U64 dst_address, void *src, U64 size){ + DEMON_W32_Ext *process_ext = demon_w32_ext(process); + HANDLE handle = process_ext->proc.handle; + B32 result = demon_w32_write_memory(handle, dst_address, src, size); + return(result); +} + +//- rjf: thread registers reading/writing + +internal B32 +demon_os_read_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *dst){ + B32 result = 0; + + // NOTE(allen): Get Thread Context + WOW64_CONTEXT ctx = {0}; + ctx.ContextFlags = DEMON_W32_CTX_X86_ALL; + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + HANDLE handle = thread_ext->thread.handle; + if (Wow64GetThreadContext(handle, (WOW64_CONTEXT *)&ctx)){ + result = 1; + + // NOTE(allen): Convert WOW64_CONTEXT -> REGS_RegBlockX86 + dst->eax.u32 = ctx.Eax; + dst->ebx.u32 = ctx.Ebx; + dst->ecx.u32 = ctx.Ecx; + dst->edx.u32 = ctx.Edx; + dst->esi.u32 = ctx.Esi; + dst->edi.u32 = ctx.Edi; + dst->esp.u32 = ctx.Esp; + dst->ebp.u32 = ctx.Ebp; + dst->eip.u32 = ctx.Eip; + dst->cs.u16 = ctx.SegCs; + dst->ds.u16 = ctx.SegDs; + dst->es.u16 = ctx.SegEs; + dst->fs.u16 = ctx.SegFs; + dst->gs.u16 = ctx.SegGs; + dst->ss.u16 = ctx.SegSs; + dst->dr0.u32 = ctx.Dr0; + dst->dr1.u32 = ctx.Dr1; + dst->dr2.u32 = ctx.Dr2; + dst->dr3.u32 = ctx.Dr3; + dst->dr6.u32 = ctx.Dr6; + dst->dr7.u32 = ctx.Dr7; + + // NOTE(allen): This bit is "supposed to always be 1" I guess. + // TODO(allen): Not sure what this is all about but I haven't investigated it yet. + // This might be totally not necessary or something. + dst->eflags.u32 = ctx.EFlags | 0x2; + + XSAVE_FORMAT *fxsave = (XSAVE_FORMAT*)ctx.ExtendedRegisters; + dst->fcw.u16 = fxsave->ControlWord; + dst->fsw.u16 = fxsave->StatusWord; + dst->ftw.u16 = demon_w32_real_tag_word_from_xsave(fxsave); + dst->fop.u16 = fxsave->ErrorOpcode; + dst->fip.u32 = fxsave->ErrorOffset; + dst->fcs.u16 = fxsave->ErrorSelector; + dst->fdp.u32 = fxsave->DataOffset; + dst->fds.u16 = fxsave->DataSelector; + dst->mxcsr.u32 = fxsave->MxCsr; + dst->mxcsr_mask.u32 = fxsave->MxCsr_Mask; + + M128A *float_s = fxsave->FloatRegisters; + REGS_Reg80 *float_d = &dst->fpr0; + for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, sizeof(*float_d)); + } + + M128A *xmm_s = fxsave->XmmRegisters; + REGS_Reg256 *xmm_d = &dst->ymm0; + for (U32 n = 0; n < 8; n += 1, xmm_s += 1, xmm_d += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); + } + + // read FS/GS base + WOW64_LDT_ENTRY ldt = {0}; + + if (Wow64GetThreadSelectorEntry(handle, ctx.SegFs, &ldt)){ + U32 base = (ldt.BaseLow) | (ldt.HighWord.Bytes.BaseMid << 16) | (ldt.HighWord.Bytes.BaseHi << 24); + dst->fsbase.u32 = base; + } + if (Wow64GetThreadSelectorEntry(handle, ctx.SegGs, &ldt)){ + U32 base = (ldt.BaseLow) | (ldt.HighWord.Bytes.BaseMid << 16) | (ldt.HighWord.Bytes.BaseHi << 24); + dst->gsbase.u32 = base; + } + } + + return(result); +} + +internal B32 +demon_os_write_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *src){ + // NOTE(allen): Convert REGS_RegBlockX86 -> WOW64_CONTEXT + WOW64_CONTEXT ctx = {0}; + ctx.ContextFlags = DEMON_W32_CTX_X86_ALL; + ctx.Eax = src->eax.u32; + ctx.Ebx = src->ebx.u32; + ctx.Ecx = src->ecx.u32; + ctx.Edx = src->edx.u32; + ctx.Esi = src->esi.u32; + ctx.Edi = src->edi.u32; + ctx.Esp = src->esp.u32; + ctx.Ebp = src->ebp.u32; + ctx.Eip = src->eip.u32; + ctx.SegCs = src->cs.u16; + ctx.SegDs = src->ds.u16; + ctx.SegEs = src->es.u16; + ctx.SegFs = src->fs.u16; + ctx.SegGs = src->gs.u16; + ctx.SegSs = src->ss.u16; + ctx.Dr0 = src->dr0.u32; + ctx.Dr1 = src->dr1.u32; + ctx.Dr2 = src->dr2.u32; + ctx.Dr3 = src->dr3.u32; + ctx.Dr6 = src->dr6.u32; + ctx.Dr7 = src->dr7.u32; + ctx.EFlags = src->eflags.u32; + + XSAVE_FORMAT *fxsave = (XSAVE_FORMAT*)ctx.ExtendedRegisters; + fxsave->ControlWord = src->fcw.u16; + fxsave->StatusWord = src->fsw.u16; + fxsave->TagWord = demon_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); + fxsave->ErrorOpcode = src->fop.u16; + fxsave->ErrorSelector = src->fcs.u16; + fxsave->DataSelector = src->fds.u16; + fxsave->ErrorOffset = src->fip.u32; + fxsave->DataOffset = src->fdp.u32; + fxsave->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; + fxsave->MxCsr_Mask = src->mxcsr_mask.u32; + + M128A *float_d = fxsave->FloatRegisters; + REGS_Reg80 *float_s = &src->fpr0; + for (U32 n = 0; + n < 8; + n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, 10); + } + + M128A *xmm_d = fxsave->XmmRegisters; + REGS_Reg256 *xmm_s = &src->ymm0; + for (U32 n = 0; + n < 8; + n += 1, xmm_d += 1, xmm_s += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); + } + + // set thread context + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + HANDLE handle = thread_ext->thread.handle; + B32 result = 0; + if (Wow64SetThreadContext(handle, &ctx)){ + result = 1; + } + + return(result); +} + +internal B32 +demon_os_read_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *dst){ + Temp scratch = scratch_begin(0, 0); + + // NOTE(allen): Check available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + // NOTE(allen): Setup the context + CONTEXT *ctx = 0; + U32 ctx_flags = DEMON_W32_CTX_X64_ALL; + if (avx_enabled){ + ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ + void *ctx_memory = push_array(scratch.arena, U8, size); + if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ + ctx = 0; + } + } + + B32 avx_available = 0; + + if (ctx != 0){ + // NOTE(allen): Finish Context Setup + if (avx_enabled){ + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + + // NOTE(allen): Determine what features are available on this particular ctx + // TODO(allen): Experiment carefully with this nonsense. + // Does avx_enabled = avx_available in all circumstances or not? + DWORD64 xstate_flags = 0; + if (GetXStateFeaturesMask(ctx, &xstate_flags)){ + if (xstate_flags & XSTATE_MASK_AVX){ + avx_available = 1; + } + } + } + + // get thread context + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + HANDLE thread_handle = thread_ext->thread.handle; + if (!GetThreadContext(thread_handle, ctx)){ + ctx = 0; + } + + B32 result = 0; + if (ctx != 0){ + result = 1; + + // NOTE(allen): Convert CONTEXT -> REGS_RegBlockX64 + dst->rax.u64 = ctx->Rax; + dst->rcx.u64 = ctx->Rcx; + dst->rdx.u64 = ctx->Rdx; + dst->rbx.u64 = ctx->Rbx; + dst->rsp.u64 = ctx->Rsp; + dst->rbp.u64 = ctx->Rbp; + dst->rsi.u64 = ctx->Rsi; + dst->rdi.u64 = ctx->Rdi; + dst->r8.u64 = ctx->R8; + dst->r9.u64 = ctx->R9; + dst->r10.u64 = ctx->R10; + dst->r11.u64 = ctx->R11; + dst->r12.u64 = ctx->R12; + dst->r13.u64 = ctx->R13; + dst->r14.u64 = ctx->R14; + dst->r15.u64 = ctx->R15; + dst->rip.u64 = ctx->Rip; + dst->cs.u16 = ctx->SegCs; + dst->ds.u16 = ctx->SegDs; + dst->es.u16 = ctx->SegEs; + dst->fs.u16 = ctx->SegFs; + dst->gs.u16 = ctx->SegGs; + dst->ss.u16 = ctx->SegSs; + dst->dr0.u32 = ctx->Dr0; + dst->dr1.u32 = ctx->Dr1; + dst->dr2.u32 = ctx->Dr2; + dst->dr3.u32 = ctx->Dr3; + dst->dr6.u32 = ctx->Dr6; + dst->dr7.u32 = ctx->Dr7; + + // NOTE(allen): This bit is "supposed to always be 1" I guess. + // TODO(allen): Not sure what this is all about but I haven't investigated it yet. + // This might be totally not necessary or something. + dst->rflags.u64 = ctx->EFlags | 0x2; + + XSAVE_FORMAT *xsave = &ctx->FltSave; + dst->fcw.u16 = xsave->ControlWord; + dst->fsw.u16 = xsave->StatusWord; + dst->ftw.u16 = demon_w32_real_tag_word_from_xsave(xsave); + dst->fop.u16 = xsave->ErrorOpcode; + dst->fcs.u16 = xsave->ErrorSelector; + dst->fds.u16 = xsave->DataSelector; + dst->fip.u32 = xsave->ErrorOffset; + dst->fdp.u32 = xsave->DataOffset; + dst->mxcsr.u32 = xsave->MxCsr; + dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; + + M128A *float_s = xsave->FloatRegisters; + REGS_Reg80 *float_d = &dst->fpr0; + for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, sizeof(*float_d)); + } + + if (!avx_available){ + M128A *xmm_s = xsave->XmmRegisters; + REGS_Reg256 *xmm_d = &dst->ymm0; + for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); + } + } + + if (avx_available){ + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + REGS_Reg256 *ymm_d = &dst->ymm0; + for (DWORD i = 0; + i < count; + i += 1, part0 += 1, part1 += 1, ymm_d += 1){ + // TODO(allen): Are we writing these out in the right order? Seems weird right? + ymm_d->u64[3] = part0->Low; + ymm_d->u64[2] = part0->High; + ymm_d->u64[1] = part1->Low; + ymm_d->u64[0] = part1->High; + } + } + + } + + scratch_end(scratch); + return(result); +} + +internal B32 +demon_os_write_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *src){ + Temp scratch = scratch_begin(0, 0); + + // NOTE(allen): Check available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + // NOTE(allen): Setup the context + CONTEXT *ctx = 0; + U32 ctx_flags = DEMON_W32_CTX_X64_ALL; + if (avx_enabled){ + ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ + void *ctx_memory = push_array(scratch.arena, U8, size); + if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ + ctx = 0; + } + } + + B32 avx_available = 0; + + if (ctx != 0){ + // NOTE(allen): Finish Context Setup + if (avx_enabled){ + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + + // NOTE(allen): Determine what features are available on this particular ctx + // TODO(allen): Experiment carefully with this nonsense. + // Does avx_enabled = avx_available in all circumstances or not? + DWORD64 xstate_flags = 0; + if (GetXStateFeaturesMask(ctx, &xstate_flags)){ + if (xstate_flags & XSTATE_MASK_AVX){ + avx_available = 1; + } + } + } + + B32 result = 0; + if (ctx != 0){ + // NOTE(allen): Convert REGS_RegBlockX64 -> CONTEXT + ctx->ContextFlags = ctx_flags; + + ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; + + ctx->Rax = src->rax.u64; + ctx->Rcx = src->rcx.u64; + ctx->Rdx = src->rdx.u64; + ctx->Rbx = src->rbx.u64; + ctx->Rsp = src->rsp.u64; + ctx->Rbp = src->rbp.u64; + ctx->Rsi = src->rsi.u64; + ctx->Rdi = src->rdi.u64; + ctx->R8 = src->r8.u64; + ctx->R9 = src->r9.u64; + ctx->R10 = src->r10.u64; + ctx->R11 = src->r11.u64; + ctx->R12 = src->r12.u64; + ctx->R13 = src->r13.u64; + ctx->R14 = src->r14.u64; + ctx->R15 = src->r15.u64; + ctx->Rip = src->rip.u64; + ctx->SegCs = src->cs.u16; + ctx->SegDs = src->ds.u16; + ctx->SegEs = src->es.u16; + ctx->SegFs = src->fs.u16; + ctx->SegGs = src->gs.u16; + ctx->SegSs = src->ss.u16; + ctx->Dr0 = src->dr0.u32; + ctx->Dr1 = src->dr1.u32; + ctx->Dr2 = src->dr2.u32; + ctx->Dr3 = src->dr3.u32; + ctx->Dr6 = src->dr6.u32; + ctx->Dr7 = src->dr7.u32; + + ctx->EFlags = src->rflags.u64; + + XSAVE_FORMAT *fxsave = &ctx->FltSave; + fxsave->ControlWord = src->fcw.u16; + fxsave->StatusWord = src->fsw.u16; + fxsave->TagWord = demon_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); + fxsave->ErrorOpcode = src->fop.u16; + fxsave->ErrorSelector = src->fcs.u16; + fxsave->DataSelector = src->fds.u16; + fxsave->ErrorOffset = src->fip.u32; + fxsave->DataOffset = src->fdp.u32; + + M128A *float_d = fxsave->FloatRegisters; + REGS_Reg80 *float_s = &src->fpr0; + for (U32 n = 0; + n < 8; + n += 1, float_s += 1, float_d += 1){ + MemoryCopy(float_d, float_s, 10); + } + + if (!avx_available){ + M128A *xmm_d = fxsave->XmmRegisters; + REGS_Reg256 *xmm_s = &src->ymm0; + for (U32 n = 0; + n < 8; + n += 1, xmm_d += 1, xmm_s += 1){ + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); + } + } + + if (avx_available){ + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + REGS_Reg256 *ymm_d = &src->ymm0; + for (DWORD i = 0; + i < count; + i += 1, part0 += 1, part1 += 1, ymm_d += 1){ + // TODO(allen): Are we writing these out in the right order? Seems weird right? + part0->Low = ymm_d->u64[3]; + part0->High = ymm_d->u64[2]; + part1->Low = ymm_d->u64[1]; + part1->High = ymm_d->u64[0]; + } + } + + //- set thread context + DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); + HANDLE thread_handle = thread_ext->thread.handle; + if (SetThreadContext(thread_handle, ctx)){ + result = 1; + } + } + + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: @demon_os_hooks Process Listing + +internal void +demon_os_proc_iter_begin(DEMON_ProcessIter *iter){ + MemoryZeroStruct(iter); + iter->v[0] = (U64)CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); +} + +internal B32 +demon_os_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out){ + // get the next process entry + B32 result = 0; + PROCESSENTRY32W process_entry = {sizeof(process_entry)}; + HANDLE snapshot = (HANDLE)iter->v[0]; + if (iter->v[1] == 0){ + if (Process32FirstW(snapshot, &process_entry)){ + result = 1; + } + } + else{ + if (Process32NextW(snapshot, &process_entry)){ + result = 1; + } + } + + // increment counter + iter->v[1] += 1; + + // convert to process info + if (result){ + info_out->name = str8_from_16(arena, str16_cstring((U16*)process_entry.szExeFile)); + info_out->pid = (U32)process_entry.th32ProcessID; + } + + return(result); +} + +internal void +demon_os_proc_iter_end(DEMON_ProcessIter *iter){ + CloseHandle((HANDLE)iter->v[0]); + MemoryZeroStruct(iter); +} diff --git a/src/demon/win32/demon_os_win32.h b/src/demon/win32/demon_os_win32.h new file mode 100644 index 00000000..e62a7662 --- /dev/null +++ b/src/demon/win32/demon_os_win32.h @@ -0,0 +1,378 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_OS_WIN32_H +#define DEMON_OS_WIN32_H + +//////////////////////////////// +//~ NOTE(allen): Win32 Demon Headers Negotation + +// windows headers +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +//////////////////////////////// +//~ NOTE(allen): Win32 Demon Types + +//- entities + +// Demon Win32 Entity Extensions +// Process: ext points to independently allocated DEMON_W32_Ext +// Thread : ext points to independently allocated DEMON_W32_Ext +// Module : ext set to HANDLE + +typedef union DEMON_W32_Ext DEMON_W32_Ext; +union DEMON_W32_Ext +{ + DEMON_W32_Ext *next; + struct{ + HANDLE handle; + U64 injection_address; + B32 did_first_bp; + } proc; + struct{ + HANDLE handle; + U64 thread_local_base; + } thread; + struct{ + HANDLE handle; + U64 address_of_name_pointer; + B32 is_main; + B32 name_is_unicode; + } module; +}; + +//- helpers + +typedef struct DEMON_W32_InjectedBreak DEMON_W32_InjectedBreak; +struct DEMON_W32_InjectedBreak +{ + U64 code; + U64 user_data; +}; +#define DEMON_W32_INJECTED_CODE_SIZE 32 + +typedef struct DEMON_W32_ImageInfo DEMON_W32_ImageInfo; +struct DEMON_W32_ImageInfo +{ + Architecture arch; + U32 size; +}; + +typedef struct DEMON_W32_EntityNode DEMON_W32_EntityNode; +struct DEMON_W32_EntityNode +{ + DEMON_W32_EntityNode *next; + DEMON_Entity *entity; +}; + + +//////////////////////////////// +//~ NOTE(allen): Win32 Demon Exceptions + +#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u +#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u +#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u +#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u +#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu +#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u +#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u +#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du +#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu +#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu +#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u +#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u +#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u +#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u +#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u +#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u +#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u +#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du +#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u +#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u +#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u +#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu +#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u +#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u +#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u +#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u +#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u +#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u +#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au +#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u +#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u +#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u +#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u +#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u +#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u +#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u +#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u +#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u +#define DEMON_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u + +//////////////////////////////// +//~ NOTE(allen): Win32 Demon Register API Codes + +#define DEMON_W32_CTX_X86 0x00010000 +#define DEMON_W32_CTX_X64 0x00100000 + +#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 +#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 +#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 +#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 +#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 +#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 +#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 + +#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ +DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ +DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ +DEMON_W32_CTX_INTEL_EXTENDED) +#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ +DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ +DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ +DEMON_W32_CTX_INTEL_DEBUG) + +//////////////////////////////// +//~ rjf: DOS Header Types + +// this is the "MZ" as a 16-bit short +#define DEMON_DOS_MAGIC 0x5a4d + +#pragma pack(push,1) +typedef struct DEMON_DosHeader DEMON_DosHeader; +struct DEMON_DosHeader +{ + U16 magic; + U16 last_page_size; + U16 page_count; + U16 reloc_count; + U16 paragraph_header_size; + U16 min_paragraph; + U16 max_paragraph; + U16 init_ss; + U16 init_sp; + U16 checksum; + U16 init_ip; + U16 init_cs; + U16 reloc_table_file_off; + U16 overlay_number; + U16 reserved[4]; + U16 oem_id; + U16 oem_info; + U16 reserved2[10]; + U32 coff_file_offset; +}; +#pragma pack(pop) + +//////////////////////////////// +//~ rjf: Coff Header Types + +#define DEMON_PE_MAGIC 0x00004550u + +typedef U16 DEMON_CoffMachineType; +enum{ + DEMON_CoffMachineType_UNKNOWN = 0x0, + DEMON_CoffMachineType_X86 = 0x14c, + DEMON_CoffMachineType_X64 = 0x8664, + DEMON_CoffMachineType_ARM33 = 0x1d3, + DEMON_CoffMachineType_ARM = 0x1c0, + DEMON_CoffMachineType_ARM64 = 0xaa64, + DEMON_CoffMachineType_ARMNT = 0x1c4, + DEMON_CoffMachineType_EBC = 0xebc, + DEMON_CoffMachineType_IA64 = 0x200, + DEMON_CoffMachineType_M32R = 0x9041, + DEMON_CoffMachineType_MIPS16 = 0x266, + DEMON_CoffMachineType_MIPSFPU = 0x366, + DEMON_CoffMachineType_MIPSFPU16 = 0x466, + DEMON_CoffMachineType_POWERPC = 0x1f0, + DEMON_CoffMachineType_POWERPCFP = 0x1f1, + DEMON_CoffMachineType_R4000 = 0x166, + DEMON_CoffMachineType_RISCV32 = 0x5032, + DEMON_CoffMachineType_RISCV64 = 0x5064, + DEMON_CoffMachineType_RISCV128 = 0x5128, + DEMON_CoffMachineType_SH3 = 0x1a2, + DEMON_CoffMachineType_SH3DSP = 0x1a3, + DEMON_CoffMachineType_SH4 = 0x1a6, + DEMON_CoffMachineType_SH5 = 0x1a8, + DEMON_CoffMachineType_THUMB = 0x1c2, + DEMON_CoffMachineType_WCEMIPSV2 = 0x169, + DEMON_CoffMachineType_COUNT = 25 +}; + +typedef U16 DEMON_CoffFlags; +enum{ + DEMON_CoffFlag_RELOC_STRIPPED = (1 << 0), + DEMON_CoffFlag_EXECUTABLE_IMAGE = (1 << 1), + DEMON_CoffFlag_LINE_NUMS_STRIPPED = (1 << 2), + DEMON_CoffFlag_SYM_STRIPPED = (1 << 3), + DEMON_CoffFlag_RESERVED_0 = (1 << 4), + DEMON_CoffFlag_LARGE_ADDRESS_AWARE = (1 << 5), + DEMON_CoffFlag_RESERVED_1 = (1 << 6), + DEMON_CoffFlag_RESERVED_2 = (1 << 7), + DEMON_CoffFlag_32BIT_MACHINE = (1 << 8), + DEMON_CoffFlag_DEBUG_STRIPPED = (1 << 9), + DEMON_CoffFlag_REMOVABLE_RUN_FROM_SWAP = (1 << 10), + DEMON_CoffFlag_NET_RUN_FROM_SWAP = (1 << 11), + DEMON_CoffFlag_SYSTEM = (1 << 12), + DEMON_CoffFlag_DLL = (1 << 13), + DEMON_CoffFlag_UP_SYSTEM_ONLY = (1 << 14), + DEMON_CoffFlag_BYTES_RESERVED_HI = (1 << 15), +}; + +#pragma pack(push,1) +typedef struct DEMON_CoffHeader DEMON_CoffHeader; +struct DEMON_CoffHeader +{ + DEMON_CoffMachineType machine; + U16 section_count; + U32 time_date_stamp; + // TODO: rename to "unix_timestamp" + U32 pointer_to_symbol_table; + U32 number_of_symbols; + // TODO: rename to "symbol_count" + U16 size_of_optional_header; + // TODO: rename to "optional_header_size" + DEMON_CoffFlags flags; +}; +#pragma pack(pop) + +//////////////////////////////// +//~ rjf: PE Header Types + +#pragma pack(push, 1) + +typedef U16 DEMON_PeWindowsSubsystem; +enum{ + DEMON_PeWindowsSubsystem_UNKNOWN = 0, + DEMON_PeWindowsSubsystem_NATIVE = 1, + DEMON_PeWindowsSubsystem_WINDOWS_GUI = 2, + DEMON_PeWindowsSubsystem_WINDOWS_CUI = 3, + DEMON_PeWindowsSubsystem_OS2_CUI = 5, + DEMON_PeWindowsSubsystem_POSIX_CUI = 7, + DEMON_PeWindowsSubsystem_NATIVE_WINDOWS = 8, + DEMON_PeWindowsSubsystem_WINDOWS_CE_GUI = 9, + DEMON_PeWindowsSubsystem_EFI_APPLICATION = 10, + DEMON_PeWindowsSubsystem_EFI_BOOT_SERVICE_DRIVER = 11, + DEMON_PeWindowsSubsystem_EFI_RUNTIME_DRIVER = 12, + DEMON_PeWindowsSubsystem_EFI_ROM = 13, + DEMON_PeWindowsSubsystem_XBOX = 14, + DEMON_PeWindowsSubsystem_WINDOWS_BOOT_APPLICATION = 16, + DEMON_PeWindowsSubsystem_COUNT = 14 +}; + +typedef U16 DEMON_DllCharacteristics; +enum{ + DEMON_DllCharacteristic_HIGH_ENTROPY_VA = (1 << 5), + DEMON_DllCharacteristic_DYNAMIC_BASE = (1 << 6), + DEMON_DllCharacteristic_FORCE_INTEGRITY = (1 << 7), + DEMON_DllCharacteristic_NX_COMPAT = (1 << 8), + DEMON_DllCharacteristic_NO_ISOLATION = (1 << 9), + DEMON_DllCharacteristic_NO_SEH = (1 << 10), + DEMON_DllCharacteristic_NO_BIND = (1 << 11), + DEMON_DllCharacteristic_APPCONTAINER = (1 << 12), + DEMON_DllCharacteristic_WDM_DRIVER = (1 << 13), + DEMON_DllCharacteristic_GUARD_CF = (1 << 14), + DEMON_DllCharacteristic_TERMINAL_SERVER_AWARE = (1 << 15), +}; + +typedef struct DEMON_PeOptionalHeader32 DEMON_PeOptionalHeader32; +struct DEMON_PeOptionalHeader32 +{ + U16 magic; + U8 major_linker_version; + U8 minor_linker_version; + U32 sizeof_code; + U32 sizeof_inited_data; + U32 sizeof_uninited_data; + U32 entry_point_va; + U32 code_base; + U32 data_base; + U32 image_base; + U32 section_alignment; + U32 file_alignment; + U16 major_os_ver; + U16 minor_os_ver; + U16 major_img_ver; + U16 minor_img_ver; + U16 major_subsystem_ver; + U16 minor_subsystem_ver; + U32 win32_version_value; + U32 sizeof_image; + U32 sizeof_headers; + U32 check_sum; + DEMON_PeWindowsSubsystem subsystem; + DEMON_DllCharacteristics dll_characteristics; + U32 sizeof_stack_reserve; + U32 sizeof_stack_commit; + U32 sizeof_heap_reserve; + U32 sizeof_heap_commit; + U32 loader_flags; + U32 data_dir_count; +}; + +typedef struct DEMON_PeOptionalHeader32Plus DEMON_PeOptionalHeader32Plus; +struct DEMON_PeOptionalHeader32Plus +{ + U16 magic; + U8 major_linker_version; + U8 minor_linker_version; + U32 sizeof_code; + U32 sizeof_inited_data; + U32 sizeof_uninited_data; + U32 entry_point_va; + U32 code_base; + U64 image_base; + U32 section_alignment; + U32 file_alignment; + U16 major_os_ver; + U16 minor_os_ver; + U16 major_img_ver; + U16 minor_img_ver; + U16 major_subsystem_ver; + U16 minor_subsystem_ver; + U32 win32_version_value; + U32 sizeof_image; + U32 sizeof_headers; + U32 check_sum; + DEMON_PeWindowsSubsystem subsystem; + DEMON_DllCharacteristics dll_characteristics; + U64 sizeof_stack_reserve; + U64 sizeof_stack_commit; + U64 sizeof_heap_reserve; + U64 sizeof_heap_commit; + U32 loader_flags; + U32 data_dir_count; +}; + +#pragma pack(pop) + +//////////////////////////////// +//~ rjf: Helpers + +internal DEMON_W32_Ext* demon_w32_ext_alloc(void); +internal DEMON_W32_Ext* demon_w32_ext(DEMON_Entity *entity); + +internal U64 demon_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size); +internal B32 demon_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size); +internal String8 demon_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address); +internal String16 demon_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address); + +#define demon_w32_read_struct(h,dst,src) demon_w32_read_memory((h), (dst), (src), sizeof(*(dst))) + +internal DEMON_W32_ImageInfo demon_w32_image_info_from_base(HANDLE process_handle, U64 base); +internal DWORD demon_w32_inject_thread(DEMON_Entity *process, U64 start_address); + +internal U16 demon_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave); +internal U16 demon_w32_xsave_tag_word_from_real_tag_word(U16 ftw); + +internal DWORD demon_w32_win32_from_memory_protect_flags(DEMON_MemoryProtectFlags flags); + +//////////////////////////////// +//~ rjf: Experiments + +internal void demon_w32_peak_at_tls(DEMON_Handle handle); + +#endif //DEMON_OS_WIN32_H diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c new file mode 100644 index 00000000..ba5db393 --- /dev/null +++ b/src/df/core/df_core.c @@ -0,0 +1,8043 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#undef RADDBG_LAYER_COLOR +#define RADDBG_LAYER_COLOR 0.70f, 0.50f, 0.25f + +//////////////////////////////// +//~ rjf: Generated Code + +#include "df/core/generated/df_core.meta.c" + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +df_hash_from_seed_string(U64 seed, String8 string) +{ + U64 result = seed; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal U64 +df_hash_from_string(String8 string) +{ + return df_hash_from_seed_string(5381, string); +} + +internal U64 +df_hash_from_seed_string__case_insensitive(U64 seed, String8 string) +{ + U64 result = seed; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + char_to_lower(string.str[i]); + } + return result; +} + +internal U64 +df_hash_from_string__case_insensitive(String8 string) +{ + return df_hash_from_seed_string__case_insensitive(5381, string); +} + +//////////////////////////////// +//~ rjf: Handles + +internal DF_Handle +df_handle_zero(void) +{ + DF_Handle result = {0}; + return result; +} + +internal B32 +df_handle_match(DF_Handle a, DF_Handle b) +{ + return (a.u64[0] == b.u64[0] && a.u64[1] == b.u64[1]); +} + +internal void +df_handle_list_push_node(DF_HandleList *list, DF_HandleNode *node) +{ + DLLPushBack(list->first, list->last, node); + list->count += 1; +} + +internal void +df_handle_list_push(Arena *arena, DF_HandleList *list, DF_Handle handle) +{ + DF_HandleNode *n = push_array(arena, DF_HandleNode, 1); + n->handle = handle; + df_handle_list_push_node(list, n); +} + +internal void +df_handle_list_remove(DF_HandleList *list, DF_HandleNode *node) +{ + DLLRemove(list->first, list->last, node); + list->count -= 1; +} + +internal DF_HandleNode * +df_handle_list_find(DF_HandleList *list, DF_Handle handle) +{ + DF_HandleNode *result = 0; + for(DF_HandleNode *n = list->first; n != 0; n = n->next) + { + if(df_handle_match(n->handle, handle)) + { + result = n; + break; + } + } + return result; +} + +internal DF_HandleList +df_push_handle_list_copy(Arena *arena, DF_HandleList list) +{ + DF_HandleList result = {0}; + for(DF_HandleNode *n = list.first; n != 0; n = n->next) + { + df_handle_list_push(arena, &result, n->handle); + } + return result; +} + +//////////////////////////////// +//~ rjf: State History Data Structure + +internal DF_StateDeltaHistory * +df_state_delta_history_alloc(void) +{ + Arena *arena = arena_alloc(); + DF_StateDeltaHistory *hist = push_array(arena, DF_StateDeltaHistory, 1); + hist->arena = arena; + for(Side side = (Side)0; side < Side_COUNT; side = (Side)(side+1)) + { + hist->side_arenas[side] = arena_alloc(); + } + return hist; +} + +internal void +df_state_delta_history_release(DF_StateDeltaHistory *hist) +{ + for(Side side = (Side)0; side < Side_COUNT; side = (Side)(side+1)) + { + arena_release(hist->side_arenas[side]); + } + arena_release(hist->arena); +} + +internal void +df_state_delta_history_push_batch(DF_StateDeltaHistory *hist, U64 *optional_gen_ptr) +{ + if(hist == 0) { return; } + if(hist->side_arenas[Side_Max] != 0) + { + arena_clear(hist->side_arenas[Side_Max]); + hist->side_tops[Side_Max] = 0; + } + DF_StateDeltaBatch *batch = push_array(hist->side_arenas[Side_Min], DF_StateDeltaBatch, 1); + SLLStackPush(hist->side_tops[Side_Min], batch); + if(optional_gen_ptr != 0) + { + batch->gen = *optional_gen_ptr; + batch->gen_vaddr = (U64)optional_gen_ptr; + } +} + +internal void +df_state_delta_history_push_delta(DF_StateDeltaHistory *hist, void *ptr, U64 size) +{ + if(hist == 0) { return; } + DF_StateDeltaBatch *batch = hist->side_tops[Side_Min]; + if(batch == 0) + { + df_state_delta_history_push_batch(hist, 0); + batch = hist->side_tops[Side_Min]; + } + DF_StateDeltaNode *n = push_array(hist->side_arenas[Side_Min], DF_StateDeltaNode, 1); + SLLQueuePush(batch->first, batch->last, n); + n->v.vaddr = (U64)ptr; + n->v.data = push_str8_copy(hist->arena, str8((U8*)ptr, size)); +} + +internal void +df_state_delta_history_wind(DF_StateDeltaHistory *hist, Side side) +{ + if(hist == 0) { return; } + DF_StateDeltaBatch *src_batch = hist->side_tops[side]; + if(src_batch != 0) + { + B32 src_batch_gen_good = (src_batch->gen_vaddr == 0 || src_batch->gen == *(U64 *)(src_batch->gen_vaddr)); + U64 pop_pos = (U64)hist->side_tops[side] - (U64)hist->side_arenas[side]; + SLLStackPop(hist->side_tops[side]); + if(src_batch_gen_good) + { + DF_StateDeltaBatch *dst_batch = push_array(hist->side_arenas[side_flip(side)], DF_StateDeltaBatch, 1); + SLLStackPush(hist->side_tops[side_flip(side)], dst_batch); + for(DF_StateDeltaNode *src_n = src_batch->first; src_n != 0; src_n = src_n->next) + { + DF_StateDelta *src_delta = &src_n->v; + DF_StateDeltaNode *dst_n = push_array(hist->side_arenas[side_flip(side)], DF_StateDeltaNode, 1); + SLLQueuePush(dst_batch->first, dst_batch->last, dst_n); + dst_n->v.vaddr = src_delta->vaddr; + dst_n->v.data = push_str8_copy(hist->side_arenas[side_flip(side)], str8((U8 *)src_delta->vaddr, src_delta->data.size)); + MemoryCopy((void *)src_delta->vaddr, src_delta->data.str, src_delta->data.size); + } + } + arena_pop_to(hist->side_arenas[side], pop_pos); + } +} + +//////////////////////////////// +//~ rjf: Sparse Tree Expansion State Data Structure + +//- rjf: keys + +internal DF_ExpandKey +df_expand_key_make(U64 uniquifier, U64 parent_hash, U64 child_num) +{ + DF_ExpandKey key; + { + key.uniquifier = uniquifier; + key.parent_hash = parent_hash; + key.child_num = child_num; + } + return key; +} + +internal DF_ExpandKey +df_expand_key_zero(void) +{ + DF_ExpandKey key = {0}; + return key; +} + +internal B32 +df_expand_key_match(DF_ExpandKey a, DF_ExpandKey b) +{ + return MemoryMatchStruct(&a, &b); +} + +internal U64 +df_hash_from_expand_key(DF_ExpandKey key) +{ + U64 data[] = + { + key.uniquifier, + key.child_num, + }; + U64 hash = df_hash_from_seed_string(key.parent_hash, str8((U8 *)data, sizeof(data))); + return hash; +} + +//- rjf: table + +internal void +df_expand_tree_table_init(Arena *arena, DF_ExpandTreeTable *table, U64 slot_count) +{ + MemoryZeroStruct(table); + table->slots_count = slot_count; + table->slots = push_array(arena, DF_ExpandSlot, table->slots_count); +} + +internal void +df_expand_tree_table_animate(DF_ExpandTreeTable *table, F32 dt) +{ + F32 rate = 1 - pow_f32(2, (-50.f * dt)); + for(U64 slot_idx = 0; slot_idx < table->slots_count; slot_idx += 1) + { + for(DF_ExpandNode *node = table->slots[slot_idx].first; + node != 0; + node = node->hash_next) + { + node->expanded_t += (((F32)!!node->expanded) - node->expanded_t) * rate; + } + } +} + +internal DF_ExpandNode * +df_expand_node_from_key(DF_ExpandTreeTable *table, DF_ExpandKey key) +{ + U64 hash = df_hash_from_expand_key(key); + U64 slot_idx = hash%table->slots_count; + DF_ExpandSlot *slot = &table->slots[slot_idx]; + DF_ExpandNode *node = 0; + for(DF_ExpandNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_expand_key_match(n->key, key)) + { + node = n; + break; + } + } + return node; +} + +internal B32 +df_expand_key_is_set(DF_ExpandTreeTable *table, DF_ExpandKey key) +{ + DF_ExpandNode *node = df_expand_node_from_key(table, key); + return (node != 0 && node->expanded); +} + +internal void +df_expand_set_expansion(Arena *arena, DF_ExpandTreeTable *table, DF_ExpandKey parent_key, DF_ExpandKey key, B32 expanded) +{ + // rjf: map keys => nodes + DF_ExpandNode *parent_node = df_expand_node_from_key(table, parent_key); + DF_ExpandNode *node = df_expand_node_from_key(table, key); + + // rjf: make node if we don't have one, and we need one + if(node == 0 && expanded) + { + node = table->free_node; + if(node != 0) + { + table->free_node = table->free_node->next; + MemoryZeroStruct(node); + } + else + { + node = push_array(arena, DF_ExpandNode, 1); + } + + // rjf: link into table + U64 hash = df_hash_from_expand_key(key); + U64 slot = hash % table->slots_count; + DLLPushBack_NP(table->slots[slot].first, table->slots[slot].last, node, hash_next, hash_prev); + + // rjf: link into parent + if(parent_node != 0) + { + DF_ExpandNode *prev = 0; + for(DF_ExpandNode *n = parent_node->first; n != 0; n = n->next) + { + if(n->key.child_num < key.child_num) + { + prev = n; + } + else + { + break; + } + } + DLLInsert_NP(parent_node->first, parent_node->last, prev, node, next, prev); + node->parent = parent_node; + } + } + + // rjf: fill + if(node != 0) + { + node->key = key; + node->expanded = expanded; + } + + // rjf: unlink node & free if we don't need it anymore + if(expanded == 0 && node != 0 && node->first == 0) + { + // rjf: unlink from table + U64 hash = df_hash_from_expand_key(key); + U64 slot = hash % table->slots_count; + DLLRemove_NP(table->slots[slot].first, table->slots[slot].last, node, hash_next, hash_prev); + + // rjf: unlink from tree + if(parent_node != 0) + { + DLLRemove_NP(parent_node->first, parent_node->last, node, next, prev); + } + + // rjf: free + node->next = table->free_node; + table->free_node = node; + } +} + +//////////////////////////////// +//~ rjf: Config Type Functions + +internal DF_CfgNode * +df_cfg_tree_copy(Arena *arena, DF_CfgNode *src_root) +{ + DF_CfgNode *dst_root = &df_g_nil_cfg_node; + DF_CfgNode *dst_parent = dst_root; + { + DF_CfgNodeRec rec = {0}; + for(DF_CfgNode *src = src_root; src != &df_g_nil_cfg_node; src = rec.next) + { + DF_CfgNode *dst = push_array(arena, DF_CfgNode, 1); + dst->first = dst->last = dst->parent = dst->next = &df_g_nil_cfg_node; + dst->flags = src->flags; + dst->string = push_str8_copy(arena, src->string); + dst->source = src->source; + dst->parent = dst_parent; + if(dst_parent != &df_g_nil_cfg_node) + { + SLLQueuePush_NZ(&df_g_nil_cfg_node, dst_parent->first, dst_parent->last, dst, next); + } + else + { + dst_root = dst_parent = dst; + } + rec = df_cfg_node_rec__depth_first_pre(src, src_root); + if(rec.push_count != 0) + { + dst_parent = dst; + } + else for(U64 idx = 0; idx < rec.pop_count; idx += 1) + { + dst_parent = dst_parent->parent; + } + } + } + return dst_root; +} + +internal DF_CfgNodeRec +df_cfg_node_rec__depth_first_pre(DF_CfgNode *node, DF_CfgNode *root) +{ + DF_CfgNodeRec rec = {0}; + rec.next = &df_g_nil_cfg_node; + if(node->first != &df_g_nil_cfg_node) + { + rec.next = node->first; + rec.push_count = 1; + } + else for(DF_CfgNode *p = node; p != &df_g_nil_cfg_node && p != root; p = p->parent, rec.pop_count += 1) + { + if(p->next != &df_g_nil_cfg_node) + { + rec.next = p->next; + break; + } + } + return rec; +} + +internal void +df_cfg_table_push_unparsed_string(Arena *arena, DF_CfgTable *table, String8 string, DF_CfgSrc source) +{ + Temp scratch = scratch_begin(&arena, 1); + if(table->slot_count == 0) + { + table->slot_count = 64; + table->slots = push_array(arena, DF_CfgSlot, table->slot_count); + } + MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, string); + MD_ParseResult parse = md_parse_from_text_tokens(scratch.arena, str8_lit(""), string, tokenize.tokens); + MD_Node *md_root = parse.root; + for(MD_EachNode(tln, md_root->first)) if(tln->string.size != 0) + { + // rjf: map string -> hash*slot + String8 string = str8(tln->string.str, tln->string.size); + U64 hash = df_hash_from_string__case_insensitive(string); + U64 slot_idx = hash % table->slot_count; + DF_CfgSlot *slot = &table->slots[slot_idx]; + + // rjf: find existing value for this string + DF_CfgVal *val = 0; + for(DF_CfgVal *v = slot->first; v != 0; v = v->hash_next) + { + if(str8_match(v->string, string, StringMatchFlag_CaseInsensitive)) + { + val = v; + break; + } + } + + // rjf: create new value if needed + if(val == 0) + { + val = push_array(arena, DF_CfgVal, 1); + val->string = push_str8_copy(arena, string); + val->insertion_stamp = table->insertion_stamp_counter; + SLLStackPush_N(slot->first, val, hash_next); + SLLQueuePush_N(table->first_val, table->last_val, val, linear_next); + table->insertion_stamp_counter += 1; + } + + // rjf: deep copy tree into streamlined config structure + DF_CfgNode *dst_root = &df_g_nil_cfg_node; + { + DF_CfgNode *dst_parent = &df_g_nil_cfg_node; + for(MD_Node *src = tln, *src_next = 0; !md_node_is_nil(src); src = src_next) + { + src_next = 0; + + // rjf: copy + DF_CfgNode *dst = push_array(arena, DF_CfgNode, 1); + dst->first = dst->last = dst->parent = dst->next = &df_g_nil_cfg_node; + if(dst_parent == &df_g_nil_cfg_node) + { + dst_root = dst; + } + else + { + SLLQueuePush_NZ(&df_g_nil_cfg_node, dst_parent->first, dst_parent->last, dst, next); + dst->parent = dst_parent; + } + { + dst->flags |= !!(src->flags & MD_NodeFlag_Identifier) * DF_CfgNodeFlag_Identifier; + dst->flags |= !!(src->flags & MD_NodeFlag_Numeric) * DF_CfgNodeFlag_Numeric; + dst->flags |= !!(src->flags & MD_NodeFlag_StringLiteral) * DF_CfgNodeFlag_StringLiteral; + dst->string = push_str8_copy(arena, str8(src->string.str, src->string.size)); + dst->source = source; + } + + // rjf: grab next + if(!md_node_is_nil(src->first)) + { + src_next = src->first; + dst_parent = dst; + } + else for(MD_Node *p = src; !md_node_is_nil(p) && p != tln; p = p->parent, dst_parent = dst_parent->parent) + { + if(!md_node_is_nil(p->next)) + { + src_next = p->next; + break; + } + } + } + } + + // rjf: push tree into value + SLLQueuePush_NZ(&df_g_nil_cfg_node, val->first, val->last, dst_root, next); + } + scratch_end(scratch); +} + +internal DF_CfgTable +df_cfg_table_from_inheritance(Arena *arena, DF_CfgTable *src) +{ + DF_CfgTable dst_ = {0}; + DF_CfgTable *dst = &dst_; + { + dst->slot_count = src->slot_count; + dst->slots = push_array(arena, DF_CfgSlot, dst->slot_count); + } + for(DF_CfgVal *src_val = src->first_val; src_val != 0 && src_val != &df_g_nil_cfg_val; src_val = src_val->linear_next) + { + DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(src_val->string); + if(spec->info.flags & DF_CoreViewRuleSpecInfoFlag_Inherited) + { + U64 hash = df_hash_from_string(spec->info.string); + U64 dst_slot_idx = hash%dst->slot_count; + DF_CfgSlot *dst_slot = &dst->slots[dst_slot_idx]; + DF_CfgVal *dst_val = push_array(arena, DF_CfgVal, 1); + dst_val->first = src_val->first; + dst_val->last = src_val->last; + dst_val->string = src_val->string; + dst_val->insertion_stamp = dst->insertion_stamp_counter; + SLLStackPush_N(dst_slot->first, dst_val, hash_next); + dst->insertion_stamp_counter += 1; + } + } + return dst_; +} + +internal DF_CfgTable +df_cfg_table_copy(Arena *arena, DF_CfgTable *src) +{ + DF_CfgTable result = {0}; + result.slot_count = src->slot_count; + result.slots = push_array(arena, DF_CfgSlot, result.slot_count); + MemoryCopy(result.slots, src->slots, sizeof(DF_CfgSlot)*result.slot_count); + return result; +} + +internal DF_CfgVal * +df_cfg_val_from_string(DF_CfgTable *table, String8 string) +{ + DF_CfgVal *result = &df_g_nil_cfg_val; + if(table->slot_count != 0) + { + U64 hash = df_hash_from_string__case_insensitive(string); + U64 slot_idx = hash % table->slot_count; + DF_CfgSlot *slot = &table->slots[slot_idx]; + for(DF_CfgVal *val = slot->first; val != 0; val = val->hash_next) + { + if(str8_match(val->string, string, StringMatchFlag_CaseInsensitive)) + { + result = val; + break; + } + } + } + return result; +} + +internal DF_CfgNode * +df_cfg_node_child_from_string(DF_CfgNode *node, String8 string, StringMatchFlags flags) +{ + DF_CfgNode *result = &df_g_nil_cfg_node; + for(DF_CfgNode *child = node->first; child != &df_g_nil_cfg_node; child = child->next) + { + if(str8_match(child->string, string, flags)) + { + result = child; + break; + } + } + return result; +} + +internal DF_CfgNode * +df_first_cfg_node_child_from_flags(DF_CfgNode *node, DF_CfgNodeFlags flags) +{ + DF_CfgNode *result = &df_g_nil_cfg_node; + for(DF_CfgNode *child = node->first; child != &df_g_nil_cfg_node; child = child->next) + { + if(child->flags & flags) + { + result = child; + break; + } + } + return result; +} + +internal String8 +df_string_from_cfg_node_children(Arena *arena, DF_CfgNode *node) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List strs = {0}; + for(DF_CfgNode *child = node->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &strs, child->string); + } + String8 result = str8_list_join(arena, &strs, 0); + scratch_end(scratch); + return result; +} + +internal Vec4F32 +df_hsva_from_cfg_node(DF_CfgNode *node) +{ + Vec4F32 result = {0}; + DF_CfgNode *hsva = df_cfg_node_child_from_string(node, str8_lit("hsva"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *rgba = df_cfg_node_child_from_string(node, str8_lit("rgba"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *hsv = df_cfg_node_child_from_string(node, str8_lit("hsv"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *rgb = df_cfg_node_child_from_string(node, str8_lit("rgb"), StringMatchFlag_CaseInsensitive); + if(hsva != &df_g_nil_cfg_node) + { + DF_CfgNode *hue = hsva->first; + DF_CfgNode *sat = hue->next; + DF_CfgNode *val = sat->next; + DF_CfgNode *alp = val->next; + F32 hue_f32 = (F32)f64_from_str8(hue->string); + F32 sat_f32 = (F32)f64_from_str8(sat->string); + F32 val_f32 = (F32)f64_from_str8(val->string); + F32 alp_f32 = (F32)f64_from_str8(alp->string); + result = v4f32(hue_f32, sat_f32, val_f32, alp_f32); + } + else if(hsv != &df_g_nil_cfg_node) + { + DF_CfgNode *hue = hsva->first; + DF_CfgNode *sat = hue->next; + DF_CfgNode *val = sat->next; + F32 hue_f32 = (F32)f64_from_str8(hue->string); + F32 sat_f32 = (F32)f64_from_str8(sat->string); + F32 val_f32 = (F32)f64_from_str8(val->string); + result = v4f32(hue_f32, sat_f32, val_f32, 1.f); + } + else if(rgba != &df_g_nil_cfg_node) + { + DF_CfgNode *red = rgba->first; + DF_CfgNode *grn = red->next; + DF_CfgNode *blu = grn->next; + DF_CfgNode *alp = blu->next; + F32 red_f32 = (F32)f64_from_str8(red->string); + F32 grn_f32 = (F32)f64_from_str8(grn->string); + F32 blu_f32 = (F32)f64_from_str8(blu->string); + F32 alp_f32 = (F32)f64_from_str8(alp->string); + Vec3F32 hsv = hsv_from_rgb(v3f32(red_f32, grn_f32, blu_f32)); + result = v4f32(hsv.x, hsv.y, hsv.z, alp_f32); + } + else if(rgb != &df_g_nil_cfg_node) + { + DF_CfgNode *red = rgba->first; + DF_CfgNode *grn = red->next; + DF_CfgNode *blu = grn->next; + F32 red_f32 = (F32)f64_from_str8(red->string); + F32 grn_f32 = (F32)f64_from_str8(grn->string); + F32 blu_f32 = (F32)f64_from_str8(blu->string); + Vec3F32 hsv = hsv_from_rgb(v3f32(red_f32, grn_f32, blu_f32)); + result = v4f32(hsv.x, hsv.y, hsv.z, 1.f); + } + return result; +} + +internal String8 +df_string_from_cfg_node_key(DF_CfgNode *node, String8 key, StringMatchFlags flags) +{ + DF_CfgNode *child = df_cfg_node_child_from_string(node, key, flags); + return child->first->string; +} + +//////////////////////////////// +//~ rjf: Disassembling + +#include "third_party/udis86/config.h" +#include "third_party/udis86/udis86.h" +#include "third_party/udis86/libudis86/syn.h" + +internal DF_Inst +df_single_inst_from_machine_code__x64(Arena *arena, U64 start_voff, String8 string) +{ + Architecture arch = Architecture_x64; + + //- rjf: prep ud state + struct ud ud_ctx_; + struct ud *ud_ctx = &ud_ctx_; + ud_init(ud_ctx); + ud_set_mode(ud_ctx, bit_size_from_arch(arch)); + ud_set_pc(ud_ctx, start_voff); + ud_set_input_buffer(ud_ctx, string.str, string.size); + ud_set_vendor(ud_ctx, UD_VENDOR_ANY); + ud_set_syntax(ud_ctx, UD_SYN_INTEL); + + //- rjf: disassembly + get info + U32 bytes_disassembled = ud_disassemble(ud_ctx); + struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(ud_ctx, 0); + U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(ud_ctx, first_op) : 0; + DF_InstFlags flags = 0; + enum ud_mnemonic_code code = ud_insn_mnemonic(ud_ctx); + switch(code) + { + case UD_Icall: + { + flags |= DF_InstFlag_Call; + }break; + + /* TODO(wonchun) + case UD_Iiretd: + case UD_Iiretw: + */ + + case UD_Ija: + case UD_Ijae: + case UD_Ijb: + case UD_Ijbe: + case UD_Ijcxz: + case UD_Ijecxz: + case UD_Ijg: + case UD_Ijge: + case UD_Ijl: + case UD_Ijle: + { + flags |= DF_InstFlag_Branch; + }break; + + case UD_Ijmp: + { + flags |= DF_InstFlag_UnconditionalJump; + }break; + + case UD_Ijno: + case UD_Ijnp: + case UD_Ijns: + case UD_Ijnz: + case UD_Ijo: + case UD_Ijp: + case UD_Ijrcxz: + case UD_Ijs: + case UD_Ijz: + case UD_Iloop: + case UD_Iloope: + case UD_Iloopne: + { + flags |= DF_InstFlag_Branch; + }break; + + case UD_Iret: + case UD_Iretf: + { + flags |= DF_InstFlag_Return; + }break; + + /* TODO(wonchun) + case UD_Isyscall: + case UD_Isysenter: + case UD_Isysexit: + case UD_Isysret: + case UD_Ivmcall: + case UD_Ivmmcall: + */ + default: + { + flags |= DF_InstFlag_NonFlow; + }break; + } + + //- rjf: check for stack pointer modifications + S64 sp_delta = 0; + { + struct ud_operand *dst_op = (struct ud_operand *)ud_insn_opr(ud_ctx, 0); + struct ud_operand *src_op = (struct ud_operand *)ud_insn_opr(ud_ctx, 1); + + // rjf: direct additions/subtractions to RSP + if(dst_op && src_op && dst_op->base == UD_R_RSP && dst_op->type == UD_OP_REG) + { + flags |= DF_InstFlag_ChangesStackPointer; + // TODO(rjf): does the library report constant changes to the stack pointer + // as UD_OP_CONST too? what does UD_OP_JIMM refer to? + if(src_op->base == UD_NONE && src_op->type == UD_OP_IMM && code == UD_Isub) + { + S64 sign = -1; + sp_delta = sign * src_op->lval.sqword; + } + else if(src_op->base == UD_NONE && src_op->type == UD_OP_IMM && code == UD_Iadd) + { + S64 sign = +1; + sp_delta = sign * src_op->lval.sqword; + } + else + { + flags |= DF_InstFlag_ChangesStackPointerVariably; + } + } + + // rjf: push/pop + if(code == UD_Ipush) + { + flags |= DF_InstFlag_ChangesStackPointer; + sp_delta = -8; + } + else if(code == UD_Ipop) + { + flags |= DF_InstFlag_ChangesStackPointer; + sp_delta = +8; + } + + // rjf: mark extra flags + if(ud_ctx->pfx_rep != 0 || + ud_ctx->pfx_repe != 0 || + ud_ctx->pfx_repne != 0) + { + flags |= DF_InstFlag_Repeats; + } + } + + //- rjf: fill+return + DF_Inst inst = {0}; + inst.size = bytes_disassembled; + inst.string = push_str8_copy(arena, str8_cstring((char *)ud_insn_asm(ud_ctx))); + inst.rel_voff = rel_voff; + inst.sp_delta = sp_delta; + inst.flags = flags; + return inst; +} + +internal DF_Inst +df_single_inst_from_machine_code(Arena *arena, Architecture arch, U64 start_voff, String8 string) +{ + DF_Inst result = {0}; + switch(arch) + { + default:{}break; + case Architecture_x64: + { + result = df_single_inst_from_machine_code__x64(arena, start_voff, string); + }break; + } + return result; +} + +//////////////////////////////// +//~ rjf: Control Flow Analysis Functions + +internal DF_CtrlFlowInfo +df_ctrl_flow_info_from_vaddr_code__x64(Arena *arena, DF_InstFlags exit_points_mask, U64 vaddr, String8 code) +{ + Temp scratch = scratch_begin(&arena, 1); + DF_CtrlFlowInfo info = {0}; + for(U64 offset = 0; offset < code.size;) + { + DF_Inst inst = df_single_inst_from_machine_code__x64(scratch.arena, 0, str8_skip(code, offset)); + U64 inst_vaddr = vaddr+offset; + info.cumulative_sp_delta += inst.sp_delta; + offset += inst.size; + info.total_size += inst.size; + if(inst.flags & exit_points_mask) + { + DF_CtrlFlowPoint point = {0}; + point.inst_flags = inst.flags; + point.vaddr = inst_vaddr; + point.jump_dest_vaddr = 0; + point.expected_sp_delta = info.cumulative_sp_delta; + if(inst.rel_voff != 0) + { + point.jump_dest_vaddr = (U64)(point.vaddr + (S64)((S32)inst.rel_voff)); + } + DF_CtrlFlowPointNode *node = push_array(arena, DF_CtrlFlowPointNode, 1); + node->point = point; + SLLQueuePush(info.exit_points.first, info.exit_points.last, node); + info.exit_points.count += 1; + } + } + scratch_end(scratch); + return info; +} + +internal DF_CtrlFlowInfo +df_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DF_InstFlags exit_points_mask, Architecture arch, U64 vaddr, String8 code) +{ + DF_CtrlFlowInfo result = {0}; + switch(arch) + { + default:{}break; + case Architecture_x64: + { + result = df_ctrl_flow_info_from_vaddr_code__x64(arena, exit_points_mask, vaddr, code); + }break; + } + return result; +} + +//////////////////////////////// +//~ rjf: Command Type Pure Functions + +//- rjf: specs + +internal B32 +df_cmd_spec_is_nil(DF_CmdSpec *spec) +{ + return (spec == 0 || spec == &df_g_nil_cmd_spec); +} + +internal void +df_cmd_spec_list_push(Arena *arena, DF_CmdSpecList *list, DF_CmdSpec *spec) +{ + DF_CmdSpecNode *n = push_array(arena, DF_CmdSpecNode, 1); + n->spec = spec; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal DF_CmdSpecArray +df_cmd_spec_array_from_list(Arena *arena, DF_CmdSpecList list) +{ + DF_CmdSpecArray result = {0}; + result.count = list.count; + result.v = push_array(arena, DF_CmdSpec *, list.count); + U64 idx = 0; + for(DF_CmdSpecNode *n = list.first; n != 0; n = n->next, idx += 1) + { + result.v[idx] = n->spec; + } + return result; +} + +internal int +df_qsort_compare_cmd_spec__run_counter(DF_CmdSpec **a, DF_CmdSpec **b) +{ + int result = 0; + if(a[0]->run_count > b[0]->run_count) + { + result = -1; + } + else if(a[0]->run_count < b[0]->run_count) + { + result = +1; + } + return result; +} + +internal void +df_cmd_spec_array_sort_by_run_counter__in_place(DF_CmdSpecArray array) +{ + qsort(array.v, array.count, sizeof(DF_CmdSpec *), (int (*)(const void *, const void *))df_qsort_compare_cmd_spec__run_counter); +} + +internal DF_Handle +df_handle_from_cmd_spec(DF_CmdSpec *spec) +{ + DF_Handle handle = {0}; + handle.u64[0] = (U64)spec; + return handle; +} + +internal DF_CmdSpec * +df_cmd_spec_from_handle(DF_Handle handle) +{ + DF_CmdSpec *result = (DF_CmdSpec *)handle.u64[0]; + if(result == 0) + { + result = &df_g_nil_cmd_spec; + } + return result; +} + +//- rjf: string -> command parsing + +internal String8 +df_cmd_name_part_from_string(String8 string) +{ + String8 result = string; + for(U64 idx = 0; idx <= string.size; idx += 1) + { + if(idx == string.size || char_is_space(string.str[idx])) + { + result = str8_prefix(string, idx); + break; + } + } + return result; +} + +internal String8 +df_cmd_arg_part_from_string(String8 string) +{ + String8 result = str8_lit(""); + B32 found_space = 0; + for(U64 idx = 0; idx <= string.size; idx += 1) + { + if(found_space && (idx == string.size || !char_is_space(string.str[idx]))) + { + result = str8_skip(string, idx); + break; + } + else if(!found_space && (idx == string.size || char_is_space(string.str[idx]))) + { + found_space = 1; + } + } + return result; +} + +//- rjf: command parameter bundles + +internal DF_CmdParams +df_cmd_params_zero(void) +{ + DF_CmdParams p = {0}; + return p; +} + +internal void +df_cmd_params_mark_slot(DF_CmdParams *params, DF_CmdParamSlot slot) +{ + params->slot_props[slot/64] |= (1ull<<(slot%64)); +} + +internal B32 +df_cmd_params_has_slot(DF_CmdParams *params, DF_CmdParamSlot slot) +{ + return !!(params->slot_props[slot/64] & (1ull<<(slot%64))); +} + +internal String8 +df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams *params, DF_CmdSpec *spec, String8 query) +{ + String8 error = {0}; + B32 prefer_imm = 0; + switch(spec->info.query_rule) + { + default: + case DF_CmdQueryRule_String: + { + params->string = push_str8_copy(arena, query); + df_cmd_params_mark_slot(params, DF_CmdParamSlot_String); + }break; + case DF_CmdQueryRule_FilePath: + { + params->file_path = push_str8_copy(arena, query); + df_cmd_params_mark_slot(params, DF_CmdParamSlot_FilePath); + }break; + case DF_CmdQueryRule_TextPoint: + { + U64 v = 0; + if(try_u64_from_str8_c_rules(query, &v)) + { + params->text_point.column = 1; + params->text_point.line = v; + df_cmd_params_mark_slot(params, DF_CmdParamSlot_TextPoint); + } + }break; + case DF_CmdQueryRule_FilePathAndTextPoint: + { + String8TxtPtPair pair = str8_txt_pt_pair_from_string(query); + params->file_path = push_str8_copy(arena, pair.string); + params->text_point = pair.pt; + df_cmd_params_mark_slot(params, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(params, DF_CmdParamSlot_TextPoint); + }break; + case DF_CmdQueryRule_VirtualAddr: prefer_imm = 0; goto use_numeric_eval; + case DF_CmdQueryRule_VirtualOff: prefer_imm = 0; goto use_numeric_eval; + case DF_CmdQueryRule_Index: prefer_imm = 1; goto use_numeric_eval; + case DF_CmdQueryRule_ID: prefer_imm = 1; goto use_numeric_eval; + use_numeric_eval: + { + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + U64 vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx->unwind_count); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_process_vaddr(process, vaddr); + U64 voff = df_voff_from_vaddr(module, vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_module_voff(scope, module, voff); + DF_Eval eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, &parse_ctx, query); + if(eval.errors.count == 0) + { + TG_Kind eval_type_kind = tg_kind_from_key(tg_unwrapped_from_graph_raddbg_key(parse_ctx.type_graph, parse_ctx.rdbg, eval.type_key)); + if(eval_type_kind == TG_Kind_Ptr || eval_type_kind == TG_Kind_LRef || eval_type_kind == TG_Kind_RRef) + { + eval = df_value_mode_eval_from_eval(parse_ctx.type_graph, parse_ctx.rdbg, ctrl_ctx, eval); + prefer_imm = 1; + } + U64 u64 = !prefer_imm && eval.offset ? eval.offset : eval.imm_u64; + switch(spec->info.query_rule) + { + default:{}break; + case DF_CmdQueryRule_VirtualAddr: + { + params->vaddr = u64; + df_cmd_params_mark_slot(params, DF_CmdParamSlot_VirtualAddr); + }break; + case DF_CmdQueryRule_VirtualOff: + { + params->voff = u64; + df_cmd_params_mark_slot(params, DF_CmdParamSlot_VirtualOff); + }break; + case DF_CmdQueryRule_Index: + { + params->index = u64; + df_cmd_params_mark_slot(params, DF_CmdParamSlot_Index); + }break; + case DF_CmdQueryRule_ID: + { + params->id = u64; + df_cmd_params_mark_slot(params, DF_CmdParamSlot_ID); + }break; + } + } + else + { + error = push_str8f(scratch.arena, "Couldn't evaluate \"%S\" as an address", query); + } + dbgi_scope_close(scope); + scratch_end(scratch); + }break; + } + return error; +} + +//- rjf: command lists + +internal void +df_cmd_list_push(Arena *arena, DF_CmdList *cmds, DF_CmdParams *params, DF_CmdSpec *spec) +{ + DF_CmdNode *n = push_array(arena, DF_CmdNode, 1); + n->cmd.spec = spec; + MemoryCopyStruct(&n->cmd.params, params); + n->cmd.params.entity_list = df_push_handle_list_copy(arena, params->entity_list); + n->cmd.params.string = push_str8_copy(arena, params->string); + n->cmd.params.file_path = push_str8_copy(arena, params->file_path); + if(n->cmd.params.cmd_spec == 0) {n->cmd.params.cmd_spec = &df_g_nil_cmd_spec;} + DLLPushBack(cmds->first, cmds->last, n); + cmds->count += 1; +} + +//- rjf: string -> core layer command kind + +internal DF_CoreCmdKind +df_core_cmd_kind_from_string(String8 string) +{ + DF_CoreCmdKind result = DF_CoreCmdKind_Null; + for(U64 idx = 0; idx < ArrayCount(df_g_core_cmd_kind_spec_info_table); idx += 1) + { + if(str8_match(string, df_g_core_cmd_kind_spec_info_table[idx].string, StringMatchFlag_CaseInsensitive)) + { + result = (DF_CoreCmdKind)idx; + break; + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Entity Functions + +//- rjf: nil + +internal B32 +df_entity_is_nil(DF_Entity *entity) +{ + return (entity == 0 || entity == &df_g_nil_entity); +} + +//- rjf: handle <-> entity conversions + +internal U64 +df_index_from_entity(DF_Entity *entity) +{ + return (U64)(entity - df_state->entities_base); +} + +internal DF_Handle +df_handle_from_entity(DF_Entity *entity) +{ + DF_Handle handle = df_handle_zero(); + if(!df_entity_is_nil(entity)) + { + handle.u64[0] = df_index_from_entity(entity); + handle.u64[1] = entity->generation; + } + return handle; +} + +internal DF_Entity * +df_entity_from_handle(DF_Handle handle) +{ + DF_Entity *result = df_state->entities_base + handle.u64[0]; + if(handle.u64[0] >= df_state->entities_count || result->generation != handle.u64[1]) + { + result = &df_g_nil_entity; + } + return result; +} + +internal DF_EntityList +df_entity_list_from_handle_list(Arena *arena, DF_HandleList handles) +{ + DF_EntityList result = {0}; + for(DF_HandleNode *n = handles.first; n != 0; n = n->next) + { + DF_Entity *entity = df_entity_from_handle(n->handle); + if(!df_entity_is_nil(entity)) + { + df_entity_list_push(arena, &result, entity); + } + } + return result; +} + +internal DF_HandleList +df_handle_list_from_entity_list(Arena *arena, DF_EntityList entities) +{ + DF_HandleList result = {0}; + for(DF_EntityNode *n = entities.first; n != 0; n = n->next) + { + DF_Handle handle = df_handle_from_entity(n->entity); + df_handle_list_push(arena, &result, handle); + } + return result; +} + +//- rjf: entity recursion iterators + +internal DF_EntityRec +df_entity_rec_df(DF_Entity *entity, DF_Entity *subtree_root, U64 sib_off, U64 child_off) +{ + DF_EntityRec result = {0}; + if(!df_entity_is_nil(*MemberFromOffset(DF_Entity **, entity, child_off))) + { + result.next = *MemberFromOffset(DF_Entity **, entity, child_off); + result.push_count = 1; + } + else for(DF_Entity *parent = entity; parent != subtree_root && !df_entity_is_nil(parent); parent = parent->parent) + { + if(!df_entity_is_nil(*MemberFromOffset(DF_Entity **, parent, sib_off))) + { + result.next = *MemberFromOffset(DF_Entity **, parent, sib_off); + break; + } + result.pop_count += 1; + } + return result; +} + +//- rjf: ancestor/child introspection + +internal DF_Entity * +df_entity_child_from_kind(DF_Entity *entity, DF_EntityKind kind) +{ + DF_Entity *result = &df_g_nil_entity; + for(DF_Entity *child = entity->first; !df_entity_is_nil(child); child = child->next) + { + if(!child->deleted && child->kind == kind) + { + result = child; + break; + } + } + return result; +} + +internal DF_Entity * +df_entity_ancestor_from_kind(DF_Entity *entity, DF_EntityKind kind) +{ + DF_Entity *result = &df_g_nil_entity; + for(DF_Entity *p = entity->parent; !df_entity_is_nil(p); p = p->parent) + { + if(p->kind == kind) + { + result = p; + break; + } + } + return result; +} + +internal DF_EntityList +df_push_entity_child_list_with_kind(Arena *arena, DF_Entity *entity, DF_EntityKind kind) +{ + DF_EntityList result = {0}; + for(DF_Entity *child = entity->first; !df_entity_is_nil(child); child = child->next) + { + if(!child->deleted && child->kind == kind) + { + df_entity_list_push(arena, &result, child); + } + } + return result; +} + +internal DF_Entity * +df_entity_child_from_name_and_kind(DF_Entity *parent, String8 string, DF_EntityKind kind) +{ + DF_Entity *result = &df_g_nil_entity; + for(DF_Entity *child = parent->first; !df_entity_is_nil(child); child = child->next) + { + if(!child->deleted && str8_match(child->name, string, 0) && child->kind == kind) + { + result = child; + break; + } + } + return result; +} + +//- rjf: entity list building + +internal void +df_entity_list_push(Arena *arena, DF_EntityList *list, DF_Entity *entity) +{ + DF_EntityNode *n = push_array(arena, DF_EntityNode, 1); + n->entity = entity; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal DF_EntityArray +df_entity_array_from_list(Arena *arena, DF_EntityList *list) +{ + DF_EntityArray result = {0}; + result.count = list->count; + result.v = push_array(arena, DF_Entity *, result.count); + U64 idx = 0; + for(DF_EntityNode *n = list->first; n != 0; n = n->next, idx += 1) + { + result.v[idx] = n->entity; + } + return result; +} + +//- rjf: entity -> text info + +internal TXTI_Handle +df_txti_handle_from_entity(DF_Entity *entity) +{ + TXTI_Handle handle = {0}; + Temp scratch = scratch_begin(0, 0); + String8 path = df_full_path_from_entity(scratch.arena, entity); + handle = txti_handle_from_path(path); + scratch_end(scratch); + return handle; +} + +//- rjf: entity -> disasm info + +internal DASM_Handle +df_dasm_handle_from_process_vaddr(DF_Entity *process, U64 vaddr) +{ + Rng1U64 disasm_vaddr_rng = r1u64(AlignDownPow2(vaddr, KB(4)), AlignDownPow2(vaddr, KB(4)) + KB(16)); + DASM_Handle dasm_handle = dasm_handle_from_ctrl_process_range(process->ctrl_machine_id, process->ctrl_handle, disasm_vaddr_rng); + return dasm_handle; +} + +//- rjf: full path building, from file/folder entities + +internal String8 +df_full_path_from_entity(Arena *arena, DF_Entity *entity) +{ + String8 string = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + String8List strs = {0}; + for(DF_Entity *e = entity; !df_entity_is_nil(e); e = e->parent) + { + if(e->kind == DF_EntityKind_File || + e->kind == DF_EntityKind_OverrideFileLink) + { + str8_list_push_front(scratch.arena, &strs, e->name); + } + } + StringJoin join = {0}; + join.sep = str8_lit("/"); + string = str8_list_join(arena, &strs, &join); + scratch_end(scratch); + } + return string; +} + +//- rjf: display string entities, for referencing entities in ui + +internal String8 +df_display_string_from_entity(Arena *arena, DF_Entity *entity) +{ + String8 result = {0}; + switch(entity->kind) + { + default: + { + if(entity->name.size != 0) + { + result = push_str8_copy(arena, entity->name); + } + else + { + String8 kind_string = df_g_entity_kind_display_string_table[entity->kind]; + result = push_str8f(arena, "%S $%I64u", kind_string, entity->id); + } + }break; + + case DF_EntityKind_Target: + { + if(entity->name.size != 0) + { + result = push_str8_copy(arena, entity->name); + } + else + { + DF_Entity *exe = df_entity_child_from_kind(entity, DF_EntityKind_Executable); + result = push_str8_copy(arena, exe->name); + } + }break; + + case DF_EntityKind_Breakpoint: + { + if(entity->name.size != 0) + { + result = push_str8_copy(arena, entity->name); + } + else if(entity->flags & DF_EntityFlag_HasVAddr) + { + result = str8_from_u64(arena, entity->vaddr, 16, 16, 0); + } + else + { + DF_Entity *symb = df_entity_child_from_kind(entity, DF_EntityKind_EntryPointName); + DF_Entity *file = df_entity_ancestor_from_kind(entity, DF_EntityKind_File); + if(!df_entity_is_nil(symb)) + { + result = push_str8_copy(arena, symb->name); + } + else if(!df_entity_is_nil(file) && entity->flags & DF_EntityFlag_HasTextPoint) + { + result = push_str8f(arena, "%S:%I64d:%I64d", file->name, entity->text_point.line, entity->text_point.column); + } + } + }break; + + case DF_EntityKind_Process: + { + DF_Entity *main_mod_child = df_entity_child_from_kind(entity, DF_EntityKind_Module); + String8 main_mod_name = str8_skip_last_slash(main_mod_child->name); + result = push_str8f(arena, "%S%s%sPID: %i%s", + main_mod_name, + main_mod_name.size != 0 ? " " : "", + main_mod_name.size != 0 ? "(" : "", + entity->ctrl_id, + main_mod_name.size != 0 ? ")" : ""); + }break; + + case DF_EntityKind_Thread: + { + String8 name = entity->name; + if(name.size == 0) + { + DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); + DF_Entity *first_thread = df_entity_child_from_kind(process, DF_EntityKind_Thread); + if(first_thread == entity) + { + name = str8_lit("Main Thread"); + } + } + result = push_str8f(arena, "%S%s%sTID: %i%s", + name, + name.size != 0 ? " " : "", + name.size != 0 ? "(" : "", + entity->ctrl_id, + name.size != 0 ? ")" : ""); + }break; + + case DF_EntityKind_Module: + { + result = push_str8_copy(arena, entity->name); + result = str8_skip_last_slash(result); + }break; + } + return result; +} + +//- rjf: entity -> color operations + +internal Vec4F32 +df_hsva_from_entity(DF_Entity *entity) +{ + Vec4F32 result = {0}; + if(entity->flags & DF_EntityFlag_HasColor) + { + result = entity->color_hsva; + } + return result; +} + +internal Vec4F32 +df_rgba_from_entity(DF_Entity *entity) +{ + Vec4F32 result = {0}; + if(entity->flags & DF_EntityFlag_HasColor) + { + Vec3F32 hsv = v3f32(entity->color_hsva.x, entity->color_hsva.y, entity->color_hsva.z); + Vec3F32 rgb = rgb_from_hsv(hsv); + result = v4f32(rgb.x, rgb.y, rgb.z, entity->color_hsva.w); + } + return result; +} + +//////////////////////////////// +//~ rjf: Name Allocation + +internal U64 +df_name_bucket_idx_from_string_size(U64 size) +{ + U64 size_rounded = u64_up_to_pow2(size+1); + size_rounded = ClampBot((1<<4), size_rounded); + U64 bucket_idx = 0; + switch(size_rounded) + { + case 1<<4: {bucket_idx = 0;}break; + case 1<<5: {bucket_idx = 1;}break; + case 1<<6: {bucket_idx = 2;}break; + case 1<<7: {bucket_idx = 3;}break; + case 1<<8: {bucket_idx = 4;}break; + case 1<<9: {bucket_idx = 5;}break; + case 1<<10:{bucket_idx = 6;}break; + default:{bucket_idx = ArrayCount(df_state->free_name_chunks)-1;}break; + } + return bucket_idx; +} + +internal String8 +df_name_alloc(DF_StateDeltaHistory *hist, String8 string) +{ + if(string.size == 0) {return str8_zero();} + U64 bucket_idx = df_name_bucket_idx_from_string_size(string.size); + DF_NameChunkNode *node = df_state->free_name_chunks[bucket_idx]; + + // rjf: pull from bucket free list + if(node != 0) + { + if(bucket_idx == ArrayCount(df_state->free_name_chunks)-1) + { + node = 0; + DF_NameChunkNode *prev = 0; + for(DF_NameChunkNode *n = df_state->free_name_chunks[bucket_idx]; + n != 0; + prev = n, n = n->next) + { + if(n->size >= string.size+1) + { + if(prev == 0) + { + df_state->free_name_chunks[bucket_idx] = n->next; + } + else + { + prev->next = n->next; + } + node = n; + break; + } + } + } + else + { + SLLStackPop(df_state->free_name_chunks[bucket_idx]); + } + } + + // rjf: no found node -> allocate new + if(node == 0) + { + U64 chunk_size = 0; + if(bucket_idx < ArrayCount(df_state->free_name_chunks)-1) + { + chunk_size = 1<<(bucket_idx+4); + } + else + { + chunk_size = u64_up_to_pow2(string.size); + } + U8 *chunk_memory = push_array(df_state->arena, U8, chunk_size); + node = (DF_NameChunkNode *)chunk_memory; + } + + // rjf: fill string & return + String8 allocated_string = str8((U8 *)node, string.size); + MemoryCopy((U8 *)node, string.str, string.size); + return allocated_string; +} + +internal void +df_name_release(DF_StateDeltaHistory *hist, String8 string) +{ + if(string.size == 0) {return;} + U64 bucket_idx = df_name_bucket_idx_from_string_size(string.size); + DF_NameChunkNode *node = (DF_NameChunkNode *)string.str; + node->size = u64_up_to_pow2(string.size); + SLLStackPush(df_state->free_name_chunks[bucket_idx], node); +} + +//////////////////////////////// +//~ rjf: Entity State Functions + +//- rjf: entity mutation notification codepath + +internal void +df_entity_notify_mutation(DF_Entity *entity) +{ + for(DF_Entity *e = entity; !df_entity_is_nil(e); e = e->parent) + { + DF_EntityKindFlags flags = df_g_entity_kind_flags_table[entity->kind]; + if(e == entity && flags & DF_EntityKindFlag_LeafMutationProfileConfig) + { + DF_CmdParams p = {0}; + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WriteProfileData)); + } + if(e == entity && flags & DF_EntityKindFlag_LeafMutationSoftHalt) + { + df_state->entities_mut_soft_halt = 1; + } + if(e == entity && flags & DF_EntityKindFlag_LeafMutationDebugInfoMap) + { + df_state->entities_mut_dbg_info_map = 1; + } + if(flags & DF_EntityKindFlag_TreeMutationSoftHalt) + { + df_state->entities_mut_soft_halt = 1; + } + if(flags & DF_EntityKindFlag_TreeMutationDebugInfoMap) + { + df_state->entities_mut_dbg_info_map = 1; + } + } +} + +//- rjf: entity allocation + tree forming + +internal DF_Entity * +df_entity_alloc(DF_StateDeltaHistory *hist, DF_Entity *parent, DF_EntityKind kind) +{ + B32 user_defined_lifetime = !!(df_g_entity_kind_flags_table[kind] & DF_EntityKindFlag_UserDefinedLifetime); + U64 free_list_idx = !!user_defined_lifetime; + if(df_entity_is_nil(parent)) { parent = df_state->entities_root; } + + // rjf: empty free list -> push new + if(!df_state->entities_free[free_list_idx]) + { + DF_Entity *entity = push_array(df_state->entities_arena, DF_Entity, 1); + df_state->entities_count += 1; + df_state->entities_free_count += 1; + SLLStackPush(df_state->entities_free[free_list_idx], entity); + } + + // rjf: user-defined lifetimes -> push record of df_state info + if(user_defined_lifetime) + { + df_state_delta_history_push_struct_delta(hist, &df_state->entities_root); + df_state_delta_history_push_struct_delta(hist, &df_state->entities_free_count); + df_state_delta_history_push_struct_delta(hist, &df_state->entities_active_count); + df_state_delta_history_push_struct_delta(hist, &df_state->entities_free[free_list_idx]); + df_state_delta_history_push_struct_delta(hist, &df_state->kind_alloc_gens[kind]); + } + + // rjf: pop new entity off free-list + DF_Entity *entity = df_state->entities_free[free_list_idx]; + SLLStackPop(df_state->entities_free[free_list_idx]); + df_state->entities_free_count -= 1; + df_state->entities_active_count += 1; + + // rjf: user-defined lifetimes -> push records of initial entity data + if(user_defined_lifetime) + { + df_state_delta_history_push_struct_delta(hist, &entity->next); + df_state_delta_history_push_struct_delta(hist, &entity->prev); + df_state_delta_history_push_struct_delta(hist, &entity->first); + df_state_delta_history_push_struct_delta(hist, &entity->last); + df_state_delta_history_push_struct_delta(hist, &entity->parent); + df_state_delta_history_push_struct_delta(hist, &entity->generation); + df_state_delta_history_push_struct_delta(hist, &entity->id); + df_state_delta_history_push_struct_delta(hist, &entity->kind); + if(!df_entity_is_nil(parent)) + { + df_state_delta_history_push_struct_delta(hist, &parent->first); + df_state_delta_history_push_struct_delta(hist, &parent->last); + } + if(!df_entity_is_nil(parent->last)) + { + df_state_delta_history_push_struct_delta(hist, &parent->last->next); + } + } + + // rjf: zero entity + { + U64 generation = entity->generation; + MemoryZeroStruct(entity); + entity->generation = generation; + } + + // rjf: set up alloc'd entity links + entity->first = entity->last = entity->next = entity->prev = entity->parent = &df_g_nil_entity; + entity->parent = parent; + + // rjf: stitch up parent links + if(df_entity_is_nil(parent)) + { + df_state->entities_root = entity; + } + else + { + DLLPushBack_NPZ(&df_g_nil_entity, parent->first, parent->last, entity, next, prev); + } + + // rjf: fill out metadata + entity->kind = kind; + df_state->entities_id_gen += 1; + entity->id = df_state->entities_id_gen; + entity->generation += 1; + + // rjf: dirtify caches + df_state->kind_alloc_gens[kind] += 1; + df_entity_notify_mutation(entity); + + return entity; +} + +internal void +df_entity_mark_for_deletion(DF_Entity *entity) +{ + if(!df_entity_is_nil(entity)) + { + entity->flags |= DF_EntityFlag_MarkedForDeletion; + df_entity_notify_mutation(entity); + } +} + +internal void +df_entity_release(DF_StateDeltaHistory *hist, DF_Entity *entity) +{ + Temp scratch = scratch_begin(0, 0); + + // rjf: unpack + U64 free_list_idx = !!(df_g_entity_kind_flags_table[entity->kind] & DF_EntityKindFlag_UserDefinedLifetime); + + // rjf: record pre-deletion entity state + df_state_delta_history_push_struct_delta(hist, &df_state->entities_free_count); + df_state_delta_history_push_struct_delta(hist, &df_state->entities_active_count); + + // rjf: release whole tree + typedef struct Task Task; + struct Task + { + Task *next; + DF_Entity *e; + }; + Task start_task = {0, entity}; + Task *first_task = &start_task; + Task *last_task = &start_task; + for(Task *task = first_task; task != 0; task = task->next) + { + for(DF_Entity *child = task->e->first; !df_entity_is_nil(child); child = child->next) + { + Task *t = push_array(scratch.arena, Task, 1); + t->e = child; + SLLQueuePush(first_task, last_task, t); + } + df_state_delta_history_push_struct_delta(hist, &task->e->first); + df_state_delta_history_push_struct_delta(hist, &task->e->last); + df_state_delta_history_push_struct_delta(hist, &task->e->next); + df_state_delta_history_push_struct_delta(hist, &task->e->prev); + df_state_delta_history_push_struct_delta(hist, &task->e->parent); + df_state_delta_history_push_struct_delta(hist, &df_state->kind_alloc_gens[task->e->kind]); + df_state_delta_history_push_struct_delta(hist, &df_state->entities_free[free_list_idx]); + df_set_thread_freeze_state(task->e, 0); + SLLStackPush(df_state->entities_free[free_list_idx], task->e); + df_state->entities_free_count += 1; + df_state->entities_active_count -= 1; + task->e->generation += 1; + if(task->e->name.size != 0) + { + df_name_release(hist, task->e->name); + } + df_state->kind_alloc_gens[task->e->kind] += 1; + } + + scratch_end(scratch); +} + +internal void +df_entity_change_parent(DF_StateDeltaHistory *hist, DF_Entity *entity, DF_Entity *old_parent, DF_Entity *new_parent) +{ + Assert(entity->parent == old_parent); + + // rjf: push delta records + if(hist != 0) + { + if(!df_entity_is_nil(old_parent)) + { + df_state_delta_history_push_struct_delta(df_state->hist, &old_parent->first); + df_state_delta_history_push_struct_delta(df_state->hist, &old_parent->last); + } + if(!df_entity_is_nil(new_parent)) + { + df_state_delta_history_push_struct_delta(df_state->hist, &new_parent->first); + df_state_delta_history_push_struct_delta(df_state->hist, &new_parent->last); + } + if(!df_entity_is_nil(entity->prev)) + { + df_state_delta_history_push_struct_delta(df_state->hist, &entity->prev->next); + } + if(!df_entity_is_nil(entity->next)) + { + df_state_delta_history_push_struct_delta(df_state->hist, &entity->next->prev); + } + df_state_delta_history_push_struct_delta(df_state->hist, &entity->next); + df_state_delta_history_push_struct_delta(df_state->hist, &entity->prev); + df_state_delta_history_push_struct_delta(df_state->hist, &entity->parent); + } + + // rjf: fix up links + if(!df_entity_is_nil(old_parent)) + { + DLLRemove_NPZ(&df_g_nil_entity, old_parent->first, old_parent->last, entity, next, prev); + } + if(!df_entity_is_nil(new_parent)) + { + DLLPushBack_NPZ(&df_g_nil_entity, new_parent->first, new_parent->last, entity, next, prev); + } + entity->parent = new_parent; + + // rjf: notify + df_entity_notify_mutation(entity); + df_entity_notify_mutation(new_parent); + df_entity_notify_mutation(old_parent); +} + +//- rjf: entity simple equipment + +internal void +df_entity_equip_txt_pt(DF_Entity *entity, TxtPt point) +{ + entity->text_point = point; + entity->flags |= DF_EntityFlag_HasTextPoint; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_txt_pt_alt(DF_Entity *entity, TxtPt point) +{ + entity->text_point_alt = point; + entity->flags |= DF_EntityFlag_HasTextPointAlt; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_entity_handle(DF_Entity *entity, DF_Handle handle) +{ + entity->entity_handle = handle; + entity->flags |= DF_EntityFlag_HasEntityHandle; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_b32(DF_Entity *entity, B32 b32) +{ + entity->b32 = b32; + entity->flags |= DF_EntityFlag_HasB32; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_u64(DF_Entity *entity, U64 u64) +{ + entity->u64 = u64; + entity->flags |= DF_EntityFlag_HasU64; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_rng1u64(DF_Entity *entity, Rng1U64 range) +{ + entity->rng1u64 = range; + entity->flags |= DF_EntityFlag_HasRng1U64; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_color_rgba(DF_Entity *entity, Vec4F32 rgba) +{ + Vec3F32 rgb = v3f32(rgba.x, rgba.y, rgba.z); + Vec3F32 hsv = hsv_from_rgb(rgb); + Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); + df_entity_equip_color_hsva(entity, hsva); +} + +internal void +df_entity_equip_color_hsva(DF_Entity *entity, Vec4F32 hsva) +{ + entity->color_hsva = hsva; + entity->flags |= DF_EntityFlag_HasColor; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_death_timer(DF_Entity *entity, F32 seconds_til_death) +{ + entity->flags |= DF_EntityFlag_DiesWithTime; + entity->life_left = seconds_til_death; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src) +{ + entity->cfg_src = cfg_src; + df_entity_notify_mutation(entity); +} + +//- rjf: control layer correllation equipment + +internal void +df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id) +{ + entity->ctrl_machine_id = machine_id; + entity->flags |= DF_EntityFlag_HasCtrlMachineID; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle) +{ + entity->ctrl_handle = handle; + entity->flags |= DF_EntityFlag_HasCtrlHandle; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_arch(DF_Entity *entity, Architecture arch) +{ + entity->arch = arch; + entity->flags |= DF_EntityFlag_HasArch; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_ctrl_id(DF_Entity *entity, U32 id) +{ + entity->ctrl_id = id; + entity->flags |= DF_EntityFlag_HasCtrlID; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_stack_base(DF_Entity *entity, U64 stack_base) +{ + entity->stack_base = stack_base; + entity->flags |= DF_EntityFlag_HasStackBase; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_tls_root(DF_Entity *entity, U64 tls_root) +{ + entity->tls_root = tls_root; + entity->flags |= DF_EntityFlag_HasTLSRoot; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_vaddr_rng(DF_Entity *entity, Rng1U64 range) +{ + entity->vaddr_rng = range; + entity->flags |= DF_EntityFlag_HasVAddrRng; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_vaddr(DF_Entity *entity, U64 vaddr) +{ + entity->vaddr = vaddr; + entity->flags |= DF_EntityFlag_HasVAddr; + df_entity_notify_mutation(entity); +} + +//- rjf: name equipment + +internal void +df_entity_equip_name(DF_StateDeltaHistory *hist, DF_Entity *entity, String8 name) +{ + entity->name = df_name_alloc(hist, name); + entity->name_generation += 1; + df_entity_notify_mutation(entity); +} + +internal void +df_entity_equip_namef(DF_StateDeltaHistory *hist, DF_Entity *entity, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + df_entity_equip_name(hist, entity, string); + scratch_end(scratch); +} + +//- rjf: opening folders/files & maintaining the entity model of the filesystem + +internal DF_Entity * +df_entity_from_path(String8 path, DF_EntityFromPathFlags flags) +{ + Temp scratch = scratch_begin(0, 0); + PathStyle path_style = PathStyle_Relative; + String8List path_parts = path_normalized_list_from_string(scratch.arena, path, &path_style); + StringMatchFlags path_match_flags = path_match_flags_from_os(operating_system_from_context()); + + //- rjf: pass 1: open parts, ignore overrides + DF_Entity *file_no_override = &df_g_nil_entity; + { + DF_Entity *parent = df_entity_root(); + for(String8Node *path_part_n = path_parts.first; + path_part_n != 0; + path_part_n = path_part_n->next) + { + // rjf: find next child + DF_Entity *next_parent = &df_g_nil_entity; + for(DF_Entity *child = parent->first; !df_entity_is_nil(child); child = child->next) + { + B32 name_matches = str8_match(child->name, path_part_n->string, path_match_flags); + if(name_matches && child->kind == DF_EntityKind_File) + { + next_parent = child; + break; + } + } + + // rjf: no next -> allocate one + if(df_entity_is_nil(next_parent)) + { + if(flags & DF_EntityFromPathFlag_OpenAsNeeded) + { + String8 parent_path = df_full_path_from_entity(scratch.arena, parent); + String8 path = push_str8f(scratch.arena, "%S%s%S", parent_path, parent_path.size != 0 ? "/" : "", path_part_n->string); + FileProperties file_properties = os_properties_from_file_path(path); + if(file_properties.created != 0 || flags & DF_EntityFromPathFlag_OpenMissing) + { + next_parent = df_entity_alloc(0, parent, DF_EntityKind_File); + df_entity_equip_name(0, next_parent, path_part_n->string); + next_parent->timestamp = file_properties.modified; + next_parent->flags |= DF_EntityFlag_IsFolder * !!(file_properties.flags & FilePropertyFlag_IsFolder); + next_parent->flags |= DF_EntityFlag_IsMissing * !!(file_properties.created == 0); + } + } + else + { + parent = &df_g_nil_entity; + break; + } + } + + // rjf: next parent -> follow it + parent = next_parent; + } + file_no_override = parent; + } + + //- rjf: pass 2: follow overrides + DF_Entity *file_overrides_applied = &df_g_nil_entity; + if(flags & DF_EntityFromPathFlag_AllowOverrides) + { + DF_Entity *parent = df_entity_root(); + for(String8Node *path_part_n = path_parts.first; + path_part_n != 0; + path_part_n = path_part_n->next) + { + // rjf: find next child + DF_Entity *next_parent = &df_g_nil_entity; + for(DF_Entity *child = parent->first; !df_entity_is_nil(child); child = child->next) + { + B32 name_matches = str8_match(child->name, path_part_n->string, path_match_flags); + if(name_matches && child->kind == DF_EntityKind_File) + { + next_parent = child; + } + if(name_matches && child->kind == DF_EntityKind_OverrideFileLink) + { + next_parent = df_entity_from_handle(child->entity_handle); + break; + } + } + + // rjf: no next -> allocate one + if(df_entity_is_nil(next_parent)) + { + if(flags & DF_EntityFromPathFlag_OpenAsNeeded) + { + String8 parent_path = df_full_path_from_entity(scratch.arena, parent); + String8 path = push_str8f(scratch.arena, "%S%s%S", parent_path, parent_path.size != 0 ? "/" : "", path_part_n->string); + FileProperties file_properties = os_properties_from_file_path(path); + if(file_properties.created != 0 || flags & DF_EntityFromPathFlag_OpenMissing) + { + next_parent = df_entity_alloc(0, parent, DF_EntityKind_File); + df_entity_equip_name(0, next_parent, path_part_n->string); + next_parent->timestamp = file_properties.modified; + next_parent->flags |= DF_EntityFlag_IsFolder * !!(file_properties.flags & FilePropertyFlag_IsFolder); + next_parent->flags |= DF_EntityFlag_IsMissing * !!(file_properties.created == 0); + } + } + else + { + parent = &df_g_nil_entity; + break; + } + } + + // rjf: next parent -> follow it + parent = next_parent; + } + file_overrides_applied = parent; + } + + //- rjf: pick & return result + DF_Entity *result = (flags & DF_EntityFromPathFlag_AllowOverrides) ? file_overrides_applied : file_no_override; + if(flags & DF_EntityFromPathFlag_AllowOverrides && + result == file_overrides_applied && + result->flags & DF_EntityFlag_IsMissing) + { + result = file_no_override; + } + + scratch_end(scratch); + return result; +} + +internal DF_EntityList +df_possible_overrides_from_entity(Arena *arena, DF_Entity *entity) +{ + Temp scratch = scratch_begin(&arena, 1); + StringMatchFlags path_match_flags = path_match_flags_from_os(operating_system_from_context()); + DF_EntityList result = {0}; + df_entity_list_push(arena, &result, entity); + { + DF_EntityList links = df_query_cached_entity_list_with_kind(DF_EntityKind_OverrideFileLink); + String8List p_chain_names_to_entity = {0}; + for(DF_Entity *p = entity; + !df_entity_is_nil(p); + str8_list_push_front(scratch.arena, &p_chain_names_to_entity, p->name), p = p->parent) + { + // rjf: gather all links which would redirect to this chain + DF_EntityList links_going_to_p = {0}; + for(DF_EntityNode *n = links.first; n != 0; n = n->next) + { + DF_Entity *link_src = n->entity; + DF_Entity *link_dst = df_entity_from_handle(link_src->entity_handle); + if(link_dst == p) + { + df_entity_list_push(scratch.arena, &links_going_to_p, link_src); + } + } + + // rjf: for each link, gather possible overrides + for(DF_EntityNode *n = links_going_to_p.first; n != 0; n = n->next) + { + DF_Entity *link_src = n->entity; + DF_Entity *link_src_parent = link_src->parent; + + // rjf: find the sibling that this link overrides + DF_Entity *link_overridden_sibling = &df_g_nil_entity; + for(DF_Entity *child = link_src_parent->first; + !df_entity_is_nil(child); + child = child->next) + { + B32 name_matches = str8_match(child->name, link_src->name, path_match_flags); + if(name_matches && child->kind == DF_EntityKind_File) + { + link_overridden_sibling = child; + break; + } + } + + // rjf: descend tree if needed, by the chain names, find override + DF_Entity *override = link_overridden_sibling; + { + DF_Entity *parent = override; + for(String8Node *path_part_n = p_chain_names_to_entity.first; + path_part_n != 0; + path_part_n = path_part_n->next) + { + // rjf: find next child + DF_Entity *next_parent = &df_g_nil_entity; + for(DF_Entity *child = parent->first; !df_entity_is_nil(child); child = child->next) + { + B32 name_matches = str8_match(child->name, path_part_n->string, path_match_flags); + if(name_matches && child->kind == DF_EntityKind_File) + { + next_parent = child; + break; + } + } + + // rjf: no next -> allocate one + if(df_entity_is_nil(next_parent)) + { + next_parent = df_entity_alloc(0, parent, DF_EntityKind_File); + df_entity_equip_name(0, next_parent, path_part_n->string); + String8 path = df_full_path_from_entity(scratch.arena, next_parent); + FileProperties file_properties = os_properties_from_file_path(path); + next_parent->timestamp = file_properties.modified; + next_parent->flags |= DF_EntityFlag_IsFolder * !!(file_properties.flags & FilePropertyFlag_IsFolder); + next_parent->flags |= DF_EntityFlag_IsMissing * !!(file_properties.created == 0); + } + + // rjf: next parent -> follow it + parent = next_parent; + } + override = parent; + } + + // rjf: valid override -> push + if(!df_entity_is_nil(override)) + { + df_entity_list_push(arena, &result, override); + } + } + } + } + scratch_end(scratch); + return result; +} + +//- rjf: top-level state queries + +internal DF_Entity * +df_entity_root(void) +{ + return df_state->entities_root; +} + +internal DF_EntityList +df_push_entity_list_with_kind(Arena *arena, DF_EntityKind kind) +{ + ProfBeginFunction(); + DF_EntityList result = {0}; + for(DF_Entity *entity = df_state->entities_root; + !df_entity_is_nil(entity); + entity = df_entity_rec_df_pre(entity, &df_g_nil_entity).next) + { + if(!entity->deleted && entity->kind == kind) + { + df_entity_list_push(arena, &result, entity); + } + } + ProfEnd(); + return result; +} + +internal DF_Entity * +df_entity_from_id(DF_EntityID id) +{ + DF_Entity *result = &df_g_nil_entity; + for(DF_Entity *e = df_entity_root(); + !df_entity_is_nil(e); + e = df_entity_rec_df_pre(e, &df_g_nil_entity).next) + { + if(e->id == id) + { + result = e; + break; + } + } + return result; +} + +internal DF_Entity * +df_machine_entity_from_machine_id(CTRL_MachineID machine_id) +{ + DF_Entity *result = &df_g_nil_entity; + for(DF_Entity *e = df_entity_root(); + !df_entity_is_nil(e); + e = df_entity_rec_df_pre(e, &df_g_nil_entity).next) + { + if(e->kind == DF_EntityKind_Machine && e->ctrl_machine_id == machine_id) + { + result = e; + break; + } + } + if(df_entity_is_nil(result)) + { + result = df_entity_alloc(0, df_entity_root(), DF_EntityKind_Machine); + df_entity_equip_ctrl_machine_id(result, machine_id); + } + return result; +} + +internal DF_Entity * +df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle) +{ + DF_Entity *result = &df_g_nil_entity; + if(handle.u64[0] != 0) + { + for(DF_Entity *e = df_entity_root(); + !df_entity_is_nil(e); + e = df_entity_rec_df_pre(e, &df_g_nil_entity).next) + { + if(e->flags & DF_EntityFlag_HasCtrlMachineID && + e->flags & DF_EntityFlag_HasCtrlHandle && + e->ctrl_machine_id == machine_id && + MemoryMatchStruct(&e->ctrl_handle, &handle)) + { + result = e; + break; + } + } + } + return result; +} + +internal DF_Entity * +df_entity_from_ctrl_id(CTRL_MachineID machine_id, U32 id) +{ + DF_Entity *result = &df_g_nil_entity; + if(id != 0) + { + for(DF_Entity *e = df_entity_root(); + !df_entity_is_nil(e); + e = df_entity_rec_df_pre(e, &df_g_nil_entity).next) + { + if(e->flags & DF_EntityFlag_HasCtrlMachineID && + e->flags & DF_EntityFlag_HasCtrlID && + e->ctrl_machine_id == machine_id && + e->ctrl_id == id) + { + result = e; + break; + } + } + } + return result; +} + +internal DF_Entity * +df_entity_from_name_and_kind(String8 string, DF_EntityKind kind) +{ + DF_Entity *result = &df_g_nil_entity; + DF_EntityList all_of_this_kind = df_query_cached_entity_list_with_kind(kind); + for(DF_EntityNode *n = all_of_this_kind.first; n != 0; n = n->next) + { + if(str8_match(n->entity->name, string, 0)) + { + result = n->entity; + break; + } + } + return result; +} + +internal DF_Entity * +df_entity_from_u64_and_kind(U64 u64, DF_EntityKind kind) +{ + DF_Entity *result = &df_g_nil_entity; + DF_EntityList all_of_this_kind = df_query_cached_entity_list_with_kind(kind); + for(DF_EntityNode *n = all_of_this_kind.first; n != 0; n = n->next) + { + if(n->entity->u64 == u64) + { + result = n->entity; + break; + } + } + return result; +} + +//- rjf: entity freezing state + +internal void +df_set_thread_freeze_state(DF_Entity *thread, B32 frozen) +{ + DF_Handle thread_handle = df_handle_from_entity(thread); + DF_HandleNode *already_frozen_node = df_handle_list_find(&df_state->frozen_threads, thread_handle); + B32 is_frozen = !!already_frozen_node; + B32 should_be_frozen = frozen; + + // rjf: not frozen => frozen + if(!is_frozen && should_be_frozen) + { + DF_HandleNode *node = df_state->free_handle_node; + if(node) + { + SLLStackPop(df_state->free_handle_node); + } + else + { + node = push_array(df_state->arena, DF_HandleNode, 1); + } + node->handle = thread_handle; + df_handle_list_push_node(&df_state->frozen_threads, node); + } + + // rjf: frozen => not frozen + if(is_frozen && !should_be_frozen) + { + df_handle_list_remove(&df_state->frozen_threads, already_frozen_node); + SLLStackPush(df_state->free_handle_node, already_frozen_node); + } + + df_entity_notify_mutation(thread); +} + +internal B32 +df_entity_is_frozen(DF_Entity *entity) +{ + B32 is_frozen = !df_entity_is_nil(entity); + for(DF_Entity *e = entity; !df_entity_is_nil(e); e = df_entity_rec_df_pre(e, entity).next) + { + if(e->kind == DF_EntityKind_Thread) + { + B32 thread_is_frozen = !!df_handle_list_find(&df_state->frozen_threads, df_handle_from_entity(e)); + if(!thread_is_frozen) + { + is_frozen = 0; + break; + } + } + } + return is_frozen; +} + +//////////////////////////////// +//~ rjf: Command Stateful Functions + +internal void +df_register_cmd_specs(DF_CmdSpecInfoArray specs) +{ + U64 registrar_idx = df_state->total_registrar_count; + df_state->total_registrar_count += 1; + for(U64 idx = 0; idx < specs.count; idx += 1) + { + // rjf: extract info from array slot + DF_CmdSpecInfo *info = &specs.v[idx]; + + // rjf: skip empties + if(info->string.size == 0) + { + continue; + } + + // rjf: determine hash/slot + U64 hash = df_hash_from_string(info->string); + U64 slot = hash % df_state->cmd_spec_table_size; + + // rjf: allocate node & push + DF_CmdSpec *spec = push_array(df_state->arena, DF_CmdSpec, 1); + SLLStackPush_N(df_state->cmd_spec_table[slot], spec, hash_next); + + // rjf: fill node + DF_CmdSpecInfo *info_copy = &spec->info; + info_copy->string = push_str8_copy(df_state->arena, info->string); + info_copy->description = push_str8_copy(df_state->arena, info->description); + info_copy->search_tags = push_str8_copy(df_state->arena, info->search_tags); + info_copy->display_name = push_str8_copy(df_state->arena, info->display_name); + info_copy->flags = info->flags; + info_copy->query_rule = info->query_rule; + info_copy->canonical_icon_kind = info->canonical_icon_kind; + MemoryCopyArray(info_copy->query_info_u64, info->query_info_u64); + spec->registrar_index = registrar_idx; + spec->ordering_index = idx; + } +} + +internal DF_CmdSpec * +df_cmd_spec_from_string(String8 string) +{ + DF_CmdSpec *result = &df_g_nil_cmd_spec; + { + U64 hash = df_hash_from_string(string); + U64 slot = hash%df_state->cmd_spec_table_size; + for(DF_CmdSpec *n = df_state->cmd_spec_table[slot]; n != 0; n = n->hash_next) + { + if(str8_match(n->info.string, string, 0)) + { + result = n; + break; + } + } + } + return result; +} + +internal DF_CmdSpec * +df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind core_cmd_kind) +{ + String8 string = df_g_core_cmd_kind_spec_info_table[core_cmd_kind].string; + DF_CmdSpec *result = df_cmd_spec_from_string(string); + return result; +} + +internal void +df_cmd_spec_counter_inc(DF_CmdSpec *spec) +{ + if(!df_cmd_spec_is_nil(spec)) + { + spec->run_count += 1; + } +} + +internal DF_CmdSpecList +df_push_cmd_spec_list(Arena *arena) +{ + DF_CmdSpecList list = {0}; + for(U64 idx = 0; idx < df_state->cmd_spec_table_size; idx += 1) + { + for(DF_CmdSpec *spec = df_state->cmd_spec_table[idx]; spec != 0; spec = spec->hash_next) + { + df_cmd_spec_list_push(arena, &list, spec); + } + } + return list; +} + +//////////////////////////////// +//~ rjf: View Rule Spec Stateful Functions + +internal void +df_register_core_view_rule_specs(DF_CoreViewRuleSpecInfoArray specs) +{ + for(U64 idx = 0; idx < specs.count; idx += 1) + { + // rjf: extract info from array slot + DF_CoreViewRuleSpecInfo *info = &specs.v[idx]; + + // rjf: skip empties + if(info->string.size == 0) + { + continue; + } + + // rjf: determine hash/slot + U64 hash = df_hash_from_string(info->string); + U64 slot_idx = hash%df_state->view_rule_spec_table_size; + + // rjf: allocate node & push + DF_CoreViewRuleSpec *spec = push_array(df_state->arena, DF_CoreViewRuleSpec, 1); + SLLStackPush_N(df_state->view_rule_spec_table[slot_idx], spec, hash_next); + + // rjf: fill node + DF_CoreViewRuleSpecInfo *info_copy = &spec->info; + MemoryCopyStruct(info_copy, info); + info_copy->string = push_str8_copy(df_state->arena, info->string); + info_copy->display_string = push_str8_copy(df_state->arena, info->display_string); + info_copy->description = push_str8_copy(df_state->arena, info->description); + } +} + +internal DF_CoreViewRuleSpec * +df_core_view_rule_spec_from_string(String8 string) +{ + DF_CoreViewRuleSpec *spec = &df_g_nil_core_view_rule_spec; + { + U64 hash = df_hash_from_string(string); + U64 slot_idx = hash%df_state->view_rule_spec_table_size; + for(DF_CoreViewRuleSpec *s = df_state->view_rule_spec_table[slot_idx]; s != 0; s = s->hash_next) + { + if(str8_match(string, s->info.string, 0)) + { + spec = s; + break; + } + } + } + return spec; +} + +//////////////////////////////// +//~ rjf: Debug Info Mapping + +internal String8 +df_debug_info_path_from_module(Arena *arena, DF_Entity *module) +{ + ProfBeginFunction(); + String8 result = {0}; + DF_Entity *override_entity = df_entity_child_from_kind(module, DF_EntityKind_DebugInfoOverride); + if(!df_entity_is_nil(override_entity) && override_entity->name.size != 0) + { + result = override_entity->name; + } + else + { + Temp scratch = scratch_begin(&arena, 1); + String8 exe_path = module->name; + String8 dbg_path = ctrl_og_dbg_path_from_exe_path(arena, exe_path); + result = dbg_path; + scratch_end(scratch); + } + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Stepping "Trap Net" Builders + +internal CTRL_TrapList +df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread) +{ + Temp scratch = scratch_begin(&arena, 1); + CTRL_TrapList result = {0}; + + // rjf: thread => unpacked info + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + Architecture arch = df_architecture_from_entity(thread); + U64 ip_vaddr = df_rip_from_thread(thread); + + // rjf: ip => machine code + String8 machine_code = {0}; + { + Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch)); + machine_code.str = push_array_no_zero(scratch.arena, U8, max_instruction_size_from_arch(arch)); + machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, rng, machine_code.str); + } + + // rjf: build traps if machine code was read successfully + if(machine_code.size != 0) + { + // rjf: decode instruction + DF_Inst inst = df_single_inst_from_machine_code(scratch.arena, arch, ip_vaddr, machine_code); + + // rjf: call => run until call returns + if(inst.flags & DF_InstFlag_Call || inst.flags & DF_InstFlag_Repeats) + { + CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, ip_vaddr+inst.size}; + ctrl_trap_list_push(arena, &result, &trap); + } + } + + scratch_end(scratch); + return result; +} + +internal CTRL_TrapList +df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) +{ + Temp scratch = scratch_begin(&arena, 1); + CTRL_TrapList result = {0}; + + // rjf: thread => info + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_thread(thread); + DF_Entity *binary = df_binary_file_from_module(module); + Architecture arch = df_architecture_from_entity(thread); + U64 ip_vaddr = df_rip_from_thread(thread); + + // rjf: ip => line vaddr range + Rng1U64 line_vaddr_rng = {0}; + { + U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, ip_voff); + Rng1U64 line_voff_rng = line_info.voff_range; + if(line_voff_rng.max != 0) + { + line_vaddr_rng = df_vaddr_range_from_voff_range(module, line_voff_rng); + } + } + + // rjf: line vaddr range => did we find anything successfully? + B32 good_line_info = (line_vaddr_rng.max != 0); + + // rjf: line vaddr range => line's machine code + String8 machine_code = {0}; + if(good_line_info) + { + machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng)); + machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str); + } + + // rjf: machine code => ctrl flow analysis + DF_CtrlFlowInfo ctrl_flow_info = {0}; + if(good_line_info) + { + ctrl_flow_info = df_ctrl_flow_info_from_arch_vaddr_code(scratch.arena, + DF_InstFlag_Call| + DF_InstFlag_Branch| + DF_InstFlag_UnconditionalJump| + DF_InstFlag_ChangesStackPointer| + DF_InstFlag_Return, + arch, + line_vaddr_rng.min, + machine_code); + } + + // rjf: push traps for all exit points + if(good_line_info) for(DF_CtrlFlowPointNode *n = ctrl_flow_info.exit_points.first; n != 0; n = n->next) + { + DF_CtrlFlowPoint *point = &n->point; + CTRL_TrapFlags flags = 0; + B32 add = 1; + U64 trap_addr = point->vaddr; + + // rjf: branches/jumps/returns => single-step & end, OR trap @ destination. + if(point->inst_flags & (DF_InstFlag_Branch| + DF_InstFlag_UnconditionalJump| + DF_InstFlag_Return)) + { + flags |= (CTRL_TrapFlag_SingleStepAfterHit|CTRL_TrapFlag_EndStepping); + + // rjf: omit if this jump stays inside of this line + if(contains_1u64(line_vaddr_rng, point->jump_dest_vaddr)) + { + add = 0; + } + + // rjf: trap @ destination, if we can - we can avoid a single-step this way. + if(point->jump_dest_vaddr != 0) + { + trap_addr = point->jump_dest_vaddr; + flags &= ~CTRL_TrapFlag_SingleStepAfterHit; + } + + } + + // rjf: call => place spoof at return spot in stack, single-step after hitting + else if(point->inst_flags & DF_InstFlag_Call) + { + flags |= (CTRL_TrapFlag_BeginSpoofMode|CTRL_TrapFlag_SingleStepAfterHit); + } + + // rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping + else if(point->inst_flags & DF_InstFlag_ChangesStackPointer) + { + flags |= (CTRL_TrapFlag_SingleStepAfterHit|CTRL_TrapFlag_SaveStackPointer); + } + + // rjf: add if appropriate + if(add) + { + CTRL_Trap trap = {flags, trap_addr}; + ctrl_trap_list_push(arena, &result, &trap); + } + } + + // rjf: push trap for natural linear flow + if(good_line_info) + { + CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max}; + ctrl_trap_list_push(arena, &result, &trap); + } + + scratch_end(scratch); + return result; +} + +internal CTRL_TrapList +df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) +{ + Temp scratch = scratch_begin(&arena, 1); + CTRL_TrapList result = {0}; + + // rjf: thread => info + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_thread(thread); + DF_Entity *binary = df_binary_file_from_module(module); + Architecture arch = df_architecture_from_entity(thread); + U64 ip_vaddr = df_rip_from_thread(thread); + + // rjf: ip => line vaddr range + Rng1U64 line_vaddr_rng = {0}; + { + U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, ip_voff); + Rng1U64 line_voff_rng = line_info.voff_range; + if(line_voff_rng.max != 0) + { + line_vaddr_rng = df_vaddr_range_from_voff_range(module, line_voff_rng); + } + } + + // rjf: line vaddr range => did we find anything successfully? + B32 good_line_info = (line_vaddr_rng.max != 0); + + // rjf: line vaddr range => line's machine code + String8 machine_code = {0}; + if(good_line_info) + { + machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng)); + machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str); + } + + // rjf: machine code => ctrl flow analysis + DF_CtrlFlowInfo ctrl_flow_info = {0}; + if(good_line_info) + { + ctrl_flow_info = df_ctrl_flow_info_from_arch_vaddr_code(scratch.arena, + DF_InstFlag_Call| + DF_InstFlag_Branch| + DF_InstFlag_UnconditionalJump| + DF_InstFlag_ChangesStackPointer| + DF_InstFlag_Return, + arch, + line_vaddr_rng.min, + machine_code); + } + + // rjf: push traps for all exit points + if(good_line_info) for(DF_CtrlFlowPointNode *n = ctrl_flow_info.exit_points.first; n != 0; n = n->next) + { + DF_CtrlFlowPoint *point = &n->point; + CTRL_TrapFlags flags = 0; + B32 add = 1; + U64 trap_addr = point->vaddr; + + // rjf: branches/jumps/returns => single-step & end, OR trap @ destination. + if(point->inst_flags & (DF_InstFlag_Call| + DF_InstFlag_Branch| + DF_InstFlag_UnconditionalJump| + DF_InstFlag_Return)) + { + flags |= (CTRL_TrapFlag_SingleStepAfterHit|CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck); + + // rjf: omit if this jump stays inside of this line + if(contains_1u64(line_vaddr_rng, point->jump_dest_vaddr)) + { + add = 0; + } + + // rjf: trap @ destination, if we can - we can avoid a single-step this way. + if(point->jump_dest_vaddr != 0) + { + trap_addr = point->jump_dest_vaddr; + flags &= ~CTRL_TrapFlag_SingleStepAfterHit; + } + } + + // rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping + else if(point->inst_flags & DF_InstFlag_ChangesStackPointer) + { + flags |= (CTRL_TrapFlag_SingleStepAfterHit|CTRL_TrapFlag_SaveStackPointer); + } + + // rjf: add if appropriate + if(add) + { + CTRL_Trap trap = {flags, trap_addr}; + ctrl_trap_list_push(arena, &result, &trap); + } + } + + // rjf: push trap for natural linear flow + if(good_line_info) + { + CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max}; + ctrl_trap_list_push(arena, &result, &trap); + } + + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Modules & Debug Info Mappings + +//- rjf: module <=> binary file + +internal DF_Entity * +df_binary_file_from_module(DF_Entity *module) +{ + DF_Entity *binary = df_entity_from_handle(module->entity_handle); + return binary; +} + +internal DF_EntityList +df_modules_from_binary_file(Arena *arena, DF_Entity *binary_info) +{ + DF_EntityList list = {0}; + DF_EntityList all_modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); + for(DF_EntityNode *n = all_modules.first; n != 0; n = n->next) + { + DF_Entity *module = n->entity; + DF_Entity *module_binary_info = df_binary_file_from_module(module); + if(module_binary_info == binary_info) + { + df_entity_list_push(arena, &list, module); + } + } + return list; +} + +//- rjf: voff <=> vaddr + +internal U64 +df_base_vaddr_from_module(DF_Entity *module) +{ + U64 module_base_vaddr = module->vaddr; + return module_base_vaddr; +} + +internal U64 +df_voff_from_vaddr(DF_Entity *module, U64 vaddr) +{ + U64 module_base_vaddr = df_base_vaddr_from_module(module); + U64 voff = vaddr - module_base_vaddr; + return voff; +} + +internal U64 +df_vaddr_from_voff(DF_Entity *module, U64 voff) +{ + U64 module_base_vaddr = df_base_vaddr_from_module(module); + U64 vaddr = voff + module_base_vaddr; + return vaddr; +} + +internal Rng1U64 +df_voff_range_from_vaddr_range(DF_Entity *module, Rng1U64 vaddr_rng) +{ + U64 rng_size = dim_1u64(vaddr_rng); + Rng1U64 voff_rng = {0}; + voff_rng.min = df_voff_from_vaddr(module, vaddr_rng.min); + voff_rng.max = voff_rng.min + rng_size; + return voff_rng; +} + +internal Rng1U64 +df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_rng) +{ + U64 rng_size = dim_1u64(voff_rng); + Rng1U64 vaddr_rng = {0}; + vaddr_rng.min = df_vaddr_from_voff(module, voff_rng.min); + vaddr_rng.max = vaddr_rng.min + rng_size; + return vaddr_rng; +} + +//////////////////////////////// +//~ rjf: Debug Info Lookups + +//- rjf: binary file -> dbgi parse + +internal DBGI_Parse * +df_dbgi_parse_from_binary_file(DBGI_Scope *scope, DF_Entity *binary) +{ + Temp scratch = scratch_begin(0, 0); + String8 exe_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, 0); + scratch_end(scratch); + return dbgi; +} + +//- rjf: symbol lookups + +internal String8 +df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff) +{ + String8 result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + String8 path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + if(rdbg->scope_vmap != 0) + { + U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff); + RADDBG_Scope *scope = &rdbg->scopes[scope_idx]; + U64 proc_idx = scope->proc_idx; + RADDBG_Procedure *procedure = &rdbg->procedures[proc_idx]; + U64 name_size = 0; + U8 *name_ptr = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size); + result = push_str8_copy(arena, str8(name_ptr, name_size)); + } + dbgi_scope_close(scope); + scratch_end(scratch); + } + return result; +} + +internal String8 +df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr) +{ + String8 result = {0}; + { + DF_Entity *module = df_module_from_process_vaddr(process, vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 voff = df_voff_from_vaddr(module, vaddr); + result = df_symbol_name_from_binary_voff(arena, binary, voff); + } + return result; +} + +//- rjf: src -> voff lookups + +internal DF_TextLineSrc2DasmInfoListArray +df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entity *file, Rng1S64 line_num_range) +{ + DF_TextLineSrc2DasmInfoListArray src2dasm_array = {0}; + { + src2dasm_array.count = dim_1s64(line_num_range)+1; + src2dasm_array.v = push_array(arena, DF_TextLineSrc2DasmInfoList, src2dasm_array.count); + } + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + DF_EntityList overrides = df_possible_overrides_from_entity(scratch.arena, file); + for(DF_EntityNode *override_n = overrides.first; + override_n != 0; + override_n = override_n->next) + { + DF_Entity *override = override_n->entity; + String8 file_path = df_full_path_from_entity(scratch.arena, override); + String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); + for(DF_EntityNode *binary_n = binaries.first; + binary_n != 0; + binary_n = binary_n->next) + { + // rjf: binary -> rdbg + DF_Entity *binary = binary_n->entity; + String8 binary_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + + // rjf: file_path_normalized * rdbg -> src_id + B32 good_src_id = 0; + U32 src_id = 0; + if(dbgi != &dbgi_parse_nil) + { + RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_NormalSourcePaths); + if(mapptr != 0) + { + RADDBG_ParsedNameMap map = {0}; + raddbg_name_map_parse(rdbg, mapptr, &map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, file_path_normalized.str, file_path_normalized.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + if(id_count > 0) + { + good_src_id = 1; + src_id = ids[0]; + } + } + } + } + + // rjf: good src-id -> look up line info for visible range + if(good_src_id) + { + RADDBG_SourceFile *src = rdbg->source_files+src_id; + RADDBG_ParsedLineMap line_map = {0}; + raddbg_line_map_from_source_file(rdbg, src, &line_map); + U64 line_idx = 0; + for(S64 line_num = line_num_range.min; + line_num <= line_num_range.max; + line_num += 1, line_idx += 1) + { + DF_TextLineSrc2DasmInfoList *src2dasm_list = &src2dasm_array.v[line_idx]; + U32 voff_count = 0; + U64 *voffs = raddbg_line_voffs_from_num(&line_map, u32_from_u64_saturate((U64)line_num), &voff_count); + for(U64 idx = 0; idx < voff_count; idx += 1) + { + U64 base_voff = voffs[idx]; + U64 unit_idx = raddbg_vmap_idx_from_voff(rdbg->unit_vmap, rdbg->unit_vmap_count, base_voff); + RADDBG_Unit *unit = &rdbg->units[unit_idx]; + RADDBG_ParsedLineInfo unit_line_info = {0}; + raddbg_line_info_from_unit(rdbg, unit, &unit_line_info); + U64 line_info_idx = raddbg_line_info_idx_from_voff(&unit_line_info, base_voff); + if(unit_line_info.voffs != 0) + { + Rng1U64 range = r1u64(base_voff, unit_line_info.voffs[line_info_idx+1]); + S64 actual_line = (S64)unit_line_info.lines[line_info_idx].line_num; + DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(arena, DF_TextLineSrc2DasmInfoNode, 1); + src2dasm_n->v.voff_range = range; + src2dasm_n->v.remap_line = (S64)actual_line; + src2dasm_n->v.binary = binary; + SLLQueuePush(src2dasm_list->first, src2dasm_list->last, src2dasm_n); + src2dasm_list->count += 1; + } + } + } + } + + // rjf: good src id -> push to relevant binaries + if(good_src_id) + { + df_entity_list_push(arena, &src2dasm_array.binaries, binary); + } + } + } + dbgi_scope_close(scope); + scratch_end(scratch); + return src2dasm_array; +} + +//- rjf: voff -> src lookups + +internal DF_TextLineDasm2SrcInfo +df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) +{ + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + String8 path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + DF_TextLineDasm2SrcInfo result = {0}; + result.file = result.binary = &df_g_nil_entity; + if(rdbg->unit_vmap != 0 && rdbg->units != 0 && rdbg->source_files != 0) + { + U64 unit_idx = raddbg_vmap_idx_from_voff(rdbg->unit_vmap, rdbg->unit_vmap_count, voff); + RADDBG_Unit *unit = &rdbg->units[unit_idx]; + RADDBG_ParsedLineInfo unit_line_info = {0}; + raddbg_line_info_from_unit(rdbg, unit, &unit_line_info); + U64 line_info_idx = raddbg_line_info_idx_from_voff(&unit_line_info, voff); + if(line_info_idx < unit_line_info.count) + { + RADDBG_Line *line = &unit_line_info.lines[line_info_idx]; + RADDBG_Column *column = (line_info_idx < unit_line_info.col_count) ? &unit_line_info.cols[line_info_idx] : 0; + RADDBG_SourceFile *file = &rdbg->source_files[line->file_idx]; + String8 file_normalized_full_path = {0}; + file_normalized_full_path.str = raddbg_string_from_idx(rdbg, file->normal_full_path_string_idx, &file_normalized_full_path.size); + result.binary = binary; + if(line->file_idx != 0 && file_normalized_full_path.size != 0) + { + result.file = df_entity_from_path(file_normalized_full_path, DF_EntityFromPathFlag_All); + } + result.pt = txt_pt(line->line_num, column ? column->col_first : 1); + result.voff_range = r1u64(unit_line_info.voffs[line_info_idx], unit_line_info.voffs[line_info_idx+1]); + } + } + + dbgi_scope_close(scope); + scratch_end(scratch); + return result; +} + +internal DF_TextLineDasm2SrcInfoList +df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff) +{ + Temp scratch = scratch_begin(&arena, 1); + DF_TextLineDasm2SrcInfoList result = {0}; + DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + for(DF_EntityNode *n = binaries.first; n != 0; n = n->next) + { + DF_TextLineDasm2SrcInfo info = df_text_line_dasm2src_info_from_binary_voff(n->entity, voff); + if(!df_entity_is_nil(info.file)) + { + DF_TextLineDasm2SrcInfoNode *dst_n = push_array(arena, DF_TextLineDasm2SrcInfoNode, 1); + dst_n->v = info; + SLLQueuePush(result.first, result.last, dst_n); + result.count += 1; + } + } + scratch_end(scratch); + return result; +} + +//- rjf: symbol -> voff lookups + +internal U64 +df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + U64 result = 0; + { + String8 binary_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + RADDBG_NameMapKind name_map_kinds[] = + { + RADDBG_NameMapKind_GlobalVariables, + RADDBG_NameMapKind_Procedures, + }; + if(dbgi != &dbgi_parse_nil) + { + for(U64 name_map_kind_idx = 0; + name_map_kind_idx < ArrayCount(name_map_kinds); + name_map_kind_idx += 1) + { + RADDBG_NameMapKind name_map_kind = name_map_kinds[name_map_kind_idx]; + RADDBG_NameMap *name_map = raddbg_name_map_from_kind(rdbg, name_map_kind); + RADDBG_ParsedNameMap parsed_name_map = {0}; + raddbg_name_map_parse(rdbg, name_map, &parsed_name_map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &parsed_name_map, symbol_name.str, symbol_name.size); + + // rjf: node -> num + U64 entity_num = 0; + if(node != 0) + { + switch(node->match_count) + { + case 1: + { + entity_num = node->match_idx_or_idx_run_first + 1; + }break; + default: + { + U32 num = 0; + U32 *run = raddbg_matches_from_map_node(rdbg, node, &num); + if(num != 0) + { + entity_num = run[0]+1; + } + }break; + } + } + + // rjf: num -> voff + U64 voff = 0; + if(entity_num != 0) switch(name_map_kind) + { + default:{}break; + case RADDBG_NameMapKind_GlobalVariables: if(entity_num <= rdbg->global_variable_count) + { + RADDBG_GlobalVariable *global_var = &rdbg->global_variables[entity_num-1]; + voff = global_var->voff; + }break; + case RADDBG_NameMapKind_Procedures: if(entity_num <= rdbg->procedure_count) + { + RADDBG_Procedure *procedure = &rdbg->procedures[entity_num-1]; + RADDBG_Scope *scope = &rdbg->scopes[procedure->root_scope_idx]; + voff = rdbg->scope_voffs[scope->voff_range_first]; + }break; + } + + // rjf: nonzero voff -> break + if(voff != 0) + { + result = voff; + break; + } + } + } + } + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); + return result; +} + +internal U64 +df_type_num_from_binary_name(DF_Entity *binary, String8 name) +{ + ProfBeginFunction(); + DBGI_Scope *scope = dbgi_scope_open(); + Temp scratch = scratch_begin(0, 0); + U64 result = 0; + { + String8 binary_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + RADDBG_NameMap *name_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Types); + RADDBG_ParsedNameMap parsed_name_map = {0}; + raddbg_name_map_parse(rdbg, name_map, &parsed_name_map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &parsed_name_map, name.str, name.size); + U64 entity_num = 0; + if(node != 0) + { + switch(node->match_count) + { + case 1: + { + entity_num = node->match_idx_or_idx_run_first + 1; + }break; + default: + { + U32 num = 0; + U32 *run = raddbg_matches_from_map_node(rdbg, node, &num); + if(num != 0) + { + entity_num = run[0]+1; + } + }break; + } + } + result = entity_num; + } + scratch_end(scratch); + dbgi_scope_close(scope); + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Process/Thread Info Lookups + +//- rjf: thread info extraction helpers + +internal DF_Entity * +df_module_from_process_vaddr(DF_Entity *process, U64 vaddr) +{ + DF_Entity *module = &df_g_nil_entity; + for(DF_Entity *child = process->first; !df_entity_is_nil(child); child = child->next) + { + if(child->kind == DF_EntityKind_Module && contains_1u64(child->vaddr_rng, vaddr)) + { + module = child; + break; + } + } + return module; +} + +internal DF_Entity * +df_module_from_thread(DF_Entity *thread) +{ + DF_Entity *process = thread->parent; + U64 rip = df_query_cached_rip_from_thread(thread); + return df_module_from_process_vaddr(process, rip); +} + +internal U64 +df_tls_base_vaddr_from_thread(DF_Entity *thread) +{ + U64 base_vaddr = 0; + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + + //- rjf: unpack thread info + DF_Entity *module = df_module_from_thread(thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *binary = df_binary_file_from_module(module); + DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); + String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); + PE_BinInfo *bin = &dbgi->pe; + B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF + U64 addr_size = bit_size_from_arch(bin->arch)/8; + + //- rjf: grab tls range + Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); + + //- rjf: read module's TLS index + // TODO(allen): migrate all of this logic into DEMON + U64 tls_index = 0; + { + U64 bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, &tls_index); + if(bytes_read < sizeof(U64)) + { + tls_index = 0; + } + } + + //- rjf: PE path + if(bin_is_pe) + { + U64 thread_info_addr = ctrl_tls_root_vaddr_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 tls_addr_off = tls_index*addr_size; + U64 tls_addr_array = 0; + String8 tls_addr_array_data = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size)); + if(tls_addr_array_data.size >= 8) + { + MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64)); + } + String8 result_data = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size)); + if(result_data.size >= 8) + { + MemoryCopy(&base_vaddr, result_data.str, sizeof(U64)); + } + } + + //- rjf: non-PE path (not implemented) + if(!bin_is_pe) + { + // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: +#if 0 + // TODO(nick): This code works only if the linked c runtime library is glibc. + // Implement CRT detection here. + + U64 dtv_addr = UINT64_MAX; + demon_read_memory(process->demon_handle, &dtv_addr, thread_info_addr, addr_size); + + /* + union delta_thread_vector + { + size_t counter; + struct + { + void *value; + void *to_free; + } pointer; + }; + */ + + U64 dtv_size = 16; + U64 dtv_count = 0; + demon_read_memory(process->demon_handle, &dtv_count, dtv_addr - dtv_size, addr_size); + + if (tls_index > 0 && tls_index < dtv_count) + { + demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); + } +#endif + } + + dbgi_scope_close(scope); + scratch_end(scratch); + return base_vaddr; +} + +internal Architecture +df_architecture_from_entity(DF_Entity *entity) +{ + return entity->arch; +} + +internal DF_Unwind +df_push_unwind_from_thread(Arena *arena, DF_Entity *thread) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + Architecture arch = df_architecture_from_entity(thread); + U64 arch_reg_block_size = regs_block_size_from_architecture(arch); + DF_Unwind unwind = {0}; + unwind.error = 1; + switch(arch) + { + default:{}break; + case Architecture_x64: + { + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + // rjf: grab initial register block + void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); + B32 regs_block_good = 0; + { + void *regs_raw = ctrl_reg_block_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + if(regs_raw != 0) + { + MemoryCopy(regs_block, regs_raw, arch_reg_block_size); + regs_block_good = 1; + } + } + + // rjf: grab initial memory view + B32 stack_memview_good = 0; + UNW_MemView stack_memview = {0}; + if(regs_block_good) + { + U64 stack_base_unrounded = thread->stack_base; + U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); + U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); + U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); + U64 stack_size = stack_base - stack_top; + if(stack_base >= stack_top) + { + String8 stack_memory = {0}; + stack_memory.str = push_array_no_zero(scratch.arena, U8, stack_size); + stack_memory.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(stack_top, stack_top+stack_size), stack_memory.str); + if(stack_memory.size != 0) + { + stack_memview_good = 1; + stack_memview.data = stack_memory.str; + stack_memview.addr_first = stack_top; + stack_memview.addr_opl = stack_base; + } + } + } + + // rjf: loop & unwind + UNW_MemView memview = stack_memview; + if(stack_memview_good) for(;;) + { + unwind.error = 0; + + // rjf: regs -> rip*module*binary + U64 rip = regs_rip_from_arch_block(arch, regs_block); + DF_Entity *module = df_module_from_process_vaddr(process, rip); + DF_Entity *binary = df_binary_file_from_module(module); + + // rjf: cancel on 0 rip + if(rip == 0) + { + break; + } + + // rjf: binary -> all the binary info + String8 binary_full_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_full_path, 0); + String8 binary_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); + + // rjf: cancel on bad data + if(binary_data.size == 0) + { + unwind.error = 1; + break; + } + + // rjf: valid step -> push frame + DF_UnwindFrame *frame = push_array(arena, DF_UnwindFrame, 1); + frame->rip = rip; + frame->regs = push_array_no_zero(arena, U8, arch_reg_block_size); + MemoryCopy(frame->regs, regs_block, arch_reg_block_size); + SLLQueuePush(unwind.first, unwind.last, frame); + unwind.count += 1; + + // rjf: unwind one step + UNW_Result unwind_step = unw_pe_x64(binary_data, &dbgi->pe, df_base_vaddr_from_module(module), &memview, (UNW_X64_Regs *)regs_block); + + // rjf: cancel on bad step + if(unwind_step.dead != 0) + { + break; + } + if(unwind_step.missed_read != 0) + { + unwind.error = 1; + break; + } + if(unwind_step.stack_pointer == 0) + { + break; + } + } + }break; + } + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); + return unwind; +} + +internal U64 +df_rip_from_thread(DF_Entity *thread) +{ + U64 result = ctrl_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + return result; +} + +internal U64 +df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) +{ + Temp scratch = scratch_begin(0, 0); + U64 result = df_rip_from_thread(thread); + if(unwind_count != 0) + { + DF_Unwind unwind = df_push_unwind_from_thread(scratch.arena, thread); + U64 unwind_idx = 0; + for(DF_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) + { + if(unwind_count == unwind_idx) + { + result = frame->rip; + break; + } + } + } + scratch_end(scratch); + return result; +} + +internal EVAL_String2NumMap * +df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 binary_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + EVAL_String2NumMap *result = eval_push_locals_map_from_raddbg_voff(arena, rdbg, voff); + scratch_end(scratch); + return result; +} + +internal EVAL_String2NumMap * +df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 binary_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + EVAL_String2NumMap *result = eval_push_member_map_from_raddbg_voff(arena, rdbg, voff); + scratch_end(scratch); + return result; +} + +internal B32 +df_set_thread_rip(DF_Entity *thread, U64 vaddr) +{ + B32 result = ctrl_thread_write_rip(thread->ctrl_machine_id, thread->ctrl_handle, vaddr); + + // rjf: invalidate unwind/locals cache + if(result) + { + df_state->unwind_cache_invalidated = 1; + df_state->locals_cache_invalidated = 1; + df_state->member_cache_invalidated = 1; + } + + // rjf: early mutation of unwind cache for immediate frontend effect + if(result) + { + DF_RunUnwindCache *unwind_cache = &df_state->unwind_cache; + DF_Handle thread_handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&thread_handle)); + U64 slot_idx = hash % unwind_cache->table_size; + DF_RunUnwindCacheSlot *slot = &unwind_cache->table[slot_idx]; + for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0) + { + n->unwind.first->rip = vaddr; + break; + } + } + } + + return result; +} + +internal DF_Entity * +df_module_from_thread_candidates(DF_Entity *thread, DF_EntityList *candidates) +{ + DF_Entity *src_module = df_module_from_thread(thread); + DF_Entity *module = &df_g_nil_entity; + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + for(DF_EntityNode *n = candidates->first; n != 0; n = n->next) + { + DF_Entity *candidate_module = n->entity; + DF_Entity *candidate_process = df_entity_ancestor_from_kind(candidate_module, DF_EntityKind_Process); + if(candidate_process == process) + { + module = candidate_module; + } + if(candidate_module == src_module) + { + break; + } + } + return module; +} + +//////////////////////////////// +//~ rjf: Entity -> Log Entities + +internal DF_Entity * +df_log_from_entity(DF_Entity *entity) +{ + Temp scratch = scratch_begin(0, 0); + String8 log_name = {0}; + switch(entity->kind) + { + default: + { + log_name = push_str8f(scratch.arena, "id_%I64u", entity->id); + }break; + case DF_EntityKind_Root: + { + U32 session_pid = os_get_pid(); + log_name = push_str8f(scratch.arena, "session_%i", session_pid); + }break; + case DF_EntityKind_Machine: + { + log_name = push_str8f(scratch.arena, "machine_%I64u", entity->id); + }break; + case DF_EntityKind_Process: + { + log_name = push_str8f(scratch.arena, "pid_%i", entity->ctrl_id); + }break; + case DF_EntityKind_Thread: + { + log_name = push_str8f(scratch.arena, "tid_%i", entity->ctrl_id); + }break; + } + String8 user_program_data_path = os_string_from_system_path(scratch.arena, OS_SystemPath_UserProgramData); + String8 user_data_folder = push_str8f(scratch.arena, "%S/%S", user_program_data_path, str8_lit("raddbg/logs")); + String8 log_path = push_str8f(scratch.arena, "%S/log%s%S.txt", user_data_folder, log_name.size != 0 ? "_" : "", log_name); + DF_Entity *log = df_entity_from_path(log_path, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + log->flags |= DF_EntityFlag_Output; + scratch_end(scratch); + return log; +} + +//////////////////////////////// +//~ rjf: Target Controls + +//- rjf: control message dispatching + +internal void +df_push_ctrl_msg(CTRL_Msg *msg) +{ + CTRL_Msg *dst = ctrl_msg_list_push(df_state->ctrl_msg_arena, &df_state->ctrl_msgs); + ctrl_msg_deep_copy(df_state->ctrl_msg_arena, dst, msg); + if(df_state->ctrl_soft_halt_issued == 0 && df_ctrl_targets_running()) + { + df_state->ctrl_soft_halt_issued = 1; + ctrl_halt(); + } +} + +//- rjf: control thread running + +internal void +df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_TrapList *run_traps) +{ + DBGI_Scope *scope = dbgi_scope_open(); + Temp scratch = scratch_begin(0, 0); + + // rjf: build run message + CTRL_Msg msg = {(run == DF_RunKind_Run || run == DF_RunKind_Step) ? CTRL_MsgKind_Run : CTRL_MsgKind_SingleStep}; + { + DF_EntityList user_bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + DF_Entity *process = df_entity_ancestor_from_kind(run_thread, DF_EntityKind_Process); + msg.machine_id = run_thread->ctrl_machine_id; + msg.entity = run_thread->ctrl_handle; + msg.parent = process->ctrl_handle; + MemoryCopyArray(msg.exception_code_filters, df_state->ctrl_exception_code_filters); + if(run_traps != 0) + { + MemoryCopyStruct(&msg.traps, run_traps); + } + for(DF_EntityNode *user_bp_n = user_bps.first; + user_bp_n != 0; + user_bp_n = user_bp_n->next) + { + // rjf: unpack user breakpoint entity + DF_Entity *user_bp = user_bp_n->entity; + if(user_bp->b32 == 0) + { + continue; + } + DF_Entity *file = df_entity_ancestor_from_kind(user_bp, DF_EntityKind_File); + DF_Entity *symb = df_entity_child_from_kind(user_bp, DF_EntityKind_EntryPointName); + DF_EntityList overrides = df_possible_overrides_from_entity(scratch.arena, file); + for(DF_EntityNode *override_n = overrides.first; override_n != 0; override_n = override_n->next) + { + DF_Entity *override = override_n->entity; + DF_Entity *condition_child = df_entity_child_from_kind(user_bp, DF_EntityKind_Condition); + String8 condition = condition_child->name; + + // rjf: generate user breakpoint info depending on breakpoint placement + CTRL_UserBreakpointKind ctrl_user_bp_kind = CTRL_UserBreakpointKind_FileNameAndLineColNumber; + String8 ctrl_user_bp_string = {0}; + TxtPt ctrl_user_bp_pt = {0}; + U64 ctrl_user_bp_u64 = 0; + { + if(user_bp->flags & DF_EntityFlag_HasTextPoint) + { + ctrl_user_bp_kind = CTRL_UserBreakpointKind_FileNameAndLineColNumber; + ctrl_user_bp_string = df_full_path_from_entity(scratch.arena, override); + ctrl_user_bp_pt = user_bp->text_point; + } + else if(user_bp->flags & DF_EntityFlag_HasVAddr) + { + ctrl_user_bp_kind = CTRL_UserBreakpointKind_VirtualAddress; + ctrl_user_bp_u64 = user_bp->vaddr; + } + else if(!df_entity_is_nil(symb)) + { + ctrl_user_bp_kind = CTRL_UserBreakpointKind_SymbolNameAndOffset; + ctrl_user_bp_string = symb->name; + ctrl_user_bp_u64 = user_bp->u64; + } + } + + // rjf: push user breakpoint to list + { + CTRL_UserBreakpoint ctrl_user_bp = {ctrl_user_bp_kind}; + ctrl_user_bp.string = ctrl_user_bp_string; + ctrl_user_bp.pt = ctrl_user_bp_pt; + ctrl_user_bp.u64 = ctrl_user_bp_u64; + ctrl_user_bp.condition = condition; + ctrl_user_breakpoint_list_push(scratch.arena, &msg.user_bps, &ctrl_user_bp); + } + } + } + if(df_state->ctrl_solo_stepping_mode && !df_entity_is_nil(run_thread)) + { + msg.freeze_state_is_frozen = 0; + CTRL_MachineIDHandlePair pair = {run_thread->ctrl_machine_id, run_thread->ctrl_handle}; + ctrl_machine_id_handle_pair_list_push(scratch.arena, &msg.freeze_state_threads, &pair); + } + else + { + for(DF_HandleNode *n = df_state->frozen_threads.first; n != 0; n = n->next) + { + DF_Entity *thread = df_entity_from_handle(n->handle); + if(!df_entity_is_nil(thread)) + { + CTRL_MachineIDHandlePair pair = {thread->ctrl_machine_id, thread->ctrl_handle}; + ctrl_machine_id_handle_pair_list_push(scratch.arena, &msg.freeze_state_threads, &pair); + } + } + msg.freeze_state_is_frozen = 1; + } + } + + // rjf: push msg + df_push_ctrl_msg(&msg); + + // rjf: copy run traps to scratch (needed, if the caller can pass `df_state->ctrl_last_run_traps`) + CTRL_TrapList run_traps_copy = {0}; + if(run_traps != 0) + { + run_traps_copy = ctrl_trap_list_copy(scratch.arena, run_traps); + } + + // rjf: store last run info + arena_clear(df_state->ctrl_last_run_arena); + df_state->ctrl_last_run_kind = run; + df_state->ctrl_last_run_frame_idx = df_frame_index(); + df_state->ctrl_last_run_thread = df_handle_from_entity(run_thread); + df_state->ctrl_last_run_traps = ctrl_trap_list_copy(df_state->ctrl_last_run_arena, &run_traps_copy); + df_state->ctrl_is_running = 1; + + scratch_end(scratch); + dbgi_scope_close(scope); +} + +//- rjf: stopped info from the control thread + +internal CTRL_Event +df_ctrl_last_stop_event(void) +{ + return df_state->ctrl_last_stop_event; +} + +//////////////////////////////// +//~ rjf: Evaluation + +internal B32 +df_eval_memory_read(void *u, void *out, U64 addr, U64 size) +{ + DF_Entity *process = (DF_Entity *)u; + Assert(process->kind == DF_EntityKind_Process); + Temp scratch = scratch_begin(0, 0); + B32 result = 0; + String8 data = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(addr, addr+size)); + if(data.size == size) + { + result = 1; + MemoryCopy(out, data.str, data.size); + } + scratch_end(scratch); + return result; +} + +internal EVAL_ParseCtx +df_eval_parse_ctx_from_module_voff(DBGI_Scope *scope, DF_Entity *module, U64 voff) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: extract info + DF_Entity *binary = df_binary_file_from_module(module); + String8 binary_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + Architecture arch = df_architecture_from_entity(module); + EVAL_String2NumMap *reg_map = ctrl_string2reg_from_arch (arch); + EVAL_String2NumMap *reg_alias_map = ctrl_string2alias_from_arch(arch); + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, voff); + EVAL_String2NumMap *member_map = df_query_cached_member_map_from_binary_voff(binary, voff); + + //- rjf: build ctx + EVAL_ParseCtx ctx = zero_struct; + { + ctx.arch = arch; + ctx.ip_voff = voff; + ctx.rdbg = rdbg; + ctx.type_graph = tg_graph_begin(bit_size_from_arch(arch)/8, 256); + ctx.regs_map = reg_map; + ctx.reg_alias_map = reg_alias_map; + ctx.locals_map = locals_map; + ctx.member_map = member_map; + } + scratch_end(scratch); + return ctx; +} + +internal EVAL_ParseCtx +df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) +{ + Temp scratch = scratch_begin(0, 0); + EVAL_ParseCtx ctx = zero_struct; + DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + DF_TextLineSrc2DasmInfoList src2dasm_list = {0}; + + //- rjf: search for line info in all binaries for this file:pt + DF_EntityList overrides = df_possible_overrides_from_entity(scratch.arena, file); + for(DF_EntityNode *override_n = overrides.first; + override_n != 0; + override_n = override_n->next) + { + DF_Entity *override = override_n->entity; + String8 file_path = df_full_path_from_entity(scratch.arena, override); + String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); + for(DF_EntityNode *binary_n = binaries.first; + binary_n != 0; + binary_n = binary_n->next) + { + // rjf: binary -> rdbg + DF_Entity *binary = binary_n->entity; + String8 binary_path = df_full_path_from_entity(scratch.arena, binary); + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); + RADDBG_Parsed *rdbg = &dbgi->rdbg; + + // rjf: file_path_normalized * rdbg -> src_id + B32 good_src_id = 0; + U32 src_id = 0; + { + RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_NormalSourcePaths); + if(mapptr != 0) + { + RADDBG_ParsedNameMap map = {0}; + raddbg_name_map_parse(rdbg, mapptr, &map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, file_path_normalized.str, file_path_normalized.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + if(id_count > 0) + { + good_src_id = 1; + src_id = ids[0]; + } + } + } + } + + // rjf: good src-id -> look up line info for visible range + if(good_src_id) + { + RADDBG_SourceFile *src = rdbg->source_files+src_id; + RADDBG_ParsedLineMap line_map = {0}; + raddbg_line_map_from_source_file(rdbg, src, &line_map); + U32 voff_count = 0; + U64 *voffs = raddbg_line_voffs_from_num(&line_map, (U32)pt.line, &voff_count); + for(U64 idx = 0; idx < voff_count; idx += 1) + { + U64 base_voff = voffs[idx]; + U64 unit_idx = raddbg_vmap_idx_from_voff(rdbg->unit_vmap, rdbg->unit_vmap_count, base_voff); + RADDBG_Unit *unit = &rdbg->units[unit_idx]; + RADDBG_ParsedLineInfo unit_line_info = {0}; + raddbg_line_info_from_unit(rdbg, unit, &unit_line_info); + U64 line_info_idx = raddbg_line_info_idx_from_voff(&unit_line_info, base_voff); + Rng1U64 range = r1u64(base_voff, unit_line_info.voffs[line_info_idx+1]); + S64 actual_line = (S64)unit_line_info.lines[line_info_idx].line_num; + DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(scratch.arena, DF_TextLineSrc2DasmInfoNode, 1); + src2dasm_n->v.voff_range = range; + src2dasm_n->v.remap_line = (S64)actual_line; + src2dasm_n->v.binary = binary; + SLLQueuePush(src2dasm_list.first, src2dasm_list.last, src2dasm_n); + src2dasm_list.count += 1; + } + } + } + } + + //- rjf: try to form ctx from line info + B32 good_ctx = 0; + if(src2dasm_list.count != 0) + { + for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list.first; n != 0; n = n->next) + { + DF_TextLineSrc2DasmInfo *src2dasm = &n->v; + DF_EntityList modules = df_modules_from_binary_file(scratch.arena, src2dasm->binary); + if(modules.count != 0) + { + DF_Entity *module = modules.first->entity; + ctx = df_eval_parse_ctx_from_module_voff(scope, module, src2dasm->voff_range.min); + good_ctx = 1; + break; + } + } + } + + //- rjf: bad ctx -> reset with graceful defaults + if(good_ctx == 0) + { + ctx.rdbg = &dbgi_parse_nil.rdbg; + ctx.type_graph = tg_graph_begin(8, 256); + ctx.regs_map = &eval_string2num_map_nil; + ctx.regs_map = &eval_string2num_map_nil; + ctx.reg_alias_map = &eval_string2num_map_nil; + ctx.locals_map = &eval_string2num_map_nil; + ctx.member_map = &eval_string2num_map_nil; + } + + scratch_end(scratch); + return ctx; +} + +internal DF_Eval +df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, String8 string) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: unpack arguments + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = thread->parent; + U64 unwind_count = ctrl_ctx->unwind_count; + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + Architecture arch = df_architecture_from_entity(thread); + U64 reg_size = regs_block_size_from_architecture(arch); + U64 thread_unwind_ip_vaddr = 0; + void *thread_unwind_regs_block = push_array(scratch.arena, U8, reg_size); + { + U64 idx = 0; + for(DF_UnwindFrame *f = unwind.first; f != 0; f = f->next, idx += 1) + { + if(idx == unwind_count) + { + thread_unwind_ip_vaddr = f->rip; + thread_unwind_regs_block = f->regs; + break; + } + } + } + + //- rjf: lex & parse + EVAL_TokenArray tokens = eval_token_array_from_text(arena, string); + EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(arena, parse_ctx, string, &tokens); + EVAL_ErrorList errors = parse.errors; + B32 parse_has_expr = (parse.expr != &eval_expr_nil); + B32 parse_is_type = (parse_has_expr && parse.expr->kind == EVAL_ExprKind_TypeIdent); + + //- rjf: produce IR tree & type + EVAL_IRTreeAndType ir_tree_and_type = {&eval_irtree_nil}; + if(parse_has_expr && errors.count == 0) + { + ir_tree_and_type = eval_irtree_and_type_from_expr(arena, parse_ctx->type_graph, parse_ctx->rdbg, parse.expr, &errors); + } + + //- rjf: get list of ops + EVAL_OpList op_list = {0}; + if(parse_has_expr && ir_tree_and_type.tree != &eval_irtree_nil) + { + eval_oplist_from_irtree(arena, ir_tree_and_type.tree, &op_list); + } + + //- rjf: get bytecode string + String8 bytecode = {0}; + if(parse_has_expr && parse_is_type == 0 && op_list.encoded_size != 0) + { + bytecode = eval_bytecode_from_oplist(arena, &op_list); + } + + //- rjf: grab thread/module + DF_Entity *module = df_module_from_process_vaddr(process, thread_unwind_ip_vaddr); + + //- rjf: evaluate + EVAL_Result eval = {0}; + if(bytecode.size != 0) + { + U64 module_base = df_base_vaddr_from_module(module); + U64 tls_base = df_tls_base_vaddr_from_thread(thread); + EVAL_Machine machine = {0}; + machine.u = (void *)thread->parent; + machine.arch = arch; + machine.memory_read = df_eval_memory_read; + machine.reg_data = thread_unwind_regs_block; + machine.reg_size = reg_size; + machine.module_base = &module_base; + machine.tls_base = &tls_base; + eval = eval_interpret(&machine, bytecode); + } + + //- rjf: fill result + DF_Eval result = zero_struct; + { + result.type_key = ir_tree_and_type.type_key; + result.mode = ir_tree_and_type.mode; + switch(result.mode) + { + default: + case EVAL_EvalMode_Value: + { + MemoryCopyArray(result.imm_u128, eval.value.u128); + }break; + case EVAL_EvalMode_Addr: + { + result.offset = eval.value.u64; + }break; + case EVAL_EvalMode_Reg: + { + U64 reg_off = (eval.value.u64 & 0x0000ffff) >> 0; + U64 reg_size = (eval.value.u64 & 0xffff0000) >> 16; + result.offset = reg_off; + (void)reg_size; + }break; + } + result.errors = errors; + } + + scratch_end(scratch); + ProfEnd(); + return result; +} + +internal DF_Eval +df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval) +{ + ProfBeginFunction(); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = thread->parent; + switch(eval.mode) + { + //- rjf: no work to be done. already in value mode + default: + case EVAL_EvalMode_Value:{}break; + + //- rjf: address => resolve into value, if leaf + case EVAL_EvalMode_Addr: + { + TG_Key type_key = eval.type_key; + TG_Kind type_kind = tg_kind_from_key(type_key); + U64 type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + if(!tg_key_match(type_key, tg_key_zero()) && type_byte_size <= 8) + { + Temp scratch = scratch_begin(0, 0); + Rng1U64 vaddr_range = r1u64(eval.offset, eval.offset + type_byte_size); + if(dim_1u64(vaddr_range) == type_byte_size) + { + String8 data = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, vaddr_range); + MemoryZeroArray(eval.imm_u128); + MemoryCopy(eval.imm_u128, data.str, Min(data.size, sizeof(U64)*2)); + eval.mode = EVAL_EvalMode_Value; + + // rjf: manually sign-extend + switch(type_kind) + { + default: break; + case TG_Kind_S8: {eval.imm_s64 = (S64)*((S8 *)&eval.imm_u64);}break; + case TG_Kind_S16: {eval.imm_s64 = (S64)*((S16 *)&eval.imm_u64);}break; + case TG_Kind_S32: {eval.imm_s64 = (S64)*((S32 *)&eval.imm_u64);}break; + } + } + scratch_end(scratch); + } + }break; + + //- rjf: register => resolve into value + case EVAL_EvalMode_Reg: + { + TG_Key type_key = eval.type_key; + U64 type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + U64 reg_off = eval.offset; + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + if(unwind.first != 0) + { + U64 unwind_idx = 0; + for(DF_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) + { + if(unwind_idx == ctrl_ctx->unwind_count && frame->regs != 0) + { + MemoryCopy(&eval.imm_u128[0], ((U8 *)frame->regs + reg_off), Min(type_byte_size, sizeof(U64)*2)); + break; + } + } + } + eval.mode = EVAL_EvalMode_Value; + }break; + } + + ProfEnd(); + return eval; +} + +internal DF_Eval +df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, DF_CfgTable *cfg) +{ + ProfBeginFunction(); + for(DF_CfgVal *val = cfg->first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) + { + DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string); + if(spec->info.flags & DF_CoreViewRuleSpecInfoFlag_EvalResolution) + { + eval = spec->info.eval_resolution(arena, scope, ctrl_ctx, parse_ctx, eval, val); + goto end_resolve; + } + } + end_resolve:; + ProfEnd(); + return eval; +} + +//////////////////////////////// +//~ rjf: Evaluation Views + +#if !defined(BLAKE2_H) +#define HAVE_SSE2 +#include "third_party/blake2/blake2.h" +#include "third_party/blake2/blake2b.c" +#endif + +internal DF_EvalViewKey +df_eval_view_key_make(U64 v0, U64 v1) +{ + DF_EvalViewKey v = {v0, v1}; + return v; +} + +internal DF_EvalViewKey +df_eval_view_key_from_string(String8 string) +{ + DF_EvalViewKey key = {0}; + blake2b((U8 *)&key.u64[0], sizeof(key), string.str, string.size, 0, 0); + return key; +} + +internal DF_EvalViewKey +df_eval_view_key_from_stringf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + DF_EvalViewKey key = df_eval_view_key_from_string(string); + scratch_end(scratch); + return key; +} + +internal B32 +df_eval_view_key_match(DF_EvalViewKey a, DF_EvalViewKey b) +{ + return MemoryMatchStruct(&a, &b); +} + +internal DF_EvalView * +df_eval_view_from_key(DF_EvalViewKey key) +{ + DF_EvalView *eval_view = &df_g_nil_eval_view; + { + U64 slot_idx = key.u64[1]%df_state->eval_view_cache.slots_count; + DF_EvalViewSlot *slot = &df_state->eval_view_cache.slots[slot_idx]; + for(DF_EvalView *v = slot->first; v != &df_g_nil_eval_view && v != 0; v = v->hash_next) + { + if(df_eval_view_key_match(key, v->key)) + { + eval_view = v; + break; + } + } + if(eval_view == &df_g_nil_eval_view) + { + eval_view = push_array(df_state->arena, DF_EvalView, 1); + DLLPushBack_NPZ(&df_g_nil_eval_view, slot->first, slot->last, eval_view, hash_next, hash_prev); + eval_view->key = key; + eval_view->arena = arena_alloc(); + df_expand_tree_table_init(eval_view->arena, &eval_view->expand_tree_table, 256); + eval_view->history_cache_table_size = 64; + eval_view->history_cache_table = push_array(eval_view->arena, DF_EvalHistoryCacheSlot, eval_view->history_cache_table_size); + eval_view->view_rule_table.slot_count = 64; + eval_view->view_rule_table.slots = push_array(eval_view->arena, DF_EvalViewRuleCacheSlot, eval_view->view_rule_table.slot_count); + } + } + return eval_view; +} + +//- rjf: key -> eval history + +internal DF_EvalHistoryCacheNode * +df_eval_history_cache_node_from_key(DF_EvalView *eval_view, DF_ExpandKey key) +{ + //- rjf: key -> hash * slot idx * slot + String8 key_string = str8_struct(&key); + U64 hash = df_hash_from_string(key_string); + U64 slot_idx = hash%eval_view->history_cache_table_size; + DF_EvalHistoryCacheSlot *slot = &eval_view->history_cache_table[slot_idx]; + + //- rjf: slot idx -> existing node + DF_EvalHistoryCacheNode *existing_node = 0; + for(DF_EvalHistoryCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_expand_key_match(n->key, key)) + { + existing_node = n; + break; + } + } + + return existing_node; +} + +internal B32 +df_eval_view_record_history_val(DF_EvalView *eval_view, DF_ExpandKey key, DF_EvalHistoryVal val) +{ + B32 change = 0; + + //- rjf: key -> hash * slot idx * slot + String8 key_string = str8_struct(&key); + U64 hash = df_hash_from_string(key_string); + U64 slot_idx = hash%eval_view->history_cache_table_size; + DF_EvalHistoryCacheSlot *slot = &eval_view->history_cache_table[slot_idx]; + + //- rjf: slot idx -> existing node + DF_EvalHistoryCacheNode *existing_node = 0; + for(DF_EvalHistoryCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_expand_key_match(n->key, key)) + { + existing_node = n; + break; + } + } + + //- rjf: grab existing node - if there is none, we need to allocate one + DF_EvalHistoryCacheNode *node = existing_node; + if(node == 0) + { + // TODO(rjf): check lru cache, allocate from there, prevent too much growth + node = push_array(eval_view->arena, DF_EvalHistoryCacheNode, 1); + DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev); + node->key = key; + node->first_run_idx = node->last_run_idx = df_ctrl_run_gen(); + } + + //- rjf: record value + if(node != 0) + { + DF_EvalHistoryVal *newest_val = &node->values[node->newest_val_idx]; + if(newest_val->mode != val.mode || + newest_val->imm_u128[0] != val.imm_u128[0] || + newest_val->imm_u128[1] != val.imm_u128[1] || + newest_val->offset != val.offset) + { + change = 1; + node->newest_val_idx = (node->newest_val_idx + 1) % ArrayCount(node->values); + node->values[node->newest_val_idx] = val; + node->last_run_idx = df_ctrl_run_gen(); + } + } + + return change; +} + +//- rjf: key -> view rules + +internal void +df_eval_view_set_key_rule(DF_EvalView *eval_view, DF_ExpandKey key, String8 view_rule_string) +{ + //- rjf: key -> hash * slot idx * slot + String8 key_string = str8_struct(&key); + U64 hash = df_hash_from_string(key_string); + U64 slot_idx = hash%eval_view->view_rule_table.slot_count; + DF_EvalViewRuleCacheSlot *slot = &eval_view->view_rule_table.slots[slot_idx]; + + //- rjf: slot -> existing node + DF_EvalViewRuleCacheNode *existing_node = 0; + for(DF_EvalViewRuleCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_expand_key_match(n->key, key)) + { + existing_node = n; + break; + } + } + + //- rjf: existing node * new node -> node + DF_EvalViewRuleCacheNode *node = existing_node; + if(node == 0) + { + node = push_array(eval_view->arena, DF_EvalViewRuleCacheNode, 1); + DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev); + node->key = key; + node->buffer_cap = 512; + node->buffer = push_array(eval_view->arena, U8, node->buffer_cap); + } + + //- rjf: mutate node + if(node != 0) + { + node->buffer_string_size = ClampTop(view_rule_string.size, node->buffer_cap); + MemoryCopy(node->buffer, view_rule_string.str, node->buffer_string_size); + } +} + +internal String8 +df_eval_view_rule_from_key(DF_EvalView *eval_view, DF_ExpandKey key) +{ + String8 result = {0}; + + //- rjf: key -> hash * slot idx * slot + String8 key_string = str8_struct(&key); + U64 hash = df_hash_from_string(key_string); + U64 slot_idx = hash%eval_view->view_rule_table.slot_count; + DF_EvalViewRuleCacheSlot *slot = &eval_view->view_rule_table.slots[slot_idx]; + + //- rjf: slot -> existing node + DF_EvalViewRuleCacheNode *existing_node = 0; + for(DF_EvalViewRuleCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_expand_key_match(n->key, key)) + { + existing_node = n; + break; + } + } + + //- rjf: node -> result + if(existing_node != 0) + { + result = str8(existing_node->buffer, existing_node->buffer_string_size); + } + + return result; +} + +//////////////////////////////// +//~ rjf: Evaluation View Visualization & Interaction + +//- rjf: evaluation value string builder helpers + +internal String8 +df_string_from_ascii_value(Arena *arena, U8 val) +{ + String8 result = {0}; + switch(val) + { + case 0x00:{result = str8_lit("\\0");}break; + case 0x07:{result = str8_lit("\\a");}break; + case 0x08:{result = str8_lit("\\b");}break; + case 0x0c:{result = str8_lit("\\f");}break; + case 0x0a:{result = str8_lit("\\n");}break; + case 0x0d:{result = str8_lit("\\r");}break; + case 0x09:{result = str8_lit("\\t");}break; + case 0x0b:{result = str8_lit("\\v");}break; + case 0x3f:{result = str8_lit("\\?");}break; + case '"': {result = str8_lit("\\\"");}break; + case '\'':{result = str8_lit("\\'");}break; + case '\\':{result = str8_lit("\\\\");}break; + default: + { + result = push_str8f(arena, "%c", val); + }break; + } + return result; +} + +internal String8 +df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_EvalVizStringFlags flags, U32 radix, DF_Eval eval) +{ + ProfBeginFunction(); + String8 result = {0}; + TG_Key type_key = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, eval.type_key); + TG_Kind type_kind = tg_kind_from_key(type_key); + U64 type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + U8 digit_group_separator = 0; + if(!(flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules)) + { + digit_group_separator = 0; + } + switch(type_kind) + { + default:{}break; + + case TG_Kind_Char8: + case TG_Kind_Char16: + case TG_Kind_Char32: + case TG_Kind_UChar8: + case TG_Kind_UChar16: + case TG_Kind_UChar32: + { + String8 char_str = df_string_from_ascii_value(arena, eval.imm_s64); + if(flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules) + { + String8 imm_string = str8_from_s64(arena, eval.imm_s64, radix, 0, digit_group_separator); + result = push_str8f(arena, "'%S' (%S)", char_str, imm_string); + } + else + { + result = push_str8f(arena, "'%S'", char_str); + } + }break; + + case TG_Kind_S8: + case TG_Kind_S16: + case TG_Kind_S32: + case TG_Kind_S64: + { + U64 min_digits = (radix == 16) ? type_byte_size*2 : 0; + result = str8_from_s64(arena, eval.imm_s64, radix, 0, digit_group_separator); + }break; + + case TG_Kind_U8: + case TG_Kind_U16: + case TG_Kind_U32: + case TG_Kind_U64: + { + U64 min_digits = (radix == 16) ? type_byte_size*2 : 0; + result = str8_from_u64(arena, eval.imm_u64, radix, min_digits, digit_group_separator); + }break; + + case TG_Kind_U128: + { + Temp scratch = scratch_begin(&arena, 1); + U64 min_digits = (radix == 16) ? type_byte_size*2 : 0; + String8 upper64 = str8_from_u64(scratch.arena, eval.imm_u128[0], radix, min_digits, digit_group_separator); + String8 lower64 = str8_from_u64(scratch.arena, eval.imm_u128[1], radix, min_digits, digit_group_separator); + result = push_str8f(arena, "%S:%S", upper64, lower64); + scratch_end(scratch); + }break; + + case TG_Kind_F32: {result = push_str8f(arena, "%f", eval.imm_f32);}break; + case TG_Kind_F64: {result = push_str8f(arena, "%f", eval.imm_f64);}break; + case TG_Kind_Bool:{result = push_str8f(arena, "%s", eval.imm_u64 ? "true" : "false");}break; + case TG_Kind_Ptr: {result = push_str8f(arena, "0x%I64x", eval.imm_u64);}break; + case TG_Kind_LRef:{result = push_str8f(arena, "0x%I64x", eval.imm_u64);}break; + case TG_Kind_RRef:{result = push_str8f(arena, "0x%I64x", eval.imm_u64);}break; + case TG_Kind_Function:{result = push_str8f(arena, "0x%I64x", eval.imm_u64);}break; + + case TG_Kind_Enum: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, type_key); + String8 constant_name = {0}; + for(U64 val_idx = 0; val_idx < type->count; val_idx += 1) + { + if(eval.imm_u64 == type->enum_vals[val_idx].val) + { + constant_name = type->enum_vals[val_idx].name; + break; + } + } + if(flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules) + { + result = push_str8f(arena, "0x%I64x%s%S%s", eval.imm_u64, + constant_name.size != 0 ? " (" : "", + constant_name, + constant_name.size != 0 ? ")" : ""); + } + else if(constant_name.size != 0) + { + result = push_str8f(arena, "%S", constant_name); + } + else + { + result = push_str8f(arena, "0x%I64x", eval.imm_u64); + } + scratch_end(scratch); + }break; + } + + ProfEnd(); + return result; +} + +//- rjf: writing values back to child processes + +internal B32 +df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval dst_eval, DF_Eval src_eval) +{ + B32 result = 0; + Temp scratch = scratch_begin(0, 0); + + //- rjf: unpack arguments + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = thread->parent; + TG_Key dst_type_key = dst_eval.type_key; + TG_Key src_type_key = src_eval.type_key; + TG_Kind dst_type_kind = tg_kind_from_key(dst_type_key); + TG_Kind src_type_kind = tg_kind_from_key(src_type_key); + U64 dst_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, dst_type_key); + U64 src_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, src_type_key); + + //- rjf: get commit data based on destination type + String8 commit_data = {0}; + if(src_eval.errors.count == 0) + { + result = 1; + switch(dst_type_kind) + { + default: + { + // NOTE(rjf): not supported + result = 0; + }break; + + //- rjf: pointers + case TG_Kind_Ptr: + case TG_Kind_LRef: + if((TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) || src_type_kind == TG_Kind_Ptr) + { + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + commit_data = str8((U8 *)&value_eval.imm_u64, dst_type_byte_size); + commit_data = push_str8_copy(scratch.arena, commit_data); + }break; + + //- rjf: integers + case TG_Kind_S8: + case TG_Kind_S16: + case TG_Kind_S32: + case TG_Kind_S64: + case TG_Kind_U8: + case TG_Kind_U16: + case TG_Kind_U32: + case TG_Kind_U64: + if(TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) + { + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + commit_data = str8((U8 *)&value_eval.imm_u64, dst_type_byte_size); + commit_data = push_str8_copy(scratch.arena, commit_data); + }break; + + //- rjf: float32s + case TG_Kind_F32: + if((TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) || + src_type_kind == TG_Kind_F32 || + src_type_kind == TG_Kind_F64) + { + F32 value = 0; + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + switch(src_type_kind) + { + case TG_Kind_F32:{value = value_eval.imm_f32;}break; + case TG_Kind_F64:{value = (F32)value_eval.imm_f64;}break; + default:{value = (F32)value_eval.imm_s64;}break; + } + commit_data = str8((U8 *)&value, sizeof(F32)); + commit_data = push_str8_copy(scratch.arena, commit_data); + }break; + + //- rjf: float64s + case TG_Kind_F64: + if((TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) || + src_type_kind == TG_Kind_F32 || + src_type_kind == TG_Kind_F64) + { + F64 value = 0; + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + switch(src_type_kind) + { + case TG_Kind_F32:{value = (F64)value_eval.imm_f32;}break; + case TG_Kind_F64:{value = value_eval.imm_f64;}break; + default:{value = (F64)value_eval.imm_s64;}break; + } + commit_data = str8((U8 *)&value, sizeof(F64)); + commit_data = push_str8_copy(scratch.arena, commit_data); + }break; + + //- rjf: enums + case TG_Kind_Enum: + if(TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) + { + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + commit_data = str8((U8 *)&value_eval.imm_u64, dst_type_byte_size); + commit_data = push_str8_copy(scratch.arena, commit_data); + }break; + } + } + + //- rjf: commit + if(result && commit_data.size != 0) + { + switch(dst_eval.mode) + { + default:{}break; + case EVAL_EvalMode_Addr: + { + ctrl_process_write_data(process->ctrl_machine_id, process->ctrl_handle, dst_eval.offset, commit_data); + }break; + case EVAL_EvalMode_Reg: + { + // TODO(rjf) + result = 0; + }break; + } + } + + scratch_end(scratch); + return result; +} + +//- rjf: type helpers + +internal TG_MemberArray +df_filtered_data_members_from_members_cfg_table(Arena *arena, TG_MemberArray members, DF_CfgTable *cfg) +{ + DF_CfgVal *only = df_cfg_val_from_string(cfg, str8_lit("only")); + DF_CfgVal *omit = df_cfg_val_from_string(cfg, str8_lit("omit")); + TG_MemberArray filtered_members = members; + if(only != &df_g_nil_cfg_val || omit != &df_g_nil_cfg_val) + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct DF_TypeMemberLooseNode DF_TypeMemberLooseNode; + struct DF_TypeMemberLooseNode + { + DF_TypeMemberLooseNode *next; + TG_Member *member; + }; + DF_TypeMemberLooseNode *first_member = 0; + DF_TypeMemberLooseNode *last_member = 0; + U64 member_count = 0; + MemoryZeroStruct(&filtered_members); + for(U64 idx = 0; idx < members.count; idx += 1) + { + // rjf: check if included by 'only's + B32 is_included = 1; + for(DF_CfgNode *r = only->first; r != &df_g_nil_cfg_node; r = r->next) + { + is_included = 0; + for(DF_CfgNode *name_node = r->first; name_node != &df_g_nil_cfg_node; name_node = name_node->next) + { + String8 name = name_node->string; + if(str8_match(members.v[idx].name, name, 0)) + { + is_included = 1; + goto end_inclusion_check; + } + } + } + end_inclusion_check:; + + // rjf: remove if excluded by 'omit's + for(DF_CfgNode *r = omit->first; r != &df_g_nil_cfg_node; r = r->next) + { + for(DF_CfgNode *name_node = r->first; name_node != &df_g_nil_cfg_node; name_node = name_node->next) + { + String8 name = name_node->string; + if(str8_match(members.v[idx].name, name, 0)) + { + is_included = 0; + goto end_exclusion_check; + } + } + } + end_exclusion_check:; + + // rjf: push if included + if(is_included) + { + DF_TypeMemberLooseNode *n = push_array(scratch.arena, DF_TypeMemberLooseNode, 1); + n->member = &members.v[idx]; + SLLQueuePush(first_member, last_member, n); + member_count += 1; + } + } + + // rjf: bake + { + filtered_members.count = member_count; + filtered_members.v = push_array_no_zero(arena, TG_Member, filtered_members.count); + U64 idx = 0; + for(DF_TypeMemberLooseNode *n = first_member; n != 0; n = n->next, idx += 1) + { + MemoryCopyStruct(&filtered_members.v[idx], n->member); + filtered_members.v[idx].name = push_str8_copy(arena, filtered_members.v[idx].name); + } + } + scratch_end(scratch); + } + return filtered_members; +} + +internal DF_EvalLinkBaseChunkList +df_eval_link_base_chunk_list_from_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key link_member_type_key, U64 link_member_off, DF_CtrlCtx *ctrl_ctx, DF_Eval eval, U64 cap) +{ + DF_EvalLinkBaseChunkList list = {0}; + for(DF_Eval base_eval = eval, last_eval = zero_struct; list.count < cap;) + { + // rjf: check this ptr's validity + if(base_eval.offset == 0 || (base_eval.offset == last_eval.offset && base_eval.mode == last_eval.mode)) + { + break; + } + + // rjf: gather + { + DF_EvalLinkBaseChunkNode *chunk = list.last; + if(chunk == 0 || chunk->count == ArrayCount(chunk->b)) + { + chunk = push_array_no_zero(arena, DF_EvalLinkBaseChunkNode, 1); + chunk->next = 0; + chunk->count = 0; + SLLQueuePush(list.first, list.last, chunk); + } + chunk->b[chunk->count].mode = base_eval.mode; + chunk->b[chunk->count].offset = base_eval.offset; + chunk->count += 1; + list.count += 1; + } + + // rjf: grab link member + DF_Eval link_member_eval = + { + link_member_type_key, + base_eval.mode, + base_eval.offset + link_member_off, + }; + DF_Eval link_member_value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, link_member_eval); + + // rjf: advance to next link + last_eval = base_eval; + base_eval.mode = EVAL_EvalMode_Addr; + base_eval.offset = link_member_value_eval.imm_u64; + } + return list; +} + +internal DF_EvalLinkBase +df_eval_link_base_from_chunk_list_index(DF_EvalLinkBaseChunkList *list, U64 idx) +{ + DF_EvalLinkBase result = zero_struct; + U64 scan_idx = 0; + for(DF_EvalLinkBaseChunkNode *chunk = list->first; chunk != 0; chunk = chunk->next) + { + U64 chunk_idx_opl = scan_idx+chunk->count; + if(scan_idx <= idx && idx < chunk_idx_opl) + { + result = chunk->b[idx - scan_idx]; + } + scan_idx = chunk_idx_opl; + } + return result; +} + +internal DF_EvalLinkBaseArray +df_eval_link_base_array_from_chunk_list(Arena *arena, DF_EvalLinkBaseChunkList *chunks) +{ + DF_EvalLinkBaseArray array = {0}; + array.count = chunks->count; + array.v = push_array_no_zero(arena, DF_EvalLinkBase, array.count); + U64 idx = 0; + for(DF_EvalLinkBaseChunkNode *n = chunks->first; n != 0; n = n->next) + { + MemoryCopy(array.v + idx, n->b, n->count * sizeof(DF_EvalLinkBase)); + idx += n->count; + } + return array; +} + +//- rjf: watch tree visualization + +internal void +df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalView *eval_view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + + ////////////////////////////// + //- rjf: determine if this key is expanded + // + DF_ExpandNode *node = df_expand_node_from_key(&eval_view->expand_tree_table, key); + B32 parent_is_expanded = (node != 0 && node->expanded && !tg_key_match(tg_key_zero(), eval.type_key)); + + ////////////////////////////// + //- rjf: apply view rules & resolve eval + // + eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, eval, cfg_table); + + ////////////////////////////// + //- rjf: unpack eval + // + TG_Key eval_type_key = tg_unwrapped_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, eval.type_key); + TG_Kind eval_type_kind = tg_kind_from_key(eval_type_key); + + ////////////////////////////// + //- rjf: make and push block for root + // + DF_EvalVizBlock *block = push_array(arena, DF_EvalVizBlock, 1); + { + block->kind = DF_EvalVizBlockKind_Root; + block->eval_view = eval_view; + block->eval = eval; + block->cfg_table = *cfg_table; + block->string = push_str8_copy(arena, string); + block->parent_key = parent_key; + block->key = key; + block->visual_idx_range = r1u64(key.child_num-1, key.child_num+0); + block->semantic_idx_range = r1u64(key.child_num-1, key.child_num+0); + block->depth = depth; + SLLQueuePush(list_out->first, list_out->last, block); + list_out->count += 1; + list_out->total_visual_row_count += 1; + list_out->total_semantic_row_count += 1; + } + + ////////////////////////////// + //- rjf: (pointers) extract type & info to use for members and/or arrays + // + DF_Eval udt_eval = eval; + DF_Eval arr_eval = eval; + DF_Eval ptr_eval = zero_struct; + TG_Kind udt_type_kind = eval_type_kind; + TG_Kind arr_type_kind = eval_type_kind; + TG_Kind ptr_type_kind = TG_Kind_Null; + if(eval_type_kind == TG_Kind_Ptr || eval_type_kind == TG_Kind_LRef || eval_type_kind == TG_Kind_RRef) + { + TG_Key direct_type_key = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, eval_type_key); + TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); + DF_Eval ptr_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, block->eval); + + // rjf: ptrs to udts + if(parent_is_expanded && + (direct_type_kind == TG_Kind_Struct || + direct_type_kind == TG_Kind_Union || + direct_type_kind == TG_Kind_Class || + direct_type_kind == TG_Kind_IncompleteStruct || + direct_type_kind == TG_Kind_IncompleteUnion || + direct_type_kind == TG_Kind_IncompleteClass)) + { + udt_eval.type_key = direct_type_key; + udt_eval.mode = EVAL_EvalMode_Addr; + udt_eval.offset = ptr_val_eval.imm_u64; + udt_type_kind = tg_kind_from_key(direct_type_key); + } + + // rjf: ptrs to arrays + if(direct_type_kind == TG_Kind_Array) + { + arr_eval.type_key = direct_type_key; + arr_eval.mode = EVAL_EvalMode_Addr; + arr_eval.offset = ptr_val_eval.imm_u64; + arr_type_kind = tg_kind_from_key(direct_type_key); + } + + // rjf: ptrs to ptrs + if(direct_type_kind == TG_Kind_Ptr || direct_type_kind == TG_Kind_LRef || direct_type_kind == TG_Kind_RRef) + { + ptr_eval.type_key = direct_type_key; + ptr_eval.mode = EVAL_EvalMode_Addr; + ptr_eval.offset = ptr_val_eval.imm_u64; + ptr_type_kind = tg_kind_from_key(direct_type_key); + } + } + + ////////////////////////////// + //- rjf: determine rule for building expansion children + // + typedef enum DF_EvalVizExpandRule + { + DF_EvalVizExpandRule_Default, + DF_EvalVizExpandRule_List, + DF_EvalVizExpandRule_ViewRule, + } + DF_EvalVizExpandRule; + DF_EvalVizExpandRule expand_rule = DF_EvalVizExpandRule_Default; + DF_CoreViewRuleSpec *expand_view_rule_spec = &df_g_nil_core_view_rule_spec; + DF_CfgVal *expand_view_rule_cfg = &df_g_nil_cfg_val; + String8 list_next_link_member_name = {0}; + { + //- rjf: look for view rules which have their own custom viz block building rules + if(expand_rule == DF_EvalVizExpandRule_Default && parent_is_expanded) + { + for(DF_CfgVal *val = cfg_table->first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) + { + DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string); + if(spec->info.flags & DF_CoreViewRuleSpecInfoFlag_VizBlockProd) + { + expand_rule = DF_EvalVizExpandRule_ViewRule; + expand_view_rule_spec = spec; + expand_view_rule_cfg = val; + break; + } + } + } + + //- rjf: get linked list viz view rule info for structs + if(expand_rule == DF_EvalVizExpandRule_Default && + parent_is_expanded && + (udt_type_kind == TG_Kind_Struct || + udt_type_kind == TG_Kind_Union || + udt_type_kind == TG_Kind_Class)) + { + DF_CfgVal *list_cfg = df_cfg_val_from_string(cfg_table, str8_lit("list")); + if(list_cfg != &df_g_nil_cfg_val) + { + list_next_link_member_name = list_cfg->first->first->string; + expand_rule = DF_EvalVizExpandRule_List; + } + } + } + + ////////////////////////////// + //- rjf: (all) descend to make blocks according to lens + // + if(parent_is_expanded && expand_rule == DF_EvalVizExpandRule_ViewRule && + expand_view_rule_spec != &df_g_nil_core_view_rule_spec && + expand_view_rule_cfg != &df_g_nil_cfg_val) + ProfScope("build viz blocks for lens") + { + expand_view_rule_spec->info.viz_block_prod(arena, scope, ctrl_ctx, parse_ctx, eval_view, eval, cfg_table, parent_key, key, depth+1, expand_view_rule_cfg->last, list_out); + } + + ////////////////////////////// + //- rjf: (structs, unions, classes) descend to members & make block(s), normally + // + if(parent_is_expanded && expand_rule == DF_EvalVizExpandRule_Default && + (udt_type_kind == TG_Kind_Struct || + udt_type_kind == TG_Kind_Union || + udt_type_kind == TG_Kind_Class)) + ProfScope("build viz blocks for UDT members") + { + // rjf: get members + TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, udt_eval.type_key); + TG_MemberArray filtered_data_members = df_filtered_data_members_from_members_cfg_table(scratch.arena, data_members, cfg_table); + + // rjf: make block for all members (assume no members are expanded) + DF_EvalVizBlock *memblock = push_array(arena, DF_EvalVizBlock, 1); + { + memblock->kind = DF_EvalVizBlockKind_Members; + memblock->eval_view = eval_view; + memblock->eval = udt_eval; + memblock->cfg_table = *cfg_table; + memblock->parent_key = key; + memblock->key = df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), 0); + memblock->visual_idx_range = r1u64(0, filtered_data_members.count); + memblock->semantic_idx_range = r1u64(0, filtered_data_members.count); + memblock->depth = depth+1; + SLLQueuePush(list_out->first, list_out->last, memblock); + list_out->count += 1; + list_out->total_visual_row_count += filtered_data_members.count; + list_out->total_semantic_row_count += filtered_data_members.count; + } + + // rjf: split memblock by sub-expansions + for(DF_ExpandNode *child = node->first; child != 0; child = child->next) + { + U64 child_num = child->key.child_num; + U64 child_idx = child_num-1; + if(child_idx >= filtered_data_members.count) + { + continue; + } + + // rjf: truncate existing memblock + memblock->visual_idx_range.max = child_idx; + memblock->semantic_idx_range.max = child_idx; + + // rjf: build inheriting cfg table + DF_CfgTable child_cfg = *cfg_table; + { + String8 view_rule_string = df_eval_view_rule_from_key(eval_view, df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), child_num)); + child_cfg = df_cfg_table_from_inheritance(arena, cfg_table); + if(view_rule_string.size != 0) + { + df_cfg_table_push_unparsed_string(arena, &child_cfg, view_rule_string, DF_CfgSrc_User); + } + } + + // rjf: recurse for sub-block + { + TG_Member *member = &filtered_data_members.v[child_idx]; + DF_Eval child_eval = zero_struct; + { + child_eval.type_key = member->type_key; + child_eval.mode = udt_eval.mode; + child_eval.offset = udt_eval.offset + member->off; + } + list_out->total_visual_row_count -= 1; + list_out->total_semantic_row_count -= 1; + df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, key, child->key, member->name, child_eval, &child_cfg, depth+1, list_out); + } + + // rjf: make new memblock for remainder of children (if any) + if(child_idx+1 < filtered_data_members.count) + { + DF_EvalVizBlock *next_memblock = push_array(arena, DF_EvalVizBlock, 1); + next_memblock->kind = DF_EvalVizBlockKind_Members; + next_memblock->eval_view = eval_view; + next_memblock->eval = udt_eval; + next_memblock->cfg_table = *cfg_table; + next_memblock->parent_key = key; + next_memblock->key = df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), 0); + next_memblock->visual_idx_range = r1u64(child_idx+1, filtered_data_members.count); + next_memblock->semantic_idx_range= r1u64(child_idx+1, filtered_data_members.count); + next_memblock->depth = depth+1; + SLLQueuePush(list_out->first, list_out->last, next_memblock); + list_out->count += 1; + memblock = next_memblock; + } + } + } + + ////////////////////////////// + //- rjf: (structs, unions, classes) descend to members & make block(s), with linked list view + // + if(parent_is_expanded && expand_rule == DF_EvalVizExpandRule_List && + (udt_type_kind == TG_Kind_Struct || + udt_type_kind == TG_Kind_Union || + udt_type_kind == TG_Kind_Class)) + ProfScope("(structs, unions, classes) descend to members & make block(s), with linked list view") + { + // rjf: get members + TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, udt_eval.type_key); + TG_MemberArray filtered_data_members = df_filtered_data_members_from_members_cfg_table(scratch.arena, data_members, cfg_table); + + // rjf: find link member + TG_Member *link_member = 0; + TG_Kind link_member_type_kind = TG_Kind_Null; + TG_Key link_member_ptee_type_key = zero_struct; + for(U64 idx = 0; idx < data_members.count; idx += 1) + { + TG_Member *mem = &data_members.v[idx]; + if(str8_match(mem->name, list_next_link_member_name, 0)) + { + link_member = mem; + link_member_type_kind = tg_kind_from_key(link_member->type_key); + link_member_ptee_type_key = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, link_member->type_key); + break; + } + } + + // rjf: invalid link member -> early-out! + if(link_member == 0 || + link_member_type_kind != TG_Kind_Ptr || + !tg_key_match(link_member_ptee_type_key, udt_eval.type_key)) + { + goto end_linked_struct_expansion_build; + } + + // rjf: gather link bases + DF_EvalLinkBaseChunkList link_bases = df_eval_link_base_chunk_list_from_eval(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, link_member->type_key, link_member->off, ctrl_ctx, udt_eval, 512); + + // rjf: make block for all links (assume no members are expanded) + DF_EvalVizBlock *linkblock = push_array(arena, DF_EvalVizBlock, 1); + { + linkblock->kind = DF_EvalVizBlockKind_Links; + linkblock->eval_view = eval_view; + linkblock->eval = udt_eval; + linkblock->link_member_type_key = link_member->type_key; + linkblock->link_member_off = link_member->off; + linkblock->cfg_table = *cfg_table; + linkblock->parent_key = key; + linkblock->key = df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), 0); + linkblock->visual_idx_range = r1u64(0, link_bases.count); + linkblock->semantic_idx_range = r1u64(0, link_bases.count); + linkblock->depth = depth+1; + SLLQueuePush(list_out->first, list_out->last, linkblock); + list_out->count += 1; + list_out->total_visual_row_count += link_bases.count; + list_out->total_semantic_row_count += link_bases.count; + } + + // rjf: split linkblock by sub-expansions + for(DF_ExpandNode *child = node->first; child != 0; child = child->next) + { + U64 child_num = child->key.child_num; + U64 child_idx = child_num-1; + if(child_idx >= link_bases.count) + { + continue; + } + + // rjf: truncate existing elemblock + linkblock->visual_idx_range.max = child_idx; + linkblock->semantic_idx_range.max = child_idx; + + // rjf: build inheriting cfg table + DF_CfgTable child_cfg = *cfg_table; + { + String8 view_rule_string = df_eval_view_rule_from_key(eval_view, df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), child_num)); + child_cfg = df_cfg_table_from_inheritance(arena, cfg_table); + if(view_rule_string.size != 0) + { + df_cfg_table_push_unparsed_string(arena, &child_cfg, view_rule_string, DF_CfgSrc_User); + } + } + + // rjf: find mode/offset of this link + DF_EvalLinkBase link_base = df_eval_link_base_from_chunk_list_index(&link_bases, child_idx); + + // rjf: recurse for sub-block + DF_Eval child_eval = zero_struct; + { + child_eval.type_key = udt_eval.type_key; + child_eval.mode = link_base.mode; + child_eval.offset = link_base.offset; + } + list_out->total_visual_row_count -= 1; + list_out->total_semantic_row_count -= 1; + df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, key, child->key, push_str8f(arena, "[%I64u]", child_idx), child_eval, &child_cfg, depth+1, list_out); + + // rjf: make new elemblock for remainder of children (if any) + if(child_idx+1 < link_bases.count) + { + DF_EvalVizBlock *next_linkblock = push_array(arena, DF_EvalVizBlock, 1); + next_linkblock->kind = DF_EvalVizBlockKind_Links; + next_linkblock->eval_view = eval_view; + next_linkblock->eval = udt_eval; + next_linkblock->link_member_type_key = link_member->type_key; + next_linkblock->link_member_off = link_member->off; + next_linkblock->cfg_table = *cfg_table; + next_linkblock->parent_key = key; + next_linkblock->key = df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), 0); + next_linkblock->visual_idx_range = r1u64(child_idx+1, link_bases.count); + next_linkblock->semantic_idx_range = r1u64(child_idx+1, link_bases.count); + next_linkblock->depth = depth+1; + SLLQueuePush(list_out->first, list_out->last, next_linkblock); + list_out->count += 1; + linkblock = next_linkblock; + } + } + } + end_linked_struct_expansion_build:; + + ////////////////////////////// + //- rjf: (arrays) descend to elements & make block(s), normally + // + if(parent_is_expanded && expand_rule == DF_EvalVizExpandRule_Default && + arr_type_kind == TG_Kind_Array) + ProfScope("(arrays) descend to elements & make block(s)") + { + TG_Type *array_type = tg_type_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, arr_eval.type_key); + U64 array_count = array_type->count; + TG_Key element_type_key = array_type->direct_type_key; + U64 element_type_byte_size = tg_byte_size_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, element_type_key); + + // rjf: make block for all elements (assume no elements are expanded) + DF_EvalVizBlock *elemblock = push_array(arena, DF_EvalVizBlock, 1); + { + elemblock->kind = DF_EvalVizBlockKind_Elements; + elemblock->eval_view = eval_view; + elemblock->eval = arr_eval; + elemblock->cfg_table = *cfg_table; + elemblock->parent_key = key; + elemblock->key = df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), 0); + elemblock->visual_idx_range = r1u64(0, array_count); + elemblock->semantic_idx_range = r1u64(0, array_count); + elemblock->depth = depth+1; + SLLQueuePush(list_out->first, list_out->last, elemblock); + list_out->count += 1; + list_out->total_visual_row_count += array_count; + list_out->total_semantic_row_count += array_count; + } + + // rjf: split elemblock by sub-expansions + for(DF_ExpandNode *child = node->first; child != 0; child = child->next) + { + U64 child_num = child->key.child_num; + U64 child_idx = child_num-1; + if(child_idx >= array_count) + { + continue; + } + + // rjf: truncate existing elemblock + elemblock->visual_idx_range.max = child_idx; + elemblock->semantic_idx_range.max = child_idx; + + // rjf: build inheriting cfg table + DF_CfgTable child_cfg = *cfg_table; + { + String8 view_rule_string = df_eval_view_rule_from_key(eval_view, df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), child_num)); + child_cfg = df_cfg_table_from_inheritance(arena, cfg_table); + if(view_rule_string.size != 0) + { + df_cfg_table_push_unparsed_string(arena, &child_cfg, view_rule_string, DF_CfgSrc_User); + } + } + + // rjf: recurse for sub-block + DF_Eval child_eval = zero_struct; + { + child_eval.type_key = element_type_key; + child_eval.mode = arr_eval.mode; + child_eval.offset = arr_eval.offset + child_idx*element_type_byte_size; + } + list_out->total_visual_row_count -= 1; + list_out->total_semantic_row_count -= 1; + df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, key, child->key, push_str8f(arena, "[%I64u]", child_idx), child_eval, &child_cfg, depth+1, list_out); + + // rjf: make new elemblock for remainder of children (if any) + if(child_idx+1 < array_count) + { + DF_EvalVizBlock *next_elemblock = push_array(arena, DF_EvalVizBlock, 1); + next_elemblock->kind = DF_EvalVizBlockKind_Elements; + next_elemblock->eval_view = eval_view; + next_elemblock->eval = arr_eval; + next_elemblock->cfg_table = *cfg_table; + next_elemblock->parent_key = key; + next_elemblock->key = df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), 0); + next_elemblock->visual_idx_range = r1u64(child_idx+1, array_count); + next_elemblock->semantic_idx_range = r1u64(child_idx+1, array_count); + next_elemblock->depth = depth+1; + SLLQueuePush(list_out->first, list_out->last, next_elemblock); + list_out->count += 1; + elemblock = next_elemblock; + } + } + } + + ////////////////////////////// + //- rjf: (ptr to ptrs) descend to make blocks for pointed-at-pointer + // + if(parent_is_expanded && expand_rule == DF_EvalVizExpandRule_Default && (ptr_type_kind == TG_Kind_Ptr || ptr_type_kind == TG_Kind_LRef || ptr_type_kind == TG_Kind_RRef)) + ProfScope("build viz blocks for ptr-to-ptrs") + { + String8 subexpr = push_str8f(arena, "*(%S)", string); + df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, key, df_expand_key_make(key.uniquifier, df_hash_from_expand_key(key), 1), subexpr, ptr_eval, cfg_table, depth+1, list_out); + } + + scratch_end(scratch); + ProfEnd(); +} + +internal DF_EvalVizBlockList +df_eval_viz_block_list_from_eval_view_expr(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_EvalView *eval_view, String8 expr) +{ + ProfBeginFunction(); + DF_EvalVizBlockList blocks = {0}; + { + DF_ExpandKey start_parent_key = df_expand_key_make((U64)eval_view, 0, 0); + DF_ExpandKey start_key = df_expand_key_make((U64)eval_view, 5381, 1); + DF_Eval eval = df_eval_from_string(arena, scope, ctrl_ctx, parse_ctx, expr); + U64 expr_comma_pos = str8_find_needle(expr, 0, str8_lit(","), 0); + String8List default_view_rules = {0}; + if(expr_comma_pos < expr.size) + { + String8 expr_extension = str8_skip(expr, expr_comma_pos+1); + expr_extension = str8_skip_chop_whitespace(expr_extension); + if(str8_match(expr_extension, str8_lit("x"), StringMatchFlag_CaseInsensitive)) + { + str8_list_pushf(arena, &default_view_rules, "hex"); + } + else if(str8_match(expr_extension, str8_lit("b"), StringMatchFlag_CaseInsensitive)) + { + str8_list_pushf(arena, &default_view_rules, "bin"); + } + else if(str8_match(expr_extension, str8_lit("o"), StringMatchFlag_CaseInsensitive)) + { + str8_list_pushf(arena, &default_view_rules, "oct"); + } + else + { + str8_list_pushf(arena, &default_view_rules, "array:{%S}", expr_extension); + } + } + String8 view_rule_string = df_eval_view_rule_from_key(eval_view, start_key); + DF_CfgTable view_rule_table = {0}; + for(String8Node *n = default_view_rules.first; n != 0; n = n->next) + { + df_cfg_table_push_unparsed_string(arena, &view_rule_table, n->string, DF_CfgSrc_User); + } + df_cfg_table_push_unparsed_string(arena, &view_rule_table, view_rule_string, DF_CfgSrc_User); + df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, start_parent_key, start_key, expr, eval, &view_rule_table, 0, &blocks); + } + ProfEnd(); + return blocks; +} + +internal void +df_eval_viz_block_list_concat__in_place(DF_EvalVizBlockList *dst, DF_EvalVizBlockList *to_push) +{ + if(dst->last == 0) + { + *dst = *to_push; + } + else if(to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->count += to_push->count; + dst->total_visual_row_count += to_push->total_visual_row_count; + dst->total_semantic_row_count += to_push->total_semantic_row_count; + } + MemoryZeroStruct(to_push); +} + +//////////////////////////////// +//~ rjf: Main State Accessors/Mutators + +//- rjf: frame metadata + +internal F32 +df_dt(void) +{ + return df_state->dt; +} + +internal U64 +df_frame_index(void) +{ + return df_state->frame_index; +} + +internal F64 +df_time_in_seconds(void) +{ + return df_state->time_in_seconds; +} + +//- rjf: undo/redo history + +internal DF_StateDeltaHistory * +df_state_delta_history(void) +{ + return df_state->hist; +} + +//- rjf: control state + +internal DF_RunKind +df_ctrl_last_run_kind(void) +{ + return df_state->ctrl_last_run_kind; +} + +internal U64 +df_ctrl_last_run_frame_idx(void) +{ + return df_state->ctrl_last_run_frame_idx; +} + +internal U64 +df_ctrl_run_gen(void) +{ + return df_state->ctrl_run_gen; +} + +internal B32 +df_ctrl_targets_running(void) +{ + return df_state->ctrl_is_running; +} + +//- rjf: control context + +internal DF_CtrlCtx +df_ctrl_ctx(void) +{ + return df_state->ctrl_ctx; +} + +internal void +df_ctrl_ctx_apply_overrides(DF_CtrlCtx *ctx, DF_CtrlCtx *overrides) +{ + if(!df_handle_match(overrides->thread, df_handle_zero())) + { + ctx->thread = overrides->thread; + ctx->unwind_count = overrides->unwind_count; + } +} + +//- rjf: config paths + +internal String8 +df_cfg_path_from_src(DF_CfgSrc src) +{ + return df_state->cfg_paths[src]; +} + +//- rjf: config state + +internal DF_CfgTable * +df_cfg_table(void) +{ + return &df_state->cfg_table; +} + +//- rjf: config serialization + +internal String8List +df_cfg_strings_from_core(Arena *arena, String8 root_path, DF_CfgSrc source) +{ + ProfBeginFunction(); + String8List strs = {0}; + + //- rjf: write targets + { + B32 first = 1; + DF_EntityList targets = df_query_cached_entity_list_with_kind(DF_EntityKind_Target); + for(DF_EntityNode *n = targets.first; n != 0; n = n->next) + { + DF_Entity *target = n->entity; + if(target->cfg_src == source) + { + if(first) + { + first = 0; + str8_list_push(arena, &strs, str8_lit("/// targets ///////////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + } + Temp scratch = scratch_begin(&arena, 1); + DF_Entity *exe__ent = df_entity_child_from_kind(target, DF_EntityKind_Executable); + DF_Entity *args__ent = df_entity_child_from_kind(target, DF_EntityKind_Arguments); + DF_Entity *wdir__ent = df_entity_child_from_kind(target, DF_EntityKind_ExecutionPath); + DF_Entity *entr__ent = df_entity_child_from_kind(target, DF_EntityKind_EntryPointName); + String8 label = target->name; + String8 exe = exe__ent->name; + String8 exe_normalized = path_normalized_from_string(scratch.arena, exe); + String8 exe_normalized_rel = path_relative_dst_from_absolute_dst_src(scratch.arena, exe_normalized, root_path); + String8 wdir = wdir__ent->name; + String8 wdir_normalized = path_normalized_from_string(scratch.arena, wdir); + String8 wdir_normalized_rel = path_relative_dst_from_absolute_dst_src(scratch.arena, wdir_normalized, root_path); + String8 entry_point_name = entr__ent->name; + str8_list_push (arena, &strs, str8_lit("target:\n")); + str8_list_push (arena, &strs, str8_lit("{\n")); + if(label.size != 0) + { + str8_list_pushf(arena, &strs, " label: \"%S\"\n", label); + } + str8_list_pushf(arena, &strs, " exe: \"%S\"\n", exe_normalized_rel); + str8_list_pushf(arena, &strs, " arguments: \"%S\"\n", args__ent->name); + str8_list_pushf(arena, &strs, " working_directory: \"%S\"\n", wdir_normalized_rel); + if(entry_point_name.size != 0) + { + str8_list_pushf(arena, &strs, " entry_point: \"%S\"\n", entry_point_name); + } + str8_list_pushf(arena, &strs, " active: %i\n", (int)target->b32); + if(target->flags & DF_EntityFlag_HasColor) + { + Vec4F32 hsva = df_hsva_from_entity(target); + str8_list_pushf(arena, &strs, " hsva: %.2f %.2f %.2f %.2f\n", hsva.x, hsva.y, hsva.z, hsva.w); + } + str8_list_push (arena, &strs, str8_lit("}\n")); + str8_list_push (arena, &strs, str8_lit("\n")); + scratch_end(scratch); + } + } + } + + //- rjf: write path maps + { + B32 first = 1; + DF_EntityList path_maps = df_query_cached_entity_list_with_kind(DF_EntityKind_OverrideFileLink); + for(DF_EntityNode *n = path_maps.first; n != 0; n = n->next) + { + DF_Entity *map = n->entity; + if(map->cfg_src == source) + { + if(first) + { + first = 0; + str8_list_push(arena, &strs, str8_lit("/// file path maps ////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + } + String8 src_path = df_full_path_from_entity(arena, map); + String8 dst_path = df_full_path_from_entity(arena, df_entity_from_handle(map->entity_handle)); + str8_list_push (arena, &strs, str8_lit("file_path_map:\n")); + str8_list_push (arena, &strs, str8_lit("{\n")); + str8_list_pushf(arena, &strs, " source_path: \"%S\"\n", src_path); + str8_list_pushf(arena, &strs, " dest_path: \"%S\"\n", dst_path); + str8_list_push (arena, &strs, str8_lit("}\n")); + str8_list_push (arena, &strs, str8_lit("\n")); + } + } + } + + //- rjf: write breakpoints + { + B32 first = 1; + DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + for(DF_EntityNode *n = bps.first; n != 0; n = n->next) + { + DF_Entity *bp = n->entity; + if(bp->cfg_src == source) + { + DF_Entity *file = df_entity_ancestor_from_kind(bp, DF_EntityKind_File); + DF_Entity *symb = df_entity_child_from_kind(bp, DF_EntityKind_EntryPointName); + DF_Entity *cond = df_entity_child_from_kind(bp, DF_EntityKind_Condition); + if(first) + { + first = 0; + str8_list_push(arena, &strs, str8_lit("/// breakpoints ///////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + } + + // rjf: begin + str8_list_push(arena, &strs, str8_lit("breakpoint:\n")); + str8_list_push(arena, &strs, str8_lit("{\n")); + + // rjf: textual breakpoints + if(!df_entity_is_nil(file) && bp->flags & DF_EntityFlag_HasTextPoint) + { + String8 bp_file_path = df_full_path_from_entity(arena, file); + String8 srlized_bp_file_path = path_relative_dst_from_absolute_dst_src(arena, bp_file_path, root_path); + String8 string = push_str8f(arena, " line: (\"%S\":%I64d)\n", srlized_bp_file_path, bp->text_point.line); + str8_list_push(arena, &strs, string); + } + + // rjf: function name breakpoints + else if(!df_entity_is_nil(symb) && symb->name.size != 0) + { + str8_list_pushf(arena, &strs, " symbol: \"%S\"\n", symb->name); + } + + // rjf: address breakpoints + else if(bp->flags & DF_EntityFlag_HasVAddr) + { + str8_list_pushf(arena, &strs, " addr: 0x%I64x\n", bp->vaddr); + } + + // rjf: conditions + if(!df_entity_is_nil(cond)) + { + str8_list_pushf(arena, &strs, " condition: \"%S\"\n", cond->name); + } + + // rjf: universal options + str8_list_pushf(arena, &strs, " enabled: %i\n", (int)bp->b32); + if(bp->name.size != 0) + { + str8_list_pushf(arena, &strs, " label: \"%S\"\n", bp->name); + } + if(bp->flags & DF_EntityFlag_HasColor) + { + Vec4F32 hsva = df_hsva_from_entity(bp); + str8_list_pushf(arena, &strs, " hsva: %.2f %.2f %.2f %.2f\n", hsva.x, hsva.y, hsva.z, hsva.w); + } + + // rjf: end + str8_list_push(arena, &strs, str8_lit("}\n\n")); + } + } + } + + //- rjf: write watch pins + { + B32 first = 1; + DF_EntityList pins = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin); + for(DF_EntityNode *n = pins.first; n != 0; n = n->next) + { + DF_Entity *pin = n->entity; + if(pin->cfg_src == source) + { + if(first) + { + first = 0; + str8_list_push(arena, &strs, str8_lit("/// watch pins ////////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + } + + // rjf: write + str8_list_push(arena, &strs, str8_lit("watch_pin:\n")); + str8_list_push(arena, &strs, str8_lit("{\n")); + str8_list_pushf(arena, &strs, " expression: \"%S\"\n", pin->name); + DF_Entity *file = df_entity_ancestor_from_kind(pin, DF_EntityKind_File); + if(pin->flags & DF_EntityFlag_HasTextPoint && !df_entity_is_nil(file)) + { + String8 profile_path = root_path; + String8 pin_file_path = df_full_path_from_entity(arena, file); + profile_path = path_normalized_from_string(arena, profile_path); + pin_file_path = path_normalized_from_string(arena, pin_file_path); + String8 srlized_pin_file_path = path_relative_dst_from_absolute_dst_src(arena, pin_file_path, profile_path); + str8_list_pushf(arena, &strs, " line: (\"%S\":%I64d)\n", srlized_pin_file_path, pin->text_point.line); + } + else if(pin->flags & DF_EntityFlag_HasVAddr) + { + str8_list_pushf(arena, &strs, " addr: (0x%I64x)\n", pin->vaddr); + } + if(pin->flags & DF_EntityFlag_HasColor) + { + Vec4F32 hsva = df_hsva_from_entity(pin); + str8_list_pushf(arena, &strs, " hsva: %.2f %.2f %.2f %.2f\n", hsva.x, hsva.y, hsva.z, hsva.w); + } + str8_list_push(arena, &strs, str8_lit("}\n\n")); + } + } + } + + //- rjf: write exception code filters + if(source == DF_CfgSrc_Profile) + { + str8_list_push(arena, &strs, str8_lit("/// exception code filters ////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + str8_list_push(arena, &strs, str8_lit("exception_code_filters:\n")); + str8_list_push(arena, &strs, str8_lit("{\n")); + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)(CTRL_ExceptionCodeKind_Null+1); + k < CTRL_ExceptionCodeKind_COUNT; + k = (CTRL_ExceptionCodeKind)(k+1)) + { + String8 name = ctrl_exception_code_kind_lowercase_code_string_table[k]; + B32 value = !!(df_state->ctrl_exception_code_filters[k/64] & (1ull<<(k%64))); + str8_list_pushf(arena, &strs, " %S: %i\n", name, value); + } + str8_list_push(arena, &strs, str8_lit("}\n\n")); + } + + //- rjf: write control settings + if(source == DF_CfgSrc_Profile) + { + str8_list_push(arena, &strs, str8_lit("/// control settings //////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + str8_list_pushf(arena, &strs, "solo_stepping_mode: %i\n", df_state->ctrl_solo_stepping_mode); + str8_list_push(arena, &strs, str8_lit("\n")); + } + + //- rjf: write eval view cache +#if 0 + if(source == DF_CfgSrc_Profile) + { + B32 first = 1; + for(U64 eval_view_slot_idx = 0; + eval_view_slot_idx < df_state->eval_view_cache.slots_count; + eval_view_slot_idx += 1) + { + for(DF_EvalView *ev = df_state->eval_view_cache.slots[idx].first; + ev != &df_g_nil_eval_view && ev != 0; + ev = ev->hash_next) + { + if(first) + { + first = 0; + str8_list_push(arena, &strs, str8_lit("/// eval view state ///////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + } + str8_list_push(arena, &strs, str8_lit("eval_view:\n")); + str8_list_push(arena, &strs, str8_lit("{\n")); + str8_list_pushf(arena, &strs, " key: (%I64x, %I64x)\n", ev->key.u64[0], ev->key.u64[1]); + for(U64 expand_slot_idx = 0; + expand_slot_idx < ev->expand_tree_table.slots_count; + expand_slot_idx += 1) + { + for(DF_ExpandNode *expand_node = ev->expand_tree_table.slots[expand_slot_idx].first; + expand_node != 0; + expand_node = expand_node->hash_next) + { + DF_ExpandKey key = expand_node->key; + B32 expanded = expand_node->expanded; + str8_list_pushf(arena, &strs, " node: ()\n"); + } + } + str8_list_push(arena, &strs, str8_lit("}\n\n")); + } + } + } +#endif + + ProfEnd(); + return strs; +} + +internal void +df_cfg_push_write_string(DF_CfgSrc src, String8 string) +{ + str8_list_push(df_state->cfg_write_arenas[src], &df_state->cfg_write_data[src], push_str8_copy(df_state->cfg_write_arenas[src], string)); +} + +//- rjf: current path + +internal String8 +df_current_path(void) +{ + return df_state->current_path; +} + +//- rjf: architecture info table lookups + +internal String8 +df_info_summary_from_string__x64(String8 string) +{ + String8 result = {0}; + { + U64 hash = df_hash_from_string__case_insensitive(string); + U64 slot_idx = hash % df_state->arch_info_x64_table_size; + DF_ArchInfoSlot *slot = &df_state->arch_info_x64_table[slot_idx]; + for(DF_ArchInfoNode *n = slot->first; n != 0; n = n->hash_next) + { + if(str8_match(n->key, string, StringMatchFlag_CaseInsensitive)) + { + result = n->val; + break; + } + } + } + return result; +} + +internal String8 +df_info_summary_from_string(Architecture arch, String8 string) +{ + String8 result = {0}; + switch(arch) + { + default:{}break; + case Architecture_x64: + { + result = df_info_summary_from_string__x64(string); + }break; + } + return result; +} + +//- rjf: entity kind cache + +internal DF_EntityList +df_query_cached_entity_list_with_kind(DF_EntityKind kind) +{ + ProfBeginFunction(); + DF_EntityListCache *cache = &df_state->kind_caches[kind]; + + // rjf: build cached list if we're out-of-date + if(cache->alloc_gen != df_state->kind_alloc_gens[kind]) + { + cache->alloc_gen = df_state->kind_alloc_gens[kind]; + if(cache->arena == 0) + { + cache->arena = arena_alloc(); + } + arena_clear(cache->arena); + cache->list = df_push_entity_list_with_kind(cache->arena, kind); + } + + // rjf: grab & return cached list + DF_EntityList result = cache->list; + ProfEnd(); + return result; +} + +internal DF_EntityList +df_push_active_binary_list(Arena *arena) +{ + DF_EntityList binaries = {0}; + DF_EntityList modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); + for(DF_EntityNode *n = modules.first; n != 0; n = n->next) + { + DF_Entity *module = n->entity; + DF_Entity *binary = df_binary_file_from_module(module); + df_entity_list_push(arena, &binaries, binary); + } + return binaries; +} + +internal DF_EntityList +df_push_active_target_list(Arena *arena) +{ + DF_EntityList active_targets = {0}; + DF_EntityList all_targets = df_query_cached_entity_list_with_kind(DF_EntityKind_Target); + for(DF_EntityNode *n = all_targets.first; n != 0; n = n->next) + { + if(n->entity->b32) + { + df_entity_list_push(arena, &active_targets, n->entity); + } + } + return active_targets; +} + +//- rjf: per-run caches + +internal DF_Unwind +df_query_cached_unwind_from_thread(DF_Entity *thread) +{ + ProfBeginFunction(); + DF_Unwind result = {0}; + DF_RunUnwindCache *cache = &df_state->unwind_cache; + if(cache->table_size != 0) + { + DF_Handle handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 slot_idx = hash % cache->table_size; + DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx]; + for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_handle_match(n->thread, handle)) + { + result = n->unwind; + break; + } + } + } + ProfEnd(); + return result; +} + +internal U64 +df_query_cached_rip_from_thread(DF_Entity *thread) +{ + U64 result = 0; + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + if(unwind.first != 0) + { + result = unwind.first->rip; + } + return result; +} + +internal U64 +df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) +{ + U64 result = 0; + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + U64 unwind_idx = 0; + for(DF_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) + { + if(unwind_idx == unwind_count) + { + result = frame->rip; + break; + } + } + return result; +} + +internal EVAL_String2NumMap * +df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) +{ + ProfBeginFunction(); + EVAL_String2NumMap *map = &eval_string2num_map_nil; + { + DF_RunLocalsCache *cache = &df_state->locals_cache; + if(cache->table_size == 0) + { + cache->table_size = 256; + cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); + } + DF_Handle handle = df_handle_from_entity(binary); + U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 slot_idx = hash % cache->table_size; + DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; + DF_RunLocalsCacheNode *node = 0; + for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_handle_match(n->binary, handle) && n->voff == voff) + { + node = n; + break; + } + } + if(node == 0) + { + DBGI_Scope *scope = dbgi_scope_open(); + EVAL_String2NumMap *map = df_push_locals_map_from_binary_voff(cache->arena, scope, binary, voff); + if(map->slots_count != 0) + { + node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); + node->binary = handle; + node->voff = voff; + node->locals_map = map; + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + } + dbgi_scope_close(scope); + } + if(node != 0) + { + map = node->locals_map; + } + } + ProfEnd(); + return map; +} + +internal EVAL_String2NumMap * +df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) +{ + ProfBeginFunction(); + EVAL_String2NumMap *map = &eval_string2num_map_nil; + { + DF_RunLocalsCache *cache = &df_state->member_cache; + if(cache->table_size == 0) + { + cache->table_size = 256; + cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); + } + DF_Handle handle = df_handle_from_entity(binary); + U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 slot_idx = hash % cache->table_size; + DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; + DF_RunLocalsCacheNode *node = 0; + for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_handle_match(n->binary, handle) && n->voff == voff) + { + node = n; + break; + } + } + if(node == 0) + { + DBGI_Scope *scope = dbgi_scope_open(); + EVAL_String2NumMap *map = df_push_member_map_from_binary_voff(cache->arena, scope, binary, voff); + if(map->slots_count != 0) + { + node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); + node->binary = handle; + node->voff = voff; + node->locals_map = map; + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + } + dbgi_scope_close(scope); + } + if(node != 0) + { + map = node->locals_map; + } + } + ProfEnd(); + return map; +} + +//- rjf: top-level command dispatch + +internal void +df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec) +{ + df_cmd_list_push(df_state->root_cmd_arena, &df_state->root_cmds, params, spec); +} + +//////////////////////////////// +//~ rjf: Main Layer Top-Level Calls + +internal void +df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist) +{ + Arena *arena = arena_alloc(); + df_state = push_array(arena, DF_State, 1); + df_state->arena = arena; + df_state->root_cmd_arena = arena_alloc(); + df_state->entities_arena = arena_alloc__sized(GB(64), KB(64)); + df_state->entities_root = &df_g_nil_entity; + df_state->entities_base = push_array(df_state->entities_arena, DF_Entity, 0); + df_state->entities_count = 0; + df_state->ctrl_msg_arena = arena_alloc(); + df_state->ctrl_stop_arena = arena_alloc(); + df_state->entities_root = df_entity_alloc(0, &df_g_nil_entity, DF_EntityKind_Root); + df_state->cmd_spec_table_size = 1024; + df_state->cmd_spec_table = push_array(arena, DF_CmdSpec *, df_state->cmd_spec_table_size); + df_state->view_rule_spec_table_size = 1024; + df_state->view_rule_spec_table = push_array(arena, DF_CoreViewRuleSpec *, df_state->view_rule_spec_table_size); + df_state->seconds_til_autosave = 0.5f; + df_state->hist = hist; + + // rjf: set up initial exception filtering rules + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) + { + if(ctrl_exception_code_kind_default_enable_table[k]) + { + df_state->ctrl_exception_code_filters[k/64] |= 1ull<<(k%64); + } + } + + // rjf: set up initial entities + { + DF_Entity *local_machine = df_entity_alloc(0, df_state->entities_root, DF_EntityKind_Machine); + df_entity_equip_ctrl_machine_id(local_machine, CTRL_MachineID_Client); + df_entity_equip_name(0, local_machine, str8_lit("This PC")); + } + + // rjf: register core commands + { + DF_CmdSpecInfoArray array = {df_g_core_cmd_kind_spec_info_table, ArrayCount(df_g_core_cmd_kind_spec_info_table)}; + df_register_cmd_specs(array); + } + + // rjf: register core view rules + { + DF_CoreViewRuleSpecInfoArray array = {df_g_core_view_rule_spec_info_table, ArrayCount(df_g_core_view_rule_spec_info_table)}; + df_register_core_view_rule_specs(array); + } + + // rjf: set up per-run caches + df_state->unwind_cache.arena = arena_alloc(); + df_state->locals_cache.arena = arena_alloc(); + df_state->member_cache.arena = arena_alloc(); + + // rjf: set up eval view cache + df_state->eval_view_cache.slots_count = 4096; + df_state->eval_view_cache.slots = push_array(arena, DF_EvalViewSlot, df_state->eval_view_cache.slots_count); + + // rjf: set up run state + df_state->ctrl_last_run_arena = arena_alloc(); + + // rjf: set up config reading state + { + Temp scratch = scratch_begin(0, 0); + + // rjf: set up config path state + String8 cfg_src_paths[DF_CfgSrc_COUNT] = {user_path, profile_path}; + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + df_state->cfg_path_arenas[src] = arena_alloc(); + DF_CmdParams params = df_cmd_params_zero(); + params.file_path = path_normalized_from_string(scratch.arena, cfg_src_paths[src]); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_load_cmd_kind_table[src])); + } + + // rjf: set up config table arena + df_state->cfg_arena = arena_alloc(); + scratch_end(scratch); + } + + // rjf: set up config write state + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + df_state->cfg_write_arenas[src] = arena_alloc(); + } + + // rjf: set up initial browse path + { + Temp scratch = scratch_begin(0, 0); + String8List current_path_strs = {0}; + os_string_list_from_system_path(scratch.arena, OS_SystemPath_Current, ¤t_path_strs); + df_state->current_path_arena = arena_alloc(); + String8 current_path = str8_list_first(¤t_path_strs); + String8 current_path_with_slash = push_str8f(scratch.arena, "%S/", current_path); + df_state->current_path = push_str8_copy(df_state->current_path_arena, current_path_with_slash); + scratch_end(scratch); + } + + // rjf: set up architecture info tables + df_state->arch_info_x64_table_size = 1024; + df_state->arch_info_x64_table = push_array(df_state->arena, DF_ArchInfoSlot, df_state->arch_info_x64_table_size); + for(U64 idx = 0; idx < ArrayCount(df_g_inst_table_x64); idx += 1) + { + String8 key = df_g_inst_table_x64[idx].mnemonic; + String8 val = df_g_inst_table_x64[idx].summary; + U64 hash = df_hash_from_string__case_insensitive(key); + U64 slot_idx = hash % df_state->arch_info_x64_table_size; + DF_ArchInfoSlot *slot = &df_state->arch_info_x64_table[slot_idx]; + DF_ArchInfoNode *n = push_array(df_state->arena, DF_ArchInfoNode, 1); + SLLQueuePush_N(slot->first, slot->last, n, hash_next); + n->key = key; + n->val = val; + } +} + +internal DF_CmdList +df_core_gather_root_cmds(Arena *arena) +{ + DF_CmdList cmds = {0}; + for(DF_CmdNode *n = df_state->root_cmds.first; n != 0; n = n->next) + { + df_cmd_list_push(arena, &cmds, &n->cmd.params, n->cmd.spec); + } + return cmds; +} + +internal void +df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) +{ + ProfBeginFunction(); + df_state->frame_index += 1; + df_state->dt = dt; + df_state->time_in_seconds += dt; + + //- rjf: sync with ctrl thread + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: consume & process events + B32 run_caches_invalidated = 0; + CTRL_EventList events = ctrl_c2u_pop_events(scratch.arena); + for(CTRL_EventNode *event_n = events.first; event_n != 0; event_n = event_n->next) + { + CTRL_Event *event = &event_n->v; + switch(event->kind) + { + default:{}break; + + //- rjf: starts/stops + + case CTRL_EventKind_Started: + { + df_state->ctrl_is_running = 1; + }break; + + case CTRL_EventKind_Stopped: + { + df_state->ctrl_is_running = 0; + df_state->ctrl_soft_halt_issued = 0; + run_caches_invalidated = 1; + DF_Entity *stop_thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); + + // rjf: gather stop info + { + arena_clear(df_state->ctrl_stop_arena); + MemoryCopyStruct(&df_state->ctrl_last_stop_event, event); + df_state->ctrl_last_stop_event.string = push_str8_copy(df_state->ctrl_stop_arena, df_state->ctrl_last_stop_event.string); + } + + // rjf: select & snap to thread causing stop + if(!df_entity_is_nil(stop_thread)) + { + DF_CmdParams params = df_cmd_params_zero(); + params.entity = df_handle_from_entity(stop_thread); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectThread)); + } + + // rjf: thread hit user breakpoint -> increment breakpoint hit count + if(event->cause == CTRL_EventCause_UserBreakpoint) + { + U64 stop_thread_vaddr = df_rip_from_thread(stop_thread); + DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 stop_thread_voff = df_voff_from_vaddr(module, stop_thread_vaddr); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, stop_thread_voff); + DF_EntityList user_bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + for(DF_EntityNode *n = user_bps.first; n != 0; n = n->next) + { + DF_Entity *bp = n->entity; + if(bp->flags & DF_EntityFlag_HasVAddr && bp->vaddr == stop_thread_vaddr) + { + bp->u64 += 1; + } + if(bp->flags & DF_EntityFlag_HasTextPoint) + { + DF_Entity *bp_file = df_entity_ancestor_from_kind(bp, DF_EntityKind_File); + if(bp_file == dasm2src_info.file && bp->text_point.line == dasm2src_info.pt.line) + { + bp->u64 += 1; + } + } + } + } + }break; + + //- rjf: entity creation/deletion + + case CTRL_EventKind_NewProc: + { + run_caches_invalidated = 1; + + // rjf: the first process? -> clear session output & reset all bp hit counts + DF_EntityList existing_processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + if(existing_processes.count == 0) + { + Temp scratch = scratch_begin(0, 0); + DF_Entity *session_log = df_log_from_entity(df_entity_root()); + TXTI_Handle session_log_handle = df_txti_handle_from_entity(session_log); + txti_reload(session_log_handle, df_full_path_from_entity(scratch.arena, session_log)); + DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + for(DF_EntityNode *n = bps.first; n != 0; n = n->next) + { + n->entity->u64 = 0; + } + } + + // rjf: create entity + DF_Entity *machine = df_machine_entity_from_machine_id(event->machine_id); + DF_Entity *entity = df_entity_alloc(0, machine, DF_EntityKind_Process); + df_entity_equip_u64(entity, event->msg_id); + df_entity_equip_ctrl_machine_id(entity, event->machine_id); + df_entity_equip_ctrl_handle(entity, event->entity); + df_entity_equip_ctrl_id(entity, event->entity_id); + df_entity_equip_arch(entity, event->arch); + }break; + + case CTRL_EventKind_NewThread: + { + run_caches_invalidated = 1; + + // rjf: create entity + DF_Entity *parent = df_entity_from_ctrl_handle(event->machine_id, event->parent); + DF_Entity *entity = df_entity_alloc(0, parent, DF_EntityKind_Thread); + df_entity_equip_ctrl_machine_id(entity, event->machine_id); + df_entity_equip_ctrl_handle(entity, event->entity); + df_entity_equip_arch(entity, event->arch); + df_entity_equip_ctrl_id(entity, event->entity_id); + df_entity_equip_stack_base(entity, event->stack_base); + df_entity_equip_tls_root(entity, event->tls_root); + df_entity_equip_vaddr(entity, event->rip_vaddr); + + // rjf: determine index in process + U64 thread_idx_in_process = 0; + for(DF_Entity *child = parent->first; !df_entity_is_nil(child); child = child->next) + { + if(child == entity) + { + break; + } + if(child->kind == DF_EntityKind_Thread) + { + thread_idx_in_process += 1; + } + } + + // rjf: build default thread color table + Vec4F32 thread_colors[] = + { + df_rgba_from_theme_color(DF_ThemeColor_Thread0), + df_rgba_from_theme_color(DF_ThemeColor_Thread1), + df_rgba_from_theme_color(DF_ThemeColor_Thread2), + df_rgba_from_theme_color(DF_ThemeColor_Thread3), + df_rgba_from_theme_color(DF_ThemeColor_Thread4), + df_rgba_from_theme_color(DF_ThemeColor_Thread5), + df_rgba_from_theme_color(DF_ThemeColor_Thread6), + df_rgba_from_theme_color(DF_ThemeColor_Thread7), + }; + + // rjf: pick color + Vec4F32 thread_color = thread_colors[thread_idx_in_process % ArrayCount(thread_colors)]; + + // rjf: equip color + df_entity_equip_color_rgba(entity, thread_color); + + // rjf: automatically select if we don't have a selected thread + DF_Entity *selected_thread = df_entity_from_handle(df_state->ctrl_ctx.thread); + if(df_entity_is_nil(selected_thread)) + { + df_state->ctrl_ctx.thread = df_handle_from_entity(entity); + } + + // rjf: do initial snap + DF_EntityList already_existing_processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + B32 do_initial_snap = (already_existing_processes.count == 1 && thread_idx_in_process == 0); + if(do_initial_snap) + { + DF_CmdParams params = df_cmd_params_zero(); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectThread)); + } + }break; + + case CTRL_EventKind_NewModule: + { + // rjf: grab process + DF_Entity *parent = df_entity_from_ctrl_handle(event->machine_id, event->parent); + + // rjf: determine if this is the first module + B32 is_first = 0; + if(df_entity_is_nil(df_entity_child_from_kind(parent, DF_EntityKind_Module))) + { + is_first = 1; + } + + // rjf: create module entity + DF_Entity *module = df_entity_alloc(0, parent, DF_EntityKind_Module); + df_entity_equip_ctrl_machine_id(module, event->machine_id); + df_entity_equip_ctrl_handle(module, event->entity); + df_entity_equip_arch(module, event->arch); + df_entity_equip_name(0, module, event->string); + df_entity_equip_vaddr_rng(module, event->vaddr_rng); + df_entity_equip_vaddr(module, event->rip_vaddr); + + // rjf: create & attach binary file + String8 bin_path = module->name; + DF_Entity *binary = df_entity_from_path(bin_path, DF_EntityFromPathFlag_All); + df_entity_equip_entity_handle(module, df_handle_from_entity(binary)); + + // rjf: is first -> attach process color if applicable + if(is_first && parent->flags & DF_EntityFlag_HasColor) + { + Vec4F32 rgba = df_rgba_from_entity(parent); + df_entity_equip_color_rgba(module, rgba); + } + }break; + + case CTRL_EventKind_EndProc: + { + U32 pid = event->entity_id; + DF_Entity *process = df_entity_from_ctrl_handle(event->machine_id, event->entity); + df_entity_mark_for_deletion(process); + }break; + + case CTRL_EventKind_EndThread: + { + DF_Entity *thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); + df_set_thread_freeze_state(thread, 0); + df_entity_mark_for_deletion(thread); + }break; + + case CTRL_EventKind_EndModule: + { + DF_Entity *module = df_entity_from_ctrl_handle(event->machine_id, event->entity); + df_entity_mark_for_deletion(module); + }break; + + //- rjf: debug strings + + case CTRL_EventKind_DebugString: + { + String8 string = event->string; + DF_Entity *root = df_entity_root(); + DF_Entity *thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *machine = df_entity_ancestor_from_kind(process, DF_EntityKind_Machine); + DF_Entity *root_log = df_log_from_entity(root); + DF_Entity *thread_log = df_log_from_entity(thread); + DF_Entity *process_log = df_log_from_entity(process); + DF_Entity *machine_log = df_log_from_entity(machine); + TXTI_Handle root_log_handle = df_txti_handle_from_entity(root_log); + TXTI_Handle thread_log_handle = df_txti_handle_from_entity(thread_log); + TXTI_Handle process_log_handle = df_txti_handle_from_entity(process_log); + TXTI_Handle machine_log_handle = df_txti_handle_from_entity(machine_log); + txti_append(root_log_handle, string); + txti_append(thread_log_handle, string); + txti_append(process_log_handle, string); + txti_append(machine_log_handle, string); + }break; + + case CTRL_EventKind_ThreadName: + { + String8 string = event->string; + DF_Entity *thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); + df_entity_equip_name(0, thread, string); + }break; + + //- rjf: memory + + case CTRL_EventKind_MemReserve:{}break; + case CTRL_EventKind_MemCommit:{}break; + case CTRL_EventKind_MemDecommit:{}break; + case CTRL_EventKind_MemRelease:{}break; + + //- rjf: ctrl requests + + case CTRL_EventKind_LaunchAndInitDone: + case CTRL_EventKind_LaunchAndHandshakeDone: + case CTRL_EventKind_AttachDone: + case CTRL_EventKind_KillDone: + case CTRL_EventKind_DetachDone: + { + // rjf: resolve request entities + DF_EntityID id = event->msg_id; + DF_Entity *request_entity = df_entity_from_id(id); + if(!df_entity_is_nil(request_entity)) + { + df_entity_mark_for_deletion(request_entity); + switch(request_entity->subkind) + { + case CTRL_MsgKind_LaunchAndInit: + case CTRL_MsgKind_LaunchAndHandshake: + { + DF_Entity *target = df_entity_from_handle(request_entity->entity_handle); + DF_Entity *process = df_entity_from_ctrl_id(event->machine_id, event->entity_id); + DF_Entity *thread = df_entity_child_from_kind(process, DF_EntityKind_Thread); + if(!df_entity_is_nil(target) && !df_entity_is_nil(process) && !df_entity_is_nil(thread)) + { + df_entity_equip_entity_handle(process, df_handle_from_entity(target)); + if(target->flags & DF_EntityFlag_HasColor) + { + Vec4F32 color = df_rgba_from_entity(target); + df_entity_equip_color_rgba(process, color); + df_entity_equip_color_rgba(thread, color); + } + } + run_caches_invalidated = 1; + }break; + } + } + + // rjf: collect s top info + arena_clear(df_state->ctrl_stop_arena); + MemoryCopyStruct(&df_state->ctrl_last_stop_event, event); + df_state->ctrl_last_stop_event.string = push_str8_copy(df_state->ctrl_stop_arena, df_state->ctrl_last_stop_event.string); + }break; + } + } + + //- rjf: invalidate per-run caches + if(run_caches_invalidated) + { + df_state->unwind_cache_invalidated = 1; + df_state->locals_cache_invalidated = 1; + df_state->member_cache_invalidated = 1; + } + + //- rjf: refresh unwind cache + if(df_state->unwind_cache_invalidated && !df_ctrl_targets_running()) ProfScope("per-thread unwind gather") + { + B32 good = 1; + DF_EntityList all_threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); + DF_RunUnwindCache *cache = &df_state->unwind_cache; + arena_clear(cache->arena); + cache->table_size = 1024; + cache->table = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->table_size); + for(DF_EntityNode *n = all_threads.first; n != 0; n = n->next) + { + DF_Entity *thread = n->entity; + DF_Handle thread_handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&thread_handle)); + U64 slot_idx = hash % cache->table_size; + DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx]; + DF_RunUnwindCacheNode *cache_node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); + cache_node->thread = thread_handle; + cache_node->unwind = df_push_unwind_from_thread(cache->arena, thread); + SLLQueuePush_NZ(0, slot->first, slot->last, cache_node, hash_next); + if(cache_node->unwind.error != 0) + { + good = 0; + break; + } + } + df_state->unwind_cache_invalidated = !good; + } + + //- rjf: clear locals cache + if(df_state->locals_cache_invalidated && !df_ctrl_targets_running()) + { + df_state->locals_cache_invalidated = 0; + DF_RunLocalsCache *cache = &df_state->locals_cache; + arena_clear(cache->arena); + cache->table_size = 0; + cache->table = 0; + } + + //- rjf: clear members cache + if(df_state->member_cache_invalidated && !df_ctrl_targets_running()) + { + df_state->member_cache_invalidated = 0; + DF_RunLocalsCache *cache = &df_state->member_cache; + arena_clear(cache->arena); + cache->table_size = 0; + cache->table = 0; + } + + scratch_end(scratch); + } + + //- rjf: sync with dbgi parsers + { + Temp scratch = scratch_begin(&arena, 1); + DBGI_EventList events = dbgi_p2u_pop_events(scratch.arena, 0); + for(DBGI_EventNode *n = events.first; n != 0; n = n->next) + { + DBGI_Event *event = &n->v; + switch(event->kind) + { + default:{}break; + case DBGI_EventKind_ConversionStarted: + { + DF_Entity *task = df_entity_alloc(0, df_entity_root(), DF_EntityKind_ConversionTask); + df_entity_equip_name(0, task, event->string); + }break; + case DBGI_EventKind_ConversionEnded: + { + DF_Entity *task = df_entity_from_name_and_kind(event->string, DF_EntityKind_ConversionTask); + if(!df_entity_is_nil(task)) + { + df_entity_mark_for_deletion(task); + } + }break; + case DBGI_EventKind_ConversionFailureUnsupportedFormat: + { + // DF_Entity *task = df_entity_alloc(df_entity_root(), DF_EntityKind_ConversionFail); + // df_entity_equip_name(task, event->string); + // df_entity_equip_death_timer(task, 15.f); + }break; + } + } + scratch_end(scratch); + } + + //- rjf: start/stop telemetry captures + { + if(!ProfIsCapturing() && DEV_telemetry_capture) + { + ProfBeginCapture("raddbg"); + } + if(ProfIsCapturing() && !DEV_telemetry_capture) + { + ProfEndCapture(); + } + } + + //- rjf: clear root level commands + { + arena_clear(df_state->root_cmd_arena); + MemoryZeroStruct(&df_state->root_cmds); + } + + //- rjf: autosave + { + df_state->seconds_til_autosave -= dt; + if(df_state->seconds_til_autosave <= 0.f) + { + DF_CmdParams params = df_cmd_params_zero(); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WriteUserData)); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WriteProfileData)); + df_state->seconds_til_autosave = 5.f; + } + } + + //- rjf: process top-level commands + { + Temp scratch = scratch_begin(&arena, 1); + for(DF_CmdNode *cmd_node = cmds->first; + cmd_node != 0; + cmd_node = cmd_node->next) + { + temp_end(scratch); + + // rjf: unpack command + DF_Cmd *cmd = &cmd_node->cmd; + DF_CmdParams params = cmd->params; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + df_cmd_spec_counter_inc(cmd->spec); + + // rjf: process command + switch(core_cmd_kind) + { + default:{}break; + + //- rjf: command fast paths + case DF_CoreCmdKind_CommandFastPath: + { + DF_CmdSpec *spec = params.cmd_spec; + DF_CmdQueryRule query_rule = spec->info.query_rule; + if(query_rule == DF_CmdQueryRule_Null) + { + df_cmd_list_push(arena, cmds, ¶ms, spec); + } + }break; + + //- rjf: low-level target control operations + case DF_CoreCmdKind_LaunchAndRun: + case DF_CoreCmdKind_LaunchAndInit: + { + // rjf: get list of targets to launch + DF_EntityList targets = df_entity_list_from_handle_list(scratch.arena, params.entity_list); + + // rjf: no targets => assume all active targets + if(targets.count == 0) + { + targets = df_push_active_target_list(scratch.arena); + } + + // rjf: launch + if(targets.count != 0) + { + for(DF_EntityNode *n = targets.first; n != 0; n = n->next) + { + // rjf: extract data from target + DF_Entity *target = n->entity; + String8 name = df_entity_child_from_kind(target, DF_EntityKind_Executable)->name; + String8 args = df_entity_child_from_kind(target, DF_EntityKind_Arguments)->name; + String8 path = df_entity_child_from_kind(target, DF_EntityKind_ExecutionPath)->name; + String8 entry= df_entity_child_from_kind(target, DF_EntityKind_EntryPointName)->name; + if(path.size == 0) + { + String8List current_path_strs = {0}; + os_string_list_from_system_path(scratch.arena, OS_SystemPath_Current, ¤t_path_strs); + path = str8_list_first(¤t_path_strs); + } + + // rjf: build launch options + String8List cmdln_strings = {0}; + { + str8_list_push(scratch.arena, &cmdln_strings, name); + { + U64 start_split_idx = 0; + B32 quoted = 0; + for(U64 idx = 0; idx <= args.size; idx += 1) + { + U8 byte = idx < args.size ? args.str[idx] : 0; + if(byte == '"') + { + quoted ^= 1; + } + B32 splitter_found = (!quoted && (byte == 0 || char_is_space(byte))); + if(splitter_found) + { + String8 string = str8_substr(args, r1u64(start_split_idx, idx)); + if(string.size > 0) + { + if(str8_match(str8_prefix(string, 1), str8_lit("\""), 0)) + { + string = str8_skip(string, 1); + } + if(str8_match(str8_postfix(string, 1), str8_lit("\""), 0)) + { + string = str8_chop(string, 1); + } + str8_list_push(scratch.arena, &cmdln_strings, string); + } + start_split_idx = idx+1; + } + } + } + } + + // rjf: build corresponding request entity + DF_Entity *request_entity = df_entity_alloc(0, df_entity_root(), DF_EntityKind_CtrlRequest); + { + request_entity->subkind = CTRL_MsgKind_LaunchAndInit; + request_entity->entity_handle = df_handle_from_entity(target); + } + + // rjf: push message to launch + { + CTRL_Msg msg = {CTRL_MsgKind_LaunchAndInit}; + msg.msg_id = request_entity->id; + msg.path = path; + msg.cmd_line_string_list = cmdln_strings; + msg.env_inherit = 1; + MemoryCopyArray(msg.exception_code_filters, df_state->ctrl_exception_code_filters); + str8_list_push(scratch.arena, &msg.strings, entry); + df_push_ctrl_msg(&msg); + } + } + + // rjf: run if needed + if(core_cmd_kind == DF_CoreCmdKind_LaunchAndRun) + { + df_ctrl_run(DF_RunKind_Run, &df_g_nil_entity, 0); + } + } + + // rjf: no targets -> error + if(targets.count == 0) + { + DF_CmdParams p = params; + p.string = str8_lit("No active targets exist; cannot launch."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + }break; + case DF_CoreCmdKind_Kill: + { + DF_EntityList processes = df_entity_list_from_handle_list(scratch.arena, params.entity_list); + + // rjf: no processes => kill everything + if(processes.count == 0) + { + processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + } + + // rjf: kill processes + if(processes.count != 0) + { + for(DF_EntityNode *n = processes.first; n != 0; n = n->next) + { + DF_Entity *process = n->entity; + CTRL_Msg msg = {CTRL_MsgKind_Kill}; + { + msg.exit_code = 1; + msg.machine_id = process->ctrl_machine_id; + msg.entity = process->ctrl_handle; + MemoryCopyArray(msg.exception_code_filters, df_state->ctrl_exception_code_filters); + } + df_push_ctrl_msg(&msg); + } + } + + // rjf: no processes -> error + if(processes.count == 0) + { + DF_CmdParams p = params; + p.string = str8_lit("No attached running processes exist; cannot kill."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + }break; + case DF_CoreCmdKind_KillAll: + { + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + if(processes.count != 0) + { + for(DF_EntityNode *n = processes.first; n != 0; n = n->next) + { + DF_Entity *process = n->entity; + CTRL_Msg msg = {CTRL_MsgKind_Kill}; + { + msg.exit_code = 1; + msg.machine_id = process->ctrl_machine_id; + msg.entity = process->ctrl_handle; + MemoryCopyArray(msg.exception_code_filters, df_state->ctrl_exception_code_filters); + } + df_push_ctrl_msg(&msg); + } + } + if(processes.count == 0) + { + DF_CmdParams p = params; + p.string = str8_lit("No attached running processes exist; cannot kill."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + }break; + case DF_CoreCmdKind_Detach: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + if(entity->kind == DF_EntityKind_Process) + { + CTRL_Msg msg = {CTRL_MsgKind_Detach}; + msg.machine_id = entity->ctrl_machine_id; + msg.entity = entity->ctrl_handle; + MemoryCopyArray(msg.exception_code_filters, df_state->ctrl_exception_code_filters); + df_push_ctrl_msg(&msg); + } + }break; + case DF_CoreCmdKind_Continue: + { + B32 good_to_run = 0; + DF_EntityList machines = df_query_cached_entity_list_with_kind(DF_EntityKind_Machine); + for(DF_EntityNode *n = machines.first; n != 0; n = n->next) + { + DF_Entity *machine = n->entity; + if(!df_entity_is_frozen(machine)) + { + good_to_run = 1; + break; + } + } + if(good_to_run) + { + df_ctrl_run(DF_RunKind_Run, &df_g_nil_entity, 0); + } + else + { + DF_CmdParams p = params; + p.string = str8_lit("Cannot run with all threads frozen."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + }break; + case DF_CoreCmdKind_StepIntoInst: + case DF_CoreCmdKind_StepOverInst: + case DF_CoreCmdKind_StepIntoLine: + case DF_CoreCmdKind_StepOverLine: + case DF_CoreCmdKind_StepOut: + case DF_CoreCmdKind_RunToAddress: + { + DF_Entity *thread = df_entity_from_handle(params.entity); + if(df_ctrl_targets_running()) + { + if(df_ctrl_last_run_kind() == DF_RunKind_Run) + { + DF_CmdParams p = params; + p.string = str8_lit("Must halt before stepping."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + } + else if(df_entity_is_frozen(thread)) + { + DF_CmdParams p = params; + p.string = str8_lit("Must thaw selected thread before stepping."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + else + { + B32 good = 1; + CTRL_TrapList traps = {0}; + switch(core_cmd_kind) + { + default: break; + case DF_CoreCmdKind_StepIntoInst: {}break; + case DF_CoreCmdKind_StepOverInst: {traps = df_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break; + case DF_CoreCmdKind_StepIntoLine: {traps = df_trap_net_from_thread__step_into_line(scratch.arena, thread);}break; + case DF_CoreCmdKind_StepOverLine: {traps = df_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; + case DF_CoreCmdKind_StepOut: + { + // rjf: thread => full unwind + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + + // rjf: use first unwind frame to generate trap + if(unwind.first != 0 && unwind.first->next != 0) + { + U64 vaddr = unwind.first->next->rip; + CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr}; + ctrl_trap_list_push(scratch.arena, &traps, &trap); + } + else + { + DF_CmdParams p = params; + p.string = str8_lit("Could not find the return address of the current callstack frame successfully."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + good = 0; + } + }break; + case DF_CoreCmdKind_RunToAddress: + { + CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, params.vaddr}; + ctrl_trap_list_push(scratch.arena, &traps, &trap); + }break; + } + if(good && traps.count != 0) + { + df_ctrl_run(DF_RunKind_Step, thread, &traps); + } + if(good && traps.count == 0) + { + df_ctrl_run(DF_RunKind_SingleStep, thread, &traps); + } + } + }break; + case DF_CoreCmdKind_RunToModuleOffset: + { + DF_Entity *thread = df_entity_from_handle(params.entity); + DF_Entity *module = df_module_from_thread(thread); + U64 voff = params.voff; + U64 vaddr = df_vaddr_from_voff(module, voff); + DF_CmdParams params = df_cmd_params_zero(); + params.vaddr = vaddr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunToAddress)); + }break; + case DF_CoreCmdKind_Halt: + if(df_ctrl_targets_running()) + { + ctrl_halt(); + }break; + case DF_CoreCmdKind_SoftHaltRefresh: + { + if(df_ctrl_targets_running()) + { + df_ctrl_run(df_state->ctrl_last_run_kind, df_entity_from_handle(df_state->ctrl_last_run_thread), &df_state->ctrl_last_run_traps); + } + }break; + case DF_CoreCmdKind_SetThreadIP: + { + DF_Entity *thread = df_entity_from_handle(params.entity); + U64 vaddr = params.vaddr; + if(thread->kind == DF_EntityKind_Thread && vaddr != 0) + { + df_set_thread_rip(thread, vaddr); + } + }break; + + //- rjf: high-level composite target control operations + case DF_CoreCmdKind_Run: + { + DF_CmdParams params = df_cmd_params_zero(); + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + if(processes.count != 0) + { + DF_CmdParams params = df_cmd_params_zero(); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Continue)); + } + else + { + DF_CmdParams params = df_cmd_params_zero(); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); + } + }break; + case DF_CoreCmdKind_Restart: + { + // rjf: kill all + { + DF_CmdParams params = df_cmd_params_zero(); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_KillAll)); + } + + // rjf: gather targets corresponding to all launched processes + DF_EntityList targets = {0}; + { + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + for(DF_EntityNode *n = processes.first; n != 0; n = n->next) + { + DF_Entity *process = n->entity; + DF_Entity *target = df_entity_from_handle(process->entity_handle); + if(!df_entity_is_nil(target)) + { + df_entity_list_push(scratch.arena, &targets, target); + } + } + } + + // rjf: re-launch targets + { + DF_CmdParams params = df_cmd_params_zero(); + params.entity_list = df_handle_list_from_entity_list(scratch.arena, targets); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_EntityList); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); + } + }break; + case DF_CoreCmdKind_StepInto: + case DF_CoreCmdKind_StepOver: + { + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + if(processes.count != 0) + { + DF_CoreCmdKind step_cmd_kind = (core_cmd_kind == DF_CoreCmdKind_StepInto + ? DF_CoreCmdKind_StepIntoLine + : DF_CoreCmdKind_StepOverLine); + B32 prefer_dasm = params.prefer_dasm; + if(prefer_dasm) + { + step_cmd_kind = (core_cmd_kind == DF_CoreCmdKind_StepInto + ? DF_CoreCmdKind_StepIntoInst + : DF_CoreCmdKind_StepOverInst); + } + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(step_cmd_kind)); + } + else + { + DF_EntityList targets = df_push_active_target_list(scratch.arena); + DF_CmdParams p = params; + p.entity_list = df_handle_list_from_entity_list(scratch.arena, targets); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_EntityList); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndInit)); + } + }break; + + //- rjf: solo-stepping mode + case DF_CoreCmdKind_EnableSoloSteppingMode: + { + df_state->ctrl_solo_stepping_mode = 1; + }break; + case DF_CoreCmdKind_DisableSoloSteppingMode: + { + df_state->ctrl_solo_stepping_mode = 0; + }break; + + //- rjf: debug control context management operations + case DF_CoreCmdKind_SelectThread: + { + df_state->ctrl_ctx.thread = params.entity; + df_state->ctrl_ctx.unwind_count = 0; + }break; + case DF_CoreCmdKind_SelectUnwind: + { + DF_Entity *thread = df_entity_from_handle(df_state->ctrl_ctx.thread); + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + U64 max_unwind = unwind.count ? unwind.count-1 : 0; + U64 index = Clamp(0, params.index, max_unwind); + df_state->ctrl_ctx.unwind_count = index; + }break; + case DF_CoreCmdKind_UpOneFrame: + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx(); + DF_CmdParams p = params; + p.index = (ctrl_ctx.unwind_count > 0 ? ctrl_ctx.unwind_count - 1 : 0); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Index); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind)); + }break; + case DF_CoreCmdKind_DownOneFrame: + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx(); + DF_CmdParams p = params; + p.index = ctrl_ctx.unwind_count+1; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Index); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind)); + }break; + case DF_CoreCmdKind_FreezeThread: + case DF_CoreCmdKind_ThawThread: + case DF_CoreCmdKind_FreezeProcess: + case DF_CoreCmdKind_ThawProcess: + case DF_CoreCmdKind_FreezeMachine: + case DF_CoreCmdKind_ThawMachine: + { + DF_CoreCmdKind disptch_kind = ((core_cmd_kind == DF_CoreCmdKind_FreezeThread || + core_cmd_kind == DF_CoreCmdKind_FreezeProcess || + core_cmd_kind == DF_CoreCmdKind_FreezeMachine) + ? DF_CoreCmdKind_FreezeEntity + : DF_CoreCmdKind_ThawEntity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(disptch_kind)); + }break; + case DF_CoreCmdKind_FreezeLocalMachine: + { + CTRL_MachineID machine_id = CTRL_MachineID_Client; + DF_CmdParams params = df_cmd_params_zero(); + params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id)); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FreezeMachine)); + }break; + case DF_CoreCmdKind_ThawLocalMachine: + { + CTRL_MachineID machine_id = CTRL_MachineID_Client; + DF_CmdParams params = df_cmd_params_zero(); + params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id)); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ThawMachine)); + }break; + + //- rjf: undo/redo + case DF_CoreCmdKind_Undo: + { + df_state_delta_history_wind(df_state->hist, Side_Min); + }break; + case DF_CoreCmdKind_Redo: + { + df_state_delta_history_wind(df_state->hist, Side_Max); + }break; + + //- rjf: files + case DF_CoreCmdKind_SetCurrentPath: + { + arena_clear(df_state->current_path_arena); + df_state->current_path = push_str8_copy(df_state->current_path_arena, params.file_path); + }break; + case DF_CoreCmdKind_Open: + { + String8 path = path_normalized_from_string(scratch.arena, params.file_path); + if(path.size == 0) + { + DF_CmdParams p = params; + p.string = str8_lit("File name not specified."); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + else + { + DF_Entity *loaded_file = df_entity_from_path(path, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + if(loaded_file->flags & DF_EntityFlag_IsMissing) + { + DF_CmdParams p = params; + p.string = push_str8f(scratch.arena, "Could not load \"%S\".", path); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + } + }break; + case DF_CoreCmdKind_Reload: + { + DF_Entity *file = df_entity_from_handle(params.entity); + if(file->kind == DF_EntityKind_File) + { + TXTI_Handle txti_handle = df_txti_handle_from_entity(file); + txti_reload(txti_handle, df_full_path_from_entity(scratch.arena, file)); + } + }break; + + //- rjf: config path saving/loading/applying + case DF_CoreCmdKind_LoadUser: + case DF_CoreCmdKind_LoadProfile: + { + String8 new_path = params.file_path; + B32 load_cfg[DF_CfgSrc_COUNT] = {0}; + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + load_cfg[src] = (core_cmd_kind == df_g_cfg_src_load_cmd_kind_table[src]); + } + + //- rjf: set new config paths + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + if(load_cfg[src]) + { + arena_clear(df_state->cfg_path_arenas[src]); + df_state->cfg_paths[src] = path_normalized_from_string(df_state->cfg_path_arenas[src], params.file_path); + } + } + + //- rjf: get config files + DF_Entity *cfg_files[DF_CfgSrc_COUNT] = {0}; + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + String8 path = df_cfg_path_from_src(src); + cfg_files[src] = df_entity_from_path(path, DF_EntityFromPathFlag_OpenMissing|DF_EntityFromPathFlag_OpenAsNeeded); + } + + //- rjf: load files + String8 cfg_data[DF_CfgSrc_COUNT] = {0}; + U64 cfg_timestamps[DF_CfgSrc_COUNT] = {0}; + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + DF_Entity *file_entity = cfg_files[src]; + String8 path = df_full_path_from_entity(scratch.arena, file_entity); + OS_Handle file = os_file_open(OS_AccessFlag_Shared|OS_AccessFlag_Read, path); + FileProperties props = os_properties_from_file(file); + String8 data = os_string_from_file_range(scratch.arena, file, r1u64(0, props.size)); + if(data.size != 0) + { + cfg_data[src] = data; + cfg_timestamps[src] = props.modified; + } + os_file_close(file); + } + + //- rjf: determine if we need to save config + B32 cfg_save[DF_CfgSrc_COUNT] = {0}; + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + cfg_save[src] = (load_cfg[src] && cfg_files[src]->flags & DF_EntityFlag_IsMissing); + } + + //- rjf: determine if we need to reload config + B32 cfg_load[DF_CfgSrc_COUNT] = {0}; + B32 cfg_load_any = 0; + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + cfg_load[src] = (load_cfg[src] && ((cfg_save[src] == 0 && df_state->cfg_cached_timestamp[src] != cfg_timestamps[src]) || cfg_files[src]->timestamp == 0)); + cfg_load_any = cfg_load_any || cfg_load[src]; + } + + //- rjf: load => build new config table + if(cfg_load_any) + { + arena_clear(df_state->cfg_arena); + MemoryZeroStruct(&df_state->cfg_table); + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + df_cfg_table_push_unparsed_string(df_state->cfg_arena, &df_state->cfg_table, cfg_data[src], src); + } + } + + //- rjf: load => dispatch apply + // + // NOTE(rjf): must happen before `save`. we need to create a default before saving, which + // occurs in the 'apply' path. + // + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + if(cfg_load[src]) + { + DF_CoreCmdKind cmd_kind = df_g_cfg_src_apply_cmd_kind_table[src]; + DF_CmdParams params = df_cmd_params_zero(); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(cmd_kind)); + df_state->cfg_cached_timestamp[src] = cfg_timestamps[src]; + } + } + + //- rjf: save => dispatch write + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + if(cfg_save[src]) + { + DF_CoreCmdKind cmd_kind = df_g_cfg_src_write_cmd_kind_table[src]; + DF_CmdParams params = df_cmd_params_zero(); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(cmd_kind)); + } + } + }break; + + //- rjf: loading/applying stateful config changes + case DF_CoreCmdKind_ApplyUserData: + case DF_CoreCmdKind_ApplyProfileData: + { + DF_CfgTable *table = df_cfg_table(); + + //- rjf: get config source + DF_CfgSrc src = DF_CfgSrc_User; + for(DF_CfgSrc s = (DF_CfgSrc)0; s < DF_CfgSrc_COUNT; s = (DF_CfgSrc)(s+1)) + { + if(core_cmd_kind == df_g_cfg_src_apply_cmd_kind_table[s]) + { + src = s; + break; + } + } + + //- rjf: get paths + String8 cfg_path = df_cfg_path_from_src(src); + String8 cfg_folder = str8_chop_last_slash(cfg_path); + + //- rjf: eliminate all existing entities + { + DF_EntityList targets = df_query_cached_entity_list_with_kind(DF_EntityKind_Target); + for(DF_EntityNode *n = targets.first; n != 0; n = n->next) + { + if(n->entity->cfg_src == src) + { + df_entity_mark_for_deletion(n->entity); + } + } + DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + for(DF_EntityNode *n = bps.first; n != 0; n = n->next) + { + if(n->entity->cfg_src == src) + { + df_entity_mark_for_deletion(n->entity); + } + } + DF_EntityList pins = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin); + for(DF_EntityNode *n = pins.first; n != 0; n = n->next) + { + if(n->entity->cfg_src == src) + { + df_entity_mark_for_deletion(n->entity); + } + } + DF_EntityList links = df_query_cached_entity_list_with_kind(DF_EntityKind_OverrideFileLink); + for(DF_EntityNode *n = links.first; n != 0; n = n->next) + { + if(n->entity->cfg_src == src) + { + df_entity_mark_for_deletion(n->entity); + } + } + } + + //- rjf: apply targets + DF_CfgVal *targets = df_cfg_val_from_string(table, str8_lit("target")); + for(DF_CfgNode *target = targets->first; + target != &df_g_nil_cfg_node; + target = target->next) + { + if(target->source == src) + { + DF_CfgNode *label_cfg = df_cfg_node_child_from_string(target, str8_lit("label"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *exe_cfg = df_cfg_node_child_from_string(target, str8_lit("exe"), StringMatchFlag_CaseInsensitive); + if(exe_cfg == &df_g_nil_cfg_node) + { + exe_cfg = df_cfg_node_child_from_string(target, str8_lit("name"), StringMatchFlag_CaseInsensitive); + } + DF_CfgNode *args_cfg = df_cfg_node_child_from_string(target, str8_lit("arguments"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *wdir_cfg = df_cfg_node_child_from_string(target, str8_lit("working_directory"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *entry_cfg = df_cfg_node_child_from_string(target, str8_lit("entry_point"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *active_cfg = df_cfg_node_child_from_string(target, str8_lit("active"), StringMatchFlag_CaseInsensitive); + Vec4F32 hsva = df_hsva_from_cfg_node(target); + U64 is_active_u64 = 0; + try_u64_from_str8_c_rules(active_cfg->first->string, &is_active_u64); + DF_Entity *target__ent = df_entity_alloc(0, df_entity_root(), DF_EntityKind_Target); + DF_Entity *exe__ent = df_entity_alloc(0, target__ent, DF_EntityKind_Executable); + DF_Entity *args__ent = df_entity_alloc(0, target__ent, DF_EntityKind_Arguments); + DF_Entity *path__ent = df_entity_alloc(0, target__ent, DF_EntityKind_ExecutionPath); + DF_Entity *entry__ent = df_entity_alloc(0, target__ent, DF_EntityKind_EntryPointName); + String8 saved_label = label_cfg->first->string; + String8 saved_exe = exe_cfg->first->string; + String8 saved_exe_absolute = path_absolute_dst_from_relative_dst_src(scratch.arena, saved_exe, cfg_folder); + String8 saved_wdir = wdir_cfg->first->string; + String8 saved_wdir_absolute = path_absolute_dst_from_relative_dst_src(scratch.arena, saved_wdir, cfg_folder); + String8 saved_entry_point = entry_cfg->first->string; + df_entity_equip_b32(target__ent, active_cfg != &df_g_nil_cfg_node ? !!is_active_u64 : 1); + df_entity_equip_name(0, target__ent, saved_label); + df_entity_equip_name(0, exe__ent, saved_exe_absolute); + df_entity_equip_name(0, args__ent, args_cfg->first->string); + df_entity_equip_name(0, path__ent, saved_wdir_absolute); + df_entity_equip_name(0, entry__ent, saved_entry_point); + df_entity_equip_cfg_src(target__ent, src); + if(!memory_is_zero(&hsva, sizeof(hsva))) + { + df_entity_equip_color_hsva(target__ent, hsva); + } + } + } + + //- rjf: apply path maps + DF_CfgVal *path_maps = df_cfg_val_from_string(table, str8_lit("file_path_map")); + for(DF_CfgNode *map = path_maps->first; + map != &df_g_nil_cfg_node; + map = map->next) + { + if(map->source == src) + { + DF_CfgNode *src_cfg = df_cfg_node_child_from_string(map, str8_lit("source_path"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *dst_cfg = df_cfg_node_child_from_string(map, str8_lit("dest_path"), StringMatchFlag_CaseInsensitive); + String8 src_path = src_cfg->first->string; + String8 dst_path = dst_cfg->first->string; + DF_Entity *link_loc_entity = df_entity_from_path(src_path, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + DF_Entity *link_entity = df_entity_alloc(0, link_loc_entity->parent, DF_EntityKind_OverrideFileLink); + DF_Entity *link_dst_entity = df_entity_from_path(dst_path, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + df_entity_equip_name(0, link_entity, str8_skip_last_slash(src_path)); + df_entity_equip_entity_handle(link_entity, df_handle_from_entity(link_dst_entity)); + df_entity_equip_cfg_src(link_entity, src); + } + } + + //- rjf: apply breakpoints + DF_CfgVal *bps = df_cfg_val_from_string(table, str8_lit("breakpoint")); + for(DF_CfgNode *bp = bps->first; + bp != &df_g_nil_cfg_node; + bp = bp->next) + { + if(bp->source != src) + { + continue; + } + + // rjf: get metadata + Vec4F32 hsva = df_hsva_from_cfg_node(bp); + + // rjf: get nodes encoding location info + B32 is_enabled = 1; + DF_CfgNode *line_cfg = &df_g_nil_cfg_node; + DF_CfgNode *addr_cfg = &df_g_nil_cfg_node; + DF_CfgNode *symb_cfg = &df_g_nil_cfg_node; + DF_CfgNode *labl_cfg = &df_g_nil_cfg_node; + for(DF_CfgNode *child = bp->first; child != &df_g_nil_cfg_node; child = child->next) + { + if(child->flags & DF_CfgNodeFlag_Identifier && str8_match(child->string, str8_lit("line"), StringMatchFlag_CaseInsensitive)) + { + line_cfg = child; + } + if(child->flags & DF_CfgNodeFlag_Identifier && str8_match(child->string, str8_lit("addr"), StringMatchFlag_CaseInsensitive)) + { + addr_cfg = child; + } + if(child->flags & DF_CfgNodeFlag_Identifier && str8_match(child->string, str8_lit("symbol"), StringMatchFlag_CaseInsensitive)) + { + symb_cfg = child; + } + else if(child->flags & DF_CfgNodeFlag_Identifier && str8_match(child->string, str8_lit("label"), StringMatchFlag_CaseInsensitive)) + { + labl_cfg = child; + } + else if(child->flags & DF_CfgNodeFlag_Identifier && str8_match(child->string, str8_lit("enabled"), StringMatchFlag_CaseInsensitive)) + { + U64 is_enabled_u64 = 0; + try_u64_from_str8_c_rules(child->first->string, &is_enabled_u64); + is_enabled = (B32)is_enabled_u64; + } + } + + // rjf: extract textual location bp info + DF_Entity *bp_parent_ent = df_entity_root(); + TxtPt pt = {0}; + if(line_cfg != &df_g_nil_cfg_node) + { + DF_CfgNode *file = line_cfg->first; + DF_CfgNode *line = file->first; + U64 line_num = 0; + if(try_u64_from_str8_c_rules(line->string, &line_num)) + { + String8 saved_path = file->string; + String8 saved_path_absolute = path_absolute_dst_from_relative_dst_src(scratch.arena, saved_path, cfg_folder); + bp_parent_ent = df_entity_from_path(saved_path_absolute, DF_EntityFromPathFlag_All); + pt = txt_pt((S64)line_num, 1); + } + } + + // rjf: get condition info + DF_CfgNode *cond_cfg = df_cfg_node_child_from_string(bp, str8_lit("condition"), StringMatchFlag_CaseInsensitive); + + // rjf: build entity + { + DF_Entity *bp_ent = df_entity_alloc(0, bp_parent_ent, DF_EntityKind_Breakpoint); + df_entity_equip_b32(bp_ent, is_enabled); + df_entity_equip_cfg_src(bp_ent, src); + if(pt.line != 0) + { + df_entity_equip_txt_pt(bp_ent, pt); + } + if(addr_cfg != &df_g_nil_cfg_node) + { + U64 u64 = 0; + try_u64_from_str8_c_rules(addr_cfg->first->string, &u64); + df_entity_equip_vaddr(bp_ent, u64); + } + if(symb_cfg != &df_g_nil_cfg_node) + { + DF_Entity *symb = df_entity_alloc(0, bp_ent, DF_EntityKind_EntryPointName); + df_entity_equip_name(0, symb, symb_cfg->first->string); + } + if(labl_cfg->string.size != 0) + { + df_entity_equip_name(0, bp_ent, labl_cfg->first->string); + } + if(!memory_is_zero(&hsva, sizeof(hsva))) + { + df_entity_equip_color_hsva(bp_ent, hsva); + } + if(cond_cfg->string.size != 0) + { + DF_Entity *cond = df_entity_alloc(0, bp_ent, DF_EntityKind_Condition); + df_entity_equip_name(0, cond, cond_cfg->first->string); + } + } + } + + //- rjf: apply watch pins + DF_CfgVal *pins = df_cfg_val_from_string(table, str8_lit("watch_pin")); + for(DF_CfgNode *pin = pins->first; + pin != &df_g_nil_cfg_node; + pin = pin->next) + { + if(pin->source != src) + { + continue; + } + Vec4F32 hsva = df_hsva_from_cfg_node(pin); + String8 string = df_string_from_cfg_node_key(pin, str8_lit("expression"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *line_cfg = df_cfg_node_child_from_string(pin, str8_lit("line"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *addr_cfg = df_cfg_node_child_from_string(pin, str8_lit("addr"), StringMatchFlag_CaseInsensitive); + DF_Entity *pin_parent_ent = df_entity_root(); + TxtPt pt = {0}; + if(line_cfg != &df_g_nil_cfg_node) + { + String8 saved_path = line_cfg->first->string; + String8 line_num_string = line_cfg->first->first->string; + String8 saved_path_absolute = path_absolute_dst_from_relative_dst_src(scratch.arena, saved_path, cfg_folder); + pin_parent_ent = df_entity_from_path(saved_path_absolute, DF_EntityFromPathFlag_All); + U64 line_num = 0; + if(try_u64_from_str8_c_rules(line_num_string, &line_num)) + { + if(line_num != 0) + { + pt = txt_pt((S64)line_num, 1); + } + } + } + U64 vaddr = 0; + if(addr_cfg != &df_g_nil_cfg_node) + { + try_u64_from_str8_c_rules(addr_cfg->first->string, &vaddr); + } + DF_Entity *pin_ent = df_entity_alloc(0, pin_parent_ent, DF_EntityKind_WatchPin); + df_entity_equip_cfg_src(pin_ent, src); + df_entity_equip_name(0, pin_ent, string); + if(!memory_is_zero(&hsva, sizeof(hsva))) + { + df_entity_equip_color_hsva(pin_ent, hsva); + } + if(pt.line != 0) + { + df_entity_equip_txt_pt(pin_ent, pt); + } + if(vaddr != 0) + { + df_entity_equip_vaddr(pin_ent, vaddr); + } + } + + //- rjf: apply exception code filters + DF_CfgVal *filter_tables = df_cfg_val_from_string(table, str8_lit("exception_code_filters")); + for(DF_CfgNode *table = filter_tables->first; + table != &df_g_nil_cfg_node; + table = table->next) + { + for(DF_CfgNode *rule = table->first; + rule != &df_g_nil_cfg_node; + rule = rule->next) + { + String8 name = rule->string; + String8 val_string = rule->first->string; + U64 val = 0; + if(try_u64_from_str8_c_rules(val_string, &val)) + { + CTRL_ExceptionCodeKind kind = CTRL_ExceptionCodeKind_Null; + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)(CTRL_ExceptionCodeKind_Null+1); + k < CTRL_ExceptionCodeKind_COUNT; + k = (CTRL_ExceptionCodeKind)(k+1)) + { + if(str8_match(name, ctrl_exception_code_kind_lowercase_code_string_table[k], 0)) + { + kind = k; + break; + } + } + if(kind != CTRL_ExceptionCodeKind_Null) + { + if(val) + { + df_state->ctrl_exception_code_filters[kind/64] |= (1ull<<(kind%64)); + } + else + { + df_state->ctrl_exception_code_filters[kind/64] &= ~(1ull<<(kind%64)); + } + } + } + } + } + + //- rjf: apply control settings + { + DF_CfgVal *solo_stepping_mode_cfg_val = df_cfg_val_from_string(table, str8_lit("solo_stepping_mode")); + if(solo_stepping_mode_cfg_val != &df_g_nil_cfg_val) + { + DF_CfgNode *value_cfg = solo_stepping_mode_cfg_val->last->first; + U64 val = 0; + try_u64_from_str8_c_rules(value_cfg->string, &val); + df_state->ctrl_solo_stepping_mode = (B32)val; + } + } + + }break; + + //- rjf: writing config changes + case DF_CoreCmdKind_WriteUserData: + case DF_CoreCmdKind_WriteProfileData: + { + DF_CfgSrc src = DF_CfgSrc_User; + for(DF_CfgSrc s = (DF_CfgSrc)0; s < DF_CfgSrc_COUNT; s = (DF_CfgSrc)(s+1)) + { + if(core_cmd_kind == df_g_cfg_src_write_cmd_kind_table[s]) + { + src = s; + break; + } + } + arena_clear(df_state->cfg_write_arenas[src]); + MemoryZeroStruct(&df_state->cfg_write_data[src]); + String8 path = df_cfg_path_from_src(src); + String8List strs = df_cfg_strings_from_core(scratch.arena, path, src); + String8 header = push_str8f(scratch.arena, "// raddbg %s file\n\n", df_g_cfg_src_string_table[src].str); + str8_list_push_front(scratch.arena, &strs, header); + String8 data = str8_list_join(scratch.arena, &strs, 0); + df_state->cfg_write_issued[src] = 1; + df_cfg_push_write_string(src, data); + }break; + + //- rjf: override file links + case DF_CoreCmdKind_SetFileOverrideLinkSrc: + case DF_CoreCmdKind_SetFileOverrideLinkDst: + { + // rjf: unpack args + DF_Entity *map = df_entity_from_handle(params.entity); + String8 path = path_normalized_from_string(scratch.arena, params.file_path); + String8 path_folder = str8_chop_last_slash(path); + String8 path_file = str8_skip_last_slash(path); + + // rjf: src -> move map & commit name; dst -> open destination file & refer to it in map + switch(core_cmd_kind) + { + default:{}break; + case DF_CoreCmdKind_SetFileOverrideLinkSrc: + { + DF_Entity *map_parent = (params.file_path.size != 0) ? df_entity_from_path(path_folder, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing) : df_entity_root(); + if(df_entity_is_nil(map)) + { + map = df_entity_alloc(0, map_parent, DF_EntityKind_OverrideFileLink); + } + else + { + df_entity_change_parent(0, map, map->parent, map_parent); + } + df_entity_equip_name(0, map, path_file); + }break; + case DF_CoreCmdKind_SetFileOverrideLinkDst: + { + if(df_entity_is_nil(map)) + { + map = df_entity_alloc(0, df_entity_root(), DF_EntityKind_OverrideFileLink); + } + DF_Entity *map_dst_entity = &df_g_nil_entity; + if(params.file_path.size != 0) + { + map_dst_entity = df_entity_from_path(path, DF_EntityFromPathFlag_All); + } + df_entity_equip_entity_handle(map, df_handle_from_entity(map_dst_entity)); + }break; + } + + // rjf: empty src/dest -> delete + if(!df_entity_is_nil(map) && map->name.size == 0 && df_entity_is_nil(df_entity_from_handle(map->entity_handle))) + { + df_entity_mark_for_deletion(map); + } + }break; + case DF_CoreCmdKind_SetFileReplacementPath: + { + DF_Entity *file = df_entity_from_handle(params.entity); + DF_Entity *replacement = df_entity_from_path(params.file_path, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + if(!df_entity_is_nil(file) && !df_entity_is_nil(replacement)) + { + DF_Entity *link = df_entity_child_from_name_and_kind(file->parent, file->name, DF_EntityKind_OverrideFileLink); + if(df_entity_is_nil(link)) + { + link = df_entity_alloc(0, file->parent, DF_EntityKind_OverrideFileLink); + df_entity_equip_name(0, link, file->name); + } + df_entity_equip_entity_handle(link, df_handle_from_entity(replacement)); + } + }break; + + //- rjf: general entity operations + case DF_CoreCmdKind_EnableEntity: + case DF_CoreCmdKind_EnableBreakpoint: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + df_state_delta_history_push_batch(df_state->hist, &entity->generation); + df_state_delta_history_push_struct_delta(df_state->hist, &entity->b32); + df_entity_equip_b32(entity, 1); + }break; + case DF_CoreCmdKind_DisableEntity: + case DF_CoreCmdKind_DisableBreakpoint: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + df_state_delta_history_push_batch(df_state->hist, &entity->generation); + df_state_delta_history_push_struct_delta(df_state->hist, &entity->b32); + df_entity_equip_b32(entity, 0); + }break; + case DF_CoreCmdKind_FreezeEntity: + case DF_CoreCmdKind_ThawEntity: + { + B32 should_freeze = (core_cmd_kind == DF_CoreCmdKind_FreezeEntity); + DF_Entity *root = df_entity_from_handle(params.entity); + for(DF_Entity *e = root; !df_entity_is_nil(e); e = df_entity_rec_df_pre(e, root).next) + { + if(e->kind == DF_EntityKind_Thread) + { + df_set_thread_freeze_state(e, should_freeze); + } + } + }break; + case DF_CoreCmdKind_RemoveEntity: + case DF_CoreCmdKind_RemoveBreakpoint: + case DF_CoreCmdKind_RemoveTarget: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + DF_EntityOpFlags op_flags = df_g_entity_kind_op_flags_table[entity->kind]; + if(op_flags & DF_EntityOpFlag_Delete) + { + df_entity_mark_for_deletion(entity); + } + }break; + case DF_CoreCmdKind_NameEntity: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + String8 string = params.string; + df_state_delta_history_push_batch(df_state_delta_history(), &entity->generation); + df_entity_equip_name(df_state_delta_history(), entity, string); + }break; + case DF_CoreCmdKind_EditEntity:{}break; + case DF_CoreCmdKind_DuplicateEntity: + { + DF_Entity *src = df_entity_from_handle(params.entity); + if(!df_entity_is_nil(src)) + { + typedef struct Task Task; + struct Task + { + Task *next; + DF_Entity *src_n; + DF_Entity *dst_parent; + }; + Task starter_task = {0, src, src->parent}; + Task *first_task = &starter_task; + Task *last_task = &starter_task; + df_state_delta_history_push_batch(df_state_delta_history(), 0); + for(Task *task = first_task; task != 0; task = task->next) + { + DF_Entity *src_n = task->src_n; + DF_Entity *dst_n = df_entity_alloc(df_state_delta_history(), task->dst_parent, task->src_n->kind); + if(src_n->flags & DF_EntityFlag_HasTextPoint) {df_entity_equip_txt_pt(dst_n, src_n->text_point);} + if(src_n->flags & DF_EntityFlag_HasTextPointAlt) {df_entity_equip_txt_pt_alt(dst_n, src_n->text_point_alt);} + if(src_n->flags & DF_EntityFlag_HasB32) {df_entity_equip_b32(dst_n, src_n->b32);} + if(src_n->flags & DF_EntityFlag_HasU64) {df_entity_equip_u64(dst_n, src_n->u64);} + if(src_n->flags & DF_EntityFlag_HasRng1U64) {df_entity_equip_rng1u64(dst_n, src_n->rng1u64);} + if(src_n->flags & DF_EntityFlag_HasColor) {df_entity_equip_color_hsva(dst_n, df_hsva_from_entity(src_n));} + if(src_n->flags & DF_EntityFlag_HasVAddrRng) {df_entity_equip_vaddr_rng(dst_n, src_n->vaddr_rng);} + if(src_n->flags & DF_EntityFlag_HasVAddr) {df_entity_equip_vaddr(dst_n, src_n->vaddr);} + if(src_n->name.size != 0) {df_entity_equip_name(df_state_delta_history(), dst_n, src_n->name);} + dst_n->cfg_src = src_n->cfg_src; + for(DF_Entity *src_child = task->src_n->first; !df_entity_is_nil(src_child); src_child = src_child->next) + { + Task *child_task = push_array(scratch.arena, Task, 1); + child_task->src_n = src_child; + child_task->dst_parent = dst_n; + SLLQueuePush(first_task, last_task, child_task); + } + } + } + }break; + + //- rjf: breakpoints + case DF_CoreCmdKind_TextBreakpoint: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + if(!df_entity_is_nil(entity)) + { + S64 line_num = params.text_point.line; + B32 removed_existing = 0; + for(DF_Entity *child = entity->first, *next = 0; !df_entity_is_nil(child); child = next) + { + next = child->next; + if(child->deleted) { continue; } + if(child->kind == DF_EntityKind_Breakpoint && child->flags & DF_EntityFlag_HasTextPoint && child->text_point.line == line_num) + { + removed_existing = 1; + df_entity_mark_for_deletion(child); + } + } + if(removed_existing == 0) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + DF_Entity *bp = df_entity_alloc(df_state_delta_history(), entity, DF_EntityKind_Breakpoint); + df_entity_equip_txt_pt(bp, params.text_point); + df_entity_equip_b32(bp, 1); + df_entity_equip_cfg_src(bp, DF_CfgSrc_Profile); + } + } + }break; + case DF_CoreCmdKind_AddressBreakpoint: + { + U64 vaddr = params.vaddr; + if(vaddr != 0) + { + DF_Entity *bp = &df_g_nil_entity; + DF_EntityList existing_bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + for(DF_EntityNode *n = existing_bps.first; n != 0; n = n->next) + { + if(n->entity->vaddr == vaddr) + { + bp = n->entity; + break; + } + } + if(df_entity_is_nil(bp)) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + bp = df_entity_alloc(df_state_delta_history(), df_entity_root(), DF_EntityKind_Breakpoint); + df_entity_equip_vaddr(bp, vaddr); + df_entity_equip_b32(bp, 1); + df_entity_equip_cfg_src(bp, DF_CfgSrc_Profile); + } + else + { + df_entity_mark_for_deletion(bp); + } + } + }break; + case DF_CoreCmdKind_FunctionBreakpoint: + { + String8 function_name = params.string; + if(function_name.size != 0) + { + DF_Entity *symb = df_entity_from_name_and_kind(function_name, DF_EntityKind_EntryPointName); + DF_Entity *bp = df_entity_ancestor_from_kind(symb, DF_EntityKind_Breakpoint); + if(df_entity_is_nil(bp)) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + bp = df_entity_alloc(df_state_delta_history(), df_entity_root(), DF_EntityKind_Breakpoint); + DF_Entity *symbol_name_entity = df_entity_alloc(df_state_delta_history(), bp, DF_EntityKind_EntryPointName); + df_entity_equip_name(df_state_delta_history(), symbol_name_entity, function_name); + df_entity_equip_b32(bp, 1); + df_entity_equip_cfg_src(bp, DF_CfgSrc_Profile); + } + else + { + df_entity_mark_for_deletion(bp); + } + } + }break; + + //- rjf: watches + case DF_CoreCmdKind_ToggleWatchPin: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + S64 line_num = params.text_point.line; + if(!df_entity_is_nil(entity) && line_num != 0) + { + B32 removed_existing = 0; + for(DF_Entity *child = entity->first, *next = 0; !df_entity_is_nil(child); child = next) + { + next = child->next; + if(child->deleted) { continue; } + if(child->kind == DF_EntityKind_WatchPin && child->flags & DF_EntityFlag_HasTextPoint && child->text_point.line == line_num && + str8_match(child->name, params.string, 0)) + { + removed_existing = 1; + df_entity_mark_for_deletion(child); + } + } + if(removed_existing == 0) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + DF_Entity *watch = df_entity_alloc(df_state_delta_history(), entity, DF_EntityKind_WatchPin); + df_entity_equip_txt_pt(watch, params.text_point); + df_entity_equip_name(df_state_delta_history(), watch, params.string); + df_entity_equip_cfg_src(watch, DF_CfgSrc_Profile); + } + } + else if(params.vaddr != 0) + { + B32 removed_existing = 0; + DF_EntityList pins = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin); + for(DF_EntityNode *n = pins.first; n != 0; n = n->next) + { + DF_Entity *pin = n->entity; + if(pin->flags & DF_EntityFlag_HasVAddr && pin->vaddr == params.vaddr && str8_match(pin->name, params.string, 0)) + { + removed_existing = 1; + df_entity_mark_for_deletion(pin); + } + } + if(!removed_existing) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + DF_Entity *pin = df_entity_alloc(df_state_delta_history(), df_entity_root(), DF_EntityKind_WatchPin); + df_entity_equip_vaddr(pin, params.vaddr); + df_entity_equip_name(df_state_delta_history(), pin, params.string); + df_entity_equip_cfg_src(pin, DF_CfgSrc_Profile); + } + } + }break; + + //- rjf: targets + case DF_CoreCmdKind_AddTarget: + { + // rjf: build target + df_state_delta_history_push_batch(df_state_delta_history(), 0); + DF_Entity *entity = df_entity_alloc(df_state_delta_history(), df_entity_root(), DF_EntityKind_Target); + df_entity_equip_b32(entity, 1); + df_entity_equip_cfg_src(entity, DF_CfgSrc_Profile); + DF_Entity *exe = df_entity_alloc(df_state_delta_history(), entity, DF_EntityKind_Executable); + df_entity_equip_name(df_state_delta_history(), exe, params.file_path); + String8 working_dir = str8_chop_last_slash(params.file_path); + if(working_dir.size != 0) + { + String8 working_dir_path = push_str8f(scratch.arena, "%S/", working_dir); + DF_Entity *execution_path = df_entity_alloc(df_state_delta_history(), entity, DF_EntityKind_ExecutionPath); + df_entity_equip_name(df_state_delta_history(), execution_path, working_dir_path); + } + DF_CmdParams p = params; + p.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EditTarget)); + }break; + + //- rjf: ended processes + case DF_CoreCmdKind_RetryEndedProcess: + { + DF_Entity *ended_process = df_entity_from_handle(params.entity); + DF_Entity *target = df_entity_from_handle(ended_process->entity_handle); + if(target->kind == DF_EntityKind_Target) + { + DF_CmdParams p = params; + p.entity = df_handle_from_entity(target); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); + } + else if(df_entity_is_nil(target)) + { + DF_CmdParams p = params; + p.string = str8_lit("The ended process' corresponding target is missing."); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + else if(df_entity_is_nil(ended_process)) + { + DF_CmdParams p = params; + p.string = str8_lit("Invalid ended process."); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + }break; + + //- rjf: attaching + case DF_CoreCmdKind_Attach: + { + U64 pid = params.id; + if(pid != 0) + { + CTRL_Msg msg = {CTRL_MsgKind_Attach}; + msg.entity_id = (U32)pid; + MemoryCopyArray(msg.exception_code_filters, df_state->ctrl_exception_code_filters); + df_push_ctrl_msg(&msg); + } + }break; + + //- rjf: jit-debugger registration + case DF_CoreCmdKind_RegisterAsJITDebugger: + { +#if OS_WINDOWS + String8 path_to_debugger_binary = os_get_command_line_arguments().first->string; + String8 name8 = str8_lit("Debugger"); + String8 data8 = push_str8f(scratch.arena, "%S --jit_pid:%%ld --jit_code:%%ld --jit_addr:0x%%p", path_to_debugger_binary); + String16 name16 = str16_from_8(scratch.arena, name8); + String16 data16 = str16_from_8(scratch.arena, data8); + B32 likely_not_in_admin_mode = 0; + { + HKEY reg_key = 0; + LSTATUS status = 0; + status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\", 0, KEY_SET_VALUE, ®_key); + likely_not_in_admin_mode = (status == ERROR_ACCESS_DENIED); + status = RegSetValueExW(reg_key, (LPCWSTR)name16.str, 0, REG_SZ, (BYTE *)data16.str, data16.size*sizeof(U16)+2); + RegCloseKey(reg_key); + } + { + HKEY reg_key = 0; + LSTATUS status = 0; + status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\", 0, KEY_SET_VALUE, ®_key); + likely_not_in_admin_mode = (status == ERROR_ACCESS_DENIED); + status = RegSetValueExW(reg_key, (LPCWSTR)name16.str, 0, REG_SZ, (BYTE *)data16.str, data16.size*sizeof(U16)+2); + RegCloseKey(reg_key); + } + if(likely_not_in_admin_mode) + { + DF_CmdParams p = params; + p.string = str8_lit("Could not register as the just-in-time debugger, access was denied; try running the debugger as administrator."); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } +#else + DF_CmdParams p = params; + p.string = str8_lit("Registering as the just-in-time debugger is currently not supported on this system."); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); +#endif + }break; + } + } + scratch_end(scratch); + } + ProfEnd(); +} + +internal void +df_core_end_frame(void) +{ + ProfBeginFunction(); + + //- rjf: entity mutation -> soft halt + if(df_state->entities_mut_soft_halt) + { + df_state->entities_mut_soft_halt = 0; + DF_CmdParams params = df_cmd_params_zero(); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SoftHaltRefresh)); + } + + //- rjf: entity mutation -> send refreshed debug info map + if(df_state->entities_mut_dbg_info_map) ProfScope("entity mutation -> send refreshed debug info map") + { + df_state->entities_mut_dbg_info_map = 0; + // TODO(rjf) + } + + //- rjf: send messages + if(df_state->ctrl_msgs.count != 0) + { + if(ctrl_u2c_push_msgs(&df_state->ctrl_msgs, os_now_microseconds()+100)) + { + MemoryZeroStruct(&df_state->ctrl_msgs); + arena_clear(df_state->ctrl_msg_arena); + } + } + + //- rjf: eliminate entities that are marked for deletion + kill off entities with a death-timer + ProfScope("eliminate deleted/deletion-timer entities") + { + for(DF_Entity *entity = df_entity_root(), *next = 0; !df_entity_is_nil(entity); entity = next) + { + next = df_entity_rec_df_pre(entity, &df_g_nil_entity).next; + if(entity->flags & DF_EntityFlag_DiesWithTime) + { + entity->life_left -= df_dt(); + if(entity->life_left <= 0.f) + { + df_entity_mark_for_deletion(entity); + } + } + if(entity->flags & DF_EntityFlag_MarkedForDeletion) + { + B32 undoable = (df_g_entity_kind_flags_table[entity->kind] & DF_EntityKindFlag_UserDefinedLifetime); + + // rjf: fixup next entity to iterate to + next = df_entity_rec_df(entity, &df_g_nil_entity, OffsetOf(DF_Entity, next), OffsetOf(DF_Entity, next)).next; + + // rjf: undoable -> just mark as deleted; this must be able to be trivially undone + if(undoable) + { + df_state_delta_history_push_batch(df_state->hist, 0); + df_state_delta_history_push_struct_delta(df_state->hist, &entity->deleted); + df_state_delta_history_push_struct_delta(df_state->hist, &entity->generation); + df_state_delta_history_push_struct_delta(df_state->hist, &df_state->kind_alloc_gens[entity->kind]); + entity->deleted = 1; + entity->generation += 1; + entity->flags &= ~DF_EntityFlag_MarkedForDeletion; + df_state->kind_alloc_gens[entity->kind] += 1; + } + + // rjf: not undoable -> actually release + if(!undoable) + { + // rjf: eliminate root entity if we're freeing it + if(entity == df_state->entities_root) + { + df_state->entities_root = &df_g_nil_entity; + } + + // rjf: unhook & release this entity tree + df_entity_change_parent(0, entity, entity->parent, &df_g_nil_entity); + df_entity_release(0, entity); + } + } + } + } + + //- rjf: write config changes + ProfScope("write config changes") + { + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) ProfScope("write %.*s config data", str8_varg(df_g_cfg_src_string_table[src])) + { + if(df_state->cfg_write_issued[src]) + { + df_state->cfg_write_issued[src] = 0; + String8 path = df_cfg_path_from_src(src); + os_write_data_list_to_file_path(path, df_state->cfg_write_data[src]); + } + arena_clear(df_state->cfg_write_arenas[src]); + MemoryZeroStruct(&df_state->cfg_write_data[src]); + } + } + + ProfEnd(); +} diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h new file mode 100644 index 00000000..b9a0bf85 --- /dev/null +++ b/src/df/core/df_core.h @@ -0,0 +1,1668 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DF_CORE_H +#define DF_CORE_H + +//////////////////////////////// +//~ rjf: Handles + +typedef struct DF_Handle DF_Handle; +struct DF_Handle +{ + U64 u64[2]; +}; + +typedef struct DF_HandleNode DF_HandleNode; +struct DF_HandleNode +{ + DF_HandleNode *next; + DF_HandleNode *prev; + DF_Handle handle; +}; + +typedef struct DF_HandleList DF_HandleList; +struct DF_HandleList +{ + DF_HandleNode *first; + DF_HandleNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Sparse Tree Expansion State Data Structure + +typedef struct DF_ExpandKey DF_ExpandKey; +struct DF_ExpandKey +{ + U64 uniquifier; + U64 parent_hash; + U64 child_num; +}; + +typedef struct DF_ExpandNode DF_ExpandNode; +struct DF_ExpandNode +{ + DF_ExpandNode *hash_next; + DF_ExpandNode *hash_prev; + DF_ExpandNode *first; + DF_ExpandNode *last; + DF_ExpandNode *next; + DF_ExpandNode *prev; + DF_ExpandNode *parent; + DF_ExpandKey key; + B32 expanded; + F32 expanded_t; +}; + +typedef struct DF_ExpandSlot DF_ExpandSlot; +struct DF_ExpandSlot +{ + DF_ExpandNode *first; + DF_ExpandNode *last; +}; + +typedef struct DF_ExpandTreeTable DF_ExpandTreeTable; +struct DF_ExpandTreeTable +{ + DF_ExpandSlot *slots; + U64 slots_count; + DF_ExpandNode *free_node; +}; + +//////////////////////////////// +//~ rjf: Fuzzy Matching + +typedef struct DF_FuzzyMatchRangeNode DF_FuzzyMatchRangeNode; +struct DF_FuzzyMatchRangeNode +{ + DF_FuzzyMatchRangeNode *next; + Rng1U64 range; +}; + +typedef struct DF_FuzzyMatchRangeList DF_FuzzyMatchRangeList; +struct DF_FuzzyMatchRangeList +{ + DF_FuzzyMatchRangeNode *first; + DF_FuzzyMatchRangeNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Control Context Types + +typedef struct DF_CtrlCtx DF_CtrlCtx; +struct DF_CtrlCtx +{ + DF_Handle thread; + U64 unwind_count; +}; + +//////////////////////////////// +//~ rjf: Entity Kind Flags + +typedef U32 DF_EntityKindFlags; +enum +{ + DF_EntityKindFlag_LeafMutationUserConfig = (1<<0), + DF_EntityKindFlag_TreeMutationUserConfig = (1<<1), + DF_EntityKindFlag_LeafMutationProfileConfig= (1<<2), + DF_EntityKindFlag_TreeMutationProfileConfig= (1<<3), + DF_EntityKindFlag_LeafMutationSoftHalt = (1<<4), + DF_EntityKindFlag_TreeMutationSoftHalt = (1<<5), + DF_EntityKindFlag_LeafMutationDebugInfoMap = (1<<6), + DF_EntityKindFlag_TreeMutationDebugInfoMap = (1<<7), + DF_EntityKindFlag_NameIsCode = (1<<8), + DF_EntityKindFlag_UserDefinedLifetime = (1<<9), +}; + +//////////////////////////////// +//~ rjf: Entity Operation Flags + +typedef U32 DF_EntityOpFlags; +enum +{ + DF_EntityOpFlag_Delete = (1<<0), + DF_EntityOpFlag_Freeze = (1<<1), + DF_EntityOpFlag_Edit = (1<<2), + DF_EntityOpFlag_Rename = (1<<3), + DF_EntityOpFlag_Enable = (1<<4), + DF_EntityOpFlag_Condition = (1<<5), + DF_EntityOpFlag_Duplicate = (1<<6), +}; + +//////////////////////////////// +//~ rjf: Entity Filesystem Lookup Flags + +typedef U32 DF_EntityFromPathFlags; +enum +{ + DF_EntityFromPathFlag_AllowOverrides = (1<<0), + DF_EntityFromPathFlag_OpenAsNeeded = (1<<1), + DF_EntityFromPathFlag_OpenMissing = (1<<2), + + DF_EntityFromPathFlag_All = 0xffffffff, +}; + +//////////////////////////////// +//~ rjf: Debug Engine Control Communication Types + +typedef enum DF_RunKind +{ + DF_RunKind_Run, + DF_RunKind_SingleStep, + DF_RunKind_Step, + DF_RunKind_COUNT +} +DF_RunKind; + +//////////////////////////////// +//~ rjf: Disassembly Types + +typedef U32 DF_InstFlags; +enum +{ + DF_InstFlag_Call = (1<<0), + DF_InstFlag_Branch = (1<<1), + DF_InstFlag_UnconditionalJump = (1<<2), + DF_InstFlag_Return = (1<<3), + DF_InstFlag_NonFlow = (1<<4), + DF_InstFlag_Repeats = (1<<5), + DF_InstFlag_ChangesStackPointer = (1<<6), + DF_InstFlag_ChangesStackPointerVariably = (1<<7), +}; + +typedef struct DF_Inst DF_Inst; +struct DF_Inst +{ + DF_InstFlags flags; + U64 size; + String8 string; + U64 rel_voff; + S64 sp_delta; +}; + +typedef struct DF_InstNode DF_InstNode; +struct DF_InstNode +{ + DF_InstNode *next; + DF_Inst inst; +}; + +typedef struct DF_InstList DF_InstList; +struct DF_InstList +{ + DF_InstNode *first; + DF_InstNode *last; + U64 count; +}; + +typedef struct DF_InstArray DF_InstArray; +struct DF_InstArray +{ + DF_InstArray *v; + U64 count; +}; + +typedef struct DF_InstMemVOffTuple DF_InstMemVOffTuple; +struct DF_InstMemVOffTuple +{ + DF_Inst inst; + String8 mem; + U64 voff; +}; + +typedef struct DF_InstMemVOffTupleArray DF_InstMemVOffTupleArray; +struct DF_InstMemVOffTupleArray +{ + DF_InstMemVOffTuple *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Control Flow Analysis Types + +typedef U32 DF_CtrlFlowFlags; +enum +{ + DF_CtrlFlowFlag_StackPointerChangesVariably = (1<<0), +}; + +typedef struct DF_CtrlFlowPoint DF_CtrlFlowPoint; +struct DF_CtrlFlowPoint +{ + U64 vaddr; + U64 jump_dest_vaddr; + S64 expected_sp_delta; + DF_InstFlags inst_flags; +}; + +typedef struct DF_CtrlFlowPointNode DF_CtrlFlowPointNode; +struct DF_CtrlFlowPointNode +{ + DF_CtrlFlowPointNode *next; + DF_CtrlFlowPoint point; +}; + +typedef struct DF_CtrlFlowPointList DF_CtrlFlowPointList; +struct DF_CtrlFlowPointList +{ + DF_CtrlFlowPointNode *first; + DF_CtrlFlowPointNode *last; + U64 count; +}; + +typedef struct DF_CtrlFlowInfo DF_CtrlFlowInfo; +struct DF_CtrlFlowInfo +{ + DF_CtrlFlowFlags flags; + DF_CtrlFlowPointList exit_points; + U64 total_size; + S64 cumulative_sp_delta; +}; + +//////////////////////////////// +//~ rjf: Unwind Types + +typedef struct DF_UnwindFrame DF_UnwindFrame; +struct DF_UnwindFrame +{ + DF_UnwindFrame *next; + U64 rip; + void *regs; +}; + +typedef struct DF_Unwind DF_Unwind; +struct DF_Unwind +{ + DF_UnwindFrame *first; + DF_UnwindFrame *last; + U64 count; + B32 error; +}; + +//////////////////////////////// +//~ rjf: Evaluation Types + +//- rjf: primary artifact from evaluation + +typedef struct DF_Eval DF_Eval; +struct DF_Eval +{ + TG_Key type_key; + EVAL_EvalMode mode; + U64 offset; + union + { + S64 imm_s64; + U64 imm_u64; + F32 imm_f32; + F64 imm_f64; + U64 imm_u128[2]; + }; + EVAL_ErrorList errors; +}; + +//- rjf: value history types + +typedef struct DF_EvalHistoryVal DF_EvalHistoryVal; +struct DF_EvalHistoryVal +{ + EVAL_EvalMode mode; + U64 offset; + U64 imm_u128[2]; +}; + +typedef struct DF_EvalHistoryCacheNode DF_EvalHistoryCacheNode; +struct DF_EvalHistoryCacheNode +{ + DF_EvalHistoryCacheNode *lru_next; + DF_EvalHistoryCacheNode *lru_prev; + DF_EvalHistoryCacheNode *hash_next; + DF_EvalHistoryCacheNode *hash_prev; + DF_ExpandKey key; + U64 first_run_idx; + U64 last_run_idx; + U64 newest_val_idx; + DF_EvalHistoryVal values[64]; +}; + +typedef struct DF_EvalHistoryCacheSlot DF_EvalHistoryCacheSlot; +struct DF_EvalHistoryCacheSlot +{ + DF_EvalHistoryCacheNode *first; + DF_EvalHistoryCacheNode *last; +}; + +//////////////////////////////// +//~ rjf: View Rule Hook Types + +#define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(name) DF_Eval name(Arena *arena, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, struct DF_CfgVal *val) +#define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(name) df_core_view_rule_eval_resolution__##name +#define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(name) internal DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(name)) +#define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(name) void name(Arena *arena, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, struct DF_EvalView *eval_view, DF_Eval eval, struct DF_CfgTable *cfg_table, DF_ExpandKey parent_key, DF_ExpandKey key, S32 depth, struct DF_CfgNode *cfg, struct DF_EvalVizBlockList *out) +#define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(name) df_core_view_rule_viz_block_prod__##name +#define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(name) internal DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(name)) +typedef DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(DF_CoreViewRuleEvalResolutionHookFunctionType); +typedef DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(DF_CoreViewRuleVizBlockProdHookFunctionType); + +//////////////////////////////// +//~ rjf: Generated Code + +#include "df/core/generated/df_core.meta.h" + +//////////////////////////////// +//~ rjf: Config Types + +typedef U32 DF_CfgNodeFlags; +enum +{ + DF_CfgNodeFlag_Identifier = (1<<0), + DF_CfgNodeFlag_Numeric = (1<<1), + DF_CfgNodeFlag_StringLiteral = (1<<2), +}; + +typedef struct DF_CfgNode DF_CfgNode; +struct DF_CfgNode +{ + DF_CfgNode *first; + DF_CfgNode *last; + DF_CfgNode *parent; + DF_CfgNode *next; + DF_CfgNodeFlags flags; + String8 string; + DF_CfgSrc source; +}; + +typedef struct DF_CfgNodeRec DF_CfgNodeRec; +struct DF_CfgNodeRec +{ + DF_CfgNode *next; + S32 push_count; + S32 pop_count; +}; + +typedef struct DF_CfgVal DF_CfgVal; +struct DF_CfgVal +{ + DF_CfgVal *hash_next; + DF_CfgVal *linear_next; + DF_CfgNode *first; + DF_CfgNode *last; + U64 insertion_stamp; + String8 string; +}; + +typedef struct DF_CfgSlot DF_CfgSlot; +struct DF_CfgSlot +{ + DF_CfgVal *first; +}; + +typedef struct DF_CfgTable DF_CfgTable; +struct DF_CfgTable +{ + U64 slot_count; + DF_CfgSlot *slots; + U64 insertion_stamp_counter; + DF_CfgVal *first_val; + DF_CfgVal *last_val; +}; + +//////////////////////////////// +//~ rjf: View Rules + +typedef U32 DF_CoreViewRuleSpecInfoFlags; // NOTE(rjf): see @view_rule_info +enum +{ + DF_CoreViewRuleSpecInfoFlag_Inherited = (1<<0), + DF_CoreViewRuleSpecInfoFlag_Expandable = (1<<1), + DF_CoreViewRuleSpecInfoFlag_EvalResolution = (1<<2), + DF_CoreViewRuleSpecInfoFlag_VizBlockProd = (1<<3), +}; + +typedef struct DF_CoreViewRuleSpecInfo DF_CoreViewRuleSpecInfo; +struct DF_CoreViewRuleSpecInfo +{ + String8 string; + String8 display_string; + String8 description; + DF_CoreViewRuleSpecInfoFlags flags; + DF_CoreViewRuleEvalResolutionHookFunctionType *eval_resolution; + DF_CoreViewRuleVizBlockProdHookFunctionType *viz_block_prod; +}; + +typedef struct DF_CoreViewRuleSpecInfoArray DF_CoreViewRuleSpecInfoArray; +struct DF_CoreViewRuleSpecInfoArray +{ + DF_CoreViewRuleSpecInfo *v; + U64 count; +}; + +typedef struct DF_CoreViewRuleSpec DF_CoreViewRuleSpec; +struct DF_CoreViewRuleSpec +{ + DF_CoreViewRuleSpec *hash_next; + DF_CoreViewRuleSpecInfo info; +}; + +//////////////////////////////// +//~ rjf: Entity Types + +typedef U32 DF_EntitySubKind; + +typedef U32 DF_EntityFlags; +enum +{ + //- rjf: allocationless, simple equipment + DF_EntityFlag_HasTextPoint = (1<<0), + DF_EntityFlag_HasTextPointAlt = (1<<1), + DF_EntityFlag_HasEntityHandle = (1<<2), + DF_EntityFlag_HasB32 = (1<<3), + DF_EntityFlag_HasU64 = (1<<4), + DF_EntityFlag_HasRng1U64 = (1<<5), + DF_EntityFlag_HasColor = (1<<6), + DF_EntityFlag_DiesWithTime = (1<<7), + + //- rjf: ctrl entity equipment + DF_EntityFlag_HasCtrlMachineID = (1<<8), + DF_EntityFlag_HasCtrlHandle = (1<<9), + DF_EntityFlag_HasArch = (1<<10), + DF_EntityFlag_HasCtrlID = (1<<11), + DF_EntityFlag_HasStackBase = (1<<12), + DF_EntityFlag_HasTLSRoot = (1<<13), + DF_EntityFlag_HasVAddrRng = (1<<14), + DF_EntityFlag_HasVAddr = (1<<15), + + //- rjf: file properties + DF_EntityFlag_IsFolder = (1<<16), + DF_EntityFlag_IsMissing = (1<<17), + DF_EntityFlag_Output = (1<<18), // NOTE(rjf): might be missing, but written by us + + //- rjf: deletion + DF_EntityFlag_MarkedForDeletion = (1<<31), +}; + +typedef U64 DF_EntityID; + +typedef struct DF_Entity DF_Entity; +struct DF_Entity +{ + // rjf: tree links + DF_Entity *first; + DF_Entity *last; + DF_Entity *next; + DF_Entity *prev; + DF_Entity *parent; + + // rjf: metadata + DF_EntityKind kind; + DF_EntitySubKind subkind; + DF_EntityFlags flags; + DF_EntityID id; + U64 generation; + B32 deleted; + F32 alive_t; + + // rjf: allocationless, simple equipment + TxtPt text_point; + TxtPt text_point_alt; + DF_Handle entity_handle; + B32 b32; + U64 u64; + Rng1U64 rng1u64; + Vec4F32 color_hsva; + F32 life_left; + DF_CfgSrc cfg_src; + + // rjf: ctrl entity equipment + CTRL_MachineID ctrl_machine_id; + CTRL_Handle ctrl_handle; + Architecture arch; + U32 ctrl_id; + U64 stack_base; + U64 tls_root; + Rng1U64 vaddr_rng; + U64 vaddr; + + // rjf: name equipment + String8 name; + U64 name_generation; + + // rjf: timestamp + U64 timestamp; +}; + +typedef struct DF_EntityNode DF_EntityNode; +struct DF_EntityNode +{ + DF_EntityNode *next; + DF_Entity *entity; +}; + +typedef struct DF_EntityList DF_EntityList; +struct DF_EntityList +{ + DF_EntityNode *first; + DF_EntityNode *last; + U64 count; +}; + +typedef struct DF_EntityArray DF_EntityArray; +struct DF_EntityArray +{ + DF_Entity **v; + U64 count; +}; + +typedef struct DF_EntityRec DF_EntityRec; +struct DF_EntityRec +{ + DF_Entity *next; + S32 push_count; + S32 pop_count; +}; + +//////////////////////////////// +//~ rjf: Text Slices (output type from data which can be used to produce readable text) + +//- rjf: text slice construction flags + +typedef U32 DF_TextSliceFlags; +enum +{ + DF_TextSliceFlag_CodeBytes = (1<<0), + DF_TextSliceFlag_Addresses = (1<<1), + DF_TextSliceFlag_Tokens = (1<<2), + DF_TextSliceFlag_Src2Dasm = (1<<3), + DF_TextSliceFlag_Dasm2Src = (1<<4), + DF_TextSliceFlag_VirtualOff= (1<<5), +}; + +//- rjf: debug info for mapping src -> disasm + +typedef struct DF_TextLineSrc2DasmInfo DF_TextLineSrc2DasmInfo; +struct DF_TextLineSrc2DasmInfo +{ + Rng1U64 voff_range; + S64 remap_line; + DF_Entity *binary; +}; + +typedef struct DF_TextLineSrc2DasmInfoNode DF_TextLineSrc2DasmInfoNode; +struct DF_TextLineSrc2DasmInfoNode +{ + DF_TextLineSrc2DasmInfoNode *next; + DF_TextLineSrc2DasmInfo v; +}; + +typedef struct DF_TextLineSrc2DasmInfoList DF_TextLineSrc2DasmInfoList; +struct DF_TextLineSrc2DasmInfoList +{ + DF_TextLineSrc2DasmInfoNode *first; + DF_TextLineSrc2DasmInfoNode *last; + U64 count; +}; + +typedef struct DF_TextLineSrc2DasmInfoListArray DF_TextLineSrc2DasmInfoListArray; +struct DF_TextLineSrc2DasmInfoListArray +{ + DF_TextLineSrc2DasmInfoList *v; + DF_EntityList binaries; + U64 count; +}; + +//- rjf: debug info for mapping disasm -> src + +typedef struct DF_TextLineDasm2SrcInfo DF_TextLineDasm2SrcInfo; +struct DF_TextLineDasm2SrcInfo +{ + DF_Entity *binary; + DF_Entity *file; + TxtPt pt; + Rng1U64 voff_range; +}; + +typedef struct DF_TextLineDasm2SrcInfoNode DF_TextLineDasm2SrcInfoNode; +struct DF_TextLineDasm2SrcInfoNode +{ + DF_TextLineDasm2SrcInfoNode *next; + DF_TextLineDasm2SrcInfo v; +}; + +typedef struct DF_TextLineDasm2SrcInfoList DF_TextLineDasm2SrcInfoList; +struct DF_TextLineDasm2SrcInfoList +{ + DF_TextLineDasm2SrcInfoNode *first; + DF_TextLineDasm2SrcInfoNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Evaluation Visualization Types + +//- rjf: expansion key -> view rule table + +typedef struct DF_EvalViewRuleCacheNode DF_EvalViewRuleCacheNode; +struct DF_EvalViewRuleCacheNode +{ + DF_EvalViewRuleCacheNode *hash_next; + DF_EvalViewRuleCacheNode *hash_prev; + DF_ExpandKey key; + U8 *buffer; + U64 buffer_cap; + U64 buffer_string_size; +}; + +typedef struct DF_EvalViewRuleCacheSlot DF_EvalViewRuleCacheSlot; +struct DF_EvalViewRuleCacheSlot +{ + DF_EvalViewRuleCacheNode *first; + DF_EvalViewRuleCacheNode *last; +}; + +typedef struct DF_EvalViewRuleCacheTable DF_EvalViewRuleCacheTable; +struct DF_EvalViewRuleCacheTable +{ + U64 slot_count; + DF_EvalViewRuleCacheSlot *slots; +}; + +//- rjf: 'eval view' entities for sparse-state expandable tree view cache for evaluation visualization + +typedef struct DF_EvalViewKey DF_EvalViewKey; +struct DF_EvalViewKey +{ + U64 u64[2]; +}; + +typedef struct DF_EvalView DF_EvalView; +struct DF_EvalView +{ + // rjf: links + DF_EvalView *hash_next; + DF_EvalView *hash_prev; + + // rjf: key + DF_EvalViewKey key; + + // rjf: arena + Arena *arena; + + // rjf: expansion state + DF_ExpandTreeTable expand_tree_table; + + // rjf: key -> value history cache + U64 history_cache_table_size; + U64 history_cache_table_num_active_nodes; + DF_EvalHistoryCacheSlot *history_cache_table; + DF_EvalHistoryCacheNode *history_cache_lru_first; + DF_EvalHistoryCacheNode *history_cache_lru_last; + + // rjf: key -> view rule cache + DF_EvalViewRuleCacheTable view_rule_table; +}; + +typedef struct DF_EvalViewSlot DF_EvalViewSlot; +struct DF_EvalViewSlot +{ + DF_EvalView *first; + DF_EvalView *last; +}; + +typedef struct DF_EvalViewCache DF_EvalViewCache; +struct DF_EvalViewCache +{ + DF_EvalViewSlot *slots; + U64 slots_count; +}; + +//- rjf: eval view visualization building + +typedef struct DF_EvalLinkBase DF_EvalLinkBase; +struct DF_EvalLinkBase +{ + EVAL_EvalMode mode; + U64 offset; +}; + +typedef struct DF_EvalLinkBaseChunkNode DF_EvalLinkBaseChunkNode; +struct DF_EvalLinkBaseChunkNode +{ + DF_EvalLinkBaseChunkNode *next; + DF_EvalLinkBase b[64]; + U64 count; +}; + +typedef struct DF_EvalLinkBaseChunkList DF_EvalLinkBaseChunkList; +struct DF_EvalLinkBaseChunkList +{ + DF_EvalLinkBaseChunkNode *first; + DF_EvalLinkBaseChunkNode *last; + U64 count; +}; + +typedef struct DF_EvalLinkBaseArray DF_EvalLinkBaseArray; +struct DF_EvalLinkBaseArray +{ + DF_EvalLinkBase *v; + U64 count; +}; + +typedef enum DF_EvalVizBlockKind +{ + DF_EvalVizBlockKind_Root, + DF_EvalVizBlockKind_Members, + DF_EvalVizBlockKind_Elements, + DF_EvalVizBlockKind_Links, + DF_EvalVizBlockKind_Canvas, + DF_EvalVizBlockKind_COUNT, +} +DF_EvalVizBlockKind; + +typedef struct DF_EvalVizBlock DF_EvalVizBlock; +struct DF_EvalVizBlock +{ + DF_EvalVizBlock *next; + DF_EvalVizBlockKind kind; + DF_EvalView *eval_view; + DF_Eval eval; + TG_Key link_member_type_key; + U64 link_member_off; + DF_CfgTable cfg_table; + String8 string; + DF_ExpandKey parent_key; + DF_ExpandKey key; + Rng1U64 visual_idx_range; + Rng1U64 semantic_idx_range; + S32 depth; +}; + +typedef struct DF_EvalVizBlockList DF_EvalVizBlockList; +struct DF_EvalVizBlockList +{ + DF_EvalVizBlock *first; + DF_EvalVizBlock *last; + U64 count; + U64 total_visual_row_count; + U64 total_semantic_row_count; +}; + +typedef U32 DF_EvalVizStringFlags; +enum +{ + DF_EvalVizStringFlag_ReadOnlyDisplayRules = (1<<0), +}; + +// TODO(rjf): move viz-row stuff to gfx layer + +typedef U32 DF_EvalVizRowFlags; +enum +{ + DF_EvalVizRowFlag_CanExpand = (1<<0), + DF_EvalVizRowFlag_CanEditValue = (1<<1), + DF_EvalVizRowFlag_Canvas = (1<<2), +}; + +typedef struct DF_EvalVizRow DF_EvalVizRow; +struct DF_EvalVizRow +{ + DF_EvalVizRow *next; + DF_EvalVizRowFlags flags; + + // rjf: eval & eval view state + DF_EvalView *eval_view; + DF_Eval eval; + + // rjf: basic visualization contents + String8 expr; + String8 display_value; + String8 edit_value; + + // rjf: variable-size & hook info + U64 size_in_rows; + U64 skipped_size_in_rows; + U64 chopped_size_in_rows; + struct DF_GfxViewRuleSpec *expand_ui_rule_spec; + struct DF_CfgNode *expand_ui_rule_node; + + // rjf: value area override view rule spec + struct DF_GfxViewRuleSpec *value_ui_rule_spec; + struct DF_CfgNode *value_ui_rule_node; + + // rjf: errors + EVAL_ErrorList errors; + + // rjf: tree depth & keys + S32 depth; + DF_ExpandKey parent_key; + DF_ExpandKey key; +}; + +typedef struct DF_EvalVizWindowedRowList DF_EvalVizWindowedRowList; +struct DF_EvalVizWindowedRowList +{ + DF_EvalVizRow *first; + DF_EvalVizRow *last; + U64 count; + U64 count_before_visual; + U64 count_before_semantic; +}; + +//////////////////////////////// +//~ rjf: Command Specification Types + +typedef U32 DF_CmdSpecFlags; +enum +{ + DF_CmdSpecFlag_OmitFromLists = (1<<0), + DF_CmdSpecFlag_RunKeepsQuery = (1<<1), + DF_CmdSpecFlag_QueryUsesOldInput = (1<<2), + DF_CmdSpecFlag_AppliesToView = (1<<3), + DF_CmdSpecFlag_QueryIsCode = (1<<4), +}; + +typedef struct DF_CmdSpecInfo DF_CmdSpecInfo; +struct DF_CmdSpecInfo +{ + String8 string; + String8 description; + String8 search_tags; + String8 display_name; + DF_CmdSpecFlags flags; + DF_CmdParamSlot query_slots[4]; + DF_CmdQueryRule query_rule; + DF_IconKind canonical_icon_kind; + U64 query_info_u64[2]; +}; + +typedef struct DF_CmdSpec DF_CmdSpec; +struct DF_CmdSpec +{ + DF_CmdSpec *hash_next; + DF_CmdSpecInfo info; + U64 registrar_index; + U64 ordering_index; + U64 run_count; +}; + +typedef struct DF_CmdSpecNode DF_CmdSpecNode; +struct DF_CmdSpecNode +{ + DF_CmdSpecNode *next; + DF_CmdSpec *spec; +}; + +typedef struct DF_CmdSpecList DF_CmdSpecList; +struct DF_CmdSpecList +{ + DF_CmdSpecNode *first; + DF_CmdSpecNode *last; + U64 count; +}; + +typedef struct DF_CmdSpecArray DF_CmdSpecArray; +struct DF_CmdSpecArray +{ + DF_CmdSpec **v; + U64 count; +}; + +typedef struct DF_CmdSpecInfoArray DF_CmdSpecInfoArray; +struct DF_CmdSpecInfoArray +{ + DF_CmdSpecInfo *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Command Types + +typedef struct DF_Cmd DF_Cmd; +struct DF_Cmd +{ + DF_CmdParams params; + DF_CmdSpec *spec; +}; + +typedef struct DF_CmdNode DF_CmdNode; +struct DF_CmdNode +{ + DF_CmdNode *next; + DF_CmdNode *prev; + DF_Cmd cmd; +}; + +typedef struct DF_CmdList DF_CmdList; +struct DF_CmdList +{ + DF_CmdNode *first; + DF_CmdNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Main State Caches + +//- rjf: per-entity-kind state cache + +typedef struct DF_EntityListCache DF_EntityListCache; +struct DF_EntityListCache +{ + Arena *arena; + U64 alloc_gen; + DF_EntityList list; +}; + +//- rjf: per-run unwind cache + +typedef struct DF_RunUnwindCacheNode DF_RunUnwindCacheNode; +struct DF_RunUnwindCacheNode +{ + DF_RunUnwindCacheNode *hash_next; + DF_Handle thread; + DF_Unwind unwind; +}; + +typedef struct DF_RunUnwindCacheSlot DF_RunUnwindCacheSlot; +struct DF_RunUnwindCacheSlot +{ + DF_RunUnwindCacheNode *first; + DF_RunUnwindCacheNode *last; +}; + +typedef struct DF_RunUnwindCache DF_RunUnwindCache; +struct DF_RunUnwindCache +{ + Arena *arena; + U64 table_size; + DF_RunUnwindCacheSlot *table; +}; + +//- rjf: per-run locals cache + +typedef struct DF_RunLocalsCacheNode DF_RunLocalsCacheNode; +struct DF_RunLocalsCacheNode +{ + DF_RunLocalsCacheNode *hash_next; + DF_Handle binary; + U64 voff; + EVAL_String2NumMap *locals_map; +}; + +typedef struct DF_RunLocalsCacheSlot DF_RunLocalsCacheSlot; +struct DF_RunLocalsCacheSlot +{ + DF_RunLocalsCacheNode *first; + DF_RunLocalsCacheNode *last; +}; + +typedef struct DF_RunLocalsCache DF_RunLocalsCache; +struct DF_RunLocalsCache +{ + Arena *arena; + U64 table_size; + DF_RunLocalsCacheSlot *table; +}; + +//////////////////////////////// +//~ rjf: File Change Detector Shared Data Structure Types + +typedef struct DF_FileScanNode DF_FileScanNode; +struct DF_FileScanNode +{ + DF_FileScanNode *next; + String8 path; + U64 stamp; +}; + +typedef struct DF_FileScanSlot DF_FileScanSlot; +struct DF_FileScanSlot +{ + DF_FileScanNode *first; + DF_FileScanNode *last; +}; + +//////////////////////////////// +//~ rjf: State Delta History Types + +typedef struct DF_StateDelta DF_StateDelta; +struct DF_StateDelta +{ + U64 vaddr; + String8 data; +}; + +typedef struct DF_StateDeltaNode DF_StateDeltaNode; +struct DF_StateDeltaNode +{ + DF_StateDeltaNode *next; + DF_StateDelta v; +}; + +typedef struct DF_StateDeltaBatch DF_StateDeltaBatch; +struct DF_StateDeltaBatch +{ + DF_StateDeltaBatch *next; + DF_StateDeltaNode *first; + DF_StateDeltaNode *last; + U64 gen; + U64 gen_vaddr; +}; + +typedef struct DF_StateDeltaHistory DF_StateDeltaHistory; +struct DF_StateDeltaHistory +{ + Arena *arena; + Arena *side_arenas[Side_COUNT]; // min -> undo; max -> redo + DF_StateDeltaBatch *side_tops[Side_COUNT]; +}; + +//////////////////////////////// +//~ rjf: Main State Types + +//- rjf: architecture info table types + +typedef struct DF_ArchInfoNode DF_ArchInfoNode; +struct DF_ArchInfoNode +{ + DF_ArchInfoNode *hash_next; + String8 key; + String8 val; +}; + +typedef struct DF_ArchInfoSlot DF_ArchInfoSlot; +struct DF_ArchInfoSlot +{ + DF_ArchInfoNode *first; + DF_ArchInfoNode *last; +}; + +//- rjf: name allocator types + +typedef struct DF_NameChunkNode DF_NameChunkNode; +struct DF_NameChunkNode +{ + DF_NameChunkNode *next; + U64 size; +}; + +//- rjf: core bundle state type + +typedef struct DF_State DF_State; +struct DF_State +{ + // rjf: top-level state + Arena *arena; + U64 frame_index; + F64 time_in_seconds; + F32 dt; + F32 seconds_til_autosave; + + // rjf: top-level command batch + Arena *root_cmd_arena; + DF_CmdList root_cmds; + + // rjf: history cache + DF_StateDeltaHistory *hist; + + // rjf: name allocator + DF_NameChunkNode *free_name_chunks[8]; + + // rjf: entity state + Arena *entities_arena; + DF_Entity *entities_base; + U64 entities_count; + U64 entities_id_gen; + DF_Entity *entities_root; + DF_Entity *entities_free[2]; // [0] -> normal lifetime, not user defined; [1] -> user defined lifetime (& thus undoable) + U64 entities_free_count; + U64 entities_active_count; + B32 entities_mut_soft_halt; + B32 entities_mut_dbg_info_map; + + // rjf: entity query caches + U64 kind_alloc_gens[DF_EntityKind_COUNT]; + DF_EntityListCache kind_caches[DF_EntityKind_COUNT]; + DF_EntityListCache dbg_info_cache; + DF_EntityListCache bin_file_cache; + + // rjf: per-run caches + B32 unwind_cache_invalidated; + DF_RunUnwindCache unwind_cache; + B32 locals_cache_invalidated; + DF_RunLocalsCache locals_cache; + B32 member_cache_invalidated; + DF_RunLocalsCache member_cache; + + // rjf: eval view cache + DF_EvalViewCache eval_view_cache; + + // rjf: command specification table + U64 total_registrar_count; + U64 cmd_spec_table_size; + DF_CmdSpec **cmd_spec_table; + + // rjf: view rule specification table + U64 view_rule_spec_table_size; + DF_CoreViewRuleSpec **view_rule_spec_table; + + // rjf: freeze state + DF_HandleList frozen_threads; + DF_HandleNode *free_handle_node; + + // rjf: main control context + DF_CtrlCtx ctrl_ctx; + + // rjf: control thread user -> ctrl driving state + Arena *ctrl_last_run_arena; + DF_RunKind ctrl_last_run_kind; + U64 ctrl_last_run_frame_idx; + DF_Handle ctrl_last_run_thread; + CTRL_TrapList ctrl_last_run_traps; + U64 ctrl_run_gen; + B32 ctrl_is_running; + B32 ctrl_soft_halt_issued; + Arena *ctrl_msg_arena; + CTRL_MsgList ctrl_msgs; + U64 ctrl_exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; + B32 ctrl_solo_stepping_mode; + + // rjf: control thread ctrl -> user reading state + Arena *ctrl_stop_arena; + CTRL_Event ctrl_last_stop_event; + + // rjf: config reading state + Arena *cfg_path_arenas[DF_CfgSrc_COUNT]; + String8 cfg_paths[DF_CfgSrc_COUNT]; + U64 cfg_cached_timestamp[DF_CfgSrc_COUNT]; + Arena *cfg_arena; + DF_CfgTable cfg_table; + + // rjf: config writing state + B32 cfg_write_issued[DF_CfgSrc_COUNT]; + Arena *cfg_write_arenas[DF_CfgSrc_COUNT]; + String8List cfg_write_data[DF_CfgSrc_COUNT]; + + // rjf: current path + Arena *current_path_arena; + String8 current_path; + + // rjf: architecture info tables + U64 arch_info_x64_table_size; + DF_ArchInfoSlot *arch_info_x64_table; +}; + +//////////////////////////////// +//~ rjf: Globals + +read_only global DF_CmdSpec df_g_nil_cmd_spec = {0}; +read_only global DF_CoreViewRuleSpec df_g_nil_core_view_rule_spec = {0}; +read_only global DF_CfgNode df_g_nil_cfg_node = {&df_g_nil_cfg_node, &df_g_nil_cfg_node, &df_g_nil_cfg_node, &df_g_nil_cfg_node}; +read_only global DF_CfgVal df_g_nil_cfg_val = {&df_g_nil_cfg_val, &df_g_nil_cfg_val, &df_g_nil_cfg_node, &df_g_nil_cfg_node}; +read_only global DF_Entity df_g_nil_entity = +{ + // rjf: tree links + &df_g_nil_entity, + &df_g_nil_entity, + &df_g_nil_entity, + &df_g_nil_entity, + &df_g_nil_entity, + + // rjf: metadata + DF_EntityKind_Nil, + 0, + 0, + 0, + 0, + 0, + 0, + + // rjf: allocationless, simple equipment + {0}, + {0}, + {0}, + 0, + 0, + {0}, + {0}, + 0, + DF_CfgSrc_User, + + // rjf: ctrl entity equipment + 0, + {0}, + Architecture_Null, + 0, + 0, + 0, + {0}, + 0, + + // rjf: name equipment + 0, + zero_struct, + 0, + + // rjf: timestamp + 0, +}; +read_only global DF_EvalView df_g_nil_eval_view = {&df_g_nil_eval_view, &df_g_nil_eval_view}; + +global DF_State *df_state = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 df_hash_from_seed_string(U64 seed, String8 string); +internal U64 df_hash_from_string(String8 string); +internal U64 df_hash_from_seed_string__case_insensitive(U64 seed, String8 string); +internal U64 df_hash_from_string__case_insensitive(String8 string); + +//////////////////////////////// +//~ rjf: Handle Type Pure Functions + +internal DF_Handle df_handle_zero(void); +internal B32 df_handle_match(DF_Handle a, DF_Handle b); +internal void df_handle_list_push_node(DF_HandleList *list, DF_HandleNode *node); +internal void df_handle_list_push(Arena *arena, DF_HandleList *list, DF_Handle handle); +internal void df_handle_list_remove(DF_HandleList *list, DF_HandleNode *node); +internal DF_HandleNode *df_handle_list_find(DF_HandleList *list, DF_Handle handle); +internal DF_HandleList df_push_handle_list_copy(Arena *arena, DF_HandleList list); + +//////////////////////////////// +//~ rjf: State History Data Structure + +internal DF_StateDeltaHistory *df_state_delta_history_alloc(void); +internal void df_state_delta_history_release(DF_StateDeltaHistory *hist); +internal void df_state_delta_history_push_batch(DF_StateDeltaHistory *hist, U64 *optional_gen_ptr); +internal void df_state_delta_history_push_delta(DF_StateDeltaHistory *hist, void *ptr, U64 size); +#define df_state_delta_history_push_struct_delta(hist, ptr) df_state_delta_history_push_delta((hist), (ptr), sizeof(*(ptr))) +internal void df_state_delta_history_wind(DF_StateDeltaHistory *hist, Side side); + +//////////////////////////////// +//~ rjf: Sparse Tree Expansion State Data Structure + +//- rjf: keys +internal DF_ExpandKey df_expand_key_make(U64 uniquifier, U64 parent_hash, U64 child_num); +internal DF_ExpandKey df_expand_key_zero(void); +internal B32 df_expand_key_match(DF_ExpandKey a, DF_ExpandKey b); + +//- rjf: table +internal void df_expand_tree_table_init(Arena *arena, DF_ExpandTreeTable *table, U64 slot_count); +internal void df_expand_tree_table_animate(DF_ExpandTreeTable *table, F32 dt); +internal DF_ExpandNode *df_expand_node_from_key(DF_ExpandTreeTable *table, DF_ExpandKey key); +internal B32 df_expand_key_is_set(DF_ExpandTreeTable *table, DF_ExpandKey key); +internal void df_expand_set_expansion(Arena *arena, DF_ExpandTreeTable *table, DF_ExpandKey parent_key, DF_ExpandKey key, B32 expanded); + +//////////////////////////////// +//~ rjf: Config Type Pure Functions + +internal DF_CfgNode *df_cfg_tree_copy(Arena *arena, DF_CfgNode *src_root); +internal DF_CfgNodeRec df_cfg_node_rec__depth_first_pre(DF_CfgNode *node, DF_CfgNode *root); +internal void df_cfg_table_push_unparsed_string(Arena *arena, DF_CfgTable *table, String8 string, DF_CfgSrc source); +internal DF_CfgTable df_cfg_table_from_inheritance(Arena *arena, DF_CfgTable *src); +internal DF_CfgTable df_cfg_table_copy(Arena *arena, DF_CfgTable *src); +internal DF_CfgVal *df_cfg_val_from_string(DF_CfgTable *table, String8 string); +internal DF_CfgNode *df_cfg_node_child_from_string(DF_CfgNode *node, String8 string, StringMatchFlags flags); +internal DF_CfgNode *df_first_cfg_node_child_from_flags(DF_CfgNode *node, DF_CfgNodeFlags flags); +internal String8 df_string_from_cfg_node_children(Arena *arena, DF_CfgNode *node); +internal Vec4F32 df_hsva_from_cfg_node(DF_CfgNode *node); +internal String8 df_string_from_cfg_node_key(DF_CfgNode *node, String8 key, StringMatchFlags flags); + +//////////////////////////////// +//~ rjf: Disassembly Pure Functions + +internal DF_Inst df_single_inst_from_machine_code__x64(Arena *arena, U64 start_voff, String8 string); +internal DF_Inst df_single_inst_from_machine_code(Arena *arena, Architecture arch, U64 start_voff, String8 string); + +//////////////////////////////// +//~ rjf: Control Flow Analysis Pure Functions + +internal DF_CtrlFlowInfo df_ctrl_flow_info_from_vaddr_code__x64(Arena *arena, DF_InstFlags exit_points_mask, U64 vaddr, String8 code); +internal DF_CtrlFlowInfo df_ctrl_flow_info_from_arch_vaddr_code(Arena *arena, DF_InstFlags exit_points_mask, Architecture arch, U64 vaddr, String8 code); + +//////////////////////////////// +//~ rjf: Command Type Pure Functions + +//- rjf: specs +internal B32 df_cmd_spec_is_nil(DF_CmdSpec *spec); +internal void df_cmd_spec_list_push(Arena *arena, DF_CmdSpecList *list, DF_CmdSpec *spec); +internal DF_CmdSpecArray df_cmd_spec_array_from_list(Arena *arena, DF_CmdSpecList list); +internal int df_qsort_compare_cmd_spec__run_counter(DF_CmdSpec **a, DF_CmdSpec **b); +internal void df_cmd_spec_array_sort_by_run_counter__in_place(DF_CmdSpecArray array); +internal DF_Handle df_handle_from_cmd_spec(DF_CmdSpec *spec); +internal DF_CmdSpec *df_cmd_spec_from_handle(DF_Handle handle); + +//- rjf: string -> command parsing +internal String8 df_cmd_name_part_from_string(String8 string); +internal String8 df_cmd_arg_part_from_string(String8 string); + +//- rjf: command parameter bundles +internal DF_CmdParams df_cmd_params_zero(void); +internal void df_cmd_params_mark_slot(DF_CmdParams *params, DF_CmdParamSlot slot); +internal B32 df_cmd_params_has_slot(DF_CmdParams *params, DF_CmdParamSlot slot); +internal String8 df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams *params, DF_CmdSpec *spec, String8 query); + +//- rjf: command lists +internal void df_cmd_list_push(Arena *arena, DF_CmdList *cmds, DF_CmdParams *params, DF_CmdSpec *spec); + +//- rjf: string -> core layer command kind +internal DF_CoreCmdKind df_core_cmd_kind_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Entity Type Pure Functions + +//- rjf: nil +internal B32 df_entity_is_nil(DF_Entity *entity); + +//- rjf: handle <-> entity conversions +internal U64 df_index_from_entity(DF_Entity *entity); +internal DF_Handle df_handle_from_entity(DF_Entity *entity); +internal DF_Entity *df_entity_from_handle(DF_Handle handle); +internal DF_EntityList df_entity_list_from_handle_list(Arena *arena, DF_HandleList handles); +internal DF_HandleList df_handle_list_from_entity_list(Arena *arena, DF_EntityList entities); + +//- rjf: entity recursion iterators +internal DF_EntityRec df_entity_rec_df(DF_Entity *entity, DF_Entity *subtree_root, U64 sib_off, U64 child_off); +#define df_entity_rec_df_pre(entity, subtree_root) df_entity_rec_df((entity), (subtree_root), OffsetOf(DF_Entity, next), OffsetOf(DF_Entity, first)) +#define df_entity_rec_df_post(entity, subtree_root) df_entity_rec_df((entity), (subtree_root), OffsetOf(DF_Entity, prev), OffsetOf(DF_Entity, last)) + +//- rjf: ancestor/child introspection +internal DF_Entity *df_entity_child_from_kind(DF_Entity *entity, DF_EntityKind kind); +internal DF_Entity *df_entity_ancestor_from_kind(DF_Entity *entity, DF_EntityKind kind); +internal DF_EntityList df_push_entity_child_list_with_kind(Arena *arena, DF_Entity *entity, DF_EntityKind kind); +internal DF_Entity *df_entity_child_from_name_and_kind(DF_Entity *parent, String8 string, DF_EntityKind kind); + +//- rjf: entity list building +internal void df_entity_list_push(Arena *arena, DF_EntityList *list, DF_Entity *entity); +internal DF_EntityArray df_entity_array_from_list(Arena *arena, DF_EntityList *list); +#define df_first_entity_from_list(list) ((list)->first != 0 ? (list)->first->entity : &df_g_nil_entity) + +//- rjf: entity -> text info +internal TXTI_Handle df_txti_handle_from_entity(DF_Entity *entity); + +//- rjf: entity -> disasm info +internal DASM_Handle df_dasm_handle_from_process_vaddr(DF_Entity *process, U64 vaddr); + +//- rjf: full path building, from file/folder entities +internal String8 df_full_path_from_entity(Arena *arena, DF_Entity *entity); + +//- rjf: display string entities, for referencing entities in ui +internal String8 df_display_string_from_entity(Arena *arena, DF_Entity *entity); + +//- rjf: entity -> color operations +internal Vec4F32 df_hsva_from_entity(DF_Entity *entity); +internal Vec4F32 df_rgba_from_entity(DF_Entity *entity); + +//////////////////////////////// +//~ rjf: Name Allocation + +internal U64 df_name_bucket_idx_from_string_size(U64 size); +internal String8 df_name_alloc(DF_StateDeltaHistory *hist, String8 string); +internal void df_name_release(DF_StateDeltaHistory *hist, String8 string); + +//////////////////////////////// +//~ rjf: Entity Stateful Functions + +//- rjf: entity mutation notification codepath +internal void df_entity_notify_mutation(DF_Entity *entity); + +//- rjf: entity allocation + tree forming +internal DF_Entity *df_entity_alloc(DF_StateDeltaHistory *hist, DF_Entity *parent, DF_EntityKind kind); +internal void df_entity_mark_for_deletion(DF_Entity *entity); +internal void df_entity_release(DF_StateDeltaHistory *hist, DF_Entity *entity); +internal void df_entity_change_parent(DF_StateDeltaHistory *hist, DF_Entity *entity, DF_Entity *old_parent, DF_Entity *new_parent); + +//- rjf: entity simple equipment +internal void df_entity_equip_txt_pt(DF_Entity *entity, TxtPt point); +internal void df_entity_equip_txt_pt_alt(DF_Entity *entity, TxtPt point); +internal void df_entity_equip_entity_handle(DF_Entity *entity, DF_Handle handle); +internal void df_entity_equip_b32(DF_Entity *entity, B32 b32); +internal void df_entity_equip_u64(DF_Entity *entity, U64 u64); +internal void df_entity_equip_rng1u64(DF_Entity *entity, Rng1U64 range); +internal void df_entity_equip_color_rgba(DF_Entity *entity, Vec4F32 rgba); +internal void df_entity_equip_color_hsva(DF_Entity *entity, Vec4F32 hsva); +internal void df_entity_equip_death_timer(DF_Entity *entity, F32 seconds_til_death); +internal void df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src); + +//- rjf: control layer correllation equipment +internal void df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id); +internal void df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle); +internal void df_entity_equip_arch(DF_Entity *entity, Architecture arch); +internal void df_entity_equip_ctrl_id(DF_Entity *entity, U32 id); +internal void df_entity_equip_stack_base(DF_Entity *entity, U64 stack_base); +internal void df_entity_equip_tls_root(DF_Entity *entity, U64 tls_root); +internal void df_entity_equip_vaddr_rng(DF_Entity *entity, Rng1U64 range); +internal void df_entity_equip_vaddr(DF_Entity *entity, U64 vaddr); + +//- rjf: name equipment +internal void df_entity_equip_name(DF_StateDeltaHistory *hist, DF_Entity *entity, String8 name); +internal void df_entity_equip_namef(DF_StateDeltaHistory *hist, DF_Entity *entity, char *fmt, ...); + +//- rjf: opening folders/files & maintaining the entity model of the filesystem +internal DF_Entity *df_entity_from_path(String8 path, DF_EntityFromPathFlags flags); +internal DF_EntityList df_possible_overrides_from_entity(Arena *arena, DF_Entity *entity); + +//- rjf: top-level state queries +internal DF_Entity *df_entity_root(void); +internal DF_EntityList df_push_entity_list_with_kind(Arena *arena, DF_EntityKind kind); +internal DF_Entity *df_entity_from_id(DF_EntityID id); +internal DF_Entity *df_machine_entity_from_machine_id(CTRL_MachineID machine_id); +internal DF_Entity *df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle); +internal DF_Entity *df_entity_from_ctrl_id(CTRL_MachineID machine_id, U32 id); +internal DF_Entity *df_entity_from_name_and_kind(String8 string, DF_EntityKind kind); +internal DF_Entity *df_entity_from_u64_and_kind(U64 u64, DF_EntityKind kind); + +//- rjf: entity freezing state +internal void df_set_thread_freeze_state(DF_Entity *thread, B32 frozen); +internal B32 df_entity_is_frozen(DF_Entity *entity); + +//////////////////////////////// +//~ rjf: Command Stateful Functions + +internal void df_register_cmd_specs(DF_CmdSpecInfoArray specs); +internal DF_CmdSpec *df_cmd_spec_from_string(String8 string); +internal DF_CmdSpec *df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind core_cmd_kind); +internal void df_cmd_spec_counter_inc(DF_CmdSpec *spec); +internal DF_CmdSpecList df_push_cmd_spec_list(Arena *arena); + +//////////////////////////////// +//~ rjf: View Rule Spec Stateful Functions + +internal void df_register_core_view_rule_specs(DF_CoreViewRuleSpecInfoArray specs); +internal DF_CoreViewRuleSpec *df_core_view_rule_spec_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Debug Info Mapping + +internal String8 df_debug_info_path_from_module(Arena *arena, DF_Entity *module); + +//////////////////////////////// +//~ rjf: Stepping "Trap Net" Builders + +internal CTRL_TrapList df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread); +internal CTRL_TrapList df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread); +internal CTRL_TrapList df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread); + +//////////////////////////////// +//~ rjf: Modules & Debug Info Mappings + +//- rjf: module <=> binary file +internal DF_Entity *df_binary_file_from_module(DF_Entity *module); +internal DF_EntityList df_modules_from_binary_file(Arena *arena, DF_Entity *binary_info); + +//- rjf: voff <=> vaddr +internal U64 df_base_vaddr_from_module(DF_Entity *module); +internal U64 df_voff_from_vaddr(DF_Entity *module, U64 vaddr); +internal U64 df_vaddr_from_voff(DF_Entity *module, U64 voff); +internal Rng1U64 df_voff_range_from_vaddr_range(DF_Entity *module, Rng1U64 vaddr_rng); +internal Rng1U64 df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_rng); + +//////////////////////////////// +//~ rjf: Debug Info Lookups + +//- rjf: binary file -> dbgi parse +internal DBGI_Parse *df_dbgi_parse_from_binary_file(DBGI_Scope *scope, DF_Entity *binary); + +//- rjf: voff|vaddr -> symbol lookups +internal String8 df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff); +internal String8 df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr); + +//- rjf: src -> voff lookups +internal DF_TextLineSrc2DasmInfoListArray df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entity *file, Rng1S64 line_num_range); + +//- rjf: voff -> src lookups +internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff); +internal DF_TextLineDasm2SrcInfoList df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff); + +//- rjf: symbol -> voff lookups +internal U64 df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name); +internal U64 df_type_num_from_binary_name(DF_Entity *binary, String8 name); + +//////////////////////////////// +//~ rjf: Process/Thread Info Lookups + +//- rjf: thread info extraction helpers +internal DF_Entity *df_module_from_process_vaddr(DF_Entity *process, U64 vaddr); +internal DF_Entity *df_module_from_thread(DF_Entity *thread); +internal U64 df_tls_base_vaddr_from_thread(DF_Entity *thread); +internal Architecture df_architecture_from_entity(DF_Entity *entity); +internal DF_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread); +internal U64 df_rip_from_thread(DF_Entity *thread); +internal U64 df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); +internal EVAL_String2NumMap *df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); +internal EVAL_String2NumMap *df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); +internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr); +internal DF_Entity *df_module_from_thread_candidates(DF_Entity *thread, DF_EntityList *candidates); + +//////////////////////////////// +//~ rjf: Entity -> Log Entities + +internal DF_Entity *df_log_from_entity(DF_Entity *entity); + +//////////////////////////////// +//~ rjf: Target Controls + +//- rjf: control message dispatching +internal void df_push_ctrl_msg(CTRL_Msg *msg); + +//- rjf: control thread running +internal void df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_TrapList *run_traps); + +//- rjf: stopped info from the control thread +internal CTRL_Event df_ctrl_last_stop_event(void); + +//////////////////////////////// +//~ rjf: Evaluation + +internal B32 df_eval_memory_read(void *u, void *out, U64 addr, U64 size); +internal EVAL_ParseCtx df_eval_parse_ctx_from_module_voff(DBGI_Scope *scope, DF_Entity *module, U64 voff); +internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt); +internal DF_Eval df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, String8 string); +internal DF_Eval df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); +internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, DF_CfgTable *cfg); + +//////////////////////////////// +//~ rjf: Evaluation Views + +//- rjf: keys +internal DF_EvalViewKey df_eval_view_key_make(U64 v0, U64 v1); +internal DF_EvalViewKey df_eval_view_key_from_string(String8 string); +internal DF_EvalViewKey df_eval_view_key_from_stringf(char *fmt, ...); +internal B32 df_eval_view_key_match(DF_EvalViewKey a, DF_EvalViewKey b); + +//- rjf: cache lookup +internal DF_EvalView *df_eval_view_from_key(DF_EvalViewKey key); + +//- rjf: key -> eval history +internal DF_EvalHistoryCacheNode *df_eval_history_cache_node_from_key(DF_EvalView *eval_view, DF_ExpandKey key); +internal B32 df_eval_view_record_history_val(DF_EvalView *eval_view, DF_ExpandKey key, DF_EvalHistoryVal val); + +//- rjf: key -> view rules +internal void df_eval_view_set_key_rule(DF_EvalView *eval_view, DF_ExpandKey key, String8 view_rule_string); +internal String8 df_eval_view_rule_from_key(DF_EvalView *eval_view, DF_ExpandKey key); + +//////////////////////////////// +//~ rjf: Evaluation View Visualization & Interaction + +//- rjf: evaluation value string builder helpers +internal String8 df_string_from_ascii_value(Arena *arena, U8 val); +internal String8 df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_EvalVizStringFlags flags, U32 radix, DF_Eval eval); + +//- rjf: writing values back to child processes +internal B32 df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval dst_eval, DF_Eval src_eval); + +//- rjf: type helpers +internal TG_MemberArray df_filtered_data_members_from_members_cfg_table(Arena *arena, TG_MemberArray members, DF_CfgTable *cfg); +internal DF_EvalLinkBaseChunkList df_eval_link_base_chunk_list_from_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key link_member_type_key, U64 link_member_off, DF_CtrlCtx *ctrl_ctx, DF_Eval eval, U64 cap); +internal DF_EvalLinkBase df_eval_link_base_from_chunk_list_index(DF_EvalLinkBaseChunkList *list, U64 idx); +internal DF_EvalLinkBaseArray df_eval_link_base_array_from_chunk_list(Arena *arena, DF_EvalLinkBaseChunkList *chunks); + +//- rjf: watch tree visualization +internal void df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalView *view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out); +internal DF_EvalVizBlockList df_eval_viz_block_list_from_eval_view_expr(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_EvalView *eval_view, String8 expr); +internal void df_eval_viz_block_list_concat__in_place(DF_EvalVizBlockList *dst, DF_EvalVizBlockList *to_push); + +//////////////////////////////// +//~ rjf: Main State Accessors/Mutators + +//- rjf: frame metadata +internal F32 df_dt(void); +internal U64 df_frame_index(void); +internal F64 df_time_in_seconds(void); + +//- rjf: undo/redo history +internal DF_StateDeltaHistory *df_state_delta_history(void); + +//- rjf: control state +internal DF_RunKind df_ctrl_last_run_kind(void); +internal U64 df_ctrl_last_run_frame_idx(void); +internal U64 df_ctrl_run_gen(void); +internal B32 df_ctrl_targets_running(void); + +//- rjf: control context +internal DF_CtrlCtx df_ctrl_ctx(void); +internal void df_ctrl_ctx_apply_overrides(DF_CtrlCtx *ctx, DF_CtrlCtx *overrides); + +//- rjf: config paths +internal String8 df_cfg_path_from_src(DF_CfgSrc src); + +//- rjf: config state +internal DF_CfgTable *df_cfg_table(void); + +//- rjf: config serialization +internal String8List df_cfg_strings_from_core(Arena *arena, String8 root_path, DF_CfgSrc source); +internal void df_cfg_push_write_string(DF_CfgSrc src, String8 string); + +//- rjf: current path +internal String8 df_current_path(void); + +//- rjf: architecture info table lookups +internal String8 df_info_summary_from_string__x64(String8 string); +internal String8 df_info_summary_from_string(Architecture arch, String8 string); + +//- rjf: entity kind cache +internal DF_EntityList df_query_cached_entity_list_with_kind(DF_EntityKind kind); +internal DF_EntityList df_push_active_binary_list(Arena *arena); +internal DF_EntityList df_push_active_target_list(Arena *arena); + +//- rjf: per-run caches +internal DF_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread); +internal U64 df_query_cached_rip_from_thread(DF_Entity *thread); +internal U64 df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); +internal EVAL_String2NumMap *df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff); +internal EVAL_String2NumMap *df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff); + +//- rjf: top-level command dispatch +internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec); + +//////////////////////////////// +//~ rjf: Main Layer Top-Level Calls + +internal void df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist); +internal DF_CmdList df_core_gather_root_cmds(Arena *arena); +internal void df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt); +internal void df_core_end_frame(void); + +#endif // DF_CORE_H diff --git a/src/df/core/df_core.mc b/src/df/core/df_core.mc new file mode 100644 index 00000000..3845b61c --- /dev/null +++ b/src/df/core/df_core.mc @@ -0,0 +1,1891 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Config Sources + +@table(string, name, load_cmd, write_cmd, apply_cmd) +DF_CfgSrcTable: +{ + {"user" User LoadUser WriteUserData ApplyUserData } + {"profile" Profile LoadProfile WriteProfileData ApplyProfileData } + {"command_line" CommandLine Null Null Null } +} + +//////////////////////////////// +//~ rjf: Entity Kind Tables + +@table(name) +DF_NameKindTable: +{ + {Null} + {EntityName} + {EntityKindName} +} + +@table(name name_lower op_delete op_freeze op_edit op_rename op_enable op_cond op_dup lf_mut_user_cfg tr_mut_user_cfg lf_mut_prof_cfg tr_mut_prof_cfg lf_mut_halt lf_mut_dbg tr_mut_halt tr_mut_dbg name_is_code user_lifetime name_label icon_kind display_string) +DF_EntityKindTable: +{ + {Nil nil 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Nil" } + {Root root 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Root" } + {Machine machine 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Machine "Machine" } + + //- rjf: filesystem modeling + {File file 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "File" } + {OverrideFileLink override_file_link 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Override File Link" } + {PendingFileChange pending_file_change 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Pending File Change" } + + //- rjf: diagnostics log + {DiagLog diag_log 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Diagnostics Log" } + + //- rjf: text attachments + {FlashMarker flash_marker 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Flash Marker" } + + //- rjf: watch pins + {WatchPin watch_pin 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 1 "Expression" Pin "Watch Pin" } + + //- rjf: breakpoints + {Breakpoint breakpoint 1 0 0 1 1 1 1 0 0 1 0 1 0 0 0 0 1 "Label" CircleFilled "Breakpoint" } + {Condition condition 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 "Expression" CircleFilled "Condition" } + + //- rjf: targets + {Target target 1 0 1 1 1 0 1 0 0 1 0 0 0 0 0 0 1 "Label" Target "Target" } + {Executable executable 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 "Executable" Null "Executable" } + {Arguments arguments 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 "Arguments" Null "Arguments" } + {ExecutionPath execution_path 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 "Execution Path" Null "Execution Path" } + {EntryPointName entry_point_name 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 "Symbol Name" Null "Entry Point Name" } + + //- rjf: src -> dst mapping + {Source source 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Path" Null "Source" } + {Dest dest 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Path" Null "Destination" } + + //- rjf: control system entities + {CtrlRequest ctrl_request 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Control Request" } + {Process process 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Threads "Process" } + {Thread thread 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Thread "Thread" } + {Module module 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Module "Module" } + {DebugInfoOverride debug_info_override 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 "Label" Null "Debug Info Override" } + + //- rjf: parser task entities + {ConversionTask conversion_task 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Conversion Task" } + {ConversionFail conversion_fail 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Conversion Failure" } + + //- rjf: history + {EndedProcess ended_process 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "EndedProcess" } +} + +//////////////////////////////// +//~ rjf: Built-In Command Tables + +@table(name, name_lower, c_type) +DF_CmdParamSlotTable: +{ + {Window, window, `DF_Handle`} + {Panel, panel, `DF_Handle`} + {DestPanel, dest_panel, `DF_Handle`} + {PrevView, prev_view, `DF_Handle`} + {View, view, `DF_Handle`} + {Entity, entity, `DF_Handle`} + {EntityList, entity_list, `DF_HandleList`} + {String, string, `String8`} + {FilePath, file_path, `String8`} + {TextPoint, text_point, `TxtPt`} + {CmdSpec, cmd_spec, `struct DF_CmdSpec *`} + {VirtualAddr, vaddr, `U64`} + {VirtualOff, voff, `U64`} + {Index, index, `U64`} + {ID, id, `U64`} + {PreferDisassembly, prefer_dasm, `B32`} +} + +@table(name, display_string, args_desc) +DF_CmdQueryRuleTable: +{ + {Null "" "" } + {Entity "" "" } + {String "" "" } + {SearchString "" "" } + {FilePath "File Path" "" } + {TextPoint "Text Point" "[:column]" } + {FilePathAndTextPoint "Source Location" "[:line[:column]]" } + {VirtualAddr "Virtual Address" "

" } + {VirtualOff "Virtual Offset" "" } + {Index "Index" "" } + {ID "ID" "" } +} + +@table(name lister_omit keep_query old_input apply_to_view query_is_code query_slot0 query_slot1 query_slot2 query_entity_filter query_rule query_info_0_u64 query_info_1_u64 canonical_icon string display_name desc search_tags ) +DF_CoreCmdTable: +{ + {Null 1 0 0 0 0 Null Null Null Null Null 0 0 Null "" "" "" "" } + + //- rjf: exiting + {Exit 0 0 0 0 0 Null Null Null Null Null 0 0 X "exit" "Exit" "Exits the debugger." "quit,close,abort" } + + //- rjf: command fast path + {CommandFastPath 1 0 0 0 0 CmdSpec Null Null Null Null 0 0 Null "command_fast_path" "Command Fast Path" "Performs the fast path for the command named by the argument." "" } + + //- rjf: notifications + {Error 1 0 0 0 0 String Null Null Null Null 0 0 Null "error" "Error" "Notifies of an error." "" } + + //- rjf: low-level target control operations + {LaunchAndRun 0 0 0 0 0 EntityList Null Null Target Entity DF_EntityKind_Target 0 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" } + {LaunchAndInit 0 0 0 0 0 EntityList Null Null Target Entity DF_EntityKind_Target 0 PlayStepForward "launch_and_init" "Launch and Initialize" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" } + {Kill 0 0 0 0 0 EntityList Null Null Process Entity DF_EntityKind_Process 0 Stop "kill" "Kill" "Kills the specified existing debugged process(es)." "stop,kill" } + {KillAll 0 0 0 0 0 Null Null Null Null Null 0 0 Stop "kill_all" "Kill All" "Kills all debugged child processes." "stop,kill,all" } + {Detach 0 0 0 0 0 EntityList Null Null Process Entity DF_EntityKind_Process 0 Null "detach" "Detach" "Detaches the specified debugged process." "detach" } + {Continue 0 0 0 0 0 Null Null Null Null Null 0 0 Play "continue" "Continue" "Continues all halted threads." "" } + {StepIntoInst 0 0 0 0 0 Entity Null Null Null Null 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" } + {StepOverInst 0 0 0 0 0 Entity Null Null Null Null 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" } + {StepIntoLine 0 0 0 0 0 Entity Null Null Null Null 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" } + {StepOverLine 0 0 0 0 0 Entity Null Null Null Null 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" } + {StepOut 0 0 0 0 0 Entity Null Null Null Null 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" } + {RunToAddress 0 0 0 0 0 Entity VirtualAddr Null Thread VirtualAddr 0 0 PlayStepForward "run_to_address" "Run To Address" "Runs the selected thread to the specified address." "" } + {RunToModuleOffset 0 0 0 0 0 Entity VirtualOff Null Thread VirtualOff 0 0 PlayStepForward "run_to_module_offset" "Run To Module Offset" "Runs the selected thread to the specified offset within the current module." "" } + {Halt 0 0 0 0 0 Null Null Null Null Null 0 0 Pause "halt" "Halt" "Halts all running processes." "pause" } + {SoftHaltRefresh 0 0 0 0 0 Null Null Null Null Null 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all running processes to collect data, and then resumes them." "" } + {SetThreadIP 1 0 0 0 0 Entity VirtualAddr Null Null Null 0 0 Null "set_thread_ip" "Set Thread IP" "Sets the passed thread's instruction pointer at the passed address." "" } + + //- rjf: high-level composite target control operations + {Run 0 0 0 0 0 Null Null Null Null Null 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" } + {Restart 0 0 0 0 0 Null Null Null Null Null 0 0 Redo "restart" "Restart" "Kills all running processes, then restarts the targets which were used to launch all current processes (if any)." "restart,retry" } + {StepInto 0 0 0 0 0 Entity Null Null Thread Null 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either line or instructions." "" } + {StepOver 0 0 0 0 0 Entity Null Null Thread Null 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either line or instructions." "" } + {RunToCursor 0 0 0 0 0 Entity View Null Thread Null 0 0 Play "run_to_cursor" "Run To Cursor" "Runs the selected thread to the current cursor." "" } + {SetNextStatement 0 0 0 0 0 Entity View Null Thread Null 0 0 RightArrow "set_next_statement" "Set Next Statement" "Sets the selected thread's instruction pointer to the cursor's position." "" } + + //- rjf: solo stepping mode + {EnableSoloSteppingMode 0 0 0 0 0 Null Null Null Null Null 0 0 Thread "enable_solo_stepping_mode" "Enable Solo Stepping Mode" "Enables 'solo stepping mode', which suspends all non-selected threads before stepping." "solo,stepping,mode,suspend" } + {DisableSoloSteppingMode 0 0 0 0 0 Null Null Null Null Null 0 0 Thread "disable_solo_stepping_mode" "Disable Solo Stepping Mode" "Disables 'solo stepping mode', which suspends all non-selected threads before stepping." "solo,stepping,mode,suspend" } + + //- rjf: debug control context management operations + {SelectThread 0 0 0 0 0 Entity Null Null Thread Entity DF_EntityKind_Thread 0 Null "select_thread" "Select Thread" "Selects a thread." "" } + {SelectThreadWindow 0 0 0 0 0 Entity Window Null Thread Entity DF_EntityKind_Thread 0 Null "select_thread_window" "Select Thread On Window" "Selects a thread for the active window, overriding the global selected thread." "" } + {SelectThreadView 0 0 0 0 0 Entity View Null Thread Entity DF_EntityKind_Thread 0 Null "select_thread_view" "Select Thread On View" "Selects a thread for the active view, overriding the global and per-window selected threads." "" } + {SelectUnwind 1 0 0 0 0 Index Null Null Null Null 0 0 Null "select_unwind" "Select Unwind" "Selects an unwind frame number for the selected thread." "" } + {UpOneFrame 0 0 0 0 0 Null Null Null Null Null 0 0 UpArrow "up_one_frame" "Up One Frame" "Selects the callstack frame above the currently selected." "" } + {DownOneFrame 0 0 0 0 0 Null Null Null Null Null 0 0 DownArrow "down_one_frame" "Down One Frame" "Selects the callstack frame below the currently selected." "" } + {FreezeThread 0 0 0 0 0 Entity Null Null Thread Entity DF_EntityKind_Thread 0 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "" } + {ThawThread 0 0 0 0 0 Entity Null Null Thread Entity DF_EntityKind_Thread 0 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" } + {FreezeProcess 0 0 0 0 0 Entity Null Null Process Entity DF_EntityKind_Process 0 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" } + {ThawProcess 0 0 0 0 0 Entity Null Null Process Entity DF_EntityKind_Process 0 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" } + {FreezeMachine 1 0 0 0 0 Entity Null Null Machine Entity DF_EntityKind_Machine 0 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" } + {ThawMachine 1 0 0 0 0 Entity Null Null Machine Entity DF_EntityKind_Machine 0 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" } + {FreezeLocalMachine 0 0 0 0 0 Null Null Null Null Null 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" } + {ThawLocalMachine 0 0 0 0 0 Null Null Null Null Null 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" } + + //- rjf: font sizes + {IncUIFontScale 0 0 0 0 0 Window Null Null Null Null 0 0 Null "inc_ui_font_scale" "Increase UI Font Scale" "Increases the font size used for UI." "" } + {DecUIFontScale 0 0 0 0 0 Window Null Null Null Null 0 0 Null "dec_ui_font_scale" "Decrease UI Font Scale" "Decreases the font size used for UI." "" } + {IncCodeFontScale 0 0 0 0 0 Window Null Null Null Null 0 0 Null "inc_code_font_scale" "Increase Code Font Scale" "Increases the font size used for code." "" } + {DecCodeFontScale 0 0 0 0 0 Window Null Null Null Null 0 0 Null "dec_code_font_scale" "Decrease Code Font Scale" "Decreases the font size used for code." "" } + + //- rjf: windows + {OpenWindow 0 0 0 0 0 Null Null Null Null Null 0 0 Window "open_window" "Open New Window" "Opens a new window." "" } + {CloseWindow 0 0 0 0 0 Window Null Null Null Null 0 0 Window "close_window" "Close Window" "Closes an opened window." "" } + {ToggleFullscreen 0 0 0 0 0 Window Null Null Null Null 0 0 Window "toggle_fullscreen" "Toggle Fullscreen" "Toggles fullscreen view on the active window." "" } + + //- rjf: panel splitting + {ResetToDefaultPanels 0 0 0 0 0 Window Null Null Null Null 0 0 Window "reset_to_default_panels" "Reset To Default Panel Layout" "Resets the window to the default panel layout." "panel" } + {NewPanelRight 0 0 0 0 0 Window Panel Null Null Null 0 0 XSplit "new_panel_right" "Split Panel Vertically" "Creates a new panel to the right of the active panel." "panel" } + {NewPanelDown 0 0 0 0 0 Window Panel Null Null Null 0 0 YSplit "new_panel_down" "Split Panel Horizontally" "Creates a new panel at the bottom of the active panel." "panel" } + + //- rjf: panel rotation + {RotatePanelColumns 0 0 0 0 0 Window Panel Null Null Null 0 0 Null "rotate_panel_columns" "Rotate Panel Columns" "Rotates all panels at the closest column level of the panel hierarchy." "" } + + //- rjf: focused panel changing + {NextPanel 0 0 0 0 0 Window Null Null Null Null 0 0 RightArrow "next_panel" "Focus Next Panel" "Cycles the active panel forward." "" } + {PrevPanel 0 0 0 0 0 Window Null Null Null Null 0 0 LeftArrow "prev_panel" "Focus Previous Panel" "Cycles the active panel backwards." "" } + {FocusPanel 1 0 0 0 0 Window Panel Null Null Null 0 0 Null "focus_panel" "Focus Panel" "Focuses a new panel." "" } + {FocusPanelRight 0 0 0 0 0 Window Null Null Null Null 0 0 RightArrow "focus_panel_right" "Focus Panel Right" "Focuses a panel rightward of the currently focused panel." "" } + {FocusPanelLeft 0 0 0 0 0 Window Null Null Null Null 0 0 LeftArrow "focus_panel_left" "Focus Panel Left" "Focuses a panel leftward of the currently focused panel." "" } + {FocusPanelUp 0 0 0 0 0 Window Null Null Null Null 0 0 UpArrow "focus_panel_up" "Focus Panel Up" "Focuses a panel upward of the currently focused panel." "" } + {FocusPanelDown 0 0 0 0 0 Window Null Null Null Null 0 0 DownArrow "focus_panel_down" "Focus Panel Down" "Focuses a panel downward of the currently focused panel." "" } + + //- rjf: undo/redo + {Undo 1 0 0 0 0 Null Null Null Null Null 0 0 Undo "undo" "Undo" "Undoes the previous action." "" } + {Redo 1 0 0 0 0 Null Null Null Null Null 0 0 Redo "redo" "Redo" "Redoes the first previously undone action." "" } + + //- rjf: focus history + {GoBack 1 0 0 0 0 Window Panel Null Null Null 0 0 LeftArrow "go_back" "Go Back" "Returns to the previously selected panel and tab in recorded history." "" } + {GoForward 1 0 0 0 0 Window Panel Null Null Null 0 0 RightArrow "go_forward" "Go Forward" "Returns to the next selected panel and tab in recorded history." "" } + + //- rjf: panel removal + {ClosePanel 0 0 0 0 0 Window Panel Null Null Null 0 0 ClosePanel "close_panel" "Close Panel" "Closes the currently active panel." "" } + + //- rjf: panel tab + {NextTab 0 0 0 0 0 Null Null Null Null Null 0 0 RightArrow "next_tab" "Focus Next Tab" "Focuses the next tab on the active panel." "" } + {PrevTab 0 0 0 0 0 Null Null Null Null Null 0 0 LeftArrow "prev_tab" "Focus Previous Tab" "Focuses the previous tab on the active panel." "" } + {MoveTabRight 0 0 0 0 0 Null Null Null Null Null 0 0 RightArrow "move_tab_right" "Move Tab Right" "Moves the selected tab right one slot." "" } + {MoveTabLeft 0 0 0 0 0 Null Null Null Null Null 0 0 LeftArrow "move_tab_left" "Move Tab Left" "Moves the selected tab left one slot." "" } + {CloseTab 0 0 0 0 0 Null Null Null Null Null 0 0 X "close_tab" "Close Tab" "Closes the currently opened tab." "" } + {MoveTab 1 0 0 0 0 Null Null Null Null Null 0 0 Null "move_tab" "Move Tab" "Moves a tab to a new panel." "" } + {TabBarTop 0 0 0 0 0 Null Null Null Null Null 0 0 UpArrow "tab_bar_top" "Anchor Tab Bar To Top" "Anchors a panel's tab bar to the top of the panel." "" } + {TabBarBottom 0 0 0 0 0 Null Null Null Null Null 0 0 DownArrow "tab_bar_bottom" "Anchor Tab Bar To Bottom" "Anchors a panel's tab bar to the bottom of the panel." "" } + {TabBarEnable 0 0 0 0 0 Null Null Null Null Null 0 0 Null "tab_bar_enable" "Enable Tab Bar" "Enables a panel's tab bar." "" } + {TabBarDisable 0 0 0 0 0 Null Null Null Null Null 0 0 Null "tab_bar_disable" "Disable Tab Bar" "Disables a panel's tab bar." "" } + {TabBarHistoryModeEnable 0 0 0 0 0 Null Null Null Null Null 0 0 Null "tab_bar_history_mode_enable" "Enable Tab Bar History Mode" "Enables history mode for a panel's tab bar, which orders and manages tabs as recorded history of views." "" } + {TabBarHistoryModeDisable 0 0 0 0 0 Null Null Null Null Null 0 0 Null "tab_bar_history_mode_disable""Disable Tab Bar History Mode" "Disables history mode for a panel's tab bar." "" } + + //- rjf: files + {SetCurrentPath 0 0 0 0 0 FilePath Null Null Null FilePath 0 0 FileOutline "set_current_path" "Set Current Path" "Sets the debugger's current path, which is used as a starting point when browsing for files." "" } + {Open 0 0 0 0 0 FilePath Null Null Null FilePath 0 0 FileOutline "open" "Open" "Opens a file." "code,source,file" } + {Reload 0 0 0 0 0 Entity Null Null File Entity DF_EntityKind_File 0 FileOutline "reload" "Reload" "Reloads a loaded file." "code,source,file,reload" } + {ReloadActive 0 0 0 0 0 Window Panel Null Null Null 0 0 FileOutline "reload_active" "Reload Active File" "Reloads the active file." "code,source,file,reload" } + {Switch 0 0 0 0 0 Window Panel Entity File Entity DF_EntityKind_File DF_EntityFlag_IsFolder FileOutline "switch" "Switch" "Switches to a loaded file." "code,source,file" } + + //- rjf: override file links + {SetFileOverrideLinkSrc 1 0 0 0 0 Null Null Null Null Null 0 0 Null "set_file_override_link_src" "Set File Override Link Source" "Sets the source path for an override file link." "" } + {SetFileOverrideLinkDst 1 0 0 0 0 Null Null Null Null Null 0 0 Null "set_file_override_link_dst" "Set File Override Link Destination" "Sets the destination path for an override file link." "" } + {SetFileReplacementPath 1 0 0 0 0 Null Null Null Null Null 0 0 Null "set_file_replacement_path" "Set File Replacement Path" "Sets the path which should be used as the replacement for the passed file." "" } + + //- rjf: setting config paths + {LoadUser 0 0 0 0 0 FilePath Null Null Null FilePath 0 0 Person "load_user" "Load User" "Loads and applies a user file." "load,user,profile,layout" } + {LoadProfile 0 0 0 0 0 FilePath Null Null Null FilePath 0 0 Briefcase "load_profile" "Load Profile" "Loads and applies a profile file." "profile,project,session" } + + //- rjf: loading/applying stateful config changes + {ApplyUserData 1 0 0 0 0 Null Null Null Null Null 0 0 Null "apply_user_data" "Apply User Data" "Applies user data from the active user file." "" } + {ApplyProfileData 1 0 0 0 0 Null Null Null Null Null 0 0 Null "apply_profile_data" "Apply Profile Data" "Applies profile data from the active profile file." "" } + + //- rjf: writing config changes + {WriteUserData 1 0 0 0 0 Null Null Null Null Null 0 0 Null "write_user_data" "Write User Data" "Writes user data to the active user file." "" } + {WriteProfileData 1 0 0 0 0 Null Null Null Null Null 0 0 Null "write_profile_data" "Write Profile Data" "Writes profile data to the active profile file." "" } + + //- rjf: directional movement & text controls + {MoveLeft 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_left" "Move Left" "Moves the cursor or selection left." "" } + {MoveRight 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_right" "Move Right" "Moves the cursor or selection right." "" } + {MoveUp 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up" "Move Up" "Moves the cursor or selection up." "" } + {MoveDown 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down" "Move Down" "Moves the cursor or selection down." "" } + {MoveLeftSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_left_select" "Move Left Select" "Moves the cursor or selection left, while selecting." "" } + {MoveRightSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_right_select" "Move Right Select" "Moves the cursor or selection right, while selecting." "" } + {MoveUpSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up_select" "Move Up Select" "Moves the cursor or selection up, while selecting." "" } + {MoveDownSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down_select" "Move Down Select" "Moves the cursor or selection down, while selecting." "" } + {MoveLeftChunk 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_left_chunk" "Move Left Select" "Moves the cursor or selection left one chunk." "" } + {MoveRightChunk 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_right_chunk" "Move Right Select" "Moves the cursor or selection right one chunk." "" } + {MoveUpChunk 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up_chunk" "Move Up Chunk" "Moves the cursor or selection up one chunk." "" } + {MoveDownChunk 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down_chunk" "Move Down Chunk" "Moves the cursor or selection down one chunk." "" } + {MoveUpPage 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up_page" "Move Up Page" "Moves the cursor or selection up one page." "" } + {MoveDownPage 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down_page" "Move Down Page" "Moves the cursor or selection down one page." "" } + {MoveUpWhole 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up_whole" "Move Up Whole" "Moves the cursor or selection to the beginning of the relevant content." "" } + {MoveDownWhole 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down_whole" "Move Down Whole" "Moves the cursor or selection to the end of the relevant content." "" } + {MoveLeftChunkSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_left_chunk_select" "Move Left Chunk Select" "Moves the cursor or selection left one chunk." "" } + {MoveRightChunkSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_right_chunk_select" "Move Right Chunk Select" "Moves the cursor or selection right one chunk." "" } + {MoveUpChunkSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up_chunk_select" "Move Up Chunk Select" "Moves the cursor or selection up one chunk." "" } + {MoveDownChunkSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down_chunk_select" "Move Down Chunk Select" "Moves the cursor or selection down one chunk." "" } + {MoveUpPageSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up_page_select" "Move Up Page Select" "Moves the cursor or selection up one page, while selecting." "" } + {MoveDownPageSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down_page_select" "Move Down Page Select" "Moves the cursor or selection down one page, while selecting." "" } + {MoveUpWholeSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_up_whole_select" "Move Up Whole Select" "Moves the cursor or selection to the beginning of the relevant content, while selecting." "" } + {MoveDownWholeSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_down_whole_select" "Move Down Whole Select" "Moves the cursor or selection to the end of the relevant content, while selecting." "" } + {MoveHome 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_home" "Move Home" "Moves the cursor to the beginning of the line." "" } + {MoveEnd 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_end" "Move End" "Moves the cursor to the end of the line." "" } + {MoveHomeSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_home_select" "Move Home Select" "Moves the cursor to the beginning of the line, while selecting." "" } + {MoveEndSelect 0 0 0 0 0 Null Null Null Null Null 0 0 Null "move_end_select" "Move End Select" "Moves the cursor to the end of the line, while selecting." "" } + {SelectAll 0 0 0 0 0 Null Null Null Null Null 0 0 Null "select_all" "Select All" "Selects everything possible." "" } + {DeleteSingle 0 0 0 0 0 Null Null Null Null Null 0 0 Null "delete_single" "Delete Single" "Deletes a single element to the right of the cursor, or the active selection." "" } + {DeleteChunk 0 0 0 0 0 Null Null Null Null Null 0 0 Null "delete_chunk" "Delete Chunk" "Deletes a chunk to the right of the cursor, or the active selection." "" } + {BackspaceSingle 0 0 0 0 0 Null Null Null Null Null 0 0 Null "backspace_single" "Backspace Single" "Deletes a single element to the left of the cursor, or the active selection." "" } + {BackspaceChunk 0 0 0 0 0 Null Null Null Null Null 0 0 Null "backspace_chunk" "Backspace Chunk" "Deletes a chunk to the left of the cursor, or the active selection." "" } + {Copy 0 0 0 0 0 Null Null Null Null Null 0 0 Clipboard "copy" "Copy" "Copies the active selection to the clipboard." "" } + {Cut 0 0 0 0 0 Null Null Null Null Null 0 0 Clipboard "cut" "Cut" "Copies the active selection to the clipboard, then deletes it." "" } + {Paste 0 0 0 0 0 Null Null Null Null Null 0 0 Clipboard "paste" "Paste" "Pastes the current contents of the clipboard." "" } + {InsertText 1 0 0 0 0 Null Null Null Null Null 0 0 Null "insert_text" "Insert Text" "Inserts the text that was used to cause this command." "" } + + //- rjf: code navigation + {GoToLine 0 0 0 1 0 TextPoint Null Null Null TextPoint 0 0 Null "goto_line" "Go To Line" "Jumps to a line number in the current code file." "" } + {GoToAddress 0 0 0 1 1 VirtualAddr Null Null Null VirtualAddr 0 0 Null "goto_address" "Go To Address" "Jumps to an address in the current memory or disassembly view." "" } + {CenterCursor 0 0 0 0 0 Null Null Null Null Null 0 0 Null "center_cursor" "Center Cursor" "Snaps the current code view to center the cursor." "" } + {ContainCursor 0 0 0 0 0 Null Null Null Null Null 0 0 Null "contain_cursor" "Contain Cursor" "Snaps the current code view to contain the cursor." "" } + {FindTextForward 0 1 1 1 1 String Null Null Null SearchString 0 0 Find "find_text_forward" "Find Text (Forward)" "Searches the current code file forward (from the cursor) for a string." "" } + {FindTextBackward 0 1 1 1 1 String Null Null Null SearchString 0 0 Find "find_text_backward" "Find Text (Backwards)" "Searches the current code file backwards (from the cursor) for a string." "" } + {FindNext 0 1 1 1 0 String Null Null Null Null 0 0 Find "find_next" "Find Next" "Searches the current code file forward (from the cursor) for the last searched string." "" } + {FindPrev 0 1 1 1 0 String Null Null Null Null 0 0 Find "find_prev" "Find Previous" "Searches the current code file backwards (from the cursor) for the last searched string." "" } + + //- rjf: thread finding + {FindThread 0 0 0 0 0 Entity Null Null Thread Entity DF_EntityKind_Thread 0 Find "find_thread" "Find Thread" "Jumps to the passed thread in either source code, disassembly, or both if they're already open." "" } + {FindSelectedThread 0 0 0 0 0 Null Null Null Null Null 0 0 Find "find_selected_thread" "Find Selected Thread" "Jumps to the selected thread in either source code, disassembly, or both if they're already open." "" } + + //- rjf: name finding + {GoToName 0 0 0 0 1 Null Null Null Null String 0 0 Null "goto_name" "Go To Name" "Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible." "" } + {GoToNameAtCursor 0 0 0 0 0 Null Null Null Null Null 0 0 Null "goto_name_at_cursor" "Go To Name At Cursor" "Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible." "" } + + //- rjf: watch expressions + {ToggleWatchExpression 0 0 0 0 0 Null Null Null Null Null 0 0 Binoculars "toggle_watch_expr" "Toggle Watch Expression" "Adds or removes an expression to an opened watch view." "" } + {ToggleWatchExpressionAtCursor 0 0 0 0 0 Null Null Null Null Null 0 0 Binoculars "toggle_watch_expr_at_cursor" "Toggle Watch Expression At Cursor" "Adds or removes the expression that the cursor or selection is currently over to an opened watch view." "" } + + //- rjf: memory openers + {OpenFileMemory 0 0 0 0 0 Entity Null Null File Entity DF_EntityKind_File 0 Grid "open_file_memory" "Open File Memory" "Opens a memory view for the passed file." "" } + {OpenProcessMemory 0 0 0 0 0 Entity Null Null Process Entity DF_EntityKind_Process 0 Grid "open_process_memory" "Open Process Memory" "Opens a memory view for the passed process." "" } + {OpenSelectedProcessMemory 0 0 0 0 0 Null Null Null Null Null 0 0 Grid "open_selected_process_memory""Open Selected Process Memory" "Opens a memory view for the selected process." "" } + + //- rjf: memory view parameterization + {SetColumns 0 0 0 1 0 Index Null Null Null Index 0 0 Thumbnails "set_columns" "Set Columns" "Sets the number of columns for a memory view." "" } + + //- rjf: disassembly view parameterization + {ToggleAddressVisibility 0 0 0 1 0 Null Null Null Null Null 0 0 Thumbnails "toggle_address_visibility" "Toggle Address Visibility" "Toggles the visibility of addresses in a disassembly view." "" } + {ToggleCodeBytesVisibility 0 0 0 1 0 Null Null Null Null Null 0 0 Thumbnails "toggle_code_bytes_visibility""Toggle Code Bytes Visibility" "Toggles the visibility of machine code bytes in a disassembly view." "" } + + //- rjf: general entity operations + {EnableEntity 1 0 0 0 0 Null Null Null Null Null 0 0 Null "enable_entity" "Enable Entity" "Enables an entity." "" } + {DisableEntity 1 0 0 0 0 Null Null Null Null Null 0 0 Null "disable_entity" "Disable Entity" "Disables an entity." "" } + {FreezeEntity 1 0 0 0 0 Null Null Null Null Null 0 0 Null "freeze_entity" "Freeze Entity" "Freezes an entity." "" } + {ThawEntity 1 0 0 0 0 Null Null Null Null Null 0 0 Null "thaw_entity" "Thaw Entity" "Thaws an entity." "" } + {RemoveEntity 1 0 0 0 0 Null Null Null Null Null 0 0 Null "remove_entity" "Remove Entity" "Removes an entity." "" } + {NameEntity 1 0 0 0 0 Entity String Null Null Null 0 0 Null "name_entity" "Name Entity" "Equips an entity with a name." "" } + {EditEntity 1 0 0 0 0 Null Null Null Null Null 0 0 Null "edit_entity" "Edit Entity" "Opens the editor for an entity." "" } + {DuplicateEntity 1 0 0 0 0 Null Null Null Null Null 0 0 Null "duplicate_entity" "Duplicate Entity" "Duplicates an entity." "" } + + //- rjf: breakpoints + {TextBreakpoint 1 0 0 0 0 Null Null Null Null Null 0 0 CircleFilled "text_breakpoint" "Text Breakpoint" "Places or removes a breakpoint on the specified line of source code." "" } + {AddressBreakpoint 0 0 0 0 1 VirtualAddr Null Null Null VirtualAddr 0 0 CircleFilled "address_breakpoint" "Address Breakpoint" "Places or removes a breakpoint on the specified address." "" } + {FunctionBreakpoint 0 0 0 0 1 String Null Null Null String 0 0 CircleFilled "function_breakpoint" "Function Breakpoint" "Places or removes a breakpoint on the first address(es) of the specified function." "" } + {ToggleBreakpointAtCursor 0 0 0 0 0 Null Null Null Null Null 0 0 CircleFilled "toggle_breakpoint_cursor" "Toggle Breakpoint At Cursor" "Places or removes a breakpoint on the line on which the active cursor sits." "" } + {RemoveBreakpoint 0 0 0 0 0 Entity Null Null Breakpoint Entity DF_EntityKind_Breakpoint 0 Trash "remove_breakpoint" "Remove Breakpoint" "Removes an existing breakpoint." "" } + {EnableBreakpoint 0 0 0 0 0 Entity Null Null Breakpoint Entity DF_EntityKind_Breakpoint 0 CheckFilled "enable_breakpoint" "Enable Breakpoint" "Enables a breakpoint." "" } + {DisableBreakpoint 0 0 0 0 0 Entity Null Null Breakpoint Entity DF_EntityKind_Breakpoint 0 CheckHollow "disable_breakpoint" "Disable Breakpoint" "Disables a breakpoint." "" } + + //- rjf: watches + {ToggleWatchPin 1 0 0 0 1 Entity TextPoint String Null String 0 0 Binoculars "toggle_watch_pin" "Toggle Watch Pin" "Places or removes a watch pin on a textual location on a particular entity." "" } + {ToggleWatchPinAtCursor 0 0 0 1 1 String Null Null Null String 0 0 Binoculars "toggle_watch_pin_at_cursor" "Toggle Watch Pin At Cursor" "Places or removes a watch pin at the cursor on the currently active file." "" } + + //- rjf: targets + {AddTarget 0 0 0 0 0 FilePath Null Null Null FilePath 0 0 Target "add_target" "Add Target" "Adds a new target." "application,executable,debug" } + {RemoveTarget 0 0 0 0 0 Entity Null Null Target Entity DF_EntityKind_Target 0 Trash "remove_target" "Remove Target" "Removes an existing target." "delete,remove,target" } + {EditTarget 0 0 0 0 0 Entity Null Null Target Entity DF_EntityKind_Target 0 Pencil "edit_target" "Edit Target" "Edits an existing target." "" } + + //- rjf: ended processes + {RetryEndedProcess 1 0 0 0 0 Entity Null Null EndedProcess Entity DF_EntityKind_EndedProcess 0 Null "retry_ended_process" "Retry Ended Process" "Launches a new process with the same options as the passed ended process." "" } + + //- rjf: attaching + {Attach 0 0 0 0 0 String Null Null Null String 0 0 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" } + {RegisterAsJITDebugger 0 0 0 0 0 Null Null Null Null Null 0 0 Null "register_as_jit_debugger" "Register As Just-In-Time (JIT) Debugger" "Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system." "" } + + //- rjf: catchall general entity activation paths (drag/drop, clicking) + {EntityRefFastPath 1 0 0 0 0 Null Null Null Null Null 0 0 Null "entity_ref_fast_path" "Entity Reference Fast Path" "Activates the default behavior when clicking an entity reference." "" } + {SpawnEntityView 1 0 0 0 0 Null Null Null Null Null 0 0 Null "spawn_entity_view" "Spawn Entity View" "Spawns a new view, given an entity and other parameterizations." "" } + {FindCodeLocation 0 0 0 0 0 FilePath TextPoint Null Null FilePathAndTextPoint 0 0 FileOutline "find_code_location" "Find Code Location" "Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary." "" } + + //- rjf: view drivers + {Commands 0 0 0 0 0 Null Null Null Null String 0 0 List "commands" "Commands" "Opens the list of all commands." "" } + {Target 1 0 0 0 0 Null Null Null Null Null 0 0 Target "target_editor" "Target" "Opens the editor for a target." "" } + {Targets 0 0 0 0 0 Null Null Null Null Null 0 0 Target "targets" "Targets" "Opens the list of all targets." "" } + {FilePathMap 0 0 0 0 0 Null Null Null Null Null 0 0 FileOutline "file_path_map" "File Path Map" "Opens the file path mapping editor." "" } + {Scheduler 0 0 0 0 0 Null Null Null Null Null 0 0 Scheduler "scheduler" "Scheduler" "Opens the scheduler view, for process and thread controls." "" } + {CallStack 0 0 0 0 0 Null Null Null Null Null 0 0 Thread "call_stack" "Call Stack" "Opens the call stack view." "callstack,thread" } + {Modules 0 0 0 0 0 Null Null Null Null Null 0 0 Module "modules" "Modules" "Opens the modules view." "" } + {PendingEntity 1 0 0 0 0 Null Null Null Null Null 0 0 FileOutline "pending_entity" "Pending Entity" "Opens a view which waits for the passed entity to be completely loaded, then replaces itself with a new view." "" } + {Code 1 0 0 0 0 Null Null Null Null Null 0 0 FileOutline "code" "Code" "Opens the code view for an already-loaded file." "" } + {Watch 0 0 0 0 0 Null Null Null Null Null 0 0 Binoculars "watch" "Watch" "Opens a watch view." "" } + {Locals 0 0 0 0 0 Null Null Null Null Null 0 0 Binoculars "locals" "Locals" "Opens a locals view." "" } + {Registers 0 0 0 0 0 Null Null Null Null Null 0 0 Binoculars "registers" "Registers" "Opens a registers view for the currently selected thread." "" } + {Output 0 0 0 0 0 Null Null Null Null Null 0 0 List "output" "Output" "Opens an output view." "" } + {Memory 0 0 0 0 0 Null Null Null Null Null 0 0 Grid "memory" "Memory" "Opens a memory view." "" } + {Disassembly 0 0 0 0 0 Null Null Null Null Null 0 0 Glasses "disassembly" "Disassembly" "Opens the disassembly view." "disasm" } + {Breakpoints 0 0 0 0 0 Null Null Null Null Null 0 0 CircleFilled "breakpoints" "Breakpoints" "Opens the breakpoints view." "" } + {WatchPins 0 0 0 0 0 Null Null Null Null Null 0 0 Pin "watch_pins" "Watch Pins" "Opens the watch pins view." "" } + {ExceptionFilters 0 0 0 0 0 Null Null Null Null Null 0 0 Gear "exception_filters" "Exception Filters" "Opens the exception filters view." "exceptions,filters" } + {Theme 0 0 0 0 0 Null Null Null Null Null 0 0 Palette "theme" "Theme" "Opens the theme view." "theme,color,scheme,palette" } + {PickFile 1 0 0 1 0 FilePath Null Null Null FilePath 0 0 FileOutline "pick_file" "Pick File" "Opens the file browser to pick a file." "" } + + //- rjf: core pass-through view result commands + {ViewReturn 1 0 0 0 0 Null Null Null Null Null 0 0 Null "complete_view" "Complete View" "Completes a view, passing all parameters to a new command matching the passed command spec." "" } + + //- rjf: developer commands + {ToggleDevMenu 0 0 0 0 0 Null Null Null Null Null 0 0 Null "toggle_dev_menu" "Toggle Developer Menu" "Opens and closes the developer menu." "" } +} + +//////////////////////////////// +//~ rjf: Built-In View Rules +// +// @view_rule_info +// +// NOTE(rjf): View rules are subtle in that they may impact any subset of the +// eval visualization pipeline. The "array" view rule, for example, functions +// by tweaking the type of an eval from `X *` to `X (*)[N]` (where N is +// computed from whatever expression is specified by the view rule). The "list" +// view rule, on the other hand, does not require any changes to the actual +// eval nor its type - instead, it follows an alternative path in constructing +// "viz blocks", and then constructing "viz rows" from those blocks. Compare +// these to the simpler 'dec', 'bin', or 'oct' rules, which simply tweak the +// radix used when stringizing numbers, which is something that only occurs in +// single-line eval stringization building. +// +// As such, each view rule specification has a mask, which determines which +// stages it may be used for. For a given view rule specification, if the bit +// corresponding to a particular eval stage is set, then that view rule spec- +// -ification also includes a hook which can be called from that stage. +// +// Below is a list of the stages in the eval visualization pipeline, as well as +// abbreviations which are used in the tables. +// +// eval resolution, "er" -> provides a chance for a view rule to impact an eval +// value or type, before the rest of the eval visual +// pipeline continues. +// +// viz block prod, "vb" -> given a resolved eval, produce a list of non- +// windowed "viz blocks", which correspond to one or +// many contiguous rows in a watch-window-style UI. +// one level of expanded struct members, with no sub- +// expansions, would be one viz block. if one of those +// members - in the middle - were expanded too, then +// it would require three viz blocks - one for the +// members before the sub-expansion, one for the +// sub expansion members, and one for the members +// after, and so on. this is done recursively. +// +// viz row prod, "vr" -> given a list of viz blocks, a windowed list of viz +// rows may be produced. each of these rows has info +// for building actual UI in e.g. a watch window - +// whether or not the row can be expanded, whether or +// not the row's value can be edited, what the edit- +// able string is for a row, what the display string +// is for a row, what the expression string is for a +// row, what the type is for a row, and so on. +// +// line stringize, "ls" -> this is the stage used to produce display strings +// in the "viz row prod" stage, as well as basically +// any time UI needs to display the result of an eval +// in a single line. this also occurs recursively, +// descending into members & elements as needed, +// constrained by # of available pixels and font size +// and so on. +// +// row ui build, "ru" -> finally, after the previous stages are completed, +// ui can finally be built according to all of the +// per-row information produced. this is the stage +// where view rules can insert their own arbitrary ui +// on a per-row basis. +// +// block ui build, "bu" -> sometimes, view rules want to take over an entire +// viz block. while those viz blocks will still be +// used to size a collapsed region in terms of #-of- +// rows, this stage offers the ability to build a ui +// stretching over all of the rows. +// +// A few other bits are included for various ways in which a view rule may be +// applied throughout the eval visualization pipeline. A list follows: +// +// inherited, "ih" -> is this view rule included, or not included, in +// child expansions? +// +// expandable, "ex" -> does this view rule force the ability to expand +// an expression, even if traditional analysis of type +// info would not allow expansion? +// +// Not all of these stages are specified at this layer, however, since the +// "df_core" layer is for the non-graphical core debugger features. So the +// information pertaining to the eval visualization pipeline stages which +// do require graphical subsystems (e.g. UI, fonts, rendering) are specified +// in the "df_gfx" layer. +// +// For any view rules in this layer which also have graphical features, they +// are specified in both tables under the same name. + +@table(name name_lower string ih ex er vb display_name docs description) +DF_CoreViewRuleTable: +{ + {Null null "" - - - - "" - "" } + {Array array "array" - - x - "Array" x "Specifies that a pointer points to N elements, rather than only 1." } + {List list "list" - - - x "List" x "Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list." } + {ByteSwap bswap "bswap" x - x - "Byte Swap" x "Specifies that all integer primitives should be byte-swapped, such that their endianness is reversed." } + {BaseDec base_dec "dec" x - - - "Decimal Base (Base 10)" x "Specifies that all integral evaluations should appear in base-10 form." } + {BaseBin base_bin "bin" x - - - "Binary Base (Base 2)" x "Specifies that all integral evaluations should appear in base-2 form." } + {BaseOct base_oct "oct" x - - - "Octal Base (Base 8)" x "Specifies that all integral evaluations should appear in base-8 form." } + {BaseHex base_hex "hex" x - - - "Hexadecimal Base (Base 16)" x "Specifies that all integral evaluations should appear in base-16 form." } + {Only only "only" x - - x "Only Specified Members" x "Specifies that only the specified members should appear in struct, union, or class evaluations." } + {Omit omit "omit" x - - x "Omit Specified Members" x "Omits a list of member names from appearing in struct, union, or class evaluations." } + {NoAddr no_addr "no_addr" x - - - "Disable Address Values" x "Displays only what pointers point to, if possible, without the pointer's address value." } + {RGBA rgba "rgba" - x - x "Color (RGBA)" x "Displays as a color, interpreting the data as encoding R, G, B, and A values." } + {Text text "text" - x - x "Text" x "Displays as text." } + {Disasm disasm "disasm" - x - x "Disassembly" x "Displays as disassembled instructions, interpreting the data as raw machine code." } + {Bitmap bitmap "bitmap" - x - x "Bitmap" x "Displays as a bitmap, interpreting the data as raw pixel data." } + {Geo geo "geo" - x - x "Geometry" x "Displays as geometry, interpreting the data as vertex data." } +} + +//////////////////////////////// +//~ rjf: Icons (TODO(rjf): this needs to move to the df_gfx graphical layer) + +@table(name, text) +DF_IconTable: +{ + (Null "") + (FolderOpenOutline "b") + (FolderClosedOutline "c") + (FolderOpenFilled "B") + (FolderClosedFilled "C") + (FileOutline "f") + (FileFilled "F") + (Play "g") + (PlayStepForward "h") + (Pause "r") + (Stop "s") + (Info "i") + (WarningSmall "w") + (WarningBig "W") + (Unlocked "k") + (Locked "K") + (LeftArrow "L") + (RightArrow "R") + (UpArrow "U") + (DownArrow "D") + (Gear "G") + (Pencil "P") + (Trash "3") + (Pin "p") + (RadioHollow "O") + (RadioFilled "o") + (CheckHollow "!") + (CheckFilled "1") + (LeftCaret "<") + (RightCaret ">") + (UpCaret "^") + (DownCaret "v") + (UpScroll "9") + (DownScroll "0") + (LeftScroll "7") + (RightScroll "8") + (Add "+") + (Minus "-") + (Thread "'") + (Threads '\\"') + (Machine "M") + (CircleFilled ".") + (X "x") + (Refresh "q") + (Undo "j") + (Redo "u") + (Save "m") + (Window "n") + (Target "l") + (Clipboard "a") + (Scheduler "z") + (Module "y") + (XSplit "X") + (YSplit "Y") + (ClosePanel "S") + (StepInto "T") + (StepOver "Z") + (StepOut "d") + (Find "N") + (Palette "E") + (Thumbnails "H") + (Glasses "e") + (Binoculars "I") + (List "J") + (Grid "A") + (QuestionMark "?") + (Person "4") + (Briefcase "5") + (Dot "c") +} + +//////////////////////////////// +//~ rjf: X64 Instruction Table + +@table(name summary) +DF_InstTableX64: +{ + + //- rjf: core + {AAA "ASCII Adjust After Addition" } + {AAD "ASCII Adjust AX Before Division" } + {AAM "ASCII Adjust AX After Multiply" } + {AAS "ASCII Adjust AL After Subtraction" } + {ADC "Add with Carry" } + {ADCX "Unsigned Integer Addition of Two Operands with Carry Flag" } + {ADD "Add" } + {ADDPD "Add Packed Double-Precision Floating-Point Values" } + {ADDPS "Add Packed Single-Precision Floating-Point Values" } + {ADDSD "Add Scalar Double-Precision Floating-Point Values" } + {ADDSS "Add Scalar Single-Precision Floating-Point Values" } + {ADDSUBPD "Packed Double-FP Add/Subtract" } + {ADDSUBPS "Packed Single-FP Add/Subtract" } + {ADOX "Unsigned Integer Addition of Two Operands with Overflow Flag" } + {AESDEC "Perform One Round of an AES Decryption Flow" } + {AESDEC128KL "Perform Ten Rounds of AES Decryption Flow with Key Locker Using 128-Bit Key" } + {AESDEC256KL "Perform 14 Rounds of AES Decryption Flow with Key Locker Using 256-Bit Key" } + {AESDECLAST "Perform Last Round of an AES Decryption Flow" } + {AESDECWIDE128KL "Perform Ten Rounds of AES Decryption Flow with Key Locker on 8 Blocks Using 128-Bit Key" } + {AESDECWIDE256KL "Perform 14 Rounds of AES Decryption Flow with Key Locker on 8 Blocks Using 256-Bit Key" } + {AESENC "Perform One Round of an AES Encryption Flow" } + {AESENC128KL "Perform Ten Rounds of AES Encryption Flow with Key Locker Using 128-Bit Key" } + {AESENC256KL "Perform 14 Rounds of AES Encryption Flow with Key Locker Using 256-Bit Key" } + {AESENCLAST "Perform Last Round of an AES Encryption Flow" } + {AESENCWIDE128KL "Perform Ten Rounds of AES Encryption Flow with Key Locker on 8 Blocks Using 128-Bit Key" } + {AESENCWIDE256KL "Perform 14 Rounds of AES Encryption Flow with Key Locker on 8 Blocks Using 256-Bit Key" } + {AESIMC "Perform the AES InvMixColumn Transformation" } + {AESKEYGENASSIST "AES Round Key Generation Assist" } + {AND "Logical AND" } + {ANDN "Logical AND NOT" } + {ANDNPD "Bitwise Logical AND NOT of Packed Double Precision Floating-Point Values" } + {ANDNPS "Bitwise Logical AND NOT of Packed Single Precision Floating-Point Values" } + {ANDPD "Bitwise Logical AND of Packed Double Precision Floating-Point Values" } + {ANDPS "Bitwise Logical AND of Packed Single Precision Floating-Point Values" } + {ARPL "Adjust RPL Field of Segment Selector" } + {BEXTR "Bit Field Extract" } + {BLENDPD "Blend Packed Double Precision Floating-Point Values" } + {BLENDPS "Blend Packed Single Precision Floating-Point Values" } + {BLENDVPD "Variable Blend Packed Double Precision Floating-Point Values" } + {BLENDVPS "Variable Blend Packed Single Precision Floating-Point Values" } + {BLSI "Extract Lowest Set Isolated Bit" } + {BLSMSK "Get Mask Up to Lowest Set Bit" } + {BLSR "Reset Lowest Set Bit" } + {BNDCL "Check Lower Bound" } + {BNDCN "Check Upper Bound" } + {BNDCU "Check Upper Bound" } + {BNDLDX "Load Extended Bounds Using Address Translation" } + {BNDMK "Make Bounds" } + {BNDMOV "Move Bounds" } + {BNDSTX "Store Extended Bounds Using Address Translation" } + {BOUND "Check Array Index Against Bounds" } + {BSF "Bit Scan Forward" } + {BSR "Bit Scan Reverse" } + {BSWAP "Byte Swap" } + {BT "Bit Test" } + {BTC "Bit Test and Complement" } + {BTR "Bit Test and Reset" } + {BTS "Bit Test and Set" } + {BZHI "Zero High Bits Starting with Specified Bit Position" } + {CALL "Call Procedure" } + {CBW "Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword" } + {CDQ "Convert Word to Doubleword/Convert Doubleword to Quadword" } + {CDQE "Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword" } + {CLAC "Clear AC Flag in EFLAGS Register" } + {CLC "Clear Carry Flag" } + {CLD "Clear Direction Flag" } + {CLDEMOTE "Cache Line Demote" } + {CLFLUSH "Flush Cache Line" } + {CLFLUSHOPT "Flush Cache Line Optimized" } + {CLI "Clear Interrupt Flag" } + {CLRSSBSY "Clear Busy Flag in a Supervisor Shadow Stack Token" } + {CLTS "Clear Task-Switched Flag in CR0" } + {CLWB "Cache Line Write Back" } + {CMC "Complement Carry Flag" } + {CMOVcc "Conditional Move" } + {CMP "Compare Two Operands" } + {CMPPD "Compare Packed Double-Precision Floating-Point Values" } + {CMPPS "Compare Packed Single-Precision Floating-Point Values" } + {CMPS "Compare String Operands" } + {CMPSB "Compare String Operands" } + {CMPSD "Compare String Operands" } + {CMPSQ "Compare String Operands" } + {CMPSS "Compare Scalar Single-Precision Floating-Point Value" } + {CMPSW "Compare String Operands" } + {CMPXCHG "Compare and Exchange" } + {CMPXCHG16B "Compare and Exchange Bytes" } + {CMPXCHG8B "Compare and Exchange Bytes" } + {COMISD "Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS" } + {COMISS "Compare Scalar Ordered Single-Precision Floating-Point Values and Set EFLAGS" } + {CPUID "CPU Identification" } + {CQO "Convert Word to Doubleword/Convert Doubleword to Quadword" } + {CRC32 "Accumulate CRC32 Value" } + {CVTDQ2PD "Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values" } + {CVTDQ2PS "Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values" } + {CVTPD2DQ "Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers" } + {CVTPD2PI "Convert Packed Double-Precision FP Values to Packed Dword Integers" } + {CVTPD2PS "Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values" } + {CVTPI2PD "Convert Packed Dword Integers to Packed Double-Precision FP Values" } + {CVTPI2PS "Convert Packed Dword Integers to Packed Single-Precision FP Values" } + {CVTPS2DQ "Convert Packed Single-Precision Floating-Point Values to Packed Signed Doubleword Integer Values" } + {CVTPS2PD "Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values" } + {CVTPS2PI "Convert Packed Single-Precision FP Values to Packed Dword Integers" } + {CVTSD2SI "Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer" } + {CVTSD2SS "Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value" } + {CVTSI2SD "Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value" } + {CVTSI2SS "Convert Doubleword Integer to Scalar Single-Precision Floating-Point Value" } + {CVTSS2SD "Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value" } + {CVTSS2SI "Convert Scalar Single-Precision Floating-Point Value to Doubleword Integer" } + {CVTTPD2DQ "Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers" } + {CVTTPD2PI "Convert with Truncation Packed Double-Precision FP Values to Packed Dword Integers" } + {CVTTPS2DQ "Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Signed Doubleword Integer Values" } + {CVTTPS2PI "Convert with Truncation Packed Single-Precision FP Values to Packed Dword Integers" } + {CVTTSD2SI "Convert with Truncation Scalar Double-Precision Floating-Point Value to Signed Integer" } + {CVTTSS2SI "Convert with Truncation Scalar Single-Precision Floating-Point Value to Integer" } + {CWD "Convert Word to Doubleword/Convert Doubleword to Quadword" } + {CWDE "Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword" } + {DAA "Decimal Adjust AL after Addition" } + {DAS "Decimal Adjust AL after Subtraction" } + {DEC "Decrement by 1" } + {DIV "Unsigned Divide" } + {DIVPD "Divide Packed Double-Precision Floating-Point Values" } + {DIVPS "Divide Packed Single-Precision Floating-Point Values" } + {DIVSD "Divide Scalar Double-Precision Floating-Point Value" } + {DIVSS "Divide Scalar Single-Precision Floating-Point Values" } + {DPPD "Dot Product of Packed Double Precision Floating-Point Values" } + {DPPS "Dot Product of Packed Single Precision Floating-Point Values" } + {EMMS "Empty MMX Technology State" } + {ENCODEKEY128 "Encode 128-Bit Key with Key Locker" } + {ENCODEKEY256 "Encode 256-Bit Key with Key Locker" } + {ENDBR32 "Terminate an Indirect Branch in 32-bit and Compatibility Mode" } + {ENDBR64 "Terminate an Indirect Branch in 64-bit Mode" } + {ENTER "Make Stack Frame for Procedure Parameters" } + {EXTRACTPS "Extract Packed Floating-Point Values" } + {F2XM1 "Compute 2x–1" } + {FABS "Absolute Value" } + {FADD "Add" } + {FADDP "Add" } + {FBLD "Load Binary Coded Decimal" } + {FBSTP "Store BCD Integer and Pop" } + {FCHS "Change Sign" } + {FCLEX "Clear Exceptions" } + {FCMOVcc "Floating-Point Conditional Move" } + {FCOM "Compare Floating Point Values" } + {FCOMI "Compare Floating Point Values and Set EFLAGS" } + {FCOMIP "Compare Floating Point Values and Set EFLAGS" } + {FCOMP "Compare Floating Point Values" } + {FCOMPP "Compare Floating Point Values" } + {FCOS "Cosine" } + {FDECSTP "Decrement Stack-Top Pointer" } + {FDIV "Divide" } + {FDIVP "Divide" } + {FDIVR "Reverse Divide" } + {FDIVRP "Reverse Divide" } + {FFREE "Free Floating-Point Register" } + {FIADD "Add" } + {FICOM "Compare Integer" } + {FICOMP "Compare Integer" } + {FIDIV "Divide" } + {FIDIVR "Reverse Divide" } + {FILD "Load Integer" } + {FIMUL "Multiply" } + {FINCSTP "Increment Stack-Top Pointer" } + {FINIT "Initialize Floating-Point Unit" } + {FIST "Store Integer" } + {FISTP "Store Integer" } + {FISTTP "Store Integer with Truncation" } + {FISUB "Subtract" } + {FISUBR "Reverse Subtract" } + {FLD "Load Floating Point Value" } + {FLD1 "Load Constant" } + {FLDCW "Load x87 FPU Control Word" } + {FLDENV "Load x87 FPU Environment" } + {FLDL2E "Load Constant" } + {FLDL2T "Load Constant" } + {FLDLG2 "Load Constant" } + {FLDLN2 "Load Constant" } + {FLDPI "Load Constant" } + {FLDZ "Load Constant" } + {FMUL "Multiply" } + {FMULP "Multiply" } + {FNCLEX "Clear Exceptions" } + {FNINIT "Initialize Floating-Point Unit" } + {FNOP "No Operation" } + {FNSAVE "Store x87 FPU State" } + {FNSTCW "Store x87 FPU Control Word" } + {FNSTENV "Store x87 FPU Environment" } + {FNSTSW "Store x87 FPU Status Word" } + {FPATAN "Partial Arctangent" } + {FPREM "Partial Remainder" } + {FPREM1 "Partial Remainder" } + {FPTAN "Partial Tangent" } + {FRNDINT "Round to Integer" } + {FRSTOR "Restore x87 FPU State" } + {FSAVE "Store x87 FPU State" } + {FSCALE "Scale" } + {FSIN "Sine" } + {FSINCOS "Sine and Cosine" } + {FSQRT "Square Root" } + {FST "Store Floating Point Value" } + {FSTCW "Store x87 FPU Control Word" } + {FSTENV "Store x87 FPU Environment" } + {FSTP "Store Floating Point Value" } + {FSTSW "Store x87 FPU Status Word" } + {FSUB "Subtract" } + {FSUBP "Subtract" } + {FSUBR "Reverse Subtract" } + {FSUBRP "Reverse Subtract" } + {FTST "TEST" } + {FUCOM "Unordered Compare Floating Point Values" } + {FUCOMI "Compare Floating Point Values and Set EFLAGS" } + {FUCOMIP "Compare Floating Point Values and Set EFLAGS" } + {FUCOMP "Unordered Compare Floating Point Values" } + {FUCOMPP "Unordered Compare Floating Point Values" } + {FWAIT "Wait" } + {FXAM "Examine Floating-Point" } + {FXCH "Exchange Register Contents" } + {FXRSTOR "Restore x87 FPU, MMX, XMM, and MXCSR State" } + {FXSAVE "Save x87 FPU, MMX Technology, and SSE State" } + {FXTRACT "Extract Exponent and Significand" } + {FYL2X "Compute y * log2x" } + {FYL2XP1 "Compute y * log2(x +1)" } + {GF2P8AFFINEINVQB "Galois Field Affine Transformation Inverse" } + {GF2P8AFFINEQB "Galois Field Affine Transformation" } + {GF2P8MULB "Galois Field Multiply Bytes" } + {HADDPD "Packed Double-FP Horizontal Add" } + {HADDPS "Packed Single-FP Horizontal Add" } + {HLT "Halt" } + {HRESET "History Reset" } + {HSUBPD "Packed Double-FP Horizontal Subtract" } + {HSUBPS "Packed Single-FP Horizontal Subtract" } + {IDIV "Signed Divide" } + {IMUL "Signed Multiply" } + {IN "Input from Port" } + {INC "Increment by 1" } + {INCSSPD "Increment Shadow Stack Pointer" } + {INCSSPQ "Increment Shadow Stack Pointer" } + {INS "Input from Port to String" } + {INSB "Input from Port to String" } + {INSD "Input from Port to String" } + {INSERTPS "Insert Scalar Single-Precision Floating-Point Value" } + {INSW "Input from Port to String" } + {INT "Call to Interrupt Procedure" } + {INT1 "Call to Interrupt Procedure" } + {INT3 "Call to Interrupt Procedure" } + {INTO "Call to Interrupt Procedure" } + {INVD "Invalidate Internal Caches" } + {INVLPG "Invalidate TLB Entries" } + {INVPCID "Invalidate Process-Context Identifier" } + {IRET "Interrupt Return" } + {IRETD "Interrupt Return" } + {IRETQ "Interrupt Return" } + {JMP "Jump" } + {Jcc "Jump if Condition Is Met" } + {KADDB "ADD Two Masks" } + {KADDD "ADD Two Masks" } + {KADDQ "ADD Two Masks" } + {KADDW "ADD Two Masks" } + {KANDB "Bitwise Logical AND Masks" } + {KANDD "Bitwise Logical AND Masks" } + {KANDNB "Bitwise Logical AND NOT Masks" } + {KANDND "Bitwise Logical AND NOT Masks" } + {KANDNQ "Bitwise Logical AND NOT Masks" } + {KANDNW "Bitwise Logical AND NOT Masks" } + {KANDQ "Bitwise Logical AND Masks" } + {KANDW "Bitwise Logical AND Masks" } + {KMOVB "Move from and to Mask Registers" } + {KMOVD "Move from and to Mask Registers" } + {KMOVQ "Move from and to Mask Registers" } + {KMOVW "Move from and to Mask Registers" } + {KNOTB "NOT Mask Register" } + {KNOTD "NOT Mask Register" } + {KNOTQ "NOT Mask Register" } + {KNOTW "NOT Mask Register" } + {KORB "Bitwise Logical OR Masks" } + {KORD "Bitwise Logical OR Masks" } + {KORQ "Bitwise Logical OR Masks" } + {KORTESTB "OR Masks And Set Flags" } + {KORTESTD "OR Masks And Set Flags" } + {KORTESTQ "OR Masks And Set Flags" } + {KORTESTW "OR Masks And Set Flags" } + {KORW "Bitwise Logical OR Masks" } + {KSHIFTLB "Shift Left Mask Registers" } + {KSHIFTLD "Shift Left Mask Registers" } + {KSHIFTLQ "Shift Left Mask Registers" } + {KSHIFTLW "Shift Left Mask Registers" } + {KSHIFTRB "Shift Right Mask Registers" } + {KSHIFTRD "Shift Right Mask Registers" } + {KSHIFTRQ "Shift Right Mask Registers" } + {KSHIFTRW "Shift Right Mask Registers" } + {KTESTB "Packed Bit Test Masks and Set Flags" } + {KTESTD "Packed Bit Test Masks and Set Flags" } + {KTESTQ "Packed Bit Test Masks and Set Flags" } + {KTESTW "Packed Bit Test Masks and Set Flags" } + {KUNPCKBW "Unpack for Mask Registers" } + {KUNPCKDQ "Unpack for Mask Registers" } + {KUNPCKWD "Unpack for Mask Registers" } + {KXNORB "Bitwise Logical XNOR Masks" } + {KXNORD "Bitwise Logical XNOR Masks" } + {KXNORQ "Bitwise Logical XNOR Masks" } + {KXNORW "Bitwise Logical XNOR Masks" } + {KXORB "Bitwise Logical XOR Masks" } + {KXORD "Bitwise Logical XOR Masks" } + {KXORQ "Bitwise Logical XOR Masks" } + {KXORW "Bitwise Logical XOR Masks" } + {LAHF "Load Status Flags into AH Register" } + {LAR "Load Access Rights Byte" } + {LDDQU "Load Unaligned Integer 128 Bits" } + {LDMXCSR "Load MXCSR Register" } + {LDS "Load Far Pointer" } + {LEA "Load Effective Address" } + {LEAVE "High Level Procedure Exit" } + {LES "Load Far Pointer" } + {LFENCE "Load Fence" } + {LFS "Load Far Pointer" } + {LGDT "Load Global/Interrupt Descriptor Table Register" } + {LGS "Load Far Pointer" } + {LIDT "Load Global/Interrupt Descriptor Table Register" } + {LLDT "Load Local Descriptor Table Register" } + {LMSW "Load Machine Status Word" } + {LOADIWKEY "Load Internal Wrapping Key with Key Locker" } + {LOCK "Assert LOCK# Signal Prefix" } + {LODS "Load String" } + {LODSB "Load String" } + {LODSD "Load String" } + {LODSQ "Load String" } + {LODSW "Load String" } + {LOOP "Loop According to ECX Counter" } + {LOOPcc "Loop According to ECX Counter" } + {LSL "Load Segment Limit" } + {LSS "Load Far Pointer" } + {LTR "Load Task Register" } + {LZCNT "Count the Number of Leading Zero Bits" } + {MASKMOVDQU "Store Selected Bytes of Double Quadword" } + {MASKMOVQ "Store Selected Bytes of Quadword" } + {MAXPD "Maximum of Packed Double-Precision Floating-Point Values" } + {MAXPS "Maximum of Packed Single-Precision Floating-Point Values" } + {MAXSD "Return Maximum Scalar Double-Precision Floating-Point Value" } + {MAXSS "Return Maximum Scalar Single-Precision Floating-Point Value" } + {MFENCE "Memory Fence" } + {MINPD "Minimum of Packed Double-Precision Floating-Point Values" } + {MINPS "Minimum of Packed Single-Precision Floating-Point Values" } + {MINSD "Return Minimum Scalar Double-Precision Floating-Point Value" } + {MINSS "Return Minimum Scalar Single-Precision Floating-Point Value" } + {MONITOR "Set Up Monitor Address" } + {MOV "Move" } + {MOVAPD "Move Aligned Packed Double-Precision Floating-Point Values" } + {MOVAPS "Move Aligned Packed Single-Precision Floating-Point Values" } + {MOVBE "Move Data After Swapping Bytes" } + {MOVD "Move Doubleword/Move Quadword" } + {MOVDDUP "Replicate Double FP Values" } + {MOVDIR64B "Move 64 Bytes as Direct Store" } + {MOVDIRI "Move Doubleword as Direct Store" } + {MOVDQ2Q "Move Quadword from XMM to MMX Technology Register" } + {MOVDQA "Move Aligned Packed Integer Values" } + {MOVDQU "Move Unaligned Packed Integer Values" } + {MOVHLPS "Move Packed Single-Precision Floating-Point Values High to Low" } + {MOVHPD "Move High Packed Double-Precision Floating-Point Value" } + {MOVHPS "Move High Packed Single-Precision Floating-Point Values" } + {MOVLHPS "Move Packed Single-Precision Floating-Point Values Low to High" } + {MOVLPD "Move Low Packed Double-Precision Floating-Point Value" } + {MOVLPS "Move Low Packed Single-Precision Floating-Point Values" } + {MOVMSKPD "Extract Packed Double-Precision Floating-Point Sign Mask" } + {MOVMSKPS "Extract Packed Single-Precision Floating-Point Sign Mask" } + {MOVNTDQ "Store Packed Integers Using Non-Temporal Hint" } + {MOVNTDQA "Load Double Quadword Non-Temporal Aligned Hint" } + {MOVNTI "Store Doubleword Using Non-Temporal Hint" } + {MOVNTPD "Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint" } + {MOVNTPS "Store Packed Single-Precision Floating-Point Values Using Non-Temporal Hint" } + {MOVNTQ "Store of Quadword Using Non-Temporal Hint" } + {MOVQ "Move Doubleword/Move Quadword" } + {MOVQ2DQ "Move Quadword from MMX Technology to XMM Register" } + {MOVS "Move Data from String to String" } + {MOVSB "Move Data from String to String" } + {MOVSD "Move Data from String to String" } + {MOVSHDUP "Replicate Single FP Values" } + {MOVSLDUP "Replicate Single FP Values" } + {MOVSQ "Move Data from String to String" } + {MOVSS "Move or Merge Scalar Single-Precision Floating-Point Value" } + {MOVSW "Move Data from String to String" } + {MOVSX "Move with Sign-Extension" } + {MOVSXD "Move with Sign-Extension" } + {MOVUPD "Move Unaligned Packed Double-Precision Floating-Point Values" } + {MOVUPS "Move Unaligned Packed Single-Precision Floating-Point Values" } + {MOVZX "Move with Zero-Extend" } + {MPSADBW "Compute Multiple Packed Sums of Absolute Difference" } + {MUL "Unsigned Multiply" } + {MULPD "Multiply Packed Double-Precision Floating-Point Values" } + {MULPS "Multiply Packed Single-Precision Floating-Point Values" } + {MULSD "Multiply Scalar Double-Precision Floating-Point Value" } + {MULSS "Multiply Scalar Single-Precision Floating-Point Values" } + {MULX "Unsigned Multiply Without Affecting Flags" } + {MWAIT "Monitor Wait" } + {NEG "Two's Complement Negation" } + {NOP "No Operation" } + {NOT "One's Complement Negation" } + {OR "Logical Inclusive OR" } + {ORPD "Bitwise Logical OR of Packed Double Precision Floating-Point Values" } + {ORPS "Bitwise Logical OR of Packed Single Precision Floating-Point Values" } + {OUT "Output to Port" } + {OUTS "Output String to Port" } + {OUTSB "Output String to Port" } + {OUTSD "Output String to Port" } + {OUTSW "Output String to Port" } + {PABSB "Packed Absolute Value" } + {PABSD "Packed Absolute Value" } + {PABSQ "Packed Absolute Value" } + {PABSW "Packed Absolute Value" } + {PACKSSDW "Pack with Signed Saturation" } + {PACKSSWB "Pack with Signed Saturation" } + {PACKUSDW "Pack with Unsigned Saturation" } + {PACKUSWB "Pack with Unsigned Saturation" } + {PADDB "Add Packed Integers" } + {PADDD "Add Packed Integers" } + {PADDQ "Add Packed Integers" } + {PADDSB "Add Packed Signed Integers with Signed Saturation" } + {PADDSW "Add Packed Signed Integers with Signed Saturation" } + {PADDUSB "Add Packed Unsigned Integers with Unsigned Saturation" } + {PADDUSW "Add Packed Unsigned Integers with Unsigned Saturation" } + {PADDW "Add Packed Integers" } + {PALIGNR "Packed Align Right" } + {PAND "Logical AND" } + {PANDN "Logical AND NOT" } + {PAUSE "Spin Loop Hint" } + {PAVGB "Average Packed Integers" } + {PAVGW "Average Packed Integers" } + {PBLENDVB "Variable Blend Packed Bytes" } + {PBLENDW "Blend Packed Words" } + {PCLMULQDQ "Carry-Less Multiplication Quadword" } + {PCMPEQB "Compare Packed Data for Equal" } + {PCMPEQD "Compare Packed Data for Equal" } + {PCMPEQQ "Compare Packed Qword Data for Equal" } + {PCMPEQW "Compare Packed Data for Equal" } + {PCMPESTRI "Packed Compare Explicit Length Strings, Return Index" } + {PCMPESTRM "Packed Compare Explicit Length Strings, Return Mask" } + {PCMPGTB "Compare Packed Signed Integers for Greater Than" } + {PCMPGTD "Compare Packed Signed Integers for Greater Than" } + {PCMPGTQ "Compare Packed Data for Greater Than" } + {PCMPGTW "Compare Packed Signed Integers for Greater Than" } + {PCMPISTRI "Packed Compare Implicit Length Strings, Return Index" } + {PCMPISTRM "Packed Compare Implicit Length Strings, Return Mask" } + {PCONFIG "Platform Configuration" } + {PDEP "Parallel Bits Deposit" } + {PEXT "Parallel Bits Extract" } + {PEXTRB "Extract Byte/Dword/Qword" } + {PEXTRD "Extract Byte/Dword/Qword" } + {PEXTRQ "Extract Byte/Dword/Qword" } + {PEXTRW "Extract Word" } + {PHADDD "Packed Horizontal Add" } + {PHADDSW "Packed Horizontal Add and Saturate" } + {PHADDW "Packed Horizontal Add" } + {PHMINPOSUW "Packed Horizontal Word Minimum" } + {PHSUBD "Packed Horizontal Subtract" } + {PHSUBSW "Packed Horizontal Subtract and Saturate" } + {PHSUBW "Packed Horizontal Subtract" } + {PINSRB "Insert Byte/Dword/Qword" } + {PINSRD "Insert Byte/Dword/Qword" } + {PINSRQ "Insert Byte/Dword/Qword" } + {PINSRW "Insert Word" } + {PMADDUBSW "Multiply and Add Packed Signed and Unsigned Bytes" } + {PMADDWD "Multiply and Add Packed Integers" } + {PMAXSB "Maximum of Packed Signed Integers" } + {PMAXSD "Maximum of Packed Signed Integers" } + {PMAXSQ "Maximum of Packed Signed Integers" } + {PMAXSW "Maximum of Packed Signed Integers" } + {PMAXUB "Maximum of Packed Unsigned Integers" } + {PMAXUD "Maximum of Packed Unsigned Integers" } + {PMAXUQ "Maximum of Packed Unsigned Integers" } + {PMAXUW "Maximum of Packed Unsigned Integers" } + {PMINSB "Minimum of Packed Signed Integers" } + {PMINSD "Minimum of Packed Signed Integers" } + {PMINSQ "Minimum of Packed Signed Integers" } + {PMINSW "Minimum of Packed Signed Integers" } + {PMINUB "Minimum of Packed Unsigned Integers" } + {PMINUD "Minimum of Packed Unsigned Integers" } + {PMINUQ "Minimum of Packed Unsigned Integers" } + {PMINUW "Minimum of Packed Unsigned Integers" } + {PMOVMSKB "Move Byte Mask" } + {PMOVSX "Packed Move with Sign Extend" } + {PMOVZX "Packed Move with Zero Extend" } + {PMULDQ "Multiply Packed Doubleword Integers" } + {PMULHRSW "Packed Multiply High with Round and Scale" } + {PMULHUW "Multiply Packed Unsigned Integers and Store High Result" } + {PMULHW "Multiply Packed Signed Integers and Store High Result" } + {PMULLD "Multiply Packed Integers and Store Low Result" } + {PMULLQ "Multiply Packed Integers and Store Low Result" } + {PMULLW "Multiply Packed Signed Integers and Store Low Result" } + {PMULUDQ "Multiply Packed Unsigned Doubleword Integers" } + {POP "Pop a Value from the Stack" } + {POPA "Pop All General-Purpose Registers" } + {POPAD "Pop All General-Purpose Registers" } + {POPCNT "Return the Count of Number of Bits Set to 1" } + {POPF "Pop Stack into EFLAGS Register" } + {POPFD "Pop Stack into EFLAGS Register" } + {POPFQ "Pop Stack into EFLAGS Register" } + {POR "Bitwise Logical OR" } + {PREFETCHW "Prefetch Data into Caches in Anticipation of a Write" } + {PREFETCHh "Prefetch Data Into Caches" } + {PSADBW "Compute Sum of Absolute Differences" } + {PSHUFB "Packed Shuffle Bytes" } + {PSHUFD "Shuffle Packed Doublewords" } + {PSHUFHW "Shuffle Packed High Words" } + {PSHUFLW "Shuffle Packed Low Words" } + {PSHUFW "Shuffle Packed Words" } + {PSIGNB "Packed SIGN" } + {PSIGND "Packed SIGN" } + {PSIGNW "Packed SIGN" } + {PSLLD "Shift Packed Data Left Logical" } + {PSLLDQ "Shift Double Quadword Left Logical" } + {PSLLQ "Shift Packed Data Left Logical" } + {PSLLW "Shift Packed Data Left Logical" } + {PSRAD "Shift Packed Data Right Arithmetic" } + {PSRAQ "Shift Packed Data Right Arithmetic" } + {PSRAW "Shift Packed Data Right Arithmetic" } + {PSRLD "Shift Packed Data Right Logical" } + {PSRLDQ "Shift Double Quadword Right Logical" } + {PSRLQ "Shift Packed Data Right Logical" } + {PSRLW "Shift Packed Data Right Logical" } + {PSUBB "Subtract Packed Integers" } + {PSUBD "Subtract Packed Integers" } + {PSUBQ "Subtract Packed Quadword Integers" } + {PSUBSB "Subtract Packed Signed Integers with Signed Saturation" } + {PSUBSW "Subtract Packed Signed Integers with Signed Saturation" } + {PSUBUSB "Subtract Packed Unsigned Integers with Unsigned Saturation" } + {PSUBUSW "Subtract Packed Unsigned Integers with Unsigned Saturation" } + {PSUBW "Subtract Packed Integers" } + {PTEST "Logical Compare" } + {PTWRITE "Write Data to a Processor Trace Packet" } + {PUNPCKHBW "Unpack High Data" } + {PUNPCKHDQ "Unpack High Data" } + {PUNPCKHQDQ "Unpack High Data" } + {PUNPCKHWD "Unpack High Data" } + {PUNPCKLBW "Unpack Low Data" } + {PUNPCKLDQ "Unpack Low Data" } + {PUNPCKLQDQ "Unpack Low Data" } + {PUNPCKLWD "Unpack Low Data" } + {PUSH "Push Word, Doubleword or Quadword Onto the Stack" } + {PUSHA "Push All General-Purpose Registers" } + {PUSHAD "Push All General-Purpose Registers" } + {PUSHF "Push EFLAGS Register onto the Stack" } + {PUSHFD "Push EFLAGS Register onto the Stack" } + {PUSHFQ "Push EFLAGS Register onto the Stack" } + {PXOR "Logical Exclusive OR" } + {RCL "Rotate" } + {RCPPS "Compute Reciprocals of Packed Single-Precision Floating-Point Values" } + {RCPSS "Compute Reciprocal of Scalar Single-Precision Floating-Point Values" } + {RCR "Rotate" } + {RDFSBASE "Read FS/GS Segment Base" } + {RDGSBASE "Read FS/GS Segment Base" } + {RDMSR "Read from Model Specific Register" } + {RDPID "Read Processor ID" } + {RDPKRU "Read Protection Key Rights for User Pages" } + {RDPMC "Read Performance-Monitoring Counters" } + {RDRAND "Read Random Number" } + {RDSEED "Read Random SEED" } + {RDSSPD "Read Shadow Stack Pointer" } + {RDSSPQ "Read Shadow Stack Pointer" } + {RDTSC "Read Time-Stamp Counter" } + {RDTSCP "Read Time-Stamp Counter and Processor ID" } + {REP "Repeat String Operation Prefix" } + {REPE "Repeat String Operation Prefix" } + {REPNE "Repeat String Operation Prefix" } + {REPNZ "Repeat String Operation Prefix" } + {REPZ "Repeat String Operation Prefix" } + {RET "Return from Procedure" } + {ROL "Rotate" } + {ROR "Rotate" } + {RORX "Rotate Right Logical Without Affecting Flags" } + {ROUNDPD "Round Packed Double Precision Floating-Point Values" } + {ROUNDPS "Round Packed Single Precision Floating-Point Values" } + {ROUNDSD "Round Scalar Double Precision Floating-Point Values" } + {ROUNDSS "Round Scalar Single Precision Floating-Point Values" } + {RSM "Resume from System Management Mode" } + {RSQRTPS "Compute Reciprocals of Square Roots of Packed Single-Precision Floating-Point Values" } + {RSQRTSS "Compute Reciprocal of Square Root of Scalar Single-Precision Floating-Point Value" } + {RSTORSSP "Restore Saved Shadow Stack Pointer" } + {SAHF "Store AH into Flags" } + {SAL "Shift" } + {SAR "Shift" } + {SARX "Shift Without Affecting Flags" } + {SAVEPREVSSP "Save Previous Shadow Stack Pointer" } + {SBB "Integer Subtraction with Borrow" } + {SCAS "Scan String" } + {SCASB "Scan String" } + {SCASD "Scan String" } + {SCASW "Scan String" } + {SERIALIZE "Serialize Instruction Execution" } + {SETSSBSY "Mark Shadow Stack Busy" } + {SETcc "Set Byte on Condition" } + {SFENCE "Store Fence" } + {SGDT "Store Global Descriptor Table Register" } + {SHA1MSG1 "Perform an Intermediate Calculation for the Next Four SHA1 Message Dwords" } + {SHA1MSG2 "Perform a Final Calculation for the Next Four SHA1 Message Dwords" } + {SHA1NEXTE "Calculate SHA1 State Variable E after Four Rounds" } + {SHA1RNDS4 "Perform Four Rounds of SHA1 Operation" } + {SHA256MSG1 "Perform an Intermediate Calculation for the Next Four SHA256 Message Dwords" } + {SHA256MSG2 "Perform a Final Calculation for the Next Four SHA256 Message Dwords" } + {SHA256RNDS2 "Perform Two Rounds of SHA256 Operation" } + {SHL "Shift" } + {SHLD "Double Precision Shift Left" } + {SHLX "Shift Without Affecting Flags" } + {SHR "Shift" } + {SHRD "Double Precision Shift Right" } + {SHRX "Shift Without Affecting Flags" } + {SHUFPD "Packed Interleave Shuffle of Pairs of Double-Precision Floating-Point Values" } + {SHUFPS "Packed Interleave Shuffle of Quadruplets of Single-Precision Floating-Point Values" } + {SIDT "Store Interrupt Descriptor Table Register" } + {SLDT "Store Local Descriptor Table Register" } + {SMSW "Store Machine Status Word" } + {SQRTPD "Square Root of Double-Precision Floating-Point Values" } + {SQRTPS "Square Root of Single-Precision Floating-Point Values" } + {SQRTSD "Compute Square Root of Scalar Double-Precision Floating-Point Value" } + {SQRTSS "Compute Square Root of Scalar Single-Precision Value" } + {STAC "Set AC Flag in EFLAGS Register" } + {STC "Set Carry Flag" } + {STD "Set Direction Flag" } + {STI "Set Interrupt Flag" } + {STMXCSR "Store MXCSR Register State" } + {STOS "Store String" } + {STOSB "Store String" } + {STOSD "Store String" } + {STOSQ "Store String" } + {STOSW "Store String" } + {STR "Store Task Register" } + {SUB "Subtract" } + {SUBPD "Subtract Packed Double-Precision Floating-Point Values" } + {SUBPS "Subtract Packed Single-Precision Floating-Point Values" } + {SUBSD "Subtract Scalar Double-Precision Floating-Point Value" } + {SUBSS "Subtract Scalar Single-Precision Floating-Point Value" } + {SWAPGS "Swap GS Base Register" } + {SYSCALL "Fast System Call" } + {SYSENTER "Fast System Call" } + {SYSEXIT "Fast Return from Fast System Call" } + {SYSRET "Return From Fast System Call" } + {TEST "Logical Compare" } + {TPAUSE "Timed PAUSE" } + {TZCNT "Count the Number of Trailing Zero Bits" } + {UCOMISD "Unordered Compare Scalar Double-Precision Floating-Point Values and Set EFLAGS" } + {UCOMISS "Unordered Compare Scalar Single-Precision Floating-Point Values and Set EFLAGS" } + {UD "Undefined Instruction" } + {UMONITOR "User Level Set Up Monitor Address" } + {UMWAIT "User Level Monitor Wait" } + {UNPCKHPD "Unpack and Interleave High Packed Double-Precision Floating-Point Values" } + {UNPCKHPS "Unpack and Interleave High Packed Single-Precision Floating-Point Values" } + {UNPCKLPD "Unpack and Interleave Low Packed Double-Precision Floating-Point Values" } + {UNPCKLPS "Unpack and Interleave Low Packed Single-Precision Floating-Point Values" } + {VALIGND "Align Doubleword/Quadword Vectors" } + {VALIGNQ "Align Doubleword/Quadword Vectors" } + {VBLENDMPD "Blend Float64/Float32 Vectors Using an OpMask Control" } + {VBLENDMPS "Blend Float64/Float32 Vectors Using an OpMask Control" } + {VBROADCAST "Load with Broadcast Floating-Point Data" } + {VCOMPRESSPD "Store Sparse Packed Double-Precision Floating-Point Values into Dense Memory" } + {VCOMPRESSPS "Store Sparse Packed Single-Precision Floating-Point Values into Dense Memory" } + {VCOMPRESSW "Store Sparse Packed Byte/Word Integer Values into Dense Memory/Register" } + {VCVTNE2PS2BF16 "Convert Two Packed Single Data to One Packed BF16 Data" } + {VCVTNEPS2BF16 "Convert Packed Single Data to Packed BF16 Data" } + {VCVTPD2QQ "Convert Packed Double-Precision Floating-Point Values to Packed Quadword Integers" } + {VCVTPD2UDQ "Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers" } + {VCVTPD2UQQ "Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers" } + {VCVTPH2PS "Convert 16-bit FP values to Single-Precision FP values" } + {VCVTPS2PH "Convert Single-Precision FP value to 16-bit FP value" } + {VCVTPS2QQ "Convert Packed Single Precision Floating-Point Values to Packed Signed Quadword Integer Values" } + {VCVTPS2UDQ "Convert Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values" } + {VCVTPS2UQQ "Convert Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values" } + {VCVTQQ2PD "Convert Packed Quadword Integers to Packed Double-Precision Floating-Point Values" } + {VCVTQQ2PS "Convert Packed Quadword Integers to Packed Single-Precision Floating-Point Values" } + {VCVTSD2USI "Convert Scalar Double-Precision Floating-Point Value to Unsigned Doubleword Integer" } + {VCVTSS2USI "Convert Scalar Single-Precision Floating-Point Value to Unsigned Doubleword Integer" } + {VCVTTPD2QQ "Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Quadword Integers" } + {VCVTTPD2UDQ "Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers" } + {VCVTTPD2UQQ "Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers" } + {VCVTTPS2QQ "Convert with Truncation Packed Single Precision Floating-Point Values to Packed Signed Quadword Integer Values" } + {VCVTTPS2UDQ "Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values" } + {VCVTTPS2UQQ "Convert with Truncation Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values" } + {VCVTTSD2USI "Convert with Truncation Scalar Double-Precision Floating-Point Value to Unsigned Integer" } + {VCVTTSS2USI "Convert with Truncation Scalar Single-Precision Floating-Point Value to Unsigned Integer" } + {VCVTUDQ2PD "Convert Packed Unsigned Doubleword Integers to Packed Double-Precision Floating-Point Values" } + {VCVTUDQ2PS "Convert Packed Unsigned Doubleword Integers to Packed Single-Precision Floating-Point Values" } + {VCVTUQQ2PD "Convert Packed Unsigned Quadword Integers to Packed Double-Precision Floating-Point Values" } + {VCVTUQQ2PS "Convert Packed Unsigned Quadword Integers to Packed Single-Precision Floating-Point Values" } + {VCVTUSI2SD "Convert Unsigned Integer to Scalar Double-Precision Floating-Point Value" } + {VCVTUSI2SS "Convert Unsigned Integer to Scalar Single-Precision Floating-Point Value" } + {VDBPSADBW "Double Block Packed Sum-Absolute-Differences (SAD) on Unsigned Bytes" } + {VDPBF16PS "Dot Product of BF16 Pairs Accumulated into Packed Single Precision" } + {VERR "Verify a Segment for Reading or Writing" } + {VERW "Verify a Segment for Reading or Writing" } + {VEXPANDPD "Load Sparse Packed Double-Precision Floating-Point Values from Dense Memory" } + {VEXPANDPS "Load Sparse Packed Single-Precision Floating-Point Values from Dense Memory" } + {VEXTRACTF128 "Extr act Packed Floating-Point Values" } + {VEXTRACTF32x4 "Extr act Packed Floating-Point Values" } + {VEXTRACTF32x8 "Extr act Packed Floating-Point Values" } + {VEXTRACTF64x2 "Extr act Packed Floating-Point Values" } + {VEXTRACTF64x4 "Extr act Packed Floating-Point Values" } + {VEXTRACTI128 "Extract packed Integer Values" } + {VEXTRACTI32x4 "Extract packed Integer Values" } + {VEXTRACTI32x8 "Extract packed Integer Values" } + {VEXTRACTI64x2 "Extract packed Integer Values" } + {VEXTRACTI64x4 "Extract packed Integer Values" } + {VFIXUPIMMPD "Fix Up Special Packed Float64 Values" } + {VFIXUPIMMPS "Fix Up Special Packed Float32 Values" } + {VFIXUPIMMSD "Fix Up Special Scalar Float64 Value" } + {VFIXUPIMMSS "Fix Up Special Scalar Float32 Value" } + {VFMADD132PD "Fused Multiply-Add of Packed Double- Precision Floating-Point Values" } + {VFMADD132PS "Fused Multiply-Add of Packed Single- Precision Floating-Point Values" } + {VFMADD132SD "Fused Multiply-Add of Scalar Double- Precision Floating-Point Values" } + {VFMADD132SS "Fused Multiply-Add of Scalar Single-Precision Floating-Point Values" } + {VFMADD213PD "Fused Multiply-Add of Packed Double- Precision Floating-Point Values" } + {VFMADD213PS "Fused Multiply-Add of Packed Single- Precision Floating-Point Values" } + {VFMADD213SD "Fused Multiply-Add of Scalar Double- Precision Floating-Point Values" } + {VFMADD213SS "Fused Multiply-Add of Scalar Single-Precision Floating-Point Values" } + {VFMADD231PD "Fused Multiply-Add of Packed Double- Precision Floating-Point Values" } + {VFMADD231PS "Fused Multiply-Add of Packed Single- Precision Floating-Point Values" } + {VFMADD231SD "Fused Multiply-Add of Scalar Double- Precision Floating-Point Values" } + {VFMADD231SS "Fused Multiply-Add of Scalar Single-Precision Floating-Point Values" } + {VFMADDSUB132PD "Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values" } + {VFMADDSUB132PS "Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values" } + {VFMADDSUB213PD "Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values" } + {VFMADDSUB213PS "Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values" } + {VFMADDSUB231PD "Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values" } + {VFMADDSUB231PS "Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values" } + {VFMSUB132PD "Fused Multiply-Subtract of Packed Double- Precision Floating-Point Values" } + {VFMSUB132PS "Fused Multiply-Subtract of Packed Single- Precision Floating-Point Values" } + {VFMSUB132SD "Fused Multiply-Subtract of Scalar Double- Precision Floating-Point Values" } + {VFMSUB132SS "Fused Multiply-Subtract of Scalar Single- Precision Floating-Point Values" } + {VFMSUB213PD "Fused Multiply-Subtract of Packed Double- Precision Floating-Point Values" } + {VFMSUB213PS "Fused Multiply-Subtract of Packed Single- Precision Floating-Point Values" } + {VFMSUB213SD "Fused Multiply-Subtract of Scalar Double- Precision Floating-Point Values" } + {VFMSUB213SS "Fused Multiply-Subtract of Scalar Single- Precision Floating-Point Values" } + {VFMSUB231PD "Fused Multiply-Subtract of Packed Double- Precision Floating-Point Values" } + {VFMSUB231PS "Fused Multiply-Subtract of Packed Single- Precision Floating-Point Values" } + {VFMSUB231SD "Fused Multiply-Subtract of Scalar Double- Precision Floating-Point Values" } + {VFMSUB231SS "Fused Multiply-Subtract of Scalar Single- Precision Floating-Point Values" } + {VFMSUBADD132PD "Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values" } + {VFMSUBADD132PS "Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values" } + {VFMSUBADD213PD "Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values" } + {VFMSUBADD213PS "Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values" } + {VFMSUBADD231PD "Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values" } + {VFMSUBADD231PS "Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values" } + {VFNMADD132PD "Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values" } + {VFNMADD132PS "Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values" } + {VFNMADD132SD "Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values" } + {VFNMADD132SS "Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values" } + {VFNMADD213PD "Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values" } + {VFNMADD213PS "Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values" } + {VFNMADD213SD "Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values" } + {VFNMADD213SS "Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values" } + {VFNMADD231PD "Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values" } + {VFNMADD231PS "Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values" } + {VFNMADD231SD "Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values" } + {VFNMADD231SS "Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values" } + {VFNMSUB132PD "Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values" } + {VFNMSUB132PS "Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values" } + {VFNMSUB132SD "Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values" } + {VFNMSUB132SS "Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values" } + {VFNMSUB213PD "Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values" } + {VFNMSUB213PS "Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values" } + {VFNMSUB213SD "Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values" } + {VFNMSUB213SS "Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values" } + {VFNMSUB231PD "Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values" } + {VFNMSUB231PS "Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values" } + {VFNMSUB231SD "Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values" } + {VFNMSUB231SS "Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values" } + {VFPCLASSPD "Tests Types Of a Packed Float64 Values" } + {VFPCLASSPS "Tests Types Of a Packed Float32 Values" } + {VFPCLASSSD "Tests Types Of a Scalar Float64 Values" } + {VFPCLASSSS "Tests Types Of a Scalar Float32 Values" } + {VGATHERDPD "Gather Packed DP FP Values Using Signed Dword/Qword Indices" } + {VGATHERDPS "Gather Packed SP FP values Using Signed Dword/Qword Indices" } + {VGATHERQPD "Gather Packed DP FP Values Using Signed Dword/Qword Indices" } + {VGATHERQPS "Gather Packed SP FP values Using Signed Dword/Qword Indices" } + {VGETEXPPD "Convert Exponents of Packed DP FP Values to DP FP Values" } + {VGETEXPPS "Convert Exponents of Packed SP FP Values to SP FP Values" } + {VGETEXPSD "Convert Exponents of Scalar DP FP Values to DP FP Value" } + {VGETEXPSS "Convert Exponents of Scalar SP FP Values to SP FP Value" } + {VGETMANTPD "Extract Float64 Vector of Normalized Mantissas from Float64 Vector" } + {VGETMANTPS "Extract Float32 Vector of Normalized Mantissas from Float32 Vector" } + {VGETMANTSD "Extract Float64 of Normalized Mantissas from Float64 Scalar" } + {VGETMANTSS "Extract Float32 Vector of Normalized Mantissa from Float32 Vector" } + {VINSERTF128 "Insert Packed Floating-Point Values" } + {VINSERTF32x4 "Insert Packed Floating-Point Values" } + {VINSERTF32x8 "Insert Packed Floating-Point Values" } + {VINSERTF64x2 "Insert Packed Floating-Point Values" } + {VINSERTF64x4 "Insert Packed Floating-Point Values" } + {VINSERTI128 "Insert Packed Integer Values" } + {VINSERTI32x4 "Insert Packed Integer Values" } + {VINSERTI32x8 "Insert Packed Integer Values" } + {VINSERTI64x2 "Insert Packed Integer Values" } + {VINSERTI64x4 "Insert Packed Integer Values" } + {VMASKMOV "Conditional SIMD Packed Loads and Stores" } + {VMOVDQA32 "Move Aligned Packed Integer Values" } + {VMOVDQA64 "Move Aligned Packed Integer Values" } + {VMOVDQU16 "Move Unaligned Packed Integer Values" } + {VMOVDQU32 "Move Unaligned Packed Integer Values" } + {VMOVDQU64 "Move Unaligned Packed Integer Values" } + {VMOVDQU8 "Move Unaligned Packed Integer Values" } + {VP2INTERSECTD "Compute Intersection Between DWORDS/QUADWORDS to a Pair of Mask Registers" } + {VP2INTERSECTQ "Compute Intersection Between DWORDS/QUADWORDS to a Pair of Mask Registers" } + {VPBLENDD "Blend Packed Dwords" } + {VPBLENDMB "Blend Byte/Word Vectors Using an Opmask Control" } + {VPBLENDMD "Blend Int32/Int64 Vectors Using an OpMask Control" } + {VPBLENDMQ "Blend Int32/Int64 Vectors Using an OpMask Control" } + {VPBLENDMW "Blend Byte/Word Vectors Using an Opmask Control" } + {VPBROADCAST "Load Integer and Broadcast" } + {VPBROADCASTB "Load with Broadcast Integer Data from General Purpose Register" } + {VPBROADCASTD "Load with Broadcast Integer Data from General Purpose Register" } + {VPBROADCASTM "Broadcast Mask to Vector Register" } + {VPBROADCASTQ "Load with Broadcast Integer Data from General Purpose Register" } + {VPBROADCASTW "Load with Broadcast Integer Data from General Purpose Register" } + {VPCMPB "Compare Packed Byte Values Into Mask" } + {VPCMPD "Compare Packed Integer Values into Mask" } + {VPCMPQ "Compare Packed Integer Values into Mask" } + {VPCMPUB "Compare Packed Byte Values Into Mask" } + {VPCMPUD "Compare Packed Integer Values into Mask" } + {VPCMPUQ "Compare Packed Integer Values into Mask" } + {VPCMPUW "Compare Packed Word Values Into Mask" } + {VPCMPW "Compare Packed Word Values Into Mask" } + {VPCOMPRESSB "Store Sparse Packed Byte/Word Integer Values into Dense Memory/Register" } + {VPCOMPRESSD "Store Sparse Packed Doubleword Integer Values into Dense Memory/Register" } + {VPCOMPRESSQ "Store Sparse Packed Quadword Integer Values into Dense Memory/Register" } + {VPCONFLICTD "Detect Conflicts Within a Vector of Packed Dword/Qword Values into Dense Memory/ Register" } + {VPCONFLICTQ "Detect Conflicts Within a Vector of Packed Dword/Qword Values into Dense Memory/ Register" } + {VPDPBUSD "Multiply and Add Unsigned and Signed Bytes" } + {VPDPBUSDS "Multiply and Add Unsigned and Signed Bytes with Saturation" } + {VPDPWSSD "Multiply and Add Signed Word Integers" } + {VPDPWSSDS "Multiply and Add Signed Word Integers with Saturation" } + {VPERM2F128 "Permute Floating-Point Values" } + {VPERM2I128 "Permute Integer Values" } + {VPERMB "Permute Packed Bytes Elements" } + {VPERMD "Permute Packed Doublewords/Words Elements" } + {VPERMI2B "Full Permute of Bytes from Two Tables Overwriting the Index" } + {VPERMI2D "Full Permute From Two Tables Overwriting the Index" } + {VPERMI2PD "Full Permute From Two Tables Overwriting the Index" } + {VPERMI2PS "Full Permute From Two Tables Overwriting the Index" } + {VPERMI2Q "Full Permute From Two Tables Overwriting the Index" } + {VPERMI2W "Full Permute From Two Tables Overwriting the Index" } + {VPERMILPD "Permute In-Lane of Pairs of Double-Precision Floating-Point Values" } + {VPERMILPS "Permute In-Lane of Quadruples of Single-Precision Floating-Point Values" } + {VPERMPD "Permute Double-Precision Floating-Point Elements" } + {VPERMPS "Permute Single-Precision Floating-Point Elements" } + {VPERMQ "Qwords Element Permutation" } + {VPERMT2B "Full Permute of Bytes from Two Tables Overwriting a Table" } + {VPERMT2D "Full Permute from Two Tables Overwriting one Table" } + {VPERMT2PD "Full Permute from Two Tables Overwriting one Table" } + {VPERMT2PS "Full Permute from Two Tables Overwriting one Table" } + {VPERMT2Q "Full Permute from Two Tables Overwriting one Table" } + {VPERMT2W "Full Permute from Two Tables Overwriting one Table" } + {VPERMW "Permute Packed Doublewords/Words Elements" } + {VPEXPANDB "Expand Byte/Word Values" } + {VPEXPANDD "Load Sparse Packed Doubleword Integer Values from Dense Memory / Register" } + {VPEXPANDQ "Load Sparse Packed Quadword Integer Values from Dense Memory / Register" } + {VPEXPANDW "Expand Byte/Word Values" } + {VPGATHERDD "Gather Packed Dword Values Using Signed Dword/Qword Indices" } + {VPGATHERDQ "Gather Packed Dword, Packed Qword with Signed Dword Indices" } + {VPGATHERQD "Gather Packed Dword Values Using Signed Dword/Qword Indices" } + {VPGATHERQQ "Gather Packed Qword Values Using Signed Dword/Qword Indices" } + {VPLZCNTD "Count the Number of Leading Zero Bits for Packed Dword, Packed Qword Values" } + {VPLZCNTQ "Count the Number of Leading Zero Bits for Packed Dword, Packed Qword Values" } + {VPMADD52HUQ "Packed Multiply of Unsigned 52-bit Unsigned Integers and Add High 52-bit Products to 64-bit Accumulators" } + {VPMADD52LUQ "Packed Multiply of Unsigned 52-bit Integers and Add the Low 52-bit Products to Qword Accumulators" } + {VPMASKMOV "Conditional SIMD Integer Packed Loads and Stores" } + {VPMOVB2M "Convert a Vector Register to a Mask" } + {VPMOVD2M "Convert a Vector Register to a Mask" } + {VPMOVDB "Down Convert DWord to Byte" } + {VPMOVDW "Down Convert DWord to Word" } + {VPMOVM2B "Convert a Mask Register to a Vector Register" } + {VPMOVM2D "Convert a Mask Register to a Vector Register" } + {VPMOVM2Q "Convert a Mask Register to a Vector Register" } + {VPMOVM2W "Convert a Mask Register to a Vector Register" } + {VPMOVQ2M "Convert a Vector Register to a Mask" } + {VPMOVQB "Down Convert QWord to Byte" } + {VPMOVQD "Down Convert QWord to DWord" } + {VPMOVQW "Down Convert QWord to Word" } + {VPMOVSDB "Down Convert DWord to Byte" } + {VPMOVSDW "Down Convert DWord to Word" } + {VPMOVSQB "Down Convert QWord to Byte" } + {VPMOVSQD "Down Convert QWord to DWord" } + {VPMOVSQW "Down Convert QWord to Word" } + {VPMOVSWB "Down Convert Word to Byte" } + {VPMOVUSDB "Down Convert DWord to Byte" } + {VPMOVUSDW "Down Convert DWord to Word" } + {VPMOVUSQB "Down Convert QWord to Byte" } + {VPMOVUSQD "Down Convert QWord to DWord" } + {VPMOVUSQW "Down Convert QWord to Word" } + {VPMOVUSWB "Down Convert Word to Byte" } + {VPMOVW2M "Convert a Vector Register to a Mask" } + {VPMOVWB "Down Convert Word to Byte" } + {VPMULTISHIFTQB "Select Packed Unaligned Bytes from Quadword Sources" } + {VPOPCNT "Return the Count of Number of Bits Set to 1 in BYTE/WORD/DWORD/QWORD" } + {VPROLD "Bit Rotate Left" } + {VPROLQ "Bit Rotate Left" } + {VPROLVD "Bit Rotate Left" } + {VPROLVQ "Bit Rotate Left" } + {VPRORD "Bit Rotate Right" } + {VPRORQ "Bit Rotate Right" } + {VPRORVD "Bit Rotate Right" } + {VPRORVQ "Bit Rotate Right" } + {VPSCATTERDD "Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices" } + {VPSCATTERDQ "Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices" } + {VPSCATTERQD "Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices" } + {VPSCATTERQQ "Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices" } + {VPSHLD "Concatenate and Shift Packed Data Left Logical" } + {VPSHLDV "Concatenate and Variable Shift Packed Data Left Logical" } + {VPSHRD "Concatenate and Shift Packed Data Right Logical" } + {VPSHRDV "Concatenate and Variable Shift Packed Data Right Logical" } + {VPSHUFBITQMB "Shuffle Bits from Quadword Elements Using Byte Indexes into Mask" } + {VPSLLVD "Variable Bit Shift Left Logical" } + {VPSLLVQ "Variable Bit Shift Left Logical" } + {VPSLLVW "Variable Bit Shift Left Logical" } + {VPSRAVD "Variable Bit Shift Right Arithmetic" } + {VPSRAVQ "Variable Bit Shift Right Arithmetic" } + {VPSRAVW "Variable Bit Shift Right Arithmetic" } + {VPSRLVD "Variable Bit Shift Right Logical" } + {VPSRLVQ "Variable Bit Shift Right Logical" } + {VPSRLVW "Variable Bit Shift Right Logical" } + {VPTERNLOGD "Bitwise Ternary Logic" } + {VPTERNLOGQ "Bitwise Ternary Logic" } + {VPTESTMB "Logical AND and Set Mask" } + {VPTESTMD "Logical AND and Set Mask" } + {VPTESTMQ "Logical AND and Set Mask" } + {VPTESTMW "Logical AND and Set Mask" } + {VPTESTNMB "Logical NAND and Set" } + {VPTESTNMD "Logical NAND and Set" } + {VPTESTNMQ "Logical NAND and Set" } + {VPTESTNMW "Logical NAND and Set" } + {VRANGEPD "Range Restriction Calculation For Packed Pairs of Float64 Values" } + {VRANGEPS "Range Restriction Calculation For Packed Pairs of Float32 Values" } + {VRANGESD "Range Restriction Calculation From a pair of Scalar Float64 Values" } + {VRANGESS "Range Restriction Calculation From a Pair of Scalar Float32 Values" } + {VRCP14PD "Compute Approximate Reciprocals of Packed Float64 Values" } + {VRCP14PS "Compute Approximate Reciprocals of Packed Float32 Values" } + {VRCP14SD "Compute Approximate Reciprocal of Scalar Float64 Value" } + {VRCP14SS "Compute Approximate Reciprocal of Scalar Float32 Value" } + {VREDUCEPD "Perform Reduction Transformation on Packed Float64 Values" } + {VREDUCEPS "Perform Reduction Transformation on Packed Float32 Values" } + {VREDUCESD "Perform a Reduction Transformation on a Scalar Float64 Value" } + {VREDUCESS "Perform a Reduction Transformation on a Scalar Float32 Value" } + {VRNDSCALEPD "Round Packed Float64 Values To Include A Given Number Of Fraction Bits" } + {VRNDSCALEPS "Round Packed Float32 Values To Include A Given Number Of Fraction Bits" } + {VRNDSCALESD "Round Scalar Float64 Value To Include A Given Number Of Fraction Bits" } + {VRNDSCALESS "Round Scalar Float32 Value To Include A Given Number Of Fraction Bits" } + {VRSQRT14PD "Compute Approximate Reciprocals of Square Roots of Packed Float64 Values" } + {VRSQRT14PS "Compute Approximate Reciprocals of Square Roots of Packed Float32 Values" } + {VRSQRT14SD "Compute Approximate Reciprocal of Square Root of Scalar Float64 Value" } + {VRSQRT14SS "Compute Approximate Reciprocal of Square Root of Scalar Float32 Value" } + {VSCALEFPD "Scale Packed Float64 Values With Float64 Values" } + {VSCALEFPS "Scale Packed Float32 Values With Float32 Values" } + {VSCALEFSD "Scale Scalar Float64 Values With Float64 Values" } + {VSCALEFSS "Scale Scalar Float32 Value With Float32 Value" } + {VSCATTERDPD "Scatter Packed Single, Packed Double with Signed Dword and Qword Indices" } + {VSCATTERDPS "Scatter Packed Single, Packed Double with Signed Dword and Qword Indices" } + {VSCATTERQPD "Scatter Packed Single, Packed Double with Signed Dword and Qword Indices" } + {VSCATTERQPS "Scatter Packed Single, Packed Double with Signed Dword and Qword Indices" } + {VSHUFF32x4 "Shuffle Packed Values at 128-bit Granularity" } + {VSHUFF64x2 "Shuffle Packed Values at 128-bit Granularity" } + {VSHUFI32x4 "Shuffle Packed Values at 128-bit Granularity" } + {VSHUFI64x2 "Shuffle Packed Values at 128-bit Granularity" } + {VTESTPD "Packed Bit Test" } + {VTESTPS "Packed Bit Test" } + {VZEROALL "Zero XMM, YMM and ZMM Registers" } + {VZEROUPPER "Zero Upper Bits of YMM and ZMM Registers" } + {WAIT "Wait" } + {WBINVD "Write Back and Invalidate Cache" } + {WBNOINVD "Write Back and Do Not Invalidate Cache" } + {WRFSBASE "Write FS/GS Segment Base" } + {WRGSBASE "Write FS/GS Segment Base" } + {WRMSR "Write to Model Specific Register" } + {WRPKRU "Write Data to User Page Key Register" } + {WRSSD "Write to Shadow Stack" } + {WRSSQ "Write to Shadow Stack" } + {WRUSSD "Write to User Shadow Stack" } + {WRUSSQ "Write to User Shadow Stack" } + {XABORT "Transactional Abort" } + {XACQUIRE "Hardware Lock Elision Prefix Hints" } + {XADD "Exchange and Add" } + {XBEGIN "Transactional Begin" } + {XCHG "Exchange Register/Memory with Register" } + {XEND "Transactional End" } + {XGETBV "Get Value of Extended Control Register" } + {XLAT "Table Look-up Translation" } + {XLATB "Table Look-up Translation" } + {XOR "Logical Exclusive OR" } + {XORPD "Bitwise Logical XOR of Packed Double Precision Floating-Point Values" } + {XORPS "Bitwise Logical XOR of Packed Single Precision Floating-Point Values" } + {XRELEASE "Hardware Lock Elision Prefix Hints" } + {XRSTOR "Restore Processor Extended States" } + {XRSTORS "Restore Processor Extended States Supervisor" } + {XSAVE "Save Processor Extended States" } + {XSAVEC "Save Processor Extended States with Compaction" } + {XSAVEOPT "Save Processor Extended States Optimized" } + {XSAVES "Save Processor Extended States Supervisor" } + {XSETBV "Set Extended Control Register" } + {XTEST "Test If In Transactional Execution" } + + //- rjf: sgx + {ENCLS "Execute an Enclave System Function of Specified Leaf Number" } + {ENCLS "[EADD] Add a Page to an Uninitialized Enclave" } + {ENCLS "[EAUG] Add a Page to an Initialized Enclave" } + {ENCLS "[EBLOCK] Mark a page in EPC as Blocked" } + {ENCLS "[ECREATE] Create an SECS page in the Enclave Page Cache" } + {ENCLS "[EDBGRD] Read From a Debug Enclave" } + {ENCLS "[EDBGWR] Write to a Debug Enclave" } + {ENCLS "[EEXTEND] Extend Uninitialized Enclave Measurement by 256 Bytes" } + {ENCLS "[EINIT] Initialize an Enclave for Execution" } + {ENCLS "[ELDBC] Load an EPC Page and Mark its State" } + {ENCLS "[ELDB] Load an EPC Page and Mark its State" } + {ENCLS "[ELDUC] Load an EPC Page and Mark its State" } + {ENCLS "[ELDU] Load an EPC Page and Mark its State" } + {ENCLS "[EMODPR] Restrict the Permissions of an EPC Page" } + {ENCLS "[EMODT] Change the Type of an EPC Page" } + {ENCLS "[EPA] Add Version Array" } + {ENCLS "[ERDINFO] Read Type and Status Information About an EPC Page" } + {ENCLS "[EREMOVE] Remove a page from the EPC" } + {ENCLS "[ETRACKC] Activates EBLOCK Checks" } + {ENCLS "[ETRACK] Activates EBLOCK Checks" } + {ENCLS "[EWB] Invalidate an EPC Page and Write out to Main Memory" } + {ENCLU "Execute an Enclave User Function of Specified Leaf Number" } + {ENCLU "[EACCEPTCOPY] Initialize a Pending Page" } + {ENCLU "[EACCEPT] Accept Changes to an EPC Page" } + {ENCLU "[EENTER] Enters an Enclave" } + {ENCLU "[EEXIT] Exits an Enclave" } + {ENCLU "[EGETKEY] Retrieves a Cryptographic Key" } + {ENCLU "[EMODPE] Extend an EPC Page Permissions" } + {ENCLU "[EREPORT] Create a Cryptographic Report of the Enclave" } + {ENCLU "[ERESUME] Re-Enters an Enclave" } + {ENCLV "Execute an Enclave VMM Function of Specified Leaf Number" } + + //- rjf: vmx + {INVEPT "Invalidate Translations Derived from EPT" } + {INVVPID "Invalidate Translations Based on VPID" } + {VMCALL "Call to VM Monitor" } + {VMCLEAR "Clear Virtual-Machine Control Structure" } + {VMFUNC "Invoke VM function" } + {VMLAUNCH "Launch/Resume Virtual Machine" } + {VMPTRLD "Load Pointer to Virtual-Machine Control Structure" } + {VMPTRST "Store Pointer to Virtual-Machine Control Structure" } + {VMREAD "Read Field from Virtual-Machine Control Structure" } + {VMRESUME "Launch/Resume Virtual Machine" } + {VMWRITE "Write Field to Virtual-Machine Control Structure" } + {VMXOFF "Leave VMX Operation" } + {VMXON "Enter VMX Operation" } + + //- rjf: xeon phi + {PREFETCHWT1 "Prefetch Vector Data Into Caches with Intent to Write and T1 Hint" } + {V4FMADDPS "Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations)" } + {V4FMADDSS "Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations)" } + {V4FNMADDPS "Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations)" } + {V4FNMADDSS "Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations)" } + {VEXP2PD "Approximation to the Exponential 2^x of Packed Double-Precision Floating-Point Values with Less Than 2^-23 Relative Error"} + {VEXP2PS "Approximation to the Exponential 2^x of Packed Single-Precision Floating-Point Values with Less Than 2^-23 Relative Error"} + {VGATHERPF0DPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint" } + {VGATHERPF0DPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint" } + {VGATHERPF0QPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint" } + {VGATHERPF0QPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint" } + {VGATHERPF1DPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint" } + {VGATHERPF1DPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint" } + {VGATHERPF1QPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint" } + {VGATHERPF1QPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint" } + {VP4DPWSSD "Dot Product of Signed Words with Dword Accumulation (4-iterations)" } + {VP4DPWSSDS "Dot Product of Signed Words with Dword Accumulation and Saturation (4-iterations)" } + {VRCP28PD "Approximation to the Reciprocal of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error" } + {VRCP28PS "Approximation to the Reciprocal of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error" } + {VRCP28SD "Approximation to the Reciprocal of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error" } + {VRCP28SS "Approximation to the Reciprocal of Scalar Single-Precision Floating-Point Value with Less Than 2^-28 Relative Error" } + {VRSQRT28PD "Approximation to the Reciprocal Square Root of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error"} + {VRSQRT28PS "Approximation to the Reciprocal Square Root of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error"} + {VRSQRT28SD "Approximation to the Reciprocal Square Root of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error"} + {VRSQRT28SS "Approximation to the Reciprocal Square Root of Scalar Single-Precision Floating- Point Value with Less Than 2^-28 Relative Error"} + {VSCATTERPF0DPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write" } + {VSCATTERPF0DPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write" } + {VSCATTERPF0QPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write" } + {VSCATTERPF0QPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write" } + {VSCATTERPF1DPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write" } + {VSCATTERPF1DPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write" } + {VSCATTERPF1QPD "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write" } + {VSCATTERPF1QPS "Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write" } + +} + +//////////////////////////////// +//~ rjf: Developer Toggles + +@table(name) +DF_DevToggleTable: +{ + {telemetry_capture} + {simulate_lag} + {draw_ui_text_pos} + {draw_ui_focus_debug} + {draw_ui_box_heatmap} + {eval_compiler_tooltips} + {eval_watch_key_tooltips} + {cmd_context_tooltips} + {scratch_mouse_draw} + {updating_indicator} +} + +//////////////////////////////// +//~ rjf: Generators + +//- rjf: enums + +@table_gen_enum +DF_CfgSrc: +{ + @expand(DF_CfgSrcTable a) `DF_CfgSrc_$(a.name),`; + `DF_CfgSrc_COUNT`; +} + +@table_gen_enum +DF_EntityKind: +{ + @expand(DF_EntityKindTable a) `DF_EntityKind_$(a.name),`; + `DF_EntityKind_COUNT`; +} + +@table_gen_enum +DF_NameKind: +{ + @expand(DF_NameKindTable, a) `DF_NameKind_$(a.name),`; + `DF_NameKind_COUNT`; +} + +@table_gen_enum +DF_CoreCmdKind: +{ + @expand(DF_CoreCmdTable, a) + `DF_CoreCmdKind_$(a.name),`, + `DF_CoreCmdKind_COUNT`, +} + +@table_gen_enum +DF_IconKind: +{ + @expand(DF_IconTable a) + `DF_IconKind_$(a.name),`; + `DF_IconKind_COUNT`; +} + +@table_gen_enum +DF_CoreViewRuleKind: +{ + @expand(DF_CoreViewRuleTable a) `DF_CoreViewRuleKind_$(a.name),`; + `DF_CoreViewRuleKind_COUNT`; +} + +//- rjf: command params + +@table_gen_enum +DF_CmdParamSlot: +{ + `DF_CmdParamSlot_Null,`; + @expand(DF_CmdParamSlotTable a) + `DF_CmdParamSlot_$(a.name),`; + `DF_CmdParamSlot_COUNT`; +} + +@table_gen +{ + `typedef struct DF_CmdParams DF_CmdParams;`; + `struct DF_CmdParams`; + `{`; + `U64 slot_props[(DF_CmdParamSlot_COUNT + 63) / 64];`; + @expand(DF_CmdParamSlotTable a) + `$(a.c_type) $(a.name_lower);`; + `};`; +} + +@table_gen_enum +DF_CmdQueryRule: +{ + @expand(DF_CmdQueryRuleTable a) + `DF_CmdQueryRule_$(a.name),`; + `DF_CmdQueryRule_COUNT`; +} + +@table_gen_data(type: String8, fallback: `{0}`) +df_g_cmd_query_rule_kind_arg_desc_table: +{ + @expand(DF_CmdQueryRuleTable a) + `str8_lit_comp("$(a.args_desc)"),`; +} + +//- rjf: entity kind tables + +@table_gen_data(type: DF_IconKind, fallback: `DF_IconKind_Null`) +df_g_entity_kind_icon_kind_table: +{ + @expand(DF_EntityKindTable a) `DF_IconKind_$(a.icon_kind),`; +} + +@table_gen_data(type: String8, fallback: `{0}`) +df_g_entity_kind_display_string_table: +{ + @expand(DF_EntityKindTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type: String8, fallback: `{0}`) +df_g_entity_kind_name_label_table: +{ + @expand(DF_EntityKindTable a) `str8_lit_comp("$(a.name_label)"),`; +} + +@table_gen_data(type:DF_EntityKindFlags, fallback: `0`) +df_g_entity_kind_flags_table: +{ + @expand(DF_EntityKindTable a) `($(a.lf_mut_user_cfg)*DF_EntityKindFlag_LeafMutationUserConfig | $(a.lf_mut_prof_cfg)*DF_EntityKindFlag_LeafMutationProfileConfig | $(a.lf_mut_halt)*DF_EntityKindFlag_LeafMutationSoftHalt | $(a.lf_mut_dbg)*DF_EntityKindFlag_LeafMutationDebugInfoMap | $(a.tr_mut_user_cfg)*DF_EntityKindFlag_TreeMutationUserConfig | $(a.tr_mut_prof_cfg)*DF_EntityKindFlag_TreeMutationProfileConfig | $(a.tr_mut_halt)*DF_EntityKindFlag_TreeMutationSoftHalt | $(a.tr_mut_dbg)*DF_EntityKindFlag_TreeMutationDebugInfoMap | $(a.name_is_code)*DF_EntityKindFlag_NameIsCode | $(a.user_lifetime)*DF_EntityKindFlag_UserDefinedLifetime),`; +} + +@table_gen_data(type: DF_EntityOpFlags, fallback: `0`) +df_g_entity_kind_op_flags_table: +{ + @expand(DF_EntityKindTable a) `($(a.op_delete)*DF_EntityOpFlag_Delete) | ($(a.op_freeze)*DF_EntityOpFlag_Freeze) | ($(a.op_edit)*DF_EntityOpFlag_Edit) | ($(a.op_rename)*DF_EntityOpFlag_Rename) | ($(a.op_enable)*DF_EntityOpFlag_Enable) | ($(a.op_cond)*DF_EntityOpFlag_Condition) | ($(a.op_dup)*DF_EntityOpFlag_Duplicate),`; +} + +//- rjf: config source tables + +@table_gen_data(type: String8, fallback: DF_CoreCmdKind_Null) +df_g_cfg_src_string_table: +{ + @expand(DF_CfgSrcTable a) `str8_lit_comp("$(a.string)"),`; +} + +@table_gen_data(type: DF_CoreCmdKind, fallback: DF_CoreCmdKind_Null) +df_g_cfg_src_load_cmd_kind_table: +{ + @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.load_cmd),`; +} + +@table_gen_data(type: DF_CoreCmdKind, fallback: DF_CoreCmdKind_Null) +df_g_cfg_src_write_cmd_kind_table: +{ + @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.write_cmd),`; +} + +@table_gen_data(type: DF_CoreCmdKind, fallback: DF_CoreCmdKind_Null) +df_g_cfg_src_apply_cmd_kind_table: +{ + @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.apply_cmd),`; +} + +//- rjf: core view rule function prototypes + +@table_gen +{ + ``; + @expand(DF_CoreViewRuleTable a) + `$(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(" .. a.name_lower .. ");")`; + @expand(DF_CoreViewRuleTable a) + `$(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(" .. a.name_lower .. ");")`; +} + +//- rjf: core command kind tables + +@table_gen_data(type: DF_CmdSpecInfo, fallback: `{0}`) @c_file +df_g_core_cmd_kind_spec_info_table: +{ + @expand(DF_CoreCmdTable, a) + ```{ str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.desc)"), str8_lit_comp("$(a.search_tags)"), str8_lit_comp("$(a.display_name)"), (DF_CmdSpecFlag_OmitFromLists*$(a.lister_omit)) | (DF_CmdSpecFlag_RunKeepsQuery*$(a.keep_query)) | (DF_CmdSpecFlag_QueryUsesOldInput*$(a.old_input)) | (DF_CmdSpecFlag_AppliesToView*$(a.apply_to_view)) | (DF_CmdSpecFlag_QueryIsCode*$(a.query_is_code)), {DF_CmdParamSlot_$(a.query_slot0), DF_CmdParamSlot_$(a.query_slot1), DF_CmdParamSlot_$(a.query_slot2)}, DF_CmdQueryRule_$(a.query_rule), DF_IconKind_$(a.canonical_icon), {$(a.query_info_0_u64), $(a.query_info_1_u64)}},```; +} + +//- rjf: core view rule tables + +@table_gen_data(type: DF_CoreViewRuleSpecInfo, fallback: `{0}`) @c_file +df_g_core_view_rule_spec_info_table: +{ + @expand(DF_CoreViewRuleTable a) + ```{str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.description)"), (DF_CoreViewRuleSpecInfoFlag_Inherited*$(a.ih == "x"))|(DF_CoreViewRuleSpecInfoFlag_Expandable*$(a.ex == "x"))|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*$(a.er == "x"))|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*$(a.vb == "x")), $(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME("..a.name_lower..")") $(a.er != "x" -> 0), $(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vb != "x" -> 0), },```; +} + +//- rjf: icon kinds + +@table_gen_data(type: String8, fallback: `{0}`) +df_g_icon_kind_text_table: +{ + @expand(DF_IconTable a) + `str8_lit_comp("$(a.text)"),`; +} + +//- rjf: instruction metadata table + +@table_gen +{ + ``; + `struct{String8 mnemonic; String8 summary;} df_g_inst_table_x64[] =`; + `{`; + @expand(DF_InstTableX64 a) `{str8_lit_comp("$(a.name)"), str8_lit_comp("$(a.summary)")},`; + `};`; + ``; +} + +//- rjf: developer toggles + +@table_gen +{ + @expand(DF_DevToggleTable a) `global B32 DEV_$(a.name) = 0;` +} + +@table_gen +{ + `struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =`; + `{`; + @expand(DF_DevToggleTable a) `{&DEV_$(a.name), str8_lit_comp("$(a.name)")},` + `};`; +} diff --git a/src/df/core/generated/df_core.meta.c b/src/df/core/generated/df_core.meta.c new file mode 100644 index 00000000..87d0345d --- /dev/null +++ b/src/df/core/generated/df_core.meta.c @@ -0,0 +1,225 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[] = +{ +{ str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("exit"), str8_lit_comp("Exits the debugger."), str8_lit_comp("quit,close,abort"), str8_lit_comp("Exit"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_X, {0, 0}}, +{ str8_lit_comp("command_fast_path"), str8_lit_comp("Performs the fast path for the command named by the argument."), str8_lit_comp(""), str8_lit_comp("Command Fast Path"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_CmdSpec, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("error"), str8_lit_comp("Notifies of an error."), str8_lit_comp(""), str8_lit_comp("Error"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp("Launch and Run"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_EntityList, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Play, {DF_EntityKind_Target, 0}}, +{ str8_lit_comp("launch_and_init"), str8_lit_comp("Starts debugging a new instance of a target, then stops at the program's entry point."), str8_lit_comp("launch,start,entry,point"), str8_lit_comp("Launch and Initialize"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_EntityList, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_PlayStepForward, {DF_EntityKind_Target, 0}}, +{ str8_lit_comp("kill"), str8_lit_comp("Kills the specified existing debugged process(es)."), str8_lit_comp("stop,kill"), str8_lit_comp("Kill"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_EntityList, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Stop, {DF_EntityKind_Process, 0}}, +{ str8_lit_comp("kill_all"), str8_lit_comp("Kills all debugged child processes."), str8_lit_comp("stop,kill,all"), str8_lit_comp("Kill All"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Stop, {0, 0}}, +{ str8_lit_comp("detach"), str8_lit_comp("Detaches the specified debugged process."), str8_lit_comp("detach"), str8_lit_comp("Detach"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_EntityList, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Null, {DF_EntityKind_Process, 0}}, +{ str8_lit_comp("continue"), str8_lit_comp("Continues all halted threads."), str8_lit_comp(""), str8_lit_comp("Continue"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Play, {0, 0}}, +{ str8_lit_comp("step_into_inst"), str8_lit_comp("Performs a step that goes into calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp("Step Into (Assembly)"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_StepInto, {0, 0}}, +{ str8_lit_comp("step_over_inst"), str8_lit_comp("Performs a step that skips calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp("Step Over (Assembly)"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_StepOver, {0, 0}}, +{ str8_lit_comp("step_into_line"), str8_lit_comp("Performs a step that goes into calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp("Step Into (Line)"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_StepInto, {0, 0}}, +{ str8_lit_comp("step_over_line"), str8_lit_comp("Performs a step that skips calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp("Step Over (Line)"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_StepOver, {0, 0}}, +{ str8_lit_comp("step_out"), str8_lit_comp("Runs to the end of the current function and exits it."), str8_lit_comp(""), str8_lit_comp("Step Out"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_StepOut, {0, 0}}, +{ str8_lit_comp("run_to_address"), str8_lit_comp("Runs the selected thread to the specified address."), str8_lit_comp(""), str8_lit_comp("Run To Address"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_VirtualAddr, DF_CmdParamSlot_Null}, DF_CmdQueryRule_VirtualAddr, DF_IconKind_PlayStepForward, {0, 0}}, +{ str8_lit_comp("run_to_module_offset"), str8_lit_comp("Runs the selected thread to the specified offset within the current module."), str8_lit_comp(""), str8_lit_comp("Run To Module Offset"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_VirtualOff, DF_CmdParamSlot_Null}, DF_CmdQueryRule_VirtualOff, DF_IconKind_PlayStepForward, {0, 0}}, +{ str8_lit_comp("halt"), str8_lit_comp("Halts all running processes."), str8_lit_comp("pause"), str8_lit_comp("Halt"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Pause, {0, 0}}, +{ str8_lit_comp("soft_halt_refresh"), str8_lit_comp("Interrupts all running processes to collect data, and then resumes them."), str8_lit_comp(""), str8_lit_comp("Soft Halt Refresh"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Refresh, {0, 0}}, +{ str8_lit_comp("set_thread_ip"), str8_lit_comp("Sets the passed thread's instruction pointer at the passed address."), str8_lit_comp(""), str8_lit_comp("Set Thread IP"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_VirtualAddr, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("run"), str8_lit_comp("Runs all targets after starting them if they have not been started yet."), str8_lit_comp("play"), str8_lit_comp("Run"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Play, {0, 0}}, +{ str8_lit_comp("restart"), str8_lit_comp("Kills all running processes, then restarts the targets which were used to launch all current processes (if any)."), str8_lit_comp("restart,retry"), str8_lit_comp("Restart"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Redo, {0, 0}}, +{ str8_lit_comp("step_into"), str8_lit_comp("Steps once, possibly into function calls, for either line or instructions."), str8_lit_comp(""), str8_lit_comp("Step Into"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_StepInto, {0, 0}}, +{ str8_lit_comp("step_over"), str8_lit_comp("Steps once, always over function calls, for either line or instructions."), str8_lit_comp(""), str8_lit_comp("Step Over"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_StepOver, {0, 0}}, +{ str8_lit_comp("run_to_cursor"), str8_lit_comp("Runs the selected thread to the current cursor."), str8_lit_comp(""), str8_lit_comp("Run To Cursor"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_View, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Play, {0, 0}}, +{ str8_lit_comp("set_next_statement"), str8_lit_comp("Sets the selected thread's instruction pointer to the cursor's position."), str8_lit_comp(""), str8_lit_comp("Set Next Statement"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_View, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_RightArrow, {0, 0}}, +{ str8_lit_comp("enable_solo_stepping_mode"), str8_lit_comp("Enables 'solo stepping mode', which suspends all non-selected threads before stepping."), str8_lit_comp("solo,stepping,mode,suspend"), str8_lit_comp("Enable Solo Stepping Mode"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Thread, {0, 0}}, +{ str8_lit_comp("disable_solo_stepping_mode"), str8_lit_comp("Disables 'solo stepping mode', which suspends all non-selected threads before stepping."), str8_lit_comp("solo,stepping,mode,suspend"), str8_lit_comp("Disable Solo Stepping Mode"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Thread, {0, 0}}, +{ str8_lit_comp("select_thread"), str8_lit_comp("Selects a thread."), str8_lit_comp(""), str8_lit_comp("Select Thread"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Null, {DF_EntityKind_Thread, 0}}, +{ str8_lit_comp("select_thread_window"), str8_lit_comp("Selects a thread for the active window, overriding the global selected thread."), str8_lit_comp(""), str8_lit_comp("Select Thread On Window"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Window, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Null, {DF_EntityKind_Thread, 0}}, +{ str8_lit_comp("select_thread_view"), str8_lit_comp("Selects a thread for the active view, overriding the global and per-window selected threads."), str8_lit_comp(""), str8_lit_comp("Select Thread On View"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_View, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Null, {DF_EntityKind_Thread, 0}}, +{ str8_lit_comp("select_unwind"), str8_lit_comp("Selects an unwind frame number for the selected thread."), str8_lit_comp(""), str8_lit_comp("Select Unwind"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Index, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("up_one_frame"), str8_lit_comp("Selects the callstack frame above the currently selected."), str8_lit_comp(""), str8_lit_comp("Up One Frame"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_UpArrow, {0, 0}}, +{ str8_lit_comp("down_one_frame"), str8_lit_comp("Selects the callstack frame below the currently selected."), str8_lit_comp(""), str8_lit_comp("Down One Frame"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_DownArrow, {0, 0}}, +{ str8_lit_comp("freeze_thread"), str8_lit_comp("Freezes the passed thread."), str8_lit_comp(""), str8_lit_comp("Freeze Thread"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Locked, {DF_EntityKind_Thread, 0}}, +{ str8_lit_comp("thaw_thread"), str8_lit_comp("Thaws the passed thread."), str8_lit_comp(""), str8_lit_comp("Thaw Thread"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Unlocked, {DF_EntityKind_Thread, 0}}, +{ str8_lit_comp("freeze_process"), str8_lit_comp("Freezes the passed process."), str8_lit_comp(""), str8_lit_comp("Freeze Process"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Locked, {DF_EntityKind_Process, 0}}, +{ str8_lit_comp("thaw_process"), str8_lit_comp("Thaws the passed process."), str8_lit_comp(""), str8_lit_comp("Thaw Process"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Unlocked, {DF_EntityKind_Process, 0}}, +{ str8_lit_comp("freeze_machine"), str8_lit_comp("Freezes the passed machine."), str8_lit_comp(""), str8_lit_comp("Freeze Machine"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Locked, {DF_EntityKind_Machine, 0}}, +{ str8_lit_comp("thaw_machine"), str8_lit_comp("Thaws the passed machine."), str8_lit_comp(""), str8_lit_comp("Thaw Machine"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Unlocked, {DF_EntityKind_Machine, 0}}, +{ str8_lit_comp("freeze_local_machine"), str8_lit_comp("Freezes the local machine."), str8_lit_comp(""), str8_lit_comp("Freeze Local Machine"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Machine, {0, 0}}, +{ str8_lit_comp("thaw_local_machine"), str8_lit_comp("Thaws the local machine."), str8_lit_comp(""), str8_lit_comp("Thaw Local Machine"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Machine, {0, 0}}, +{ str8_lit_comp("inc_ui_font_scale"), str8_lit_comp("Increases the font size used for UI."), str8_lit_comp(""), str8_lit_comp("Increase UI Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("dec_ui_font_scale"), str8_lit_comp("Decreases the font size used for UI."), str8_lit_comp(""), str8_lit_comp("Decrease UI Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("inc_code_font_scale"), str8_lit_comp("Increases the font size used for code."), str8_lit_comp(""), str8_lit_comp("Increase Code Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("dec_code_font_scale"), str8_lit_comp("Decreases the font size used for code."), str8_lit_comp(""), str8_lit_comp("Decrease Code Font Scale"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("open_window"), str8_lit_comp("Opens a new window."), str8_lit_comp(""), str8_lit_comp("Open New Window"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}}, +{ str8_lit_comp("close_window"), str8_lit_comp("Closes an opened window."), str8_lit_comp(""), str8_lit_comp("Close Window"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}}, +{ str8_lit_comp("toggle_fullscreen"), str8_lit_comp("Toggles fullscreen view on the active window."), str8_lit_comp(""), str8_lit_comp("Toggle Fullscreen"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}}, +{ str8_lit_comp("reset_to_default_panels"), str8_lit_comp("Resets the window to the default panel layout."), str8_lit_comp("panel"), str8_lit_comp("Reset To Default Panel Layout"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}}, +{ str8_lit_comp("new_panel_right"), str8_lit_comp("Creates a new panel to the right of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Vertically"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_XSplit, {0, 0}}, +{ str8_lit_comp("new_panel_down"), str8_lit_comp("Creates a new panel at the bottom of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Horizontally"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_YSplit, {0, 0}}, +{ str8_lit_comp("rotate_panel_columns"), str8_lit_comp("Rotates all panels at the closest column level of the panel hierarchy."), str8_lit_comp(""), str8_lit_comp("Rotate Panel Columns"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("next_panel"), str8_lit_comp("Cycles the active panel forward."), str8_lit_comp(""), str8_lit_comp("Focus Next Panel"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_RightArrow, {0, 0}}, +{ str8_lit_comp("prev_panel"), str8_lit_comp("Cycles the active panel backwards."), str8_lit_comp(""), str8_lit_comp("Focus Previous Panel"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_LeftArrow, {0, 0}}, +{ str8_lit_comp("focus_panel"), str8_lit_comp("Focuses a new panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("focus_panel_right"), str8_lit_comp("Focuses a panel rightward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Right"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_RightArrow, {0, 0}}, +{ str8_lit_comp("focus_panel_left"), str8_lit_comp("Focuses a panel leftward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Left"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_LeftArrow, {0, 0}}, +{ str8_lit_comp("focus_panel_up"), str8_lit_comp("Focuses a panel upward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Up"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_UpArrow, {0, 0}}, +{ str8_lit_comp("focus_panel_down"), str8_lit_comp("Focuses a panel downward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Down"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_DownArrow, {0, 0}}, +{ str8_lit_comp("undo"), str8_lit_comp("Undoes the previous action."), str8_lit_comp(""), str8_lit_comp("Undo"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Undo, {0, 0}}, +{ str8_lit_comp("redo"), str8_lit_comp("Redoes the first previously undone action."), str8_lit_comp(""), str8_lit_comp("Redo"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Redo, {0, 0}}, +{ str8_lit_comp("go_back"), str8_lit_comp("Returns to the previously selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp("Go Back"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_LeftArrow, {0, 0}}, +{ str8_lit_comp("go_forward"), str8_lit_comp("Returns to the next selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp("Go Forward"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_RightArrow, {0, 0}}, +{ str8_lit_comp("close_panel"), str8_lit_comp("Closes the currently active panel."), str8_lit_comp(""), str8_lit_comp("Close Panel"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_ClosePanel, {0, 0}}, +{ str8_lit_comp("next_tab"), str8_lit_comp("Focuses the next tab on the active panel."), str8_lit_comp(""), str8_lit_comp("Focus Next Tab"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_RightArrow, {0, 0}}, +{ str8_lit_comp("prev_tab"), str8_lit_comp("Focuses the previous tab on the active panel."), str8_lit_comp(""), str8_lit_comp("Focus Previous Tab"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_LeftArrow, {0, 0}}, +{ str8_lit_comp("move_tab_right"), str8_lit_comp("Moves the selected tab right one slot."), str8_lit_comp(""), str8_lit_comp("Move Tab Right"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_RightArrow, {0, 0}}, +{ str8_lit_comp("move_tab_left"), str8_lit_comp("Moves the selected tab left one slot."), str8_lit_comp(""), str8_lit_comp("Move Tab Left"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_LeftArrow, {0, 0}}, +{ str8_lit_comp("close_tab"), str8_lit_comp("Closes the currently opened tab."), str8_lit_comp(""), str8_lit_comp("Close Tab"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_X, {0, 0}}, +{ str8_lit_comp("move_tab"), str8_lit_comp("Moves a tab to a new panel."), str8_lit_comp(""), str8_lit_comp("Move Tab"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("tab_bar_top"), str8_lit_comp("Anchors a panel's tab bar to the top of the panel."), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Top"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_UpArrow, {0, 0}}, +{ str8_lit_comp("tab_bar_bottom"), str8_lit_comp("Anchors a panel's tab bar to the bottom of the panel."), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Bottom"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_DownArrow, {0, 0}}, +{ str8_lit_comp("tab_bar_enable"), str8_lit_comp("Enables a panel's tab bar."), str8_lit_comp(""), str8_lit_comp("Enable Tab Bar"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("tab_bar_disable"), str8_lit_comp("Disables a panel's tab bar."), str8_lit_comp(""), str8_lit_comp("Disable Tab Bar"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("tab_bar_history_mode_enable"), str8_lit_comp("Enables history mode for a panel's tab bar, which orders and manages tabs as recorded history of views."), str8_lit_comp(""), str8_lit_comp("Enable Tab Bar History Mode"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("tab_bar_history_mode_disable"), str8_lit_comp("Disables history mode for a panel's tab bar."), str8_lit_comp(""), str8_lit_comp("Disable Tab Bar History Mode"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("set_current_path"), str8_lit_comp("Sets the debugger's current path, which is used as a starting point when browsing for files."), str8_lit_comp(""), str8_lit_comp("Set Current Path"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_FilePath, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_FilePath, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("open"), str8_lit_comp("Opens a file."), str8_lit_comp("code,source,file"), str8_lit_comp("Open"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_FilePath, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_FilePath, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("reload"), str8_lit_comp("Reloads a loaded file."), str8_lit_comp("code,source,file,reload"), str8_lit_comp("Reload"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_FileOutline, {DF_EntityKind_File, 0}}, +{ str8_lit_comp("reload_active"), str8_lit_comp("Reloads the active file."), str8_lit_comp("code,source,file,reload"), str8_lit_comp("Reload Active File"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("switch"), str8_lit_comp("Switches to a loaded file."), str8_lit_comp("code,source,file"), str8_lit_comp("Switch"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Entity}, DF_CmdQueryRule_Entity, DF_IconKind_FileOutline, {DF_EntityKind_File, DF_EntityFlag_IsFolder}}, +{ str8_lit_comp("set_file_override_link_src"), str8_lit_comp("Sets the source path for an override file link."), str8_lit_comp(""), str8_lit_comp("Set File Override Link Source"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("set_file_override_link_dst"), str8_lit_comp("Sets the destination path for an override file link."), str8_lit_comp(""), str8_lit_comp("Set File Override Link Destination"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("set_file_replacement_path"), str8_lit_comp("Sets the path which should be used as the replacement for the passed file."), str8_lit_comp(""), str8_lit_comp("Set File Replacement Path"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("load_user"), str8_lit_comp("Loads and applies a user file."), str8_lit_comp("load,user,profile,layout"), str8_lit_comp("Load User"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_FilePath, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_FilePath, DF_IconKind_Person, {0, 0}}, +{ str8_lit_comp("load_profile"), str8_lit_comp("Loads and applies a profile file."), str8_lit_comp("profile,project,session"), str8_lit_comp("Load Profile"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_FilePath, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_FilePath, DF_IconKind_Briefcase, {0, 0}}, +{ str8_lit_comp("apply_user_data"), str8_lit_comp("Applies user data from the active user file."), str8_lit_comp(""), str8_lit_comp("Apply User Data"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("apply_profile_data"), str8_lit_comp("Applies profile data from the active profile file."), str8_lit_comp(""), str8_lit_comp("Apply Profile Data"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("write_user_data"), str8_lit_comp("Writes user data to the active user file."), str8_lit_comp(""), str8_lit_comp("Write User Data"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("write_profile_data"), str8_lit_comp("Writes profile data to the active profile file."), str8_lit_comp(""), str8_lit_comp("Write Profile Data"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_left"), str8_lit_comp("Moves the cursor or selection left."), str8_lit_comp(""), str8_lit_comp("Move Left"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_right"), str8_lit_comp("Moves the cursor or selection right."), str8_lit_comp(""), str8_lit_comp("Move Right"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up"), str8_lit_comp("Moves the cursor or selection up."), str8_lit_comp(""), str8_lit_comp("Move Up"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down"), str8_lit_comp("Moves the cursor or selection down."), str8_lit_comp(""), str8_lit_comp("Move Down"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_left_select"), str8_lit_comp("Moves the cursor or selection left, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Left Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_right_select"), str8_lit_comp("Moves the cursor or selection right, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Right Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up_select"), str8_lit_comp("Moves the cursor or selection up, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down_select"), str8_lit_comp("Moves the cursor or selection down, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_left_chunk"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp("Move Left Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_right_chunk"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp("Move Right Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up_chunk"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp("Move Up Chunk"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down_chunk"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp("Move Down Chunk"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up_page"), str8_lit_comp("Moves the cursor or selection up one page."), str8_lit_comp(""), str8_lit_comp("Move Up Page"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down_page"), str8_lit_comp("Moves the cursor or selection down one page."), str8_lit_comp(""), str8_lit_comp("Move Down Page"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up_whole"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content."), str8_lit_comp(""), str8_lit_comp("Move Up Whole"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down_whole"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content."), str8_lit_comp(""), str8_lit_comp("Move Down Whole"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_left_chunk_select"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp("Move Left Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_right_chunk_select"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp("Move Right Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up_chunk_select"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp("Move Up Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down_chunk_select"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp("Move Down Chunk Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up_page_select"), str8_lit_comp("Moves the cursor or selection up one page, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Page Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down_page_select"), str8_lit_comp("Moves the cursor or selection down one page, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Page Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_up_whole_select"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Whole Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_down_whole_select"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Whole Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_home"), str8_lit_comp("Moves the cursor to the beginning of the line."), str8_lit_comp(""), str8_lit_comp("Move Home"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_end"), str8_lit_comp("Moves the cursor to the end of the line."), str8_lit_comp(""), str8_lit_comp("Move End"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_home_select"), str8_lit_comp("Moves the cursor to the beginning of the line, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Home Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("move_end_select"), str8_lit_comp("Moves the cursor to the end of the line, while selecting."), str8_lit_comp(""), str8_lit_comp("Move End Select"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("select_all"), str8_lit_comp("Selects everything possible."), str8_lit_comp(""), str8_lit_comp("Select All"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("delete_single"), str8_lit_comp("Deletes a single element to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Delete Single"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("delete_chunk"), str8_lit_comp("Deletes a chunk to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Delete Chunk"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("backspace_single"), str8_lit_comp("Deletes a single element to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Backspace Single"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("backspace_chunk"), str8_lit_comp("Deletes a chunk to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Backspace Chunk"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("copy"), str8_lit_comp("Copies the active selection to the clipboard."), str8_lit_comp(""), str8_lit_comp("Copy"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Clipboard, {0, 0}}, +{ str8_lit_comp("cut"), str8_lit_comp("Copies the active selection to the clipboard, then deletes it."), str8_lit_comp(""), str8_lit_comp("Cut"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Clipboard, {0, 0}}, +{ str8_lit_comp("paste"), str8_lit_comp("Pastes the current contents of the clipboard."), str8_lit_comp(""), str8_lit_comp("Paste"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Clipboard, {0, 0}}, +{ str8_lit_comp("insert_text"), str8_lit_comp("Inserts the text that was used to cause this command."), str8_lit_comp(""), str8_lit_comp("Insert Text"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("goto_line"), str8_lit_comp("Jumps to a line number in the current code file."), str8_lit_comp(""), str8_lit_comp("Go To Line"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_TextPoint, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_TextPoint, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("goto_address"), str8_lit_comp("Jumps to an address in the current memory or disassembly view."), str8_lit_comp(""), str8_lit_comp("Go To Address"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_VirtualAddr, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_VirtualAddr, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("center_cursor"), str8_lit_comp("Snaps the current code view to center the cursor."), str8_lit_comp(""), str8_lit_comp("Center Cursor"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("contain_cursor"), str8_lit_comp("Snaps the current code view to contain the cursor."), str8_lit_comp(""), str8_lit_comp("Contain Cursor"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("find_text_forward"), str8_lit_comp("Searches the current code file forward (from the cursor) for a string."), str8_lit_comp(""), str8_lit_comp("Find Text (Forward)"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*1) | (DF_CmdSpecFlag_QueryUsesOldInput*1) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_SearchString, DF_IconKind_Find, {0, 0}}, +{ str8_lit_comp("find_text_backward"), str8_lit_comp("Searches the current code file backwards (from the cursor) for a string."), str8_lit_comp(""), str8_lit_comp("Find Text (Backwards)"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*1) | (DF_CmdSpecFlag_QueryUsesOldInput*1) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_SearchString, DF_IconKind_Find, {0, 0}}, +{ str8_lit_comp("find_next"), str8_lit_comp("Searches the current code file forward (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp("Find Next"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*1) | (DF_CmdSpecFlag_QueryUsesOldInput*1) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Find, {0, 0}}, +{ str8_lit_comp("find_prev"), str8_lit_comp("Searches the current code file backwards (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp("Find Previous"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*1) | (DF_CmdSpecFlag_QueryUsesOldInput*1) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Find, {0, 0}}, +{ str8_lit_comp("find_thread"), str8_lit_comp("Jumps to the passed thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp("Find Thread"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Find, {DF_EntityKind_Thread, 0}}, +{ str8_lit_comp("find_selected_thread"), str8_lit_comp("Jumps to the selected thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp("Find Selected Thread"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Find, {0, 0}}, +{ str8_lit_comp("goto_name"), str8_lit_comp("Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp("Go To Name"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_String, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("goto_name_at_cursor"), str8_lit_comp("Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp("Go To Name At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("toggle_watch_expr"), str8_lit_comp("Adds or removes an expression to an opened watch view."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Binoculars, {0, 0}}, +{ str8_lit_comp("toggle_watch_expr_at_cursor"), str8_lit_comp("Adds or removes the expression that the cursor or selection is currently over to an opened watch view."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Binoculars, {0, 0}}, +{ str8_lit_comp("open_file_memory"), str8_lit_comp("Opens a memory view for the passed file."), str8_lit_comp(""), str8_lit_comp("Open File Memory"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Grid, {DF_EntityKind_File, 0}}, +{ str8_lit_comp("open_process_memory"), str8_lit_comp("Opens a memory view for the passed process."), str8_lit_comp(""), str8_lit_comp("Open Process Memory"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Grid, {DF_EntityKind_Process, 0}}, +{ str8_lit_comp("open_selected_process_memory"), str8_lit_comp("Opens a memory view for the selected process."), str8_lit_comp(""), str8_lit_comp("Open Selected Process Memory"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Grid, {0, 0}}, +{ str8_lit_comp("set_columns"), str8_lit_comp("Sets the number of columns for a memory view."), str8_lit_comp(""), str8_lit_comp("Set Columns"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Index, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Index, DF_IconKind_Thumbnails, {0, 0}}, +{ str8_lit_comp("toggle_address_visibility"), str8_lit_comp("Toggles the visibility of addresses in a disassembly view."), str8_lit_comp(""), str8_lit_comp("Toggle Address Visibility"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Thumbnails, {0, 0}}, +{ str8_lit_comp("toggle_code_bytes_visibility"), str8_lit_comp("Toggles the visibility of machine code bytes in a disassembly view."), str8_lit_comp(""), str8_lit_comp("Toggle Code Bytes Visibility"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Thumbnails, {0, 0}}, +{ str8_lit_comp("enable_entity"), str8_lit_comp("Enables an entity."), str8_lit_comp(""), str8_lit_comp("Enable Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("disable_entity"), str8_lit_comp("Disables an entity."), str8_lit_comp(""), str8_lit_comp("Disable Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("freeze_entity"), str8_lit_comp("Freezes an entity."), str8_lit_comp(""), str8_lit_comp("Freeze Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("thaw_entity"), str8_lit_comp("Thaws an entity."), str8_lit_comp(""), str8_lit_comp("Thaw Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("remove_entity"), str8_lit_comp("Removes an entity."), str8_lit_comp(""), str8_lit_comp("Remove Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("name_entity"), str8_lit_comp("Equips an entity with a name."), str8_lit_comp(""), str8_lit_comp("Name Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_String, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("edit_entity"), str8_lit_comp("Opens the editor for an entity."), str8_lit_comp(""), str8_lit_comp("Edit Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("duplicate_entity"), str8_lit_comp("Duplicates an entity."), str8_lit_comp(""), str8_lit_comp("Duplicate Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("text_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified line of source code."), str8_lit_comp(""), str8_lit_comp("Text Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_CircleFilled, {0, 0}}, +{ str8_lit_comp("address_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("Address Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_VirtualAddr, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_VirtualAddr, DF_IconKind_CircleFilled, {0, 0}}, +{ str8_lit_comp("function_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("Function Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_String, DF_IconKind_CircleFilled, {0, 0}}, +{ str8_lit_comp("toggle_breakpoint_cursor"), str8_lit_comp("Places or removes a breakpoint on the line on which the active cursor sits."), str8_lit_comp(""), str8_lit_comp("Toggle Breakpoint At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_CircleFilled, {0, 0}}, +{ str8_lit_comp("remove_breakpoint"), str8_lit_comp("Removes an existing breakpoint."), str8_lit_comp(""), str8_lit_comp("Remove Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Trash, {DF_EntityKind_Breakpoint, 0}}, +{ str8_lit_comp("enable_breakpoint"), str8_lit_comp("Enables a breakpoint."), str8_lit_comp(""), str8_lit_comp("Enable Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_CheckFilled, {DF_EntityKind_Breakpoint, 0}}, +{ str8_lit_comp("disable_breakpoint"), str8_lit_comp("Disables a breakpoint."), str8_lit_comp(""), str8_lit_comp("Disable Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_CheckHollow, {DF_EntityKind_Breakpoint, 0}}, +{ str8_lit_comp("toggle_watch_pin"), str8_lit_comp("Places or removes a watch pin on a textual location on a particular entity."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Pin"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_TextPoint, DF_CmdParamSlot_String}, DF_CmdQueryRule_String, DF_IconKind_Binoculars, {0, 0}}, +{ str8_lit_comp("toggle_watch_pin_at_cursor"), str8_lit_comp("Places or removes a watch pin at the cursor on the currently active file."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Pin At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*1), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_String, DF_IconKind_Binoculars, {0, 0}}, +{ str8_lit_comp("add_target"), str8_lit_comp("Adds a new target."), str8_lit_comp("application,executable,debug"), str8_lit_comp("Add Target"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_FilePath, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_FilePath, DF_IconKind_Target, {0, 0}}, +{ str8_lit_comp("remove_target"), str8_lit_comp("Removes an existing target."), str8_lit_comp("delete,remove,target"), str8_lit_comp("Remove Target"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Trash, {DF_EntityKind_Target, 0}}, +{ str8_lit_comp("edit_target"), str8_lit_comp("Edits an existing target."), str8_lit_comp(""), str8_lit_comp("Edit Target"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Pencil, {DF_EntityKind_Target, 0}}, +{ str8_lit_comp("retry_ended_process"), str8_lit_comp("Launches a new process with the same options as the passed ended process."), str8_lit_comp(""), str8_lit_comp("Retry Ended Process"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Entity, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Entity, DF_IconKind_Null, {DF_EntityKind_EndedProcess, 0}}, +{ str8_lit_comp("attach"), str8_lit_comp("Attaches to a process that is already running on the local machine."), str8_lit_comp(""), str8_lit_comp("Attach"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_String, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_String, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("register_as_jit_debugger"), str8_lit_comp("Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system."), str8_lit_comp(""), str8_lit_comp("Register As Just-In-Time (JIT) Debugger"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("entity_ref_fast_path"), str8_lit_comp("Activates the default behavior when clicking an entity reference."), str8_lit_comp(""), str8_lit_comp("Entity Reference Fast Path"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("spawn_entity_view"), str8_lit_comp("Spawns a new view, given an entity and other parameterizations."), str8_lit_comp(""), str8_lit_comp("Spawn Entity View"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("find_code_location"), str8_lit_comp("Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary."), str8_lit_comp(""), str8_lit_comp("Find Code Location"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_FilePath, DF_CmdParamSlot_TextPoint, DF_CmdParamSlot_Null}, DF_CmdQueryRule_FilePathAndTextPoint, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("commands"), str8_lit_comp("Opens the list of all commands."), str8_lit_comp(""), str8_lit_comp("Commands"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_String, DF_IconKind_List, {0, 0}}, +{ str8_lit_comp("target_editor"), str8_lit_comp("Opens the editor for a target."), str8_lit_comp(""), str8_lit_comp("Target"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Target, {0, 0}}, +{ str8_lit_comp("targets"), str8_lit_comp("Opens the list of all targets."), str8_lit_comp(""), str8_lit_comp("Targets"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Target, {0, 0}}, +{ str8_lit_comp("file_path_map"), str8_lit_comp("Opens the file path mapping editor."), str8_lit_comp(""), str8_lit_comp("File Path Map"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("scheduler"), str8_lit_comp("Opens the scheduler view, for process and thread controls."), str8_lit_comp(""), str8_lit_comp("Scheduler"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Scheduler, {0, 0}}, +{ str8_lit_comp("call_stack"), str8_lit_comp("Opens the call stack view."), str8_lit_comp("callstack,thread"), str8_lit_comp("Call Stack"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Thread, {0, 0}}, +{ str8_lit_comp("modules"), str8_lit_comp("Opens the modules view."), str8_lit_comp(""), str8_lit_comp("Modules"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Module, {0, 0}}, +{ str8_lit_comp("pending_entity"), str8_lit_comp("Opens a view which waits for the passed entity to be completely loaded, then replaces itself with a new view."), str8_lit_comp(""), str8_lit_comp("Pending Entity"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("code"), str8_lit_comp("Opens the code view for an already-loaded file."), str8_lit_comp(""), str8_lit_comp("Code"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("watch"), str8_lit_comp("Opens a watch view."), str8_lit_comp(""), str8_lit_comp("Watch"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Binoculars, {0, 0}}, +{ str8_lit_comp("locals"), str8_lit_comp("Opens a locals view."), str8_lit_comp(""), str8_lit_comp("Locals"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Binoculars, {0, 0}}, +{ str8_lit_comp("registers"), str8_lit_comp("Opens a registers view for the currently selected thread."), str8_lit_comp(""), str8_lit_comp("Registers"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Binoculars, {0, 0}}, +{ str8_lit_comp("output"), str8_lit_comp("Opens an output view."), str8_lit_comp(""), str8_lit_comp("Output"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_List, {0, 0}}, +{ str8_lit_comp("memory"), str8_lit_comp("Opens a memory view."), str8_lit_comp(""), str8_lit_comp("Memory"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Grid, {0, 0}}, +{ str8_lit_comp("disassembly"), str8_lit_comp("Opens the disassembly view."), str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Glasses, {0, 0}}, +{ str8_lit_comp("breakpoints"), str8_lit_comp("Opens the breakpoints view."), str8_lit_comp(""), str8_lit_comp("Breakpoints"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_CircleFilled, {0, 0}}, +{ str8_lit_comp("watch_pins"), str8_lit_comp("Opens the watch pins view."), str8_lit_comp(""), str8_lit_comp("Watch Pins"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Pin, {0, 0}}, +{ str8_lit_comp("exception_filters"), str8_lit_comp("Opens the exception filters view."), str8_lit_comp("exceptions,filters"), str8_lit_comp("Exception Filters"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Gear, {0, 0}}, +{ str8_lit_comp("theme"), str8_lit_comp("Opens the theme view."), str8_lit_comp("theme,color,scheme,palette"), str8_lit_comp("Theme"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Palette, {0, 0}}, +{ str8_lit_comp("pick_file"), str8_lit_comp("Opens the file browser to pick a file."), str8_lit_comp(""), str8_lit_comp("Pick File"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*1) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_FilePath, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_FilePath, DF_IconKind_FileOutline, {0, 0}}, +{ str8_lit_comp("complete_view"), str8_lit_comp("Completes a view, passing all parameters to a new command matching the passed command spec."), str8_lit_comp(""), str8_lit_comp("Complete View"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +{ str8_lit_comp("toggle_dev_menu"), str8_lit_comp("Opens and closes the developer menu."), str8_lit_comp(""), str8_lit_comp("Toggle Developer Menu"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}}, +}; + +DF_CoreViewRuleSpecInfo df_g_core_view_rule_spec_info_table[] = +{ +{str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, +{str8_lit_comp("array"), str8_lit_comp("Array"), str8_lit_comp("Specifies that a pointer points to N elements, rather than only 1."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(array) , 0, }, +{str8_lit_comp("list"), str8_lit_comp("List"), str8_lit_comp("Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(list) , }, +{str8_lit_comp("bswap"), str8_lit_comp("Byte Swap"), str8_lit_comp("Specifies that all integer primitives should be byte-swapped, such that their endianness is reversed."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(bswap) , 0, }, +{str8_lit_comp("dec"), str8_lit_comp("Decimal Base (Base 10)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-10 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, +{str8_lit_comp("bin"), str8_lit_comp("Binary Base (Base 2)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-2 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, +{str8_lit_comp("oct"), str8_lit_comp("Octal Base (Base 8)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-8 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, +{str8_lit_comp("hex"), str8_lit_comp("Hexadecimal Base (Base 16)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-16 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, +{str8_lit_comp("only"), str8_lit_comp("Only Specified Members"), str8_lit_comp("Specifies that only the specified members should appear in struct, union, or class evaluations."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(only) , }, +{str8_lit_comp("omit"), str8_lit_comp("Omit Specified Members"), str8_lit_comp("Omits a list of member names from appearing in struct, union, or class evaluations."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(omit) , }, +{str8_lit_comp("no_addr"), str8_lit_comp("Disable Address Values"), str8_lit_comp("Displays only what pointers point to, if possible, without the pointer's address value."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, +{str8_lit_comp("rgba"), str8_lit_comp("Color (RGBA)"), str8_lit_comp("Displays as a color, interpreting the data as encoding R, G, B, and A values."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(rgba) , }, +{str8_lit_comp("text"), str8_lit_comp("Text"), str8_lit_comp("Displays as text."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(text) , }, +{str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), str8_lit_comp("Displays as disassembled instructions, interpreting the data as raw machine code."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(disasm) , }, +{str8_lit_comp("bitmap"), str8_lit_comp("Bitmap"), str8_lit_comp("Displays as a bitmap, interpreting the data as raw pixel data."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(bitmap) , }, +{str8_lit_comp("geo"), str8_lit_comp("Geometry"), str8_lit_comp("Displays as geometry, interpreting the data as vertex data."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(geo) , }, +}; + diff --git a/src/df/core/generated/df_core.meta.h b/src/df/core/generated/df_core.meta.h new file mode 100644 index 00000000..9c6d63bf --- /dev/null +++ b/src/df/core/generated/df_core.meta.h @@ -0,0 +1,1785 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef DF_CORE_META_H +#define DF_CORE_META_H + +typedef enum DF_CfgSrc +{ +DF_CfgSrc_User, +DF_CfgSrc_Profile, +DF_CfgSrc_CommandLine, +DF_CfgSrc_COUNT +} DF_CfgSrc; + +typedef enum DF_EntityKind +{ +DF_EntityKind_Nil, +DF_EntityKind_Root, +DF_EntityKind_Machine, +DF_EntityKind_File, +DF_EntityKind_OverrideFileLink, +DF_EntityKind_PendingFileChange, +DF_EntityKind_DiagLog, +DF_EntityKind_FlashMarker, +DF_EntityKind_WatchPin, +DF_EntityKind_Breakpoint, +DF_EntityKind_Condition, +DF_EntityKind_Target, +DF_EntityKind_Executable, +DF_EntityKind_Arguments, +DF_EntityKind_ExecutionPath, +DF_EntityKind_EntryPointName, +DF_EntityKind_Source, +DF_EntityKind_Dest, +DF_EntityKind_CtrlRequest, +DF_EntityKind_Process, +DF_EntityKind_Thread, +DF_EntityKind_Module, +DF_EntityKind_DebugInfoOverride, +DF_EntityKind_ConversionTask, +DF_EntityKind_ConversionFail, +DF_EntityKind_EndedProcess, +DF_EntityKind_COUNT +} DF_EntityKind; + +typedef enum DF_NameKind +{ +DF_NameKind_Null, +DF_NameKind_EntityName, +DF_NameKind_EntityKindName, +DF_NameKind_COUNT +} DF_NameKind; + +typedef enum DF_CoreCmdKind +{ +DF_CoreCmdKind_Null, +DF_CoreCmdKind_Exit, +DF_CoreCmdKind_CommandFastPath, +DF_CoreCmdKind_Error, +DF_CoreCmdKind_LaunchAndRun, +DF_CoreCmdKind_LaunchAndInit, +DF_CoreCmdKind_Kill, +DF_CoreCmdKind_KillAll, +DF_CoreCmdKind_Detach, +DF_CoreCmdKind_Continue, +DF_CoreCmdKind_StepIntoInst, +DF_CoreCmdKind_StepOverInst, +DF_CoreCmdKind_StepIntoLine, +DF_CoreCmdKind_StepOverLine, +DF_CoreCmdKind_StepOut, +DF_CoreCmdKind_RunToAddress, +DF_CoreCmdKind_RunToModuleOffset, +DF_CoreCmdKind_Halt, +DF_CoreCmdKind_SoftHaltRefresh, +DF_CoreCmdKind_SetThreadIP, +DF_CoreCmdKind_Run, +DF_CoreCmdKind_Restart, +DF_CoreCmdKind_StepInto, +DF_CoreCmdKind_StepOver, +DF_CoreCmdKind_RunToCursor, +DF_CoreCmdKind_SetNextStatement, +DF_CoreCmdKind_EnableSoloSteppingMode, +DF_CoreCmdKind_DisableSoloSteppingMode, +DF_CoreCmdKind_SelectThread, +DF_CoreCmdKind_SelectThreadWindow, +DF_CoreCmdKind_SelectThreadView, +DF_CoreCmdKind_SelectUnwind, +DF_CoreCmdKind_UpOneFrame, +DF_CoreCmdKind_DownOneFrame, +DF_CoreCmdKind_FreezeThread, +DF_CoreCmdKind_ThawThread, +DF_CoreCmdKind_FreezeProcess, +DF_CoreCmdKind_ThawProcess, +DF_CoreCmdKind_FreezeMachine, +DF_CoreCmdKind_ThawMachine, +DF_CoreCmdKind_FreezeLocalMachine, +DF_CoreCmdKind_ThawLocalMachine, +DF_CoreCmdKind_IncUIFontScale, +DF_CoreCmdKind_DecUIFontScale, +DF_CoreCmdKind_IncCodeFontScale, +DF_CoreCmdKind_DecCodeFontScale, +DF_CoreCmdKind_OpenWindow, +DF_CoreCmdKind_CloseWindow, +DF_CoreCmdKind_ToggleFullscreen, +DF_CoreCmdKind_ResetToDefaultPanels, +DF_CoreCmdKind_NewPanelRight, +DF_CoreCmdKind_NewPanelDown, +DF_CoreCmdKind_RotatePanelColumns, +DF_CoreCmdKind_NextPanel, +DF_CoreCmdKind_PrevPanel, +DF_CoreCmdKind_FocusPanel, +DF_CoreCmdKind_FocusPanelRight, +DF_CoreCmdKind_FocusPanelLeft, +DF_CoreCmdKind_FocusPanelUp, +DF_CoreCmdKind_FocusPanelDown, +DF_CoreCmdKind_Undo, +DF_CoreCmdKind_Redo, +DF_CoreCmdKind_GoBack, +DF_CoreCmdKind_GoForward, +DF_CoreCmdKind_ClosePanel, +DF_CoreCmdKind_NextTab, +DF_CoreCmdKind_PrevTab, +DF_CoreCmdKind_MoveTabRight, +DF_CoreCmdKind_MoveTabLeft, +DF_CoreCmdKind_CloseTab, +DF_CoreCmdKind_MoveTab, +DF_CoreCmdKind_TabBarTop, +DF_CoreCmdKind_TabBarBottom, +DF_CoreCmdKind_TabBarEnable, +DF_CoreCmdKind_TabBarDisable, +DF_CoreCmdKind_TabBarHistoryModeEnable, +DF_CoreCmdKind_TabBarHistoryModeDisable, +DF_CoreCmdKind_SetCurrentPath, +DF_CoreCmdKind_Open, +DF_CoreCmdKind_Reload, +DF_CoreCmdKind_ReloadActive, +DF_CoreCmdKind_Switch, +DF_CoreCmdKind_SetFileOverrideLinkSrc, +DF_CoreCmdKind_SetFileOverrideLinkDst, +DF_CoreCmdKind_SetFileReplacementPath, +DF_CoreCmdKind_LoadUser, +DF_CoreCmdKind_LoadProfile, +DF_CoreCmdKind_ApplyUserData, +DF_CoreCmdKind_ApplyProfileData, +DF_CoreCmdKind_WriteUserData, +DF_CoreCmdKind_WriteProfileData, +DF_CoreCmdKind_MoveLeft, +DF_CoreCmdKind_MoveRight, +DF_CoreCmdKind_MoveUp, +DF_CoreCmdKind_MoveDown, +DF_CoreCmdKind_MoveLeftSelect, +DF_CoreCmdKind_MoveRightSelect, +DF_CoreCmdKind_MoveUpSelect, +DF_CoreCmdKind_MoveDownSelect, +DF_CoreCmdKind_MoveLeftChunk, +DF_CoreCmdKind_MoveRightChunk, +DF_CoreCmdKind_MoveUpChunk, +DF_CoreCmdKind_MoveDownChunk, +DF_CoreCmdKind_MoveUpPage, +DF_CoreCmdKind_MoveDownPage, +DF_CoreCmdKind_MoveUpWhole, +DF_CoreCmdKind_MoveDownWhole, +DF_CoreCmdKind_MoveLeftChunkSelect, +DF_CoreCmdKind_MoveRightChunkSelect, +DF_CoreCmdKind_MoveUpChunkSelect, +DF_CoreCmdKind_MoveDownChunkSelect, +DF_CoreCmdKind_MoveUpPageSelect, +DF_CoreCmdKind_MoveDownPageSelect, +DF_CoreCmdKind_MoveUpWholeSelect, +DF_CoreCmdKind_MoveDownWholeSelect, +DF_CoreCmdKind_MoveHome, +DF_CoreCmdKind_MoveEnd, +DF_CoreCmdKind_MoveHomeSelect, +DF_CoreCmdKind_MoveEndSelect, +DF_CoreCmdKind_SelectAll, +DF_CoreCmdKind_DeleteSingle, +DF_CoreCmdKind_DeleteChunk, +DF_CoreCmdKind_BackspaceSingle, +DF_CoreCmdKind_BackspaceChunk, +DF_CoreCmdKind_Copy, +DF_CoreCmdKind_Cut, +DF_CoreCmdKind_Paste, +DF_CoreCmdKind_InsertText, +DF_CoreCmdKind_GoToLine, +DF_CoreCmdKind_GoToAddress, +DF_CoreCmdKind_CenterCursor, +DF_CoreCmdKind_ContainCursor, +DF_CoreCmdKind_FindTextForward, +DF_CoreCmdKind_FindTextBackward, +DF_CoreCmdKind_FindNext, +DF_CoreCmdKind_FindPrev, +DF_CoreCmdKind_FindThread, +DF_CoreCmdKind_FindSelectedThread, +DF_CoreCmdKind_GoToName, +DF_CoreCmdKind_GoToNameAtCursor, +DF_CoreCmdKind_ToggleWatchExpression, +DF_CoreCmdKind_ToggleWatchExpressionAtCursor, +DF_CoreCmdKind_OpenFileMemory, +DF_CoreCmdKind_OpenProcessMemory, +DF_CoreCmdKind_OpenSelectedProcessMemory, +DF_CoreCmdKind_SetColumns, +DF_CoreCmdKind_ToggleAddressVisibility, +DF_CoreCmdKind_ToggleCodeBytesVisibility, +DF_CoreCmdKind_EnableEntity, +DF_CoreCmdKind_DisableEntity, +DF_CoreCmdKind_FreezeEntity, +DF_CoreCmdKind_ThawEntity, +DF_CoreCmdKind_RemoveEntity, +DF_CoreCmdKind_NameEntity, +DF_CoreCmdKind_EditEntity, +DF_CoreCmdKind_DuplicateEntity, +DF_CoreCmdKind_TextBreakpoint, +DF_CoreCmdKind_AddressBreakpoint, +DF_CoreCmdKind_FunctionBreakpoint, +DF_CoreCmdKind_ToggleBreakpointAtCursor, +DF_CoreCmdKind_RemoveBreakpoint, +DF_CoreCmdKind_EnableBreakpoint, +DF_CoreCmdKind_DisableBreakpoint, +DF_CoreCmdKind_ToggleWatchPin, +DF_CoreCmdKind_ToggleWatchPinAtCursor, +DF_CoreCmdKind_AddTarget, +DF_CoreCmdKind_RemoveTarget, +DF_CoreCmdKind_EditTarget, +DF_CoreCmdKind_RetryEndedProcess, +DF_CoreCmdKind_Attach, +DF_CoreCmdKind_RegisterAsJITDebugger, +DF_CoreCmdKind_EntityRefFastPath, +DF_CoreCmdKind_SpawnEntityView, +DF_CoreCmdKind_FindCodeLocation, +DF_CoreCmdKind_Commands, +DF_CoreCmdKind_Target, +DF_CoreCmdKind_Targets, +DF_CoreCmdKind_FilePathMap, +DF_CoreCmdKind_Scheduler, +DF_CoreCmdKind_CallStack, +DF_CoreCmdKind_Modules, +DF_CoreCmdKind_PendingEntity, +DF_CoreCmdKind_Code, +DF_CoreCmdKind_Watch, +DF_CoreCmdKind_Locals, +DF_CoreCmdKind_Registers, +DF_CoreCmdKind_Output, +DF_CoreCmdKind_Memory, +DF_CoreCmdKind_Disassembly, +DF_CoreCmdKind_Breakpoints, +DF_CoreCmdKind_WatchPins, +DF_CoreCmdKind_ExceptionFilters, +DF_CoreCmdKind_Theme, +DF_CoreCmdKind_PickFile, +DF_CoreCmdKind_ViewReturn, +DF_CoreCmdKind_ToggleDevMenu, +DF_CoreCmdKind_COUNT +} DF_CoreCmdKind; + +typedef enum DF_IconKind +{ +DF_IconKind_Null, +DF_IconKind_FolderOpenOutline, +DF_IconKind_FolderClosedOutline, +DF_IconKind_FolderOpenFilled, +DF_IconKind_FolderClosedFilled, +DF_IconKind_FileOutline, +DF_IconKind_FileFilled, +DF_IconKind_Play, +DF_IconKind_PlayStepForward, +DF_IconKind_Pause, +DF_IconKind_Stop, +DF_IconKind_Info, +DF_IconKind_WarningSmall, +DF_IconKind_WarningBig, +DF_IconKind_Unlocked, +DF_IconKind_Locked, +DF_IconKind_LeftArrow, +DF_IconKind_RightArrow, +DF_IconKind_UpArrow, +DF_IconKind_DownArrow, +DF_IconKind_Gear, +DF_IconKind_Pencil, +DF_IconKind_Trash, +DF_IconKind_Pin, +DF_IconKind_RadioHollow, +DF_IconKind_RadioFilled, +DF_IconKind_CheckHollow, +DF_IconKind_CheckFilled, +DF_IconKind_LeftCaret, +DF_IconKind_RightCaret, +DF_IconKind_UpCaret, +DF_IconKind_DownCaret, +DF_IconKind_UpScroll, +DF_IconKind_DownScroll, +DF_IconKind_LeftScroll, +DF_IconKind_RightScroll, +DF_IconKind_Add, +DF_IconKind_Minus, +DF_IconKind_Thread, +DF_IconKind_Threads, +DF_IconKind_Machine, +DF_IconKind_CircleFilled, +DF_IconKind_X, +DF_IconKind_Refresh, +DF_IconKind_Undo, +DF_IconKind_Redo, +DF_IconKind_Save, +DF_IconKind_Window, +DF_IconKind_Target, +DF_IconKind_Clipboard, +DF_IconKind_Scheduler, +DF_IconKind_Module, +DF_IconKind_XSplit, +DF_IconKind_YSplit, +DF_IconKind_ClosePanel, +DF_IconKind_StepInto, +DF_IconKind_StepOver, +DF_IconKind_StepOut, +DF_IconKind_Find, +DF_IconKind_Palette, +DF_IconKind_Thumbnails, +DF_IconKind_Glasses, +DF_IconKind_Binoculars, +DF_IconKind_List, +DF_IconKind_Grid, +DF_IconKind_QuestionMark, +DF_IconKind_Person, +DF_IconKind_Briefcase, +DF_IconKind_Dot, +DF_IconKind_COUNT +} DF_IconKind; + +typedef enum DF_CoreViewRuleKind +{ +DF_CoreViewRuleKind_Null, +DF_CoreViewRuleKind_Array, +DF_CoreViewRuleKind_List, +DF_CoreViewRuleKind_ByteSwap, +DF_CoreViewRuleKind_BaseDec, +DF_CoreViewRuleKind_BaseBin, +DF_CoreViewRuleKind_BaseOct, +DF_CoreViewRuleKind_BaseHex, +DF_CoreViewRuleKind_Only, +DF_CoreViewRuleKind_Omit, +DF_CoreViewRuleKind_NoAddr, +DF_CoreViewRuleKind_RGBA, +DF_CoreViewRuleKind_Text, +DF_CoreViewRuleKind_Disasm, +DF_CoreViewRuleKind_Bitmap, +DF_CoreViewRuleKind_Geo, +DF_CoreViewRuleKind_COUNT +} DF_CoreViewRuleKind; + +typedef enum DF_CmdParamSlot +{ +DF_CmdParamSlot_Null, +DF_CmdParamSlot_Window, +DF_CmdParamSlot_Panel, +DF_CmdParamSlot_DestPanel, +DF_CmdParamSlot_PrevView, +DF_CmdParamSlot_View, +DF_CmdParamSlot_Entity, +DF_CmdParamSlot_EntityList, +DF_CmdParamSlot_String, +DF_CmdParamSlot_FilePath, +DF_CmdParamSlot_TextPoint, +DF_CmdParamSlot_CmdSpec, +DF_CmdParamSlot_VirtualAddr, +DF_CmdParamSlot_VirtualOff, +DF_CmdParamSlot_Index, +DF_CmdParamSlot_ID, +DF_CmdParamSlot_PreferDisassembly, +DF_CmdParamSlot_COUNT +} DF_CmdParamSlot; + +typedef enum DF_CmdQueryRule +{ +DF_CmdQueryRule_Null, +DF_CmdQueryRule_Entity, +DF_CmdQueryRule_String, +DF_CmdQueryRule_SearchString, +DF_CmdQueryRule_FilePath, +DF_CmdQueryRule_TextPoint, +DF_CmdQueryRule_FilePathAndTextPoint, +DF_CmdQueryRule_VirtualAddr, +DF_CmdQueryRule_VirtualOff, +DF_CmdQueryRule_Index, +DF_CmdQueryRule_ID, +DF_CmdQueryRule_COUNT +} DF_CmdQueryRule; + +typedef struct DF_CmdParams DF_CmdParams; +struct DF_CmdParams +{ +U64 slot_props[(DF_CmdParamSlot_COUNT + 63) / 64]; +DF_Handle window; +DF_Handle panel; +DF_Handle dest_panel; +DF_Handle prev_view; +DF_Handle view; +DF_Handle entity; +DF_HandleList entity_list; +String8 string; +String8 file_path; +TxtPt text_point; +struct DF_CmdSpec * cmd_spec; +U64 vaddr; +U64 voff; +U64 index; +U64 id; +B32 prefer_dasm; +}; + +DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array); +DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(bswap); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(list); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(only); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(omit); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(rgba); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(text); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(disasm); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(bitmap); +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(geo); + +struct{String8 mnemonic; String8 summary;} df_g_inst_table_x64[] = +{ +{str8_lit_comp("AAA"), str8_lit_comp("ASCII Adjust After Addition")}, +{str8_lit_comp("AAD"), str8_lit_comp("ASCII Adjust AX Before Division")}, +{str8_lit_comp("AAM"), str8_lit_comp("ASCII Adjust AX After Multiply")}, +{str8_lit_comp("AAS"), str8_lit_comp("ASCII Adjust AL After Subtraction")}, +{str8_lit_comp("ADC"), str8_lit_comp("Add with Carry")}, +{str8_lit_comp("ADCX"), str8_lit_comp("Unsigned Integer Addition of Two Operands with Carry Flag")}, +{str8_lit_comp("ADD"), str8_lit_comp("Add")}, +{str8_lit_comp("ADDPD"), str8_lit_comp("Add Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("ADDPS"), str8_lit_comp("Add Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("ADDSD"), str8_lit_comp("Add Scalar Double-Precision Floating-Point Values")}, +{str8_lit_comp("ADDSS"), str8_lit_comp("Add Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("ADDSUBPD"), str8_lit_comp("Packed Double-FP Add/Subtract")}, +{str8_lit_comp("ADDSUBPS"), str8_lit_comp("Packed Single-FP Add/Subtract")}, +{str8_lit_comp("ADOX"), str8_lit_comp("Unsigned Integer Addition of Two Operands with Overflow Flag")}, +{str8_lit_comp("AESDEC"), str8_lit_comp("Perform One Round of an AES Decryption Flow")}, +{str8_lit_comp("AESDEC128KL"), str8_lit_comp("Perform Ten Rounds of AES Decryption Flow with Key Locker Using 128-Bit Key")}, +{str8_lit_comp("AESDEC256KL"), str8_lit_comp("Perform 14 Rounds of AES Decryption Flow with Key Locker Using 256-Bit Key")}, +{str8_lit_comp("AESDECLAST"), str8_lit_comp("Perform Last Round of an AES Decryption Flow")}, +{str8_lit_comp("AESDECWIDE128KL"), str8_lit_comp("Perform Ten Rounds of AES Decryption Flow with Key Locker on 8 Blocks Using 128-Bit Key")}, +{str8_lit_comp("AESDECWIDE256KL"), str8_lit_comp("Perform 14 Rounds of AES Decryption Flow with Key Locker on 8 Blocks Using 256-Bit Key")}, +{str8_lit_comp("AESENC"), str8_lit_comp("Perform One Round of an AES Encryption Flow")}, +{str8_lit_comp("AESENC128KL"), str8_lit_comp("Perform Ten Rounds of AES Encryption Flow with Key Locker Using 128-Bit Key")}, +{str8_lit_comp("AESENC256KL"), str8_lit_comp("Perform 14 Rounds of AES Encryption Flow with Key Locker Using 256-Bit Key")}, +{str8_lit_comp("AESENCLAST"), str8_lit_comp("Perform Last Round of an AES Encryption Flow")}, +{str8_lit_comp("AESENCWIDE128KL"), str8_lit_comp("Perform Ten Rounds of AES Encryption Flow with Key Locker on 8 Blocks Using 128-Bit Key")}, +{str8_lit_comp("AESENCWIDE256KL"), str8_lit_comp("Perform 14 Rounds of AES Encryption Flow with Key Locker on 8 Blocks Using 256-Bit Key")}, +{str8_lit_comp("AESIMC"), str8_lit_comp("Perform the AES InvMixColumn Transformation")}, +{str8_lit_comp("AESKEYGENASSIST"), str8_lit_comp("AES Round Key Generation Assist")}, +{str8_lit_comp("AND"), str8_lit_comp("Logical AND")}, +{str8_lit_comp("ANDN"), str8_lit_comp("Logical AND NOT")}, +{str8_lit_comp("ANDNPD"), str8_lit_comp("Bitwise Logical AND NOT of Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("ANDNPS"), str8_lit_comp("Bitwise Logical AND NOT of Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("ANDPD"), str8_lit_comp("Bitwise Logical AND of Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("ANDPS"), str8_lit_comp("Bitwise Logical AND of Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("ARPL"), str8_lit_comp("Adjust RPL Field of Segment Selector")}, +{str8_lit_comp("BEXTR"), str8_lit_comp("Bit Field Extract")}, +{str8_lit_comp("BLENDPD"), str8_lit_comp("Blend Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("BLENDPS"), str8_lit_comp("Blend Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("BLENDVPD"), str8_lit_comp("Variable Blend Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("BLENDVPS"), str8_lit_comp("Variable Blend Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("BLSI"), str8_lit_comp("Extract Lowest Set Isolated Bit")}, +{str8_lit_comp("BLSMSK"), str8_lit_comp("Get Mask Up to Lowest Set Bit")}, +{str8_lit_comp("BLSR"), str8_lit_comp("Reset Lowest Set Bit")}, +{str8_lit_comp("BNDCL"), str8_lit_comp("Check Lower Bound")}, +{str8_lit_comp("BNDCN"), str8_lit_comp("Check Upper Bound")}, +{str8_lit_comp("BNDCU"), str8_lit_comp("Check Upper Bound")}, +{str8_lit_comp("BNDLDX"), str8_lit_comp("Load Extended Bounds Using Address Translation")}, +{str8_lit_comp("BNDMK"), str8_lit_comp("Make Bounds")}, +{str8_lit_comp("BNDMOV"), str8_lit_comp("Move Bounds")}, +{str8_lit_comp("BNDSTX"), str8_lit_comp("Store Extended Bounds Using Address Translation")}, +{str8_lit_comp("BOUND"), str8_lit_comp("Check Array Index Against Bounds")}, +{str8_lit_comp("BSF"), str8_lit_comp("Bit Scan Forward")}, +{str8_lit_comp("BSR"), str8_lit_comp("Bit Scan Reverse")}, +{str8_lit_comp("BSWAP"), str8_lit_comp("Byte Swap")}, +{str8_lit_comp("BT"), str8_lit_comp("Bit Test")}, +{str8_lit_comp("BTC"), str8_lit_comp("Bit Test and Complement")}, +{str8_lit_comp("BTR"), str8_lit_comp("Bit Test and Reset")}, +{str8_lit_comp("BTS"), str8_lit_comp("Bit Test and Set")}, +{str8_lit_comp("BZHI"), str8_lit_comp("Zero High Bits Starting with Specified Bit Position")}, +{str8_lit_comp("CALL"), str8_lit_comp("Call Procedure")}, +{str8_lit_comp("CBW"), str8_lit_comp("Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword")}, +{str8_lit_comp("CDQ"), str8_lit_comp("Convert Word to Doubleword/Convert Doubleword to Quadword")}, +{str8_lit_comp("CDQE"), str8_lit_comp("Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword")}, +{str8_lit_comp("CLAC"), str8_lit_comp("Clear AC Flag in EFLAGS Register")}, +{str8_lit_comp("CLC"), str8_lit_comp("Clear Carry Flag")}, +{str8_lit_comp("CLD"), str8_lit_comp("Clear Direction Flag")}, +{str8_lit_comp("CLDEMOTE"), str8_lit_comp("Cache Line Demote")}, +{str8_lit_comp("CLFLUSH"), str8_lit_comp("Flush Cache Line")}, +{str8_lit_comp("CLFLUSHOPT"), str8_lit_comp("Flush Cache Line Optimized")}, +{str8_lit_comp("CLI"), str8_lit_comp("Clear Interrupt Flag")}, +{str8_lit_comp("CLRSSBSY"), str8_lit_comp("Clear Busy Flag in a Supervisor Shadow Stack Token")}, +{str8_lit_comp("CLTS"), str8_lit_comp("Clear Task-Switched Flag in CR0")}, +{str8_lit_comp("CLWB"), str8_lit_comp("Cache Line Write Back")}, +{str8_lit_comp("CMC"), str8_lit_comp("Complement Carry Flag")}, +{str8_lit_comp("CMOVcc"), str8_lit_comp("Conditional Move")}, +{str8_lit_comp("CMP"), str8_lit_comp("Compare Two Operands")}, +{str8_lit_comp("CMPPD"), str8_lit_comp("Compare Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("CMPPS"), str8_lit_comp("Compare Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("CMPS"), str8_lit_comp("Compare String Operands")}, +{str8_lit_comp("CMPSB"), str8_lit_comp("Compare String Operands")}, +{str8_lit_comp("CMPSD"), str8_lit_comp("Compare String Operands")}, +{str8_lit_comp("CMPSQ"), str8_lit_comp("Compare String Operands")}, +{str8_lit_comp("CMPSS"), str8_lit_comp("Compare Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("CMPSW"), str8_lit_comp("Compare String Operands")}, +{str8_lit_comp("CMPXCHG"), str8_lit_comp("Compare and Exchange")}, +{str8_lit_comp("CMPXCHG16B"), str8_lit_comp("Compare and Exchange Bytes")}, +{str8_lit_comp("CMPXCHG8B"), str8_lit_comp("Compare and Exchange Bytes")}, +{str8_lit_comp("COMISD"), str8_lit_comp("Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS")}, +{str8_lit_comp("COMISS"), str8_lit_comp("Compare Scalar Ordered Single-Precision Floating-Point Values and Set EFLAGS")}, +{str8_lit_comp("CPUID"), str8_lit_comp("CPU Identification")}, +{str8_lit_comp("CQO"), str8_lit_comp("Convert Word to Doubleword/Convert Doubleword to Quadword")}, +{str8_lit_comp("CRC32"), str8_lit_comp("Accumulate CRC32 Value")}, +{str8_lit_comp("CVTDQ2PD"), str8_lit_comp("Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("CVTDQ2PS"), str8_lit_comp("Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("CVTPD2DQ"), str8_lit_comp("Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers")}, +{str8_lit_comp("CVTPD2PI"), str8_lit_comp("Convert Packed Double-Precision FP Values to Packed Dword Integers")}, +{str8_lit_comp("CVTPD2PS"), str8_lit_comp("Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("CVTPI2PD"), str8_lit_comp("Convert Packed Dword Integers to Packed Double-Precision FP Values")}, +{str8_lit_comp("CVTPI2PS"), str8_lit_comp("Convert Packed Dword Integers to Packed Single-Precision FP Values")}, +{str8_lit_comp("CVTPS2DQ"), str8_lit_comp("Convert Packed Single-Precision Floating-Point Values to Packed Signed Doubleword Integer Values")}, +{str8_lit_comp("CVTPS2PD"), str8_lit_comp("Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("CVTPS2PI"), str8_lit_comp("Convert Packed Single-Precision FP Values to Packed Dword Integers")}, +{str8_lit_comp("CVTSD2SI"), str8_lit_comp("Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer")}, +{str8_lit_comp("CVTSD2SS"), str8_lit_comp("Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("CVTSI2SD"), str8_lit_comp("Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("CVTSI2SS"), str8_lit_comp("Convert Doubleword Integer to Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("CVTSS2SD"), str8_lit_comp("Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("CVTSS2SI"), str8_lit_comp("Convert Scalar Single-Precision Floating-Point Value to Doubleword Integer")}, +{str8_lit_comp("CVTTPD2DQ"), str8_lit_comp("Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers")}, +{str8_lit_comp("CVTTPD2PI"), str8_lit_comp("Convert with Truncation Packed Double-Precision FP Values to Packed Dword Integers")}, +{str8_lit_comp("CVTTPS2DQ"), str8_lit_comp("Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Signed Doubleword Integer Values")}, +{str8_lit_comp("CVTTPS2PI"), str8_lit_comp("Convert with Truncation Packed Single-Precision FP Values to Packed Dword Integers")}, +{str8_lit_comp("CVTTSD2SI"), str8_lit_comp("Convert with Truncation Scalar Double-Precision Floating-Point Value to Signed Integer")}, +{str8_lit_comp("CVTTSS2SI"), str8_lit_comp("Convert with Truncation Scalar Single-Precision Floating-Point Value to Integer")}, +{str8_lit_comp("CWD"), str8_lit_comp("Convert Word to Doubleword/Convert Doubleword to Quadword")}, +{str8_lit_comp("CWDE"), str8_lit_comp("Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword")}, +{str8_lit_comp("DAA"), str8_lit_comp("Decimal Adjust AL after Addition")}, +{str8_lit_comp("DAS"), str8_lit_comp("Decimal Adjust AL after Subtraction")}, +{str8_lit_comp("DEC"), str8_lit_comp("Decrement by 1")}, +{str8_lit_comp("DIV"), str8_lit_comp("Unsigned Divide")}, +{str8_lit_comp("DIVPD"), str8_lit_comp("Divide Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("DIVPS"), str8_lit_comp("Divide Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("DIVSD"), str8_lit_comp("Divide Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("DIVSS"), str8_lit_comp("Divide Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("DPPD"), str8_lit_comp("Dot Product of Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("DPPS"), str8_lit_comp("Dot Product of Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("EMMS"), str8_lit_comp("Empty MMX Technology State")}, +{str8_lit_comp("ENCODEKEY128"), str8_lit_comp("Encode 128-Bit Key with Key Locker")}, +{str8_lit_comp("ENCODEKEY256"), str8_lit_comp("Encode 256-Bit Key with Key Locker")}, +{str8_lit_comp("ENDBR32"), str8_lit_comp("Terminate an Indirect Branch in 32-bit and Compatibility Mode")}, +{str8_lit_comp("ENDBR64"), str8_lit_comp("Terminate an Indirect Branch in 64-bit Mode")}, +{str8_lit_comp("ENTER"), str8_lit_comp("Make Stack Frame for Procedure Parameters")}, +{str8_lit_comp("EXTRACTPS"), str8_lit_comp("Extract Packed Floating-Point Values")}, +{str8_lit_comp("F2XM1"), str8_lit_comp("Compute 2x–1")}, +{str8_lit_comp("FABS"), str8_lit_comp("Absolute Value")}, +{str8_lit_comp("FADD"), str8_lit_comp("Add")}, +{str8_lit_comp("FADDP"), str8_lit_comp("Add")}, +{str8_lit_comp("FBLD"), str8_lit_comp("Load Binary Coded Decimal")}, +{str8_lit_comp("FBSTP"), str8_lit_comp("Store BCD Integer and Pop")}, +{str8_lit_comp("FCHS"), str8_lit_comp("Change Sign")}, +{str8_lit_comp("FCLEX"), str8_lit_comp("Clear Exceptions")}, +{str8_lit_comp("FCMOVcc"), str8_lit_comp("Floating-Point Conditional Move")}, +{str8_lit_comp("FCOM"), str8_lit_comp("Compare Floating Point Values")}, +{str8_lit_comp("FCOMI"), str8_lit_comp("Compare Floating Point Values and Set EFLAGS")}, +{str8_lit_comp("FCOMIP"), str8_lit_comp("Compare Floating Point Values and Set EFLAGS")}, +{str8_lit_comp("FCOMP"), str8_lit_comp("Compare Floating Point Values")}, +{str8_lit_comp("FCOMPP"), str8_lit_comp("Compare Floating Point Values")}, +{str8_lit_comp("FCOS"), str8_lit_comp("Cosine")}, +{str8_lit_comp("FDECSTP"), str8_lit_comp("Decrement Stack-Top Pointer")}, +{str8_lit_comp("FDIV"), str8_lit_comp("Divide")}, +{str8_lit_comp("FDIVP"), str8_lit_comp("Divide")}, +{str8_lit_comp("FDIVR"), str8_lit_comp("Reverse Divide")}, +{str8_lit_comp("FDIVRP"), str8_lit_comp("Reverse Divide")}, +{str8_lit_comp("FFREE"), str8_lit_comp("Free Floating-Point Register")}, +{str8_lit_comp("FIADD"), str8_lit_comp("Add")}, +{str8_lit_comp("FICOM"), str8_lit_comp("Compare Integer")}, +{str8_lit_comp("FICOMP"), str8_lit_comp("Compare Integer")}, +{str8_lit_comp("FIDIV"), str8_lit_comp("Divide")}, +{str8_lit_comp("FIDIVR"), str8_lit_comp("Reverse Divide")}, +{str8_lit_comp("FILD"), str8_lit_comp("Load Integer")}, +{str8_lit_comp("FIMUL"), str8_lit_comp("Multiply")}, +{str8_lit_comp("FINCSTP"), str8_lit_comp("Increment Stack-Top Pointer")}, +{str8_lit_comp("FINIT"), str8_lit_comp("Initialize Floating-Point Unit")}, +{str8_lit_comp("FIST"), str8_lit_comp("Store Integer")}, +{str8_lit_comp("FISTP"), str8_lit_comp("Store Integer")}, +{str8_lit_comp("FISTTP"), str8_lit_comp("Store Integer with Truncation")}, +{str8_lit_comp("FISUB"), str8_lit_comp("Subtract")}, +{str8_lit_comp("FISUBR"), str8_lit_comp("Reverse Subtract")}, +{str8_lit_comp("FLD"), str8_lit_comp("Load Floating Point Value")}, +{str8_lit_comp("FLD1"), str8_lit_comp("Load Constant")}, +{str8_lit_comp("FLDCW"), str8_lit_comp("Load x87 FPU Control Word")}, +{str8_lit_comp("FLDENV"), str8_lit_comp("Load x87 FPU Environment")}, +{str8_lit_comp("FLDL2E"), str8_lit_comp("Load Constant")}, +{str8_lit_comp("FLDL2T"), str8_lit_comp("Load Constant")}, +{str8_lit_comp("FLDLG2"), str8_lit_comp("Load Constant")}, +{str8_lit_comp("FLDLN2"), str8_lit_comp("Load Constant")}, +{str8_lit_comp("FLDPI"), str8_lit_comp("Load Constant")}, +{str8_lit_comp("FLDZ"), str8_lit_comp("Load Constant")}, +{str8_lit_comp("FMUL"), str8_lit_comp("Multiply")}, +{str8_lit_comp("FMULP"), str8_lit_comp("Multiply")}, +{str8_lit_comp("FNCLEX"), str8_lit_comp("Clear Exceptions")}, +{str8_lit_comp("FNINIT"), str8_lit_comp("Initialize Floating-Point Unit")}, +{str8_lit_comp("FNOP"), str8_lit_comp("No Operation")}, +{str8_lit_comp("FNSAVE"), str8_lit_comp("Store x87 FPU State")}, +{str8_lit_comp("FNSTCW"), str8_lit_comp("Store x87 FPU Control Word")}, +{str8_lit_comp("FNSTENV"), str8_lit_comp("Store x87 FPU Environment")}, +{str8_lit_comp("FNSTSW"), str8_lit_comp("Store x87 FPU Status Word")}, +{str8_lit_comp("FPATAN"), str8_lit_comp("Partial Arctangent")}, +{str8_lit_comp("FPREM"), str8_lit_comp("Partial Remainder")}, +{str8_lit_comp("FPREM1"), str8_lit_comp("Partial Remainder")}, +{str8_lit_comp("FPTAN"), str8_lit_comp("Partial Tangent")}, +{str8_lit_comp("FRNDINT"), str8_lit_comp("Round to Integer")}, +{str8_lit_comp("FRSTOR"), str8_lit_comp("Restore x87 FPU State")}, +{str8_lit_comp("FSAVE"), str8_lit_comp("Store x87 FPU State")}, +{str8_lit_comp("FSCALE"), str8_lit_comp("Scale")}, +{str8_lit_comp("FSIN"), str8_lit_comp("Sine")}, +{str8_lit_comp("FSINCOS"), str8_lit_comp("Sine and Cosine")}, +{str8_lit_comp("FSQRT"), str8_lit_comp("Square Root")}, +{str8_lit_comp("FST"), str8_lit_comp("Store Floating Point Value")}, +{str8_lit_comp("FSTCW"), str8_lit_comp("Store x87 FPU Control Word")}, +{str8_lit_comp("FSTENV"), str8_lit_comp("Store x87 FPU Environment")}, +{str8_lit_comp("FSTP"), str8_lit_comp("Store Floating Point Value")}, +{str8_lit_comp("FSTSW"), str8_lit_comp("Store x87 FPU Status Word")}, +{str8_lit_comp("FSUB"), str8_lit_comp("Subtract")}, +{str8_lit_comp("FSUBP"), str8_lit_comp("Subtract")}, +{str8_lit_comp("FSUBR"), str8_lit_comp("Reverse Subtract")}, +{str8_lit_comp("FSUBRP"), str8_lit_comp("Reverse Subtract")}, +{str8_lit_comp("FTST"), str8_lit_comp("TEST")}, +{str8_lit_comp("FUCOM"), str8_lit_comp("Unordered Compare Floating Point Values")}, +{str8_lit_comp("FUCOMI"), str8_lit_comp("Compare Floating Point Values and Set EFLAGS")}, +{str8_lit_comp("FUCOMIP"), str8_lit_comp("Compare Floating Point Values and Set EFLAGS")}, +{str8_lit_comp("FUCOMP"), str8_lit_comp("Unordered Compare Floating Point Values")}, +{str8_lit_comp("FUCOMPP"), str8_lit_comp("Unordered Compare Floating Point Values")}, +{str8_lit_comp("FWAIT"), str8_lit_comp("Wait")}, +{str8_lit_comp("FXAM"), str8_lit_comp("Examine Floating-Point")}, +{str8_lit_comp("FXCH"), str8_lit_comp("Exchange Register Contents")}, +{str8_lit_comp("FXRSTOR"), str8_lit_comp("Restore x87 FPU, MMX, XMM, and MXCSR State")}, +{str8_lit_comp("FXSAVE"), str8_lit_comp("Save x87 FPU, MMX Technology, and SSE State")}, +{str8_lit_comp("FXTRACT"), str8_lit_comp("Extract Exponent and Significand")}, +{str8_lit_comp("FYL2X"), str8_lit_comp("Compute y * log2x")}, +{str8_lit_comp("FYL2XP1"), str8_lit_comp("Compute y * log2(x +1)")}, +{str8_lit_comp("GF2P8AFFINEINVQB"), str8_lit_comp("Galois Field Affine Transformation Inverse")}, +{str8_lit_comp("GF2P8AFFINEQB"), str8_lit_comp("Galois Field Affine Transformation")}, +{str8_lit_comp("GF2P8MULB"), str8_lit_comp("Galois Field Multiply Bytes")}, +{str8_lit_comp("HADDPD"), str8_lit_comp("Packed Double-FP Horizontal Add")}, +{str8_lit_comp("HADDPS"), str8_lit_comp("Packed Single-FP Horizontal Add")}, +{str8_lit_comp("HLT"), str8_lit_comp("Halt")}, +{str8_lit_comp("HRESET"), str8_lit_comp("History Reset")}, +{str8_lit_comp("HSUBPD"), str8_lit_comp("Packed Double-FP Horizontal Subtract")}, +{str8_lit_comp("HSUBPS"), str8_lit_comp("Packed Single-FP Horizontal Subtract")}, +{str8_lit_comp("IDIV"), str8_lit_comp("Signed Divide")}, +{str8_lit_comp("IMUL"), str8_lit_comp("Signed Multiply")}, +{str8_lit_comp("IN"), str8_lit_comp("Input from Port")}, +{str8_lit_comp("INC"), str8_lit_comp("Increment by 1")}, +{str8_lit_comp("INCSSPD"), str8_lit_comp("Increment Shadow Stack Pointer")}, +{str8_lit_comp("INCSSPQ"), str8_lit_comp("Increment Shadow Stack Pointer")}, +{str8_lit_comp("INS"), str8_lit_comp("Input from Port to String")}, +{str8_lit_comp("INSB"), str8_lit_comp("Input from Port to String")}, +{str8_lit_comp("INSD"), str8_lit_comp("Input from Port to String")}, +{str8_lit_comp("INSERTPS"), str8_lit_comp("Insert Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("INSW"), str8_lit_comp("Input from Port to String")}, +{str8_lit_comp("INT"), str8_lit_comp("Call to Interrupt Procedure")}, +{str8_lit_comp("INT1"), str8_lit_comp("Call to Interrupt Procedure")}, +{str8_lit_comp("INT3"), str8_lit_comp("Call to Interrupt Procedure")}, +{str8_lit_comp("INTO"), str8_lit_comp("Call to Interrupt Procedure")}, +{str8_lit_comp("INVD"), str8_lit_comp("Invalidate Internal Caches")}, +{str8_lit_comp("INVLPG"), str8_lit_comp("Invalidate TLB Entries")}, +{str8_lit_comp("INVPCID"), str8_lit_comp("Invalidate Process-Context Identifier")}, +{str8_lit_comp("IRET"), str8_lit_comp("Interrupt Return")}, +{str8_lit_comp("IRETD"), str8_lit_comp("Interrupt Return")}, +{str8_lit_comp("IRETQ"), str8_lit_comp("Interrupt Return")}, +{str8_lit_comp("JMP"), str8_lit_comp("Jump")}, +{str8_lit_comp("Jcc"), str8_lit_comp("Jump if Condition Is Met")}, +{str8_lit_comp("KADDB"), str8_lit_comp("ADD Two Masks")}, +{str8_lit_comp("KADDD"), str8_lit_comp("ADD Two Masks")}, +{str8_lit_comp("KADDQ"), str8_lit_comp("ADD Two Masks")}, +{str8_lit_comp("KADDW"), str8_lit_comp("ADD Two Masks")}, +{str8_lit_comp("KANDB"), str8_lit_comp("Bitwise Logical AND Masks")}, +{str8_lit_comp("KANDD"), str8_lit_comp("Bitwise Logical AND Masks")}, +{str8_lit_comp("KANDNB"), str8_lit_comp("Bitwise Logical AND NOT Masks")}, +{str8_lit_comp("KANDND"), str8_lit_comp("Bitwise Logical AND NOT Masks")}, +{str8_lit_comp("KANDNQ"), str8_lit_comp("Bitwise Logical AND NOT Masks")}, +{str8_lit_comp("KANDNW"), str8_lit_comp("Bitwise Logical AND NOT Masks")}, +{str8_lit_comp("KANDQ"), str8_lit_comp("Bitwise Logical AND Masks")}, +{str8_lit_comp("KANDW"), str8_lit_comp("Bitwise Logical AND Masks")}, +{str8_lit_comp("KMOVB"), str8_lit_comp("Move from and to Mask Registers")}, +{str8_lit_comp("KMOVD"), str8_lit_comp("Move from and to Mask Registers")}, +{str8_lit_comp("KMOVQ"), str8_lit_comp("Move from and to Mask Registers")}, +{str8_lit_comp("KMOVW"), str8_lit_comp("Move from and to Mask Registers")}, +{str8_lit_comp("KNOTB"), str8_lit_comp("NOT Mask Register")}, +{str8_lit_comp("KNOTD"), str8_lit_comp("NOT Mask Register")}, +{str8_lit_comp("KNOTQ"), str8_lit_comp("NOT Mask Register")}, +{str8_lit_comp("KNOTW"), str8_lit_comp("NOT Mask Register")}, +{str8_lit_comp("KORB"), str8_lit_comp("Bitwise Logical OR Masks")}, +{str8_lit_comp("KORD"), str8_lit_comp("Bitwise Logical OR Masks")}, +{str8_lit_comp("KORQ"), str8_lit_comp("Bitwise Logical OR Masks")}, +{str8_lit_comp("KORTESTB"), str8_lit_comp("OR Masks And Set Flags")}, +{str8_lit_comp("KORTESTD"), str8_lit_comp("OR Masks And Set Flags")}, +{str8_lit_comp("KORTESTQ"), str8_lit_comp("OR Masks And Set Flags")}, +{str8_lit_comp("KORTESTW"), str8_lit_comp("OR Masks And Set Flags")}, +{str8_lit_comp("KORW"), str8_lit_comp("Bitwise Logical OR Masks")}, +{str8_lit_comp("KSHIFTLB"), str8_lit_comp("Shift Left Mask Registers")}, +{str8_lit_comp("KSHIFTLD"), str8_lit_comp("Shift Left Mask Registers")}, +{str8_lit_comp("KSHIFTLQ"), str8_lit_comp("Shift Left Mask Registers")}, +{str8_lit_comp("KSHIFTLW"), str8_lit_comp("Shift Left Mask Registers")}, +{str8_lit_comp("KSHIFTRB"), str8_lit_comp("Shift Right Mask Registers")}, +{str8_lit_comp("KSHIFTRD"), str8_lit_comp("Shift Right Mask Registers")}, +{str8_lit_comp("KSHIFTRQ"), str8_lit_comp("Shift Right Mask Registers")}, +{str8_lit_comp("KSHIFTRW"), str8_lit_comp("Shift Right Mask Registers")}, +{str8_lit_comp("KTESTB"), str8_lit_comp("Packed Bit Test Masks and Set Flags")}, +{str8_lit_comp("KTESTD"), str8_lit_comp("Packed Bit Test Masks and Set Flags")}, +{str8_lit_comp("KTESTQ"), str8_lit_comp("Packed Bit Test Masks and Set Flags")}, +{str8_lit_comp("KTESTW"), str8_lit_comp("Packed Bit Test Masks and Set Flags")}, +{str8_lit_comp("KUNPCKBW"), str8_lit_comp("Unpack for Mask Registers")}, +{str8_lit_comp("KUNPCKDQ"), str8_lit_comp("Unpack for Mask Registers")}, +{str8_lit_comp("KUNPCKWD"), str8_lit_comp("Unpack for Mask Registers")}, +{str8_lit_comp("KXNORB"), str8_lit_comp("Bitwise Logical XNOR Masks")}, +{str8_lit_comp("KXNORD"), str8_lit_comp("Bitwise Logical XNOR Masks")}, +{str8_lit_comp("KXNORQ"), str8_lit_comp("Bitwise Logical XNOR Masks")}, +{str8_lit_comp("KXNORW"), str8_lit_comp("Bitwise Logical XNOR Masks")}, +{str8_lit_comp("KXORB"), str8_lit_comp("Bitwise Logical XOR Masks")}, +{str8_lit_comp("KXORD"), str8_lit_comp("Bitwise Logical XOR Masks")}, +{str8_lit_comp("KXORQ"), str8_lit_comp("Bitwise Logical XOR Masks")}, +{str8_lit_comp("KXORW"), str8_lit_comp("Bitwise Logical XOR Masks")}, +{str8_lit_comp("LAHF"), str8_lit_comp("Load Status Flags into AH Register")}, +{str8_lit_comp("LAR"), str8_lit_comp("Load Access Rights Byte")}, +{str8_lit_comp("LDDQU"), str8_lit_comp("Load Unaligned Integer 128 Bits")}, +{str8_lit_comp("LDMXCSR"), str8_lit_comp("Load MXCSR Register")}, +{str8_lit_comp("LDS"), str8_lit_comp("Load Far Pointer")}, +{str8_lit_comp("LEA"), str8_lit_comp("Load Effective Address")}, +{str8_lit_comp("LEAVE"), str8_lit_comp("High Level Procedure Exit")}, +{str8_lit_comp("LES"), str8_lit_comp("Load Far Pointer")}, +{str8_lit_comp("LFENCE"), str8_lit_comp("Load Fence")}, +{str8_lit_comp("LFS"), str8_lit_comp("Load Far Pointer")}, +{str8_lit_comp("LGDT"), str8_lit_comp("Load Global/Interrupt Descriptor Table Register")}, +{str8_lit_comp("LGS"), str8_lit_comp("Load Far Pointer")}, +{str8_lit_comp("LIDT"), str8_lit_comp("Load Global/Interrupt Descriptor Table Register")}, +{str8_lit_comp("LLDT"), str8_lit_comp("Load Local Descriptor Table Register")}, +{str8_lit_comp("LMSW"), str8_lit_comp("Load Machine Status Word")}, +{str8_lit_comp("LOADIWKEY"), str8_lit_comp("Load Internal Wrapping Key with Key Locker")}, +{str8_lit_comp("LOCK"), str8_lit_comp("Assert LOCK# Signal Prefix")}, +{str8_lit_comp("LODS"), str8_lit_comp("Load String")}, +{str8_lit_comp("LODSB"), str8_lit_comp("Load String")}, +{str8_lit_comp("LODSD"), str8_lit_comp("Load String")}, +{str8_lit_comp("LODSQ"), str8_lit_comp("Load String")}, +{str8_lit_comp("LODSW"), str8_lit_comp("Load String")}, +{str8_lit_comp("LOOP"), str8_lit_comp("Loop According to ECX Counter")}, +{str8_lit_comp("LOOPcc"), str8_lit_comp("Loop According to ECX Counter")}, +{str8_lit_comp("LSL"), str8_lit_comp("Load Segment Limit")}, +{str8_lit_comp("LSS"), str8_lit_comp("Load Far Pointer")}, +{str8_lit_comp("LTR"), str8_lit_comp("Load Task Register")}, +{str8_lit_comp("LZCNT"), str8_lit_comp("Count the Number of Leading Zero Bits")}, +{str8_lit_comp("MASKMOVDQU"), str8_lit_comp("Store Selected Bytes of Double Quadword")}, +{str8_lit_comp("MASKMOVQ"), str8_lit_comp("Store Selected Bytes of Quadword")}, +{str8_lit_comp("MAXPD"), str8_lit_comp("Maximum of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("MAXPS"), str8_lit_comp("Maximum of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("MAXSD"), str8_lit_comp("Return Maximum Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("MAXSS"), str8_lit_comp("Return Maximum Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("MFENCE"), str8_lit_comp("Memory Fence")}, +{str8_lit_comp("MINPD"), str8_lit_comp("Minimum of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("MINPS"), str8_lit_comp("Minimum of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("MINSD"), str8_lit_comp("Return Minimum Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("MINSS"), str8_lit_comp("Return Minimum Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("MONITOR"), str8_lit_comp("Set Up Monitor Address")}, +{str8_lit_comp("MOV"), str8_lit_comp("Move")}, +{str8_lit_comp("MOVAPD"), str8_lit_comp("Move Aligned Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("MOVAPS"), str8_lit_comp("Move Aligned Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("MOVBE"), str8_lit_comp("Move Data After Swapping Bytes")}, +{str8_lit_comp("MOVD"), str8_lit_comp("Move Doubleword/Move Quadword")}, +{str8_lit_comp("MOVDDUP"), str8_lit_comp("Replicate Double FP Values")}, +{str8_lit_comp("MOVDIR64B"), str8_lit_comp("Move 64 Bytes as Direct Store")}, +{str8_lit_comp("MOVDIRI"), str8_lit_comp("Move Doubleword as Direct Store")}, +{str8_lit_comp("MOVDQ2Q"), str8_lit_comp("Move Quadword from XMM to MMX Technology Register")}, +{str8_lit_comp("MOVDQA"), str8_lit_comp("Move Aligned Packed Integer Values")}, +{str8_lit_comp("MOVDQU"), str8_lit_comp("Move Unaligned Packed Integer Values")}, +{str8_lit_comp("MOVHLPS"), str8_lit_comp("Move Packed Single-Precision Floating-Point Values High to Low")}, +{str8_lit_comp("MOVHPD"), str8_lit_comp("Move High Packed Double-Precision Floating-Point Value")}, +{str8_lit_comp("MOVHPS"), str8_lit_comp("Move High Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("MOVLHPS"), str8_lit_comp("Move Packed Single-Precision Floating-Point Values Low to High")}, +{str8_lit_comp("MOVLPD"), str8_lit_comp("Move Low Packed Double-Precision Floating-Point Value")}, +{str8_lit_comp("MOVLPS"), str8_lit_comp("Move Low Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("MOVMSKPD"), str8_lit_comp("Extract Packed Double-Precision Floating-Point Sign Mask")}, +{str8_lit_comp("MOVMSKPS"), str8_lit_comp("Extract Packed Single-Precision Floating-Point Sign Mask")}, +{str8_lit_comp("MOVNTDQ"), str8_lit_comp("Store Packed Integers Using Non-Temporal Hint")}, +{str8_lit_comp("MOVNTDQA"), str8_lit_comp("Load Double Quadword Non-Temporal Aligned Hint")}, +{str8_lit_comp("MOVNTI"), str8_lit_comp("Store Doubleword Using Non-Temporal Hint")}, +{str8_lit_comp("MOVNTPD"), str8_lit_comp("Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint")}, +{str8_lit_comp("MOVNTPS"), str8_lit_comp("Store Packed Single-Precision Floating-Point Values Using Non-Temporal Hint")}, +{str8_lit_comp("MOVNTQ"), str8_lit_comp("Store of Quadword Using Non-Temporal Hint")}, +{str8_lit_comp("MOVQ"), str8_lit_comp("Move Doubleword/Move Quadword")}, +{str8_lit_comp("MOVQ2DQ"), str8_lit_comp("Move Quadword from MMX Technology to XMM Register")}, +{str8_lit_comp("MOVS"), str8_lit_comp("Move Data from String to String")}, +{str8_lit_comp("MOVSB"), str8_lit_comp("Move Data from String to String")}, +{str8_lit_comp("MOVSD"), str8_lit_comp("Move Data from String to String")}, +{str8_lit_comp("MOVSHDUP"), str8_lit_comp("Replicate Single FP Values")}, +{str8_lit_comp("MOVSLDUP"), str8_lit_comp("Replicate Single FP Values")}, +{str8_lit_comp("MOVSQ"), str8_lit_comp("Move Data from String to String")}, +{str8_lit_comp("MOVSS"), str8_lit_comp("Move or Merge Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("MOVSW"), str8_lit_comp("Move Data from String to String")}, +{str8_lit_comp("MOVSX"), str8_lit_comp("Move with Sign-Extension")}, +{str8_lit_comp("MOVSXD"), str8_lit_comp("Move with Sign-Extension")}, +{str8_lit_comp("MOVUPD"), str8_lit_comp("Move Unaligned Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("MOVUPS"), str8_lit_comp("Move Unaligned Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("MOVZX"), str8_lit_comp("Move with Zero-Extend")}, +{str8_lit_comp("MPSADBW"), str8_lit_comp("Compute Multiple Packed Sums of Absolute Difference")}, +{str8_lit_comp("MUL"), str8_lit_comp("Unsigned Multiply")}, +{str8_lit_comp("MULPD"), str8_lit_comp("Multiply Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("MULPS"), str8_lit_comp("Multiply Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("MULSD"), str8_lit_comp("Multiply Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("MULSS"), str8_lit_comp("Multiply Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("MULX"), str8_lit_comp("Unsigned Multiply Without Affecting Flags")}, +{str8_lit_comp("MWAIT"), str8_lit_comp("Monitor Wait")}, +{str8_lit_comp("NEG"), str8_lit_comp("Two's Complement Negation")}, +{str8_lit_comp("NOP"), str8_lit_comp("No Operation")}, +{str8_lit_comp("NOT"), str8_lit_comp("One's Complement Negation")}, +{str8_lit_comp("OR"), str8_lit_comp("Logical Inclusive OR")}, +{str8_lit_comp("ORPD"), str8_lit_comp("Bitwise Logical OR of Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("ORPS"), str8_lit_comp("Bitwise Logical OR of Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("OUT"), str8_lit_comp("Output to Port")}, +{str8_lit_comp("OUTS"), str8_lit_comp("Output String to Port")}, +{str8_lit_comp("OUTSB"), str8_lit_comp("Output String to Port")}, +{str8_lit_comp("OUTSD"), str8_lit_comp("Output String to Port")}, +{str8_lit_comp("OUTSW"), str8_lit_comp("Output String to Port")}, +{str8_lit_comp("PABSB"), str8_lit_comp("Packed Absolute Value")}, +{str8_lit_comp("PABSD"), str8_lit_comp("Packed Absolute Value")}, +{str8_lit_comp("PABSQ"), str8_lit_comp("Packed Absolute Value")}, +{str8_lit_comp("PABSW"), str8_lit_comp("Packed Absolute Value")}, +{str8_lit_comp("PACKSSDW"), str8_lit_comp("Pack with Signed Saturation")}, +{str8_lit_comp("PACKSSWB"), str8_lit_comp("Pack with Signed Saturation")}, +{str8_lit_comp("PACKUSDW"), str8_lit_comp("Pack with Unsigned Saturation")}, +{str8_lit_comp("PACKUSWB"), str8_lit_comp("Pack with Unsigned Saturation")}, +{str8_lit_comp("PADDB"), str8_lit_comp("Add Packed Integers")}, +{str8_lit_comp("PADDD"), str8_lit_comp("Add Packed Integers")}, +{str8_lit_comp("PADDQ"), str8_lit_comp("Add Packed Integers")}, +{str8_lit_comp("PADDSB"), str8_lit_comp("Add Packed Signed Integers with Signed Saturation")}, +{str8_lit_comp("PADDSW"), str8_lit_comp("Add Packed Signed Integers with Signed Saturation")}, +{str8_lit_comp("PADDUSB"), str8_lit_comp("Add Packed Unsigned Integers with Unsigned Saturation")}, +{str8_lit_comp("PADDUSW"), str8_lit_comp("Add Packed Unsigned Integers with Unsigned Saturation")}, +{str8_lit_comp("PADDW"), str8_lit_comp("Add Packed Integers")}, +{str8_lit_comp("PALIGNR"), str8_lit_comp("Packed Align Right")}, +{str8_lit_comp("PAND"), str8_lit_comp("Logical AND")}, +{str8_lit_comp("PANDN"), str8_lit_comp("Logical AND NOT")}, +{str8_lit_comp("PAUSE"), str8_lit_comp("Spin Loop Hint")}, +{str8_lit_comp("PAVGB"), str8_lit_comp("Average Packed Integers")}, +{str8_lit_comp("PAVGW"), str8_lit_comp("Average Packed Integers")}, +{str8_lit_comp("PBLENDVB"), str8_lit_comp("Variable Blend Packed Bytes")}, +{str8_lit_comp("PBLENDW"), str8_lit_comp("Blend Packed Words")}, +{str8_lit_comp("PCLMULQDQ"), str8_lit_comp("Carry-Less Multiplication Quadword")}, +{str8_lit_comp("PCMPEQB"), str8_lit_comp("Compare Packed Data for Equal")}, +{str8_lit_comp("PCMPEQD"), str8_lit_comp("Compare Packed Data for Equal")}, +{str8_lit_comp("PCMPEQQ"), str8_lit_comp("Compare Packed Qword Data for Equal")}, +{str8_lit_comp("PCMPEQW"), str8_lit_comp("Compare Packed Data for Equal")}, +{str8_lit_comp("PCMPESTRI"), str8_lit_comp("Packed Compare Explicit Length Strings, Return Index")}, +{str8_lit_comp("PCMPESTRM"), str8_lit_comp("Packed Compare Explicit Length Strings, Return Mask")}, +{str8_lit_comp("PCMPGTB"), str8_lit_comp("Compare Packed Signed Integers for Greater Than")}, +{str8_lit_comp("PCMPGTD"), str8_lit_comp("Compare Packed Signed Integers for Greater Than")}, +{str8_lit_comp("PCMPGTQ"), str8_lit_comp("Compare Packed Data for Greater Than")}, +{str8_lit_comp("PCMPGTW"), str8_lit_comp("Compare Packed Signed Integers for Greater Than")}, +{str8_lit_comp("PCMPISTRI"), str8_lit_comp("Packed Compare Implicit Length Strings, Return Index")}, +{str8_lit_comp("PCMPISTRM"), str8_lit_comp("Packed Compare Implicit Length Strings, Return Mask")}, +{str8_lit_comp("PCONFIG"), str8_lit_comp("Platform Configuration")}, +{str8_lit_comp("PDEP"), str8_lit_comp("Parallel Bits Deposit")}, +{str8_lit_comp("PEXT"), str8_lit_comp("Parallel Bits Extract")}, +{str8_lit_comp("PEXTRB"), str8_lit_comp("Extract Byte/Dword/Qword")}, +{str8_lit_comp("PEXTRD"), str8_lit_comp("Extract Byte/Dword/Qword")}, +{str8_lit_comp("PEXTRQ"), str8_lit_comp("Extract Byte/Dword/Qword")}, +{str8_lit_comp("PEXTRW"), str8_lit_comp("Extract Word")}, +{str8_lit_comp("PHADDD"), str8_lit_comp("Packed Horizontal Add")}, +{str8_lit_comp("PHADDSW"), str8_lit_comp("Packed Horizontal Add and Saturate")}, +{str8_lit_comp("PHADDW"), str8_lit_comp("Packed Horizontal Add")}, +{str8_lit_comp("PHMINPOSUW"), str8_lit_comp("Packed Horizontal Word Minimum")}, +{str8_lit_comp("PHSUBD"), str8_lit_comp("Packed Horizontal Subtract")}, +{str8_lit_comp("PHSUBSW"), str8_lit_comp("Packed Horizontal Subtract and Saturate")}, +{str8_lit_comp("PHSUBW"), str8_lit_comp("Packed Horizontal Subtract")}, +{str8_lit_comp("PINSRB"), str8_lit_comp("Insert Byte/Dword/Qword")}, +{str8_lit_comp("PINSRD"), str8_lit_comp("Insert Byte/Dword/Qword")}, +{str8_lit_comp("PINSRQ"), str8_lit_comp("Insert Byte/Dword/Qword")}, +{str8_lit_comp("PINSRW"), str8_lit_comp("Insert Word")}, +{str8_lit_comp("PMADDUBSW"), str8_lit_comp("Multiply and Add Packed Signed and Unsigned Bytes")}, +{str8_lit_comp("PMADDWD"), str8_lit_comp("Multiply and Add Packed Integers")}, +{str8_lit_comp("PMAXSB"), str8_lit_comp("Maximum of Packed Signed Integers")}, +{str8_lit_comp("PMAXSD"), str8_lit_comp("Maximum of Packed Signed Integers")}, +{str8_lit_comp("PMAXSQ"), str8_lit_comp("Maximum of Packed Signed Integers")}, +{str8_lit_comp("PMAXSW"), str8_lit_comp("Maximum of Packed Signed Integers")}, +{str8_lit_comp("PMAXUB"), str8_lit_comp("Maximum of Packed Unsigned Integers")}, +{str8_lit_comp("PMAXUD"), str8_lit_comp("Maximum of Packed Unsigned Integers")}, +{str8_lit_comp("PMAXUQ"), str8_lit_comp("Maximum of Packed Unsigned Integers")}, +{str8_lit_comp("PMAXUW"), str8_lit_comp("Maximum of Packed Unsigned Integers")}, +{str8_lit_comp("PMINSB"), str8_lit_comp("Minimum of Packed Signed Integers")}, +{str8_lit_comp("PMINSD"), str8_lit_comp("Minimum of Packed Signed Integers")}, +{str8_lit_comp("PMINSQ"), str8_lit_comp("Minimum of Packed Signed Integers")}, +{str8_lit_comp("PMINSW"), str8_lit_comp("Minimum of Packed Signed Integers")}, +{str8_lit_comp("PMINUB"), str8_lit_comp("Minimum of Packed Unsigned Integers")}, +{str8_lit_comp("PMINUD"), str8_lit_comp("Minimum of Packed Unsigned Integers")}, +{str8_lit_comp("PMINUQ"), str8_lit_comp("Minimum of Packed Unsigned Integers")}, +{str8_lit_comp("PMINUW"), str8_lit_comp("Minimum of Packed Unsigned Integers")}, +{str8_lit_comp("PMOVMSKB"), str8_lit_comp("Move Byte Mask")}, +{str8_lit_comp("PMOVSX"), str8_lit_comp("Packed Move with Sign Extend")}, +{str8_lit_comp("PMOVZX"), str8_lit_comp("Packed Move with Zero Extend")}, +{str8_lit_comp("PMULDQ"), str8_lit_comp("Multiply Packed Doubleword Integers")}, +{str8_lit_comp("PMULHRSW"), str8_lit_comp("Packed Multiply High with Round and Scale")}, +{str8_lit_comp("PMULHUW"), str8_lit_comp("Multiply Packed Unsigned Integers and Store High Result")}, +{str8_lit_comp("PMULHW"), str8_lit_comp("Multiply Packed Signed Integers and Store High Result")}, +{str8_lit_comp("PMULLD"), str8_lit_comp("Multiply Packed Integers and Store Low Result")}, +{str8_lit_comp("PMULLQ"), str8_lit_comp("Multiply Packed Integers and Store Low Result")}, +{str8_lit_comp("PMULLW"), str8_lit_comp("Multiply Packed Signed Integers and Store Low Result")}, +{str8_lit_comp("PMULUDQ"), str8_lit_comp("Multiply Packed Unsigned Doubleword Integers")}, +{str8_lit_comp("POP"), str8_lit_comp("Pop a Value from the Stack")}, +{str8_lit_comp("POPA"), str8_lit_comp("Pop All General-Purpose Registers")}, +{str8_lit_comp("POPAD"), str8_lit_comp("Pop All General-Purpose Registers")}, +{str8_lit_comp("POPCNT"), str8_lit_comp("Return the Count of Number of Bits Set to 1")}, +{str8_lit_comp("POPF"), str8_lit_comp("Pop Stack into EFLAGS Register")}, +{str8_lit_comp("POPFD"), str8_lit_comp("Pop Stack into EFLAGS Register")}, +{str8_lit_comp("POPFQ"), str8_lit_comp("Pop Stack into EFLAGS Register")}, +{str8_lit_comp("POR"), str8_lit_comp("Bitwise Logical OR")}, +{str8_lit_comp("PREFETCHW"), str8_lit_comp("Prefetch Data into Caches in Anticipation of a Write")}, +{str8_lit_comp("PREFETCHh"), str8_lit_comp("Prefetch Data Into Caches")}, +{str8_lit_comp("PSADBW"), str8_lit_comp("Compute Sum of Absolute Differences")}, +{str8_lit_comp("PSHUFB"), str8_lit_comp("Packed Shuffle Bytes")}, +{str8_lit_comp("PSHUFD"), str8_lit_comp("Shuffle Packed Doublewords")}, +{str8_lit_comp("PSHUFHW"), str8_lit_comp("Shuffle Packed High Words")}, +{str8_lit_comp("PSHUFLW"), str8_lit_comp("Shuffle Packed Low Words")}, +{str8_lit_comp("PSHUFW"), str8_lit_comp("Shuffle Packed Words")}, +{str8_lit_comp("PSIGNB"), str8_lit_comp("Packed SIGN")}, +{str8_lit_comp("PSIGND"), str8_lit_comp("Packed SIGN")}, +{str8_lit_comp("PSIGNW"), str8_lit_comp("Packed SIGN")}, +{str8_lit_comp("PSLLD"), str8_lit_comp("Shift Packed Data Left Logical")}, +{str8_lit_comp("PSLLDQ"), str8_lit_comp("Shift Double Quadword Left Logical")}, +{str8_lit_comp("PSLLQ"), str8_lit_comp("Shift Packed Data Left Logical")}, +{str8_lit_comp("PSLLW"), str8_lit_comp("Shift Packed Data Left Logical")}, +{str8_lit_comp("PSRAD"), str8_lit_comp("Shift Packed Data Right Arithmetic")}, +{str8_lit_comp("PSRAQ"), str8_lit_comp("Shift Packed Data Right Arithmetic")}, +{str8_lit_comp("PSRAW"), str8_lit_comp("Shift Packed Data Right Arithmetic")}, +{str8_lit_comp("PSRLD"), str8_lit_comp("Shift Packed Data Right Logical")}, +{str8_lit_comp("PSRLDQ"), str8_lit_comp("Shift Double Quadword Right Logical")}, +{str8_lit_comp("PSRLQ"), str8_lit_comp("Shift Packed Data Right Logical")}, +{str8_lit_comp("PSRLW"), str8_lit_comp("Shift Packed Data Right Logical")}, +{str8_lit_comp("PSUBB"), str8_lit_comp("Subtract Packed Integers")}, +{str8_lit_comp("PSUBD"), str8_lit_comp("Subtract Packed Integers")}, +{str8_lit_comp("PSUBQ"), str8_lit_comp("Subtract Packed Quadword Integers")}, +{str8_lit_comp("PSUBSB"), str8_lit_comp("Subtract Packed Signed Integers with Signed Saturation")}, +{str8_lit_comp("PSUBSW"), str8_lit_comp("Subtract Packed Signed Integers with Signed Saturation")}, +{str8_lit_comp("PSUBUSB"), str8_lit_comp("Subtract Packed Unsigned Integers with Unsigned Saturation")}, +{str8_lit_comp("PSUBUSW"), str8_lit_comp("Subtract Packed Unsigned Integers with Unsigned Saturation")}, +{str8_lit_comp("PSUBW"), str8_lit_comp("Subtract Packed Integers")}, +{str8_lit_comp("PTEST"), str8_lit_comp("Logical Compare")}, +{str8_lit_comp("PTWRITE"), str8_lit_comp("Write Data to a Processor Trace Packet")}, +{str8_lit_comp("PUNPCKHBW"), str8_lit_comp("Unpack High Data")}, +{str8_lit_comp("PUNPCKHDQ"), str8_lit_comp("Unpack High Data")}, +{str8_lit_comp("PUNPCKHQDQ"), str8_lit_comp("Unpack High Data")}, +{str8_lit_comp("PUNPCKHWD"), str8_lit_comp("Unpack High Data")}, +{str8_lit_comp("PUNPCKLBW"), str8_lit_comp("Unpack Low Data")}, +{str8_lit_comp("PUNPCKLDQ"), str8_lit_comp("Unpack Low Data")}, +{str8_lit_comp("PUNPCKLQDQ"), str8_lit_comp("Unpack Low Data")}, +{str8_lit_comp("PUNPCKLWD"), str8_lit_comp("Unpack Low Data")}, +{str8_lit_comp("PUSH"), str8_lit_comp("Push Word, Doubleword or Quadword Onto the Stack")}, +{str8_lit_comp("PUSHA"), str8_lit_comp("Push All General-Purpose Registers")}, +{str8_lit_comp("PUSHAD"), str8_lit_comp("Push All General-Purpose Registers")}, +{str8_lit_comp("PUSHF"), str8_lit_comp("Push EFLAGS Register onto the Stack")}, +{str8_lit_comp("PUSHFD"), str8_lit_comp("Push EFLAGS Register onto the Stack")}, +{str8_lit_comp("PUSHFQ"), str8_lit_comp("Push EFLAGS Register onto the Stack")}, +{str8_lit_comp("PXOR"), str8_lit_comp("Logical Exclusive OR")}, +{str8_lit_comp("RCL"), str8_lit_comp("Rotate")}, +{str8_lit_comp("RCPPS"), str8_lit_comp("Compute Reciprocals of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("RCPSS"), str8_lit_comp("Compute Reciprocal of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("RCR"), str8_lit_comp("Rotate")}, +{str8_lit_comp("RDFSBASE"), str8_lit_comp("Read FS/GS Segment Base")}, +{str8_lit_comp("RDGSBASE"), str8_lit_comp("Read FS/GS Segment Base")}, +{str8_lit_comp("RDMSR"), str8_lit_comp("Read from Model Specific Register")}, +{str8_lit_comp("RDPID"), str8_lit_comp("Read Processor ID")}, +{str8_lit_comp("RDPKRU"), str8_lit_comp("Read Protection Key Rights for User Pages")}, +{str8_lit_comp("RDPMC"), str8_lit_comp("Read Performance-Monitoring Counters")}, +{str8_lit_comp("RDRAND"), str8_lit_comp("Read Random Number")}, +{str8_lit_comp("RDSEED"), str8_lit_comp("Read Random SEED")}, +{str8_lit_comp("RDSSPD"), str8_lit_comp("Read Shadow Stack Pointer")}, +{str8_lit_comp("RDSSPQ"), str8_lit_comp("Read Shadow Stack Pointer")}, +{str8_lit_comp("RDTSC"), str8_lit_comp("Read Time-Stamp Counter")}, +{str8_lit_comp("RDTSCP"), str8_lit_comp("Read Time-Stamp Counter and Processor ID")}, +{str8_lit_comp("REP"), str8_lit_comp("Repeat String Operation Prefix")}, +{str8_lit_comp("REPE"), str8_lit_comp("Repeat String Operation Prefix")}, +{str8_lit_comp("REPNE"), str8_lit_comp("Repeat String Operation Prefix")}, +{str8_lit_comp("REPNZ"), str8_lit_comp("Repeat String Operation Prefix")}, +{str8_lit_comp("REPZ"), str8_lit_comp("Repeat String Operation Prefix")}, +{str8_lit_comp("RET"), str8_lit_comp("Return from Procedure")}, +{str8_lit_comp("ROL"), str8_lit_comp("Rotate")}, +{str8_lit_comp("ROR"), str8_lit_comp("Rotate")}, +{str8_lit_comp("RORX"), str8_lit_comp("Rotate Right Logical Without Affecting Flags")}, +{str8_lit_comp("ROUNDPD"), str8_lit_comp("Round Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("ROUNDPS"), str8_lit_comp("Round Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("ROUNDSD"), str8_lit_comp("Round Scalar Double Precision Floating-Point Values")}, +{str8_lit_comp("ROUNDSS"), str8_lit_comp("Round Scalar Single Precision Floating-Point Values")}, +{str8_lit_comp("RSM"), str8_lit_comp("Resume from System Management Mode")}, +{str8_lit_comp("RSQRTPS"), str8_lit_comp("Compute Reciprocals of Square Roots of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("RSQRTSS"), str8_lit_comp("Compute Reciprocal of Square Root of Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("RSTORSSP"), str8_lit_comp("Restore Saved Shadow Stack Pointer")}, +{str8_lit_comp("SAHF"), str8_lit_comp("Store AH into Flags")}, +{str8_lit_comp("SAL"), str8_lit_comp("Shift")}, +{str8_lit_comp("SAR"), str8_lit_comp("Shift")}, +{str8_lit_comp("SARX"), str8_lit_comp("Shift Without Affecting Flags")}, +{str8_lit_comp("SAVEPREVSSP"), str8_lit_comp("Save Previous Shadow Stack Pointer")}, +{str8_lit_comp("SBB"), str8_lit_comp("Integer Subtraction with Borrow")}, +{str8_lit_comp("SCAS"), str8_lit_comp("Scan String")}, +{str8_lit_comp("SCASB"), str8_lit_comp("Scan String")}, +{str8_lit_comp("SCASD"), str8_lit_comp("Scan String")}, +{str8_lit_comp("SCASW"), str8_lit_comp("Scan String")}, +{str8_lit_comp("SERIALIZE"), str8_lit_comp("Serialize Instruction Execution")}, +{str8_lit_comp("SETSSBSY"), str8_lit_comp("Mark Shadow Stack Busy")}, +{str8_lit_comp("SETcc"), str8_lit_comp("Set Byte on Condition")}, +{str8_lit_comp("SFENCE"), str8_lit_comp("Store Fence")}, +{str8_lit_comp("SGDT"), str8_lit_comp("Store Global Descriptor Table Register")}, +{str8_lit_comp("SHA1MSG1"), str8_lit_comp("Perform an Intermediate Calculation for the Next Four SHA1 Message Dwords")}, +{str8_lit_comp("SHA1MSG2"), str8_lit_comp("Perform a Final Calculation for the Next Four SHA1 Message Dwords")}, +{str8_lit_comp("SHA1NEXTE"), str8_lit_comp("Calculate SHA1 State Variable E after Four Rounds")}, +{str8_lit_comp("SHA1RNDS4"), str8_lit_comp("Perform Four Rounds of SHA1 Operation")}, +{str8_lit_comp("SHA256MSG1"), str8_lit_comp("Perform an Intermediate Calculation for the Next Four SHA256 Message Dwords")}, +{str8_lit_comp("SHA256MSG2"), str8_lit_comp("Perform a Final Calculation for the Next Four SHA256 Message Dwords")}, +{str8_lit_comp("SHA256RNDS2"), str8_lit_comp("Perform Two Rounds of SHA256 Operation")}, +{str8_lit_comp("SHL"), str8_lit_comp("Shift")}, +{str8_lit_comp("SHLD"), str8_lit_comp("Double Precision Shift Left")}, +{str8_lit_comp("SHLX"), str8_lit_comp("Shift Without Affecting Flags")}, +{str8_lit_comp("SHR"), str8_lit_comp("Shift")}, +{str8_lit_comp("SHRD"), str8_lit_comp("Double Precision Shift Right")}, +{str8_lit_comp("SHRX"), str8_lit_comp("Shift Without Affecting Flags")}, +{str8_lit_comp("SHUFPD"), str8_lit_comp("Packed Interleave Shuffle of Pairs of Double-Precision Floating-Point Values")}, +{str8_lit_comp("SHUFPS"), str8_lit_comp("Packed Interleave Shuffle of Quadruplets of Single-Precision Floating-Point Values")}, +{str8_lit_comp("SIDT"), str8_lit_comp("Store Interrupt Descriptor Table Register")}, +{str8_lit_comp("SLDT"), str8_lit_comp("Store Local Descriptor Table Register")}, +{str8_lit_comp("SMSW"), str8_lit_comp("Store Machine Status Word")}, +{str8_lit_comp("SQRTPD"), str8_lit_comp("Square Root of Double-Precision Floating-Point Values")}, +{str8_lit_comp("SQRTPS"), str8_lit_comp("Square Root of Single-Precision Floating-Point Values")}, +{str8_lit_comp("SQRTSD"), str8_lit_comp("Compute Square Root of Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("SQRTSS"), str8_lit_comp("Compute Square Root of Scalar Single-Precision Value")}, +{str8_lit_comp("STAC"), str8_lit_comp("Set AC Flag in EFLAGS Register")}, +{str8_lit_comp("STC"), str8_lit_comp("Set Carry Flag")}, +{str8_lit_comp("STD"), str8_lit_comp("Set Direction Flag")}, +{str8_lit_comp("STI"), str8_lit_comp("Set Interrupt Flag")}, +{str8_lit_comp("STMXCSR"), str8_lit_comp("Store MXCSR Register State")}, +{str8_lit_comp("STOS"), str8_lit_comp("Store String")}, +{str8_lit_comp("STOSB"), str8_lit_comp("Store String")}, +{str8_lit_comp("STOSD"), str8_lit_comp("Store String")}, +{str8_lit_comp("STOSQ"), str8_lit_comp("Store String")}, +{str8_lit_comp("STOSW"), str8_lit_comp("Store String")}, +{str8_lit_comp("STR"), str8_lit_comp("Store Task Register")}, +{str8_lit_comp("SUB"), str8_lit_comp("Subtract")}, +{str8_lit_comp("SUBPD"), str8_lit_comp("Subtract Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("SUBPS"), str8_lit_comp("Subtract Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("SUBSD"), str8_lit_comp("Subtract Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("SUBSS"), str8_lit_comp("Subtract Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("SWAPGS"), str8_lit_comp("Swap GS Base Register")}, +{str8_lit_comp("SYSCALL"), str8_lit_comp("Fast System Call")}, +{str8_lit_comp("SYSENTER"), str8_lit_comp("Fast System Call")}, +{str8_lit_comp("SYSEXIT"), str8_lit_comp("Fast Return from Fast System Call")}, +{str8_lit_comp("SYSRET"), str8_lit_comp("Return From Fast System Call")}, +{str8_lit_comp("TEST"), str8_lit_comp("Logical Compare")}, +{str8_lit_comp("TPAUSE"), str8_lit_comp("Timed PAUSE")}, +{str8_lit_comp("TZCNT"), str8_lit_comp("Count the Number of Trailing Zero Bits")}, +{str8_lit_comp("UCOMISD"), str8_lit_comp("Unordered Compare Scalar Double-Precision Floating-Point Values and Set EFLAGS")}, +{str8_lit_comp("UCOMISS"), str8_lit_comp("Unordered Compare Scalar Single-Precision Floating-Point Values and Set EFLAGS")}, +{str8_lit_comp("UD"), str8_lit_comp("Undefined Instruction")}, +{str8_lit_comp("UMONITOR"), str8_lit_comp("User Level Set Up Monitor Address")}, +{str8_lit_comp("UMWAIT"), str8_lit_comp("User Level Monitor Wait")}, +{str8_lit_comp("UNPCKHPD"), str8_lit_comp("Unpack and Interleave High Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("UNPCKHPS"), str8_lit_comp("Unpack and Interleave High Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("UNPCKLPD"), str8_lit_comp("Unpack and Interleave Low Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("UNPCKLPS"), str8_lit_comp("Unpack and Interleave Low Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VALIGND"), str8_lit_comp("Align Doubleword/Quadword Vectors")}, +{str8_lit_comp("VALIGNQ"), str8_lit_comp("Align Doubleword/Quadword Vectors")}, +{str8_lit_comp("VBLENDMPD"), str8_lit_comp("Blend Float64/Float32 Vectors Using an OpMask Control")}, +{str8_lit_comp("VBLENDMPS"), str8_lit_comp("Blend Float64/Float32 Vectors Using an OpMask Control")}, +{str8_lit_comp("VBROADCAST"), str8_lit_comp("Load with Broadcast Floating-Point Data")}, +{str8_lit_comp("VCOMPRESSPD"), str8_lit_comp("Store Sparse Packed Double-Precision Floating-Point Values into Dense Memory")}, +{str8_lit_comp("VCOMPRESSPS"), str8_lit_comp("Store Sparse Packed Single-Precision Floating-Point Values into Dense Memory")}, +{str8_lit_comp("VCOMPRESSW"), str8_lit_comp("Store Sparse Packed Byte/Word Integer Values into Dense Memory/Register")}, +{str8_lit_comp("VCVTNE2PS2BF16"), str8_lit_comp("Convert Two Packed Single Data to One Packed BF16 Data")}, +{str8_lit_comp("VCVTNEPS2BF16"), str8_lit_comp("Convert Packed Single Data to Packed BF16 Data")}, +{str8_lit_comp("VCVTPD2QQ"), str8_lit_comp("Convert Packed Double-Precision Floating-Point Values to Packed Quadword Integers")}, +{str8_lit_comp("VCVTPD2UDQ"), str8_lit_comp("Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers")}, +{str8_lit_comp("VCVTPD2UQQ"), str8_lit_comp("Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers")}, +{str8_lit_comp("VCVTPH2PS"), str8_lit_comp("Convert 16-bit FP values to Single-Precision FP values")}, +{str8_lit_comp("VCVTPS2PH"), str8_lit_comp("Convert Single-Precision FP value to 16-bit FP value")}, +{str8_lit_comp("VCVTPS2QQ"), str8_lit_comp("Convert Packed Single Precision Floating-Point Values to Packed Signed Quadword Integer Values")}, +{str8_lit_comp("VCVTPS2UDQ"), str8_lit_comp("Convert Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values")}, +{str8_lit_comp("VCVTPS2UQQ"), str8_lit_comp("Convert Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values")}, +{str8_lit_comp("VCVTQQ2PD"), str8_lit_comp("Convert Packed Quadword Integers to Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VCVTQQ2PS"), str8_lit_comp("Convert Packed Quadword Integers to Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VCVTSD2USI"), str8_lit_comp("Convert Scalar Double-Precision Floating-Point Value to Unsigned Doubleword Integer")}, +{str8_lit_comp("VCVTSS2USI"), str8_lit_comp("Convert Scalar Single-Precision Floating-Point Value to Unsigned Doubleword Integer")}, +{str8_lit_comp("VCVTTPD2QQ"), str8_lit_comp("Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Quadword Integers")}, +{str8_lit_comp("VCVTTPD2UDQ"), str8_lit_comp("Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers")}, +{str8_lit_comp("VCVTTPD2UQQ"), str8_lit_comp("Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers")}, +{str8_lit_comp("VCVTTPS2QQ"), str8_lit_comp("Convert with Truncation Packed Single Precision Floating-Point Values to Packed Signed Quadword Integer Values")}, +{str8_lit_comp("VCVTTPS2UDQ"), str8_lit_comp("Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values")}, +{str8_lit_comp("VCVTTPS2UQQ"), str8_lit_comp("Convert with Truncation Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values")}, +{str8_lit_comp("VCVTTSD2USI"), str8_lit_comp("Convert with Truncation Scalar Double-Precision Floating-Point Value to Unsigned Integer")}, +{str8_lit_comp("VCVTTSS2USI"), str8_lit_comp("Convert with Truncation Scalar Single-Precision Floating-Point Value to Unsigned Integer")}, +{str8_lit_comp("VCVTUDQ2PD"), str8_lit_comp("Convert Packed Unsigned Doubleword Integers to Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VCVTUDQ2PS"), str8_lit_comp("Convert Packed Unsigned Doubleword Integers to Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VCVTUQQ2PD"), str8_lit_comp("Convert Packed Unsigned Quadword Integers to Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VCVTUQQ2PS"), str8_lit_comp("Convert Packed Unsigned Quadword Integers to Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VCVTUSI2SD"), str8_lit_comp("Convert Unsigned Integer to Scalar Double-Precision Floating-Point Value")}, +{str8_lit_comp("VCVTUSI2SS"), str8_lit_comp("Convert Unsigned Integer to Scalar Single-Precision Floating-Point Value")}, +{str8_lit_comp("VDBPSADBW"), str8_lit_comp("Double Block Packed Sum-Absolute-Differences (SAD) on Unsigned Bytes")}, +{str8_lit_comp("VDPBF16PS"), str8_lit_comp("Dot Product of BF16 Pairs Accumulated into Packed Single Precision")}, +{str8_lit_comp("VERR"), str8_lit_comp("Verify a Segment for Reading or Writing")}, +{str8_lit_comp("VERW"), str8_lit_comp("Verify a Segment for Reading or Writing")}, +{str8_lit_comp("VEXPANDPD"), str8_lit_comp("Load Sparse Packed Double-Precision Floating-Point Values from Dense Memory")}, +{str8_lit_comp("VEXPANDPS"), str8_lit_comp("Load Sparse Packed Single-Precision Floating-Point Values from Dense Memory")}, +{str8_lit_comp("VEXTRACTF128"), str8_lit_comp("Extr act Packed Floating-Point Values")}, +{str8_lit_comp("VEXTRACTF32x4"), str8_lit_comp("Extr act Packed Floating-Point Values")}, +{str8_lit_comp("VEXTRACTF32x8"), str8_lit_comp("Extr act Packed Floating-Point Values")}, +{str8_lit_comp("VEXTRACTF64x2"), str8_lit_comp("Extr act Packed Floating-Point Values")}, +{str8_lit_comp("VEXTRACTF64x4"), str8_lit_comp("Extr act Packed Floating-Point Values")}, +{str8_lit_comp("VEXTRACTI128"), str8_lit_comp("Extract packed Integer Values")}, +{str8_lit_comp("VEXTRACTI32x4"), str8_lit_comp("Extract packed Integer Values")}, +{str8_lit_comp("VEXTRACTI32x8"), str8_lit_comp("Extract packed Integer Values")}, +{str8_lit_comp("VEXTRACTI64x2"), str8_lit_comp("Extract packed Integer Values")}, +{str8_lit_comp("VEXTRACTI64x4"), str8_lit_comp("Extract packed Integer Values")}, +{str8_lit_comp("VFIXUPIMMPD"), str8_lit_comp("Fix Up Special Packed Float64 Values")}, +{str8_lit_comp("VFIXUPIMMPS"), str8_lit_comp("Fix Up Special Packed Float32 Values")}, +{str8_lit_comp("VFIXUPIMMSD"), str8_lit_comp("Fix Up Special Scalar Float64 Value")}, +{str8_lit_comp("VFIXUPIMMSS"), str8_lit_comp("Fix Up Special Scalar Float32 Value")}, +{str8_lit_comp("VFMADD132PD"), str8_lit_comp("Fused Multiply-Add of Packed Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD132PS"), str8_lit_comp("Fused Multiply-Add of Packed Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD132SD"), str8_lit_comp("Fused Multiply-Add of Scalar Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD132SS"), str8_lit_comp("Fused Multiply-Add of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD213PD"), str8_lit_comp("Fused Multiply-Add of Packed Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD213PS"), str8_lit_comp("Fused Multiply-Add of Packed Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD213SD"), str8_lit_comp("Fused Multiply-Add of Scalar Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD213SS"), str8_lit_comp("Fused Multiply-Add of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD231PD"), str8_lit_comp("Fused Multiply-Add of Packed Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD231PS"), str8_lit_comp("Fused Multiply-Add of Packed Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD231SD"), str8_lit_comp("Fused Multiply-Add of Scalar Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMADD231SS"), str8_lit_comp("Fused Multiply-Add of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADDSUB132PD"), str8_lit_comp("Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADDSUB132PS"), str8_lit_comp("Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADDSUB213PD"), str8_lit_comp("Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADDSUB213PS"), str8_lit_comp("Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADDSUB231PD"), str8_lit_comp("Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFMADDSUB231PS"), str8_lit_comp("Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB132PD"), str8_lit_comp("Fused Multiply-Subtract of Packed Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB132PS"), str8_lit_comp("Fused Multiply-Subtract of Packed Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB132SD"), str8_lit_comp("Fused Multiply-Subtract of Scalar Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB132SS"), str8_lit_comp("Fused Multiply-Subtract of Scalar Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB213PD"), str8_lit_comp("Fused Multiply-Subtract of Packed Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB213PS"), str8_lit_comp("Fused Multiply-Subtract of Packed Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB213SD"), str8_lit_comp("Fused Multiply-Subtract of Scalar Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB213SS"), str8_lit_comp("Fused Multiply-Subtract of Scalar Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB231PD"), str8_lit_comp("Fused Multiply-Subtract of Packed Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB231PS"), str8_lit_comp("Fused Multiply-Subtract of Packed Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB231SD"), str8_lit_comp("Fused Multiply-Subtract of Scalar Double- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUB231SS"), str8_lit_comp("Fused Multiply-Subtract of Scalar Single- Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUBADD132PD"), str8_lit_comp("Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUBADD132PS"), str8_lit_comp("Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUBADD213PD"), str8_lit_comp("Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUBADD213PS"), str8_lit_comp("Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUBADD231PD"), str8_lit_comp("Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFMSUBADD231PS"), str8_lit_comp("Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD132PD"), str8_lit_comp("Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD132PS"), str8_lit_comp("Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD132SD"), str8_lit_comp("Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD132SS"), str8_lit_comp("Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD213PD"), str8_lit_comp("Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD213PS"), str8_lit_comp("Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD213SD"), str8_lit_comp("Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD213SS"), str8_lit_comp("Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD231PD"), str8_lit_comp("Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD231PS"), str8_lit_comp("Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD231SD"), str8_lit_comp("Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMADD231SS"), str8_lit_comp("Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB132PD"), str8_lit_comp("Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB132PS"), str8_lit_comp("Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB132SD"), str8_lit_comp("Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB132SS"), str8_lit_comp("Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB213PD"), str8_lit_comp("Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB213PS"), str8_lit_comp("Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB213SD"), str8_lit_comp("Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB213SS"), str8_lit_comp("Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB231PD"), str8_lit_comp("Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB231PS"), str8_lit_comp("Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB231SD"), str8_lit_comp("Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values")}, +{str8_lit_comp("VFNMSUB231SS"), str8_lit_comp("Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values")}, +{str8_lit_comp("VFPCLASSPD"), str8_lit_comp("Tests Types Of a Packed Float64 Values")}, +{str8_lit_comp("VFPCLASSPS"), str8_lit_comp("Tests Types Of a Packed Float32 Values")}, +{str8_lit_comp("VFPCLASSSD"), str8_lit_comp("Tests Types Of a Scalar Float64 Values")}, +{str8_lit_comp("VFPCLASSSS"), str8_lit_comp("Tests Types Of a Scalar Float32 Values")}, +{str8_lit_comp("VGATHERDPD"), str8_lit_comp("Gather Packed DP FP Values Using Signed Dword/Qword Indices")}, +{str8_lit_comp("VGATHERDPS"), str8_lit_comp("Gather Packed SP FP values Using Signed Dword/Qword Indices")}, +{str8_lit_comp("VGATHERQPD"), str8_lit_comp("Gather Packed DP FP Values Using Signed Dword/Qword Indices")}, +{str8_lit_comp("VGATHERQPS"), str8_lit_comp("Gather Packed SP FP values Using Signed Dword/Qword Indices")}, +{str8_lit_comp("VGETEXPPD"), str8_lit_comp("Convert Exponents of Packed DP FP Values to DP FP Values")}, +{str8_lit_comp("VGETEXPPS"), str8_lit_comp("Convert Exponents of Packed SP FP Values to SP FP Values")}, +{str8_lit_comp("VGETEXPSD"), str8_lit_comp("Convert Exponents of Scalar DP FP Values to DP FP Value")}, +{str8_lit_comp("VGETEXPSS"), str8_lit_comp("Convert Exponents of Scalar SP FP Values to SP FP Value")}, +{str8_lit_comp("VGETMANTPD"), str8_lit_comp("Extract Float64 Vector of Normalized Mantissas from Float64 Vector")}, +{str8_lit_comp("VGETMANTPS"), str8_lit_comp("Extract Float32 Vector of Normalized Mantissas from Float32 Vector")}, +{str8_lit_comp("VGETMANTSD"), str8_lit_comp("Extract Float64 of Normalized Mantissas from Float64 Scalar")}, +{str8_lit_comp("VGETMANTSS"), str8_lit_comp("Extract Float32 Vector of Normalized Mantissa from Float32 Vector")}, +{str8_lit_comp("VINSERTF128"), str8_lit_comp("Insert Packed Floating-Point Values")}, +{str8_lit_comp("VINSERTF32x4"), str8_lit_comp("Insert Packed Floating-Point Values")}, +{str8_lit_comp("VINSERTF32x8"), str8_lit_comp("Insert Packed Floating-Point Values")}, +{str8_lit_comp("VINSERTF64x2"), str8_lit_comp("Insert Packed Floating-Point Values")}, +{str8_lit_comp("VINSERTF64x4"), str8_lit_comp("Insert Packed Floating-Point Values")}, +{str8_lit_comp("VINSERTI128"), str8_lit_comp("Insert Packed Integer Values")}, +{str8_lit_comp("VINSERTI32x4"), str8_lit_comp("Insert Packed Integer Values")}, +{str8_lit_comp("VINSERTI32x8"), str8_lit_comp("Insert Packed Integer Values")}, +{str8_lit_comp("VINSERTI64x2"), str8_lit_comp("Insert Packed Integer Values")}, +{str8_lit_comp("VINSERTI64x4"), str8_lit_comp("Insert Packed Integer Values")}, +{str8_lit_comp("VMASKMOV"), str8_lit_comp("Conditional SIMD Packed Loads and Stores")}, +{str8_lit_comp("VMOVDQA32"), str8_lit_comp("Move Aligned Packed Integer Values")}, +{str8_lit_comp("VMOVDQA64"), str8_lit_comp("Move Aligned Packed Integer Values")}, +{str8_lit_comp("VMOVDQU16"), str8_lit_comp("Move Unaligned Packed Integer Values")}, +{str8_lit_comp("VMOVDQU32"), str8_lit_comp("Move Unaligned Packed Integer Values")}, +{str8_lit_comp("VMOVDQU64"), str8_lit_comp("Move Unaligned Packed Integer Values")}, +{str8_lit_comp("VMOVDQU8"), str8_lit_comp("Move Unaligned Packed Integer Values")}, +{str8_lit_comp("VP2INTERSECTD"), str8_lit_comp("Compute Intersection Between DWORDS/QUADWORDS to a Pair of Mask Registers")}, +{str8_lit_comp("VP2INTERSECTQ"), str8_lit_comp("Compute Intersection Between DWORDS/QUADWORDS to a Pair of Mask Registers")}, +{str8_lit_comp("VPBLENDD"), str8_lit_comp("Blend Packed Dwords")}, +{str8_lit_comp("VPBLENDMB"), str8_lit_comp("Blend Byte/Word Vectors Using an Opmask Control")}, +{str8_lit_comp("VPBLENDMD"), str8_lit_comp("Blend Int32/Int64 Vectors Using an OpMask Control")}, +{str8_lit_comp("VPBLENDMQ"), str8_lit_comp("Blend Int32/Int64 Vectors Using an OpMask Control")}, +{str8_lit_comp("VPBLENDMW"), str8_lit_comp("Blend Byte/Word Vectors Using an Opmask Control")}, +{str8_lit_comp("VPBROADCAST"), str8_lit_comp("Load Integer and Broadcast")}, +{str8_lit_comp("VPBROADCASTB"), str8_lit_comp("Load with Broadcast Integer Data from General Purpose Register")}, +{str8_lit_comp("VPBROADCASTD"), str8_lit_comp("Load with Broadcast Integer Data from General Purpose Register")}, +{str8_lit_comp("VPBROADCASTM"), str8_lit_comp("Broadcast Mask to Vector Register")}, +{str8_lit_comp("VPBROADCASTQ"), str8_lit_comp("Load with Broadcast Integer Data from General Purpose Register")}, +{str8_lit_comp("VPBROADCASTW"), str8_lit_comp("Load with Broadcast Integer Data from General Purpose Register")}, +{str8_lit_comp("VPCMPB"), str8_lit_comp("Compare Packed Byte Values Into Mask")}, +{str8_lit_comp("VPCMPD"), str8_lit_comp("Compare Packed Integer Values into Mask")}, +{str8_lit_comp("VPCMPQ"), str8_lit_comp("Compare Packed Integer Values into Mask")}, +{str8_lit_comp("VPCMPUB"), str8_lit_comp("Compare Packed Byte Values Into Mask")}, +{str8_lit_comp("VPCMPUD"), str8_lit_comp("Compare Packed Integer Values into Mask")}, +{str8_lit_comp("VPCMPUQ"), str8_lit_comp("Compare Packed Integer Values into Mask")}, +{str8_lit_comp("VPCMPUW"), str8_lit_comp("Compare Packed Word Values Into Mask")}, +{str8_lit_comp("VPCMPW"), str8_lit_comp("Compare Packed Word Values Into Mask")}, +{str8_lit_comp("VPCOMPRESSB"), str8_lit_comp("Store Sparse Packed Byte/Word Integer Values into Dense Memory/Register")}, +{str8_lit_comp("VPCOMPRESSD"), str8_lit_comp("Store Sparse Packed Doubleword Integer Values into Dense Memory/Register")}, +{str8_lit_comp("VPCOMPRESSQ"), str8_lit_comp("Store Sparse Packed Quadword Integer Values into Dense Memory/Register")}, +{str8_lit_comp("VPCONFLICTD"), str8_lit_comp("Detect Conflicts Within a Vector of Packed Dword/Qword Values into Dense Memory/ Register")}, +{str8_lit_comp("VPCONFLICTQ"), str8_lit_comp("Detect Conflicts Within a Vector of Packed Dword/Qword Values into Dense Memory/ Register")}, +{str8_lit_comp("VPDPBUSD"), str8_lit_comp("Multiply and Add Unsigned and Signed Bytes")}, +{str8_lit_comp("VPDPBUSDS"), str8_lit_comp("Multiply and Add Unsigned and Signed Bytes with Saturation")}, +{str8_lit_comp("VPDPWSSD"), str8_lit_comp("Multiply and Add Signed Word Integers")}, +{str8_lit_comp("VPDPWSSDS"), str8_lit_comp("Multiply and Add Signed Word Integers with Saturation")}, +{str8_lit_comp("VPERM2F128"), str8_lit_comp("Permute Floating-Point Values")}, +{str8_lit_comp("VPERM2I128"), str8_lit_comp("Permute Integer Values")}, +{str8_lit_comp("VPERMB"), str8_lit_comp("Permute Packed Bytes Elements")}, +{str8_lit_comp("VPERMD"), str8_lit_comp("Permute Packed Doublewords/Words Elements")}, +{str8_lit_comp("VPERMI2B"), str8_lit_comp("Full Permute of Bytes from Two Tables Overwriting the Index")}, +{str8_lit_comp("VPERMI2D"), str8_lit_comp("Full Permute From Two Tables Overwriting the Index")}, +{str8_lit_comp("VPERMI2PD"), str8_lit_comp("Full Permute From Two Tables Overwriting the Index")}, +{str8_lit_comp("VPERMI2PS"), str8_lit_comp("Full Permute From Two Tables Overwriting the Index")}, +{str8_lit_comp("VPERMI2Q"), str8_lit_comp("Full Permute From Two Tables Overwriting the Index")}, +{str8_lit_comp("VPERMI2W"), str8_lit_comp("Full Permute From Two Tables Overwriting the Index")}, +{str8_lit_comp("VPERMILPD"), str8_lit_comp("Permute In-Lane of Pairs of Double-Precision Floating-Point Values")}, +{str8_lit_comp("VPERMILPS"), str8_lit_comp("Permute In-Lane of Quadruples of Single-Precision Floating-Point Values")}, +{str8_lit_comp("VPERMPD"), str8_lit_comp("Permute Double-Precision Floating-Point Elements")}, +{str8_lit_comp("VPERMPS"), str8_lit_comp("Permute Single-Precision Floating-Point Elements")}, +{str8_lit_comp("VPERMQ"), str8_lit_comp("Qwords Element Permutation")}, +{str8_lit_comp("VPERMT2B"), str8_lit_comp("Full Permute of Bytes from Two Tables Overwriting a Table")}, +{str8_lit_comp("VPERMT2D"), str8_lit_comp("Full Permute from Two Tables Overwriting one Table")}, +{str8_lit_comp("VPERMT2PD"), str8_lit_comp("Full Permute from Two Tables Overwriting one Table")}, +{str8_lit_comp("VPERMT2PS"), str8_lit_comp("Full Permute from Two Tables Overwriting one Table")}, +{str8_lit_comp("VPERMT2Q"), str8_lit_comp("Full Permute from Two Tables Overwriting one Table")}, +{str8_lit_comp("VPERMT2W"), str8_lit_comp("Full Permute from Two Tables Overwriting one Table")}, +{str8_lit_comp("VPERMW"), str8_lit_comp("Permute Packed Doublewords/Words Elements")}, +{str8_lit_comp("VPEXPANDB"), str8_lit_comp("Expand Byte/Word Values")}, +{str8_lit_comp("VPEXPANDD"), str8_lit_comp("Load Sparse Packed Doubleword Integer Values from Dense Memory / Register")}, +{str8_lit_comp("VPEXPANDQ"), str8_lit_comp("Load Sparse Packed Quadword Integer Values from Dense Memory / Register")}, +{str8_lit_comp("VPEXPANDW"), str8_lit_comp("Expand Byte/Word Values")}, +{str8_lit_comp("VPGATHERDD"), str8_lit_comp("Gather Packed Dword Values Using Signed Dword/Qword Indices")}, +{str8_lit_comp("VPGATHERDQ"), str8_lit_comp("Gather Packed Dword, Packed Qword with Signed Dword Indices")}, +{str8_lit_comp("VPGATHERQD"), str8_lit_comp("Gather Packed Dword Values Using Signed Dword/Qword Indices")}, +{str8_lit_comp("VPGATHERQQ"), str8_lit_comp("Gather Packed Qword Values Using Signed Dword/Qword Indices")}, +{str8_lit_comp("VPLZCNTD"), str8_lit_comp("Count the Number of Leading Zero Bits for Packed Dword, Packed Qword Values")}, +{str8_lit_comp("VPLZCNTQ"), str8_lit_comp("Count the Number of Leading Zero Bits for Packed Dword, Packed Qword Values")}, +{str8_lit_comp("VPMADD52HUQ"), str8_lit_comp("Packed Multiply of Unsigned 52-bit Unsigned Integers and Add High 52-bit Products to 64-bit Accumulators")}, +{str8_lit_comp("VPMADD52LUQ"), str8_lit_comp("Packed Multiply of Unsigned 52-bit Integers and Add the Low 52-bit Products to Qword Accumulators")}, +{str8_lit_comp("VPMASKMOV"), str8_lit_comp("Conditional SIMD Integer Packed Loads and Stores")}, +{str8_lit_comp("VPMOVB2M"), str8_lit_comp("Convert a Vector Register to a Mask")}, +{str8_lit_comp("VPMOVD2M"), str8_lit_comp("Convert a Vector Register to a Mask")}, +{str8_lit_comp("VPMOVDB"), str8_lit_comp("Down Convert DWord to Byte")}, +{str8_lit_comp("VPMOVDW"), str8_lit_comp("Down Convert DWord to Word")}, +{str8_lit_comp("VPMOVM2B"), str8_lit_comp("Convert a Mask Register to a Vector Register")}, +{str8_lit_comp("VPMOVM2D"), str8_lit_comp("Convert a Mask Register to a Vector Register")}, +{str8_lit_comp("VPMOVM2Q"), str8_lit_comp("Convert a Mask Register to a Vector Register")}, +{str8_lit_comp("VPMOVM2W"), str8_lit_comp("Convert a Mask Register to a Vector Register")}, +{str8_lit_comp("VPMOVQ2M"), str8_lit_comp("Convert a Vector Register to a Mask")}, +{str8_lit_comp("VPMOVQB"), str8_lit_comp("Down Convert QWord to Byte")}, +{str8_lit_comp("VPMOVQD"), str8_lit_comp("Down Convert QWord to DWord")}, +{str8_lit_comp("VPMOVQW"), str8_lit_comp("Down Convert QWord to Word")}, +{str8_lit_comp("VPMOVSDB"), str8_lit_comp("Down Convert DWord to Byte")}, +{str8_lit_comp("VPMOVSDW"), str8_lit_comp("Down Convert DWord to Word")}, +{str8_lit_comp("VPMOVSQB"), str8_lit_comp("Down Convert QWord to Byte")}, +{str8_lit_comp("VPMOVSQD"), str8_lit_comp("Down Convert QWord to DWord")}, +{str8_lit_comp("VPMOVSQW"), str8_lit_comp("Down Convert QWord to Word")}, +{str8_lit_comp("VPMOVSWB"), str8_lit_comp("Down Convert Word to Byte")}, +{str8_lit_comp("VPMOVUSDB"), str8_lit_comp("Down Convert DWord to Byte")}, +{str8_lit_comp("VPMOVUSDW"), str8_lit_comp("Down Convert DWord to Word")}, +{str8_lit_comp("VPMOVUSQB"), str8_lit_comp("Down Convert QWord to Byte")}, +{str8_lit_comp("VPMOVUSQD"), str8_lit_comp("Down Convert QWord to DWord")}, +{str8_lit_comp("VPMOVUSQW"), str8_lit_comp("Down Convert QWord to Word")}, +{str8_lit_comp("VPMOVUSWB"), str8_lit_comp("Down Convert Word to Byte")}, +{str8_lit_comp("VPMOVW2M"), str8_lit_comp("Convert a Vector Register to a Mask")}, +{str8_lit_comp("VPMOVWB"), str8_lit_comp("Down Convert Word to Byte")}, +{str8_lit_comp("VPMULTISHIFTQB"), str8_lit_comp("Select Packed Unaligned Bytes from Quadword Sources")}, +{str8_lit_comp("VPOPCNT"), str8_lit_comp("Return the Count of Number of Bits Set to 1 in BYTE/WORD/DWORD/QWORD")}, +{str8_lit_comp("VPROLD"), str8_lit_comp("Bit Rotate Left")}, +{str8_lit_comp("VPROLQ"), str8_lit_comp("Bit Rotate Left")}, +{str8_lit_comp("VPROLVD"), str8_lit_comp("Bit Rotate Left")}, +{str8_lit_comp("VPROLVQ"), str8_lit_comp("Bit Rotate Left")}, +{str8_lit_comp("VPRORD"), str8_lit_comp("Bit Rotate Right")}, +{str8_lit_comp("VPRORQ"), str8_lit_comp("Bit Rotate Right")}, +{str8_lit_comp("VPRORVD"), str8_lit_comp("Bit Rotate Right")}, +{str8_lit_comp("VPRORVQ"), str8_lit_comp("Bit Rotate Right")}, +{str8_lit_comp("VPSCATTERDD"), str8_lit_comp("Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices")}, +{str8_lit_comp("VPSCATTERDQ"), str8_lit_comp("Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices")}, +{str8_lit_comp("VPSCATTERQD"), str8_lit_comp("Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices")}, +{str8_lit_comp("VPSCATTERQQ"), str8_lit_comp("Scatter Packed Dword, Packed Qword with Signed Dword, Signed Qword Indices")}, +{str8_lit_comp("VPSHLD"), str8_lit_comp("Concatenate and Shift Packed Data Left Logical")}, +{str8_lit_comp("VPSHLDV"), str8_lit_comp("Concatenate and Variable Shift Packed Data Left Logical")}, +{str8_lit_comp("VPSHRD"), str8_lit_comp("Concatenate and Shift Packed Data Right Logical")}, +{str8_lit_comp("VPSHRDV"), str8_lit_comp("Concatenate and Variable Shift Packed Data Right Logical")}, +{str8_lit_comp("VPSHUFBITQMB"), str8_lit_comp("Shuffle Bits from Quadword Elements Using Byte Indexes into Mask")}, +{str8_lit_comp("VPSLLVD"), str8_lit_comp("Variable Bit Shift Left Logical")}, +{str8_lit_comp("VPSLLVQ"), str8_lit_comp("Variable Bit Shift Left Logical")}, +{str8_lit_comp("VPSLLVW"), str8_lit_comp("Variable Bit Shift Left Logical")}, +{str8_lit_comp("VPSRAVD"), str8_lit_comp("Variable Bit Shift Right Arithmetic")}, +{str8_lit_comp("VPSRAVQ"), str8_lit_comp("Variable Bit Shift Right Arithmetic")}, +{str8_lit_comp("VPSRAVW"), str8_lit_comp("Variable Bit Shift Right Arithmetic")}, +{str8_lit_comp("VPSRLVD"), str8_lit_comp("Variable Bit Shift Right Logical")}, +{str8_lit_comp("VPSRLVQ"), str8_lit_comp("Variable Bit Shift Right Logical")}, +{str8_lit_comp("VPSRLVW"), str8_lit_comp("Variable Bit Shift Right Logical")}, +{str8_lit_comp("VPTERNLOGD"), str8_lit_comp("Bitwise Ternary Logic")}, +{str8_lit_comp("VPTERNLOGQ"), str8_lit_comp("Bitwise Ternary Logic")}, +{str8_lit_comp("VPTESTMB"), str8_lit_comp("Logical AND and Set Mask")}, +{str8_lit_comp("VPTESTMD"), str8_lit_comp("Logical AND and Set Mask")}, +{str8_lit_comp("VPTESTMQ"), str8_lit_comp("Logical AND and Set Mask")}, +{str8_lit_comp("VPTESTMW"), str8_lit_comp("Logical AND and Set Mask")}, +{str8_lit_comp("VPTESTNMB"), str8_lit_comp("Logical NAND and Set")}, +{str8_lit_comp("VPTESTNMD"), str8_lit_comp("Logical NAND and Set")}, +{str8_lit_comp("VPTESTNMQ"), str8_lit_comp("Logical NAND and Set")}, +{str8_lit_comp("VPTESTNMW"), str8_lit_comp("Logical NAND and Set")}, +{str8_lit_comp("VRANGEPD"), str8_lit_comp("Range Restriction Calculation For Packed Pairs of Float64 Values")}, +{str8_lit_comp("VRANGEPS"), str8_lit_comp("Range Restriction Calculation For Packed Pairs of Float32 Values")}, +{str8_lit_comp("VRANGESD"), str8_lit_comp("Range Restriction Calculation From a pair of Scalar Float64 Values")}, +{str8_lit_comp("VRANGESS"), str8_lit_comp("Range Restriction Calculation From a Pair of Scalar Float32 Values")}, +{str8_lit_comp("VRCP14PD"), str8_lit_comp("Compute Approximate Reciprocals of Packed Float64 Values")}, +{str8_lit_comp("VRCP14PS"), str8_lit_comp("Compute Approximate Reciprocals of Packed Float32 Values")}, +{str8_lit_comp("VRCP14SD"), str8_lit_comp("Compute Approximate Reciprocal of Scalar Float64 Value")}, +{str8_lit_comp("VRCP14SS"), str8_lit_comp("Compute Approximate Reciprocal of Scalar Float32 Value")}, +{str8_lit_comp("VREDUCEPD"), str8_lit_comp("Perform Reduction Transformation on Packed Float64 Values")}, +{str8_lit_comp("VREDUCEPS"), str8_lit_comp("Perform Reduction Transformation on Packed Float32 Values")}, +{str8_lit_comp("VREDUCESD"), str8_lit_comp("Perform a Reduction Transformation on a Scalar Float64 Value")}, +{str8_lit_comp("VREDUCESS"), str8_lit_comp("Perform a Reduction Transformation on a Scalar Float32 Value")}, +{str8_lit_comp("VRNDSCALEPD"), str8_lit_comp("Round Packed Float64 Values To Include A Given Number Of Fraction Bits")}, +{str8_lit_comp("VRNDSCALEPS"), str8_lit_comp("Round Packed Float32 Values To Include A Given Number Of Fraction Bits")}, +{str8_lit_comp("VRNDSCALESD"), str8_lit_comp("Round Scalar Float64 Value To Include A Given Number Of Fraction Bits")}, +{str8_lit_comp("VRNDSCALESS"), str8_lit_comp("Round Scalar Float32 Value To Include A Given Number Of Fraction Bits")}, +{str8_lit_comp("VRSQRT14PD"), str8_lit_comp("Compute Approximate Reciprocals of Square Roots of Packed Float64 Values")}, +{str8_lit_comp("VRSQRT14PS"), str8_lit_comp("Compute Approximate Reciprocals of Square Roots of Packed Float32 Values")}, +{str8_lit_comp("VRSQRT14SD"), str8_lit_comp("Compute Approximate Reciprocal of Square Root of Scalar Float64 Value")}, +{str8_lit_comp("VRSQRT14SS"), str8_lit_comp("Compute Approximate Reciprocal of Square Root of Scalar Float32 Value")}, +{str8_lit_comp("VSCALEFPD"), str8_lit_comp("Scale Packed Float64 Values With Float64 Values")}, +{str8_lit_comp("VSCALEFPS"), str8_lit_comp("Scale Packed Float32 Values With Float32 Values")}, +{str8_lit_comp("VSCALEFSD"), str8_lit_comp("Scale Scalar Float64 Values With Float64 Values")}, +{str8_lit_comp("VSCALEFSS"), str8_lit_comp("Scale Scalar Float32 Value With Float32 Value")}, +{str8_lit_comp("VSCATTERDPD"), str8_lit_comp("Scatter Packed Single, Packed Double with Signed Dword and Qword Indices")}, +{str8_lit_comp("VSCATTERDPS"), str8_lit_comp("Scatter Packed Single, Packed Double with Signed Dword and Qword Indices")}, +{str8_lit_comp("VSCATTERQPD"), str8_lit_comp("Scatter Packed Single, Packed Double with Signed Dword and Qword Indices")}, +{str8_lit_comp("VSCATTERQPS"), str8_lit_comp("Scatter Packed Single, Packed Double with Signed Dword and Qword Indices")}, +{str8_lit_comp("VSHUFF32x4"), str8_lit_comp("Shuffle Packed Values at 128-bit Granularity")}, +{str8_lit_comp("VSHUFF64x2"), str8_lit_comp("Shuffle Packed Values at 128-bit Granularity")}, +{str8_lit_comp("VSHUFI32x4"), str8_lit_comp("Shuffle Packed Values at 128-bit Granularity")}, +{str8_lit_comp("VSHUFI64x2"), str8_lit_comp("Shuffle Packed Values at 128-bit Granularity")}, +{str8_lit_comp("VTESTPD"), str8_lit_comp("Packed Bit Test")}, +{str8_lit_comp("VTESTPS"), str8_lit_comp("Packed Bit Test")}, +{str8_lit_comp("VZEROALL"), str8_lit_comp("Zero XMM, YMM and ZMM Registers")}, +{str8_lit_comp("VZEROUPPER"), str8_lit_comp("Zero Upper Bits of YMM and ZMM Registers")}, +{str8_lit_comp("WAIT"), str8_lit_comp("Wait")}, +{str8_lit_comp("WBINVD"), str8_lit_comp("Write Back and Invalidate Cache")}, +{str8_lit_comp("WBNOINVD"), str8_lit_comp("Write Back and Do Not Invalidate Cache")}, +{str8_lit_comp("WRFSBASE"), str8_lit_comp("Write FS/GS Segment Base")}, +{str8_lit_comp("WRGSBASE"), str8_lit_comp("Write FS/GS Segment Base")}, +{str8_lit_comp("WRMSR"), str8_lit_comp("Write to Model Specific Register")}, +{str8_lit_comp("WRPKRU"), str8_lit_comp("Write Data to User Page Key Register")}, +{str8_lit_comp("WRSSD"), str8_lit_comp("Write to Shadow Stack")}, +{str8_lit_comp("WRSSQ"), str8_lit_comp("Write to Shadow Stack")}, +{str8_lit_comp("WRUSSD"), str8_lit_comp("Write to User Shadow Stack")}, +{str8_lit_comp("WRUSSQ"), str8_lit_comp("Write to User Shadow Stack")}, +{str8_lit_comp("XABORT"), str8_lit_comp("Transactional Abort")}, +{str8_lit_comp("XACQUIRE"), str8_lit_comp("Hardware Lock Elision Prefix Hints")}, +{str8_lit_comp("XADD"), str8_lit_comp("Exchange and Add")}, +{str8_lit_comp("XBEGIN"), str8_lit_comp("Transactional Begin")}, +{str8_lit_comp("XCHG"), str8_lit_comp("Exchange Register/Memory with Register")}, +{str8_lit_comp("XEND"), str8_lit_comp("Transactional End")}, +{str8_lit_comp("XGETBV"), str8_lit_comp("Get Value of Extended Control Register")}, +{str8_lit_comp("XLAT"), str8_lit_comp("Table Look-up Translation")}, +{str8_lit_comp("XLATB"), str8_lit_comp("Table Look-up Translation")}, +{str8_lit_comp("XOR"), str8_lit_comp("Logical Exclusive OR")}, +{str8_lit_comp("XORPD"), str8_lit_comp("Bitwise Logical XOR of Packed Double Precision Floating-Point Values")}, +{str8_lit_comp("XORPS"), str8_lit_comp("Bitwise Logical XOR of Packed Single Precision Floating-Point Values")}, +{str8_lit_comp("XRELEASE"), str8_lit_comp("Hardware Lock Elision Prefix Hints")}, +{str8_lit_comp("XRSTOR"), str8_lit_comp("Restore Processor Extended States")}, +{str8_lit_comp("XRSTORS"), str8_lit_comp("Restore Processor Extended States Supervisor")}, +{str8_lit_comp("XSAVE"), str8_lit_comp("Save Processor Extended States")}, +{str8_lit_comp("XSAVEC"), str8_lit_comp("Save Processor Extended States with Compaction")}, +{str8_lit_comp("XSAVEOPT"), str8_lit_comp("Save Processor Extended States Optimized")}, +{str8_lit_comp("XSAVES"), str8_lit_comp("Save Processor Extended States Supervisor")}, +{str8_lit_comp("XSETBV"), str8_lit_comp("Set Extended Control Register")}, +{str8_lit_comp("XTEST"), str8_lit_comp("Test If In Transactional Execution")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("Execute an Enclave System Function of Specified Leaf Number")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EADD] Add a Page to an Uninitialized Enclave")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EAUG] Add a Page to an Initialized Enclave")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EBLOCK] Mark a page in EPC as Blocked")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ECREATE] Create an SECS page in the Enclave Page Cache")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EDBGRD] Read From a Debug Enclave")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EDBGWR] Write to a Debug Enclave")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EEXTEND] Extend Uninitialized Enclave Measurement by 256 Bytes")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EINIT] Initialize an Enclave for Execution")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ELDBC] Load an EPC Page and Mark its State")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ELDB] Load an EPC Page and Mark its State")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ELDUC] Load an EPC Page and Mark its State")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ELDU] Load an EPC Page and Mark its State")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EMODPR] Restrict the Permissions of an EPC Page")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EMODT] Change the Type of an EPC Page")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EPA] Add Version Array")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ERDINFO] Read Type and Status Information About an EPC Page")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EREMOVE] Remove a page from the EPC")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ETRACKC] Activates EBLOCK Checks")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[ETRACK] Activates EBLOCK Checks")}, +{str8_lit_comp("ENCLS"), str8_lit_comp("[EWB] Invalidate an EPC Page and Write out to Main Memory")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("Execute an Enclave User Function of Specified Leaf Number")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[EACCEPTCOPY] Initialize a Pending Page")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[EACCEPT] Accept Changes to an EPC Page")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[EENTER] Enters an Enclave")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[EEXIT] Exits an Enclave")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[EGETKEY] Retrieves a Cryptographic Key")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[EMODPE] Extend an EPC Page Permissions")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[EREPORT] Create a Cryptographic Report of the Enclave")}, +{str8_lit_comp("ENCLU"), str8_lit_comp("[ERESUME] Re-Enters an Enclave")}, +{str8_lit_comp("ENCLV"), str8_lit_comp("Execute an Enclave VMM Function of Specified Leaf Number")}, +{str8_lit_comp("INVEPT"), str8_lit_comp("Invalidate Translations Derived from EPT")}, +{str8_lit_comp("INVVPID"), str8_lit_comp("Invalidate Translations Based on VPID")}, +{str8_lit_comp("VMCALL"), str8_lit_comp("Call to VM Monitor")}, +{str8_lit_comp("VMCLEAR"), str8_lit_comp("Clear Virtual-Machine Control Structure")}, +{str8_lit_comp("VMFUNC"), str8_lit_comp("Invoke VM function")}, +{str8_lit_comp("VMLAUNCH"), str8_lit_comp("Launch/Resume Virtual Machine")}, +{str8_lit_comp("VMPTRLD"), str8_lit_comp("Load Pointer to Virtual-Machine Control Structure")}, +{str8_lit_comp("VMPTRST"), str8_lit_comp("Store Pointer to Virtual-Machine Control Structure")}, +{str8_lit_comp("VMREAD"), str8_lit_comp("Read Field from Virtual-Machine Control Structure")}, +{str8_lit_comp("VMRESUME"), str8_lit_comp("Launch/Resume Virtual Machine")}, +{str8_lit_comp("VMWRITE"), str8_lit_comp("Write Field to Virtual-Machine Control Structure")}, +{str8_lit_comp("VMXOFF"), str8_lit_comp("Leave VMX Operation")}, +{str8_lit_comp("VMXON"), str8_lit_comp("Enter VMX Operation")}, +{str8_lit_comp("PREFETCHWT1"), str8_lit_comp("Prefetch Vector Data Into Caches with Intent to Write and T1 Hint")}, +{str8_lit_comp("V4FMADDPS"), str8_lit_comp("Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations)")}, +{str8_lit_comp("V4FMADDSS"), str8_lit_comp("Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations)")}, +{str8_lit_comp("V4FNMADDPS"), str8_lit_comp("Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations)")}, +{str8_lit_comp("V4FNMADDSS"), str8_lit_comp("Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations)")}, +{str8_lit_comp("VEXP2PD"), str8_lit_comp("Approximation to the Exponential 2^x of Packed Double-Precision Floating-Point Values with Less Than 2^-23 Relative Error")}, +{str8_lit_comp("VEXP2PS"), str8_lit_comp("Approximation to the Exponential 2^x of Packed Single-Precision Floating-Point Values with Less Than 2^-23 Relative Error")}, +{str8_lit_comp("VGATHERPF0DPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint")}, +{str8_lit_comp("VGATHERPF0DPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint")}, +{str8_lit_comp("VGATHERPF0QPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint")}, +{str8_lit_comp("VGATHERPF0QPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint")}, +{str8_lit_comp("VGATHERPF1DPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint")}, +{str8_lit_comp("VGATHERPF1DPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint")}, +{str8_lit_comp("VGATHERPF1QPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint")}, +{str8_lit_comp("VGATHERPF1QPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint")}, +{str8_lit_comp("VP4DPWSSD"), str8_lit_comp("Dot Product of Signed Words with Dword Accumulation (4-iterations)")}, +{str8_lit_comp("VP4DPWSSDS"), str8_lit_comp("Dot Product of Signed Words with Dword Accumulation and Saturation (4-iterations)")}, +{str8_lit_comp("VRCP28PD"), str8_lit_comp("Approximation to the Reciprocal of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VRCP28PS"), str8_lit_comp("Approximation to the Reciprocal of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VRCP28SD"), str8_lit_comp("Approximation to the Reciprocal of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VRCP28SS"), str8_lit_comp("Approximation to the Reciprocal of Scalar Single-Precision Floating-Point Value with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VRSQRT28PD"), str8_lit_comp("Approximation to the Reciprocal Square Root of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VRSQRT28PS"), str8_lit_comp("Approximation to the Reciprocal Square Root of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VRSQRT28SD"), str8_lit_comp("Approximation to the Reciprocal Square Root of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VRSQRT28SS"), str8_lit_comp("Approximation to the Reciprocal Square Root of Scalar Single-Precision Floating- Point Value with Less Than 2^-28 Relative Error")}, +{str8_lit_comp("VSCATTERPF0DPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write")}, +{str8_lit_comp("VSCATTERPF0DPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write")}, +{str8_lit_comp("VSCATTERPF0QPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write")}, +{str8_lit_comp("VSCATTERPF0QPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T0 Hint with Intent to Write")}, +{str8_lit_comp("VSCATTERPF1DPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write")}, +{str8_lit_comp("VSCATTERPF1DPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write")}, +{str8_lit_comp("VSCATTERPF1QPD"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write")}, +{str8_lit_comp("VSCATTERPF1QPS"), str8_lit_comp("Sparse Prefetch Packed SP/DP Data Values with Signed Dword, Signed Qword Indices Using T1 Hint with Intent to Write")}, +}; + +global B32 DEV_telemetry_capture = 0; +global B32 DEV_simulate_lag = 0; +global B32 DEV_draw_ui_text_pos = 0; +global B32 DEV_draw_ui_focus_debug = 0; +global B32 DEV_draw_ui_box_heatmap = 0; +global B32 DEV_eval_compiler_tooltips = 0; +global B32 DEV_eval_watch_key_tooltips = 0; +global B32 DEV_cmd_context_tooltips = 0; +global B32 DEV_scratch_mouse_draw = 0; +global B32 DEV_updating_indicator = 0; +struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = +{ +{&DEV_telemetry_capture, str8_lit_comp("telemetry_capture")}, +{&DEV_simulate_lag, str8_lit_comp("simulate_lag")}, +{&DEV_draw_ui_text_pos, str8_lit_comp("draw_ui_text_pos")}, +{&DEV_draw_ui_focus_debug, str8_lit_comp("draw_ui_focus_debug")}, +{&DEV_draw_ui_box_heatmap, str8_lit_comp("draw_ui_box_heatmap")}, +{&DEV_eval_compiler_tooltips, str8_lit_comp("eval_compiler_tooltips")}, +{&DEV_eval_watch_key_tooltips, str8_lit_comp("eval_watch_key_tooltips")}, +{&DEV_cmd_context_tooltips, str8_lit_comp("cmd_context_tooltips")}, +{&DEV_scratch_mouse_draw, str8_lit_comp("scratch_mouse_draw")}, +{&DEV_updating_indicator, str8_lit_comp("updating_indicator")}, +}; +String8 df_g_cmd_query_rule_kind_arg_desc_table[] = +{ +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp("[:column]"), +str8_lit_comp("[:line[:column]]"), +str8_lit_comp("
"), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +}; + +DF_IconKind df_g_entity_kind_icon_kind_table[] = +{ +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Machine, +DF_IconKind_FileOutline, +DF_IconKind_FileOutline, +DF_IconKind_FileOutline, +DF_IconKind_FileOutline, +DF_IconKind_Null, +DF_IconKind_Pin, +DF_IconKind_CircleFilled, +DF_IconKind_CircleFilled, +DF_IconKind_Target, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Threads, +DF_IconKind_Thread, +DF_IconKind_Module, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +}; + +String8 df_g_entity_kind_display_string_table[] = +{ +str8_lit_comp("Nil"), +str8_lit_comp("Root"), +str8_lit_comp("Machine"), +str8_lit_comp("File"), +str8_lit_comp("Override File Link"), +str8_lit_comp("Pending File Change"), +str8_lit_comp("Diagnostics Log"), +str8_lit_comp("Flash Marker"), +str8_lit_comp("Watch Pin"), +str8_lit_comp("Breakpoint"), +str8_lit_comp("Condition"), +str8_lit_comp("Target"), +str8_lit_comp("Executable"), +str8_lit_comp("Arguments"), +str8_lit_comp("Execution Path"), +str8_lit_comp("Entry Point Name"), +str8_lit_comp("Source"), +str8_lit_comp("Destination"), +str8_lit_comp("Control Request"), +str8_lit_comp("Process"), +str8_lit_comp("Thread"), +str8_lit_comp("Module"), +str8_lit_comp("Debug Info Override"), +str8_lit_comp("Conversion Task"), +str8_lit_comp("Conversion Failure"), +str8_lit_comp("EndedProcess"), +}; + +String8 df_g_entity_kind_name_label_table[] = +{ +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Expression"), +str8_lit_comp("Label"), +str8_lit_comp("Expression"), +str8_lit_comp("Label"), +str8_lit_comp("Executable"), +str8_lit_comp("Arguments"), +str8_lit_comp("Execution Path"), +str8_lit_comp("Symbol Name"), +str8_lit_comp("Path"), +str8_lit_comp("Path"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +}; + +DF_EntityKindFlags df_g_entity_kind_flags_table[] = +{ +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(1*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 1*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 1*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 1*DF_EntityKindFlag_TreeMutationSoftHalt | 1*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +}; + +DF_EntityOpFlags df_g_entity_kind_op_flags_table[] = +{ +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (1*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (1*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +}; + +String8 df_g_cfg_src_string_table[] = +{ +str8_lit_comp("user"), +str8_lit_comp("profile"), +str8_lit_comp("command_line"), +}; + +DF_CoreCmdKind df_g_cfg_src_load_cmd_kind_table[] = +{ +DF_CoreCmdKind_LoadUser, +DF_CoreCmdKind_LoadProfile, +DF_CoreCmdKind_Null, +}; + +DF_CoreCmdKind df_g_cfg_src_write_cmd_kind_table[] = +{ +DF_CoreCmdKind_WriteUserData, +DF_CoreCmdKind_WriteProfileData, +DF_CoreCmdKind_Null, +}; + +DF_CoreCmdKind df_g_cfg_src_apply_cmd_kind_table[] = +{ +DF_CoreCmdKind_ApplyUserData, +DF_CoreCmdKind_ApplyProfileData, +DF_CoreCmdKind_Null, +}; + +String8 df_g_icon_kind_text_table[] = +{ +str8_lit_comp(""), +str8_lit_comp("b"), +str8_lit_comp("c"), +str8_lit_comp("B"), +str8_lit_comp("C"), +str8_lit_comp("f"), +str8_lit_comp("F"), +str8_lit_comp("g"), +str8_lit_comp("h"), +str8_lit_comp("r"), +str8_lit_comp("s"), +str8_lit_comp("i"), +str8_lit_comp("w"), +str8_lit_comp("W"), +str8_lit_comp("k"), +str8_lit_comp("K"), +str8_lit_comp("L"), +str8_lit_comp("R"), +str8_lit_comp("U"), +str8_lit_comp("D"), +str8_lit_comp("G"), +str8_lit_comp("P"), +str8_lit_comp("3"), +str8_lit_comp("p"), +str8_lit_comp("O"), +str8_lit_comp("o"), +str8_lit_comp("!"), +str8_lit_comp("1"), +str8_lit_comp("<"), +str8_lit_comp(">"), +str8_lit_comp("^"), +str8_lit_comp("v"), +str8_lit_comp("9"), +str8_lit_comp("0"), +str8_lit_comp("7"), +str8_lit_comp("8"), +str8_lit_comp("+"), +str8_lit_comp("-"), +str8_lit_comp("'"), +str8_lit_comp("\""), +str8_lit_comp("M"), +str8_lit_comp("."), +str8_lit_comp("x"), +str8_lit_comp("q"), +str8_lit_comp("j"), +str8_lit_comp("u"), +str8_lit_comp("m"), +str8_lit_comp("n"), +str8_lit_comp("l"), +str8_lit_comp("a"), +str8_lit_comp("z"), +str8_lit_comp("y"), +str8_lit_comp("X"), +str8_lit_comp("Y"), +str8_lit_comp("S"), +str8_lit_comp("T"), +str8_lit_comp("Z"), +str8_lit_comp("d"), +str8_lit_comp("N"), +str8_lit_comp("E"), +str8_lit_comp("H"), +str8_lit_comp("e"), +str8_lit_comp("I"), +str8_lit_comp("J"), +str8_lit_comp("A"), +str8_lit_comp("?"), +str8_lit_comp("4"), +str8_lit_comp("5"), +str8_lit_comp("c"), +}; + + +#endif // DF_CORE_META_H diff --git a/src/df/df_inc.c b/src/df/df_inc.c new file mode 100644 index 00000000..21d36dcc --- /dev/null +++ b/src/df/df_inc.c @@ -0,0 +1,7 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "df/core/df_core.c" +#include "df/gfx/df_gfx.c" +#include "df/gfx/df_views.c" +#include "df/gfx/df_view_rule_hooks.c" diff --git a/src/df/df_inc.h b/src/df/df_inc.h new file mode 100644 index 00000000..9a5ce481 --- /dev/null +++ b/src/df/df_inc.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEBUG_FRONTEND_INC_H +#define DEBUG_FRONTEND_INC_H + +#include "df/core/df_core.h" +#include "df/gfx/df_gfx.h" +#include "df/gfx/df_views.h" +#include "df/gfx/df_view_rule_hooks.h" + +#endif // DEBUG_FRONTEND_INC_H diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c new file mode 100644 index 00000000..961cc1a7 --- /dev/null +++ b/src/df/gfx/df_gfx.c @@ -0,0 +1,11760 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#undef RADDBG_LAYER_COLOR +#define RADDBG_LAYER_COLOR 0.10f, 0.20f, 0.25f + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/df_gfx.meta.c" + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal DF_PathQuery +df_path_query_from_string(String8 string) +{ + String8 dir_str_in_input = {0}; + for(U64 i = 0; i < string.size; i += 1) + { + String8 substr1 = str8_substr(string, r1u64(i, i+1)); + String8 substr2 = str8_substr(string, r1u64(i, i+2)); + String8 substr3 = str8_substr(string, r1u64(i, i+3)); + if(str8_match(substr1, str8_lit("/"), StringMatchFlag_SlashInsensitive)) + { + dir_str_in_input = str8_substr(string, r1u64(i, string.size)); + } + else if(i != 0 && str8_match(substr2, str8_lit(":/"), StringMatchFlag_SlashInsensitive)) + { + dir_str_in_input = str8_substr(string, r1u64(i-1, string.size)); + } + else if(str8_match(substr2, str8_lit("./"), StringMatchFlag_SlashInsensitive)) + { + dir_str_in_input = str8_substr(string, r1u64(i, string.size)); + } + else if(str8_match(substr3, str8_lit("../"), StringMatchFlag_SlashInsensitive)) + { + dir_str_in_input = str8_substr(string, r1u64(i, string.size)); + } + if(dir_str_in_input.size != 0) + { + break; + } + } + + DF_PathQuery path_query = {0}; + if(dir_str_in_input.size != 0) + { + String8 dir = dir_str_in_input; + String8 search = {0}; + U64 one_past_last_slash = dir.size; + for(U64 i = 0; i < dir_str_in_input.size; i += 1) + { + if(dir_str_in_input.str[i] == '/' || dir_str_in_input.str[i] == '\\') + { + one_past_last_slash = i+1; + } + } + dir.size = one_past_last_slash; + search = str8_substr(dir_str_in_input, r1u64(one_past_last_slash, dir_str_in_input.size)); + path_query.path = dir; + path_query.search = search; + path_query.prefix = str8_substr(string, r1u64(0, path_query.path.str - string.str)); + } + return path_query; +} + +internal DF_FuzzyMatchRangeList +df_fuzzy_match_find(Arena *arena, String8List needles, String8 haystack) +{ + DF_FuzzyMatchRangeList result = {0}; + for(String8Node *needle_n = needles.first; needle_n != 0; needle_n = needle_n->next) + { + U64 find_pos = 0; + for(;find_pos < haystack.size;) + { + find_pos = str8_find_needle(haystack, find_pos, needle_n->string, StringMatchFlag_CaseInsensitive); + B32 is_in_gathered_ranges = 0; + for(DF_FuzzyMatchRangeNode *n = result.first; n != 0; n = n->next) + { + if(n->range.min <= find_pos && find_pos < n->range.max) + { + is_in_gathered_ranges = 1; + find_pos = n->range.max; + break; + } + } + if(!is_in_gathered_ranges) + { + break; + } + } + if(find_pos < haystack.size) + { + Rng1U64 range = r1u64(find_pos, find_pos+needle_n->string.size); + DF_FuzzyMatchRangeNode *n = push_array(arena, DF_FuzzyMatchRangeNode, 1); + n->range = range; + SLLQueuePush(result.first, result.last, n); + result.count += 1; + } + } + return result; +} + +//////////////////////////////// +//~ rjf: View Type Functions + +internal B32 +df_view_is_nil(DF_View *view) +{ + return (view == 0 || view == &df_g_nil_view); +} + +internal DF_Handle +df_handle_from_view(DF_View *view) +{ + DF_Handle handle = df_handle_zero(); + if(!df_view_is_nil(view)) + { + handle.u64[0] = (U64)view; + handle.u64[1] = view->generation; + } + return handle; +} + +internal DF_View * +df_view_from_handle(DF_Handle handle) +{ + DF_View *result = (DF_View *)handle.u64[0]; + if(df_view_is_nil(result) || result->generation != handle.u64[1]) + { + result = &df_g_nil_view; + } + return result; +} + +internal DF_View * +df_view_caller_root_from_view(DF_View *view) +{ + DF_View *result = &df_g_nil_view; + for(DF_View *v = view; !df_view_is_nil(v); v = v->caller_view) + { + result = v; + } + return result; +} + +//////////////////////////////// +//~ rjf: Panel Type Functions + +//- rjf: basic type functions + +internal B32 +df_panel_is_nil(DF_Panel *panel) +{ + return panel == 0 || panel == &df_g_nil_panel; +} + +internal DF_Handle +df_handle_from_panel(DF_Panel *panel) +{ + DF_Handle h = {0}; + h.u64[0] = (U64)panel; + h.u64[1] = panel->generation; + return h; +} + +internal DF_Panel * +df_panel_from_handle(DF_Handle handle) +{ + DF_Panel *panel = (DF_Panel *)handle.u64[0]; + if(panel == 0 || panel->generation != handle.u64[1]) + { + panel = &df_g_nil_panel; + } + return panel; +} + +internal UI_Key +df_ui_key_from_panel(DF_Panel *panel) +{ + UI_Key panel_key = ui_key_from_stringf(ui_key_zero(), "panel_window_%p", panel); + return panel_key; +} + +//- rjf: panel tree mutation notification + +internal void +df_panel_notify_mutation(DF_Window *window, DF_Panel *panel) +{ + DF_CmdParams p = df_cmd_params_from_panel(window, panel); + DF_CfgSrc src = window->cfg_src; + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_write_cmd_kind_table[src])); +} + +//- rjf: tree construction + +internal void +df_panel_insert(DF_Panel *parent, DF_Panel *prev_child, DF_Panel *new_child) +{ + DLLInsert_NPZ(&df_g_nil_panel, parent->first, parent->last, prev_child, new_child, next, prev); + parent->child_count += 1; + new_child->parent = parent; +} + +internal void +df_panel_remove(DF_Panel *parent, DF_Panel *child) +{ + DLLRemove_NPZ(&df_g_nil_panel, parent->first, parent->last, child, next, prev); + child->next = child->prev = child->parent = &df_g_nil_panel; + parent->child_count -= 1; +} + +//- rjf: tree walk + +internal DF_PanelRec +df_panel_rec_df(DF_Panel *panel, U64 sib_off, U64 child_off) +{ + DF_PanelRec rec = {0}; + if(!df_panel_is_nil(*MemberFromOffset(DF_Panel **, panel, child_off))) + { + rec.next = *MemberFromOffset(DF_Panel **, panel, child_off); + rec.push_count = 1; + } + else if(!df_panel_is_nil(*MemberFromOffset(DF_Panel **, panel, sib_off))) + { + rec.next = *MemberFromOffset(DF_Panel **, panel, sib_off); + } + else + { + DF_Panel *uncle = &df_g_nil_panel; + for(DF_Panel *p = panel->parent; !df_panel_is_nil(p); p = p->parent) + { + rec.pop_count += 1; + if(!df_panel_is_nil(*MemberFromOffset(DF_Panel **, p, sib_off))) + { + uncle = *MemberFromOffset(DF_Panel **, p, sib_off); + break; + } + } + rec.next = uncle; + } + return rec; +} + +//- rjf: panel -> rect calculations + +internal Rng2F32 +df_rect_from_panel_child(Rng2F32 parent_rect, DF_Panel *parent, DF_Panel *panel) +{ + Rng2F32 rect = parent_rect; + if(!df_panel_is_nil(parent)) + { + Vec2F32 parent_rect_size = dim_2f32(parent_rect); + Axis2 axis = parent->split_axis; + rect.p1.v[axis] = rect.p0.v[axis]; + for(DF_Panel *child = parent->first; !df_panel_is_nil(child); child = child->next) + { + rect.p1.v[axis] += parent_rect_size.v[axis] * child->size_pct_of_parent.v[axis]; + rect.p1.v[axis2_flip(axis)] = rect.p0.v[axis2_flip(axis)] + parent_rect_size.v[axis2_flip(axis)] * child->size_pct_of_parent.v[axis2_flip(axis)]; + if(child == panel) + { + break; + } + rect.p0.v[axis] = rect.p1.v[axis]; + } + rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis]; + rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)]; + } + rect.x0 = roundf(rect.x0); + rect.x1 = roundf(rect.x1); + rect.y0 = roundf(rect.y0); + rect.y1 = roundf(rect.y1); + return rect; +} + +internal Rng2F32 +df_rect_from_panel(Rng2F32 root_rect, DF_Panel *root, DF_Panel *panel) +{ + Temp scratch = scratch_begin(0, 0); + + // rjf: count ancestors + U64 ancestor_count = 0; + for(DF_Panel *p = panel->parent; !df_panel_is_nil(p); p = p->parent) + { + ancestor_count += 1; + } + + // rjf: gather ancestors + DF_Panel **ancestors = push_array(scratch.arena, DF_Panel *, ancestor_count); + { + U64 ancestor_idx = 0; + for(DF_Panel *p = panel->parent; !df_panel_is_nil(p); p = p->parent) + { + ancestors[ancestor_idx] = p; + ancestor_idx += 1; + } + } + + // rjf: go from highest ancestor => panel and calculate rect + Rng2F32 parent_rect = root_rect; + for(S64 ancestor_idx = (S64)ancestor_count-1; + 0 <= ancestor_idx && ancestor_idx < ancestor_count; + ancestor_idx -= 1) + { + DF_Panel *ancestor = ancestors[ancestor_idx]; + DF_Panel *parent = ancestor->parent; + if(!df_panel_is_nil(parent)) + { + parent_rect = df_rect_from_panel_child(parent_rect, parent, ancestor); + } + } + + // rjf: calculate final rect + Rng2F32 rect = df_rect_from_panel_child(parent_rect, panel->parent, panel); + + scratch_end(scratch); + return rect; +} + +//- rjf: view ownership insertion/removal + +internal void +df_panel_history_new_branch(DF_Panel *panel) +{ + if(panel->history_tab_bar_mode) + { + for(DF_View *v = panel->selected_stable_view->next, *next = 0; !df_view_is_nil(v); v = next) + { + next = v->next; + df_panel_remove_stable_view(panel, v); + df_view_release(v); + } + } +} + +internal void +df_panel_insert_stable_view(DF_Panel *panel, DF_View *prev_view, DF_View *view) +{ + DLLInsert_NPZ(&df_g_nil_view, panel->first_stable_view, panel->last_stable_view, prev_view, view, next, prev); + panel->stable_view_count += 1; + panel->selected_stable_view = view; +} + +internal void +df_panel_remove_stable_view(DF_Panel *panel, DF_View *view) +{ + DLLRemove_NPZ(&df_g_nil_view, panel->first_stable_view, panel->last_stable_view, view, next, prev); + if(panel->selected_stable_view == view) + { + panel->selected_stable_view = !df_view_is_nil(view->prev) ? view->prev : view->next; + } + panel->stable_view_count -= 1; +} + +internal DF_View * +df_selected_view_stack_from_panel(DF_Panel *panel) +{ + DF_View *view = panel->query_view_stack_top; + if(df_view_is_nil(view)) + { + view = panel->selected_stable_view; + } + return view; +} + +internal DF_View * +df_selected_view_from_panel(DF_Panel *panel) +{ + DF_View *view = df_selected_view_stack_from_panel(panel); + for(DF_View *v = view; !df_view_is_nil(v); v = v->callee_view) + { + view = v; + } + return view; +} + +internal DF_View * +df_query_view_from_panel(DF_Panel *panel) +{ + DF_View *query_view = &df_g_nil_view; + { + if(!df_view_is_nil(panel->query_view_stack_top)) + { + query_view = panel->query_view_stack_top; + for(DF_View *v = query_view; !df_view_is_nil(v); v = v->callee_view) + { + query_view = v; + } + } + else if(!df_view_is_nil(panel->selected_stable_view)) + { + for(DF_View *v = panel->selected_stable_view->callee_view; !df_view_is_nil(v); v = v->callee_view) + { + query_view = v; + } + if(!df_view_is_nil(query_view) && query_view->cmd_spec->info.query_rule == DF_CmdQueryRule_Null) + { + query_view = &df_g_nil_view; + } + } + } + return query_view; +} + +//- rjf: icons & display strings + +internal String8 +df_display_string_from_view(Arena *arena, DF_CtrlCtx ctrl_ctx, DF_View *view) +{ + String8 result = {0}; + { + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd_spec); + DF_NameKind name_kind = view_spec->info.name_kind; + switch(name_kind) + { + default: + case DF_NameKind_Null: + { + result = view_spec->info.display_string; + }break; + case DF_NameKind_EntityName: + { + Temp scratch = scratch_begin(&arena, 1); + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + String8 display_string = df_display_string_from_entity(scratch.arena, entity); + if(display_string.size != 0) + { + result = push_str8_copy(arena, display_string); + } + else if(df_entity_is_nil(entity)) + { + result = str8_lit("Invalid"); + } + else + { + String8 kind_string = df_g_entity_kind_display_string_table[entity->kind]; + result = push_str8f(arena, "Untitled %S", kind_string); + } + scratch_end(scratch); + }break; + } + } + return result; +} + +internal DF_IconKind +df_icon_kind_from_view(DF_View *view) +{ + DF_IconKind result = DF_IconKind_Null; + DF_CmdSpec *spec = view->cmd_spec; + result = spec->info.canonical_icon_kind; + return result; +} + +//////////////////////////////// +//~ rjf: Window Type Functions + +internal DF_Handle +df_handle_from_window(DF_Window *window) +{ + DF_Handle handle = {0}; + if(window != 0) + { + handle.u64[0] = (U64)window; + handle.u64[1] = window->gen; + } + return handle; +} + +internal DF_Window * +df_window_from_handle(DF_Handle handle) +{ + DF_Window *window = (DF_Window *)handle.u64[0]; + if(window != 0 && window->gen != handle.u64[1]) + { + window = 0; + } + return window; +} + +//////////////////////////////// +//~ rjf: Control Context + +internal DF_CtrlCtx +df_ctrl_ctx_from_window(DF_Window *ws) +{ + DF_CtrlCtx ctx = df_ctrl_ctx(); + df_ctrl_ctx_apply_overrides(&ctx, &ws->ctrl_ctx_overrides); + return ctx; +} + +internal DF_CtrlCtx +df_ctrl_ctx_from_view(DF_Window *ws, DF_View *view) +{ + DF_CtrlCtx ctx = df_ctrl_ctx_from_window(ws); + df_ctrl_ctx_apply_overrides(&ctx, &view->ctrl_ctx_overrides); + return ctx; +} + +//////////////////////////////// +//~ rjf: Command Parameters From Context + +internal DF_CmdParams +df_cmd_params_from_gfx(void) +{ + DF_CmdParams p = df_cmd_params_zero(); + DF_Window *window = 0; + for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) + { + if(os_window_is_focused(w->os)) + { + window = w; + break; + } + } + if(window != 0) + { + p.window = df_handle_from_window(window); + p.panel = df_handle_from_panel(window->focused_panel); + p.view = df_handle_from_view(window->focused_panel->selected_stable_view); + } + return p; +} + +internal B32 +df_prefer_dasm_from_window(DF_Window *window) +{ + DF_Panel *panel = window->focused_panel; + DF_View *view = panel->selected_stable_view; + DF_CoreCmdKind view_cmd_kind = df_core_cmd_kind_from_string(view->cmd_spec->info.string); + B32 result = 0; + if(view_cmd_kind == DF_CoreCmdKind_Disassembly) + { + result = 1; + } + else if(view_cmd_kind == DF_CoreCmdKind_Code) + { + result = 0; + } + else + { + B32 has_src = 0; + B32 has_dasm = 0; + for(DF_Panel *p = window->root_panel; !df_panel_is_nil(p); p = df_panel_rec_df_pre(p).next) + { + DF_View *p_view = p->selected_stable_view; + DF_CoreCmdKind p_view_cmd_kind = df_core_cmd_kind_from_string(p_view->cmd_spec->info.string); + if(p_view_cmd_kind == DF_CoreCmdKind_Code) + { + has_src= 1; + } + if(p_view_cmd_kind == DF_CoreCmdKind_Disassembly) + { + has_dasm = 1; + } + } + if(has_src && !has_dasm) {result = 0;} + if(has_dasm && !has_src) {result = 1;} + } + return result; +} + +internal DF_CmdParams +df_cmd_params_from_window(DF_Window *window) +{ + DF_CmdParams p = df_cmd_params_zero(); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(window, window->focused_panel->selected_stable_view); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Window); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_View); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_PreferDisassembly); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Index); + p.window = df_handle_from_window(window); + p.panel = df_handle_from_panel(window->focused_panel); + p.view = df_handle_from_view(window->focused_panel->selected_stable_view); + p.prefer_dasm = df_prefer_dasm_from_window(window); + p.entity = ctrl_ctx.thread; + p.index = ctrl_ctx.unwind_count; + return p; +} + +internal DF_CmdParams +df_cmd_params_from_panel(DF_Window *window, DF_Panel *panel) +{ + DF_CmdParams p = df_cmd_params_zero(); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(window, panel->selected_stable_view); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Window); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_View); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_PreferDisassembly); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Index); + p.window = df_handle_from_window(window); + p.panel = df_handle_from_panel(panel); + p.view = df_handle_from_view(panel->selected_stable_view); + p.prefer_dasm = df_prefer_dasm_from_window(window); + p.entity = ctrl_ctx.thread; + p.index = ctrl_ctx.unwind_count; + return p; +} + +internal DF_CmdParams +df_cmd_params_from_view(DF_Window *window, DF_Panel *panel, DF_View *view) +{ + DF_CmdParams p = df_cmd_params_zero(); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(window, view); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Window); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_View); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_PreferDisassembly); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Index); + p.window = df_handle_from_window(window); + p.panel = df_handle_from_panel(panel); + p.view = df_handle_from_view(view); + p.prefer_dasm = df_prefer_dasm_from_window(window); + p.entity = ctrl_ctx.thread; + p.index = ctrl_ctx.unwind_count; + return p; +} + +//////////////////////////////// +//~ rjf: Global Cross-Window UI Interaction State Functions + +internal B32 +df_drag_is_active(void) +{ + return ((df_gfx_state->drag_drop_state == DF_DragDropState_Dragging) || + (df_gfx_state->drag_drop_state == DF_DragDropState_Dropping)); +} + +internal void +df_drag_begin(DF_DragDropPayload *payload) +{ + if(!df_drag_is_active()) + { + df_gfx_state->drag_drop_state = DF_DragDropState_Dragging; + MemoryCopyStruct(&df_g_drag_drop_payload, payload); + } +} + +internal B32 +df_drag_drop(DF_DragDropPayload *out_payload) +{ + B32 result = 0; + if(df_gfx_state->drag_drop_state == DF_DragDropState_Dropping) + { + result = 1; + df_gfx_state->drag_drop_state = DF_DragDropState_Null; + MemoryCopyStruct(out_payload, &df_g_drag_drop_payload); + MemoryZeroStruct(&df_g_drag_drop_payload); + } + return result; +} + +internal void +df_drag_kill(void) +{ + df_gfx_state->drag_drop_state = DF_DragDropState_Null; + MemoryZeroStruct(&df_g_drag_drop_payload); +} + +internal void +df_queue_drag_drop(void) +{ + df_gfx_state->drag_drop_state = DF_DragDropState_Dropping; +} + +internal void +df_set_hovered_line_info(DF_Entity *binary, U64 voff) +{ + df_gfx_state->hover_line_binary = df_handle_from_entity(binary); + df_gfx_state->hover_line_voff = voff; + df_gfx_state->hover_line_set_this_frame = 1; +} + +internal DF_Entity * +df_get_hovered_line_info_binary(void) +{ + return df_entity_from_handle(df_gfx_state->hover_line_binary); +} + +internal U64 +df_get_hovered_line_info_voff(void) +{ + return df_gfx_state->hover_line_voff; +} + +//////////////////////////////// +//~ rjf: View Spec State Functions + +internal void +df_register_view_specs(DF_ViewSpecInfoArray specs) +{ + for(U64 idx = 0; idx < specs.count; idx += 1) + { + DF_ViewSpecInfo *src_info = &specs.v[idx]; + U64 hash = df_hash_from_string(src_info->name); + U64 slot_idx = hash%df_gfx_state->view_spec_table_size; + DF_ViewSpec *spec = push_array(df_gfx_state->arena, DF_ViewSpec, 1); + SLLStackPush_N(df_gfx_state->view_spec_table[slot_idx], spec, hash_next); + MemoryCopyStruct(&spec->info, src_info); + spec->info.name = push_str8_copy(df_gfx_state->arena, spec->info.name); + spec->info.display_string = push_str8_copy(df_gfx_state->arena, spec->info.display_string); + } +} + +internal void +df_register_cmd2view(String8 cmd_name, String8 view_name) +{ + U64 hash = df_hash_from_string(cmd_name); + U64 slot_idx = hash%df_gfx_state->cmd2view_slot_count; + DF_String2ViewSlot *slot = &df_gfx_state->cmd2view_slots[slot_idx]; + DF_String2ViewNode *node = push_array(df_gfx_state->arena, DF_String2ViewNode, 1); + node->string = push_str8_copy(df_gfx_state->arena, cmd_name); + node->view_name = push_str8_copy(df_gfx_state->arena, view_name); + SLLQueuePush_N(slot->first, slot->last, node, hash_next); +} + +internal DF_ViewSpec * +df_view_spec_from_string(String8 string) +{ + DF_ViewSpec *spec = &df_g_nil_view_spec; + U64 hash = df_hash_from_string(string); + U64 slot_idx = hash%df_gfx_state->view_spec_table_size; + for(DF_ViewSpec *s = df_gfx_state->view_spec_table[slot_idx]; + s != 0; + s = s->hash_next) + { + if(str8_match(s->info.name, string, 0)) + { + spec = s; + break; + } + } + return spec; +} + +internal DF_ViewSpec * +df_view_spec_from_gfx_view_kind(DF_GfxViewKind gfx_view_kind) +{ + DF_ViewSpec *spec = df_view_spec_from_string(df_g_gfx_view_kind_spec_info_table[gfx_view_kind].name); + return spec; +} + +internal DF_ViewSpec * +df_view_spec_from_cmd_spec(DF_CmdSpec *cmd_spec) +{ + DF_ViewSpec *view_spec = &df_g_nil_view_spec; + { + U64 hash = df_hash_from_string(cmd_spec->info.string); + U64 slot_idx = hash%df_gfx_state->cmd2view_slot_count; + DF_String2ViewSlot *slot = &df_gfx_state->cmd2view_slots[slot_idx]; + for(DF_String2ViewNode *n = slot->first; n != 0; n = n->hash_next) + { + if(str8_match(n->string, cmd_spec->info.string, 0)) + { + view_spec = df_view_spec_from_string(n->view_name); + break; + } + } + } + return view_spec; +} + +//////////////////////////////// +//~ rjf: View Rule Spec State Functions + +internal void +df_register_gfx_view_rule_specs(DF_GfxViewRuleSpecInfoArray specs) +{ + for(U64 idx = 0; idx < specs.count; idx += 1) + { + // rjf: extract info from array slot + DF_GfxViewRuleSpecInfo *info = &specs.v[idx]; + + // rjf: skip empties + if(info->string.size == 0) + { + continue; + } + + // rjf: determine hash/slot + U64 hash = df_hash_from_string(info->string); + U64 slot_idx = hash%df_gfx_state->view_rule_spec_table_size; + + // rjf: allocate node & push + DF_GfxViewRuleSpec *spec = push_array(df_gfx_state->arena, DF_GfxViewRuleSpec, 1); + SLLStackPush_N(df_gfx_state->view_rule_spec_table[slot_idx], spec, hash_next); + + // rjf: fill node + DF_GfxViewRuleSpecInfo *info_copy = &spec->info; + MemoryCopyStruct(info_copy, info); + info_copy->string = push_str8_copy(df_gfx_state->arena, info->string); + } +} + +internal DF_GfxViewRuleSpec * +df_gfx_view_rule_spec_from_string(String8 string) +{ + DF_GfxViewRuleSpec *spec = &df_g_nil_gfx_view_rule_spec; + { + U64 hash = df_hash_from_string(string); + U64 slot_idx = hash%df_gfx_state->view_rule_spec_table_size; + for(DF_GfxViewRuleSpec *s = df_gfx_state->view_rule_spec_table[slot_idx]; s != 0; s = s->hash_next) + { + if(str8_match(string, s->info.string, 0)) + { + spec = s; + break; + } + } + } + return spec; +} + +//////////////////////////////// +//~ rjf: View State Functions + +internal DF_View * +df_view_alloc(void) +{ + // rjf: allocate + DF_View *view = df_gfx_state->free_view; + { + if(!df_view_is_nil(view)) + { + df_gfx_state->free_view_count -= 1; + SLLStackPop(df_gfx_state->free_view); + U64 generation = view->generation; + MemoryZeroStruct(view); + view->generation = generation; + } + else + { + view = push_array(df_gfx_state->arena, DF_View, 1); + } + view->generation += 1; + } + + // rjf: initialize + view->arena = arena_alloc(); + view->cmd_spec = &df_g_nil_cmd_spec; + view->cmd_entity = df_handle_zero(); + view->query.str = view->query_buffer; + view->query_cursor = view->query_mark = txt_pt(1, 1); + df_gfx_state->allocated_view_count += 1; + return view; +} + +internal void +df_view_release_single(DF_View *view) +{ + SLLStackPush(df_gfx_state->free_view, view); + for(DF_ArenaExt *ext = view->first_arena_ext; ext != 0; ext = ext->next) + { + arena_release(ext->arena); + } + view->first_arena_ext = view->last_arena_ext = 0; + arena_release(view->arena); + view->generation += 1; + + df_gfx_state->allocated_view_count -= 1; + df_gfx_state->free_view_count += 1; +} + +internal void +df_view_release(DF_View *view) +{ + // rjf: terminate this callee chain from caller + if(!df_view_is_nil(view->caller_view)) + { + view->caller_view->callee_view = &df_g_nil_view; + } + + // rjf: release all callees + for(DF_View *v = view->callee_view, *next = 0; !df_view_is_nil(v); v = next) + { + next = v->callee_view; + df_view_release_single(v); + } + + // rjf: release this view + df_view_release_single(view); +} + +internal void +df_view_equip_command(DF_View *view, DF_CmdSpec *spec, DF_CmdParams *params, String8 default_query, DF_CfgNode *cfg_root) +{ + // rjf: fill arguments buffer + MemoryCopy(view->query_buffer, default_query.str, Min(sizeof(view->query_buffer), default_query.size)); + view->query.str = view->query_buffer; + view->query.size = default_query.size; + view->query_cursor = view->query_mark = txt_pt(1, default_query.size+1); + + // rjf: initialize state for new command spec, if needed + if(view->cmd_spec != spec) + { + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(spec); + df_view_clear_user_state(view); + MemoryZeroStruct(&view->scroll_pos); + view->cmd_spec = spec; + + // rjf: fill extra parameters + MemoryZeroStruct(&view->cmd_entity); + if(!df_entity_is_nil(df_entity_from_handle(params->entity)) && view_spec->info.flags & DF_ViewSpecFlag_ParameterizedByEntity) + { + view->cmd_entity = params->entity; + } + + // rjf: give the view a chance to initialize + DF_ViewSetupFunctionType *view_setup = view_spec->info.setup_hook; + view_setup(view, cfg_root); + } +} + +internal void +df_view_equip_loading_info(DF_View *view, B32 is_loading, U64 progress_v, U64 progress_target) +{ + view->loading_t_target = (F32)!!is_loading; + view->loading_progress_v = progress_v; + view->loading_progress_v_target = progress_target; +} + +internal void +df_view_clear_user_state(DF_View *view) +{ + for(DF_ArenaExt *ext = view->first_arena_ext; ext != 0; ext = ext->next) + { + arena_release(ext->arena); + } + view->first_arena_ext = view->last_arena_ext = 0; + arena_clear(view->arena); + view->user_data = 0; +} + +internal void * +df_view_get_or_push_user_state(DF_View *view, U64 size) +{ + void *result = view->user_data; + if(result == 0) + { + view->user_data = result = push_array(view->arena, U8, size); + } + return result; +} + +internal Arena * +df_view_push_arena_ext(DF_View *view) +{ + DF_ArenaExt *ext = push_array(view->arena, DF_ArenaExt, 1); + ext->arena = arena_alloc(); + SLLQueuePush(view->first_arena_ext, view->last_arena_ext, ext); + return ext->arena; +} + +//////////////////////////////// +//~ rjf: View Rule Instance State Functions + +internal void * +df_view_rule_block_get_or_push_user_state(DF_ExpandKey key, U64 size) +{ + U64 hash = df_hash_from_expand_key(key); + U64 slot_idx = hash%df_gfx_state->view_rule_block_slots_count; + DF_ViewRuleBlockSlot *slot = &df_gfx_state->view_rule_block_slots[slot_idx]; + DF_ViewRuleBlockNode *node = 0; + for(DF_ViewRuleBlockNode *n = slot->first; n != 0; n = n->next) + { + if(df_expand_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = df_gfx_state->free_view_rule_block_node; + if(node != 0) + { + SLLStackPop(df_gfx_state->free_view_rule_block_node); + } + else + { + node = push_array(df_gfx_state->arena, DF_ViewRuleBlockNode, 1); + } + node->key = key; + node->user_state_arena = arena_alloc(); + SLLQueuePush(slot->first, slot->last, node); + } + void *user_state = node->user_state; + if(user_state == 0 || node->user_state_size != size) + { + arena_clear(node->user_state_arena); + user_state = node->user_state = push_array(node->user_state_arena, U8, size); + node->user_state_size = size; + } + return user_state; +} + +internal Arena * +df_view_rule_block_push_arena_ext(DF_ExpandKey key) +{ + // TODO(rjf) + return 0; +} + +//////////////////////////////// +//~ rjf: Panel State Functions + +internal DF_Panel * +df_panel_alloc(DF_Window *ws) +{ + DF_Panel *panel = ws->free_panel; + if(!df_panel_is_nil(panel)) + { + SLLStackPop(ws->free_panel); + U64 generation = panel->generation; + MemoryZeroStruct(panel); + panel->generation = generation; + } + else + { + panel = push_array(ws->arena, DF_Panel, 1); + } + panel->first = panel->last = panel->next = panel->prev = panel->parent = &df_g_nil_panel; + panel->generation += 1; + panel->query_view_stack_top = panel->first_stable_view = panel->last_stable_view = panel->selected_stable_view = &df_g_nil_view; + return panel; +} + +internal void +df_panel_release(DF_Window *ws, DF_Panel *panel) +{ + df_panel_release_all_views(panel); + SLLStackPush(ws->free_panel, panel); + panel->generation += 1; +} + +internal void +df_panel_release_all_views(DF_Panel *panel) +{ + if(!df_view_is_nil(panel->query_view_stack_top)) + { + df_view_release(panel->query_view_stack_top); + } + for(DF_View *view = panel->first_stable_view, *next = 0; !df_view_is_nil(view); view = next) + { + next = view->next; + df_view_release(view); + } + panel->first_stable_view = panel->last_stable_view = panel->query_view_stack_top = panel->selected_stable_view = &df_g_nil_view; +} + +//////////////////////////////// +//~ rjf: Window State Functions + +internal DF_Window * +df_window_open(Vec2F32 size, OS_Handle preferred_monitor, DF_CfgSrc cfg_src) +{ + DF_Window *window = df_gfx_state->free_window; + if(window != 0) + { + SLLStackPop(df_gfx_state->free_window); + U64 gen = window->gen; + MemoryZeroStruct(window); + window->gen = gen; + } + else + { + window = push_array(df_gfx_state->arena, DF_Window, 1); + } + window->gen += 1; + window->cfg_src = cfg_src; + window->arena = arena_alloc(); + { + String8 title = str8_lit_comp("The RAD Debugger (ALPHA) - " __DATE__); + window->os = os_window_open(size, title); + } + window->r = r_window_equip(window->os); + window->ui = ui_state_alloc(); + window->view_state_hist = df_state_delta_history_alloc(); + window->drop_completion_ctx_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_drop_complete_ctx_menu_")); + window->entity_ctx_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_entity_ctx_menu_")); + window->tab_ctx_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_tab_ctx_menu_")); + window->hover_eval_arena = arena_alloc(); + window->free_panel = &df_g_nil_panel; + window->root_panel = df_panel_alloc(window); + window->focused_panel = window->root_panel; + if(df_gfx_state->first_window == 0) + { + DF_FontSlot english_font_slots[] = {DF_FontSlot_Main, DF_FontSlot_Code}; + DF_FontSlot icon_font_slot = DF_FontSlot_Icons; + for(U64 idx = 0; idx < ArrayCount(english_font_slots); idx += 1) + { + Temp scratch = scratch_begin(0, 0); + DF_FontSlot slot = english_font_slots[idx]; + f_push_run_from_string(scratch.arena, + df_font_from_slot(slot), + df_font_size_from_slot(window, slot), + 0, + str8_lit("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890~!@#$%^&*()-_+=[{]}\\|;:'\",<.>/?")); + scratch_end(scratch); + } + for(DF_IconKind icon_kind = DF_IconKind_Null; icon_kind < DF_IconKind_COUNT; icon_kind = (DF_IconKind)(icon_kind+1)) + { + Temp scratch = scratch_begin(0, 0); + f_push_run_from_string(scratch.arena, + df_font_from_slot(icon_font_slot), + df_font_size_from_slot(window, icon_font_slot), + 0, + df_g_icon_kind_text_table[icon_kind]); + scratch_end(scratch); + } + } + OS_Handle zero_monitor = {0}; + if(!os_handle_match(zero_monitor, preferred_monitor)) + { + os_window_set_monitor(window->os, preferred_monitor); + } + os_window_equip_repaint(window->os, df_gfx_state->repaint_hook, window); + DLLPushBack(df_gfx_state->first_window, df_gfx_state->last_window, window); + return window; +} + +internal DF_Window * +df_window_from_os_handle(OS_Handle os) +{ + DF_Window *result = 0; + for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) + { + if(os_handle_match(w->os, os)) + { + result = w; + break; + } + } + return result; +} + +internal void +df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, DF_CmdList *cmds) +{ + ProfBeginFunction(); + B32 window_is_focused = os_window_is_focused(ws->os); + B32 hover_eval_is_open = (ws->hover_eval_string.size != 0 && ws->hover_eval_first_frame_idx+20 < ws->hover_eval_last_frame_idx && df_frame_index()-ws->hover_eval_last_frame_idx < 20); + B32 any_query_is_focused = !df_panel_is_nil(ws->focused_panel) && !df_view_is_nil(df_query_view_from_panel(ws->focused_panel)); + if(!window_is_focused) + { + ws->menu_bar_key_held = 0; + } + ui_select_state(ws->ui); + + //- rjf: auto-close tabs which have parameter entities that've been deleted + for(DF_Panel *panel = ws->root_panel; + !df_panel_is_nil(panel); + panel = df_panel_rec_df_pre(panel).next) + { + for(DF_View *view = panel->first_stable_view; + !df_view_is_nil(view); + view = view->next) + { + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + if(entity->flags & DF_EntityFlag_MarkedForDeletion || (df_entity_is_nil(entity) && !df_handle_match(df_handle_zero(), view->cmd_entity))) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseTab)); + } + } + } + + //- rjf: in empty views, typing should automatically pull up command lister + if(window_is_focused && + !df_panel_is_nil(ws->focused_panel) && + df_view_is_nil(ws->focused_panel->query_view_stack_top) && + df_view_is_nil(ws->focused_panel->selected_stable_view) && + !ui_any_ctx_menu_is_open()) + { + for(OS_Event *event = events->first; + event != 0; + event = event->next) + { + if(!os_handle_match(event->window, ws->os) || event->kind != OS_EventKind_Text) + { + continue; + } + DF_CmdParams params = df_cmd_params_from_window(ws); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Commands); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + break; + } + } + + //- rjf: do core-layer commands & batch up commands to be dispatched to views + UI_NavActionList nav_actions = {0}; + ProfScope("do commands") + { + Temp scratch = scratch_begin(&arena, 1); + for(DF_CmdNode *cmd_node = cmds->first; + cmd_node != 0; + cmd_node = cmd_node->next) + { + temp_end(scratch); + + // rjf: get command info + DF_Cmd *cmd = &cmd_node->cmd; + DF_CmdParams params = cmd->params; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched window => skip + if(df_window_from_handle(params.window) != ws) + { + continue; + } + + // rjf: set up data for cases + Axis2 split_axis = Axis2_X; + U64 panel_sib_off = 0; + U64 panel_child_off = 0; + Vec2S32 panel_change_dir = {0}; + + // rjf: dispatch by core command kind + switch(core_cmd_kind) + { + //- rjf: default path + default: + { + // rjf: stable view commits + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd->spec); + if(view_spec != &df_g_nil_view_spec && + cmd->spec->info.query_rule == DF_CmdQueryRule_Null) + { + DF_Panel *panel = df_panel_from_handle(params.panel); + DF_View *view = df_view_alloc(); + df_view_equip_command(view, cmd->spec, ¶ms, str8_lit(""), &df_g_nil_cfg_node); + df_panel_history_new_branch(panel); + df_panel_insert_stable_view(panel, panel->last_stable_view, view); + df_panel_notify_mutation(ws, panel); + } + }break; + + //- rjf: command fast path + case DF_CoreCmdKind_CommandFastPath: + { + DF_CmdSpec *spec = params.cmd_spec; + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd->spec); + DF_Panel *panel = df_panel_from_handle(params.panel); + if(view_spec != &df_g_nil_view_spec || + spec->info.query_rule != DF_CmdQueryRule_Null) + { + df_cmd_spec_counter_inc(spec); + + //- rjf: extract info from spec + DF_CmdQueryRule query_rule = spec->info.query_rule; + B32 applies_to_view = !!(spec->info.flags & DF_CmdSpecFlag_AppliesToView); + B32 fill_with_input = !!(spec->info.flags & DF_CmdSpecFlag_QueryUsesOldInput); + + //- rjf: grab active input from panel + B32 active_input_valid = 0; + String8 active_input = {0}; + { + DF_View *view = df_selected_view_from_panel(panel); + if(!df_view_is_nil(view) && view->cmd_spec->info.query_rule != DF_CmdQueryRule_Null) + { + active_input = view->query; + active_input_valid = 1; + } + } + + //- rjf: get view for this command + DF_View *view = &df_g_nil_view; + if(query_rule != DF_CmdQueryRule_Null) + { + DF_View *selected_view = df_view_is_nil(panel->query_view_stack_top) ? panel->selected_stable_view : panel->query_view_stack_top; + + // rjf: applies to view? => push this onto the selected view's call stack + if(applies_to_view && !df_view_is_nil(selected_view)) + { + DF_View *new_view = df_view_alloc(); + selected_view->callee_view = new_view; + new_view->caller_view = selected_view; + view = new_view; + } + + // rjf: does not apply to view => push onto the query stack + if(!applies_to_view) + { + view = df_view_alloc(); + panel->query_view_stack_top = view; + } + } + + //- rjf: map query kind => default input + String8 default_input = {0}; + { + switch(query_rule) + { + default:{}break; + case DF_CmdQueryRule_SearchString: + { + default_input = df_push_search_string(scratch.arena); + }break; + case DF_CmdQueryRule_FilePath: + case DF_CmdQueryRule_FilePathAndTextPoint: + { + String8 current_path = df_current_path(); + String8 fixed_path = push_str8_copy(scratch.arena, current_path); + for(U64 idx = 0; idx < fixed_path.size; idx += 1) + { + fixed_path.str[idx] = char_to_correct_slash(fixed_path.str[idx]); + } + default_input = fixed_path; + }break; + } + } + + //- rjf: override default input with active input, if this view wants to reuse existing inputs + if(fill_with_input && active_input_valid) + { + default_input = active_input; + } + + //- rjf: set up view for this command + if(!df_view_is_nil(view)) + { + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + df_view_equip_command(view, spec, ¶ms, default_input, &df_g_nil_cfg_node); + } + + //- rjf: focus this panel + { + DF_CmdParams p = params; + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + }break; + + //- rjf: notifications + case DF_CoreCmdKind_Error: + { + String8 error_string = params.string; + ws->error_string_size = error_string.size; + MemoryCopy(ws->error_buffer, error_string.str, Min(sizeof(ws->error_buffer), error_string.size)); + ws->error_t = 1; + }break; + + //- rjf: debug control context management operations + case DF_CoreCmdKind_SelectThread:goto thread_locator; + case DF_CoreCmdKind_SelectThreadWindow: + { + ws->ctrl_ctx_overrides.thread = params.entity; + ws->ctrl_ctx_overrides.unwind_count = 0; + }goto thread_locator; + case DF_CoreCmdKind_SelectThreadView: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + DF_View *view = df_view_from_handle(params.view); + if(df_view_is_nil(view) && !df_panel_is_nil(panel)) + { + view = panel->selected_stable_view; + } + if(!df_view_is_nil(view)) + { + view->ctrl_ctx_overrides.thread = params.entity; + view->ctrl_ctx_overrides.unwind_count = 0; + } + }goto thread_locator; + case DF_CoreCmdKind_SelectUnwind: + thread_locator:; + { + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); + }break; + + //- rjf: font sizes + case DF_CoreCmdKind_IncUIFontScale: + { + ws->main_font_size_delta += 1/200.f; + ws->main_font_size_delta = ClampTop(ws->main_font_size_delta, +0.3f); + }break; + case DF_CoreCmdKind_DecUIFontScale: + { + ws->main_font_size_delta -= 1/200.f; + ws->main_font_size_delta = ClampBot(ws->main_font_size_delta, -0.075f); + }break; + case DF_CoreCmdKind_IncCodeFontScale: + { + ws->code_font_size_delta += 1/200.f; + ws->code_font_size_delta = ClampTop(ws->code_font_size_delta, +0.3f); + }break; + case DF_CoreCmdKind_DecCodeFontScale: + { + ws->code_font_size_delta -= 1/200.f; + ws->code_font_size_delta = ClampBot(ws->code_font_size_delta, -0.075f); + }break; + + //- rjf: panel creation + case DF_CoreCmdKind_NewPanelRight: split_axis = Axis2_X; goto split; + case DF_CoreCmdKind_NewPanelDown: split_axis = Axis2_Y; goto split; + split:; + { + DF_Panel *panel = ws->focused_panel; + DF_Panel *parent = panel->parent; + if(!df_panel_is_nil(parent) && parent->split_axis == split_axis) + { + DF_Panel *next = df_panel_alloc(ws); + df_panel_insert(parent, panel, next); + next->size_pct_of_parent_target.v[split_axis] = 1.f / parent->child_count; + next->size_pct_of_parent.v[axis2_flip(split_axis)] = next->size_pct_of_parent_target.v[axis2_flip(split_axis)] = 1.f; + for(DF_Panel *child = parent->first; !df_panel_is_nil(child); child = child->next) + { + if(child != next) + { + child->size_pct_of_parent_target.v[split_axis] *= (F32)(parent->child_count-1) / (parent->child_count); + } + } + ws->focused_panel = next; + } + else + { + DF_Panel *pre_prev = panel->prev; + DF_Panel *pre_parent = parent; + DF_Panel *new_parent = df_panel_alloc(ws); + new_parent->size_pct_of_parent.v[split_axis] = panel->size_pct_of_parent.v[split_axis]; + new_parent->size_pct_of_parent_target.v[split_axis] = panel->size_pct_of_parent_target.v[split_axis]; + new_parent->size_pct_of_parent.v[axis2_flip(split_axis)] = new_parent->size_pct_of_parent_target.v[axis2_flip(split_axis)] = panel->size_pct_of_parent_target.v[axis2_flip(split_axis)]; + if(!df_panel_is_nil(pre_parent)) + { + df_panel_remove(pre_parent, panel); + df_panel_insert(pre_parent, pre_prev, new_parent); + } + else + { + ws->root_panel = new_parent; + } + DF_Panel *left = panel; + DF_Panel *right = df_panel_alloc(ws); + df_panel_insert(new_parent, &df_g_nil_panel, left); + df_panel_insert(new_parent, left, right); + new_parent->split_axis = split_axis; + left->size_pct_of_parent.v[split_axis] = 1.f; + left->size_pct_of_parent_target.v[split_axis] = 0.5f; + right->size_pct_of_parent.v[split_axis] = 0.f; + right->size_pct_of_parent_target.v[split_axis] = 0.5f; + left->size_pct_of_parent.v[axis2_flip(split_axis)] = 1.f; + left->size_pct_of_parent_target.v[axis2_flip(split_axis)] = 1.f; + right->size_pct_of_parent.v[axis2_flip(split_axis)] = 1.f; + right->size_pct_of_parent_target.v[axis2_flip(split_axis)] = 1.f; + ws->focused_panel = right; + } + df_panel_notify_mutation(ws, panel); + }break; + case DF_CoreCmdKind_ResetToDefaultPanels: + { + //- rjf: gather all panels in the panel tree - remove & gather views + // we'd like to keep in the next layout + DF_HandleList panels_to_close = {0}; + DF_HandleList views_to_close = {0}; + DF_View *watch = &df_g_nil_view; + DF_View *locals = &df_g_nil_view; + DF_View *regs = &df_g_nil_view; + DF_View *callstack = &df_g_nil_view; + DF_View *breakpoints = &df_g_nil_view; + DF_View *watch_pins = &df_g_nil_view; + DF_View *output = &df_g_nil_view; + DF_View *targets = &df_g_nil_view; + DF_View *scheduler = &df_g_nil_view; + DF_View *modules = &df_g_nil_view; + DF_View *disasm = &df_g_nil_view; + DF_View *memory = &df_g_nil_view; + DF_HandleList code_views = {0}; + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + DF_Handle handle = df_handle_from_panel(panel); + df_handle_list_push(scratch.arena, &panels_to_close, handle); + for(DF_View *view = panel->first_stable_view, *next = 0; !df_view_is_nil(view); view = next) + { + next = view->next; + DF_CoreCmdKind cmd_kind = df_core_cmd_kind_from_string(view->cmd_spec->info.string); + B32 needs_delete = 1; + switch(cmd_kind) + { + default:{}break; + case DF_CoreCmdKind_Watch: {if(df_view_is_nil(watch)) { needs_delete = 0; watch = view;} }break; + case DF_CoreCmdKind_Locals: {if(df_view_is_nil(locals)) { needs_delete = 0; locals = view;} }break; + case DF_CoreCmdKind_Registers: {if(df_view_is_nil(regs)) { needs_delete = 0; regs = view;} }break; + case DF_CoreCmdKind_CallStack: {if(df_view_is_nil(callstack)) { needs_delete = 0; callstack = view;} }break; + case DF_CoreCmdKind_Breakpoints:{if(df_view_is_nil(breakpoints)) { needs_delete = 0; breakpoints = view;} }break; + case DF_CoreCmdKind_WatchPins: {if(df_view_is_nil(watch_pins)) { needs_delete = 0; watch_pins = view;} }break; + case DF_CoreCmdKind_Output: {if(df_view_is_nil(output)) { needs_delete = 0; output = view;} }break; + case DF_CoreCmdKind_Targets: {if(df_view_is_nil(targets)) { needs_delete = 0; targets = view;} }break; + case DF_CoreCmdKind_Scheduler: {if(df_view_is_nil(scheduler)) { needs_delete = 0; scheduler = view;} }break; + case DF_CoreCmdKind_Modules: {if(df_view_is_nil(modules)) { needs_delete = 0; modules = view;} }break; + case DF_CoreCmdKind_Disassembly:{if(df_view_is_nil(disasm)) { needs_delete = 0; disasm = view;} }break; + case DF_CoreCmdKind_Memory: {if(df_view_is_nil(memory)) { needs_delete = 0; memory = view;} }break; + case DF_CoreCmdKind_Code: + { + needs_delete = 0; + df_handle_list_push(scratch.arena, &code_views, df_handle_from_view(view)); + }break; + } + if(!needs_delete) + { + df_panel_remove_stable_view(panel, view); + } + } + } + + //- rjf: close all panels/views + for(DF_HandleNode *n = panels_to_close.first; n != 0; n = n->next) + { + DF_Panel *panel = df_panel_from_handle(n->handle); + if(panel != ws->root_panel) + { + df_panel_release(ws, panel); + } + else + { + df_panel_release_all_views(panel); + panel->first = panel->last = &df_g_nil_panel; + } + } + + //- rjf: allocate any missing views + DF_CmdParams blank_params = df_cmd_params_from_window(ws); + if(df_view_is_nil(watch)) + { + watch = df_view_alloc(); + df_view_equip_command(watch, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Watch), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(locals)) + { + locals = df_view_alloc(); + df_view_equip_command(locals, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Locals), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(regs)) + { + regs = df_view_alloc(); + df_view_equip_command(regs, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Registers), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(callstack)) + { + callstack = df_view_alloc(); + df_view_equip_command(callstack, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CallStack), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(breakpoints)) + { + breakpoints = df_view_alloc(); + df_view_equip_command(breakpoints, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Breakpoints), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(watch_pins)) + { + watch_pins = df_view_alloc(); + df_view_equip_command(watch_pins, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WatchPins), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(output)) + { + output = df_view_alloc(); + df_view_equip_command(output, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Output), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(targets)) + { + targets = df_view_alloc(); + df_view_equip_command(targets, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Targets), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(scheduler)) + { + scheduler = df_view_alloc(); + df_view_equip_command(scheduler, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Scheduler), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(modules)) + { + modules = df_view_alloc(); + df_view_equip_command(modules, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Modules), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(disasm)) + { + disasm = df_view_alloc(); + df_view_equip_command(disasm, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Disassembly), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(memory)) + { + memory = df_view_alloc(); + df_view_equip_command(memory, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Memory), &blank_params, str8_lit(""), &df_g_nil_cfg_node); + } + + // rjf: root split + ws->root_panel->split_axis = Axis2_X; + DF_Panel *root_0 = df_panel_alloc(ws); + DF_Panel *root_1 = df_panel_alloc(ws); + df_panel_insert(ws->root_panel, ws->root_panel->last, root_0); + df_panel_insert(ws->root_panel, ws->root_panel->last, root_1); + root_0->size_pct_of_parent = root_0->size_pct_of_parent_target = v2f32(0.85f, 1.f); + root_1->size_pct_of_parent = root_1->size_pct_of_parent_target = v2f32(0.15f, 1.f); + + // rjf: root_0 split + root_0->split_axis = Axis2_Y; + DF_Panel *root_0_0 = df_panel_alloc(ws); + DF_Panel *root_0_1 = df_panel_alloc(ws); + df_panel_insert(root_0, root_0->last, root_0_0); + df_panel_insert(root_0, root_0->last, root_0_1); + root_0_0->size_pct_of_parent = root_0_0->size_pct_of_parent_target = v2f32(1.f, 0.80f); + root_0_1->size_pct_of_parent = root_0_1->size_pct_of_parent_target = v2f32(1.f, 0.20f); + + // rjf: root_1 split + root_1->split_axis = Axis2_Y; + DF_Panel *root_1_0 = df_panel_alloc(ws); + DF_Panel *root_1_1 = df_panel_alloc(ws); + df_panel_insert(root_1, root_1->last, root_1_0); + df_panel_insert(root_1, root_1->last, root_1_1); + root_1_0->size_pct_of_parent = root_1_0->size_pct_of_parent_target = v2f32(1.f, 0.50f); + root_1_1->size_pct_of_parent = root_1_1->size_pct_of_parent_target = v2f32(1.f, 0.50f); + df_panel_insert_stable_view(root_1_0, root_1_0->last_stable_view, targets); + df_panel_insert_stable_view(root_1_1, root_1_1->last_stable_view, scheduler); + root_1_0->selected_stable_view = targets; + root_1_1->selected_stable_view = scheduler; + root_1_1->tab_side = Side_Max; + + // rjf: root_0_0 split + root_0_0->split_axis = Axis2_X; + DF_Panel *root_0_0_0 = df_panel_alloc(ws); + DF_Panel *root_0_0_1 = df_panel_alloc(ws); + df_panel_insert(root_0_0, root_0_0->last, root_0_0_0); + df_panel_insert(root_0_0, root_0_0->last, root_0_0_1); + root_0_0_0->size_pct_of_parent = root_0_0_0->size_pct_of_parent_target = v2f32(0.25f, 1.f); + root_0_0_1->size_pct_of_parent = root_0_0_1->size_pct_of_parent_target = v2f32(0.75f, 1.f); + + // rjf: root_0_0_0 split + root_0_0_0->split_axis = Axis2_Y; + DF_Panel *root_0_0_0_0 = df_panel_alloc(ws); + DF_Panel *root_0_0_0_1 = df_panel_alloc(ws); + df_panel_insert(root_0_0_0, root_0_0_0->last, root_0_0_0_0); + df_panel_insert(root_0_0_0, root_0_0_0->last, root_0_0_0_1); + root_0_0_0_0->size_pct_of_parent = root_0_0_0_0->size_pct_of_parent_target = v2f32(1.f, 0.5f); + root_0_0_0_1->size_pct_of_parent = root_0_0_0_1->size_pct_of_parent_target = v2f32(1.f, 0.5f); + df_panel_insert_stable_view(root_0_0_0_0, root_0_0_0_0->last_stable_view, disasm); + root_0_0_0_0->selected_stable_view = disasm; + df_panel_insert_stable_view(root_0_0_0_1, root_0_0_0_1->last_stable_view, breakpoints); + df_panel_insert_stable_view(root_0_0_0_1, root_0_0_0_1->last_stable_view, watch_pins); + df_panel_insert_stable_view(root_0_0_0_1, root_0_0_0_1->last_stable_view, output); + df_panel_insert_stable_view(root_0_0_0_1, root_0_0_0_1->last_stable_view, memory); + root_0_0_0_1->selected_stable_view = output; + + // rjf: root_0_1 split + root_0_1->split_axis = Axis2_X; + DF_Panel *root_0_1_0 = df_panel_alloc(ws); + DF_Panel *root_0_1_1 = df_panel_alloc(ws); + df_panel_insert(root_0_1, root_0_1->last, root_0_1_0); + df_panel_insert(root_0_1, root_0_1->last, root_0_1_1); + root_0_1_0->size_pct_of_parent = root_0_1_0->size_pct_of_parent_target = v2f32(0.60f, 1.f); + root_0_1_1->size_pct_of_parent = root_0_1_1->size_pct_of_parent_target = v2f32(0.40f, 1.f); + df_panel_insert_stable_view(root_0_1_0, root_0_1_0->last_stable_view, watch); + df_panel_insert_stable_view(root_0_1_0, root_0_1_0->last_stable_view, locals); + df_panel_insert_stable_view(root_0_1_0, root_0_1_0->last_stable_view, regs); + root_0_1_0->selected_stable_view = watch; + root_0_1_0->tab_side = Side_Max; + df_panel_insert_stable_view(root_0_1_1, root_0_1_1->last_stable_view, callstack); + df_panel_insert_stable_view(root_0_1_1, root_0_1_1->last_stable_view, modules); + root_0_1_1->selected_stable_view = callstack; + root_0_1_1->tab_side = Side_Max; + + // rjf: fill main panel with all collected code views + for(DF_HandleNode *n = code_views.first; n != 0; n = n->next) + { + DF_View *view = df_view_from_handle(n->handle); + if(!df_view_is_nil(view)) + { + df_panel_insert_stable_view(root_0_0_1, root_0_0_1->last_stable_view, view); + } + } + + // rjf: choose initial focused panel + ws->focused_panel = root_0_0_1; + + // rjf: dispatch cfg saves + for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) + { + DF_CoreCmdKind write_cmd = df_g_cfg_src_write_cmd_kind_table[src]; + DF_CmdParams p = df_cmd_params_zero(); + p.file_path = df_cfg_path_from_src(src); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(write_cmd)); + } + }break; + + //- rjf: panel rotation + case DF_CoreCmdKind_RotatePanelColumns: + { + DF_Panel *panel = ws->focused_panel; + DF_Panel *parent = &df_g_nil_panel; + for(DF_Panel *p = panel->parent; !df_panel_is_nil(p); p = p->parent) + { + if(p->split_axis == Axis2_X) + { + parent = p; + break; + } + } + if(!df_panel_is_nil(parent) && parent->child_count > 1) + { + DF_Panel *old_first = parent->first; + DF_Panel *new_first = parent->first->next; + old_first->next = &df_g_nil_panel; + old_first->prev = parent->last; + parent->last->next = old_first; + new_first->prev = &df_g_nil_panel; + parent->first = new_first; + parent->last = old_first; + } + df_panel_notify_mutation(ws, panel); + }break; + + //- rjf: focused panel cycling + case DF_CoreCmdKind_NextPanel: panel_sib_off = OffsetOf(DF_Panel, next); panel_child_off = OffsetOf(DF_Panel, first); goto cycle; + case DF_CoreCmdKind_PrevPanel: panel_sib_off = OffsetOf(DF_Panel, prev); panel_child_off = OffsetOf(DF_Panel, last); goto cycle; + cycle:; + { + for(DF_Panel *panel = ws->focused_panel; !df_panel_is_nil(panel);) + { + DF_PanelRec rec = df_panel_rec_df(panel, panel_sib_off, panel_child_off); + panel = rec.next; + if(df_panel_is_nil(panel)) + { + panel = ws->root_panel; + } + if(df_panel_is_nil(panel->first)) + { + ws->focused_panel = panel; + break; + } + } + }break; + case DF_CoreCmdKind_FocusPanel: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + if(!df_panel_is_nil(panel)) + { + ws->focused_panel = panel; + ws->menu_bar_focused = 0; + } + }break; + + //- rjf: directional panel focus changing + case DF_CoreCmdKind_FocusPanelRight: panel_change_dir = v2s32(+1, +0); goto focus_panel_dir; + case DF_CoreCmdKind_FocusPanelLeft: panel_change_dir = v2s32(-1, +0); goto focus_panel_dir; + case DF_CoreCmdKind_FocusPanelUp: panel_change_dir = v2s32(+0, -1); goto focus_panel_dir; + case DF_CoreCmdKind_FocusPanelDown: panel_change_dir = v2s32(+0, +1); goto focus_panel_dir; + focus_panel_dir:; + { + DF_Panel *src_panel = ws->focused_panel; + Rng2F32 src_panel_rect = df_rect_from_panel(r2f32(v2f32(0, 0), v2f32(1000, 1000)), ws->root_panel, src_panel); + Vec2F32 src_panel_center = center_2f32(src_panel_rect); + Vec2F32 src_panel_half_dim = scale_2f32(dim_2f32(src_panel_rect), 0.5f); + Vec2F32 travel_dim = add_2f32(src_panel_half_dim, v2f32(10.f, 10.f)); + Vec2F32 travel_dst = add_2f32(src_panel_center, mul_2f32(travel_dim, v2f32((F32)panel_change_dir.x, (F32)panel_change_dir.y))); + DF_Panel *dst_root = &df_g_nil_panel; + for(DF_Panel *p = ws->root_panel; !df_panel_is_nil(p); p = df_panel_rec_df_pre(p).next) + { + if(p == src_panel || !df_panel_is_nil(p->first)) + { + continue; + } + Rng2F32 p_rect = df_rect_from_panel(r2f32(v2f32(0, 0), v2f32(1000, 1000)), ws->root_panel, p); + if(contains_2f32(p_rect, travel_dst)) + { + dst_root = p; + break; + } + } + if(!df_panel_is_nil(dst_root)) + { + DF_Panel *dst_panel = &df_g_nil_panel; + for(DF_Panel *p = dst_root; !df_panel_is_nil(p); p = df_panel_rec_df_pre(p).next) + { + if(df_panel_is_nil(p->first) && p != src_panel) + { + dst_panel = p; + break; + } + } + ws->focused_panel = dst_panel; + } + }break; + + //- rjf: focus history + case DF_CoreCmdKind_GoBack: + { + df_state_delta_history_wind(ws->view_state_hist, Side_Min); + }break; + case DF_CoreCmdKind_GoForward: + { + df_state_delta_history_wind(ws->view_state_hist, Side_Max); + }break; + + //- rjf: panel removal + case DF_CoreCmdKind_ClosePanel: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + DF_Panel *parent = panel->parent; + if(!df_panel_is_nil(parent)) + { + df_panel_notify_mutation(ws, panel); + Axis2 split_axis = parent->split_axis; + + // NOTE(rjf): If we're removing all but the last child of this parent, + // we should just remove both children. + if(parent->child_count == 2) + { + DF_Panel *discard_child = panel; + DF_Panel *keep_child = panel == parent->first ? parent->last : parent->first; + DF_Panel *grandparent = parent->parent; + DF_Panel *parent_prev = parent->prev; + Vec2F32 size_pct_of_parent = parent->size_pct_of_parent_target; + + // rjf: unhook kept child + df_panel_remove(parent, keep_child); + + // rjf: unhook this subtree + if(!df_panel_is_nil(grandparent)) + { + df_panel_remove(grandparent, parent); + } + + // rjf: release the things we should discard + { + df_panel_release(ws, parent); + df_panel_release(ws, discard_child); + } + + // rjf: re-hook our kept child into the overall tree + if(df_panel_is_nil(grandparent)) + { + ws->root_panel = keep_child; + } + else + { + df_panel_insert(grandparent, parent_prev, keep_child); + } + keep_child->size_pct_of_parent_target = size_pct_of_parent; + keep_child->size_pct_of_parent.v[split_axis] *= size_pct_of_parent.v[split_axis]; + keep_child->size_pct_of_parent.v[axis2_flip(split_axis)] *= size_pct_of_parent.v[axis2_flip(split_axis)]; + + // rjf: keep-child split-axis == grandparent split-axis? bubble keep-child up into grandparent's children + if(grandparent->split_axis == keep_child->split_axis && !df_panel_is_nil(keep_child->first)) + { + df_panel_remove(grandparent, keep_child); + DF_Panel *prev = parent_prev; + for(DF_Panel *child = keep_child->first, *next = 0; !df_panel_is_nil(child); child = next) + { + next = child->next; + df_panel_remove(keep_child, child); + df_panel_insert(grandparent, prev, child); + prev = child; + child->size_pct_of_parent_target.v[keep_child->split_axis] *= keep_child->size_pct_of_parent_target.v[grandparent->split_axis]; + child->size_pct_of_parent.v[keep_child->split_axis] *= keep_child->size_pct_of_parent_target.v[grandparent->split_axis]; + } + df_panel_release(ws, keep_child); + } + + // rjf: reset focus, if needed + if(ws->focused_panel == discard_child) + { + ws->focused_panel = keep_child; + for(DF_Panel *grandchild = ws->focused_panel; !df_panel_is_nil(grandchild); grandchild = grandchild->first) + { + ws->focused_panel = grandchild; + } + } + } + // NOTE(rjf): Otherwise we can just remove this child. + else + { + DF_Panel *next = &df_g_nil_panel; + F32 removed_size_pct = panel->size_pct_of_parent_target.v[parent->split_axis]; + if(df_panel_is_nil(next)) { next = panel->prev; } + if(df_panel_is_nil(next)) { next = panel->next; } + df_panel_remove(parent, panel); + df_panel_release(ws, panel); + if(ws->focused_panel == panel) + { + ws->focused_panel = next; + } + for(DF_Panel *child = parent->first; !df_panel_is_nil(child); child = child->next) + { + child->size_pct_of_parent_target.v[parent->split_axis] /= 1.f-removed_size_pct; + } + } + } + }break; + + //- rjf: panel tab controls + case DF_CoreCmdKind_NextTab: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + if(panel->history_tab_bar_mode == 0 && !df_view_is_nil(panel->selected_stable_view) && df_view_is_nil(panel->query_view_stack_top)) + { + panel->selected_stable_view = panel->selected_stable_view->next; + if(df_view_is_nil(panel->selected_stable_view)) + { + panel->selected_stable_view = panel->first_stable_view; + } + } + }break; + case DF_CoreCmdKind_PrevTab: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + if(panel->history_tab_bar_mode == 0 && !df_view_is_nil(panel->selected_stable_view) && df_view_is_nil(panel->query_view_stack_top)) + { + panel->selected_stable_view = panel->selected_stable_view->prev; + if(df_view_is_nil(panel->selected_stable_view)) + { + panel->selected_stable_view = panel->last_stable_view; + } + } + }break; + case DF_CoreCmdKind_MoveTabRight: + case DF_CoreCmdKind_MoveTabLeft: + { + DF_Panel *panel = ws->focused_panel; + DF_View *view = panel->selected_stable_view; + DF_View *prev_view = core_cmd_kind == DF_CoreCmdKind_MoveTabRight ? view->next : view->prev->prev; + if(!df_view_is_nil(prev_view) || core_cmd_kind == DF_CoreCmdKind_MoveTabLeft) + { + DF_CmdParams p = df_cmd_params_from_window(ws); + p.panel = df_handle_from_panel(panel); + p.dest_panel = df_handle_from_panel(panel); + p.view = df_handle_from_view(view); + p.prev_view = df_handle_from_view(prev_view); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_MoveTab)); + } + }break; + case DF_CoreCmdKind_CloseTab: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + DF_View *view = df_view_from_handle(params.view); + if(panel->history_tab_bar_mode == 0 && !df_view_is_nil(view)) + { + df_panel_remove_stable_view(panel, view); + df_view_release(view); + df_panel_notify_mutation(ws, panel); + } + if(panel->history_tab_bar_mode == 1) + { + for(DF_View *v = panel->first_stable_view, *next = 0; + !df_view_is_nil(v); v = next) + { + next = v->next; + df_panel_remove_stable_view(panel, v); + df_view_release(v); + } + } + }break; + case DF_CoreCmdKind_MoveTab: + { + DF_Panel *src_panel = df_panel_from_handle(params.panel); + DF_View *view = df_view_from_handle(params.view); + DF_Panel *dst_panel = df_panel_from_handle(params.dest_panel); + DF_View *prev_view = df_view_from_handle(params.prev_view); + if(!df_panel_is_nil(src_panel) && + !df_panel_is_nil(dst_panel) && + prev_view != view) + { + df_panel_remove_stable_view(src_panel, view); + df_panel_insert_stable_view(dst_panel, prev_view, view); + ws->focused_panel = dst_panel; + df_panel_notify_mutation(ws, dst_panel); + } + }break; + case DF_CoreCmdKind_TabBarTop: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + panel->tab_side = Side_Min; + df_panel_notify_mutation(ws, panel); + }break; + case DF_CoreCmdKind_TabBarBottom: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + panel->tab_side = Side_Max; + df_panel_notify_mutation(ws, panel); + }break; + case DF_CoreCmdKind_TabBarEnable: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + panel->hide_tab_bar = 0; + panel->history_tab_bar_mode = 0; + df_panel_notify_mutation(ws, panel); + }break; + case DF_CoreCmdKind_TabBarDisable: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + panel->hide_tab_bar = 1; + panel->history_tab_bar_mode = 1; + df_panel_notify_mutation(ws, panel); + }break; + case DF_CoreCmdKind_TabBarHistoryModeEnable: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + panel->history_tab_bar_mode = 1; + panel->hide_tab_bar = 0; + df_panel_notify_mutation(ws, panel); + }break; + case DF_CoreCmdKind_TabBarHistoryModeDisable: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + panel->history_tab_bar_mode = 0; + df_panel_notify_mutation(ws, panel); + }break; + + //- rjf: files + case DF_CoreCmdKind_Open: + { + DF_Entity *entity = df_entity_from_path(params.file_path, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + if(!(entity->flags & DF_EntityFlag_IsMissing) && !(entity->flags & DF_EntityFlag_IsFolder)) + { + DF_CmdParams p = params; + p.window = df_handle_from_window(ws); + p.panel = df_handle_from_panel(ws->focused_panel); + p.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Window); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); + } + }break; + case DF_CoreCmdKind_Reload: + { + DF_Entity *file = df_entity_from_handle(params.entity); + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + DF_View *view = panel->selected_stable_view; + DF_Entity *view_entity = df_entity_from_handle(view->cmd_entity); + if(view_entity == file) + { + view->flash_t = 1.f; + } + } + }break; + case DF_CoreCmdKind_ReloadActive: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + DF_View *view = panel->selected_stable_view; + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + if(entity->kind == DF_EntityKind_File) + { + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Reload)); + } + }break; + case DF_CoreCmdKind_Switch: + { + B32 already_opened = 0; + DF_Panel *panel = df_panel_from_handle(params.panel); + for(DF_View *v = panel->first_stable_view; !df_view_is_nil(v); v = v->next) + { + DF_Entity *v_param_entity = df_entity_from_handle(v->cmd_entity); + if(v_param_entity == df_entity_from_handle(params.entity)) + { + panel->selected_stable_view = v; + already_opened = 1; + break; + } + } + if(already_opened == 0) + { + DF_CmdParams p = params; + p.window = df_handle_from_window(ws); + p.panel = df_handle_from_panel(ws->focused_panel); + p.entity = params.entity; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Window); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); + } + }break; + + //- rjf: directional movement & text controls + // + // NOTE(rjf): These all get funneled into a separate intermediate that + // can be used by the UI build phase for navigation and stuff, as well + // as builder codepaths that want to use these controls to modify text. + // + case DF_CoreCmdKind_MoveLeft: + { + UI_NavAction action = {UI_NavActionFlag_PickSelectSide|UI_NavActionFlag_ZeroDeltaOnSelect|UI_NavActionFlag_ExplicitDirectional, {-1, +0}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveRight: + { + UI_NavAction action = {UI_NavActionFlag_PickSelectSide|UI_NavActionFlag_ZeroDeltaOnSelect|UI_NavActionFlag_ExplicitDirectional, {+1, +0}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUp: + { + UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, -1}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDown: + { + UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, +1}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveLeftSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {-1, +0}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveRightSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+1, +0}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUpSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, -1}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDownSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, +1}}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveLeftChunk: + { + UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {-1, +0}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveRightChunk: + { + UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+1, +0}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUpChunk: + { + UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, -1}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDownChunk: + { + UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, +1}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUpPage: + { + UI_NavAction action = {0, {+0, -1}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDownPage: + { + UI_NavAction action = {0, {+0, +1}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUpWhole: + { + UI_NavAction action = {0, {+0, -1}, UI_NavDeltaUnit_EndPoint}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDownWhole: + { + UI_NavAction action = {0, {+0, +1}, UI_NavDeltaUnit_EndPoint}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveLeftChunkSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {-1, +0}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveRightChunkSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+1, +0}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUpChunkSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, -1}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDownChunkSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, +1}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUpPageSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, -1}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDownPageSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, +1}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveUpWholeSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark, {+0, -1}, UI_NavDeltaUnit_EndPoint}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveDownWholeSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark, {+0, +1}, UI_NavDeltaUnit_EndPoint}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveHome: + { + UI_NavAction action = {0, {-1, +0}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveEnd: + { + UI_NavAction action = {0, {+1, +0}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveHomeSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark, {-1, +0}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_MoveEndSelect: + { + UI_NavAction action = {UI_NavActionFlag_KeepMark, {+1, +0}, UI_NavDeltaUnit_Whole}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_SelectAll: + { + UI_NavAction action1 = {0, {-1, +0}, UI_NavDeltaUnit_EndPoint}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action1); + UI_NavAction action2 = {UI_NavActionFlag_KeepMark, {+1, +0}, UI_NavDeltaUnit_EndPoint}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action2); + }break; + case DF_CoreCmdKind_DeleteSingle: + { + UI_NavAction action = {UI_NavActionFlag_Delete, {+1, +0}, UI_NavDeltaUnit_Element}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_DeleteChunk: + { + UI_NavAction action = {UI_NavActionFlag_Delete, {+1, +0}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_BackspaceSingle: + { + UI_NavAction action = {UI_NavActionFlag_Delete|UI_NavActionFlag_ZeroDeltaOnSelect, {-1, +0}, UI_NavDeltaUnit_Element}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_BackspaceChunk: + { + UI_NavAction action = {UI_NavActionFlag_Delete|UI_NavActionFlag_ZeroDeltaOnSelect, {-1, +0}, UI_NavDeltaUnit_Chunk}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_Copy: + { + UI_NavAction action = {UI_NavActionFlag_Copy|UI_NavActionFlag_KeepMark}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_Cut: + { + UI_NavAction action = {UI_NavActionFlag_Copy|UI_NavActionFlag_Delete}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_Paste: + { + UI_NavAction action = {UI_NavActionFlag_Paste}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + case DF_CoreCmdKind_InsertText: + { + String8 insertion = params.string; + UI_NavAction action = {0, {0}, (UI_NavDeltaUnit)0, push_str8_copy(ui_build_arena(), insertion)}; + ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + }break; + + //- rjf: address finding + case DF_CoreCmdKind_GoToAddress: + { + U64 vaddr = params.vaddr; + }break; + + //- rjf: thread finding + case DF_CoreCmdKind_FindThread: + { + DBGI_Scope *scope = dbgi_scope_open(); + DF_Entity *thread = df_entity_from_handle(params.entity); + U64 unwind_count = params.index; + if(thread->kind == DF_EntityKind_Thread) + { + // rjf: grab rip + U64 rip_vaddr = (unwind_count == 0 ? df_rip_from_thread(thread) : df_query_cached_rip_from_thread_unwind(thread, unwind_count)); + + // rjf: extract thread/rip info + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); + DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + + // rjf: snap to resolved line + B32 missing_rip = (rip_vaddr == 0); + B32 binary_missing = (binary->flags & DF_EntityFlag_IsMissing); + B32 dbg_info_pending = !binary_missing && dbgi == &dbgi_parse_nil; + B32 has_line_info = (line_info.voff_range.max != line_info.voff_range.min); + B32 has_module = !df_entity_is_nil(module); + B32 has_dbg_info = has_module && !binary_missing; + if(!dbg_info_pending && (has_line_info || has_module)) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + if(has_line_info) + { + params.file_path = df_full_path_from_entity(scratch.arena, line_info.file); + params.text_point = line_info.pt; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + } + params.entity = df_handle_from_entity(thread); + params.voff = rip_voff; + params.vaddr = rip_vaddr; + params.index = unwind_count; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualOff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + + // rjf: retry on pending debug info + if(dbg_info_pending || missing_rip) + { + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); + } + } + dbgi_scope_close(scope); + }break; + case DF_CoreCmdKind_FindSelectedThread: + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(ws); + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(selected_thread); + params.index = ctrl_ctx.unwind_count; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); + }break; + + //- rjf: name finding + case DF_CoreCmdKind_GoToName: + { + String8 name = params.string; + if(name.size != 0) + { + B32 name_resolved = 0; + + // rjf: try to resolve name as a symbol + U64 voff = 0; + DF_Entity *voff_binary = &df_g_nil_entity; + if(name_resolved == 0) + { + DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + for(DF_EntityNode *n = binaries.first; n != 0; n = n->next) + { + U64 binary_voff = df_voff_from_binary_symbol_name(n->entity, name); + if(binary_voff != 0) + { + voff = binary_voff; + voff_binary = n->entity; + name_resolved = 1; + break; + } + } + } + + // rjf: try to resolve name as a file + DF_Entity *file = &df_g_nil_entity; + if(name_resolved == 0) + { + DF_Entity *src_entity = df_entity_from_handle(params.entity); + String8 file_part_of_name = name; + U64 quote_pos = str8_find_needle(name, 0, str8_lit("\""), 0); + if(quote_pos < name.size) + { + file_part_of_name = str8_skip(name, quote_pos+1); + U64 ender_quote_pos = str8_find_needle(file_part_of_name, 0, str8_lit("\""), 0); + file_part_of_name = str8_prefix(file_part_of_name, ender_quote_pos); + } + if(file_part_of_name.size != 0) + { + String8 folder_path = str8_chop_last_slash(file_part_of_name); + String8 file_name = str8_skip_last_slash(file_part_of_name); + String8List folders = str8_split_path(scratch.arena, folder_path); + + // rjf: some folders are specified + if(folders.node_count != 0) + { + String8 first_folder_name = folders.first->string; + DF_Entity *root_folder = &df_g_nil_entity; + + // rjf: try to find root folder as if it's an absolute path + if(df_entity_is_nil(root_folder)) + { + root_folder = df_entity_from_path(first_folder_name, DF_EntityFromPathFlag_OpenAsNeeded); + } + + // rjf: try to find root folder as if it's a path we've already loaded + if(df_entity_is_nil(root_folder)) + { + root_folder = df_entity_from_name_and_kind(first_folder_name, DF_EntityKind_File); + } + + // rjf: try to find root folder as if it's inside of a path we've already loaded + if(df_entity_is_nil(root_folder)) + { + DF_EntityList all_files = df_query_cached_entity_list_with_kind(DF_EntityKind_File); + for(DF_EntityNode *n = all_files.first; n != 0; n = n->next) + { + if(n->entity->flags & DF_EntityFlag_IsFolder) + { + String8 n_entity_path = df_full_path_from_entity(scratch.arena, n->entity); + String8 estimated_full_path = push_str8f(scratch.arena, "%S/%S", n_entity_path, first_folder_name); + root_folder = df_entity_from_path(estimated_full_path, DF_EntityFromPathFlag_OpenAsNeeded); + if(!df_entity_is_nil(root_folder)) + { + break; + } + } + } + } + + // rjf: has root folder -> descend downwards + if(!df_entity_is_nil(root_folder)) + { + String8 root_folder_path = df_full_path_from_entity(scratch.arena, root_folder); + String8List full_file_path_parts = {0}; + str8_list_push(scratch.arena, &full_file_path_parts, root_folder_path); + for(String8Node *n = folders.first->next; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &full_file_path_parts, n->string); + } + str8_list_push(scratch.arena, &full_file_path_parts, file_name); + StringJoin join = {0}; + join.sep = str8_lit("/"); + String8 full_file_path = str8_list_join(scratch.arena, &full_file_path_parts, &join); + file = df_entity_from_path(full_file_path, DF_EntityFromPathFlag_AllowOverrides|DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + } + } + + // rjf: no folders specified => just try the local folder, then try globally + else if(src_entity->kind == DF_EntityKind_File) + { + file = df_entity_from_name_and_kind(file_name, DF_EntityKind_File); + if(df_entity_is_nil(file)) + { + String8 src_entity_full_path = df_full_path_from_entity(scratch.arena, src_entity); + String8 src_entity_folder = str8_chop_last_slash(src_entity_full_path); + String8 estimated_full_path = push_str8f(scratch.arena, "%S/%S", src_entity_folder, file_name); + file = df_entity_from_path(estimated_full_path, DF_EntityFromPathFlag_All); + } + } + } + name_resolved = !df_entity_is_nil(file) && !(file->flags & DF_EntityFlag_IsMissing) && !(file->flags & DF_EntityFlag_IsFolder); + } + + // rjf: process resolved info + if(name_resolved == 0) + { + DF_CmdParams p = params; + p.string = push_str8f(scratch.arena, "\"%S\" could not be found.", name); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + + // rjf: name resolved to voff * dbg info + if(name_resolved != 0 && voff != 0) + { + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(voff_binary, voff); + DF_CmdParams p = params; + { + p.file_path = df_full_path_from_entity(scratch.arena, dasm2src_info.file); + p.text_point = dasm2src_info.pt; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_TextPoint); + if(!df_entity_is_nil(voff_binary)) + { + p.entity = df_handle_from_entity(voff_binary); + p.voff = dasm2src_info.voff_range.min; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_VirtualOff); + } + } + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + + // rjf: name resolved to a file + if(name_resolved != 0 && !df_entity_is_nil(file)) + { + String8 path = df_full_path_from_entity(scratch.arena, file); + DF_CmdParams p = params; + p.file_path = path; + p.text_point = txt_pt(1, 1); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_TextPoint); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + } + }break; + + //- rjf: editors + case DF_CoreCmdKind_EditEntity: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + switch(entity->kind) + { + default: break; + case DF_EntityKind_Target: + { + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EditTarget)); + }break; + } + }break; + + //- rjf: memory openers + case DF_CoreCmdKind_OpenFileMemory: + case DF_CoreCmdKind_OpenProcessMemory: + { + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Memory)); + }break; + case DF_CoreCmdKind_OpenSelectedProcessMemory: + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(ws); + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *selected_process = df_entity_ancestor_from_kind(selected_thread, DF_EntityKind_Process); + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(selected_process); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OpenProcessMemory)); + }break; + + //- rjf: targets + case DF_CoreCmdKind_EditTarget: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + if(!df_entity_is_nil(entity) && entity->kind == DF_EntityKind_Target) + { + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Target)); + } + else + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.string = str8_lit("Invalid target."); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + }break; + + //- rjf: catchall general entity activation paths (drag/drop, clicking) + case DF_CoreCmdKind_EntityRefFastPath: + { + DF_Entity *entity = df_entity_from_handle(params.entity); + switch(entity->kind) + { + default: + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SpawnEntityView)); + }break; + case DF_EntityKind_File: + { + String8 path = df_full_path_from_entity(scratch.arena, entity); + DF_CmdParams params = df_cmd_params_from_window(ws); + params.file_path = path; + params.text_point = txt_pt(1, 1); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + }break; + case DF_EntityKind_Thread: + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectThread)); + }break; + } + }break; + case DF_CoreCmdKind_SpawnEntityView: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + DF_Entity *entity = df_entity_from_handle(params.entity); + switch(entity->kind) + { + default:{}break; + + case DF_EntityKind_File: + { + if(entity->flags & DF_EntityFlag_IsFolder) + { + String8 full_path = df_full_path_from_entity(scratch.arena, entity); + String8 full_path_w_slash = push_str8f(scratch.arena, "%S/", full_path); + + // rjf: set current path + { + DF_CmdParams p = df_cmd_params_zero(); + p.file_path = full_path_w_slash; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetCurrentPath)); + } + + // rjf: do fast path for open + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + p.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Open); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + } + else + { + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); + } + }break; + + case DF_EntityKind_Target: + { + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EditTarget)); + }break; + } + }break; + case DF_CoreCmdKind_FindCodeLocation: + { + // NOTE(rjf): This command is where a lot of high-level flow things + // in the debugger come together. It's that codepath that runs any + // time a source code location is clicked in the UI, when a thread + // is selected, or when a thread causes a halt (hitting a breakpoint + // or exception or something). This is the logic that manages the + // flow of how views and panels are changed, opened, etc. when + // something like that happens. + // + // The gist of the intended rule for textual source code locations + // is the following: + // + // 1. Try to find a panel that's viewing the file (has it open in a + // tab, *and* that tab is selected). + // 2. Try to find a panel that has the file open in a tab, but does not + // currently have that tab selected. + // 3. Try to find a panel that has ANY source code open in any tab. + // 4. If the above things fail, try to pick the biggest panel, which + // is generally a decent rule (because it matches the popular + // debugger usage UI paradigm). + // + // The reason why this is a little more complicated than you might + // imagine is because this debugger frontend does not have any special + // "code panels" or anything like that, unlike e.g. VS or Remedy. All + // panels are identical in nature to allow for the user to organize + // the interface how they want, but in cases like this, we have to + // "fish out" the best option given the user's configuration. This + // can't be what the user wants in 100% of cases (this program cannot + // read anyone's mind), but it does provide expected behavior in + // common cases. + // + // The gist of the intended rule for finding disassembly locations is + // the following: + // + // 1. Try to find a panel that's viewing disassembly already - if so, + // snap it to the right address. + // 2. If there is no disassembly tab open, then we need to open one + // ONLY if source code was not found. + // 3. If we need to open a disassembly tab, we will first try to pick + // the biggest empty panel. + // 4. If there is no empty panel, then we will pick the biggest + // panel. + + // rjf: grab things to find. file * text, process * address, etc. + DF_Entity *src_code = &df_g_nil_entity; + TxtPt point = {0}; + DF_Entity *thread = &df_g_nil_entity; + DF_Entity *process = &df_g_nil_entity; + U64 vaddr = 0; + { + DF_Entity *param_entity = df_entity_from_handle(params.entity); + if(params.file_path.size != 0) + { + src_code = df_entity_from_path(params.file_path, DF_EntityFromPathFlag_All); + } + if(param_entity->kind == DF_EntityKind_Thread) + { + thread = param_entity; + } + if(param_entity->kind == DF_EntityKind_Thread || + param_entity->kind == DF_EntityKind_Module) + { + process = df_entity_ancestor_from_kind(param_entity, DF_EntityKind_Process); + if(param_entity->kind == DF_EntityKind_Module) + { + thread = df_entity_child_from_kind(process, DF_EntityKind_Thread); + } + } + if(param_entity->kind == DF_EntityKind_Process) + { + process = param_entity; + thread = df_entity_child_from_kind(process, DF_EntityKind_Thread); + } + point = params.text_point; + vaddr = params.vaddr; + } + + // rjf: given a src code location, and a process, if no vaddr is specified, + // try to map the src coordinates to a vaddr via line info + if(vaddr == 0 && !df_entity_is_nil(src_code) && !df_entity_is_nil(process)) + { + DF_TextLineSrc2DasmInfoListArray src2dasm = df_text_line_src2dasm_info_list_array_from_src_line_range(scratch.arena, src_code, r1s64(point.line, point.line)); + for(U64 src2dasm_idx = 0; src2dasm_idx < src2dasm.count; src2dasm_idx += 1) + { + for(DF_TextLineSrc2DasmInfoNode *n = src2dasm.v[src2dasm_idx].first; n != 0; n = n->next) + { + DF_EntityList modules = df_modules_from_binary_file(scratch.arena, n->v.binary); + DF_Entity *module = df_module_from_thread_candidates(thread, &modules); + vaddr = df_vaddr_from_voff(module, n->v.voff_range.min); + goto end_lookup; + } + } + end_lookup:; + } + + // rjf: first, try to find panel/view pair that already has the src file open + DF_Panel *panel_w_this_src_code = &df_g_nil_panel; + DF_View *view_w_this_src_code = &df_g_nil_view; + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + if(!df_panel_is_nil(panel->first)) + { + continue; + } + for(DF_View *view = panel->first_stable_view; !df_view_is_nil(view); view = view->next) + { + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_CoreCmdKind cmd_kind = df_core_cmd_kind_from_string(cmd_spec->info.string); + DF_Entity *viewed_entity = df_entity_from_handle(view->cmd_entity); + if((cmd_kind == DF_CoreCmdKind_Code || cmd_kind == DF_CoreCmdKind_PendingEntity) && viewed_entity == src_code) + { + panel_w_this_src_code = panel; + view_w_this_src_code = view; + if(view == panel->selected_stable_view) + { + break; + } + } + } + } + + // rjf: find a panel that already has *any* code open + DF_Panel *panel_w_any_src_code = &df_g_nil_panel; + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + if(!df_panel_is_nil(panel->first)) + { + continue; + } + for(DF_View *view = panel->first_stable_view; !df_view_is_nil(view); view = view->next) + { + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_CoreCmdKind cmd_kind = df_core_cmd_kind_from_string(cmd_spec->info.string); + if(cmd_kind == DF_CoreCmdKind_Code) + { + panel_w_any_src_code = panel; + break; + } + } + } + + // rjf: try to find panel/view pair that has disassembly open + DF_Panel *panel_w_disasm = &df_g_nil_panel; + DF_View *view_w_disasm = &df_g_nil_view; + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + if(!df_panel_is_nil(panel->first)) + { + continue; + } + for(DF_View *view = panel->first_stable_view; !df_view_is_nil(view); view = view->next) + { + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_CoreCmdKind cmd_kind = df_core_cmd_kind_from_string(cmd_spec->info.string); + DF_Entity *viewed_entity = df_entity_from_handle(view->cmd_entity); + if(cmd_kind == DF_CoreCmdKind_Disassembly) + { + panel_w_disasm = panel; + view_w_disasm = view; + if(view == panel->selected_stable_view) + { + break; + } + } + } + } + + // rjf: find the biggest panel + DF_Panel *biggest_panel = &df_g_nil_panel; + { + Rng2F32 root_rect = os_client_rect_from_window(ws->os); + F32 best_panel_area = 0; + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + if(!df_panel_is_nil(panel->first)) + { + continue; + } + Rng2F32 panel_rect = df_rect_from_panel(root_rect, ws->root_panel, panel); + Vec2F32 panel_rect_dim = dim_2f32(panel_rect); + F32 area = panel_rect_dim.x * panel_rect_dim.y; + if((best_panel_area == 0 || area > best_panel_area)) + { + best_panel_area = area; + biggest_panel = panel; + } + } + } + + // rjf: find the biggest empty panel + DF_Panel *biggest_empty_panel = &df_g_nil_panel; + { + Rng2F32 root_rect = os_client_rect_from_window(ws->os); + F32 best_panel_area = 0; + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + if(!df_panel_is_nil(panel->first)) + { + continue; + } + Rng2F32 panel_rect = df_rect_from_panel(root_rect, ws->root_panel, panel); + Vec2F32 panel_rect_dim = dim_2f32(panel_rect); + F32 area = panel_rect_dim.x * panel_rect_dim.y; + if(df_view_is_nil(panel->first_stable_view) && (best_panel_area == 0 || area > best_panel_area)) + { + best_panel_area = area; + biggest_empty_panel = panel; + } + } + } + + // rjf: given the above, find source code location. + DF_Panel *panel_used_for_src_code = &df_g_nil_panel; + if(!df_entity_is_nil(src_code)) + { + // rjf: determine which panel we will use to find the code loc + DF_Panel *dst_panel = &df_g_nil_panel; + { + if(df_panel_is_nil(dst_panel)) { dst_panel = panel_w_this_src_code; } + if(df_panel_is_nil(dst_panel)) { dst_panel = panel_w_any_src_code; } + if(df_panel_is_nil(dst_panel)) { dst_panel = biggest_empty_panel; } + if(df_panel_is_nil(dst_panel)) { dst_panel = biggest_panel; } + } + + // rjf: construct new view if needed + DF_View *dst_view = view_w_this_src_code; + if(!df_panel_is_nil(dst_panel) && df_view_is_nil(view_w_this_src_code)) + { + DF_View *view = df_view_alloc(); + DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity); + DF_CmdParams new_view_params = df_cmd_params_zero(); + new_view_params.entity = df_handle_from_entity(src_code); + df_cmd_params_mark_slot(&new_view_params, DF_CmdParamSlot_Entity); + df_view_equip_command(view, spec, &new_view_params, str8_lit(""), &df_g_nil_cfg_node); + df_panel_history_new_branch(dst_panel); + df_panel_insert_stable_view(dst_panel, dst_panel->last_stable_view, view); + dst_view = view; + } + + // rjf: determine if we need a contain or center + DF_CoreCmdKind cursor_snap_kind = DF_CoreCmdKind_CenterCursor; + if(!df_panel_is_nil(dst_panel) && dst_view == view_w_this_src_code && dst_panel->selected_stable_view == dst_view) + { + cursor_snap_kind = DF_CoreCmdKind_ContainCursor; + } + + // rjf: move cursor & snap-to-cursor + if(!df_panel_is_nil(dst_panel)) + { + dst_panel->selected_stable_view = dst_view; + DF_CmdParams params = df_cmd_params_from_view(ws, dst_panel, dst_view); + params.text_point = point; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToLine)); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(cursor_snap_kind)); + panel_used_for_src_code = dst_panel; + } + } + + // rjf: given the above, find disassembly location. + if(!df_entity_is_nil(process) && vaddr != 0) + { + // rjf: determine which panel we will use to find the disasm loc - + // we *cannot* use the same panel we used for source code, if any. + DF_Panel *dst_panel = &df_g_nil_panel; + { + if(df_panel_is_nil(dst_panel)) { dst_panel = panel_w_disasm; } + if(df_panel_is_nil(panel_used_for_src_code) && df_panel_is_nil(dst_panel)) { dst_panel = biggest_empty_panel; } + if(df_panel_is_nil(panel_used_for_src_code) && df_panel_is_nil(dst_panel)) { dst_panel = biggest_panel; } + if(dst_panel == panel_used_for_src_code) + { + dst_panel = &df_g_nil_panel; + } + } + + // rjf: construct new view if needed + DF_View *dst_view = view_w_disasm; + if(!df_panel_is_nil(dst_panel) && df_view_is_nil(view_w_disasm)) + { + DF_View *view = df_view_alloc(); + DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Disassembly); + DF_CmdParams new_view_params = df_cmd_params_zero(); + df_view_equip_command(view, spec, &new_view_params, str8_lit(""), &df_g_nil_cfg_node); + df_panel_history_new_branch(dst_panel); + df_panel_insert_stable_view(dst_panel, dst_panel->last_stable_view, view); + dst_view = view; + } + + // rjf: determine if we need a contain or center + DF_CoreCmdKind cursor_snap_kind = DF_CoreCmdKind_CenterCursor; + if(dst_view == view_w_disasm && dst_panel->selected_stable_view == dst_view) + { + cursor_snap_kind = DF_CoreCmdKind_ContainCursor; + } + + // rjf: move cursor & snap-to-cursor + if(!df_panel_is_nil(dst_panel)) + { + dst_panel->selected_stable_view = dst_view; + DF_CmdParams params = df_cmd_params_from_view(ws, dst_panel, dst_view); + params.entity = df_handle_from_entity(process); + params.vaddr = vaddr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToAddress)); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(cursor_snap_kind)); + } + } + }break; + + //- rjf: core pass-through view result commands + case DF_CoreCmdKind_ViewReturn: + { + DF_Panel *panel = df_panel_from_handle(params.panel); + DF_View *view = df_view_from_handle(params.view); + + // rjf: if this is a stable view, remove + for(DF_View *stable_view = panel->first_stable_view; !df_view_is_nil(stable_view); stable_view = stable_view->next) + { + if(stable_view == view) + { + df_panel_remove_stable_view(panel, view); + break; + } + } + + // rjf: if this is the top of the query stack, unhook from panel + if(panel->query_view_stack_top == view) + { + panel->query_view_stack_top = &df_g_nil_view; + } + + // rjf: release + df_view_release(view); + }break; + + //- rjf: developer commands + case DF_CoreCmdKind_ToggleDevMenu: + { + ws->dev_menu_is_open ^= 1; + }break; + } + } + scratch_end(scratch); + } + + //- rjf: process view-level commands on leaf panels + ProfScope("dispatch view-level commands") + { + for(DF_Panel *panel = ws->root_panel; + !df_panel_is_nil(panel); + panel = df_panel_rec_df_pre(panel).next) + { + if(!df_panel_is_nil(panel->first)) + { + continue; + } + + // rjf: dispatch to query views + for(DF_View *view = panel->query_view_stack_top; + !df_view_is_nil(view); + view = view->callee_view) + { + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd_spec); + DF_ViewCmdFunctionType *do_view_cmds_function = view_spec->info.cmd_hook; + do_view_cmds_function(ws, panel, view, cmds); + } + + // rjf: dispatch to stable views + for(DF_View *view_stack_top = panel->first_stable_view; + !df_view_is_nil(view_stack_top); + view_stack_top = view_stack_top->next) + { + for(DF_View *view = view_stack_top; + !df_view_is_nil(view); + view = view->callee_view) + { + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd_spec); + DF_ViewCmdFunctionType *do_view_cmds_function = view_spec->info.cmd_hook; + do_view_cmds_function(ws, panel, view, cmds); + } + } + } + } + + //- rjf: build UI + UI_Box *autocomp_box = &ui_g_nil_box; + UI_Box *hover_eval_box = &ui_g_nil_box; + ProfScope("build UI") + { + //- rjf: set up + { + // rjf: gather font info + F_Tag main_font = df_font_from_slot(DF_FontSlot_Main); + F32 main_font_size = df_font_size_from_slot(ws, DF_FontSlot_Main); + F_Tag icon_font = df_font_from_slot(DF_FontSlot_Icons); + + // rjf: build icon info + UI_IconInfo icon_info = {0}; + { + icon_info.icon_font = icon_font; + icon_info.icon_kind_text_map[UI_IconKind_RightArrow] = df_g_icon_kind_text_table[DF_IconKind_RightScroll]; + icon_info.icon_kind_text_map[UI_IconKind_DownArrow] = df_g_icon_kind_text_table[DF_IconKind_DownScroll]; + icon_info.icon_kind_text_map[UI_IconKind_LeftArrow] = df_g_icon_kind_text_table[DF_IconKind_LeftScroll]; + icon_info.icon_kind_text_map[UI_IconKind_UpArrow] = df_g_icon_kind_text_table[DF_IconKind_UpScroll]; + icon_info.icon_kind_text_map[UI_IconKind_RightCaret] = df_g_icon_kind_text_table[DF_IconKind_RightCaret]; + icon_info.icon_kind_text_map[UI_IconKind_DownCaret] = df_g_icon_kind_text_table[DF_IconKind_DownCaret]; + icon_info.icon_kind_text_map[UI_IconKind_LeftCaret] = df_g_icon_kind_text_table[DF_IconKind_LeftCaret]; + icon_info.icon_kind_text_map[UI_IconKind_UpCaret] = df_g_icon_kind_text_table[DF_IconKind_UpCaret]; + icon_info.icon_kind_text_map[UI_IconKind_CheckHollow] = df_g_icon_kind_text_table[DF_IconKind_CheckHollow]; + icon_info.icon_kind_text_map[UI_IconKind_CheckFilled] = df_g_icon_kind_text_table[DF_IconKind_CheckFilled]; + } + + // rjf: begin & push initial stack values + ui_begin_build(events, ws->os, &nav_actions, &icon_info, df_dt(), df_dt()); + ui_push_font(main_font); + ui_push_font_size(main_font_size); + ui_push_pref_width(ui_em(20.f, 1)); + ui_push_pref_height(ui_em(2.25f, 1.f)); + ui_push_background_color(df_rgba_from_theme_color(DF_ThemeColor_PlainBackground)); + ui_push_text_color(df_rgba_from_theme_color(DF_ThemeColor_PlainText)); + ui_push_border_color(df_rgba_from_theme_color(DF_ThemeColor_PlainBorder)); + ui_push_text_select_color(df_rgba_from_theme_color(DF_ThemeColor_TextSelection)); + ui_push_text_cursor_color(df_rgba_from_theme_color(DF_ThemeColor_Cursor)); + ui_push_blur_size(10.f); + } + + //- rjf: calculate top-level rectangles + Rng2F32 window_rect = os_client_rect_from_window(ws->os); + Vec2F32 window_rect_dim = dim_2f32(window_rect); + Rng2F32 top_bar_rect = r2f32p(window_rect.x0, window_rect.y0, window_rect.x0+window_rect_dim.x, window_rect.y0+ui_top_pref_height().value); + Rng2F32 bottom_bar_rect = r2f32p(window_rect.x0, window_rect_dim.y - ui_top_pref_height().value, window_rect.x0+window_rect_dim.x, window_rect.y0+window_rect_dim.y); + Rng2F32 content_rect = r2f32p(window_rect.x0, top_bar_rect.y1, window_rect.x0+window_rect_dim.x, bottom_bar_rect.y0); + + //- rjf: drag/drop visualization tooltips + B32 drag_active = df_drag_is_active(); + if(drag_active && window_is_focused) + { + Temp scratch = scratch_begin(&arena, 1); + DF_DragDropPayload *payload = &df_g_drag_drop_payload; + DF_Panel *panel = df_panel_from_handle(payload->panel); + DF_Entity *entity = df_entity_from_handle(payload->entity); + DF_View *view = df_view_from_handle(payload->view); + UI_Tooltip + { + UI_Box *tooltip = ui_top_parent(); + if(!df_view_is_nil(view)) + { + ui_set_next_pref_width(ui_children_sum(1)); + UI_Row UI_HeightFill + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + String8 display_name = df_display_string_from_view(scratch.arena, ctrl_ctx, view); + DF_IconKind icon_kind = df_icon_kind_from_view(view); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + ui_label(df_g_icon_kind_text_table[icon_kind]); + ui_label(display_name); + tooltip->background_color = df_rgba_from_theme_color(DF_ThemeColor_TabActive); + } + } + if(!df_entity_is_nil(entity)) + { + ui_set_next_pref_width(ui_children_sum(1)); + UI_Row UI_HeightFill + { + String8 display_name = df_display_string_from_entity(scratch.arena, entity); + DF_IconKind icon_kind = df_g_entity_kind_icon_kind_table[entity->kind]; + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + ui_label(df_g_icon_kind_text_table[icon_kind]); + ui_label(display_name); + tooltip->background_color = df_rgba_from_theme_color(DF_ThemeColor_EntityBackground); + } + } + } + scratch_end(scratch); + } + + //- rjf: entity drop completion ctx menu + { + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_AltBackground)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_AltText)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_AltBorder)) + UI_CtxMenu(ws->drop_completion_ctx_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + DF_Entity *entity = df_entity_from_handle(ws->drop_completion_entity); + DF_Panel *panel = df_panel_from_handle(ws->drop_completion_panel); + if(df_entity_is_nil(entity)) + { + ui_ctx_menu_close(); + } + switch(entity->kind) + { + default:{}break; + + case DF_EntityKind_Module: + { + DF_Entity *bin_file = df_binary_file_from_module(entity); + if(df_icon_buttonf(DF_IconKind_Module, "Inspect Binary File Memory").clicked) + { + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + params.entity = df_handle_from_entity(bin_file); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); + ui_ctx_menu_close(); + } + if(df_icon_buttonf(DF_IconKind_Module, "View Binary File Disassembly").clicked) + { + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + params.entity = df_handle_from_entity(bin_file); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); + ui_ctx_menu_close(); + } + }break; + case DF_EntityKind_Process: + { + if(df_icon_buttonf(DF_IconKind_FileOutline, "Open Process Log").clicked) + { + DF_Entity *log = df_log_from_entity(entity); + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + params.entity = df_handle_from_entity(log); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Code)); + ui_ctx_menu_close(); + } + }break; + case DF_EntityKind_Thread: + { + if(df_icon_buttonf(DF_IconKind_FileOutline, "Open Thread Log").clicked) + { + DF_Entity *log = df_log_from_entity(entity); + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + params.entity = df_handle_from_entity(log); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Code)); + ui_ctx_menu_close(); + } + }break; + } + } + } + + //- rjf: developer menu + if(ws->dev_menu_is_open) + UI_Font(df_font_from_slot(DF_FontSlot_Code)) + UI_PaneF(r2f32p(30, 30, 30+ui_top_font_size()*100, ui_top_font_size()*150), "###dev_ctx_menu") + { + //- rjf: toggles + for(U64 idx = 0; idx < ArrayCount(DEV_toggle_table); idx += 1) + { + if(df_icon_button(*DEV_toggle_table[idx].value_ptr ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, DEV_toggle_table[idx].name).clicked) + { + *DEV_toggle_table[idx].value_ptr ^= 1; + } + } + + //- rjf: stats & info + { + //- rjf: draw per-window stats + for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) + { + // rjf: calc ui hash chain length + F64 avg_ui_hash_chain_length = 0; + { + F64 chain_count = 0; + F64 chain_length_sum = 0; + for(U64 idx = 0; idx < ws->ui->box_table_size; idx += 1) + { + F64 chain_length = 0; + for(UI_Box *b = ws->ui->box_table[idx].hash_first; !ui_box_is_nil(b); b = b->hash_next) + { + chain_length += 1; + } + if(chain_length > 0) + { + chain_length_sum += chain_length; + chain_count += 1; + } + } + avg_ui_hash_chain_length = chain_length_sum / chain_count; + } + ui_labelf("Ctrl Run Index: %I64u", ctrl_run_idx()); + ui_labelf("Window %p", window); + ui_set_next_pref_width(ui_children_sum(1)); + ui_set_next_pref_height(ui_children_sum(1)); + UI_Row + { + ui_spacer(ui_em(2.f, 1.f)); + ui_labelf("Box Count: %I64u", window->ui->last_build_box_count); + } + ui_set_next_pref_width(ui_children_sum(1)); + ui_set_next_pref_height(ui_children_sum(1)); + UI_Row + { + ui_spacer(ui_em(2.f, 1.f)); + ui_labelf("Average UI Hash Chain Length: %f", avg_ui_hash_chain_length); + } + } + + //- rjf: draw entity file tree +#if 0 + DF_EntityRec rec = {0}; + S32 indent = 0; + UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("Entity File Tree:"); + for(DF_Entity *e = df_entity_root(); !df_entity_is_nil(e); e = rec.next) + { + switch(e->kind) + { + default:{}break; + case DF_EntityKind_File: + case DF_EntityKind_OverrideFileLink: + { + ui_set_next_pref_width(ui_children_sum(1)); + ui_set_next_pref_height(ui_children_sum(1)); + UI_Row + { + ui_spacer(ui_em(2.f*indent, 1.f)); + if(e->kind == DF_EntityKind_File) + { + ui_label(e->name); + } + if(e->kind == DF_EntityKind_OverrideFileLink) + { + DF_Entity *dst = df_entity_from_handle(e->entity_handle); + ui_labelf("[link] %S -> %S", e->name, dst->name); + } + } + }break; + } + rec = df_entity_rec_df_pre(e, df_entity_root()); + indent += rec.push_count; + indent -= rec.pop_count; + } +#endif + } + } + + //- rjf: universal ctx menus + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_AltBackground)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_AltText)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_AltBorder)) + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: entity menu + UI_CtxMenu(ws->entity_ctx_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + DF_Entity *entity = df_entity_from_handle(ws->entity_ctx_menu_entity); + DF_IconKind entity_icon = df_g_entity_kind_icon_kind_table[entity->kind]; + DF_EntityKindFlags kind_flags = df_g_entity_kind_flags_table[entity->kind]; + DF_EntityOpFlags op_flags = df_g_entity_kind_op_flags_table[entity->kind]; + String8 display_name = df_display_string_from_entity(scratch.arena, entity); + + // rjf: title + UI_Row + { + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(2.f*1.5f, 1.f)) + UI_PrefHeight(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_label(df_g_icon_kind_text_table[entity_icon]); + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_label(df_g_entity_kind_display_string_table[entity->kind]); + { + Vec4F32 entity_color = ui_top_text_color(); + if(entity->flags & DF_EntityFlag_HasColor) + { + entity_color = df_rgba_from_entity(entity); + } + UI_TextColor(entity_color) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_Font((kind_flags & DF_EntityKindFlag_NameIsCode) ? df_font_from_slot(DF_FontSlot_Code) : ui_top_font()) + ui_label(display_name); + } + } + + // rjf: name editor + if(op_flags & DF_EntityOpFlag_Rename) + { + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, entity->name, "%S###entity_name_edit_%p", df_g_entity_kind_name_label_table[entity->kind], entity); + if(sig.commit) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + params.string = str8(ws->entity_ctx_menu_input_buffer, ws->entity_ctx_menu_input_size); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_NameEntity)); + } + } + + // rjf: condition editor + if(op_flags & DF_EntityOpFlag_Condition) UI_Font(df_font_from_slot(DF_FontSlot_Code)) + { + DF_Entity *condition = df_entity_child_from_kind(entity, DF_EntityKind_Condition); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border|DF_LineEditFlag_CodeContents, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, condition->name, "Condition###entity_cond_edit_%p", entity); + if(sig.commit) + { + String8 new_string = str8(ws->entity_ctx_menu_input_buffer, ws->entity_ctx_menu_input_size); + if(new_string.size != 0) + { + if(df_entity_is_nil(condition)) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + condition = df_entity_alloc(df_state_delta_history(), entity, DF_EntityKind_Condition); + } + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(condition); + params.string = new_string; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_NameEntity)); + } + else if(!df_entity_is_nil(condition)) + { + df_entity_mark_for_deletion(condition); + } + } + } + + // rjf: exe editor + if(entity->kind == DF_EntityKind_Target) + { + DF_Entity *exe = df_entity_child_from_kind(entity, DF_EntityKind_Executable); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, exe->name, "Executable###entity_exe_edit_%p", entity); + if(sig.commit) + { + String8 new_string = str8(ws->entity_ctx_menu_input_buffer, ws->entity_ctx_menu_input_size); + if(new_string.size != 0) + { + if(df_entity_is_nil(exe)) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + exe = df_entity_alloc(df_state_delta_history(), entity, DF_EntityKind_Executable); + } + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(exe); + params.string = new_string; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_NameEntity)); + } + else if(!df_entity_is_nil(exe)) + { + df_entity_mark_for_deletion(exe); + } + } + } + + // rjf: arguments editors + if(entity->kind == DF_EntityKind_Target) + { + DF_Entity *args = df_entity_child_from_kind(entity, DF_EntityKind_Arguments); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, args->name, "Arguments###entity_args_edit_%p", entity); + if(sig.commit) + { + String8 new_string = str8(ws->entity_ctx_menu_input_buffer, ws->entity_ctx_menu_input_size); + if(new_string.size != 0) + { + if(df_entity_is_nil(args)) + { + df_state_delta_history_push_batch(df_state_delta_history(), 0); + args = df_entity_alloc(df_state_delta_history(), entity, DF_EntityKind_Arguments); + } + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(args); + params.string = new_string; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_NameEntity)); + } + else if(!df_entity_is_nil(args)) + { + df_entity_mark_for_deletion(args); + } + } + } + + // rjf: copy name + if(df_icon_buttonf(DF_IconKind_Clipboard, "Copy Name").clicked) + { + os_set_clipboard_text(display_name); + ui_ctx_menu_close(); + } + + // rjf: is command line only? -> make permanent + if(entity->cfg_src == DF_CfgSrc_CommandLine && df_icon_buttonf(DF_IconKind_Save, "Save To Profile").clicked) + { + df_entity_equip_cfg_src(entity, DF_CfgSrc_Profile); + } + + // rjf: duplicate + if(op_flags & DF_EntityOpFlag_Duplicate && df_icon_buttonf(DF_IconKind_XSplit, "Duplicate").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DuplicateEntity)); + ui_ctx_menu_close(); + } + + // rjf: edit + if(op_flags & DF_EntityOpFlag_Edit && df_icon_buttonf(DF_IconKind_Pencil, "Edit").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EditEntity)); + ui_ctx_menu_close(); + } + + // rjf: deletion + if(op_flags & DF_EntityOpFlag_Delete && df_icon_buttonf(DF_IconKind_Trash, "Delete").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RemoveEntity)); + ui_ctx_menu_close(); + } + + // rjf: enabling + if(op_flags & DF_EntityOpFlag_Enable) + { + B32 is_enabled = entity->b32; + if(!is_enabled && df_icon_buttonf(DF_IconKind_CheckHollow, "Enable###enabler").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EnableEntity)); + } + if(is_enabled && df_icon_buttonf(DF_IconKind_CheckFilled, "Disable###enabler").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DisableEntity)); + } + } + + // rjf: freezing + if(op_flags & DF_EntityOpFlag_Freeze) + { + B32 is_frozen = df_entity_is_frozen(entity); + Vec4F32 color = df_rgba_from_theme_color(is_frozen ? DF_ThemeColor_FailureBackground : DF_ThemeColor_SuccessBackground); + color.x *= 0.7f; + color.y *= 0.7f; + color.z *= 0.7f; + ui_set_next_background_color(color); + if(is_frozen && df_icon_buttonf(DF_IconKind_Locked, "Thaw").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ThawEntity)); + } + if(!is_frozen && df_icon_buttonf(DF_IconKind_Unlocked, "Freeze").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FreezeEntity)); + } + } + + // rjf: go-to-text-location + if(entity->flags & DF_EntityFlag_HasTextPoint) + { + DF_Entity *file_ancestor = df_entity_ancestor_from_kind(entity, DF_EntityKind_File); + if(!df_entity_is_nil(file_ancestor) && df_icon_buttonf(DF_IconKind_FileOutline, "Go To Location").clicked) + { + Temp scratch = scratch_begin(&arena, 1); + DF_CmdParams params = df_cmd_params_from_window(ws); + params.file_path = df_full_path_from_entity(scratch.arena, file_ancestor); + params.text_point = entity->text_point; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + ui_ctx_menu_close(); + scratch_end(scratch); + } + } + + // rjf: go-to-vaddr-location + if(entity->flags & DF_EntityFlag_HasVAddr) + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx(); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + if(entity->vaddr != 0 && !df_entity_is_nil(thread) && df_icon_buttonf(DF_IconKind_FileOutline, "Go To Location").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(df_entity_ancestor_from_kind(thread, DF_EntityKind_Process)); + params.vaddr = entity->vaddr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + ui_ctx_menu_close(); + } + } + + // rjf: entity-kind-specific options + switch(entity->kind) + { + default: + { + }break; + + case DF_EntityKind_File: + { + if(entity->flags & DF_EntityFlag_IsFolder && + df_icon_buttonf(DF_IconKind_FolderOpenOutline, "Open File In Folder").clicked) + { + String8 path = df_full_path_from_entity(scratch.arena, entity); + String8 path_w_slash = push_str8f(scratch.arena, "%S/", path); + { + DF_CmdParams p = df_cmd_params_zero(); + p.file_path = path_w_slash; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetCurrentPath)); + } + { + DF_CmdParams p = df_cmd_params_from_window(ws); + p.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Open); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + ui_ctx_menu_close(); + } + if(!(entity->flags & DF_EntityFlag_IsFolder) && + !(entity->flags & DF_EntityFlag_IsMissing) && + df_icon_buttonf(DF_IconKind_FileOutline, "Go To File").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.file_path = df_full_path_from_entity(scratch.arena, entity); + params.text_point = txt_pt(1, 1); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + ui_ctx_menu_close(); + } + }break; + + case DF_EntityKind_Process: + case DF_EntityKind_Thread: + { + if(entity->kind == DF_EntityKind_Thread) + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx(); + B32 is_selected = df_handle_match(ctrl_ctx.thread, df_handle_from_entity(entity)); + if(is_selected) + { + df_icon_buttonf(DF_IconKind_Thread, "[Selected]"); + } + else if(df_icon_buttonf(DF_IconKind_Thread, "Select").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectThread)); + ui_ctx_menu_close(); + } + } + + if(df_icon_buttonf(DF_IconKind_Clipboard, "Copy ID").clicked) + { + U32 ctrl_id = entity->ctrl_id; + String8 string = push_str8f(scratch.arena, "%i", (int)ctrl_id); + os_set_clipboard_text(string); + ui_ctx_menu_close(); + } + + if(entity->kind == DF_EntityKind_Thread) + { + if(df_icon_buttonf(DF_IconKind_Clipboard, "Copy Instruction Pointer Address").clicked) + { + U64 rip = df_query_cached_rip_from_thread(entity); + String8 string = push_str8f(scratch.arena, "0x%I64x", rip); + os_set_clipboard_text(string); + ui_ctx_menu_close(); + } + } + + if(entity->kind == DF_EntityKind_Thread) + { + if(df_icon_buttonf(DF_IconKind_Clipboard, "Copy Call Stack").clicked) + { + DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); + DF_Unwind unwind = df_query_cached_unwind_from_thread(entity); + String8List lines = {0}; + for(DF_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next) + { + U64 rip_vaddr = frame->rip; + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); + String8 symbol = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + if(symbol.size != 0) + { + str8_list_pushf(scratch.arena, &lines, "0x%I64x: %S", rip_vaddr, symbol); + } + else + { + String8 module_filename = str8_skip_last_slash(module->name); + str8_list_pushf(scratch.arena, &lines, "0x%I64x: [??? in %S]", rip_vaddr, module_filename); + } + } + StringJoin join = {0}; + join.sep = join.post = str8_lit("\n"); + String8 text = str8_list_join(scratch.arena, &lines, &join); + os_set_clipboard_text(text); + ui_ctx_menu_close(); + } + } + + if(entity->kind == DF_EntityKind_Thread) + { + if(df_icon_buttonf(DF_IconKind_FileOutline, "Find").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); + ui_ctx_menu_close(); + } + } + }break; + + case DF_EntityKind_Module: + { + UI_Signal copy_full_path_sig = df_icon_buttonf(DF_IconKind_Clipboard, "Copy Full Path"); + if(copy_full_path_sig.clicked) + { + String8 string = entity->name; + os_set_clipboard_text(string); + ui_ctx_menu_close(); + } + if(copy_full_path_sig.hovering) UI_Tooltip + { + String8 string = entity->name; + ui_label(string); + } + if(df_icon_buttonf(DF_IconKind_Clipboard, "Copy Base Address").clicked) + { + Rng1U64 vaddr_rng = entity->vaddr_rng; + String8 string = push_str8f(scratch.arena, "0x%I64x", vaddr_rng.min); + os_set_clipboard_text(string); + ui_ctx_menu_close(); + } + if(df_icon_buttonf(DF_IconKind_Clipboard, "Copy Address Range Size").clicked) + { + Rng1U64 vaddr_rng = entity->vaddr_rng; + String8 string = push_str8f(scratch.arena, "0x%I64x", dim_1u64(vaddr_rng)); + os_set_clipboard_text(string); + ui_ctx_menu_close(); + } + }break; + + case DF_EntityKind_Target: + { + if(df_icon_buttonf(DF_IconKind_Play, "Launch And Run").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); + ui_ctx_menu_close(); + } + if(df_icon_buttonf(DF_IconKind_PlayStepForward, "Launch And Initialize").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndInit)); + ui_ctx_menu_close(); + } + }break; + } + + // rjf: color editor + { + B32 entity_has_color = entity->flags & DF_EntityFlag_HasColor; + if(entity_has_color) + { + UI_Padding(ui_em(1.5f, 1.f)) + { + ui_set_next_pref_height(ui_em(9.f, 1.f)); + UI_Row UI_Padding(ui_pct(1, 0)) + { + UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(9.f, 1.f)) UI_Column UI_PrefHeight(ui_em(1.5f, 0.f)) + { + Vec4F32 presets[] = + { + v4f32(1.0f, 0.2f, 0.1f, 1.0f), + v4f32(1.0f, 0.8f, 0.2f, 1.0f), + v4f32(0.3f, 0.8f, 0.2f, 1.0f), + v4f32(0.1f, 0.8f, 0.4f, 1.0f), + v4f32(0.1f, 0.6f, 0.8f, 1.0f), + v4f32(0.5f, 0.3f, 0.8f, 1.0f), + v4f32(0.8f, 0.3f, 0.5f, 1.0f), + }; + UI_CornerRadius(ui_em(0.3f, 1.f).value) + for(U64 preset_idx = 0; preset_idx < ArrayCount(presets); preset_idx += 1) + { + ui_set_next_background_color(presets[preset_idx]); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_Clickable| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "###color_preset_%i", (int)preset_idx); + UI_Signal sig = ui_signal_from_box(box); + if(sig.clicked) + { + Vec3F32 hsv = hsv_from_rgb(v3f32(presets[preset_idx].x, presets[preset_idx].y, presets[preset_idx].z)); + Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, 1); + entity->color_hsva = hsva; + } + ui_spacer(ui_em(0.3f, 1.f)); + } + } + + ui_spacer(ui_em(0.75f, 1.f)); + + UI_PrefWidth(ui_em(9.f, 1.f)) UI_PrefHeight(ui_em(9.f, 1.f)) + { + ui_sat_val_pickerf(entity->color_hsva.x, &entity->color_hsva.y, &entity->color_hsva.z, "###ent_satval_picker"); + } + + ui_spacer(ui_em(0.75f, 1.f)); + + UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(9.f, 1.f)) + ui_hue_pickerf(&entity->color_hsva.x, entity->color_hsva.y, entity->color_hsva.z, "###ent_hue_picker"); + } + } + + UI_Row UI_Padding(ui_pct(1, 0)) UI_PrefWidth(ui_em(12.f, 1.f)) UI_CornerRadius(8.f) + { + if(df_icon_buttonf(DF_IconKind_Trash, "Remove Color").clicked) + { + entity->flags &= ~DF_EntityFlag_HasColor; + } + } + + ui_spacer(ui_em(1.5f, 1.f)); + } + if(!entity_has_color && df_icon_buttonf(DF_IconKind_Palette, "Equip With Color").clicked) + { + df_entity_equip_color_rgba(entity, v4f32(1, 1, 1, 1)); + } + } + } + + //- rjf: tab menu + UI_CtxMenu(ws->tab_ctx_menu_key) UI_PrefWidth(ui_em(25.f, 1.f)) UI_CornerRadius(0) + { + DF_View *view = df_view_from_handle(ws->tab_ctx_menu_view); + DF_IconKind view_icon = df_icon_kind_from_view(view); + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + String8 display_name = df_display_string_from_view(scratch.arena, ctrl_ctx, view); + + // rjf: title + UI_Row + { + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(3.f, 1.f)) + UI_PrefHeight(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_label(df_g_icon_kind_text_table[view_icon]); + UI_PrefWidth(ui_text_dim(10, 1)) ui_label(display_name); + } + + // rjf: copy name + if(df_icon_buttonf(DF_IconKind_Clipboard, "Copy Name").clicked) + { + os_set_clipboard_text(display_name); + ui_ctx_menu_close(); + } + + // rjf: copy full path + if(entity->kind == DF_EntityKind_File) + { + UI_Signal copy_full_path_sig = df_icon_buttonf(DF_IconKind_Clipboard, "Copy Full Path"); + String8 full_path = df_full_path_from_entity(scratch.arena, entity); + if(copy_full_path_sig.clicked) + { + os_set_clipboard_text(full_path); + ui_ctx_menu_close(); + } + if(copy_full_path_sig.hovering) UI_Tooltip + { + ui_label(full_path); + } + } + + // rjf: close tab + if(df_icon_buttonf(DF_IconKind_X, "Close Tab").clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + { + params.view = df_handle_from_view(view); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_View); + } + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseTab)); + ui_ctx_menu_close(); + } + + } + + scratch_end(scratch); + } + + //- rjf: build auto-complete lister + ProfScope("build autocomplete lister") + if(!ws->autocomp_force_closed && !ui_key_match(ws->autocomp_root_key, ui_key_zero()) && ws->autocomp_last_frame_idx+1 >= df_frame_index()) + { + String8 query = str8(ws->autocomp_lister_query_buffer, ws->autocomp_lister_query_size); + UI_Box *autocomp_root_box = ui_box_from_key(ws->autocomp_root_key); + if(!ui_box_is_nil(autocomp_root_box)) + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: unpack lister params + DF_CtrlCtx ctrl_ctx = ws->autocomp_ctrl_ctx; + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); + U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + + //- rjf: unpack query words + String8List search_needles = {0}; + { + U8 splits[] = {' '}; + search_needles = str8_split(scratch.arena, query, splits, ArrayCount(splits), 0); + } + + //- rjf: gather lister items + DF_AutoCompListerItemChunkList item_list = {0}; + { + if(ws->autocomp_lister_flags & DF_AutoCompListerFlag_Locals) + { + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, thread_rip_voff); + for(U64 slot_idx = 0; slot_idx < locals_map->slots_count; slot_idx += 1) + { + for(EVAL_String2NumMapNode *n = locals_map->slots[slot_idx].first; n != 0; n = n->next) + { + DF_AutoCompListerItem item = {0}; + { + item.string = n->string; + item.kind_string = str8_lit("Local"); + item.matches = df_fuzzy_match_find(scratch.arena, search_needles, n->string); + } + if(search_needles.node_count == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } + } + if(ws->autocomp_lister_flags & DF_AutoCompListerFlag_Registers) + { + Architecture arch = df_architecture_from_entity(thread); + U64 reg_names_count = regs_reg_code_count_from_architecture(arch); + U64 alias_names_count = regs_alias_code_count_from_architecture(arch); + String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); + String8 *alias_names = regs_alias_code_string_table_from_architecture(arch); + for(U64 idx = 0; idx < reg_names_count; idx += 1) + { + if(reg_names[idx].size != 0) + { + DF_AutoCompListerItem item = {0}; + { + item.string = reg_names[idx]; + item.kind_string = str8_lit("Register"); + item.matches = df_fuzzy_match_find(scratch.arena, search_needles, reg_names[idx]); + } + if(search_needles.node_count == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } + for(U64 idx = 0; idx < alias_names_count; idx += 1) + { + if(alias_names[idx].size != 0) + { + DF_AutoCompListerItem item = {0}; + { + item.string = alias_names[idx]; + item.kind_string = str8_lit("Reg. Alias"); + item.matches = df_fuzzy_match_find(scratch.arena, search_needles, alias_names[idx]); + } + if(search_needles.node_count == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } + } + if(ws->autocomp_lister_flags & DF_AutoCompListerFlag_ViewRules) + { + for(U64 slot_idx = 0; slot_idx < df_state->view_rule_spec_table_size; slot_idx += 1) + { + for(DF_CoreViewRuleSpec *spec = df_state->view_rule_spec_table[slot_idx]; spec != 0 && spec != &df_g_nil_core_view_rule_spec; spec = spec->hash_next) + { + DF_AutoCompListerItem item = {0}; + { + item.string = spec->info.string; + item.kind_string = str8_lit("View Rule"); + item.matches = df_fuzzy_match_find(scratch.arena, search_needles, spec->info.string); + } + if(search_needles.node_count == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } + } + } + + //- rjf: lister item list -> sorted array + DF_AutoCompListerItemArray item_array = df_autocomp_lister_item_array_from_chunk_list(scratch.arena, &item_list); + df_autocomp_lister_item_array_sort__in_place(&item_array); + + //- rjf: animate toward capped number of items + F32 rate = 1 - pow_f32(2, (-40.f * df_dt())); + F32 target = Min((F32)item_array.count, 8.f); + if(abs_f32(target - ws->autocomp_num_visible_rows_t) > 0.01f) + { + df_gfx_request_frame(); + } + ws->autocomp_num_visible_rows_t += (target - ws->autocomp_num_visible_rows_t) * rate; + if(abs_f32(target - ws->autocomp_num_visible_rows_t) <= 0.02f) + { + ws->autocomp_num_visible_rows_t = target; + } + + //- rjf: build + if(item_array.count != 0) UI_Focus(1) + { + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + ui_set_next_fixed_x(autocomp_root_box->rect.x0); + ui_set_next_fixed_y(autocomp_root_box->rect.y1); + ui_set_next_pref_width(ui_em(25.f, 1.f)); + ui_set_next_pref_height(ui_px(row_height_px*ws->autocomp_num_visible_rows_t, 1.f)); + ui_set_next_child_layout_axis(Axis2_Y); + ui_set_next_corner_radius_01(ui_top_font_size()*0.25f); + ui_set_next_corner_radius_11(ui_top_font_size()*0.25f); + ui_set_next_corner_radius_10(ui_top_font_size()*0.25f); + autocomp_box = ui_build_box_from_stringf(UI_BoxFlag_DefaultFocusNavY|UI_BoxFlag_Clip|UI_BoxFlag_RoundChildrenByParent|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBackground, "autocomp_box"); + UI_Parent(autocomp_box) UI_WidthFill UI_PrefHeight(ui_px(row_height_px, 1.f)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_HoverCursor(OS_Cursor_HandPoint) + { + for(U64 idx = 0; idx < item_array.count; idx += 1) + { + DF_AutoCompListerItem *item = &item_array.v[idx]; + UI_Box *item_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawActiveEffects|UI_BoxFlag_Clickable, "autocomp_%I64x", idx); + UI_Parent(item_box) + { + UI_WidthFill ui_label(item->string); + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_label(item->kind_string); + } + UI_Signal item_sig = ui_signal_from_box(item_box); + if(item_sig.clicked) + { + UI_NavAction autocomp_action = {UI_NavActionFlag_ReplaceAndCommit, {0}, (UI_NavDeltaUnit)0, push_str8_copy(ui_build_arena(), item->string)}; + ui_nav_action_list_push(ui_build_arena(), ui_nav_actions(), autocomp_action); + } + } + } + } + + scratch_end(scratch); + } + } + + //- rjf: build hover eval + ProfScope("build hover eval") + { + if(ws->hover_eval_string.size == 0) + { + ws->hover_eval_num_visible_rows_t = 0; + } + if(ws->hover_eval_string.size != 0 && !hover_eval_is_open && ws->hover_eval_last_frame_idx < ws->hover_eval_first_frame_idx+20 && df_frame_index()-ws->hover_eval_last_frame_idx < 50) + { + df_gfx_request_frame(); + ws->hover_eval_num_visible_rows_t = 0; + } + if(ws->hover_eval_string.size != 0 && hover_eval_is_open) UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + { + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + DF_CtrlCtx ctrl_ctx = ws->hover_eval_ctrl_ctx; + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); + DF_Entity *module = df_module_from_process_vaddr(process, thread_unwind_rip_vaddr); + U64 thread_unwind_rip_voff = df_voff_from_vaddr(module, thread_unwind_rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_module_voff(scope, module, thread_unwind_rip_voff); + String8 expr = ws->hover_eval_string; + DF_Eval eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, expr); + + //- rjf: build if good + if(!tg_key_match(eval.type_key, tg_key_zero()) && !ui_any_ctx_menu_is_open()) UI_Focus(hover_eval_is_open && !ui_any_ctx_menu_is_open() && !any_query_is_focused) + { + //- rjf: eval -> viz artifacts + F32 row_height = ui_top_font_size()*2.f; + DF_CfgTable cfg_table = {0}; + U64 expr_hash = df_hash_from_string(expr); + DF_EvalViewKey eval_view_key = df_eval_view_key_from_stringf("eval_hover_%I64x", expr_hash); + DF_EvalView *eval_view = df_eval_view_from_key(eval_view_key); + DF_EvalVizBlockList viz_blocks = df_eval_viz_block_list_from_eval_view_expr(scratch.arena, scope, &ctrl_ctx, &parse_ctx, eval_view, expr); + DF_EvalVizWindowedRowList viz_rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, 10, ui_top_font(), ui_top_font_size(), r1s64(0, 50), &viz_blocks); + + //- rjf: build hover eval box + F32 fish_rate = 1 - pow_f32(2, (-40.f * df_dt())); + F32 hover_eval_container_height_target = row_height * Min(30, viz_blocks.total_visual_row_count); + ws->hover_eval_num_visible_rows_t += (hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) * fish_rate; + if(abs_f32(hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) > 0.5f) + { + df_gfx_request_frame(); + } + else + { + ws->hover_eval_num_visible_rows_t = hover_eval_container_height_target; + } + F32 hover_eval_container_height = ws->hover_eval_num_visible_rows_t; + F32 corner_radius = ui_top_font_size()*0.25f; + ui_set_next_fixed_x(ws->hover_eval_spawn_pos.x); + ui_set_next_fixed_y(ws->hover_eval_spawn_pos.y); + ui_set_next_pref_width(ui_children_sum(1)); + ui_set_next_pref_height(ui_px(hover_eval_container_height, 1.f)); + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_AltBackground)); + ui_set_next_corner_radius_00(0); + ui_set_next_corner_radius_01(corner_radius); + ui_set_next_corner_radius_10(corner_radius); + ui_set_next_corner_radius_11(corner_radius); + ui_set_next_child_layout_axis(Axis2_Y); + hover_eval_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_DrawDropShadow| + UI_BoxFlag_Clip| + UI_BoxFlag_AllowOverflowY| + UI_BoxFlag_ViewScroll| + UI_BoxFlag_Floating| + UI_BoxFlag_AnimatePos| + UI_BoxFlag_Clickable| + UI_BoxFlag_DefaultFocusNav, + "###hover_eval"); + + //- rjf: build contents + UI_Parent(hover_eval_box) UI_PrefHeight(ui_px(row_height, 1.f)) + { + //- rjf: build rows + for(DF_EvalVizRow *row = viz_rows.first; row != 0; row = row->next) + { + UI_PrefWidth(ui_children_sum(1)) UI_Row + { + ui_spacer(ui_em(0.75f, 1.f)); + ui_spacer(ui_em(1.5f*row->depth, 1.f)); + U64 row_hash = df_hash_from_expand_key(row->key); + B32 row_is_expanded = df_expand_key_is_set(&eval_view->expand_tree_table, row->key); + if(row->flags & DF_EvalVizRowFlag_CanExpand) UI_PrefWidth(ui_em(1.5f, 1)) if(ui_expanderf(row_is_expanded, "###%I64x_%I64x_is_expanded", row->key.parent_hash, row->key.child_num).pressed) + { + df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, row->parent_key, row->key, !row_is_expanded); + } + UI_PrefWidth(ui_em(30.f, 1.f)) + { + UI_PrefWidth(ui_text_dim(10, 1.f)) df_code_label(1.f, 1, row->expr); + ui_spacer(ui_em(1.5f, 1.f)); + if(row->flags & DF_EvalVizRowFlag_CanEditValue) + { + UI_Signal sig = df_line_editf(DF_LineEditFlag_CodeContents| + DF_LineEditFlag_DisplayStringIsCode| + DF_LineEditFlag_PreferDisplayString| + DF_LineEditFlag_Border, + 0, &ws->hover_eval_txt_cursor, &ws->hover_eval_txt_mark, ws->hover_eval_txt_buffer, sizeof(ws->hover_eval_txt_buffer), &ws->hover_eval_txt_size, 0, row->edit_value, "%S###val_%I64x", row->display_value, row_hash); + if(sig.commit) + { + String8 commit_string = str8(ws->hover_eval_txt_buffer, ws->hover_eval_txt_size); + DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, commit_string); + B32 success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdbg, &ctrl_ctx, row->eval, write_eval); + if(success == 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.string = str8_lit("Could not commit value successfully."); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + } + } + else + { + df_code_label(1.f, 1, row->display_value); + } + } + ui_spacer(ui_em(0.75f, 1.f)); + if(row == viz_rows.first) + { + ui_spacer(ui_em(3.f, 1.f)); + UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_em(3.f, 1.f)) + UI_CornerRadius00(0) + UI_CornerRadius01(0) + UI_CornerRadius10(0) + UI_CornerRadius11(0) + { + UI_Signal watch_sig = df_icon_buttonf(DF_IconKind_List, "###watch_hover_eval"); + if(watch_sig.hovering) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + { + ui_labelf("Add the hovered expression to an opened watch view."); + } + if(watch_sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.string = expr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); + } + } + if(!df_entity_is_nil(df_entity_from_handle(ws->hover_eval_file))) + UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_em(3.f, 1.f)) + UI_CornerRadius10(corner_radius) + UI_CornerRadius11(corner_radius) + { + UI_Signal pin_sig = df_icon_buttonf(DF_IconKind_Pin, "###pin_hover_eval"); + if(pin_sig.hovering) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + UI_CornerRadius00(0) + UI_CornerRadius01(0) + UI_CornerRadius10(0) + UI_CornerRadius11(0) + { + ui_labelf("Pin the hovered expression to this code location."); + } + if(pin_sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + if(ws->hover_eval_vaddr != 0) + { + params.vaddr = ws->hover_eval_vaddr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + } + else + { + params.entity = ws->hover_eval_file; + params.text_point = ws->hover_eval_file_pt; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + } + params.string = expr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchPin)); + } + } + } + } + } + UI_PrefWidth(ui_px(0, 0)) ui_spacer(ui_px(hover_eval_container_height-row_height, 1.f)); + } + + //- rjf: interact + { + UI_Signal hover_eval_sig = ui_signal_from_box(hover_eval_box); + if(hover_eval_sig.mouse_over) + { + ws->hover_eval_last_frame_idx = df_frame_index(); + } + else if(ws->hover_eval_last_frame_idx+2 < df_frame_index()) + { + df_gfx_request_frame(); + } + } + } + + dbgi_scope_close(scope); + scratch_end(scratch); + } + } + + //- rjf: top bar + ProfScope("build top bar") + { + ui_set_next_flags(UI_BoxFlag_DefaultFocusNav); + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_AltBackground)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_AltText)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_AltBorder)) + UI_Focus(ws->menu_bar_focused && window_is_focused && !ui_any_ctx_menu_is_open() && !hover_eval_is_open) + UI_Pane(top_bar_rect, str8_lit("###top_bar")) + UI_WidthFill UI_Row + { + MemoryZeroArray(ui_top_parent()->parent->corner_radii); + + // rjf: menu items + UI_PrefWidth(ui_text_dim(20, 1)) + { + // rjf: file menu + UI_Key file_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_file_menu_key_")); + UI_CtxMenu(file_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + DF_CoreCmdKind cmds[] = + { + DF_CoreCmdKind_Open, + DF_CoreCmdKind_LoadUser, + DF_CoreCmdKind_LoadProfile, + DF_CoreCmdKind_Exit, + }; + U32 codepoints[] = + { + 'o', + 'u', + 'p', + 'x', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + df_cmd_list_menu_buttons(ws, ArrayCount(cmds), cmds, codepoints); + } + + // rjf: window menu + UI_Key window_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_window_menu_key_")); + UI_CtxMenu(window_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + DF_CoreCmdKind cmds[] = + { + DF_CoreCmdKind_OpenWindow, + DF_CoreCmdKind_CloseWindow, + DF_CoreCmdKind_ToggleFullscreen, + }; + U32 codepoints[] = + { + 'w', + 'c', + 'f', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + df_cmd_list_menu_buttons(ws, ArrayCount(cmds), cmds, codepoints); + } + + // rjf: panel menu + UI_Key panel_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_panel_menu_key_")); + UI_CtxMenu(panel_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + DF_CoreCmdKind cmds[] = + { + DF_CoreCmdKind_NewPanelRight, + DF_CoreCmdKind_NewPanelDown, + DF_CoreCmdKind_ClosePanel, + DF_CoreCmdKind_RotatePanelColumns, + DF_CoreCmdKind_NextPanel, + DF_CoreCmdKind_PrevPanel, + DF_CoreCmdKind_CloseTab, + DF_CoreCmdKind_NextTab, + DF_CoreCmdKind_PrevTab, + DF_CoreCmdKind_TabBarTop, + DF_CoreCmdKind_TabBarBottom, + DF_CoreCmdKind_ResetToDefaultPanels, + }; + U32 codepoints[] = + { + 'r', + 'd', + 'x', + 'c', + 'n', + 'p', + 't', + 'b', + 'v', + 0, + 0, + 0, + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + df_cmd_list_menu_buttons(ws, ArrayCount(cmds), cmds, codepoints); + } + + // rjf: view menu + UI_Key view_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_view_menu_key_")); + UI_CtxMenu(view_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + DF_CoreCmdKind cmds[] = + { + DF_CoreCmdKind_Commands, + DF_CoreCmdKind_Targets, + DF_CoreCmdKind_Scheduler, + DF_CoreCmdKind_CallStack, + DF_CoreCmdKind_Modules, + DF_CoreCmdKind_Output, + DF_CoreCmdKind_Memory, + DF_CoreCmdKind_Disassembly, + DF_CoreCmdKind_Watch, + DF_CoreCmdKind_Locals, + DF_CoreCmdKind_Registers, + DF_CoreCmdKind_Breakpoints, + DF_CoreCmdKind_WatchPins, + DF_CoreCmdKind_FilePathMap, + DF_CoreCmdKind_Theme, + DF_CoreCmdKind_ExceptionFilters, + }; + U32 codepoints[] = + { + 'c', + 't', + 's', + 'k', + 'd', + 'o', + 'm', + 'y', + 'w', + 'l', + 'r', + 'b', + 'h', + 'p', + 'e', + 'g', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + df_cmd_list_menu_buttons(ws, ArrayCount(cmds), cmds, codepoints); + } + + // rjf: targets menu + UI_Key targets_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_targets_menu_key_")); + UI_CtxMenu(targets_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + Temp scratch = scratch_begin(&arena, 1); + DF_CoreCmdKind cmds[] = + { + DF_CoreCmdKind_AddTarget, + DF_CoreCmdKind_EditTarget, + DF_CoreCmdKind_RemoveTarget, + }; + U32 codepoints[] = + { + 'a', + 'e', + 'r', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + df_cmd_list_menu_buttons(ws, ArrayCount(cmds), cmds, codepoints); + DF_EntityList targets_list = df_query_cached_entity_list_with_kind(DF_EntityKind_Target); + for(DF_EntityNode *n = targets_list.first; n != 0; n = n->next) + { + DF_Entity *target = n->entity; + Vec4F32 color = ui_top_text_color(); + if(target->flags & DF_EntityFlag_HasColor) + { + color = df_rgba_from_entity(target); + } + String8 target_name = df_display_string_from_entity(scratch.arena, target); + UI_Signal sig = {0}; + UI_TextColor(color) + sig = df_icon_buttonf(DF_IconKind_Target, "%S##%p", target_name, target); + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(target); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EditTarget)); + ui_ctx_menu_close(); + ws->menu_bar_focused = 0; + } + } + scratch_end(scratch); + } + + // rjf: ctrl menu + UI_Key ctrl_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_ctrl_menu_key_")); + UI_CtxMenu(ctrl_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + DF_CoreCmdKind cmds[] = + { + DF_CoreCmdKind_Run, + DF_CoreCmdKind_KillAll, + DF_CoreCmdKind_Restart, + DF_CoreCmdKind_Halt, + DF_CoreCmdKind_SoftHaltRefresh, + DF_CoreCmdKind_StepInto, + DF_CoreCmdKind_StepOver, + DF_CoreCmdKind_StepOut, + DF_CoreCmdKind_Attach, + }; + U32 codepoints[] = + { + 'r', + 'k', + 's', + 'h', + 'f', + 'i', + 'o', + 't', + 'a', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + df_cmd_list_menu_buttons(ws, ArrayCount(cmds), cmds, codepoints); + } + + // rjf: help menu + UI_Key help_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_help_menu_key_")); + UI_CtxMenu(help_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + ui_labelf("The RAD Debugger (ALPHA) - %s", __DATE__); + ui_spacer(ui_em(0.75f, 1.f)); + ui_label_multiline(ui_top_font_size()*30.f, str8_lit("If you run into issues, please send an email describing them to:")); + UI_TextAlignment(UI_TextAlign_Center) + { + UI_Signal email_sig = ui_buttonf("ryan.fleury@epicgames.com"); + if(email_sig.hovering) UI_Tooltip + { + ui_labelf("Copy To Clipboard"); + } + if(email_sig.clicked) + { + os_set_clipboard_text(str8_lit("ryan.fleury@epicgames.com")); + } + } + } + + // rjf: buttons + UI_TextAlignment(UI_TextAlign_Center) UI_HeightFill + { + // rjf: set up table + struct + { + String8 name; + U32 codepoint; + OS_Key key; + UI_Key menu_key; + } + items[] = + { + {str8_lit("File"), 'f', OS_Key_F, file_menu_key}, + {str8_lit("Window"), 'w', OS_Key_W, window_menu_key}, + {str8_lit("Panel"), 'p', OS_Key_P, panel_menu_key}, + {str8_lit("View"), 'v', OS_Key_V, view_menu_key}, + {str8_lit("Targets"), 't', OS_Key_T, targets_menu_key}, + {str8_lit("Control"), 'c', OS_Key_C, ctrl_menu_key}, + {str8_lit("Help"), 'h', OS_Key_H, help_menu_key}, + }; + + // rjf: determine if one of the menus is already open + B32 menu_open = 0; + U64 open_menu_idx = 0; + for(U64 idx = 0; idx < ArrayCount(items); idx += 1) + { + if(ui_ctx_menu_is_open(items[idx].menu_key)) + { + menu_open = 1; + open_menu_idx = idx; + break; + } + } + + // rjf: navigate between menus + U64 open_menu_idx_prime = open_menu_idx; + if(menu_open && ws->menu_bar_focused && window_is_focused) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; + n != 0; + n = next) + { + next = n->next; + UI_NavAction *action = &n->v; + B32 taken = 0; + if(action->delta.x > 0) + { + taken = 1; + open_menu_idx_prime += 1; + open_menu_idx_prime = open_menu_idx_prime%ArrayCount(items); + } + if(action->delta.x < 0) + { + taken = 1; + open_menu_idx_prime = open_menu_idx_prime > 0 ? open_menu_idx_prime-1 : (ArrayCount(items)-1); + } + if(taken) + { + ui_nav_eat_action_node(nav_actions, n); + } + } + } + + // rjf: make ui + for(U64 idx = 0; idx < ArrayCount(items); idx += 1) + { + ui_set_next_fastpath_codepoint(items[idx].codepoint); + B32 alt_fastpath_key = 0; + if(os_key_press(ui_events(), ui_window(), OS_EventFlag_Alt, items[idx].key)) + { + alt_fastpath_key = 1; + } + if((ws->menu_bar_key_held || ws->menu_bar_focused) && !ui_any_ctx_menu_is_open()) + { + ui_set_next_flags(UI_BoxFlag_DrawTextFastpathCodepoint); + } + UI_Signal sig = df_menu_bar_button(items[idx].name); + if(menu_open) + { + if((sig.hovering && !ui_ctx_menu_is_open(items[idx].menu_key)) || (open_menu_idx_prime == idx && open_menu_idx_prime != open_menu_idx)) + { + ui_ctx_menu_open(items[idx].menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + } + } + else if(sig.pressed || alt_fastpath_key) + { + if(ui_ctx_menu_is_open(items[idx].menu_key)) + { + ui_ctx_menu_close(); + } + else + { + ui_ctx_menu_open(items[idx].menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + } + } + } + } + } + + ui_spacer(ui_em(0.75f, 1)); + + // rjf: conversion task visualization + UI_PrefWidth(ui_text_dim(10, 1)) UI_HeightFill UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight1)) + { + Temp scratch = scratch_begin(&arena, 1); + DF_EntityList tasks = df_query_cached_entity_list_with_kind(DF_EntityKind_ConversionTask); + for(DF_EntityNode *n = tasks.first; n != 0; n = n->next) + { + DF_Entity *task = n->entity; + String8 raddbg_path = task->name; + String8 raddbg_name = str8_skip_last_slash(raddbg_path); + String8 task_text = push_str8f(scratch.arena, "Creating %S...", raddbg_name); + UI_Key key = ui_key_from_stringf(ui_key_zero(), "task_%p", task); + UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawText|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, key); + UI_Signal sig = ui_signal_from_box(box); + if(sig.hovering) UI_Tooltip + { + ui_label(raddbg_path); + } + ui_box_equip_display_string(box, task_text); + } + scratch_end(scratch); + } + + ui_spacer(ui_pct(1, 0)); + + // rjf: loaded user viz + { + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_Highlight1)); + ui_set_next_pref_width(ui_children_sum(1)); + ui_set_next_child_layout_axis(Axis2_X); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *user_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "###loaded_user_button"); + UI_Parent(user_box) UI_PrefWidth(ui_text_dim(10, 1)) UI_TextAlignment(UI_TextAlign_Center) + { + String8 user_path = df_cfg_path_from_src(DF_CfgSrc_User); + UI_Font(ui_icon_font()) ui_label(df_g_icon_kind_text_table[DF_IconKind_Person]); + ui_label(str8_skip_last_slash(user_path)); + } + UI_Signal user_sig = ui_signal_from_box(user_box); + if(user_sig.clicked) + { + DF_CmdParams p = df_cmd_params_from_window(ws); + p.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LoadUser); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + } + + ui_spacer(ui_em(0.75f, 1)); + + // rjf: loaded profile viz + { + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + ui_set_next_pref_width(ui_children_sum(1)); + ui_set_next_child_layout_axis(Axis2_X); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *prof_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "###loaded_profile_button"); + UI_Parent(prof_box) UI_PrefWidth(ui_text_dim(10, 1)) UI_TextAlignment(UI_TextAlign_Center) + { + String8 prof_path = df_cfg_path_from_src(DF_CfgSrc_Profile); + UI_Font(ui_icon_font()) ui_label(df_g_icon_kind_text_table[DF_IconKind_Briefcase]); + ui_label(str8_skip_last_slash(prof_path)); + } + UI_Signal prof_sig = ui_signal_from_box(prof_box); + if(prof_sig.clicked) + { + DF_CmdParams p = df_cmd_params_from_window(ws); + p.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LoadProfile); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + } + + ui_spacer(ui_em(0.75f, 1)); + + // rjf: fast-paths + UI_PrefWidth(ui_em(2.25f, 1)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + { + Temp scratch = scratch_begin(&arena, 1); + DF_EntityList targets = df_push_active_target_list(scratch.arena); + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + B32 have_targets = targets.count != 0; + B32 can_send_signal = !df_ctrl_targets_running(); + B32 can_play = (have_targets && can_send_signal); + B32 can_pause = (!can_send_signal); + B32 can_stop = (processes.count != 0); + + if(can_play || !have_targets) UI_TextAlignment(UI_TextAlign_Center) UI_Flags((can_play ? 0 : UI_BoxFlag_Disabled)) + { + UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Play]); + if(sig.hovering && can_play == 0) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + ui_labelf("Disabled: %s", have_targets ? "Targets are currently running" : "No active targets exist"); + } + if(sig.hovering && can_play) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + { + if(can_stop) + { + ui_labelf("Resume all processes"); + } + else + { + ui_labelf("Launch all active targets:"); + for(DF_EntityNode *n = targets.first; n != 0; n = n->next) + { + ui_label(n->entity->name); + } + } + } + } + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Run)); + } + } + + if(!can_play && have_targets && !can_send_signal) UI_TextAlignment(UI_TextAlign_Center) + { + UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Redo]); + if(sig.hovering) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + { + ui_labelf("Restart all running targets:"); + { + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + for(DF_EntityNode *n = processes.first; n != 0; n = n->next) + { + DF_Entity *process = n->entity; + DF_Entity *target = df_entity_from_handle(process->entity_handle); + if(!df_entity_is_nil(target)) + { + ui_label(target->name); + } + } + } + } + } + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Restart)); + } + } + + UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_pause ? 0 : UI_BoxFlag_Disabled) + { + UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Pause]); + if(sig.hovering && can_pause == 0) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + ui_labelf("Disabled: Already halted"); + } + if(sig.hovering && can_pause) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + ui_labelf("Halt all target processes"); + } + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Halt)); + } + } + + UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_stop ? 0 : UI_BoxFlag_Disabled) + { + UI_Signal sig = {0}; + { + sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Stop]); + } + if(sig.hovering && can_stop == 0) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + ui_labelf("Disabled: No processes are running"); + } + if(sig.hovering && can_stop) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + ui_labelf("Kill all target processes"); + } + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Kill)); + } + } + scratch_end(scratch); + } + } + } + + //- rjf: bottom bar + ProfScope("build bottom bar") + { + B32 is_running = df_ctrl_targets_running() && df_ctrl_last_run_frame_idx() < df_frame_index(); + CTRL_Event stop_event = df_ctrl_last_stop_event(); + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + if(!is_running) + { + switch(stop_event.cause) + { + default: + case CTRL_EventCause_Finished: + { + color = df_rgba_from_theme_color(DF_ThemeColor_Highlight1); + }break; + case CTRL_EventCause_UserBreakpoint: + case CTRL_EventCause_InterruptedByException: + case CTRL_EventCause_InterruptedByTrap: + case CTRL_EventCause_InterruptedByHalt: + { + color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + }break; + } + } + if(ws->error_t > 0.01f) + { + Vec4F32 failure_bg = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + color.x += (failure_bg.x-color.x)*ws->error_t; + color.y += (failure_bg.y-color.y)*ws->error_t; + color.z += (failure_bg.z-color.z)*ws->error_t; + color.w += (failure_bg.w-color.w)*ws->error_t; + } + UI_Flags(UI_BoxFlag_DrawBackground) UI_BackgroundColor(color) UI_CornerRadius(0) + UI_Pane(bottom_bar_rect, str8_lit("###bottom_bar")) UI_WidthFill UI_Row + UI_Flags(0) + { + // rjf: developer frame-time indicator + if(DEV_updating_indicator) + { + F32 animation_t = pow_f32(sin_f32(df_time_in_seconds()/2.f), 2.f); + ui_spacer(ui_em(0.3f, 1.f)); + ui_spacer(ui_em(1.5f*animation_t, 1.f)); + UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("*"); + ui_spacer(ui_em(1.5f*(1-animation_t), 1.f)); + } + + // rjf: status + { + if(is_running) + { + ui_label(str8_lit("Running")); + } + else + { + Temp scratch = scratch_begin(&arena, 1); + DF_IconKind icon = DF_IconKind_Null; + String8 explanation = str8_lit("Not running"); + DF_Entity *thread = df_entity_from_ctrl_handle(stop_event.machine_id, stop_event.entity); + String8 thread_display_string = df_display_string_from_entity(scratch.arena, thread); + switch(stop_event.kind) + { + default: + { + switch(stop_event.cause) + { + default:{}break; + case CTRL_EventCause_Finished: + { + if(!df_entity_is_nil(thread)) + { + explanation = push_str8f(scratch.arena, "%S completed step", thread_display_string); + } + else + { + explanation = str8_lit("Stopped"); + } + }break; + case CTRL_EventCause_UserBreakpoint: + { + if(!df_entity_is_nil(thread)) + { + icon = DF_IconKind_CircleFilled; + explanation = push_str8f(scratch.arena, "%S hit a breakpoint", thread_display_string); + } + }break; + case CTRL_EventCause_InterruptedByException: + { + if(!df_entity_is_nil(thread)) + { + icon = DF_IconKind_WarningBig; + switch(stop_event.exception_kind) + { + default: + { + explanation = push_str8f(scratch.arena, "%S interrupted - 0x%x", thread_display_string, stop_event.exception_code); + }break; + case CTRL_ExceptionKind_CppThrow: + { + explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x", thread_display_string, stop_event.exception_code); + }break; + case CTRL_ExceptionKind_MemoryRead: + { + explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x: Access violation reading 0x%I64x", + thread_display_string, + stop_event.exception_code, + stop_event.vaddr_rng.min); + }break; + case CTRL_ExceptionKind_MemoryWrite: + { + explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x: Access violation writing 0x%I64x", + thread_display_string, + stop_event.exception_code, + stop_event.vaddr_rng.min); + }break; + case CTRL_ExceptionKind_MemoryExecute: + { + explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x: Access violation executing 0x%I64x", + thread_display_string, + stop_event.exception_code, + stop_event.vaddr_rng.min); + }break; + } + } + else + { + icon = DF_IconKind_Pause; + explanation = str8_lit("Interrupted"); + } + }break; + case CTRL_EventCause_InterruptedByTrap: + { + + }break; + case CTRL_EventCause_InterruptedByHalt: + { + icon = DF_IconKind_Pause; + explanation = str8_lit("Halted"); + }break; + } + }break; + case CTRL_EventKind_LaunchAndInitDone: + case CTRL_EventKind_LaunchAndHandshakeDone: + { + explanation = str8_lit("Launched"); + }break; + case CTRL_EventKind_AttachDone: + { + explanation = str8_lit("Attached"); + }break; + case CTRL_EventKind_DetachDone: + { + explanation = str8_lit("Detached"); + }break; + case CTRL_EventKind_KillDone: + { + explanation = str8_lit("Killed"); + }break; + } + if(icon != DF_IconKind_Null) + { + UI_PrefWidth(ui_em(2.25f, 1.f)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + ui_label(df_g_icon_kind_text_table[icon]); + } + UI_PrefWidth(ui_text_dim(10, 1)) ui_label(explanation); + scratch_end(scratch); + } + } + + ui_spacer(ui_pct(1, 0)); + + // rjf: bind change visualization + if(df_gfx_state->bind_change_active) + { + UI_PrefWidth(ui_text_dim(10, 1)) + UI_Flags(UI_BoxFlag_DrawBackground) + UI_TextAlignment(UI_TextAlign_Center) + UI_CornerRadius(4) + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight0)) + ui_labelf("Currently rebinding \"%S\" hotkey", df_gfx_state->bind_change_cmd_spec->info.display_name); + } + + // rjf: error visualization + else if(ws->error_t >= 0.01f) + { + ws->error_t -= df_dt()/8.f; + df_gfx_request_frame(); + Vec4F32 tx_color = df_rgba_from_theme_color(DF_ThemeColor_FailureText); + F32 alpha_factor = Max(ws->error_t, 0.2f); + tx_color.w *= alpha_factor; + ui_set_next_text_color(tx_color); + ui_set_next_pref_width(ui_children_sum(1)); + UI_CornerRadius(4) + UI_Row + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextAlignment(UI_TextAlign_Center) + { + String8 error_string = str8(ws->error_buffer, ws->error_string_size); + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); + ui_label(error_string); + } + } + } + } + + //- rjf: panel non-leaf UI (drag boundaries) + B32 is_changing_panel_boundaries = 0; + ProfScope("non-leaf panel UI") + for(DF_Panel *panel = ws->root_panel; + !df_panel_is_nil(panel); + panel = df_panel_rec_df_pre(panel).next) + { + //- rjf: continue on leaf panels + if(df_panel_is_nil(panel->first)) + { + continue; + } + + //- rjf: grab info + Axis2 split_axis = panel->split_axis; + Rng2F32 panel_rect = df_rect_from_panel(content_rect, ws->root_panel, panel); + + //- rjf: do UI for boundaries between all children + for(DF_Panel *child = panel->first; !df_panel_is_nil(child) && !df_panel_is_nil(child->next); child = child->next) + { + DF_Panel *min_child = child; + DF_Panel *max_child = min_child->next; + Rng2F32 min_child_rect = df_rect_from_panel_child(panel_rect, panel, min_child); + Rng2F32 max_child_rect = df_rect_from_panel_child(panel_rect, panel, max_child); + Rng2F32 boundary_rect = {0}; + { + boundary_rect.p0.v[split_axis] = min_child_rect.p1.v[split_axis] - ui_top_font_size()/3; + boundary_rect.p1.v[split_axis] = max_child_rect.p0.v[split_axis] + ui_top_font_size()/3; + boundary_rect.p0.v[axis2_flip(split_axis)] = panel_rect.p0.v[axis2_flip(split_axis)]; + boundary_rect.p1.v[axis2_flip(split_axis)] = panel_rect.p1.v[axis2_flip(split_axis)]; + } + + UI_Rect(boundary_rect) + { + ui_set_next_hover_cursor(split_axis == Axis2_X ? OS_Cursor_LeftRight : OS_Cursor_UpDown); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###%p_%p", min_child, max_child); + UI_Signal sig = ui_signal_from_box(box); + + if(sig.double_clicked) + { + ui_kill_action(); + F32 sum_pct = min_child->size_pct_of_parent_target.v[split_axis] + max_child->size_pct_of_parent_target.v[split_axis]; + min_child->size_pct_of_parent_target.v[split_axis] = 0.5f * sum_pct; + max_child->size_pct_of_parent_target.v[split_axis] = 0.5f * sum_pct; + } + else if(sig.pressed) + { + Vec2F32 v = {min_child->size_pct_of_parent_target.v[split_axis], max_child->size_pct_of_parent_target.v[split_axis]}; + ui_store_drag_struct(&v); + } + else if(sig.dragging) + { + Vec2F32 v = *ui_get_drag_struct(Vec2F32); + Vec2F32 mouse_delta = ui_drag_delta(); + F32 total_size = dim_2f32(panel_rect).v[split_axis]; + F32 min_pct__before = v.v[0]; + F32 min_pixels__before = min_pct__before * total_size; + F32 min_pixels__after = min_pixels__before + mouse_delta.v[split_axis]; + if(min_pixels__after < 50.f) + { + min_pixels__after = 50.f; + } + F32 min_pct__after = min_pixels__after / total_size; + F32 pct_delta = min_pct__after - min_pct__before; + F32 max_pct__before = v.v[1]; + F32 max_pct__after = max_pct__before - pct_delta; + F32 max_pixels__after = max_pct__after * total_size; + if(max_pixels__after < 50.f) + { + max_pixels__after = 50.f; + max_pct__after = max_pixels__after / total_size; + pct_delta = -(max_pct__after - max_pct__before); + min_pct__after = min_pct__before + pct_delta; + } + min_child->size_pct_of_parent.v[split_axis] = min_child->size_pct_of_parent_target.v[split_axis] = min_pct__after; + max_child->size_pct_of_parent.v[split_axis] = max_child->size_pct_of_parent_target.v[split_axis] = max_pct__after; + is_changing_panel_boundaries = 1; + } + if(sig.released || sig.double_clicked) + { + df_panel_notify_mutation(ws, min_child); + } + } + } + } + + //- rjf: panel leaf UI + ProfScope("leaf panel UI") + for(DF_Panel *panel = ws->root_panel; + !df_panel_is_nil(panel); + panel = df_panel_rec_df_pre(panel).next) + { + //- rjf: continue on non-leaf panels + if(!df_panel_is_nil(panel->first)) + { + continue; + } + + //- rjf: grab rect & dimensions & info + Rng2F32 panel_rect = df_rect_from_panel(content_rect, ws->root_panel, panel); + panel_rect = pad_2f32(panel_rect, -1.f); + F32 tab_bar_rheight = ui_em(3.0f, 1.f).value; + F32 tab_bar_vheight = ui_em(2.6f, 1.f).value; + F32 tab_bar_rv_diff = tab_bar_rheight - tab_bar_vheight; + F32 tab_spacing = ui_em(0.4f, 1.f).value; + Rng2F32 tab_bar_rect = r2f32p(panel_rect.x0, panel_rect.y0, panel_rect.x1, panel_rect.y0 + tab_bar_rheight); + Rng2F32 content_rect = r2f32p(panel_rect.x0, panel_rect.y0+tab_bar_vheight, panel_rect.x1, panel_rect.y1); + if(panel->tab_side == Side_Max) + { + tab_bar_rect.y0 = panel_rect.y1 - tab_bar_rheight; + tab_bar_rect.y1 = panel_rect.y1; + content_rect.y0 = panel_rect.y0; + content_rect.y1 = panel_rect.y1 - tab_bar_vheight; + } + if(panel->hide_tab_bar) + { + content_rect = panel_rect; + } + + //- rjf: grab view that is receiving a query from the user + DF_View *query_view = df_query_view_from_panel(panel); + + //- rjf: extract query view command/view specs + DF_CmdSpec *query_cmd_spec = query_view->cmd_spec; + DF_ViewSpec *query_view_spec = df_view_spec_from_cmd_spec(query_cmd_spec); + + //- rjf: determine focus + B32 ctx_menu_is_focused = ui_any_ctx_menu_is_open(); + B32 panel_is_focused = (ws->focused_panel == panel); + B32 query_is_focused = (panel_is_focused && !df_view_is_nil(query_view)); + + //- rjf: begin panel content window + UI_Box *panel_box = &ui_g_nil_box; + UI_Rect(content_rect) UI_ChildLayoutAxis(Axis2_Y) UI_CornerRadius(0) + { + Vec4F32 bg_color = df_rgba_from_theme_color(DF_ThemeColor_PlainBackground); + bg_color.x *= bg_color.w; + bg_color.y *= bg_color.w; + bg_color.z *= bg_color.w; + bg_color.w = 1; + UI_BackgroundColor(bg_color) UI_Focus(window_is_focused && !ctx_menu_is_focused && panel_is_focused && !ws->menu_bar_focused && (!hover_eval_is_open || any_query_is_focused)) + { + UI_Key panel_key = df_ui_key_from_panel(panel); + if(!panel_is_focused) + { + ui_set_next_overlay_color(df_rgba_from_theme_color(DF_ThemeColor_InactivePanelOverlay)); + } + panel_box = ui_build_box_from_key(UI_BoxFlag_MouseClickable| + UI_BoxFlag_Clip| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + (!panel_is_focused*UI_BoxFlag_DrawOverlay), + panel_key); + ui_push_parent(panel_box); + } + ui_push_pref_width(ui_pct(1, 0)); + } + + //- rjf: build minified floating tab indicator + if(panel->hide_tab_bar != 0) + { + F32 tab_size = ui_top_font_size()*2.f; + Rng2F32 tab_rect = r2f32p(0, 0, tab_size, tab_size); + { + Vec4F32 tab_color = df_rgba_from_theme_color(DF_ThemeColor_TabActive); + if(ws->focused_panel != panel) + { + tab_color.w *= 0.5f; + } + ui_set_next_background_color(tab_color); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *tab_box = &ui_g_nil_box; + UI_Rect(tab_rect) UI_CornerRadius11(tab_size/2) + { + tab_box = ui_build_box_from_stringf(UI_BoxFlag_FloatingX| + UI_BoxFlag_FloatingY| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawDropShadow| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_Clickable, "###tab_%p", panel); + } + UI_Signal sig = ui_signal_from_box(tab_box); + UI_Parent(tab_box) + { + UI_WidthFill UI_TextAlignment(UI_TextAlign_Center) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(ui_icon_font()) + { + ui_label(df_g_icon_kind_text_table[DF_IconKind_Info]); + } + } + + // rjf: hover tooltip + if(sig.hovering) + { + Temp scratch = scratch_begin(&arena, 1); + DF_View *view = panel->selected_stable_view; + DF_IconKind icon_kind = df_icon_kind_from_view(view); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + String8 label = df_display_string_from_view(scratch.arena, ctrl_ctx, view); + if(label.size != 0) UI_Tooltip UI_PrefWidth(ui_children_sum(1)) UI_Row + { + if(icon_kind != DF_IconKind_Null) + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(2.25f, 1.f)) + ui_label(df_g_icon_kind_text_table[icon_kind]); + } + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_PrefWidth(ui_text_dim(10, 1)) + ui_label(label); + } + scratch_end(scratch); + } + + // rjf: consume events for tab clicking + { + DF_View *view = panel->selected_stable_view; + if(sig.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + else if(sig.dragging && !df_drag_is_active() && length_2f32(ui_drag_delta()) > 10.f) + { + DF_DragDropPayload payload = {0}; + { + payload.key = sig.box->key; + payload.panel = df_handle_from_panel(panel); + payload.view = df_handle_from_view(view); + } + df_drag_begin(&payload); + } + else if(sig.right_clicked) + { + ui_ctx_menu_open(ws->tab_ctx_menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + ws->tab_ctx_menu_view = df_handle_from_view(view); + } + } + } + } + + //- rjf: panel query ui + if(!df_view_is_nil(query_view)) UI_PrefHeight(ui_em(2.5f, 1.f)) + { + DF_IconKind icon_kind = query_cmd_spec->info.canonical_icon_kind; + + // rjf: begin + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_QueryBar)); + ui_set_next_flags(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow); + if(query_view_spec == &df_g_nil_view_spec) + { + F32 padding = ui_em(5.25f, 1.f).value; + F32 corner_radius = ui_top_font_size() * 0.2f; + F32 width = dim_2f32(content_rect).x*0.7f; + width = Max(width, ui_top_font_size()*40); + width = Min(width, dim_2f32(content_rect).x - padding*2); + ui_set_next_fixed_x(padding/2); + ui_set_next_fixed_y(padding/2); + ui_set_next_fixed_width(width); + ui_set_next_fixed_height(ui_em(2.5f, 1.f).value); + ui_set_next_corner_radius_00(corner_radius); + ui_set_next_corner_radius_01(corner_radius); + ui_set_next_corner_radius_10(corner_radius); + ui_set_next_corner_radius_11(corner_radius); + ui_set_next_flags(ui_top_flags()|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY); + } + ui_named_row_begin(str8_lit("query_bar")); + + // rjf: build contents + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + if(icon_kind != DF_IconKind_Null) + { + ui_spacer(ui_em(0.3f, 1.f)); + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(2.25f, 1.f)) + UI_HeightFill + ui_label(df_g_icon_kind_text_table[icon_kind]); + } + ui_labelf("%S", query_cmd_spec->info.display_name); + } + B32 query_is_code = !!(query_cmd_spec->info.flags & DF_CmdSpecFlag_QueryIsCode); + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_PlainBackground)) + UI_CornerRadius00(ui_em(0.6f, 1.f).value) + UI_CornerRadius01(ui_em(0.6f, 1.f).value) + UI_WidthFill + UI_Focus(!ctx_menu_is_focused && panel_is_focused && query_is_focused && !ws->menu_bar_focused) + UI_Font(query_is_code ? df_font_from_slot(DF_FontSlot_Code) : ui_top_font()) + { + query_view->query.str = query_view->query_buffer; + UI_Signal sig = df_line_edit(query_is_code*DF_LineEditFlag_CodeContents, 0, &query_view->query_cursor, &query_view->query_mark, query_view->query_buffer, sizeof(query_view->query_buffer), &query_view->query.size, 0, query_view->query, str8_lit("###cmd_query_str")); + if(sig.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + + // rjf: end + ui_named_row_end(); + } + + //- rjf: flash animation for stable view + { + DF_View *view = panel->selected_stable_view; + if(view->flash_t >= 0.001f) + { + UI_Box *panel_box = ui_top_parent(); + Rng2F32 panel_rect = panel_box->rect; + Vec2F32 panel_rect_dim = dim_2f32(panel_rect); + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + color.w *= view->flash_t; + color.w *= 0.35f; + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(0); + ui_set_next_fixed_width(panel_rect_dim.x); + ui_set_next_fixed_height(panel_rect_dim.y); + ui_set_next_background_color(color); + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + } + } + + //- rjf: loading animation for stable view + { + DF_View *view = panel->selected_stable_view; + if(view->loading_t >= 0.001f) + { + // rjf: set up dimensions + F32 edge_padding = 30.f; + F32 width = ui_top_font_size() * 10; + F32 height = ui_top_font_size() * 1.f; + F32 min_thickness = ui_top_font_size()/2; + F32 trail = ui_top_font_size() * 4; + F32 t = pow_f32(sin_f32((F32)df_time_in_seconds() / 1.8f), 2.f); + F64 v = 1.f - abs_f32(0.5f - t); + UI_Box *panel_box = ui_top_parent(); + Rng2F32 panel_rect = panel_box->rect; + + // rjf: colors + Vec4F32 bg_color = v4f32(0.1f, 0.1f, 0.1f, 1); + Vec4F32 bd_color = df_rgba_from_theme_color(DF_ThemeColor_PlainBorder); + Vec4F32 hl_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + bg_color.w *= view->loading_t; + bd_color.w *= view->loading_t; + hl_color.w *= view->loading_t; + + // rjf: grab animation params + F32 bg_work_indicator_t = 1.f; + + // rjf: build indicator + UI_CornerRadius(height/3.f) + { + // rjf: rects + Rng2F32 indicator_region_rect = + r2f32p((panel_rect.x0 + panel_rect.x1)/2 - width/2 - panel_rect.x0, + (panel_rect.y0 + panel_rect.y1)/2 - height/2 - panel_rect.y0, + (panel_rect.x0 + panel_rect.x1)/2 + width/2 - panel_rect.x0, + (panel_rect.y0 + panel_rect.y1)/2 + height/2 - panel_rect.y0); + Rng2F32 indicator_rect = + r2f32p(indicator_region_rect.x0 + width*t - min_thickness/2 - trail*v, + indicator_region_rect.y0, + indicator_region_rect.x0 + width*t + min_thickness/2 + trail*v, + indicator_region_rect.y1); + indicator_rect.x0 = Clamp(indicator_region_rect.x0, indicator_rect.x0, indicator_region_rect.x1); + indicator_rect.x1 = Clamp(indicator_region_rect.x0, indicator_rect.x1, indicator_region_rect.x1); + indicator_rect = pad_2f32(indicator_rect, -1.f); + + // rjf: does the view have loading *progress* info? -> draw extra progress layer + if(view->loading_progress_v != view->loading_progress_v_target) + { + F64 pct_done_f64 = ((F64)view->loading_progress_v/(F64)view->loading_progress_v_target); + F32 pct_done = (F32)pct_done_f64; + ui_set_next_background_color(v4f32(1, 1, 1, 0.2f*view->loading_t)); + ui_set_next_fixed_x(indicator_region_rect.x0); + ui_set_next_fixed_y(indicator_region_rect.y0); + ui_set_next_fixed_width(dim_2f32(indicator_region_rect).x*pct_done); + ui_set_next_fixed_height(dim_2f32(indicator_region_rect).y); + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + } + + // rjf: fill + ui_set_next_background_color(hl_color); + ui_set_next_fixed_x(indicator_rect.x0); + ui_set_next_fixed_y(indicator_rect.y0); + ui_set_next_fixed_width(dim_2f32(indicator_rect).x); + ui_set_next_fixed_height(dim_2f32(indicator_rect).y); + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + + // rjf: animated bar + ui_set_next_background_color(bg_color); + ui_set_next_border_color(bd_color); + ui_set_next_fixed_x(indicator_region_rect.x0); + ui_set_next_fixed_y(indicator_region_rect.y0); + ui_set_next_fixed_width(dim_2f32(indicator_region_rect).x); + ui_set_next_fixed_height(dim_2f32(indicator_region_rect).y); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_Clickable, "bg_system_status"); + UI_Signal sig = ui_signal_from_box(box); + } + + // rjf: build background + UI_WidthFill UI_HeightFill + { + ui_set_next_background_color(bg_color); + ui_set_next_blur_size(10.f*view->loading_t); + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + } + } + } + + //- rjf: determine which view to build ui for + B32 should_do_query_view = !df_view_is_nil(query_view) && query_view_spec != &df_g_nil_view_spec; + B32 should_do_empty_view = (df_view_is_nil(panel->selected_stable_view) && df_view_is_nil(panel->query_view_stack_top)); + B32 should_do_stable_view = (!df_view_is_nil(panel->selected_stable_view) && (df_view_is_nil(query_view) || query_view_spec == &df_g_nil_view_spec)); + + //- rjf: build view container + UI_Box *view_container_box = &ui_g_nil_box; + UI_Focus(should_do_query_view || should_do_empty_view || (should_do_stable_view && !query_is_focused)) + UI_FixedWidth(dim_2f32(content_rect).x) + UI_FixedHeight(dim_2f32(content_rect).y) + UI_ChildLayoutAxis(Axis2_Y) + { + view_container_box = ui_build_box_from_key(0, ui_key_zero()); + } + + //- rjf: empty view + UI_Parent(view_container_box) if(should_do_empty_view) + { + DF_VIEW_UI_FUNCTION_NAME(Empty)(ws, panel, &df_g_nil_view, content_rect); + } + + //- rjf: view for query + UI_Parent(view_container_box) if(should_do_query_view) + { + DF_View *view = query_view; + DF_ViewUIFunctionType *build_view_ui_function = query_view_spec->info.ui_hook; + build_view_ui_function(ws, panel, view, content_rect); + } + + //- rjf: selected stable tab view + UI_Parent(view_container_box) if(should_do_stable_view) + { + DF_View *view = panel->selected_stable_view; + for(DF_View *v = view; !df_view_is_nil(v); v = v->callee_view) + { + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(v->cmd_spec); + if(view_spec != &df_g_nil_view_spec) + { + view = v; + } + } + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd_spec); + DF_ViewUIFunctionType *build_view_ui_function = view_spec->info.ui_hook; + build_view_ui_function(ws, panel, view, content_rect); + } + + //- rjf: end panel parent + ui_pop_pref_width(); + ui_pop_parent(); + + //- rjf: panel fallthrough interaction + UI_Signal panel_sig = ui_signal_from_box(panel_box); + if(panel_sig.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + //- rjf: build tab bar + if(panel->hide_tab_bar == 0) UI_Focus(0) + { + Temp scratch = scratch_begin(&arena, 1); + + // rjf: types + typedef struct DropSite DropSite; + struct DropSite + { + F32 p; + DF_View *prev_view; + }; + + // rjf: prep output data + DF_View *next_selected_stable_view = panel->selected_stable_view; + UI_Box *tab_bar_box = &ui_g_nil_box; + U64 drop_site_count = panel->stable_view_count+1; + DropSite *drop_sites = push_array(scratch.arena, DropSite, drop_site_count); + F32 drop_site_max_p = 0; + U64 view_idx = 0; + + // rjf: build + UI_Rect(tab_bar_rect) UI_CornerRadius(0) + { + tab_bar_box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_ViewScroll|UI_BoxFlag_Clickable, "tab_bar_%p", panel); + } + UI_Parent(tab_bar_box) UI_PrefHeight(ui_pct(1, 0)) + { + Temp scratch = scratch_begin(&arena, 1); + F32 corner_radius = ui_em(0.6f, 1.f).value; + ui_spacer(ui_px(1.f, 1.f)); + + // rjf: build tab list ctx menu + UI_Key tab_list_ctx_menu_key = ui_key_from_stringf(ui_key_zero(), "###tab_list_ctx_menu_%p", panel); + UI_CtxMenu(tab_list_ctx_menu_key) UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_em(2.25f, 1.f)) + { + for(DF_View *view = panel->first_stable_view; !df_view_is_nil(view); view = view->next) + { + B32 view_is_selected = view == panel->selected_stable_view; + DF_IconKind icon_kind = df_icon_kind_from_view(view); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + String8 label = df_display_string_from_view(scratch.arena, ctrl_ctx, view); + if(view_is_selected) + { + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_TabActive)); + } + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *tab_list_item_box = ui_build_box_from_stringf(UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_Clickable, + "###tab_list_item_box_%p", view); + UI_Parent(tab_list_item_box) + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(3.f, 1.f)) + UI_TextAlignment(UI_TextAlign_Center) + ui_label(df_g_icon_kind_text_table[icon_kind]); + UI_PrefWidth(ui_text_dim(10.f, 1.f)) + ui_label(label); + } + UI_Signal sig = ui_signal_from_box(tab_list_item_box); + if(sig.clicked) + { + next_selected_stable_view = view; + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + } + + // rjf: build tab list button + if(panel->stable_view_count > 5) UI_PrefWidth(ui_em(2.25f, 1.f)) UI_PrefHeight(ui_px(tab_bar_vheight, 1)) + { + UI_Signal sig = df_icon_buttonf(DF_IconKind_List, "###tab_list_%p", panel); + if(sig.clicked) + { + if(ui_ctx_menu_is_open(tab_list_ctx_menu_key)) + { + ui_ctx_menu_close(); + } + else + { + ui_ctx_menu_open(tab_list_ctx_menu_key, sig.box->key, v2f32(0, dim_2f32(sig.box->rect).y)); + } + } + } + + // rjf: build tabs + UI_PrefWidth(ui_em(18.f, 0.5f)) + UI_CornerRadius00(panel->tab_side == Side_Min ? corner_radius : 0) + UI_CornerRadius01(panel->tab_side == Side_Min ? 0 : corner_radius) + UI_CornerRadius10(panel->tab_side == Side_Min ? corner_radius : 0) + UI_CornerRadius11(panel->tab_side == Side_Min ? 0 : corner_radius) + for(DF_View *view = panel->first_stable_view; !df_view_is_nil(view); view = view->next, view_idx += 1) + { + temp_end(scratch); + + // rjf: gather info for this tab + B32 view_is_selected = view == panel->selected_stable_view; + DF_IconKind icon_kind = df_icon_kind_from_view(view); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + String8 label = df_display_string_from_view(scratch.arena, ctrl_ctx, view); + + // rjf: begin vertical region for this tab + ui_set_next_child_layout_axis(Axis2_Y); + UI_Box *tab_column_box = ui_build_box_from_stringf(!is_changing_panel_boundaries*UI_BoxFlag_AnimatePosX, "tab_column_%p", view); + + // rjf: build tab container box + UI_Parent(tab_column_box) UI_PrefHeight(ui_px(tab_bar_vheight, 1)) + { + if((!view_is_selected && panel->tab_side == Side_Min) || + (view_is_selected && panel->tab_side == Side_Max)) + { + ui_spacer(ui_px(tab_bar_rv_diff, 1.f)); + } + else + { + ui_spacer(ui_px(1.f, 1.f)); + } + Vec4F32 bg_color = df_rgba_from_theme_color(view_is_selected ? DF_ThemeColor_TabActive : DF_ThemeColor_TabInactive); + if(view_is_selected && panel != ws->focused_panel) + { + bg_color.w *= 0.5f; + } + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_background_color(bg_color); + ui_set_next_border_color(mix_4f32(v4f32(bg_color.x, bg_color.y, bg_color.z, bg_color.w), v4f32(1, 1, 1, 0.2f), 0.5f)); + UI_Box *tab_box = ui_build_box_from_stringf(UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + (UI_BoxFlag_DrawDropShadow*view_is_selected)| + UI_BoxFlag_AnimatePosY| + UI_BoxFlag_Clickable, + "tab_%p", view); + + // rjf: build tab contents + UI_Parent(tab_box) + { + if(icon_kind != DF_IconKind_Null) + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(2.25f, 1.f)) + ui_label(df_g_icon_kind_text_table[icon_kind]); + } + UI_TextColor(df_rgba_from_theme_color(view_is_selected ? DF_ThemeColor_PlainText : DF_ThemeColor_WeakText)) + UI_PrefWidth(ui_pct(1, 0)) + UI_FontSize(ui_top_font_size()*(view_is_selected ? 1.f : 0.75f)) + ui_label(label); + UI_PrefWidth(ui_em(2.35f, 1.f)) UI_TextAlignment(UI_TextAlign_Center) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)*0.75f) + UI_BackgroundColor(v4f32(0, 0, 0, 0)) + UI_CornerRadius00(0) + UI_CornerRadius01(0) + if(ui_buttonf("%S###close_view_%p", df_g_icon_kind_text_table[DF_IconKind_X], view).clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseTab)); + } + } + + // rjf: consume events for tab clicking + { + UI_Signal sig = ui_signal_from_box(tab_box); + if(sig.pressed) + { + next_selected_stable_view = view; + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + else if(sig.dragging && !df_drag_is_active() && length_2f32(ui_drag_delta()) > 10.f) + { + DF_DragDropPayload payload = {0}; + { + payload.key = sig.box->key; + payload.panel = df_handle_from_panel(panel); + payload.view = df_handle_from_view(view); + } + df_drag_begin(&payload); + } + else if(sig.right_clicked) + { + ui_ctx_menu_open(ws->tab_ctx_menu_key, sig.box->key, v2f32(0, sig.box->rect.y1 - sig.box->rect.y0)); + ws->tab_ctx_menu_view = df_handle_from_view(view); + } + if(sig.released) + { + df_panel_notify_mutation(ws, panel); + } + } + } + + // rjf: space for next tab + if(!df_view_is_nil(view->next)) + { + ui_spacer(ui_em(0.15f, 1.f)); + } + + // rjf: store off drop-site + drop_sites[view_idx].p = tab_column_box->rect.x0 - tab_spacing/2; + drop_sites[view_idx].prev_view = view->prev; + drop_site_max_p = Max(tab_column_box->rect.x1, drop_site_max_p); + } + + scratch_end(scratch); + } + + // rjf: interact with tab bar + ui_signal_from_box(tab_bar_box); + + // rjf: fill out last drop site + { + drop_sites[drop_site_count-1].p = drop_site_max_p; + drop_sites[drop_site_count-1].prev_view = panel->last_stable_view; + } + + // rjf: more precise drop-sites on tab bar + { + Vec2F32 mouse = os_mouse_from_window(ws->os); + DF_View *view = df_view_from_handle(df_g_drag_drop_payload.view); + if(df_drag_is_active() && window_is_focused && contains_2f32(panel_rect, mouse) && !df_view_is_nil(view)) + { + // rjf: mouse => hovered drop site + F32 min_distance = 0; + DropSite *active_drop_site = 0; + for(U64 drop_site_idx = 0; drop_site_idx < drop_site_count; drop_site_idx += 1) + { + F32 distance = abs_f32(drop_sites[drop_site_idx].p - mouse.x); + if(drop_site_idx == 0 || distance < min_distance) + { + active_drop_site = &drop_sites[drop_site_idx]; + min_distance = distance; + } + } + + // rjf: vis + DF_Panel *drag_panel = df_panel_from_handle(df_g_drag_drop_payload.panel); + if(!df_view_is_nil(view) && + active_drop_site != 0 && + (panel != drag_panel)) + { + tab_bar_box->flags |= UI_BoxFlag_DrawOverlay; + tab_bar_box->overlay_color = df_rgba_from_theme_color(DF_ThemeColor_DropSiteOverlay); + + if(panel->stable_view_count != 0) + { + D_Bucket *bucket = d_bucket_make(); + D_BucketScope(bucket) + { + d_rect(r2f32p(active_drop_site->p - tab_spacing/2, + tab_bar_box->rect.y0, + active_drop_site->p + tab_spacing/2, + tab_bar_box->rect.y1), + v4f32(1, 1, 1, 1), + 2.f, 0, 1.f); + } + ui_box_equip_draw_bucket(tab_bar_box, bucket); + } + } + + // rjf: drop + DF_DragDropPayload payload = df_g_drag_drop_payload; + if((active_drop_site != 0 && df_drag_drop(&payload)) || df_panel_from_handle(payload.panel) == panel) + { + DF_View *view = df_view_from_handle(payload.view); + DF_Panel *src_panel = df_panel_from_handle(payload.panel); + if(!df_panel_is_nil(panel) && !df_view_is_nil(view)) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.panel = df_handle_from_panel(src_panel); + params.dest_panel = df_handle_from_panel(panel); + params.view = df_handle_from_view(view); + params.prev_view = df_handle_from_view(active_drop_site->prev_view); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_DestPanel); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_View); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_PrevView); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_MoveTab)); + } + } + } + } + + // rjf: apply tab change + { + panel->selected_stable_view = next_selected_stable_view; + } + + scratch_end(scratch); + } + + //- rjf: less granular panel for tabs & entities drop-site + if(df_drag_is_active() && window_is_focused && contains_2f32(panel_rect, os_mouse_from_window(ws->os))) + { + DF_DragDropPayload *payload = &df_g_drag_drop_payload; + DF_View *dragged_view = df_view_from_handle(payload->view); + B32 view_is_in_panel = 0; + for(DF_View *view = panel->first_stable_view; !df_view_is_nil(view); view = view->next) + { + if(view == dragged_view) + { + view_is_in_panel = 1; + break; + } + } + + if(view_is_in_panel == 0) + { + // rjf: vis + { + panel_box->flags |= UI_BoxFlag_DrawOverlay; + panel_box->overlay_color = df_rgba_from_theme_color(DF_ThemeColor_DropSiteOverlay); + } + + // rjf: drop + { + DF_DragDropPayload payload = {0}; + if(df_drag_drop(&payload)) + { + DF_Panel *src_panel = df_panel_from_handle(payload.panel); + DF_View *view = df_view_from_handle(payload.view); + DF_Entity *entity = df_entity_from_handle(payload.entity); + + // rjf: view drop + if(!df_view_is_nil(view)) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.prev_view = df_handle_from_view(panel->last_stable_view); + params.panel = df_handle_from_panel(src_panel); + params.dest_panel = df_handle_from_panel(panel); + params.view = df_handle_from_view(view); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_PrevView); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_DestPanel); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_View); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_MoveTab)); + df_panel_notify_mutation(ws, panel); + } + + // rjf: entity drop + if(!df_entity_is_nil(entity)) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.panel = df_handle_from_panel(panel); + params.text_point = payload.text_point; + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SpawnEntityView)); + ui_ctx_menu_open(ws->drop_completion_ctx_menu_key, ui_key_zero(), sub_2f32(ui_mouse(), v2f32(2, 2))); + ws->drop_completion_entity = df_handle_from_entity(entity); + ws->drop_completion_panel = df_handle_from_panel(panel); + } + } + } + } + } + + //- rjf: panel query submission + if(panel_is_focused && !ctx_menu_is_focused) + { + DF_View *view = df_selected_view_from_panel(panel); + if(!df_view_is_nil(view) && + view->cmd_spec->info.query_rule != DF_CmdQueryRule_Null) + { + B32 submit = os_key_press(events, ws->os, 0, OS_Key_Return); + B32 cancel = os_key_press(events, ws->os, 0, OS_Key_Esc); + if(submit) + { + Temp scratch = scratch_begin(&arena, 1); + DF_CmdParams params = df_cmd_params_from_view(ws, panel, df_view_caller_root_from_view(view)); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, view->cmd_spec, view->query); + if(error.size == 0) + { + df_push_cmd__root(¶ms, view->cmd_spec); + } + else + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.string = error; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + scratch_end(scratch); + } + if(submit || cancel) + { + DF_CmdSpec *spec = view->cmd_spec; + if(cancel || !(spec->info.flags & DF_CmdSpecFlag_RunKeepsQuery)) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + } + } + } + + } + + //- rjf: animate panel pcts + { + F32 rate = 1 - pow_f32(2, (-50.f * df_dt())); + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + if(abs_f32(panel->off_pct_of_parent.x) > 0.01f || + abs_f32(panel->off_pct_of_parent.y) > 0.01f || + abs_f32(panel->size_pct_of_parent_target.x - panel->size_pct_of_parent.x) > 0.01f || + abs_f32(panel->size_pct_of_parent_target.y - panel->size_pct_of_parent.y) > 0.01f) + { + df_gfx_request_frame(); + } + panel->off_pct_of_parent.x += (-panel->off_pct_of_parent.x) * rate; + panel->off_pct_of_parent.y += (-panel->off_pct_of_parent.y) * rate; + panel->size_pct_of_parent.x += (panel->size_pct_of_parent_target.x - panel->size_pct_of_parent.x) * rate; + panel->size_pct_of_parent.y += (panel->size_pct_of_parent_target.y - panel->size_pct_of_parent.y) * rate; + } + } + + //- rjf: animate views + { + F32 rate = 1 - pow_f32(2, (-10.f * df_dt())); + F32 fast_rate = 1 - pow_f32(2, (-40.f * df_dt())); + for(DF_Panel *panel = ws->root_panel; + !df_panel_is_nil(panel); + panel = df_panel_rec_df_pre(panel).next) + { + if(!df_view_is_nil(panel->query_view_stack_top)) + { + if(abs_f32(panel->query_view_stack_top->scroll_pos.x.off) > 0.01f || + abs_f32(panel->query_view_stack_top->scroll_pos.y.off) > 0.01f) + { + df_gfx_request_frame(); + } + panel->query_view_stack_top->scroll_pos.x.off -= panel->query_view_stack_top->scroll_pos.x.off*fast_rate; + panel->query_view_stack_top->scroll_pos.y.off -= panel->query_view_stack_top->scroll_pos.y.off*fast_rate; + if(abs_f32(panel->query_view_stack_top->scroll_pos.x.off) < 0.005f) + { + panel->query_view_stack_top->scroll_pos.x.off = 0; + } + if(abs_f32(panel->query_view_stack_top->scroll_pos.y.off) < 0.005f) + { + panel->query_view_stack_top->scroll_pos.y.off = 0; + } + } + for(DF_View *stable_view = panel->first_stable_view; + !df_view_is_nil(stable_view); + stable_view = stable_view->next) + { + for(DF_View *view = stable_view; + !df_view_is_nil(view); + view = view->callee_view) + { + if(abs_f32(view->loading_t_target - view->loading_t) > 0.01f || + abs_f32(0 - view->flash_t) > 0.01f || + abs_f32(view->scroll_pos.x.off) > 0.01f || + abs_f32(view->scroll_pos.y.off) > 0.01f) + { + df_gfx_request_frame(); + } + if(view->loading_t_target != 0 && view == panel->selected_stable_view) + { + df_gfx_request_frame(); + } + view->loading_t += (view->loading_t_target - view->loading_t) * rate; + view->flash_t += (0 - view->flash_t) * rate; + view->scroll_pos.x.off -= view->scroll_pos.x.off*fast_rate; + view->scroll_pos.y.off -= view->scroll_pos.y.off*fast_rate; + if(abs_f32(view->scroll_pos.x.off) < 0.01f) + { + view->scroll_pos.x.off = 0; + } + if(abs_f32(view->scroll_pos.y.off) < 0.01f) + { + view->scroll_pos.y.off = 0; + } + if(view == panel->selected_stable_view) + { + view->loading_t_target = 0; + } + } + } + } + } + + //- rjf: drag/drop cancelling + if(df_drag_is_active() && os_key_press(events, ws->os, 0, OS_Key_Esc)) + { + df_drag_kill(); + ui_kill_action(); + } + + //- rjf: font size changing + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if(os_handle_match(event->window, ws->os) && event->kind == OS_EventKind_Scroll && event->flags & OS_EventFlag_Ctrl) + { + os_eat_event(ui_events(), event); + if(event->delta.y < 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_IncUIFontScale)); + } + else if(event->delta.y > 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DecUIFontScale)); + } + } + } + } + ui_end_build(); + + //- rjf: ensure hover eval is in-bounds + if(!ui_box_is_nil(hover_eval_box)) + { + UI_Box *root = hover_eval_box; + Rng2F32 window_rect = os_client_rect_from_window(ui_window()); + Rng2F32 root_rect = root->rect; + Vec2F32 shift = + { + -ClampBot(0, root_rect.x1 - window_rect.x1), + -ClampBot(0, root_rect.y1 - window_rect.y1), + }; + Rng2F32 new_root_rect = shift_2f32(root_rect, shift); + root->fixed_position = new_root_rect.p0; + root->fixed_size = dim_2f32(new_root_rect); + root->rect = new_root_rect; + for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis + 1)) + { + ui_calc_sizes_standalone__in_place_rec(root, axis); + ui_calc_sizes_upwards_dependent__in_place_rec(root, axis); + ui_calc_sizes_downwards_dependent__in_place_rec(root, axis); + ui_layout_enforce_constraints__in_place_rec(root, axis); + ui_layout_position__in_place_rec(root, axis); + } + } + + //- rjf: attach autocomp box to root + if(!ui_box_is_nil(autocomp_box)) + { + UI_Box *autocomp_root_box = ui_box_from_key(ws->autocomp_root_key); + if(!ui_box_is_nil(autocomp_root_box)) + { + Vec2F32 size = autocomp_box->fixed_size; + autocomp_box->fixed_position = v2f32(autocomp_root_box->rect.x0, autocomp_root_box->rect.y1); + autocomp_box->rect = r2f32(autocomp_box->fixed_position, add_2f32(autocomp_box->fixed_position, size)); + for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis + 1)) + { + ui_calc_sizes_standalone__in_place_rec(autocomp_box, axis); + ui_calc_sizes_upwards_dependent__in_place_rec(autocomp_box, axis); + ui_calc_sizes_downwards_dependent__in_place_rec(autocomp_box, axis); + ui_layout_enforce_constraints__in_place_rec(autocomp_box, axis); + ui_layout_position__in_place_rec(autocomp_box, axis); + } + } + } + + //- rjf: hover eval cancelling + if(ws->hover_eval_string.size != 0 && os_key_press(events, ws->os, 0, OS_Key_Esc)) + { + MemoryZeroStruct(&ws->hover_eval_string); + arena_clear(ws->hover_eval_arena); + df_gfx_request_frame(); + } + + //- rjf: animate + if(ui_animating_from_state(ws->ui)) + { + df_gfx_request_frame(); + } + + //- rjf: draw UI + ws->draw_bucket = d_bucket_make(); + D_BucketScope(ws->draw_bucket) + ProfScope("draw UI") + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: set up heatmap buckets + F32 heatmap_bucket_size = 32.f; + U64 *heatmap_buckets = 0; + U64 heatmap_bucket_pitch = 0; + U64 heatmap_bucket_count = 0; + if(DEV_draw_ui_box_heatmap) + { + Rng2F32 rect = os_client_rect_from_window(ws->os); + Vec2F32 size = dim_2f32(rect); + Vec2S32 buckets_dim = {(S32)(size.x/heatmap_bucket_size), (S32)(size.y/heatmap_bucket_size)}; + heatmap_bucket_pitch = buckets_dim.x; + heatmap_bucket_count = buckets_dim.x*buckets_dim.y; + heatmap_buckets = push_array(scratch.arena, U64, heatmap_bucket_count); + } + + //- rjf: draw background color + { + Vec4F32 bg_color = df_rgba_from_theme_color(DF_ThemeColor_PlainBackground); + d_rect(os_client_rect_from_window(ws->os), bg_color, 0, 0, 0); + } + + //- rjf: recurse & draw + U64 total_heatmap_sum_count = 0; + for(UI_Box *box = ui_root_from_state(ws->ui); !ui_box_is_nil(box);) + { + // rjf: get recursion + UI_BoxRec rec = ui_box_rec_df_post(box, &ui_g_nil_box); + + // rjf: sum to box heatmap + if(DEV_draw_ui_box_heatmap) + { + Vec2F32 center = center_2f32(box->rect); + Vec2S32 p = v2s32(center.x / heatmap_bucket_size, center.y / heatmap_bucket_size); + U64 bucket_idx = p.y * heatmap_bucket_pitch + p.x; + if(bucket_idx < heatmap_bucket_count) + { + heatmap_buckets[bucket_idx] += 1; + total_heatmap_sum_count += 1; + } + } + + // rjf: draw drop shadow + if(box->flags & UI_BoxFlag_DrawDropShadow) + { + Rng2F32 drop_shadow_rect = shift_2f32(pad_2f32(box->rect, 8), v2f32(4, 4)); + Vec4F32 drop_shadow_color = df_rgba_from_theme_color(DF_ThemeColor_DropShadow); + d_rect(drop_shadow_rect, drop_shadow_color, 0.8f, 0, 8.f); + } + + // rjf: blur background + if(box->flags & UI_BoxFlag_DrawBackgroundBlur) + { + R_PassParams_Blur *params = d_blur(box->rect, box->blur_size, 0); + MemoryCopyArray(params->corner_radii, box->corner_radii); + } + + // rjf: draw background + if(box->flags & UI_BoxFlag_DrawBackground) + { + // rjf: main rectangle + { + R_Rect2DInst *inst = d_rect(pad_2f32(box->rect, 1.5f), box->background_color, 0, 0, 1.f); + MemoryCopyArray(inst->corner_radii, box->corner_radii); + } + + // rjf: hot effect extension + if(box->flags & UI_BoxFlag_DrawHotEffects) + { + F32 effective_active_t = box->active_t; + if(!(box->flags & UI_BoxFlag_DrawActiveEffects)) + { + effective_active_t = 0; + } + F32 t = box->hot_t*(1-effective_active_t); + + // rjf: brighten + { + R_Rect2DInst *inst = d_rect(box->rect, v4f32(0, 0, 0, 0), 0, 0, 1.f); + inst->colors[Corner_00] = v4f32(1.f, 0.9f, 0.7f, 0.1f*t); + inst->colors[Corner_01] = v4f32(1.f, 0.9f, 0.7f, 0.1f*t); + inst->colors[Corner_10] = v4f32(1.f, 0.9f, 0.7f, 0.1f*t); + inst->colors[Corner_11] = v4f32(1.f, 0.9f, 0.7f, 0.1f*t); + MemoryCopyArray(inst->corner_radii, box->corner_radii); + } + + // rjf: slight emboss fadeoff + { + Rng2F32 rect = r2f32p(box->rect.x0, + box->rect.y0, + box->rect.x1, + box->rect.y1); + R_Rect2DInst *inst = d_rect(rect, v4f32(0, 0, 0, 0), 0, 0, 1.f); + inst->colors[Corner_00] = v4f32(0.f, 0.f, 0.f, 0.0f*t); + inst->colors[Corner_01] = v4f32(0.f, 0.f, 0.f, 0.3f*t); + inst->colors[Corner_10] = v4f32(0.f, 0.f, 0.f, 0.0f*t); + inst->colors[Corner_11] = v4f32(0.f, 0.f, 0.f, 0.3f*t); + MemoryCopyArray(inst->corner_radii, box->corner_radii); + } + } + + // rjf: active effect extension + if(box->flags & UI_BoxFlag_DrawActiveEffects) + { + Vec2F32 shadow_size = + { + (box->rect.x1 - box->rect.x0)*0.60f*box->active_t, + (box->rect.y1 - box->rect.y0)*0.60f*box->active_t, + }; + shadow_size.x = Clamp(0, shadow_size.x, box->font_size*2.f); + shadow_size.y = Clamp(0, shadow_size.y, box->font_size*2.f); + + // rjf: top -> bottom dark effect + { + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x0, box->rect.y0, box->rect.x1, box->rect.y0 + shadow_size.y), v4f32(0, 0, 0, 0), 0, 0, 1.f); + inst->colors[Corner_00] = inst->colors[Corner_10] = v4f32(0.f, 0.f, 0.f, 0.8f*box->active_t); + inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(0.f, 0.f, 0.f, 0.0f); + MemoryCopyArray(inst->corner_radii, box->corner_radii); + } + + // rjf: bottom -> top light effect + { + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x0, box->rect.y1 - shadow_size.y, box->rect.x1, box->rect.y1), v4f32(0, 0, 0, 0), 0, 0, 1.f); + inst->colors[Corner_00] = inst->colors[Corner_10] = v4f32(0, 0, 0, 0); + inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(0.4f, 0.4f, 0.4f, 0.4f*box->active_t); + MemoryCopyArray(inst->corner_radii, box->corner_radii); + } + + // rjf: left -> right dark effect + { + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x0, box->rect.y0, box->rect.x0 + shadow_size.x, box->rect.y1), v4f32(0, 0, 0, 0), 0, 0, 1.f); + inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(0.f, 0.f, 0.f, 0.f); + inst->colors[Corner_00] = v4f32(0.f, 0.f, 0.f, 0.8f*box->active_t); + inst->colors[Corner_01] = v4f32(0.f, 0.f, 0.f, 0.4f*box->active_t); + MemoryCopyArray(inst->corner_radii, box->corner_radii); + } + + // rjf: right -> left dark effect + { + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x1 - shadow_size.x, box->rect.y0, box->rect.x1, box->rect.y1), v4f32(0, 0, 0, 0), 0, 0, 1.f); + inst->colors[Corner_00] = inst->colors[Corner_01] = v4f32(0.f, 0.f, 0.f, 0.f); + inst->colors[Corner_10] = v4f32(0.f, 0.f, 0.f, 0.8f*box->active_t); + inst->colors[Corner_11] = v4f32(0.f, 0.f, 0.f, 0.4f*box->active_t); + MemoryCopyArray(inst->corner_radii, box->corner_radii); + } + } + } + + // rjf: draw string + if(box->flags & UI_BoxFlag_DrawText) + { + Vec2F32 text_position = ui_box_text_position(box); + if(DEV_draw_ui_text_pos) + { + d_rect(r2f32p(text_position.x-4, text_position.y-4, text_position.x+4, text_position.y+4), + v4f32(1, 0, 1, 1), 1, 0, 1); + } + F32 max_x = 100000.f; + F_Run ellipses_run = {0}; + if(!(box->flags & UI_BoxFlag_DisableTextTrunc)) + { + max_x = (box->rect.x1-text_position.x); + ellipses_run = f_push_run_from_string(scratch.arena, box->font, box->font_size, 0, str8_lit("...")); + } + d_truncated_fancy_run_list(text_position, &box->display_string_runs, max_x, ellipses_run); + } + + // rjf: draw focus viz + if(DEV_draw_ui_focus_debug) + { + B32 focused = (box->flags & (UI_BoxFlag_FocusHot|UI_BoxFlag_FocusActive) && + box->flags & UI_BoxFlag_Clickable); + B32 disabled = 0; + for(UI_Box *p = box; !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & (UI_BoxFlag_FocusHotDisabled|UI_BoxFlag_FocusActiveDisabled)) + { + disabled = 1; + break; + } + } + if(focused) + { + Vec4F32 color = v4f32(0.3f, 0.8f, 0.3f, 1.f); + if(disabled) + { + color = v4f32(0.8f, 0.3f, 0.3f, 1.f); + } + d_rect(r2f32p(box->rect.x0-6, box->rect.y0-6, box->rect.x0+6, box->rect.y0+6), color, 2, 0, 1); + d_rect(box->rect, color, 2, 2, 1); + } + if(box->flags & (UI_BoxFlag_FocusHot|UI_BoxFlag_FocusActive)) + { + if(box->flags & (UI_BoxFlag_FocusHotDisabled|UI_BoxFlag_FocusActiveDisabled)) + { + d_rect(r2f32p(box->rect.x0-6, box->rect.y0-6, box->rect.x0+6, box->rect.y0+6), v4f32(1, 0, 0, 0.2f), 2, 0, 1); + } + else + { + d_rect(r2f32p(box->rect.x0-6, box->rect.y0-6, box->rect.x0+6, box->rect.y0+6), v4f32(0, 1, 0, 0.2f), 2, 0, 1); + } + } + } + + // rjf: push clip + if(box->flags & UI_BoxFlag_Clip && rec.push_count != 0) + { + Rng2F32 top_clip = d_top_clip(); + Rng2F32 new_clip = pad_2f32(box->rect, -1); + if(top_clip.x1 != 0 || top_clip.y1 != 0) + { + new_clip = intersect_2f32(new_clip, top_clip); + } + d_push_clip(new_clip); + } + + // rjf: custom draw list + if(box->flags & UI_BoxFlag_DrawBucket) + { + Mat3x3F32 xform = make_translate_3x3f32(box->position_delta); + D_XForm2DScope(xform) + { + d_sub_bucket(box->draw_bucket); + } + } + + // rjf: call custom draw callback + if(box->custom_draw != 0) + { + box->custom_draw(box, box->custom_draw_user_data); + } + + // rjf: pop + { + S32 pop_idx = 0; + for(UI_Box *b = box; !ui_box_is_nil(b) && pop_idx <= rec.pop_count; b = b->parent) + { + // rjf: pop clips + if(b != box && b->flags & UI_BoxFlag_Clip) + { + d_pop_clip(); + } + + // rjf: draw border + if(b->flags & UI_BoxFlag_DrawBorder) + { + R_Rect2DInst *inst = d_rect(pad_2f32(b->rect, 1), b->border_color, 0, 1.f, 1.f); + MemoryCopyArray(inst->corner_radii, b->corner_radii); + + // rjf: hover effect + if(b->flags & UI_BoxFlag_DrawHotEffects) + { + R_Rect2DInst *inst = d_rect(pad_2f32(b->rect, 1.f), v4f32(1, 1, 1, 0.5f*b->hot_t), 0, 1.f, 1.f); + MemoryCopyArray(inst->corner_radii, b->corner_radii); + } + } + + // rjf: draw sides + { + Rng2F32 r = b->rect; + F32 half_thickness = 1.f; + F32 softness = 0.5f; + if(b->flags & UI_BoxFlag_DrawSideTop) + { + d_rect(r2f32p(r.x0, r.y0-half_thickness, r.x1, r.y0+half_thickness), b->border_color, 0, 0, softness); + } + if(b->flags & UI_BoxFlag_DrawSideBottom) + { + d_rect(r2f32p(r.x0, r.y1-half_thickness, r.x1, r.y1+half_thickness), b->border_color, 0, 0, softness); + } + if(b->flags & UI_BoxFlag_DrawSideLeft) + { + d_rect(r2f32p(r.x0-half_thickness, r.y0, r.x0+half_thickness, r.y1), b->border_color, 0, 0, softness); + } + if(b->flags & UI_BoxFlag_DrawSideRight) + { + d_rect(r2f32p(r.x1-half_thickness, r.y0, r.x1+half_thickness, r.y1), b->border_color, 0, 0, softness); + } + } + + // rjf: draw focus hot vis + if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusViz) && b->focus_hot_t > 0.01f) + { + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + F32 size_factor = 1 - Clamp(0, dim_2f32(b->rect).y / 100.f, 1); + if(b->flags & UI_BoxFlag_RequireFocusBackground) + { + color.w *= 0.2f + b->focus_hot_t * 0.3f * size_factor; + } + else + { + color.w *= b->focus_hot_t * 0.5f * size_factor; + } + R_Rect2DInst *inst = d_rect(pad_2f32(r2f32p(b->rect.x0, + b->rect.y0, + b->rect.x0 + (b->rect.x1 - b->rect.x0) * b->focus_hot_t, + b->rect.y1), + 6.f), + color, 4.f, 0, 4.f); + inst->colors[Corner_10] = inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(color.x, color.y, color.z, color.w/3.f); + MemoryCopyArray(inst->corner_radii, b->corner_radii); + } + + // rjf: draw focus active vis + if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusViz) && b->focus_active_t > 0.01f) + { + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + color.w *= b->focus_active_t; + R_Rect2DInst *inst = d_rect(pad_2f32(b->rect, 1.f), color, 0, 2.f, 1.f); + inst->colors[Corner_10] = inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(color.x, color.y, color.z, color.w/3.f); + MemoryCopyArray(inst->corner_radii, b->corner_radii); + } + + // rjf: draw overlay + if(b->flags & UI_BoxFlag_DrawOverlay) + { + R_Rect2DInst *inst = d_rect(b->rect, b->overlay_color, 0, 0, 1); + MemoryCopyArray(inst->corner_radii, b->corner_radii); + } + + // rjf: draw keyboard root vis +#if 0 + if(b->flags & UI_BoxFlag_FocusRoot) + { + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + R2_CmdInst_Rect *inst = d_rect(rect_grow(b->rect, 2.f), color, 0, 2.f, 1.f); + MemoryCopyArray(inst->corner_radii, b->corner_radii); + } +#endif + + // rjf: disabled overlay + if(b->disabled_t >= 0.005f) + { + R_Rect2DInst *inst = d_rect(b->rect, v4f32(0, 0, 0, 0.5f*b->disabled_t), 0, 0, 1); + MemoryCopyArray(inst->corner_radii, b->corner_radii); + } + + pop_idx += 1; + } + } + + // rjf: next + box = rec.next; + } + + //- rjf: draw heatmap + if(DEV_draw_ui_box_heatmap) + { + U64 uniform_dist_count = total_heatmap_sum_count / heatmap_bucket_count; + uniform_dist_count = ClampBot(uniform_dist_count, 10); + for(U64 bucket_idx = 0; bucket_idx < heatmap_bucket_count; bucket_idx += 1) + { + U64 x = bucket_idx % heatmap_bucket_pitch; + U64 y = bucket_idx / heatmap_bucket_pitch; + U64 bucket = heatmap_buckets[bucket_idx]; + F32 pct = (F32)bucket / uniform_dist_count; + pct = Clamp(0, pct, 1); + Vec3F32 hsv = v3f32((1-pct) * 0.9411f, 1, 0.5f); + Vec3F32 rgb = rgb_from_hsv(hsv); + Rng2F32 rect = r2f32p(x*heatmap_bucket_size, y*heatmap_bucket_size, (x+1)*heatmap_bucket_size, (y+1)*heatmap_bucket_size); + d_rect(rect, v4f32(rgb.x, rgb.y, rgb.z, 0.3f), 0, 0, 0); + } + } + + // TODO(rjf): MESH DRAWING TEST +#if 0 + { + F32 vertex_data[] = // pos.x, pos.y, pos.z, nor.x, nor.y, nor.z, tex.u, tex.v, col.r, col.g, col.b, ... + { + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 2.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 2.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 8.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 8.0f, 0.973f, 0.480f, 0.002f, + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 2.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 2.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 8.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 8.0f, 0.612f, 0.000f, 0.069f, + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 2.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 2.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 8.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 8.0f, 0.000f, 0.254f, 0.637f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 2.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 2.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 8.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 8.0f, 0.001f, 0.447f, 0.067f, + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + }; + + U32 index_data[] = + { + 0, 1, 9, 9, 8, 0, 1, 2, 5, 5, 4, 1, 6, 7, 10, 10, 9, 6, 2, 3, 11, 11, 10, 2, + 12, 13, 21, 21, 20, 12, 13, 14, 17, 17, 16, 13, 18, 19, 22, 22, 21, 18, 14, 15, 23, 23, 22, 14, + 24, 25, 33, 33, 32, 24, 25, 26, 29, 29, 28, 25, 30, 31, 34, 34, 33, 30, 26, 27, 35, 35, 34, 26, + 36, 37, 45, 45, 44, 36, 37, 38, 41, 41, 40, 37, 42, 43, 46, 46, 45, 42, 38, 39, 47, 47, 46, 38, + 48, 49, 57, 57, 56, 48, 49, 50, 53, 53, 52, 49, 54, 55, 58, 58, 57, 54, 50, 51, 59, 59, 58, 50, + 60, 61, 69, 69, 68, 60, 61, 62, 65, 65, 64, 61, 66, 67, 70, 70, 69, 66, 62, 63, 71, 71, 70, 62, + 72, 73, 74, 74, 75, 72, 76, 77, 78, 78, 79, 76, 80, 81, 82, 82, 83, 80, 84, 85, 86, 86, 87, 84, + 88, 89, 90, 90, 91, 88, 92, 93, 94, 94, 95, 92, 96, 97, 98, 98, 99, 96, 100, 101, 102, 102, 103, 100, + 104, 105, 106, 106, 107, 104, 108, 109, 110, 110, 111, 108, 112, 113, 114, 114, 115, 112, 116, 117, 118, 118, 119, 116, + 120, 121, 122, 122, 123, 120, 124, 125, 126, 126, 127, 124, 128, 129, 130, 130, 131, 128, 132, 133, 134, 134, 135, 132, + 136, 137, 138, 138, 139, 136, 140, 141, 142, 142, 143, 140, 144, 145, 146, 146, 147, 144, 148, 149, 150, 150, 151, 148, + 152, 153, 154, 154, 155, 152, 156, 157, 158, 158, 159, 156, 160, 161, 162, 162, 163, 160, 164, 165, 166, 166, 167, 164, + }; + + R_Handle vertex_buffer = r_buffer_alloc(R_BufferKind_Static, sizeof(vertex_data), vertex_data); + R_Handle index_buffer = r_buffer_alloc(R_BufferKind_Static, sizeof(index_data), index_data); + Rng2F32 viewport = os_client_rect_from_window(ws->os); + Vec2F32 viewport_dim = dim_2f32(viewport); + d_geo3d_begin(viewport, + make_look_at_4x4f32(v3f32(10*cos_f32(df_time_in_seconds()), 10*sin_f32(df_time_in_seconds()), 10), v3f32(0, 0, 0), v3f32(0, 0, 1)), + make_perspective_4x4f32(0.25f, viewport_dim.x/viewport_dim.y, 0.1f, 500.f)); + d_mesh(vertex_buffer, index_buffer, R_GeoTopologyKind_Triangles, R_GeoVertexFlag_TexCoord|R_GeoVertexFlag_Normals|R_GeoVertexFlag_RGB, r_handle_zero(), mat_4x4f32(1.f)); + } +#endif + + //- rjf: draw border/overlay color to signify error + if(ws->error_t > 0.01f) + { + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + color.w *= ws->error_t; + Rng2F32 rect = os_client_rect_from_window(ws->os); + d_rect(pad_2f32(rect, 24.f), color, 0, 16.f, 12.f); + d_rect(rect, v4f32(color.x, color.y, color.z, color.w*0.05f), 0, 0, 0); + } + + //- rjf: scratch debug mouse drawing + if(DEV_scratch_mouse_draw) + { + Vec2F32 p = add_2f32(os_mouse_from_window(ws->os), v2f32(30, 0)); + d_rect(os_client_rect_from_window(ws->os), v4f32(0, 0, 0, 0.4f), 0, 0, 0); + D_FancyStringList strs = {0}; + D_FancyString str1 = {df_font_from_slot(DF_FontSlot_Main), str8_lit("T"), v4f32(1, 1, 1, 1), 16.f, 4.f}; + d_fancy_string_list_push(scratch.arena, &strs, &str1); + D_FancyString str2 = {df_font_from_slot(DF_FontSlot_Main), str8_lit("his is a test of some "), v4f32(1, 0.5f, 0.5f, 1), 14.f, 0.f}; + d_fancy_string_list_push(scratch.arena, &strs, &str2); + D_FancyString str3 = {df_font_from_slot(DF_FontSlot_Code), str8_lit("very fancy text!"), v4f32(1, 0.8f, 0.4f, 1), 18.f, 4.f, 4.f}; + d_fancy_string_list_push(scratch.arena, &strs, &str3); + D_FancyRunList runs = d_fancy_run_list_from_fancy_string_list(scratch.arena, &strs); + F_Run trailer_run = f_push_run_from_string(scratch.arena, df_font_from_slot(DF_FontSlot_Main), 16.f, 0, str8_lit("...")); + F32 limit = 500.f + sin_f32(df_time_in_seconds()/10.f)*200.f; + d_truncated_fancy_run_list(p, &runs, limit, trailer_run); + d_rect(r2f32p(p.x+limit, 0, p.x+limit+2.f, 1000), v4f32(1, 0, 0, 1), 0, 0, 0); + df_gfx_request_frame(); + } + + scratch_end(scratch); + } + + //- rjf: show window after first frame + { + if(ws->frames_alive == 0) + { + os_window_first_paint(ws->os); + } + ws->frames_alive += 1; + } + + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Eval Viz + +internal String8List +df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, DF_CfgTable *cfg_table) +{ + ProfBeginFunction(); + String8List list = {0}; + F32 space_taken = 0; + if(max_size > 0) + { + TG_Kind eval_type_kind = tg_kind_from_key(tg_unwrapped_from_graph_raddbg_key(graph, rdbg, eval.type_key)); + U32 radix = default_radix; + DF_CfgVal *dec_cfg = df_cfg_val_from_string(cfg_table, str8_lit("dec")); + DF_CfgVal *hex_cfg = df_cfg_val_from_string(cfg_table, str8_lit("hex")); + DF_CfgVal *bin_cfg = df_cfg_val_from_string(cfg_table, str8_lit("bin")); + DF_CfgVal *oct_cfg = df_cfg_val_from_string(cfg_table, str8_lit("oct")); + U64 best_insertion_stamp = Max(dec_cfg->insertion_stamp, Max(hex_cfg->insertion_stamp, Max(bin_cfg->insertion_stamp, oct_cfg->insertion_stamp))); + if(dec_cfg != &df_g_nil_cfg_val && dec_cfg->insertion_stamp == best_insertion_stamp) { radix = 10; } + if(hex_cfg != &df_g_nil_cfg_val && hex_cfg->insertion_stamp == best_insertion_stamp) { radix = 16; } + if(bin_cfg != &df_g_nil_cfg_val && bin_cfg->insertion_stamp == best_insertion_stamp) { radix = 2; } + if(oct_cfg != &df_g_nil_cfg_val && oct_cfg->insertion_stamp == best_insertion_stamp) { radix = 8; } + switch(eval_type_kind) + { + //- rjf: default - leaf cases + default: + { + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, eval); + String8 string = df_string_from_simple_typed_eval(arena, graph, rdbg, flags, radix, value_eval); + space_taken += f_dim_from_tag_size_string(font, font_size, string).x; + str8_list_push(arena, &list, string); + }break; + + //- rjf: pointers + case TG_Kind_Function: + case TG_Kind_Ptr: + case TG_Kind_LRef: + case TG_Kind_RRef: + { + // rjf: determine ptr value omission + DF_CfgVal *noaddr_cfg = df_cfg_val_from_string(cfg_table, str8_lit("no_addr")); + B32 no_addr = (noaddr_cfg != &df_g_nil_cfg_val) && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules); + + // rjf: determine presence of array view rule -> omit c-string fastpath + DF_CfgVal *array_cfg = df_cfg_val_from_string(cfg_table, str8_lit("array")); + B32 has_array = (array_cfg != &df_g_nil_cfg_val); + + // rjf: get ptr value + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, eval); + + // rjf: get pointed-at info + TG_Key direct_type_key = tg_ptee_from_graph_raddbg_key(graph, rdbg, eval.type_key); + TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); + B32 direct_type_has_content = (direct_type_kind != TG_Kind_Null && direct_type_kind != TG_Kind_Void && value_eval.imm_u64 != 0); + B32 direct_type_is_string = (direct_type_kind != TG_Kind_Null && value_eval.imm_u64 != 0 && + ((TG_Kind_Char8 <= direct_type_kind && direct_type_kind <= TG_Kind_UChar32) || + direct_type_kind == TG_Kind_Char8 || + direct_type_kind == TG_Kind_UChar8)); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + String8 symbol_name = df_symbol_name_from_process_vaddr(arena, process, value_eval.imm_u64); + + // rjf: display ptr value + B32 did_ptr_value = 0; + if(!no_addr || (direct_type_has_content == 0 && direct_type_is_string == 0)) + { + did_ptr_value = 1; + String8 string = df_string_from_simple_typed_eval(arena, graph, rdbg, flags, radix, value_eval); + space_taken += f_dim_from_tag_size_string(font, font_size, string).x; + str8_list_push(arena, &list, string); + } + + // rjf: arrow + if(did_ptr_value && direct_type_has_content && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules)) + { + String8 arrow = str8_lit(" -> "); + str8_list_push(arena, &list, arrow); + space_taken += f_dim_from_tag_size_string(font, font_size, arrow).x; + } + + // rjf: special-case: strings + if(!has_array && direct_type_is_string && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules) && eval.mode == EVAL_EvalMode_Addr) + { + U64 string_memory_addr = value_eval.imm_u64; + String8 text = ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(arena, process->ctrl_machine_id, process->ctrl_handle, string_memory_addr, 256, max_U64); + space_taken += f_dim_from_tag_size_string(font, font_size, text).x; + space_taken += 2*f_dim_from_tag_size_string(font, font_size, str8_lit("\"")).x; + str8_list_push(arena, &list, str8_lit("\"")); + str8_list_push(arena, &list, text); + str8_list_push(arena, &list, str8_lit("\"")); + } + + // rjf: special-case: symbols + else if(direct_type_has_content && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules) && symbol_name.size != 0) + { + str8_list_push(arena, &list, symbol_name); + space_taken += f_dim_from_tag_size_string(font, font_size, symbol_name).x; + } + + // rjf: descend to pointed-at thing + else if(direct_type_has_content && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules)) + { + if(depth < 3) + { + DF_Eval pted_eval = zero_struct; + pted_eval.type_key = direct_type_key; + pted_eval.mode = EVAL_EvalMode_Addr; + pted_eval.offset = value_eval.imm_u64; + String8List pted_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdbg, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, pted_eval, cfg_table); + if(pted_strs.total_size == 0) + { + String8 unknown = str8_lit("???"); + str8_list_push(arena, &list, unknown); + space_taken += f_dim_from_tag_size_string(font, font_size, unknown).x; + } + else + { + space_taken += f_dim_from_tag_size_string_list(font, font_size, pted_strs).x; + str8_list_concat_in_place(&list, &pted_strs); + } + } + else + { + String8 ellipses = str8_lit("..."); + str8_list_push(arena, &list, ellipses); + space_taken += f_dim_from_tag_size_string(font, font_size, ellipses).x; + } + } + }break; + + //- rjf: arrays + case TG_Kind_Array: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *eval_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, eval.type_key); + TG_Key direct_type_key = eval_type->direct_type_key; + TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); + U64 array_count = eval_type->count; + + // rjf: determine presence of array view rule -> omit c-string fastpath + DF_CfgVal *array_cfg = df_cfg_val_from_string(cfg_table, str8_lit("array")); + B32 has_array = (array_cfg != &df_g_nil_cfg_val); + + // rjf: get pointed-at type + B32 direct_type_is_string = (direct_type_kind != TG_Kind_Null && + ((TG_Kind_Char8 <= direct_type_kind && direct_type_kind <= TG_Kind_UChar32) || + direct_type_kind == TG_Kind_S8 || + direct_type_kind == TG_Kind_U8)); + B32 special_case = 0; + + // rjf: special-case: strings + if(!has_array && direct_type_is_string && eval.mode == EVAL_EvalMode_Addr) + { + special_case = 1; + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + String8 text = ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(arena, process->ctrl_machine_id, process->ctrl_handle, eval.offset, 256, max_U64); + space_taken += f_dim_from_tag_size_string(font, font_size, text).x; + space_taken += 2*f_dim_from_tag_size_string(font, font_size, str8_lit("\"")).x; + str8_list_push(arena, &list, str8_lit("\"")); + str8_list_push(arena, &list, text); + str8_list_push(arena, &list, str8_lit("\"")); + } + + // rjf: open brace + if(!special_case) + { + String8 brace = str8_lit("["); + str8_list_push(arena, &list, brace); + space_taken += f_dim_from_tag_size_string(font, font_size, brace).x; + } + + // rjf: content + if(!special_case) + { + if(depth < 3) + { + U64 direct_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct_type_key); + for(U64 idx = 0; idx < array_count && max_size > space_taken; idx += 1) + { + DF_Eval element_eval = zero_struct; + element_eval.type_key = direct_type_key; + element_eval.mode = eval.mode; + element_eval.offset = eval.offset + direct_type_byte_size*idx; + MemoryCopyArray(element_eval.imm_u128, eval.imm_u128); + String8List element_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdbg, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, element_eval, cfg_table); + space_taken += f_dim_from_tag_size_string_list(font, font_size, element_strs).x; + str8_list_concat_in_place(&list, &element_strs); + if(idx+1 < array_count) + { + String8 comma = str8_lit(", "); + space_taken += f_dim_from_tag_size_string(font, font_size, comma).x; + str8_list_push(arena, &list, comma); + } + } + } + else + { + String8 ellipses = str8_lit("..."); + str8_list_push(arena, &list, ellipses); + space_taken += f_dim_from_tag_size_string(font, font_size, ellipses).x; + } + } + + // rjf: close brace + if(!special_case) + { + String8 brace = str8_lit("]"); + str8_list_push(arena, &list, brace); + space_taken += f_dim_from_tag_size_string(font, font_size, brace).x; + } + scratch_end(scratch); + }break; + + //- rjf: structs + case TG_Kind_Struct: + case TG_Kind_Union: + case TG_Kind_Class: + case TG_Kind_IncompleteStruct: + case TG_Kind_IncompleteUnion: + case TG_Kind_IncompleteClass: + { + // rjf: open brace + { + String8 brace = str8_lit("{"); + str8_list_push(arena, &list, brace); + space_taken += f_dim_from_tag_size_string(font, font_size, brace).x; + } + + // rjf: content + if(depth < 4) + { + Temp scratch = scratch_begin(&arena, 1); + TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, graph, rdbg, eval.type_key); + TG_MemberArray filtered_data_members = df_filtered_data_members_from_members_cfg_table(scratch.arena, data_members, cfg_table); + for(U64 member_idx = 0; member_idx < filtered_data_members.count && max_size > space_taken; member_idx += 1) + { + TG_Member *mem = &filtered_data_members.v[member_idx]; + DF_Eval member_eval = zero_struct; + member_eval.type_key = mem->type_key; + member_eval.mode = eval.mode; + member_eval.offset = eval.offset + mem->off; + MemoryCopyArray(member_eval.imm_u128, eval.imm_u128); + String8List member_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdbg, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, member_eval, cfg_table); + space_taken += f_dim_from_tag_size_string_list(font, font_size, member_strs).x; + str8_list_concat_in_place(&list, &member_strs); + if(member_idx+1 < filtered_data_members.count) + { + String8 comma = str8_lit(", "); + space_taken += f_dim_from_tag_size_string(font, font_size, comma).x; + str8_list_push(arena, &list, comma); + } + } + scratch_end(scratch); + } + else + { + String8 ellipses = str8_lit("..."); + str8_list_push(arena, &list, ellipses); + space_taken += f_dim_from_tag_size_string(font, font_size, ellipses).x; + } + + // rjf: close brace + { + String8 brace = str8_lit("}"); + str8_list_push(arena, &list, brace); + space_taken += f_dim_from_tag_size_string(font, font_size, brace).x; + } + + }break; + } + } + ProfEnd(); + return list; +} + +internal DF_EvalVizWindowedRowList +df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: produce windowed rows + U64 visual_idx_off = 0; + U64 semantic_idx_off = 0; + DF_EvalVizWindowedRowList list = {0}; + for(DF_EvalVizBlock *block = blocks->first; block != 0; block = block->next) + { + //- rjf: extract block info + U64 block_num_visual_rows = dim_1u64(block->visual_idx_range); + U64 block_num_semantic_rows = dim_1u64(block->semantic_idx_range); + Rng1S64 block_visual_range = r1s64(visual_idx_off, visual_idx_off + block_num_visual_rows); + Rng1S64 block_semantic_range = r1s64(semantic_idx_off, semantic_idx_off + block_num_semantic_rows); + TG_Kind block_type_kind = tg_kind_from_key(block->eval.type_key); + + //- rjf: determine if view rules force expandability + B32 expandability_required = 0; + for(DF_CfgVal *val = block->cfg_table.first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) + { + DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string); + if(spec->info.flags & DF_CoreViewRuleSpecInfoFlag_Expandable) + { + expandability_required = 1; + break; + } + } + + //- rjf: grab default row ui view rule to use for this block + DF_GfxViewRuleSpec *value_ui_rule_spec = &df_g_nil_gfx_view_rule_spec; + DF_CfgNode *value_ui_rule_node= &df_g_nil_cfg_node; + for(DF_CfgVal *val = block->cfg_table.first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) + { + DF_GfxViewRuleSpec *spec = df_gfx_view_rule_spec_from_string(val->string); + if(spec->info.flags & DF_GfxViewRuleSpecInfoFlag_RowUI) + { + value_ui_rule_spec = spec; + value_ui_rule_node = val->last; + break; + } + } + + //- rjf: grab expand ui view rule to use for this block's rows + DF_GfxViewRuleSpec *expand_ui_rule_spec = &df_g_nil_gfx_view_rule_spec; + DF_CfgNode *expand_ui_rule_node = &df_g_nil_cfg_node; + for(DF_CfgVal *val = block->cfg_table.first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) + { + DF_GfxViewRuleSpec *spec = df_gfx_view_rule_spec_from_string(val->string); + if(spec->info.flags & DF_GfxViewRuleSpecInfoFlag_BlockUI) + { + expand_ui_rule_spec = spec; + expand_ui_rule_node = val->last; + break; + } + } + + //- rjf: get skip/chop of block's index range + U64 num_skipped_visual = 0; + U64 num_chopped_visual = 0; + { + if(visible_range.min > block_visual_range.min) + { + num_skipped_visual = (visible_range.min - block_visual_range.min); + num_skipped_visual = Min(num_skipped_visual, block_num_visual_rows); + } + if(visible_range.max < block_visual_range.max) + { + num_chopped_visual = (block_visual_range.max - visible_range.max); + num_chopped_visual = Min(num_chopped_visual, block_num_visual_rows); + } + } + + //- rjf: get visible idx range & invisible counts + Rng1U64 visible_idx_range = block->visual_idx_range; + { + visible_idx_range.min += num_skipped_visual; + visible_idx_range.max -= num_chopped_visual; + } + + //- rjf: sum & advance + list.count_before_visual += num_skipped_visual; + if(block_num_visual_rows != 0) + { + list.count_before_semantic += block_num_semantic_rows * num_skipped_visual / block_num_visual_rows; + } + visual_idx_off += block_num_visual_rows; + semantic_idx_off += block_num_semantic_rows; + + //- rjf: produce rows, depending on block's kind + switch(block->kind) + { + default:{}break; + + //- rjf: root -> just a single row. possibly expandable. + case DF_EvalVizBlockKind_Root: + if(visible_idx_range.max > visible_idx_range.min) + { + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, block->eval, &block->cfg_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, block->eval, &block->cfg_table); + DF_EvalVizRow *row = push_array(arena, DF_EvalVizRow, 1); + row->eval_view = block->eval_view; + row->eval = block->eval; + row->expr = block->string; + row->display_value = str8_list_join(arena, &display_strings, 0); + row->edit_value = str8_list_join(arena, &edit_strings, 0); + row->value_ui_rule_node = value_ui_rule_node; + row->value_ui_rule_spec = value_ui_rule_spec; + row->expand_ui_rule_node = expand_ui_rule_node; + row->expand_ui_rule_spec = expand_ui_rule_spec; + row->errors = block->eval.errors; + if(block_type_kind != TG_Kind_Null) + { + for(TG_Key t = block->eval.type_key;; t = tg_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, t)) + { + TG_Kind kind = tg_kind_from_key(t); + if(kind == TG_Kind_Null) + { + break; + } + if((TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) || kind == TG_Kind_Ptr || kind == TG_Kind_LRef || kind == TG_Kind_RRef) + { + row->flags |= DF_EvalVizRowFlag_CanEditValue; + } + if(expandability_required || + kind == TG_Kind_Struct || + kind == TG_Kind_Union || + kind == TG_Kind_Class || + kind == TG_Kind_Array) + { + row->flags |= DF_EvalVizRowFlag_CanExpand; + } + if(row->flags & DF_EvalVizRowFlag_CanExpand) + { + break; + } + } + } + row->depth = block->depth; + row->parent_key = block->parent_key; + row->key = block->key; + SLLQueuePush(list.first, list.last, row); + list.count += 1; + }break; + + //- rjf: members -> produce rows for the visible range of members. + case DF_EvalVizBlockKind_Members: + if(block_type_kind != TG_Kind_Null) + { + TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, block->eval.type_key); + TG_MemberArray filtered_data_members = df_filtered_data_members_from_members_cfg_table(scratch.arena, data_members, &block->cfg_table); + for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max && idx < filtered_data_members.count; idx += 1) + { + TG_Member *member = &filtered_data_members.v[idx]; + + // rjf: get keys for this row + DF_ExpandKey parent_key = block->parent_key; + DF_ExpandKey key = df_expand_key_make((U64)block->eval_view, df_hash_from_expand_key(parent_key), idx+1); + + // rjf: get member eval + DF_Eval member_eval = zero_struct; + { + member_eval.type_key = member->type_key; + member_eval.mode = block->eval.mode; + member_eval.offset = block->eval.offset + member->off; + MemoryCopyArray(member_eval.imm_u128, block->eval.imm_u128); + } + + // rjf: get view rules + String8 view_rule_string = df_eval_view_rule_from_key(block->eval_view, key); + DF_CfgTable view_rule_table = df_cfg_table_from_inheritance(scratch.arena, &block->cfg_table); + df_cfg_table_push_unparsed_string(scratch.arena, &view_rule_table, view_rule_string, DF_CfgSrc_User); + + // rjf: apply view rules to eval + { + member_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, member_eval, &view_rule_table); + } + + // rjf: build & push row + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, member_eval, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, member_eval, &view_rule_table); + DF_EvalVizRow *row = push_array(arena, DF_EvalVizRow, 1); + row->eval_view = block->eval_view; + row->eval = member_eval; + row->expr = push_str8_copy(arena, member->name); + row->display_value = str8_list_join(arena, &display_strings, 0); + row->edit_value = str8_list_join(arena, &edit_strings, 0); + row->value_ui_rule_node = value_ui_rule_node; + row->value_ui_rule_spec = value_ui_rule_spec; + row->expand_ui_rule_node = expand_ui_rule_node; + row->expand_ui_rule_spec = expand_ui_rule_spec; + if(tg_kind_from_key(member_eval.type_key) != TG_Kind_Null) + { + for(TG_Key t = member_eval.type_key;; t = tg_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, t)) + { + TG_Kind kind = tg_kind_from_key(t); + if(kind == TG_Kind_Null) + { + break; + } + if((TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) || kind == TG_Kind_Ptr || kind == TG_Kind_LRef || kind == TG_Kind_RRef) + { + row->flags |= DF_EvalVizRowFlag_CanEditValue; + } + if(expandability_required || + kind == TG_Kind_Struct || + kind == TG_Kind_Union || + kind == TG_Kind_Class || + kind == TG_Kind_Array) + { + row->flags |= DF_EvalVizRowFlag_CanExpand; + } + if(row->flags & DF_EvalVizRowFlag_CanExpand) + { + break; + } + } + } + row->depth = block->depth; + row->parent_key = parent_key; + row->key = key; + SLLQueuePush(list.first, list.last, row); + list.count += 1; + } + }break; + + //- rjf: elements -> produce rows for the visible range of elements. + case DF_EvalVizBlockKind_Elements: + { + TG_Key direct_type_key = tg_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, block->eval.type_key); + TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); + U64 direct_type_key_byte_size = tg_byte_size_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, direct_type_key); + for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) + { + // rjf: get keys for this row + DF_ExpandKey parent_key = block->parent_key; + DF_ExpandKey key = df_expand_key_make((U64)block->eval_view, df_hash_from_expand_key(parent_key), idx+1); + + // rjf: get eval for this element + DF_Eval elem_eval = zero_struct; + { + elem_eval.type_key = direct_type_key; + elem_eval.mode = block->eval.mode; + elem_eval.offset = block->eval.offset + idx*direct_type_key_byte_size; + MemoryCopyArray(elem_eval.imm_u128, block->eval.imm_u128); + } + + // rjf: get view rules + String8 view_rule_string = df_eval_view_rule_from_key(block->eval_view, key); + DF_CfgTable view_rule_table = df_cfg_table_from_inheritance(scratch.arena, &block->cfg_table); + df_cfg_table_push_unparsed_string(scratch.arena, &view_rule_table, view_rule_string, DF_CfgSrc_User); + + // rjf: apply view rules to eval + { + elem_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, elem_eval, &view_rule_table); + } + + // rjf: build row + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, elem_eval, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, elem_eval, &view_rule_table); + DF_EvalVizRow *row = push_array(arena, DF_EvalVizRow, 1); + row->eval_view = block->eval_view; + row->eval = elem_eval; + row->expr = push_str8f(arena, "[%I64u]", idx); + row->display_value = str8_list_join(arena, &display_strings, 0); + row->edit_value = str8_list_join(arena, &edit_strings, 0); + row->value_ui_rule_node = value_ui_rule_node; + row->value_ui_rule_spec = value_ui_rule_spec; + row->expand_ui_rule_node = expand_ui_rule_node; + row->expand_ui_rule_spec = expand_ui_rule_spec; + if(direct_type_kind != TG_Kind_Null) + { + for(TG_Key t = elem_eval.type_key;; t = tg_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, t)) + { + TG_Kind kind = tg_kind_from_key(t); + if(kind == TG_Kind_Null) + { + break; + } + if((TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) || kind == TG_Kind_Ptr || kind == TG_Kind_LRef || kind == TG_Kind_RRef) + { + row->flags |= DF_EvalVizRowFlag_CanEditValue; + } + if(expandability_required || + kind == TG_Kind_Struct || + kind == TG_Kind_Union || + kind == TG_Kind_Class || + kind == TG_Kind_Array) + { + row->flags |= DF_EvalVizRowFlag_CanExpand; + } + if(row->flags & DF_EvalVizRowFlag_CanExpand) + { + break; + } + } + } + row->depth = block->depth; + row->parent_key = parent_key; + row->key = key; + SLLQueuePush(list.first, list.last, row); + list.count += 1; + } + }break; + + //- rjf: links -> produce rows for the visible range of links in the linked-list chain. + case DF_EvalVizBlockKind_Links: + { + DF_EvalLinkBaseChunkList link_base_chunks = df_eval_link_base_chunk_list_from_eval(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, block->link_member_type_key, block->link_member_off, ctrl_ctx, block->eval, 512); + DF_EvalLinkBaseArray link_bases = df_eval_link_base_array_from_chunk_list(scratch.arena, &link_base_chunks); + for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) + { + // rjf: get keys for this row + DF_ExpandKey parent_key = block->parent_key; + DF_ExpandKey key = df_expand_key_make((U64)block->eval_view, df_hash_from_expand_key(parent_key), idx+1); + + // rjf: get link base + DF_EvalLinkBase *link_base = &link_bases.v[idx]; + + // rjf: get eval for this link + DF_Eval link_eval = zero_struct; + { + link_eval.type_key = block->eval.type_key; + link_eval.mode = link_base->mode; + link_eval.offset = link_base->offset; + } + + // rjf: get view rules + String8 view_rule_string = df_eval_view_rule_from_key(block->eval_view, key); + DF_CfgTable view_rule_table = df_cfg_table_from_inheritance(scratch.arena, &block->cfg_table); + df_cfg_table_push_unparsed_string(scratch.arena, &view_rule_table, view_rule_string, DF_CfgSrc_User); + + // rjf: apply view rules to eval + link_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, link_eval, &view_rule_table); + TG_Kind link_type_kind = tg_kind_from_key(link_eval.type_key); + + // rjf: build row + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, link_eval, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, link_eval, &view_rule_table); + DF_EvalVizRow *row = push_array(arena, DF_EvalVizRow, 1); + row->eval_view = block->eval_view; + row->eval = link_eval; + row->expr = push_str8f(arena, "[%I64u]", idx); + row->display_value = str8_list_join(arena, &display_strings, 0); + row->edit_value = str8_list_join(arena, &edit_strings, 0); + row->value_ui_rule_node = value_ui_rule_node; + row->value_ui_rule_spec = value_ui_rule_spec; + row->expand_ui_rule_node = expand_ui_rule_node; + row->expand_ui_rule_spec = expand_ui_rule_spec; + if(link_type_kind != TG_Kind_Null) + { + for(TG_Key t = link_eval.type_key;; t = tg_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, t)) + { + TG_Kind kind = tg_kind_from_key(t); + if(kind == TG_Kind_Null) + { + break; + } + if((TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) || kind == TG_Kind_Ptr || kind == TG_Kind_LRef || kind == TG_Kind_RRef) + { + row->flags |= DF_EvalVizRowFlag_CanEditValue; + } + if(expandability_required || + kind == TG_Kind_Struct || + kind == TG_Kind_Union || + kind == TG_Kind_Class || + kind == TG_Kind_Array) + { + row->flags |= DF_EvalVizRowFlag_CanExpand; + } + if(row->flags & DF_EvalVizRowFlag_CanExpand) + { + break; + } + } + } + row->depth = block->depth; + row->parent_key = parent_key; + row->key = key; + SLLQueuePush(list.first, list.last, row); + list.count += 1; + } + }break; + + //- rjf: canvas -> produce blank row, sized by the idx range specified in the block + case DF_EvalVizBlockKind_Canvas: + if(num_skipped_visual < block_num_visual_rows) + { + DF_ExpandKey parent_key = block->parent_key; + DF_ExpandKey key = df_expand_key_make((U64)block->eval_view, df_hash_from_expand_key(parent_key), 1); + DF_EvalVizRow *row = push_array(arena, DF_EvalVizRow, 1); + row->flags = DF_EvalVizRowFlag_Canvas; + row->eval_view = block->eval_view; + row->eval = block->eval; + row->size_in_rows = dim_1u64(intersect_1u64(visible_idx_range, r1u64(0, dim_1u64(block->visual_idx_range)))); + row->skipped_size_in_rows= (visible_idx_range.min > block->visual_idx_range.min) ? visible_idx_range.min - block->visual_idx_range.min : 0; + row->chopped_size_in_rows= (visible_idx_range.max < block->visual_idx_range.max) ? block->visual_idx_range.max - visible_idx_range.max : 0; + row->depth = block->depth; + row->parent_key = parent_key; + row->key = key; + row->expand_ui_rule_node = expand_ui_rule_node; + row->expand_ui_rule_spec = expand_ui_rule_spec; + SLLQueuePush(list.first, list.last, row); + list.count += 1; + }break; + } + } + scratch_end(scratch); + ProfEnd(); + return list; +} + +//////////////////////////////// +//~ rjf: Hover Eval + +internal void +df_set_hover_eval(DF_Window *ws, Vec2F32 pos, DF_CtrlCtx ctrl_ctx, DF_Entity *file, TxtPt pt, U64 vaddr, String8 string) +{ + if(ws->hover_eval_last_frame_idx+1 < df_frame_index() && ui_key_match(ui_active_key(Side_Min), ui_key_zero()) && ui_key_match(ui_active_key(Side_Max), ui_key_zero())) + { + B32 is_new_string = !str8_match(ws->hover_eval_string, string, 0); + if(is_new_string) + { + ws->hover_eval_first_frame_idx = ws->hover_eval_last_frame_idx = df_frame_index(); + arena_clear(ws->hover_eval_arena); + ws->hover_eval_string = push_str8_copy(ws->hover_eval_arena, string); + ws->hover_eval_file = df_handle_from_entity(file); + ws->hover_eval_file_pt = pt; + ws->hover_eval_vaddr = vaddr; + } + ws->hover_eval_ctrl_ctx = ctrl_ctx; + ws->hover_eval_spawn_pos = pos; + ws->hover_eval_last_frame_idx = df_frame_index(); + } +} + +//////////////////////////////// +//~ rjf: Auto-Complete Lister + +internal void +df_autocomp_lister_item_chunk_list_push(Arena *arena, DF_AutoCompListerItemChunkList *list, U64 cap, DF_AutoCompListerItem *item) +{ + DF_AutoCompListerItemChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = push_array(arena, DF_AutoCompListerItemChunkNode, 1); + SLLQueuePush(list->first, list->last, n); + n->cap = cap; + n->v = push_array_no_zero(arena, DF_AutoCompListerItem, n->cap); + list->chunk_count += 1; + } + MemoryCopyStruct(&n->v[n->count], item); + n->count += 1; + list->total_count += 1; +} + +internal DF_AutoCompListerItemArray +df_autocomp_lister_item_array_from_chunk_list(Arena *arena, DF_AutoCompListerItemChunkList *list) +{ + DF_AutoCompListerItemArray array = {0}; + array.count = list->total_count; + array.v = push_array_no_zero(arena, DF_AutoCompListerItem, array.count); + U64 idx = 0; + for(DF_AutoCompListerItemChunkNode *n = list->first; n != 0; n = n->next) + { + MemoryCopy(array.v+idx, n->v, sizeof(DF_AutoCompListerItem)*n->count); + idx += n->count; + } + return array; +} + +internal int +df_autocomp_lister_item_qsort_compare(DF_AutoCompListerItem *a, DF_AutoCompListerItem *b) +{ + int result = 0; + if(a->matches.count > b->matches.count) + { + result = -1; + } + else if(a->matches.count < b->matches.count) + { + result = +1; + } + else + { + result = strncmp((char *)a->string.str, (char *)b->string.str, Min(a->string.size, b->string.size)); + } + return result; +} + +internal void +df_autocomp_lister_item_array_sort__in_place(DF_AutoCompListerItemArray *array) +{ + qsort(array->v, array->count, sizeof(array->v[0]), (int (*)(const void*, const void*))df_autocomp_lister_item_qsort_compare); +} + +internal void +df_set_autocomp_lister_query(DF_Window *ws, UI_Key root_key, DF_CtrlCtx ctrl_ctx, DF_AutoCompListerFlags flags, String8 query) +{ + String8 current_query = str8(ws->autocomp_lister_query_buffer, ws->autocomp_lister_query_size); + if(!str8_match(query, current_query, 0)) + { + ws->autocomp_force_closed = 0; + } + if(!ui_key_match(ws->autocomp_root_key, root_key)) + { + ws->autocomp_force_closed = 0; + ws->autocomp_num_visible_rows_t = 0; + } + if(ws->autocomp_last_frame_idx+1 < df_frame_index()) + { + ws->autocomp_force_closed = 0; + ws->autocomp_num_visible_rows_t = 0; + } + ws->autocomp_ctrl_ctx = ctrl_ctx; + ws->autocomp_root_key = root_key; + ws->autocomp_lister_flags = flags; + ws->autocomp_lister_query_size = Min(query.size, sizeof(ws->autocomp_lister_query_buffer)); + MemoryCopy(ws->autocomp_lister_query_buffer, query.str, ws->autocomp_lister_query_size); + ws->autocomp_last_frame_idx = df_frame_index(); +} + +//////////////////////////////// +//~ rjf: Search Strings + +internal void +df_set_search_string(String8 string) +{ + arena_clear(df_gfx_state->string_search_arena); + df_gfx_state->string_search_string = push_str8_copy(df_gfx_state->string_search_arena, string); +} + +internal String8 +df_push_search_string(Arena *arena) +{ + String8 result = push_str8_copy(arena, df_gfx_state->string_search_string); + return result; +} + +//////////////////////////////// +//~ rjf: Background Text Searching Thread + +internal void +df_text_search_match_chunk_list_push(Arena *arena, DF_TextSearchMatchChunkList *list, U64 cap, DF_TextSearchMatch *match) +{ + DF_TextSearchMatchChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, DF_TextSearchMatchChunkNode, 1); + node->cap = cap; + node->v = push_array_no_zero(arena, DF_TextSearchMatch, node->cap); + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + } + node->v[node->count] = *match; + node->count += 1; + list->total_count += 1; +} + +internal DF_TextSearchMatchArray +df_text_search_match_array_from_chunk_list(Arena *arena, DF_TextSearchMatchChunkList *chunks) +{ + DF_TextSearchMatchArray array = {0}; + array.count = chunks->total_count; + array.v = push_array_no_zero(arena, DF_TextSearchMatch, array.count); + U64 idx = 0; + for(DF_TextSearchMatchChunkNode *node = chunks->first; node != 0; node = node->next) + { + MemoryCopy(array.v+idx, node->v, node->count * sizeof(DF_TextSearchMatch)); + idx += node->count; + } + return array; +} + +internal U64 +df_text_search_little_hash_from_hash(U128 hash) +{ + // TODO(rjf): [ ] @de2ctrl df_text_search_little_hash_from_hash + U64 little_hash = 0; + MemoryCopy(&little_hash, &hash, sizeof(little_hash)); + return little_hash; +} + +internal void +df_text_search_thread_entry_point(void *p) +{ + TCTX tctx_; + tctx_init_and_equip(&tctx_); +#if !DE2CTRL + // TODO(rjf): [ ] @de2ctrl text searcher -- wound up in DE_Hash + + //- rjf: types + typedef enum WorkKind + { + WorkKind_Search, + WorkKind_GarbageCollect, + WorkKind_COUNT + } + WorkKind; + typedef struct WorkNode WorkNode; + struct WorkNode + { + WorkNode *next; + WorkKind kind; + U128 hash; + String8 needle; + DF_TextSliceFlags flags; + TxtPt start_pt; + }; + + //- rjf: set up local debug engine map + Arena *local_map_arena = arena_alloc(); + DE_ContentMap local_map = {0}; + DE_PipelineHint hint = zero_struct; + + //- rjf: loop over work + for(;;) + { + //- rjf: begin + Temp scratch = scratch_begin(0, 0); + DE_Session *session = de_session_begin(); + + //- rjf: wait for changes + os_mutex_take(df_gfx_state->tsrch_wakeup_mutex); + os_condition_variable_wait(df_gfx_state->tsrch_wakeup_cv, df_gfx_state->tsrch_wakeup_mutex, os_now_microseconds()+1000000); + os_mutex_drop(df_gfx_state->tsrch_wakeup_mutex); + + //- rjf: gather all searches to complete + WorkNode *first_work_node = 0; + WorkNode *last_work_node = 0; + for(U64 slot_idx = 0; slot_idx < df_gfx_state->tsrch_slot_count; slot_idx += 1) + { + //- rjf: slot idx -> slot * stripe + DF_TextSearchCacheSlot *slot = &df_gfx_state->tsrch_slots[slot_idx]; + U64 stripe_idx = slot_idx%df_gfx_state->tsrch_stripe_count; + OS_Handle stripe_rw_mutex = df_gfx_state->tsrch_stripe_rw_mutexes[stripe_idx]; + + //- rjf: gather nodes in this slot + os_rw_mutex_take_r(stripe_rw_mutex); + { + for(DF_TextSearchCacheNode *n = slot->first; n != 0; n = n->next) + { + B32 not_done = (n->good == 0); + B32 expired = (os_now_microseconds() >= n->last_time_touched_us + 10000000); + if(not_done || expired) + { + WorkNode *work = push_array(scratch.arena, WorkNode, 1); + work->kind = not_done ? WorkKind_Search : WorkKind_GarbageCollect; + work->hash = n->hash; + work->needle = push_str8_copy(scratch.arena, n->needle); + work->flags = n->flags; + work->start_pt = n->start_pt; + SLLQueuePush(first_work_node, last_work_node, work); + } + } + } + os_rw_mutex_drop_r(stripe_rw_mutex); + } + + //- rjf: perform all searches + for(WorkNode *work_node = first_work_node; work_node != 0; work_node = work_node->next) + { + //- rjf: unpack work node + WorkKind kind = work_node->kind; + DE_Hash hash = work_node->hash; + String8 needle = work_node->needle; + DF_TextSliceFlags flags = work_node->flags; + TxtPt start_pt = work_node->start_pt; + + //- rjf: work params -> slot/stripe info + U64 little_hash = df_text_search_little_hash_from_hash(hash); + U64 slot_idx = little_hash%df_gfx_state->tsrch_slot_count; + DF_TextSearchCacheSlot *slot = &df_gfx_state->tsrch_slots[slot_idx]; + U64 stripe_idx = slot_idx%df_gfx_state->tsrch_stripe_count; + OS_Handle stripe_rw_mutex = df_gfx_state->tsrch_stripe_rw_mutexes[stripe_idx]; + + //- rjf: do work + switch(kind) + { + //- rjf: search + default: + case WorkKind_Search: + { + //- rjf: hash -> artifacts + DE_Key hash2data_key = de_key_hash(DE_KeyFunc_DataFromHash, &hash); + DE_Val *hash2data_val = de_shared_chained_lookup(local_map_arena, &local_map, de_shared, &hint, &hash2data_key); + DE_ContentBlock *hash2data_block = de_session_node_access_via_val(session, hash2data_val); + String8 data = hash2data_block->data; + DE_Key hash2txti_key = de_key_hash(DE_KeyFunc_TxtiFromHash, &hash); + DE_Val *hash2txti_val = de_shared_chained_lookup(local_map_arena, &local_map, de_shared, &hint, &hash2txti_key); + DE_ContentBlock *hash2txti_block = de_session_node_access_via_val(session, hash2txti_val); + DE_InfoTxt *txt = hash2txti_block->txt; + + //- rjf: start pt -> search start offset + U64 start_off = 0; + if(1 <= start_pt.line && start_pt.line <= txt->line_count) + { + start_off = txt->line_ranges[start_pt.line-1].min; + if(1 <= start_pt.column && start_pt.column <= dim_1u64(txt->line_ranges[start_pt.line-1])) + { + start_off += (start_pt.column-1); + } + } + + //- rjf: search for all needle occurrences + U8 *byte_first = data.str; + U8 *byte_opl = data.str+data.size; + U8 *byte_start = byte_first + start_off; + U64 num_bytes_traversed = 0; + for(U8 *byte = byte_start; num_bytes_traversed < data.size;) + { + String8 rest_of_data = str8(byte, byte_opl-byte); + String8 next_needle_size = str8_prefix(rest_of_data, needle.size); + B32 found_match = str8_match(next_needle_size, needle, StringMatchFlag_CaseInsensitive); + + // rjf: record match + if(found_match) + { + U64 match_off = (U64)(byte-byte_first); + TxtPt match_pt = de_txt_pt_from_txti_off(txt, match_off); + DF_TextSearchMatch match = {match_pt}; + os_rw_mutex_take_w(stripe_rw_mutex); + { + DF_TextSearchCacheNode *node = 0; + for(DF_TextSearchCacheNode *n = slot->first; n != 0; n = n->next) + { + if(MemoryMatchStruct(&hash, &n->hash) && + str8_match(needle, n->needle, 0) && + flags == n->flags) + { + node = n; + } + } + df_text_search_match_chunk_list_push(node->arena, &node->search_matches, 256, &match); + node->good = 1; + } + os_rw_mutex_drop_w(stripe_rw_mutex); + } + + // rjf: increment + byte += 1; + num_bytes_traversed += 1; + if(byte >= byte_opl) + { + byte = byte_first; + } + } + + }break; + + //- rjf: garbage collect + case WorkKind_GarbageCollect: + { + os_rw_mutex_take_w(stripe_rw_mutex); + { + DF_TextSearchCacheNode *node = 0; + for(DF_TextSearchCacheNode *n = slot->first; n != 0; n = n->next) + { + if(MemoryMatchStruct(&hash, &n->hash) && + str8_match(needle, n->needle, 0) && + flags == n->flags) + { + node = n; + } + } + if(node != 0) + { + DLLRemove(slot->first, slot->last, node); + arena_release(node->arena); + } + } + os_rw_mutex_drop_w(stripe_rw_mutex); + }break; + } + } + + //- rjf: end + de_session_end(session); + scratch_end(scratch); + } +#endif +} + +internal DF_TextSearchMatchArray +df_text_search_match_array_from_hash_needle(Arena *arena, U128 hash, String8 needle, DF_TextSliceFlags text_slice_flags, TxtPt start_pt) +{ + // TODO(rjf): [ ] @de2ctrl text searching lookup -- wound up with DE_Hash + DF_TextSearchMatchArray result = {0}; + { + //- rjf: hash -> slot/stripe info + U64 little_hash = df_text_search_little_hash_from_hash(hash); + U64 slot_idx = little_hash%df_gfx_state->tsrch_slot_count; + DF_TextSearchCacheSlot *slot = &df_gfx_state->tsrch_slots[slot_idx]; + U64 stripe_idx = slot_idx%df_gfx_state->tsrch_stripe_count; + OS_Handle stripe_rw_mutex = df_gfx_state->tsrch_stripe_rw_mutexes[stripe_idx]; + + //- rjf: find matches from existing node + B32 found_node = 0; + { + os_rw_mutex_take_r(stripe_rw_mutex); + for(DF_TextSearchCacheNode *node = slot->first; node != 0; node = node->next) + { + if(MemoryMatchStruct(&node->hash, &hash) && + str8_match(node->needle, needle, StringMatchFlag_CaseInsensitive) && + node->flags == text_slice_flags) + { + found_node = 1; + result = df_text_search_match_array_from_chunk_list(arena, &node->search_matches); + U64 time_current_us = os_now_microseconds(); + ins_atomic_u64_eval_assign(&node->last_time_touched_us, time_current_us); + break; + } + } + os_rw_mutex_drop_r(stripe_rw_mutex); + } + + //- rjf: no existing node -> allocate new + if(found_node == 0) + { + os_rw_mutex_take_w(stripe_rw_mutex); + { + Arena *node_arena = arena_alloc(); + DF_TextSearchCacheNode *node = push_array(node_arena, DF_TextSearchCacheNode, 1); + node->arena = node_arena; + node->hash = hash; + node->needle = push_str8_copy(node_arena, needle); + node->flags = text_slice_flags; + node->start_pt = start_pt; + DLLPushBack(slot->first, slot->last, node); + } + os_rw_mutex_drop_w(stripe_rw_mutex); + os_condition_variable_signal(df_gfx_state->tsrch_wakeup_cv); + } + } + return result; +} + +internal DF_TextSearchMatchArray +df_text_search_match_array_from_entity_needle(Arena *arena, DF_Entity *entity, String8 needle, DF_TextSliceFlags flags, TxtPt start_pt) +{ + // TODO(rjf): [ ] @de2ctrl text search lookup + DF_TextSearchMatchArray matches = {0}; +#if !DE2CTRL + if(entity->kind == DF_EntityKind_File && needle.size != 0) + { + Temp scratch = scratch_begin(&arena, 1); + String8 path = df_full_path_from_entity(scratch.arena, entity); + DE_PipelineHint hint = zero_struct; + DE_Key path2hash_key = de_key_path(DE_KeyFunc_HashFromPath, path, entity->timestamp); + DE_Val *path2hash_val = de_user_peek_lookup(de_user, de_shared, &hint, &path2hash_key); + DE_Hash hash = path2hash_val->hash; + if(!de_hash_is_empty(&hash)) + { + matches = df_text_search_match_array_from_hash_needle(arena, hash, needle, flags, start_pt); + } + scratch_end(scratch); + } +#endif + return matches; +} + +internal int +df_text_search_match_array_qsort_compare(TxtPt *a, TxtPt *b) +{ + int result = 0; + if(txt_pt_less_than(*a, *b)) + { + result = -1; + } + else if(txt_pt_less_than(*b, *a)) + { + result = +1; + } + return result; +} + +internal void +df_text_search_match_array_sort_in_place(DF_TextSearchMatchArray *array) +{ + qsort(array->v, array->count, sizeof(DF_TextSearchMatch), (int (*)(const void *, const void *))df_text_search_match_array_qsort_compare); +} + +internal DF_TextSearchMatch +df_text_search_match_array_find_nearest__linear_scan(DF_TextSearchMatchArray *array, TxtPt pt, Side side) +{ + ProfBeginFunction(); + DF_TextSearchMatch result = {0}; + if(array->count != 0) + { + S64 best_line_distance = max_S64; + S64 best_column_distance = max_S64; + B32 best_matches_side = 0; + for(U64 idx = 0; idx < array->count; idx += 1) + { + S64 line_distance = abs_s64(array->v[idx].pt.line - pt.line); + S64 column_distance = abs_s64(array->v[idx].pt.column - pt.column); + B32 matches_side = (side == Side_Max ? txt_pt_less_than(pt, array->v[idx].pt) : + side == Side_Min ? txt_pt_less_than(array->v[idx].pt, pt) : + 1); + if(matches_side >= best_matches_side && line_distance == 0 && column_distance < best_column_distance) + { + best_matches_side = matches_side; + best_line_distance = 0; + best_column_distance = column_distance; + result = array->v[idx]; + } + else if(matches_side >= best_matches_side && line_distance < best_line_distance) + { + best_matches_side = matches_side; + best_line_distance = line_distance; + result = array->v[idx]; + } + } + } + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Colors, Fonts, Config + +//- rjf: keybindings + +internal OS_Key +df_os_key_from_cfg_string(String8 string) +{ + OS_Key result = OS_Key_Null; + { + for(OS_Key key = OS_Key_Null; key < OS_Key_COUNT; key = (OS_Key)(key+1)) + { + if(str8_match(string, os_g_key_cfg_string_table[key], StringMatchFlag_CaseInsensitive)) + { + result = key; + break; + } + } + } + return result; +} + +internal void +df_clear_bindings(void) +{ + arena_clear(df_gfx_state->key_map_arena); + df_gfx_state->key_map_table_size = 1024; + df_gfx_state->key_map_table = push_array(df_gfx_state->key_map_arena, DF_KeyMapSlot, df_gfx_state->key_map_table_size); + df_gfx_state->key_map_total_count = 0; +} + +internal DF_BindingList +df_bindings_from_spec(Arena *arena, DF_CmdSpec *spec) +{ + DF_BindingList result = {0}; + U64 hash = df_hash_from_string(spec->info.string); + U64 slot = hash%df_gfx_state->key_map_table_size; + for(DF_KeyMapNode *n = df_gfx_state->key_map_table[slot].first; n != 0; n = n->hash_next) + { + if(n->spec == spec) + { + DF_BindingNode *node = push_array(arena, DF_BindingNode, 1); + node->binding = n->binding; + SLLQueuePush(result.first, result.last, node); + result.count += 1; + } + } + return result; +} + +internal void +df_bind_spec(DF_CmdSpec *spec, DF_Binding binding) +{ + if(binding.key != OS_Key_Null) + { + U64 hash = df_hash_from_string(spec->info.string); + U64 slot = hash%df_gfx_state->key_map_table_size; + DF_KeyMapNode *existing_node = 0; + for(DF_KeyMapNode *n = df_gfx_state->key_map_table[slot].first; n != 0; n = n->hash_next) + { + if(n->spec == spec && n->binding.key == binding.key && n->binding.flags == binding.flags) + { + existing_node = n; + break; + } + } + if(existing_node == 0) + { + DF_KeyMapNode *n = df_gfx_state->free_key_map_node; + if(n == 0) + { + n = push_array(df_gfx_state->arena, DF_KeyMapNode, 1); + } + else + { + df_gfx_state->free_key_map_node = df_gfx_state->free_key_map_node->hash_next; + } + n->spec = spec; + n->binding = binding; + DLLPushBack_NP(df_gfx_state->key_map_table[slot].first, df_gfx_state->key_map_table[slot].last, n, hash_next, hash_prev); + df_gfx_state->key_map_total_count += 1; + } + } +} + +internal void +df_unbind_spec(DF_CmdSpec *spec, DF_Binding binding) +{ + U64 hash = df_hash_from_string(spec->info.string); + U64 slot = hash%df_gfx_state->key_map_table_size; + for(DF_KeyMapNode *n = df_gfx_state->key_map_table[slot].first, *next = 0; n != 0; n = next) + { + next = n->hash_next; + if(n->spec == spec && n->binding.key == binding.key && n->binding.flags == binding.flags) + { + DLLRemove_NP(df_gfx_state->key_map_table[slot].first, df_gfx_state->key_map_table[slot].last, n, hash_next, hash_prev); + n->hash_next = df_gfx_state->free_key_map_node; + df_gfx_state->free_key_map_node = n; + df_gfx_state->key_map_total_count -= 1; + } + } +} + +internal DF_CmdSpecList +df_cmd_spec_list_from_binding(Arena *arena, DF_Binding binding) +{ + DF_CmdSpecList result = {0}; + for(U64 idx = 0; idx < df_gfx_state->key_map_table_size; idx += 1) + { + for(DF_KeyMapNode *n = df_gfx_state->key_map_table[idx].first; n != 0; n = n->hash_next) + { + if(n->binding.key == binding.key && n->binding.flags == binding.flags) + { + df_cmd_spec_list_push(arena, &result, n->spec); + } + } + } + return result; +} + +internal DF_CmdSpecList +df_cmd_spec_list_from_event_flags(Arena *arena, OS_EventFlags flags) +{ + DF_CmdSpecList result = {0}; + for(U64 idx = 0; idx < df_gfx_state->key_map_table_size; idx += 1) + { + for(DF_KeyMapNode *n = df_gfx_state->key_map_table[idx].first; n != 0; n = n->hash_next) + { + if(n->binding.flags == flags) + { + df_cmd_spec_list_push(arena, &result, n->spec); + } + } + } + return result; +} + +//- rjf: colors + +internal Vec4F32 +df_rgba_from_theme_color(DF_ThemeColor color) +{ + return df_gfx_state->cfg_theme.colors[color]; +} + +internal DF_ThemeColor +df_theme_color_from_txti_token_kind(TXTI_TokenKind kind) +{ + DF_ThemeColor color = DF_ThemeColor_CodeDefault; + switch(kind) + { + default:break; + case TXTI_TokenKind_Keyword:{color = DF_ThemeColor_CodeKeyword;}break; + case TXTI_TokenKind_Numeric:{color = DF_ThemeColor_CodeNumeric;}break; + case TXTI_TokenKind_String: {color = DF_ThemeColor_CodeString;}break; + case TXTI_TokenKind_Meta: {color = DF_ThemeColor_CodeMeta;}break; + case TXTI_TokenKind_Comment:{color = DF_ThemeColor_CodeComment;}break; + case TXTI_TokenKind_Symbol: {color = DF_ThemeColor_CodeSymbol;}break; + } + return color; +} + +//- rjf: fonts/sizes + +internal F_Tag +df_font_from_slot(DF_FontSlot slot) +{ + F_Tag result = df_gfx_state->cfg_font_tags[slot]; + return result; +} + +internal F32 +df_font_size_from_slot(DF_Window *ws, DF_FontSlot slot) +{ + F32 result = 0; + F32 dpi = os_dpi_from_window(ws->os); + switch(slot) + { + default: + case DF_FontSlot_Main: + { + F32 size_at_96dpi = 9.f; + result = dpi * ((size_at_96dpi / 96.f) + ws->main_font_size_delta); + }break; + case DF_FontSlot_Code: + { + F32 size_at_96dpi = 9.f; + result = dpi * ((size_at_96dpi / 96.f) + ws->code_font_size_delta); + }break; + case DF_FontSlot_Icons: + { + F32 size_at_96dpi = 10.f; + result = dpi * ((size_at_96dpi / 96.f) + ws->main_font_size_delta); + }break; + } + return result; +} + +//- rjf: config serialization + +internal int +df_qsort_compare__cfg_string_bindings(DF_StringBindingPair *a, DF_StringBindingPair *b) +{ + return strncmp((char *)a->string.str, (char *)b->string.str, Min(a->string.size, b->string.size)); +} + +internal String8List +df_cfg_strings_from_gfx(Arena *arena, String8 root_path, DF_CfgSrc source) +{ + ProfBeginFunction(); + String8List strs = {0}; + + //- rjf: serialize windows + { + B32 first = 1; + for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) + { + if(window->cfg_src != source) + { + continue; + } + if(first) + { + first = 0; + str8_list_push(arena, &strs, str8_lit("/// windows ///////////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + } + OS_Handle monitor = os_monitor_from_window(window->os); + String8 monitor_name = os_name_from_monitor(arena, monitor); + DF_Panel *root_panel = window->root_panel; + Rng2F32 rect = os_rect_from_window(window->os); + Vec2F32 size = dim_2f32(rect); + str8_list_push (arena, &strs, str8_lit("window:\n")); + str8_list_push (arena, &strs, str8_lit("{\n")); + str8_list_pushf(arena, &strs, " %s%s%s\n", + root_panel->split_axis == Axis2_X ? "split_x" : "split_y", + os_window_is_fullscreen(window->os) ? " fullscreen" : "", + os_window_is_maximized(window->os) ? " maximized" : ""); + str8_list_pushf(arena, &strs, " monitor: \"%S\"\n", monitor_name); + str8_list_pushf(arena, &strs, " size: (%i %i)\n", (int)size.x, (int)size.y); + str8_list_pushf(arena, &strs, " code_font_size_delta: %.5f\n", window->code_font_size_delta); + str8_list_pushf(arena, &strs, " main_font_size_delta: %.5f\n", window->main_font_size_delta); + { + DF_PanelRec rec = {0}; + S32 indentation = 2; + String8 indent_str = str8_lit(" "); + str8_list_pushf(arena, &strs, " panels:\n"); + str8_list_pushf(arena, &strs, " {\n"); + for(DF_Panel *p = root_panel; !df_panel_is_nil(p); p = rec.next) + { + // rjf: get recursion + rec = df_panel_rec_df_pre(p); + + // rjf: non-root needs pct node + if(p != root_panel) + { + str8_list_pushf(arena, &strs, "%.*s%g:\n", indentation*2, indent_str.str, p->size_pct_of_parent_target.v[p->parent->split_axis]); + str8_list_pushf(arena, &strs, "%.*s{\n", indentation*2, indent_str.str); + indentation += 1; + } + + // rjf: per-panel options + struct { String8 key; B32 value; } options[] = + { + {str8_lit_comp("tabs_on_bottom"), p->tab_side == Side_Max}, + {str8_lit_comp("disable_tab_bar"), p->hide_tab_bar}, + {str8_lit_comp("history_mode"), p->history_tab_bar_mode}, + }; + B32 has_options = 0; + for(U64 op_idx = 0; op_idx < ArrayCount(options); op_idx += 1) + { + if(options[op_idx].value) + { + if(has_options == 0) + { + str8_list_pushf(arena, &strs, "%.*s", indentation*2, indent_str.str); + } + else + { + str8_list_pushf(arena, &strs, " "); + } + has_options = 1; + str8_list_push(arena, &strs, options[op_idx].key); + } + } + if(has_options) + { + str8_list_pushf(arena, &strs, "\n"); + } + + // rjf: views + for(DF_View *view = p->first_stable_view; !df_view_is_nil(view); view = view->next) + { + DF_CmdSpec *cmd_spec = view->cmd_spec; + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd_spec); + String8 view_string = cmd_spec->info.string; + DF_Entity *view_entity = df_entity_from_handle(view->cmd_entity); + + // rjf: serialize views which can be serialized + if(view_spec->info.flags & DF_ViewSpecFlag_CanSerialize) + { + str8_list_pushf(arena, &strs, "%.*s", indentation*2, indent_str.str); + + // rjf: serialize view string + str8_list_push(arena, &strs, view_string); + + // rjf: serialize view parameterizations + str8_list_push(arena, &strs, str8_lit(": {")); + if(view == p->selected_stable_view) + { + str8_list_push(arena, &strs, str8_lit("selected ")); + } + if(view_spec->info.flags & DF_ViewSpecFlag_CanSerializeEntityPath) + { + if(view_entity->kind == DF_EntityKind_File) + { + String8 profile_path = root_path; + String8 entity_path = df_full_path_from_entity(arena, view_entity); + String8 entity_path_rel = path_relative_dst_from_absolute_dst_src(arena, entity_path, profile_path); + str8_list_pushf(arena, &strs, "\"%S\"", entity_path_rel); + } + } + String8 view_state_string = view_spec->info.string_from_state_hook(arena, view); + str8_list_push(arena, &strs, view_state_string); + str8_list_push(arena, &strs, str8_lit("}\n")); + } + } + + // rjf: non-roots need closer + if(p != root_panel && rec.push_count == 0) + { + indentation -= 1; + str8_list_pushf(arena, &strs, "%.*s}\n", indentation*2, indent_str.str); + } + + // rjf: pop + for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + indentation -= 1; + if(pop_idx == rec.pop_count-1 && rec.next == &df_g_nil_panel) + { + break; + } + str8_list_pushf(arena, &strs, "%.*s}\n", indentation*2, indent_str.str); + } + } + str8_list_pushf(arena, &strs, " }\n"); + } + str8_list_push (arena, &strs, str8_lit("}\n")); + str8_list_push (arena, &strs, str8_lit("\n")); + } + } + + //- rjf: serialize keybindings + if(source == DF_CfgSrc_User) + { + Temp scratch = scratch_begin(&arena, 1); + String8 indent_str = str8_lit(" "); + U64 string_binding_pair_count = 0; + DF_StringBindingPair *string_binding_pairs = push_array(scratch.arena, DF_StringBindingPair, df_gfx_state->key_map_total_count); + for(U64 idx = 0; + idx < df_gfx_state->key_map_table_size && string_binding_pair_count < df_gfx_state->key_map_total_count; + idx += 1) + { + for(DF_KeyMapNode *n = df_gfx_state->key_map_table[idx].first; + n != 0 && string_binding_pair_count < df_gfx_state->key_map_total_count; + n = n->hash_next) + { + DF_StringBindingPair *pair = string_binding_pairs + string_binding_pair_count; + pair->string = n->spec->info.string; + pair->binding = n->binding; + string_binding_pair_count += 1; + } + } + qsort(string_binding_pairs, string_binding_pair_count, sizeof(DF_StringBindingPair), (int (*)(const void *, const void *))df_qsort_compare__cfg_string_bindings); + if(string_binding_pair_count != 0) + { + str8_list_push(arena, &strs, str8_lit("/// keybindings ///////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + str8_list_push(arena, &strs, str8_lit("keybindings:\n")); + str8_list_push(arena, &strs, str8_lit("{\n")); + for(U64 idx = 0; idx < string_binding_pair_count; idx += 1) + { + DF_StringBindingPair *pair = string_binding_pairs + idx; + String8List event_flags_strings = os_string_list_from_event_flags(scratch.arena, pair->binding.flags); + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + String8 event_flags_string = str8_list_join(scratch.arena, &event_flags_strings, &join); + String8 key_string = push_str8_copy(scratch.arena, os_g_key_cfg_string_table[pair->binding.key]); + for(U64 i = 0; i < event_flags_string.size; i += 1) + { + event_flags_string.str[i] = char_to_lower(event_flags_string.str[i]); + } + String8 binding_string = push_str8f(scratch.arena, "%S%s%S", + event_flags_string, + event_flags_string.size > 0 ? " " : "", + key_string); + str8_list_pushf(arena, &strs, " {\"%S\"%.*s%S%.*s}\n", + pair->string, + 40 > pair->string.size ? ((int)(40 - pair->string.size)) : 0, indent_str.str, + binding_string, + 20 > binding_string.size ? ((int)(20 - binding_string.size)) : 0, indent_str.str); + } + str8_list_push(arena, &strs, str8_lit("}\n\n")); + } + scratch_end(scratch); + } + + //- rjf: serialize theme colors + if(source == DF_CfgSrc_User) + { + String8 indent_str = str8_lit(" "); + str8_list_push(arena, &strs, str8_lit("/// colors ////////////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + str8_list_push(arena, &strs, str8_lit("colors:\n")); + str8_list_push(arena, &strs, str8_lit("{\n")); + for(DF_ThemeColor color = (DF_ThemeColor)(DF_ThemeColor_Null+1); + color < DF_ThemeColor_COUNT; + color = (DF_ThemeColor)(color+1)) + { + String8 color_name = df_g_theme_color_cfg_string_table[color]; + Vec4F32 color_rgba = df_gfx_state->cfg_theme_target.colors[color]; + String8 color_hex = hex_string_from_rgba_4f32(arena, color_rgba); + str8_list_pushf(arena, &strs, " %S:%.*s0x%S\n", + color_name, + 30 > color_name.size ? ((int)(30 - color_name.size)) : 0, indent_str.str, + color_hex); + } + str8_list_push(arena, &strs, str8_lit("}\n\n")); + } + + //- rjf: serialize fonts + if(source == DF_CfgSrc_User) + { + String8 code_font_path_absolute = f_path_from_tag(df_gfx_state->cfg_font_tags[DF_FontSlot_Code]); + String8 main_font_path_absolute = f_path_from_tag(df_gfx_state->cfg_font_tags[DF_FontSlot_Main]); + String8 code_font_path_relative = path_relative_dst_from_absolute_dst_src(arena, code_font_path_absolute, root_path); + String8 main_font_path_relative = path_relative_dst_from_absolute_dst_src(arena, main_font_path_absolute, root_path); + { + str8_list_push(arena, &strs, str8_lit("/// fonts /////////////////////////////////////////////////////////////////////\n")); + str8_list_push(arena, &strs, str8_lit("\n")); + str8_list_pushf(arena, &strs, "code_font: \"%S\"\n", code_font_path_relative); + str8_list_pushf(arena, &strs, "main_font: \"%S\"\n", main_font_path_relative); + str8_list_push(arena, &strs, str8_lit("\n")); + } + } + + ProfEnd(); + return strs; +} + +//////////////////////////////// +//~ rjf: UI Helpers + +internal void +df_box_equip_fuzzy_match_range_list_vis(UI_Box *box, DF_FuzzyMatchRangeList range_list) +{ + UI_Parent(box) + { + String8 display_string = ui_box_display_string(box); + F_Metrics metrics = f_metrics_from_tag_size(box->font, box->font_size); + F32 line_height = f_line_height_from_metrics(&metrics); + for(DF_FuzzyMatchRangeNode *match_n = range_list.first; match_n != 0; match_n = match_n->next) + { + Rng1F32 match_pixel_range = + { + f_dim_from_tag_size_string(box->font, box->font_size, str8_prefix(display_string, match_n->range.min)).x, + f_dim_from_tag_size_string(box->font, box->font_size, str8_prefix(display_string, match_n->range.max)).x, + }; + ui_set_next_fixed_x(match_pixel_range.min + box->text_padding + 2.f); + ui_set_next_fixed_y(box->font_size/4.f); + ui_set_next_fixed_width(match_pixel_range.max-match_pixel_range.min); + ui_set_next_fixed_height(line_height*1.2f); + ui_set_next_corner_radius_00(box->font_size/2.f); + ui_set_next_corner_radius_01(box->font_size/2.f); + ui_set_next_corner_radius_10(box->font_size/2.f); + ui_set_next_corner_radius_11(box->font_size/2.f); + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_PlainOverlay)); + ui_build_box_from_key(UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_DrawBackground, ui_key_zero()); + } + } +} + +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Buttons + +internal void +df_cmd_binding_button(DF_CmdSpec *spec) +{ + Temp scratch = scratch_begin(0, 0); + DF_BindingList bindings = df_bindings_from_spec(scratch.arena, spec); + DF_Binding binding = zero_struct; + if(bindings.first != 0) + { + binding = bindings.first->binding; + } + + //- rjf: grab all conflicts + DF_CmdSpecList specs_with_binding = df_cmd_spec_list_from_binding(scratch.arena, binding); + B32 has_conflicts = 0; + for(DF_CmdSpecNode *n = specs_with_binding.first; n != 0; n = n->next) + { + if(n->spec != spec) + { + has_conflicts = 1; + break; + } + } + + //- rjf: form binding string + String8 keybinding_str = {0}; + { + if(binding.key != OS_Key_Null) + { + String8List mods = os_string_list_from_event_flags(scratch.arena, binding.flags); + String8 key = os_g_key_display_string_table[binding.key]; + str8_list_push(scratch.arena, &mods, key); + StringJoin join = {0}; + join.sep = str8_lit(" + "); + keybinding_str = str8_list_join(scratch.arena, &mods, &join); + } + else + { + keybinding_str = str8_lit("- no binding -"); + } + } + + //- rjf: build box + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_text_alignment(UI_TextAlign_Center); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| + UI_BoxFlag_Clickable| + UI_BoxFlag_DrawActiveEffects, + "%S###bind_btn_%p", keybinding_str, spec); + + //- rjf: has conflicts => red + if(has_conflicts) + { + box->text_color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + } + + //- rjf: interaction + UI_Signal sig = ui_signal_from_box(box); + { + // rjf: hover => visualize clickability + if(sig.hovering) + { + box->flags |= UI_BoxFlag_DrawBorder; + box->flags |= UI_BoxFlag_DrawBackground; + } + + // rjf: click => toggle activity + if(!df_gfx_state->bind_change_active && sig.clicked) + { + df_gfx_state->bind_change_active = 1; + df_gfx_state->bind_change_cmd_spec = spec; + df_gfx_state->bind_change_binding = binding; + } + else if(df_gfx_state->bind_change_active && sig.clicked) + { + df_gfx_state->bind_change_active = 0; + } + + // rjf: hover w/ conflicts => show conflicts + if(sig.hovering && has_conflicts) UI_Tooltip + { + ui_labelf("This binding conflicts with others:"); + for(DF_CmdSpecNode *n = specs_with_binding.first; n != 0; n = n->next) + { + if(n->spec != spec) + { + ui_labelf("%S", n->spec->info.display_name); + } + } + } + } + + //- rjf: activity vis + if(df_gfx_state->bind_change_active && df_gfx_state->bind_change_cmd_spec == spec) + { + box->flags |= UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground; + box->border_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight1); + Vec4F32 bg_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight1); + bg_color.w *= 0.25f; + box->background_color = bg_color; + } + + scratch_end(scratch); +} + +internal UI_Signal +df_menu_bar_button(String8 string) +{ + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable|UI_BoxFlag_DrawHotEffects, string); + UI_Signal sig = ui_signal_from_box(box); + return sig; +} + +internal UI_Signal +df_cmd_spec_button(DF_CmdSpec *spec) +{ + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_Clickable, + "###cmd_%p", spec); + UI_Parent(box) UI_HeightFill + { + DF_IconKind canonical_icon = spec->info.canonical_icon_kind; + if(canonical_icon != DF_IconKind_Null) + { + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(2.f, 1.f)) + UI_TextAlignment(UI_TextAlign_Center) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + ui_label(df_g_icon_kind_text_table[canonical_icon]); + } + } + UI_PrefWidth(ui_text_dim(10, 1.f)) + { + UI_Flags(UI_BoxFlag_DrawTextFastpathCodepoint) + UI_FastpathCodepoint(box->fastpath_codepoint) + ui_label(spec->info.display_name); + ui_spacer(ui_pct(1, 0)); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_FastpathCodepoint(0) + { + df_cmd_binding_button(spec); + } + } + } + UI_Signal sig = ui_signal_from_box(box); + return sig; +} + +internal void +df_cmd_list_menu_buttons(DF_Window *ws, U64 count, DF_CoreCmdKind *cmds, U32 *fastpath_codepoints) +{ + Temp scratch = scratch_begin(0, 0); + for(U64 idx = 0; idx < count; idx += 1) + { + DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(cmds[idx]); + ui_set_next_fastpath_codepoint(fastpath_codepoints[idx]); + UI_Signal sig = df_cmd_spec_button(spec); + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.cmd_spec = spec; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + ui_ctx_menu_close(); + ws->menu_bar_focused = 0; + } + } + scratch_end(scratch); +} + +internal UI_Signal +df_icon_button(DF_IconKind kind, String8 string) +{ + String8 display_string = ui_display_part_from_key_string(string); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + string); + UI_Parent(box) + { + if(display_string.size == 0) + { + ui_spacer(ui_pct(1, 0)); + } + UI_TextAlignment(UI_TextAlign_Center) + UI_Flags(UI_BoxFlag_DisableTextTrunc) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(2.f, 1.f)) + UI_PrefHeight(ui_pct(1, 0)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_label(df_g_icon_kind_text_table[kind]); + if(display_string.size != 0) + { + UI_PrefWidth(ui_pct(1.f, 0.f)) ui_label(display_string); + } + if(display_string.size == 0) + { + ui_spacer(ui_pct(1, 0)); + } + } + UI_Signal result = ui_signal_from_box(box); + return result; +} + +internal UI_Signal +df_icon_buttonf(DF_IconKind kind, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = df_icon_button(kind, string); + scratch_end(scratch); + return sig; +} + +internal void +df_entity_tooltips(DF_Entity *entity) +{ + Temp scratch = scratch_begin(0, 0); + UI_Tooltip UI_PrefWidth(ui_text_dim(10, 1)) switch(entity->kind) + { + default:break; + case DF_EntityKind_File: + { + String8 full_path = df_full_path_from_entity(scratch.arena, entity); + ui_label(full_path); + }break; + case DF_EntityKind_Thread: UI_Flags(0) + { + String8 display_string = df_display_string_from_entity(scratch.arena, entity); + U64 rip_vaddr = df_query_cached_rip_from_thread(entity); + Architecture arch = df_architecture_from_entity(entity); + String8 arch_str = string_from_architecture(arch); + U32 pid_or_tid = entity->ctrl_id; + if(display_string.size != 0) UI_PrefWidth(ui_children_sum(1)) UI_Row + { + if(entity->flags & DF_EntityFlag_HasColor) + { + Vec4F32 color = df_rgba_from_entity(entity); + ui_set_next_text_color(color); + } + UI_PrefWidth(ui_text_dim(10, 1)) ui_label(display_string); + } + UI_PrefWidth(ui_children_sum(1)) UI_Row + { + UI_PrefWidth(ui_em(18.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("TID: "); + UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("%i", pid_or_tid); + } + UI_PrefWidth(ui_children_sum(1)) UI_Row + { + UI_PrefWidth(ui_em(18.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("Architecture: "); + UI_PrefWidth(ui_text_dim(10, 1)) ui_label(arch_str); + } + ui_spacer(ui_em(1.5f, 1.f)); + DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); + DF_Unwind unwind = df_query_cached_unwind_from_thread(entity); + for(DF_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next) + { + U64 rip_vaddr = frame->rip; + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); + String8 symbol = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + UI_PrefWidth(ui_children_sum(1)) UI_Row + { + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_PrefWidth(ui_em(18.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("0x%I64x", rip_vaddr); + if(symbol.size != 0) + { + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_CodeFunction)) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("%S", symbol); + } + else + { + String8 module_filename = str8_skip_last_slash(module->name); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("[??? in %S]", module_filename); + } + } + } + }break; + case DF_EntityKind_Breakpoint: UI_Flags(0) + { + if(entity->flags & DF_EntityFlag_HasColor) + { + Vec4F32 color = df_rgba_from_entity(entity); + ui_set_next_text_color(color); + } + String8 display_string = df_display_string_from_entity(scratch.arena, entity); + UI_PrefWidth(ui_text_dim(10, 1)) ui_label(display_string); + UI_PrefWidth(ui_children_sum(1)) UI_Row + { + String8 stop_condition = df_entity_child_from_kind(entity, DF_EntityKind_Condition)->name; + if(stop_condition.size == 0) + { + stop_condition = str8_lit("true"); + } + UI_PrefWidth(ui_em(12.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("Stop Condition: "); + UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, stop_condition); + } + UI_PrefWidth(ui_children_sum(1)) UI_Row + { + U64 hit_count = entity->u64; + String8 hit_count_text = str8_from_u64(scratch.arena, hit_count, 10, 0, 0); + UI_PrefWidth(ui_em(12.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("Hit Count: "); + UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, hit_count_text); + } + }break; + case DF_EntityKind_WatchPin: UI_Font(df_font_from_slot(DF_FontSlot_Code)) + { + if(entity->flags & DF_EntityFlag_HasColor) + { + Vec4F32 color = df_rgba_from_entity(entity); + ui_set_next_text_color(color); + } + String8 display_string = df_display_string_from_entity(scratch.arena, entity); + UI_PrefWidth(ui_text_dim(10, 1)) df_code_label(1.f, 1, display_string); + }break; + } + scratch_end(scratch); +} + +internal void +df_entity_desc_button(DF_Window *ws, DF_Entity *entity) +{ + Temp scratch = scratch_begin(0, 0); + if(entity->kind == DF_EntityKind_Thread) + { + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(ws); + CTRL_Event stop_event = df_ctrl_last_stop_event(); + DF_Entity *stopped_thread = df_entity_from_ctrl_handle(stop_event.machine_id, stop_event.entity); + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); + B32 do_special_color = 0; + Vec4F32 special_color = {0}; + if(selected_thread == entity) + { + Vec4F32 color = ui_top_background_color(); + Vec4F32 highlight_color = df_rgba_from_theme_color(DF_ThemeColor_SuccessBackground); + color.x += (highlight_color.x - color.x) * 0.5f; + color.y += (highlight_color.y - color.y) * 0.5f; + color.z += (highlight_color.z - color.z) * 0.5f; + color.w += (highlight_color.w - color.w) * 0.5f; + special_color = color; + do_special_color = 1; + } + if(stopped_thread == entity && + (stop_event.cause == CTRL_EventCause_UserBreakpoint || + stop_event.cause == CTRL_EventCause_InterruptedByException || + stop_event.cause == CTRL_EventCause_InterruptedByTrap || + stop_event.cause == CTRL_EventCause_InterruptedByHalt)) + { + Vec4F32 color = ui_top_background_color(); + Vec4F32 highlight_color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + color.x += (highlight_color.x - color.x) * 0.5f; + color.y += (highlight_color.y - color.y) * 0.5f; + color.z += (highlight_color.z - color.z) * 0.5f; + color.w += (highlight_color.w - color.w) * 0.5f; + special_color = color; + do_special_color = 1; + } + if(do_special_color) + { + ui_set_next_background_color(special_color); + } + } + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + if(entity->cfg_src == DF_CfgSrc_CommandLine) + { + Vec4F32 bg_color = mix_4f32(ui_top_background_color(), df_rgba_from_theme_color(DF_ThemeColor_Highlight0), 0.25f); + ui_set_next_background_color(bg_color); + } + UI_Key key = ui_key_from_stringf(ui_top_parent()->key, "entity_ref_button_%p", entity); + UI_Box *box = ui_build_box_from_key(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + key); + + //- rjf: build contents + UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 0)) + { + DF_EntityKindFlags kind_flags = df_g_entity_kind_flags_table[entity->kind]; + DF_EntityOpFlags op_flags = df_g_entity_kind_op_flags_table[entity->kind]; + DF_IconKind icon = df_g_entity_kind_icon_kind_table[entity->kind]; + Vec4F32 entity_color = df_rgba_from_theme_color(DF_ThemeColor_PlainText); + Vec4F32 entity_color_weak = df_rgba_from_theme_color(DF_ThemeColor_WeakText); + if(entity->flags & DF_EntityFlag_HasColor) + { + entity_color = df_rgba_from_entity(entity); + entity_color_weak = entity_color; + entity_color_weak.w *= 0.5f; + } + UI_TextColor(entity_color_weak) + UI_TextAlignment(UI_TextAlign_Center) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(1.875f, 1.f)) + ui_label(df_g_icon_kind_text_table[icon]); + if(entity->cfg_src == DF_CfgSrc_CommandLine) + { + UI_TextColor(entity_color_weak) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(1.875f, 1.f)) + { + UI_Box *info_box = &ui_g_nil_box; + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight0)) + { + info_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "%S###%p_temp_info", df_g_icon_kind_text_table[DF_IconKind_Info], entity); + } + UI_Signal info_sig = ui_signal_from_box(info_box); + if(info_sig.hovering) UI_Tooltip + { + ui_labelf("Specified via command line; not saved in profile."); + } + } + } + String8 label = df_display_string_from_entity(scratch.arena, entity); + UI_TextColor(entity_color) + UI_Font(kind_flags&DF_EntityKindFlag_NameIsCode ? df_font_from_slot(DF_FontSlot_Code) : ui_top_font()) + ui_label(label); + if(entity->kind == DF_EntityKind_Target) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_FontSize(ui_top_font_size()*0.95f) + { + DF_Entity *args = df_entity_child_from_kind(entity, DF_EntityKind_Arguments); + ui_label(args->name); + } + if(op_flags & DF_EntityOpFlag_Enable && entity->b32 == 0) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_FontSize(ui_top_font_size()*0.95f) UI_HeightFill + { + ui_label(str8_lit("(Disabled)")); + } + } + + //- rjf: do interaction on main box + { + UI_Signal sig = ui_signal_from_box(box); + if(ui_key_match(box->key, ui_hot_key())) + { + df_entity_tooltips(entity); + } + + // rjf: click => fastpath or dropdown for this entity + if(sig.clicked) + { + DF_EntityOpFlags flags = df_g_entity_kind_op_flags_table[entity->kind]; + if(flags & DF_EntityOpFlag_Edit || entity->kind == DF_EntityKind_Thread) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EntityRefFastPath)); + } + else + { + ui_ctx_menu_open(ws->entity_ctx_menu_key, key, v2f32(0, dim_2f32(box->rect).y)); + ws->entity_ctx_menu_entity = df_handle_from_entity(entity); + } + } + + // rjf: right-click => context menu for this entity + else if(sig.right_clicked) + { + DF_Handle handle = df_handle_from_entity(entity); + if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) + { + ui_ctx_menu_close(); + } + else + { + ui_ctx_menu_open(ws->entity_ctx_menu_key, sig.box->key, v2f32(0, sig.box->rect.y1 - sig.box->rect.y0)); + ws->entity_ctx_menu_entity = handle; + } + } + + // rjf: drag+drop + else if(sig.dragging && !contains_2f32(box->rect, ui_mouse())) + { + DF_DragDropPayload payload = {0}; + payload.key = box->key; + payload.entity = df_handle_from_entity(entity); + df_drag_begin(&payload); + } + } + scratch_end(scratch); +} + +internal void +df_entity_src_loc_button(DF_Window *ws, DF_Entity *entity, TxtPt point) +{ + Temp scratch = scratch_begin(0, 0); + String8 full_path = df_full_path_from_entity(scratch.arena, entity); + String8 filename = str8_skip_last_slash(full_path); + + // rjf: build main box + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "entity_file_ref_button_%p", entity); + UI_Signal sig = ui_signal_from_box(box); + + // rjf: build contents + UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 0)) + { + DF_IconKind icon = df_g_entity_kind_icon_kind_table[entity->kind]; + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_TextAlignment(UI_TextAlign_Center) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + ui_label(df_g_icon_kind_text_table[icon]); + ui_labelf("%S:%I64d:%I64d", filename, point.line, point.column); + } + + // rjf: click => find code location + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.file_path = full_path; + params.text_point = point; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + + // rjf: drag+drop + else if(sig.dragging && !contains_2f32(box->rect, ui_mouse())) + { + DF_DragDropPayload payload = {0}; + payload.key = box->key; + payload.entity = df_handle_from_entity(entity); + payload.text_point = point; + df_drag_begin(&payload); + } + + // rjf: hover => show full path + else if(sig.hovering && !sig.dragging) UI_Tooltip + { + ui_labelf("%S:%I64d:%I64d", full_path, point.line, point.column); + } + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: UI Widgets: Text View + +typedef struct DF_ThreadBoxDrawExtData DF_ThreadBoxDrawExtData; +struct DF_ThreadBoxDrawExtData +{ + Vec4F32 thread_color; + F32 progress_t; + F32 alive_t; + B32 is_selected; + B32 is_frozen; +}; + +internal UI_BOX_CUSTOM_DRAW(df_thread_box_draw_extensions) +{ + DF_ThreadBoxDrawExtData *u = (DF_ThreadBoxDrawExtData *)box->custom_draw_user_data; + + // rjf: draw line before next-to-execute line + { + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x0, + box->parent->rect.y0 - box->font_size*0.25f, + box->rect.x0 + box->font_size*260*u->alive_t, + box->parent->rect.y0 + box->font_size*0.25f), + v4f32(u->thread_color.x, u->thread_color.y, u->thread_color.z, 0), + 0, 0, 1); + inst->colors[Corner_00] = inst->colors[Corner_01] = u->thread_color; + } + + // rjf: draw 'progress bar', showing thread's progress through the line's address range + if(u->progress_t > 0) + { + Vec4F32 weak_thread_color = u->thread_color; + weak_thread_color.w *= 0.4f; + d_rect(r2f32p(box->rect.x0, + box->rect.y0, + box->rect.x1, + box->rect.y0 + (box->rect.y1-box->rect.y0)*u->progress_t), + weak_thread_color, + 0, 0, 1); + } + + // rjf: draw slight fill on selected thread + if(u->is_selected) + { + Vec4F32 weak_thread_color = u->thread_color; + weak_thread_color.w *= 0.3f; + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x0, + box->parent->rect.y0, + box->rect.x0 + ui_top_font_size()*22.f*u->alive_t, + box->parent->rect.y1), + v4f32(0, 0, 0, 0), + 0, 0, 1); + inst->colors[Corner_00] = inst->colors[Corner_01] = weak_thread_color; + } + + // rjf: locked icon on frozen threads + if(u->is_frozen) + { + F32 lock_icon_off = ui_top_font_size()*0.2f; + Vec4F32 lock_icon_color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + lock_icon_color.x += (1 - lock_icon_color.x) * 0.3f; + lock_icon_color.y += (1 - lock_icon_color.y) * 0.3f; + lock_icon_color.z += (1 - lock_icon_color.z) * 0.3f; + d_text(ui_icon_font(), + box->font_size, + v2f32((box->rect.x0 + box->rect.x1)/2 + lock_icon_off/2, + box->rect.y0 + lock_icon_off/2), + lock_icon_color, + df_g_icon_kind_text_table[DF_IconKind_Locked]); + } +} + +typedef struct DF_BreakpointBoxDrawExtData DF_BreakpointBoxDrawExtData; +struct DF_BreakpointBoxDrawExtData +{ + Vec4F32 color; + F32 alive_t; + F32 remap_px_delta; +}; + +internal UI_BOX_CUSTOM_DRAW(df_bp_box_draw_extensions) +{ + DF_BreakpointBoxDrawExtData *u = (DF_BreakpointBoxDrawExtData *)box->custom_draw_user_data; + + // rjf: draw line before next-to-execute line + { + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x0, + box->parent->rect.y0 - ui_top_font_size()*0.225f, + box->rect.x0 + ui_top_font_size()*250.f*u->alive_t, + box->parent->rect.y0 + ui_top_font_size()*0.225f), + v4f32(u->color.x, u->color.y, u->color.z, 0), + 0, 0, 1.f); + inst->colors[Corner_00] = inst->colors[Corner_01] = u->color; + } + + // rjf: draw slight fill + { + Vec4F32 weak_thread_color = u->color; + weak_thread_color.w *= 0.3f; + R_Rect2DInst *inst = d_rect(r2f32p(box->rect.x0, + box->parent->rect.y0, + box->rect.x0 + ui_top_font_size()*22.f*u->alive_t, + box->parent->rect.y1), + v4f32(0, 0, 0, 0), + 0, 0, 1); + inst->colors[Corner_00] = inst->colors[Corner_01] = weak_thread_color; + } + + // rjf: draw remaps + if(u->remap_px_delta != 0) + { + F32 remap_px_delta = u->remap_px_delta; + F32 circle_advance = f_dim_from_tag_size_string(box->font, box->font_size, df_g_icon_kind_text_table[DF_IconKind_CircleFilled]).x; + Vec2F32 bp_text_pos = ui_box_text_position(box); + Vec2F32 bp_center = v2f32(bp_text_pos.x + circle_advance/2 + circle_advance/8.f, bp_text_pos.y); + F_Metrics icon_font_metrics = f_metrics_from_tag_size(box->font, box->font_size); + F32 icon_font_line_height = f_line_height_from_metrics(&icon_font_metrics); + F32 remap_bar_thickness = 0.3f*ui_top_font_size(); + Vec4F32 remap_color = u->color; + remap_color.w *= 0.3f; + R_Rect2DInst *inst = d_rect(r2f32p(bp_center.x - remap_bar_thickness, + bp_center.y + ClampTop(remap_px_delta, 0) - remap_bar_thickness, + bp_center.x + remap_bar_thickness, + bp_center.y + ClampBot(remap_px_delta, 0) + remap_bar_thickness), + remap_color, 2.f, 0, 1.f); + d_text(box->font, box->font_size, + v2f32(bp_text_pos.x, + bp_center.y + remap_px_delta), + remap_color, + df_g_icon_kind_text_table[DF_IconKind_CircleFilled]); + } +} + +internal DF_CodeSliceSignal +df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, String8 string) +{ + DF_CodeSliceSignal result = {0}; + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx->thread); + CTRL_Event stop_event = df_ctrl_last_stop_event(); + DF_Entity *stopper_thread = df_entity_from_ctrl_handle(stop_event.machine_id, stop_event.entity); + B32 is_focused = ui_is_focus_active(); + B32 ctrlified = (os_get_event_flags() & OS_EventFlag_Ctrl); + + ////////////////////////////// + //- rjf: build top-level container + // + UI_Box *top_container_box = &ui_g_nil_box; + Rng2F32 clipped_top_container_rect = {0}; + { + ui_set_next_child_layout_axis(Axis2_X); + ui_set_next_pref_width(ui_px(params->line_text_max_width_px, 1)); + ui_set_next_pref_height(ui_children_sum(1)); + top_container_box = ui_build_box_from_string(UI_BoxFlag_DisableFocusViz|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, string); + clipped_top_container_rect = top_container_box->rect; + for(UI_Box *b = top_container_box; !ui_box_is_nil(b); b = b->parent) + { + if(b->flags & UI_BoxFlag_Clip) + { + clipped_top_container_rect = intersect_2f32(b->rect, clipped_top_container_rect); + } + } + } + + ////////////////////////////// + //- rjf: build per-line context menus + // + UI_Key *ctx_menu_keys = push_array(scratch.arena, UI_Key, dim_1s64(params->line_num_range)+1); + { + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num < params->line_num_range.max; + line_num += 1, line_idx += 1) + { + ctx_menu_keys[line_idx] = ui_key_from_stringf(top_container_box->key, "line_ctx_%I64d", line_num); + UI_CtxMenu(ctx_menu_keys[line_idx]) UI_PrefWidth(ui_em(37.f, 1.f)) + { + DF_TextLineSrc2DasmInfoList *line_src2dasm_list = ¶ms->line_src2dasm[line_idx]; + DF_TextLineDasm2SrcInfoList *line_dasm2src_list = ¶ms->line_dasm2src[line_idx]; + + //- rjf: copy selection + if(!txt_pt_match(*cursor, *mark) && df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Copy)).clicked) + { + result.copy_range = txt_rng(*cursor, *mark); + ui_ctx_menu_close(); + } + + //- rjf: watch selection + if(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpressionAtCursor)).clicked) + { + result.toggle_cursor_watch = 1; + ui_ctx_menu_close(); + } + + //- rjf: set-next-statement + if(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetNextStatement)).clicked) + { + result.set_next_statement_line_num = line_num; + ui_ctx_menu_close(); + } + + //- rjf: run-to-line + if(df_icon_buttonf(DF_IconKind_Play, "Run To Line").clicked) + { + result.run_to_line_num = line_num; + ui_ctx_menu_close(); + } + + //- rjf: breakpoint placing + if((params->line_bps[line_idx].count == 0 && + df_icon_buttonf(DF_IconKind_CircleFilled, "Place Breakpoint").clicked) || + (params->line_bps[line_idx].count != 0 && + df_icon_buttonf(DF_IconKind_CircleFilled, "Remove Breakpoint").clicked)) + { + result.clicked_margin_line_num = line_num; + ui_ctx_menu_close(); + } + + //- rjf: go from src -> disasm + if(line_src2dasm_list->first != 0 && + df_icon_buttonf(DF_IconKind_Find, "Go To Disassembly").clicked) + { + result.goto_disasm_line_num = line_num; + ui_ctx_menu_close(); + } + + //- rjf: go from disasm -> src + if(line_dasm2src_list->first != 0 && + df_icon_buttonf(DF_IconKind_Find, "Go To Source").clicked) + { + result.goto_src_line_num = line_num; + ui_ctx_menu_close(); + } + } + } + } + + ////////////////////////////// + //- rjf: build margins + // + UI_Box *margin_container_box = &ui_g_nil_box; + if(params->flags & DF_CodeSliceFlag_Margin) UI_Parent(top_container_box) ProfScope("build margins") + { + ui_set_next_pref_width(ui_px(params->margin_width_px, 1)); + ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); + ui_set_next_child_layout_axis(Axis2_Y); + margin_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable, str8_lit("margin_container")); + UI_Parent(margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + { + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num <= params->line_num_range.max; + line_num += 1, line_idx += 1) + { + DF_EntityList line_ips = params->line_ips[line_idx]; + DF_EntityList line_bps = params->line_bps[line_idx]; + DF_EntityList line_pins = params->line_pins[line_idx]; + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_background_color(v4f32(0, 0, 0, 0)); + UI_Box *line_margin_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawActiveEffects, "line_margin_%I64x", line_num); + UI_Parent(line_margin_box) + { + //- rjf: build margin thread ip ui + for(DF_EntityNode *n = line_ips.first; n != 0; n = n->next) + { + // rjf: unpack thread + DF_Entity *thread = n->entity; + U64 unwind_count = (thread == selected_thread) ? ctrl_ctx->unwind_count : 0; + U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); + + // rjf: thread info => color + Vec4F32 color = v4f32(1, 1, 1, 1); + { + if(unwind_count != 0) + { + color = df_rgba_from_theme_color(DF_ThemeColor_ThreadUnwound); + } + else if(thread == stopper_thread && + (stop_event.cause == CTRL_EventCause_InterruptedByHalt || + stop_event.cause == CTRL_EventCause_InterruptedByTrap || + stop_event.cause == CTRL_EventCause_InterruptedByException)) + { + color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + } + else if(thread->flags & DF_EntityFlag_HasColor) + { + color = df_rgba_from_entity(thread); + } + if(df_ctrl_targets_running() && df_ctrl_last_run_frame_idx() < df_frame_index()) + { + color.w *= 0.5f; + } + if(thread != selected_thread) + { + color.w *= 0.8f; + } + } + + // rjf: build thread box + ui_set_next_hover_cursor(OS_Cursor_UpDownLeftRight); + ui_set_next_font(ui_icon_font()); + ui_set_next_font_size(params->font_size); + ui_set_next_pref_width(ui_pct(1, 0)); + ui_set_next_pref_height(ui_pct(1, 0)); + ui_set_next_text_color(color); + ui_set_next_text_alignment(UI_TextAlign_Center); + UI_Box *thread_box = ui_build_box_from_stringf(UI_BoxFlag_DisableTextTrunc| + UI_BoxFlag_Clickable| + UI_BoxFlag_AnimatePosX| + UI_BoxFlag_DrawText, + "%S##ip_%p", + df_g_icon_kind_text_table[DF_IconKind_RightArrow], + thread); + UI_Signal thread_sig = ui_signal_from_box(thread_box); + + // rjf: custom draw + { + DF_ThreadBoxDrawExtData *u = push_array(ui_build_arena(), DF_ThreadBoxDrawExtData, 1); + u->thread_color = color; + u->alive_t = thread->alive_t; + u->is_selected = (thread == selected_thread); + u->is_frozen = df_entity_is_frozen(thread); + ui_box_equip_custom_draw(thread_box, df_thread_box_draw_extensions, u); + + // rjf: fill out progress t (progress into range of current line's + // voff range) + if(params->line_src2dasm[line_idx].first != 0) + { + DF_TextLineSrc2DasmInfoList *line_info_list = ¶ms->line_src2dasm[line_idx]; + DF_TextLineSrc2DasmInfo *line_info = 0; + for(DF_TextLineSrc2DasmInfoNode *n = line_info_list->first; + n != 0; + n = n->next) + { + if(n->v.binary == binary) + { + line_info = &n->v; + break; + } + } + if(line_info != 0) + { + Rng1U64 line_voff_rng = line_info->voff_range; + Vec4F32 weak_thread_color = color; + weak_thread_color.w *= 0.4f; + F32 progress_t = (line_voff_rng.max != line_voff_rng.min) ? ((F32)(thread_rip_voff - line_voff_rng.min) / (F32)(line_voff_rng.max - line_voff_rng.min)) : 0; + progress_t = Clamp(0, progress_t, 1); + u->progress_t = progress_t; + } + } + } + + // rjf: hover tooltips + if(thread_sig.hovering) + { + df_entity_tooltips(thread); + } + + // rjf: ip right-click menu + if(thread_sig.right_clicked) + { + DF_Handle handle = df_handle_from_entity(thread); + if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) + { + ui_ctx_menu_close(); + } + else + { + ui_ctx_menu_open(ws->entity_ctx_menu_key, thread_box->key, v2f32(0, thread_box->rect.y1-thread_box->rect.y0)); + ws->entity_ctx_menu_entity = handle; + } + } + + // rjf: double click => select + if(thread_sig.double_clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(thread); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectThread)); + } + + // rjf: drag start + if(thread_sig.dragging && !contains_2f32(thread_box->rect, ui_mouse())) + { + DF_DragDropPayload payload = {0}; + payload.key = thread_box->key; + payload.entity = df_handle_from_entity(thread); + df_drag_begin(&payload); + } + } + + //- rjf: build margin breakpoint ui + for(DF_EntityNode *n = line_bps.first; n != 0; n = n->next) + { + DF_Entity *bp = n->entity; + Vec4F32 bp_color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + if(bp->flags & DF_EntityFlag_HasColor) + { + bp_color = df_rgba_from_entity(bp); + } + if(bp->b32 == 0) + { + bp_color = v4f32(bp_color.x * 0.6f, bp_color.y * 0.6f, bp_color.z * 0.6f, bp_color.w * 0.6f); + } + + // rjf: prep custom rendering data + DF_BreakpointBoxDrawExtData *bp_draw = push_array(ui_build_arena(), DF_BreakpointBoxDrawExtData, 1); + { + bp_draw->color = bp_color; + DF_TextLineSrc2DasmInfoList *src2dasm_list = ¶ms->line_src2dasm[line_idx]; + for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list->first; n != 0; n = n->next) + { + S64 remap_line = (S64)n->v.remap_line; + if(remap_line != line_num) + { + bp_draw->remap_px_delta = (remap_line - line_num) * params->line_height_px; + break; + } + } + bp_draw->alive_t = bp->alive_t; + } + + // rjf: build box for breakpoint + ui_set_next_font(df_font_from_slot(DF_FontSlot_Icons)); + ui_set_next_font_size(params->font_size * 1.f); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_text_color(bp_color); + ui_set_next_text_alignment(UI_TextAlign_Center); + UI_Box *bp_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_AnimatePosX| + UI_BoxFlag_Clickable| + UI_BoxFlag_DisableTextTrunc, + "%S##bp_%p", + df_g_icon_kind_text_table[DF_IconKind_CircleFilled], + bp); + ui_box_equip_custom_draw(bp_box, df_bp_box_draw_extensions, bp_draw); + UI_Signal bp_sig = ui_signal_from_box(bp_box); + + // rjf: bp hovering + if(bp_sig.hovering) + { + df_entity_tooltips(bp); + } + + // rjf: click => remove breakpoint + if(bp_sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(bp); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RemoveBreakpoint)); + } + + // rjf: drag start + if(bp_sig.dragging && !contains_2f32(bp_box->rect, ui_mouse())) + { + DF_DragDropPayload payload = {0}; + payload.entity = df_handle_from_entity(bp); + df_drag_begin(&payload); + } + + // rjf: bp right-click menu + if(bp_sig.right_clicked) + { + DF_Handle handle = df_handle_from_entity(bp); + if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) + { + ui_ctx_menu_close(); + } + else + { + ui_ctx_menu_open(ws->entity_ctx_menu_key, bp_box->key, v2f32(0, bp_box->rect.y1-bp_box->rect.y0)); + ws->entity_ctx_menu_entity = handle; + } + } + } + + //- rjf: build margin watch pin ui + for(DF_EntityNode *n = line_pins.first; n != 0; n = n->next) + { + DF_Entity *pin = n->entity; + Vec4F32 color = v4f32(1, 1, 1, 1); + if(pin->flags & DF_EntityFlag_HasColor) + { + color = df_rgba_from_entity(pin); + } + + // rjf: build box for watch + ui_set_next_font(df_font_from_slot(DF_FontSlot_Icons)); + ui_set_next_font_size(params->font_size * 1.f); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_text_color(color); + ui_set_next_text_alignment(UI_TextAlign_Center); + UI_Box *pin_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_Clickable| + UI_BoxFlag_AnimatePosX| + UI_BoxFlag_DisableTextTrunc, + "%S##watch_%p", + df_g_icon_kind_text_table[DF_IconKind_Pin], + pin); + UI_Signal pin_sig = ui_signal_from_box(pin_box); + + // rjf: watch hovering + if(pin_sig.hovering) + { + df_entity_tooltips(pin); + } + + // rjf: click => remove pin + if(pin_sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(pin); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RemoveEntity)); + } + + // rjf: drag start + if(pin_sig.dragging && !contains_2f32(pin_box->rect, ui_mouse())) + { + DF_DragDropPayload payload = {0}; + payload.entity = df_handle_from_entity(pin); + df_drag_begin(&payload); + } + + // rjf: watch right-click menu + if(pin_sig.right_clicked) + { + DF_Handle handle = df_handle_from_entity(pin); + if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) + { + ui_ctx_menu_close(); + } + else + { + ui_ctx_menu_open(ws->entity_ctx_menu_key, pin_box->key, v2f32(0, pin_box->rect.y1-pin_box->rect.y0)); + ws->entity_ctx_menu_entity = handle; + } + } + } + } + UI_Signal line_margin_sig = ui_signal_from_box(line_margin_box); + if(line_margin_sig.clicked) + { + result.clicked_margin_line_num = line_num; + } + } + } + } + + ////////////////////////////// + //- rjf: build main text container box, for mouse interaction on both lines & line numbers + // + UI_Box *text_container_box = &ui_g_nil_box; + UI_Parent(top_container_box) + { + ui_set_next_hover_cursor(ctrlified ? OS_Cursor_HandPoint : OS_Cursor_IBar); + ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); + text_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable, str8_lit("text_container")); + } + + ////////////////////////////// + //- rjf: determine starting offset for each at line, at which we can begin placing extra info to the right + // + F32 *line_extras_off = push_array(scratch.arena, F32, dim_1s64(params->line_num_range)+1); + { + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num < params->line_num_range.max; + line_num += 1, line_idx += 1) + { + String8 line_text = params->line_text[line_idx]; + F32 line_text_dim = f_dim_from_tag_size_string(params->font, params->font_size, line_text).x + params->line_num_width_px; + line_extras_off[line_idx] = Max(line_text_dim, params->font_size*50); + } + } + + ////////////////////////////// + //- rjf: produce per-line extra annotation containers + // + UI_Box **line_extras_boxes = push_array(scratch.arena, UI_Box *, dim_1s64(params->line_num_range)+1); + UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) UI_Parent(text_container_box) + { + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num < params->line_num_range.max; + line_num += 1, line_idx += 1) + { + ui_set_next_fixed_x(line_extras_off[line_idx]); + ui_set_next_fixed_y(line_idx*params->line_height_px); + line_extras_boxes[line_idx] = ui_build_box_from_stringf(0, "###extras_%I64x", line_idx); + } + } + + ////////////////////////////// + //- rjf: build watch pin annotations + // + { + DBGI_Scope *scope = dbgi_scope_open(); + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num < params->line_num_range.max; + line_num += 1, line_idx += 1) + { + DF_EntityList pins = params->line_pins[line_idx]; + if(pins.count != 0) UI_Parent(line_extras_boxes[line_idx]) UI_Font(params->font) UI_FontSize(params->font_size) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + { + for(DF_EntityNode *n = pins.first; n != 0; n = n->next) + { + DF_Entity *pin = n->entity; + String8 pin_expr = pin->name; + DF_Eval eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, pin_expr); + String8 eval_string = {0}; + if(!tg_key_match(tg_key_zero(), eval.type_key)) + { + DF_CfgTable cfg_table = {0}; + String8List eval_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, 10, params->font, params->font_size, params->font_size*60.f, 0, eval, &cfg_table); + eval_string = str8_list_join(scratch.arena, &eval_strings, 0); + } + ui_spacer(ui_em(1.5f, 1.f)); + ui_set_next_pref_width(ui_children_sum(1)); + UI_Key pin_box_key = ui_key_from_stringf(ui_key_zero(), "###pin_%p", pin); + UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos|UI_BoxFlag_Clickable|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawBorder, pin_box_key); + UI_Parent(pin_box) UI_PrefWidth(ui_text_dim(10, 1)) + { + Vec4F32 pin_color = df_rgba_from_theme_color(DF_ThemeColor_WeakText); + if(pin->flags & DF_EntityFlag_HasColor) + { + pin_color = df_rgba_from_entity(pin); + } + UI_PrefWidth(ui_em(1.5f, 1.f)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_TextColor(pin_color) + UI_TextAlignment(UI_TextAlign_Center) + UI_Flags(UI_BoxFlag_DisableTextTrunc) + { + UI_Signal sig = ui_buttonf("%S###pin_nub", df_g_icon_kind_text_table[DF_IconKind_Pin]); + if(sig.dragging && !contains_2f32(sig.box->rect, ui_mouse())) + { + DF_DragDropPayload payload = {0}; + payload.entity = df_handle_from_entity(pin); + df_drag_begin(&payload); + } + if(sig.clicked || sig.right_clicked) + { + ui_ctx_menu_open(ws->entity_ctx_menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + ws->entity_ctx_menu_entity = df_handle_from_entity(pin); + } + } + df_code_label(0.8f, 1, pin_expr); + df_code_label(0.6f, 1, eval_string); + } + UI_Signal pin_sig = ui_signal_from_box(pin_box); + if(ui_key_match(pin_box_key, ui_hot_key())) + { + df_set_hover_eval(ws, v2f32(pin_box->rect.x0, pin_box->rect.y1-2.f), *ctrl_ctx, &df_g_nil_entity, txt_pt(1, 1), 0, pin_expr); + } + } + } + } + dbgi_scope_close(scope); + } + + ////////////////////////////// + //- rjf: mouse -> text coordinates + // + TxtPt mouse_pt = {0}; + ProfScope("mouse -> text coordinates") + { + Vec2F32 mouse = ui_mouse(); + + // rjf: mouse y => index + U64 mouse_y_line_idx = (U64)((mouse.y - text_container_box->rect.y0) / params->line_height_px); + + // rjf: index => line num + S64 line_num = (params->line_num_range.min + mouse_y_line_idx); + String8 line_string = (params->line_num_range.min <= line_num && line_num <= params->line_num_range.max) ? (params->line_text[mouse_y_line_idx]) : str8_zero(); + + // rjf: mouse x * string => column + S64 column = f_char_pos_from_tag_size_string_p(params->font, params->font_size, line_string, mouse.x-text_container_box->rect.x0-params->line_num_width_px)+1; + + // rjf: bundle + mouse_pt = txt_pt(line_num, column); + + // rjf: clamp + if(dim_1s64(params->line_num_range) > 0) + { + U64 last_line_size = params->line_text[dim_1s64(params->line_num_range)-1].size; + TxtRng legal_pt_rng = txt_rng(txt_pt(params->line_num_range.min, 1), + txt_pt(params->line_num_range.max, last_line_size+1)); + if(txt_pt_less_than(mouse_pt, legal_pt_rng.min)) + { + mouse_pt = legal_pt_rng.min; + } + if(txt_pt_less_than(legal_pt_rng.max, mouse_pt)) + { + mouse_pt = legal_pt_rng.max; + } + } + else + { + mouse_pt = txt_pt(1, 1); + } + result.mouse_pt = mouse_pt; + } + + ////////////////////////////// + //- rjf: interact with margin box & text box + // + UI_Signal margin_container_sig = ui_signal_from_box(margin_container_box); + UI_Signal text_container_sig = ui_signal_from_box(text_container_box); + DF_Entity *line_drag_entity = &df_g_nil_entity; + { + //- rjf: clicking/dragging over the text container + if(!ctrlified && text_container_sig.dragging) + { + if(mouse_pt.line == 0) + { + mouse_pt.column = 1; + if(ui_mouse().y <= top_container_box->rect.y0) + { + mouse_pt.line = params->line_num_range.min - 2; + } + else if(ui_mouse().y >= top_container_box->rect.y1) + { + mouse_pt.line = params->line_num_range.max + 2; + } + } + if(text_container_sig.pressed) + { + *mark = mouse_pt; + } + *cursor = mouse_pt; + *preferred_column = cursor->column; + } + + //- rjf: right-click => active context menu for line + if(text_container_sig.right_clicked) + { + S64 line_idx = mouse_pt.line-params->line_num_range.min; + if(0 <= line_idx && line_idx < dim_1s64(params->line_num_range)) + { + ui_ctx_menu_open(ctx_menu_keys[line_idx], ui_key_zero(), sub_2f32(ui_mouse(), v2f32(2, 2))); + if(txt_pt_match(*cursor, *mark)) + { + *cursor = *mark = mouse_pt; + } + } + } + + //- rjf: hovering text container & ctrl+scroll -> change font size + if(text_container_sig.hovering) + { + for(OS_Event *event = ui_events()->first; event != 0; event = event->next) + { + if(os_handle_match(event->window, ui_window()) && event->kind == OS_EventKind_Scroll && event->flags & OS_EventFlag_Ctrl) + { + os_eat_event(ui_events(), event); + if(event->delta.y < 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_IncCodeFontScale)); + } + else if(event->delta.y > 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DecCodeFontScale)); + } + } + } + } + + //- rjf: dragging threads, breakpoints, or watch pins over this slice -> + // drop target + if(df_drag_is_active() && contains_2f32(clipped_top_container_rect, ui_mouse())) + { + DF_DragDropPayload *payload = &df_g_drag_drop_payload; + DF_Entity *entity = df_entity_from_handle(payload->entity); + if(entity->kind == DF_EntityKind_Thread || + entity->kind == DF_EntityKind_WatchPin || + entity->kind == DF_EntityKind_Breakpoint) + { + line_drag_entity = entity; + } + } + + //- rjf: drop target is dropped -> process + { + DF_DragDropPayload payload = {0}; + if(!df_entity_is_nil(line_drag_entity) && df_drag_drop(&payload)) + { + result.dropped_entity = line_drag_entity; + result.dropped_entity_line_num = mouse_pt.line; + } + } + + //- rjf: commit text container signal to main output + result.base = text_container_sig; + } + + ////////////////////////////// + //- rjf: mouse -> expression range info + // + if(text_container_sig.mouse_over && contains_1s64(params->line_num_range, mouse_pt.line)) ProfScope("mouse -> expression range") + { + TxtRng selected_rng = txt_rng(*cursor, *mark); + if(!txt_pt_match(*cursor, *mark) && cursor->line == mark->line && + ((txt_pt_less_than(selected_rng.min, mouse_pt) || txt_pt_match(selected_rng.min, mouse_pt)) && + txt_pt_less_than(mouse_pt, selected_rng.max))) + { + U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; + String8 line_text = params->line_text[line_slice_idx]; + F32 expr_hoff_px = params->line_num_width_px + f_dim_from_tag_size_string(params->font, params->font_size, str8_prefix(line_text, selected_rng.min.column-1)).x; + result.mouse_expr_rng = selected_rng; + result.mouse_expr_baseline_pos = v2f32(text_container_box->rect.x0+expr_hoff_px, + text_container_box->rect.y0+line_slice_idx*params->line_height_px + params->line_height_px*0.85f); + } + else + { + U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; + String8 line_text = params->line_text[line_slice_idx]; + TXTI_TokenArray line_tokens = params->line_tokens[line_slice_idx]; + Rng1U64 line_range = params->line_ranges[line_slice_idx]; + U64 mouse_pt_off = line_range.min + (mouse_pt.column-1); + Rng1U64 expr_off_rng = txti_expr_range_from_line_off_range_string_tokens(mouse_pt_off, line_range, line_text, &line_tokens); + if(expr_off_rng.max != expr_off_rng.min) + { + F32 expr_hoff_px = params->line_num_width_px + f_dim_from_tag_size_string(params->font, params->font_size, str8_prefix(line_text, expr_off_rng.min-line_range.min)).x; + result.mouse_expr_rng = txt_rng(txt_pt(mouse_pt.line, 1+(expr_off_rng.min-line_range.min)), txt_pt(mouse_pt.line, 1+(expr_off_rng.max-line_range.min))); + result.mouse_expr_baseline_pos = v2f32(text_container_box->rect.x0+expr_hoff_px, + text_container_box->rect.y0+line_slice_idx*params->line_height_px + params->line_height_px*0.85f); + } + } + } + + ////////////////////////////// + //- rjf: mouse -> set global frontend hovered line info + // + if(text_container_sig.mouse_over && contains_1s64(params->line_num_range, mouse_pt.line)) + { + U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; + if(params->line_src2dasm[line_slice_idx].first != 0) + { + df_set_hovered_line_info(params->line_src2dasm[line_slice_idx].first->v.binary, params->line_src2dasm[line_slice_idx].first->v.voff_range.min); + } + if(params->line_dasm2src[line_slice_idx].first != 0) + { + df_set_hovered_line_info(params->line_dasm2src[line_slice_idx].first->v.binary, params->line_dasm2src[line_slice_idx].first->v.voff_range.min); + } + } + + ////////////////////////////// + //- rjf: dragging entity which applies to lines over this slice -> visualize + // + if(!df_entity_is_nil(line_drag_entity) && contains_2f32(clipped_top_container_rect, ui_mouse())) + { + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_DropSiteOverlay); + if(line_drag_entity->flags & DF_EntityFlag_HasColor) + { + color = df_rgba_from_entity(line_drag_entity); + color.w /= 2; + } + D_Bucket *bucket = d_bucket_make(); + D_BucketScope(bucket) + { + Rng2F32 drop_line_rect = r2f32p(top_container_box->rect.x0, + top_container_box->rect.y0 + (mouse_pt.line - params->line_num_range.min) * params->line_height_px, + top_container_box->rect.x1, + top_container_box->rect.y0 + (mouse_pt.line - params->line_num_range.min + 1) * params->line_height_px); + R_Rect2DInst *inst = d_rect(pad_2f32(drop_line_rect, 8.f), color, 0, 0, 4.f); + inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(color.x, color.y, color.z, 0); + } + ui_box_equip_draw_bucket(text_container_box, bucket); + } + + ////////////////////////////// + //- rjf: (cursor*mark*list(flash_range)) -> list(text_range*color) + // + typedef struct TxtRngColorPairNode TxtRngColorPairNode; + struct TxtRngColorPairNode + { + TxtRngColorPairNode *next; + TxtRng rng; + Vec4F32 color; + }; + TxtRngColorPairNode *first_txt_rng_color_pair = 0; + TxtRngColorPairNode *last_txt_rng_color_pair = 0; + { + // rjf: push initial for cursor/mark + { + TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); + n->rng = txt_rng(*cursor, *mark); + n->color = ui_top_text_select_color(); + SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); + } + + // rjf: push for flash ranges + for(DF_EntityNode *n = params->flash_ranges.first; n != 0; n = n->next) + { + DF_Entity *flash_range = n->entity; + if(flash_range->flags & DF_EntityFlag_HasTextPoint && + flash_range->flags & DF_EntityFlag_HasTextPointAlt) + { + TxtRngColorPairNode *pair = push_array(scratch.arena, TxtRngColorPairNode, 1); + pair->rng = txt_rng(flash_range->text_point, flash_range->text_point_alt); + pair->color = df_rgba_from_entity(flash_range); + pair->color.w *= ClampTop(flash_range->life_left, 1.f); + SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, pair); + } + } + + // rjf: push for ctrlified mouse expr + if(ctrlified && !txt_pt_match(result.mouse_expr_rng.max, result.mouse_expr_rng.min)) + { + TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); + n->rng = result.mouse_expr_rng; + n->color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + n->color.w *= 0.3f; + SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); + } + } + + ////////////////////////////// + //- rjf: build line numbers + // + if(params->flags & DF_CodeSliceFlag_LineNums) UI_Parent(text_container_box) ProfScope("build line numbers") + { + TxtRng select_rng = txt_rng(*cursor, *mark); + Vec4F32 inactive_color = df_rgba_from_theme_color(DF_ThemeColor_WeakText); + Vec4F32 active_color = df_rgba_from_theme_color(DF_ThemeColor_PlainText); + ui_set_next_pref_width(ui_px(params->line_num_width_px, 1.f)); + ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); + ui_set_next_flags(UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideLeft); + UI_Column + UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + UI_Font(params->font) + UI_FontSize(params->font_size) + UI_CornerRadius(0) + { + Vec4F32 code_line_bgs[] = + { + df_rgba_from_theme_color(DF_ThemeColor_LineInfo0), + df_rgba_from_theme_color(DF_ThemeColor_LineInfo1), + df_rgba_from_theme_color(DF_ThemeColor_LineInfo2), + df_rgba_from_theme_color(DF_ThemeColor_LineInfo3), + }; + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num <= params->line_num_range.max; + line_num += 1, line_idx += 1) + { + Vec4F32 text_color = (select_rng.min.line <= line_num && line_num <= select_rng.max.line) ? active_color : inactive_color; + Vec4F32 bg_color = v4f32(0, 0, 0, 0); + + // rjf: line info on this line -> adjust bg color to visualize + { + B32 has_line_info = 0; + S64 line_info_line_num = 0; + F32 line_info_t = 0; + DF_TextLineSrc2DasmInfoList *src2dasm_list = ¶ms->line_src2dasm[line_idx]; + DF_TextLineDasm2SrcInfoList *dasm2src_list = ¶ms->line_dasm2src[line_idx]; + if(src2dasm_list->first != 0) + { + has_line_info = (src2dasm_list->first->v.remap_line == line_num); + line_info_line_num = line_num; + line_info_t = src2dasm_list->first->v.binary->alive_t; + } + if(dasm2src_list->first != 0) + { + DF_TextLineDasm2SrcInfo *dasm2src_info = 0; + U64 best_stamp = 0; + for(DF_TextLineDasm2SrcInfoNode *n = dasm2src_list->first; n != 0; n = n->next) + { + if(n->v.file->timestamp > best_stamp) + { + dasm2src_info = &n->v; + best_stamp = n->v.file->timestamp; + } + } + if(dasm2src_info != 0) + { + DF_Entity *binary = dasm2src_info->binary; + has_line_info = 1; + line_info_line_num = dasm2src_info->pt.line; + line_info_t = binary->alive_t; + } + } + if(has_line_info) + { + Vec4F32 color = code_line_bgs[line_info_line_num % ArrayCount(code_line_bgs)]; + color.w *= line_info_t; + bg_color = color; + } + } + + // rjf: build line num box + ui_set_next_text_color(text_color); + ui_set_next_background_color(bg_color); + ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DrawBackground, "%I64u##line_num", line_num); + } + } + } + + ////////////////////////////// + //- rjf: build line text + // + UI_Parent(text_container_box) ProfScope("build line text") + { + DF_Entity *hovered_line_binary = df_get_hovered_line_info_binary(); + U64 hovered_line_voff = df_get_hovered_line_info_voff(); + ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); + UI_WidthFill + UI_Column + UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + UI_Font(params->font) + UI_FontSize(params->font_size) + UI_CornerRadius(0) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_CodeDefault)) + { + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num <= params->line_num_range.max; line_num += 1, line_idx += 1) + { + String8 line_string = params->line_text[line_idx]; + Rng1U64 line_range = params->line_ranges[line_idx]; + TXTI_TokenArray *line_tokens = ¶ms->line_tokens[line_idx]; + ui_set_next_text_padding(-2); + UI_Key line_key = ui_key_from_stringf(top_container_box->key, "ln_%I64x", line_num); + UI_Box *line_box = ui_build_box_from_key(UI_BoxFlag_DisableTextTrunc|UI_BoxFlag_DrawText|UI_BoxFlag_DisableIDString, line_key); + D_Bucket *line_bucket = d_bucket_make(); + d_push_bucket(line_bucket); + + // rjf: string * tokens -> fancy string list + D_FancyStringList line_fancy_strings = {0}; + { + if(line_tokens->count == 0) + { + D_FancyString fstr = + { + params->font, + line_string, + df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), + params->font_size, + 0, + 0, + }; + d_fancy_string_list_push(scratch.arena, &line_fancy_strings, &fstr); + } + else + { + TXTI_Token *line_tokens_first = line_tokens->v; + TXTI_Token *line_tokens_opl = line_tokens->v + line_tokens->count; + for(TXTI_Token *token = line_tokens_first; token < line_tokens_opl; token += 1) + { + // rjf: token -> token string + String8 token_string = {0}; + { + Rng1U64 token_range = r1u64(0, line_string.size); + if(token->range.min > line_range.min) + { + token_range.min += token->range.min-line_range.min; + } + if(token->range.max < line_range.max) + { + token_range.max = token->range.max-line_range.min; + } + token_string = str8_substr(line_string, token_range); + } + + // rjf: token -> token color + Vec4F32 token_color = df_rgba_from_theme_color(DF_ThemeColor_CodeDefault); + { + DF_ThemeColor new_color_kind = df_theme_color_from_txti_token_kind(token->kind); + F32 mix_t = 1.f; + if(token->kind == TXTI_TokenKind_Identifier) + { + B32 mapped_special = 0; + for(DF_EntityNode *n = params->relevant_binaries.first; n != 0; n = n->next) + { + DF_Entity *binary = n->entity; + if(!mapped_special) + { + U64 voff = df_voff_from_binary_symbol_name(binary, token_string); + if(voff != 0) + { + mapped_special = 1; + new_color_kind = DF_ThemeColor_CodeFunction; + mix_t = binary->alive_t; + } + } + if(!mapped_special) + { + U64 type_num = df_type_num_from_binary_name(binary, token_string); + if(type_num != 0) + { + mapped_special = 1; + new_color_kind = DF_ThemeColor_CodeType; + mix_t = binary->alive_t; + } + } + if(!mapped_special) + { + U64 local_num = eval_num_from_string(parse_ctx->locals_map, token_string); + if(local_num != 0) + { + mapped_special = 1; + new_color_kind = DF_ThemeColor_CodeLocal; + mix_t = binary->alive_t; + } + } + break; + } + } + if(new_color_kind != DF_ThemeColor_Null) + { + Vec4F32 t_color = df_rgba_from_theme_color(new_color_kind); + token_color.x += (t_color.x - token_color.x) * mix_t; + token_color.y += (t_color.y - token_color.y) * mix_t; + token_color.z += (t_color.z - token_color.z) * mix_t; + token_color.w += (t_color.w - token_color.w) * mix_t; + } + } + + // rjf: push fancy string + D_FancyString fstr = + { + params->font, + token_string, + token_color, + params->font_size, + 0, + 0, + }; + d_fancy_string_list_push(scratch.arena, &line_fancy_strings, &fstr); + } + } + } + + // rjf: equip fancy strings to line box + ui_box_equip_display_fancy_strings(line_box, &line_fancy_strings); + + // rjf: extra rendering for strings that are currently being searched for + if(params->search_query.size != 0) + { + for(U64 needle_pos = 0; needle_pos < line_string.size;) + { + needle_pos = str8_find_needle(line_string, needle_pos, params->search_query, StringMatchFlag_CaseInsensitive); + if(needle_pos < line_string.size) + { + Rng1U64 match_range = r1u64(needle_pos, needle_pos+params->search_query.size); + Rng1F32 match_column_pixel_off_range = + { + f_dim_from_tag_size_string(line_box->font, line_box->font_size, str8_prefix(line_string, match_range.min)).x, + f_dim_from_tag_size_string(line_box->font, line_box->font_size, str8_prefix(line_string, match_range.max)).x, + }; + Rng2F32 match_rect = + { + line_box->rect.x0+match_column_pixel_off_range.min, + line_box->rect.y0, + line_box->rect.x0+match_column_pixel_off_range.max+2.f, + line_box->rect.y1, + }; + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + color.w *= 0.8f; + if(cursor->line == line_num && needle_pos+1 <= cursor->column && cursor->column < needle_pos+params->search_query.size+1) + { + color.x += (1.f - color.x) * 0.5f; + color.y += (1.f - color.y) * 0.5f; + color.z += (1.f - color.z) * 0.5f; + color.w += (1.f - color.w) * 0.5f; + } + if(!is_focused) + { + color.w *= 0.5f; + } + d_rect(match_rect, color, 4.f, 0, 1.f); + needle_pos += 1; + } + } + } + + // rjf: extra rendering for list(text_range*color) + { + U64 prev_line_size = (line_idx > 0) ? params->line_text[line_idx-1].size : 0; + U64 next_line_size = (line_idx+1 < dim_1s64(params->line_num_range)) ? params->line_text[line_idx+1].size : 0; + for(TxtRngColorPairNode *n = first_txt_rng_color_pair; n != 0; n = n->next) + { + TxtRng select_range = n->rng; + TxtRng line_range = txt_rng(txt_pt(line_num, 1), txt_pt(line_num, line_string.size+1)); + TxtRng select_range_in_line = txt_rng_intersect(select_range, line_range); + if(!txt_pt_match(select_range_in_line.min, select_range_in_line.max) && + txt_pt_less_than(select_range_in_line.min, select_range_in_line.max)) + { + TxtRng prev_line_range = txt_rng(txt_pt(line_num-1, 1), txt_pt(line_num-1, prev_line_size+1)); + TxtRng next_line_range = txt_rng(txt_pt(line_num+1, 1), txt_pt(line_num+1, next_line_size+1)); + TxtRng select_range_in_prev_line = txt_rng_intersect(prev_line_range, select_range); + TxtRng select_range_in_next_line = txt_rng_intersect(next_line_range, select_range); + B32 prev_line_good = (!txt_pt_match(select_range_in_prev_line.min, select_range_in_prev_line.max) && + txt_pt_less_than(select_range_in_prev_line.min, select_range_in_prev_line.max)); + B32 next_line_good = (!txt_pt_match(select_range_in_next_line.min, select_range_in_next_line.max) && + txt_pt_less_than(select_range_in_next_line.min, select_range_in_next_line.max)); + Rng1S64 select_column_range_in_line = + { + (select_range.min.line == line_num) ? select_range.min.column : 1, + (select_range.max.line == line_num) ? select_range.max.column : (S64)(line_string.size+1), + }; + Rng1F32 select_column_pixel_off_range = + { + f_dim_from_tag_size_string(line_box->font, line_box->font_size, str8_prefix(line_string, select_column_range_in_line.min-1)).x, + f_dim_from_tag_size_string(line_box->font, line_box->font_size, str8_prefix(line_string, select_column_range_in_line.max-1)).x, + }; + Rng2F32 select_rect = + { + line_box->rect.x0+select_column_pixel_off_range.min, + floorf(line_box->rect.y0) - 1.f, + line_box->rect.x0+select_column_pixel_off_range.max+2.f, + ceilf(line_box->rect.y1) + 1.f, + }; + Vec4F32 color = n->color; + if(!is_focused) + { + color.w *= 0.5f; + } + F32 rounded_radius = params->font_size*0.4f; + R_Rect2DInst *inst = d_rect(select_rect, color, rounded_radius, 0, 1); + inst->corner_radii[Corner_00] = !prev_line_good || select_range_in_prev_line.min.column > select_range_in_line.min.column ? rounded_radius : 0.f; + inst->corner_radii[Corner_10] = (!prev_line_good || select_range_in_line.max.column > select_range_in_prev_line.max.column || select_range_in_line.max.column < select_range_in_prev_line.min.column) ? rounded_radius : 0.f; + inst->corner_radii[Corner_01] = (!next_line_good || select_range_in_next_line.min.column > select_range_in_line.min.column || select_range_in_next_line.max.column < select_range_in_line.min.column) ? rounded_radius : 0.f; + inst->corner_radii[Corner_11] = !next_line_good || select_range_in_line.max.column > select_range_in_next_line.max.column ? rounded_radius : 0.f; + } + } + } + + // rjf: extra rendering for cursor position + if(cursor->line == line_num) + { + S64 column = cursor->column; + Vec2F32 advance = f_dim_from_tag_size_string(line_box->font, line_box->font_size, str8_prefix(line_string, column-1)); + F32 cursor_off_pixels = advance.x; + F32 cursor_thickness = Max(params->font_size*0.3f, 4.f); + Rng2F32 cursor_rect = + { + ui_box_text_position(line_box).x+cursor_off_pixels, + line_box->rect.y0-params->font_size*0.55f, + ui_box_text_position(line_box).x+cursor_off_pixels+cursor_thickness, + line_box->rect.y1+params->font_size*0.55f, + }; + Vec4F32 color = is_focused ? ui_top_text_cursor_color() : df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + d_rect(cursor_rect, color, 1.f, 0, 1.f); + } + + // rjf: extra rendering for lines with line-info that match the hovered + { + B32 matches = 0; + DF_TextLineSrc2DasmInfoList *src2dasm_list = ¶ms->line_src2dasm[line_idx]; + DF_TextLineDasm2SrcInfoList *dasm2src_list = ¶ms->line_dasm2src[line_idx]; + + // rjf: check src2dasm +#if 0 + if(src2dasm_list->first != 0) + { + for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list->first; n != 0; n = n->next) + { + if(n->v.remap_line == line_num && + n->v.dbg_info == hovered_line_debug_info && + n->v.voff_range.min <= hovered_line_voff && hovered_line_voff < n->v.voff_range.max) + { + matches = 1; + break; + } + } + } +#endif + + // rjf: check dasm2src + if(dasm2src_list->first != 0) + { + DF_Entity *binary = dasm2src_list->first->v.binary; + if(binary == hovered_line_binary) + { + for(DF_TextLineDasm2SrcInfoNode *n = dasm2src_list->first; n != 0; n = n->next) + { + if(n->v.voff_range.min <= hovered_line_voff && hovered_line_voff < n->v.voff_range.max) + { + matches = 1; + break; + } + } + } + } + + // rjf: matches => highlight background + if(matches) + { + Vec4F32 highlight_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + highlight_color.w *= 0.1f; + d_rect(line_box->rect, highlight_color, 0, 0, 0); + } + } + + // rjf: equip bucket + if(line_bucket->passes.count != 0) + { + ui_box_equip_draw_bucket(line_box, line_bucket); + } + + d_pop_bucket(); + } + } + } + + scratch_end(scratch); + ProfEnd(); + return result; +} + +internal DF_CodeSliceSignal +df_code_slicef(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + DF_CodeSliceSignal sig = df_code_slice(ws, ctrl_ctx, parse_ctx, params, cursor, mark, preferred_column, string); + va_end(args); + scratch_end(scratch); + return sig; +} + +internal B32 +df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column) +{ + Temp scratch = scratch_begin(0, 0); + B32 change = 0; + UI_NavActionList *nav_actions = ui_nav_actions(); + TXTI_BufferInfo buffer_info = txti_buffer_info_from_handle(scratch.arena, handle); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + next = n->next; + B32 taken = 0; + + String8 line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line); + UI_NavTxtOp single_line_op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, line, *cursor, *mark); + + //- rjf: invalid single-line op or endpoint units => try multiline + if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint || single_line_op.flags & UI_NavTxtOpFlag_Invalid) + { + U64 line_count = buffer_info.total_line_count; + String8 prev_line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line-1); + String8 next_line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line+1); + Vec2S32 delta = n->v.delta; + + //- rjf: wrap lines right + if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count) + { + cursor->line += 1; + cursor->column = 1; + *preferred_column = 1; + change = 1; + taken = 1; + } + + //- rjf: wrap lines left + if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1) + { + cursor->line -= 1; + cursor->column = prev_line.size+1; + *preferred_column = prev_line.size+1; + change = 1; + taken = 1; + } + + //- rjf: movement down (plain) + if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y > 0 && cursor->line+1 <= line_count) + { + cursor->line += 1; + cursor->column = Min(*preferred_column, next_line.size+1); + change = 1; + taken = 1; + } + + //- rjf: movement up (plain) + if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y < 0 && cursor->line-1 >= 1) + { + cursor->line -= 1; + cursor->column = Min(*preferred_column, prev_line.size+1); + change = 1; + taken = 1; + } + + //- rjf: movement down (chunk) + if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y > 0 && cursor->line+1 <= line_count) + { + for(S64 line_num = cursor->line+1; line_num <= line_count; line_num += 1) + { + String8 line = txti_string_from_handle_line_num(scratch.arena, handle, line_num); + U64 line_size = line.size; + if(line_size == 0) + { + cursor->line = line_num; + cursor->column = 1; + break; + } + else if(line_num == line_count) + { + cursor->line = line_num; + cursor->column = line_size+1; + } + } + change = 1; + taken = 1; + } + + //- rjf: movement up (chunk) + if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y < 0 && cursor->line-1 >= 1) + { + for(S64 line_num = cursor->line-1; line_num > 0; line_num -= 1) + { + String8 line = txti_string_from_handle_line_num(scratch.arena, handle, line_num); + U64 line_size = line.size; + if(line_size == 0) + { + cursor->line = line_num; + cursor->column = 1; + break; + } + else if(line_num == 1) + { + cursor->line = line_num; + cursor->column = 1; + } + } + change = 1; + taken = 1; + } + + //- rjf: movement down (page) + if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y > 0) + { + cursor->line += line_count_per_page; + cursor->column = 1; + cursor->line = Clamp(1, cursor->line, line_count); + change = 1; + taken = 1; + } + + //- rjf: movement up (page) + if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y < 0) + { + cursor->line -= line_count_per_page; + cursor->column = 1; + cursor->line = Clamp(1, cursor->line, line_count); + change = 1; + taken = 1; + } + + //- rjf: movement to endpoint (+) + if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y > 0 || delta.x > 0)) + { + *cursor = txt_pt(line_count, buffer_info.last_line_size); + change = 1; + taken = 1; + } + + //- rjf: movement to endpoint (-) + if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y < 0 || delta.x < 0)) + { + *cursor = txt_pt(1, 1); + change = 1; + taken = 1; + } + + //- rjf: stick mark to cursor, when we don't want to keep it in the same spot + if(!(n->v.flags & UI_NavActionFlag_KeepMark)) + { + *mark = *cursor; + } + } + + //- rjf: valid single-line op => do single-line op + else + { + *cursor = single_line_op.cursor; + *mark = single_line_op.mark; + *preferred_column = cursor->column; + change = 1; + taken = 1; + } + + //- rjf: copy + if(n->v.flags & UI_NavActionFlag_Copy) + { + String8 text = txti_string_from_handle_txt_rng(scratch.arena, handle, txt_rng(*cursor, *mark)); + os_set_clipboard_text(text); + } + + //- rjf: consume + if(taken) + { + ui_nav_eat_action_node(nav_actions, n); + } + } + + scratch_end(scratch); + return change; +} + +internal B32 +df_do_dasm_controls(DASM_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column) +{ + Temp scratch = scratch_begin(0, 0); + B32 change = 0; + UI_NavActionList *nav_actions = ui_nav_actions(); + scratch_end(scratch); + return change; +} + +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Labels + +internal UI_Signal +df_error_label(String8 string) +{ + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###%S_error_label", string); + UI_Signal sig = ui_signal_from_box(box); + UI_Parent(box) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) + { + ui_set_next_font(ui_icon_font()); + ui_set_next_text_alignment(UI_TextAlign_Center); + UI_PrefWidth(ui_em(2.25f, 1.f)) ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); + ui_label(string); + } + return sig; +} + +internal B32 +df_help_label(String8 string) +{ + B32 result = 0; + UI_Box *box = ui_build_box_from_stringf(0, "###%S_help_label", string); + UI_Key help_hoverer_key = ui_key_from_stringf(box->key, "###help_hoverer"); + B32 box_is_hot = ((ui_key_match(ui_active_key(Side_Min), ui_key_zero()) || ui_key_match(ui_active_key(Side_Min), help_hoverer_key)) && + (ui_key_match(ui_active_key(Side_Max), ui_key_zero()) || ui_key_match(ui_active_key(Side_Min), help_hoverer_key)) && + contains_2f32(box->rect, ui_mouse())); + UI_Parent(box) + { + UI_PrefWidth(ui_pct(1, 0)) ui_label(string); + if(box_is_hot) UI_PrefWidth(ui_em(2.25f, 1)) + { + ui_set_next_font(ui_icon_font()); + ui_set_next_text_alignment(UI_TextAlign_Center); + UI_Box *help_hoverer = ui_build_box_from_key(UI_BoxFlag_DrawText|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_Clickable, help_hoverer_key); + ui_box_equip_display_string(help_hoverer, df_g_icon_kind_text_table[DF_IconKind_QuestionMark]); + UI_Signal sig = ui_signal_from_box(help_hoverer); + result = sig.hovering; + } + } + return result; +} + +internal D_FancyStringList +df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + D_FancyStringList fancy_strings = {0}; + TXTI_TokenArray tokens = txti_token_array_from_string__cpp(scratch.arena, 0, string); + TXTI_Token *tokens_opl = tokens.v+tokens.count; + S32 indirection_counter = 0; + for(TXTI_Token *token = tokens.v; token < tokens_opl; token += 1) + { + DF_ThemeColor token_color = df_theme_color_from_txti_token_kind(token->kind); + Vec4F32 token_color_rgba = df_rgba_from_theme_color(token_color); + token_color_rgba.w *= alpha; + String8 token_string = str8_substr(string, token->range); + if(str8_match(token_string, str8_lit("{"), 0)) { indirection_counter += 1; } + if(str8_match(token_string, str8_lit("["), 0)) { indirection_counter += 1; } + indirection_counter = ClampBot(0, indirection_counter); + switch(token->kind) + { + default: + { + D_FancyString fancy_string = + { + ui_top_font(), + token_string, + token_color_rgba, + ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)), + }; + d_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + }break; + case TXTI_TokenKind_Numeric: + { + Vec4F32 token_color_rgba_alt = token_color_rgba; + token_color_rgba_alt.x *= 0.7f; + token_color_rgba_alt.y *= 0.7f; + token_color_rgba_alt.z *= 0.7f; + F32 font_size = ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)); + + // rjf: unpack string + U32 base = 10; + U64 prefix_skip = 0; + U64 digit_group_size = 3; + if(str8_match(str8_prefix(token_string, 2), str8_lit("0x"), StringMatchFlag_CaseInsensitive)) + { + base = 16; + prefix_skip = 2; + digit_group_size = 4; + } + else if(str8_match(str8_prefix(token_string, 2), str8_lit("0b"), StringMatchFlag_CaseInsensitive)) + { + base = 2; + prefix_skip = 2; + digit_group_size = 8; + } + else if(str8_match(str8_prefix(token_string, 2), str8_lit("0o"), StringMatchFlag_CaseInsensitive)) + { + base = 8; + prefix_skip = 2; + digit_group_size = 2; + } + + // rjf: grab string parts + U64 dot_pos = str8_find_needle(token_string, 0, str8_lit("."), 0); + String8 prefix = str8_prefix(token_string, prefix_skip); + String8 whole = str8_substr(token_string, r1u64(prefix_skip, dot_pos)); + String8 decimal = str8_skip(token_string, dot_pos); + + // rjf: determine # of digits + U64 num_digits = 0; + for(U64 idx = 0; idx < whole.size; idx += 1) + { + num_digits += char_is_digit(whole.str[idx], base); + } + + // rjf: push prefix + { + D_FancyString fancy_string = + { + ui_top_font(), + prefix, + token_color_rgba, + font_size, + }; + d_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + } + + // rjf: push digit groups + { + B32 odd = 0; + U64 start_idx = 0; + U64 num_digits_passed = digit_group_size - num_digits%digit_group_size; + for(U64 idx = 0; idx <= whole.size; idx += 1) + { + U8 byte = idx < whole.size ? whole.str[idx] : 0; + if(num_digits_passed >= digit_group_size || idx == whole.size) + { + num_digits_passed = 0; + if(start_idx < idx) + { + D_FancyString fancy_string = + { + ui_top_font(), + str8_substr(whole, r1u64(start_idx, idx)), + odd ? token_color_rgba_alt : token_color_rgba, + font_size, + }; + d_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + start_idx = idx; + odd ^= 1; + } + } + if(char_is_digit(byte, base)) + { + num_digits_passed += 1; + } + } + } + + // rjf: push decimal + { + D_FancyString fancy_string = + { + ui_top_font(), + decimal, + token_color_rgba, + font_size, + }; + d_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + } + + }break; + } + if(str8_match(token_string, str8_lit("}"), 0)) { indirection_counter -= 1; } + if(str8_match(token_string, str8_lit("]"), 0)) { indirection_counter -= 1; } + indirection_counter = ClampBot(0, indirection_counter); + } + scratch_end(scratch); + return fancy_strings; +} + +internal void +df_code_label(F32 alpha, B32 indirection_size_change, String8 string) +{ + Temp scratch = scratch_begin(0, 0); + D_FancyStringList fancy_strings = df_fancy_string_list_from_code_string(scratch.arena, alpha, indirection_size_change, string); + UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fancy_strings(box, &fancy_strings); + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: UI Widgets: Line Edit + +internal UI_Signal +df_line_edit(DF_LineEditFlags flags, S32 depth, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, String8 string) +{ + //- rjf: unpack visual metrics + F32 expander_size_px = ui_top_font_size()*1.3f; + + //- rjf: get key & disect focus kind + UI_Key key = ui_key_from_string(ui_active_seed_key(), string); + B32 is_auto_focus_hot = ui_is_key_auto_focus_hot(key); + B32 is_auto_focus_active = ui_is_key_auto_focus_active(key); + if(is_auto_focus_hot) { ui_set_focus_hot(1); } + if(is_auto_focus_active) { ui_set_focus_active(1); } + B32 is_focus_hot = ui_is_focus_hot(); + B32 is_focus_active = ui_is_focus_active(); + + //- rjf: build top-level box + if(is_focus_active) + { + ui_set_next_hover_cursor(OS_Cursor_IBar); + } + UI_Box *box = ui_build_box_from_key(UI_BoxFlag_MouseClickable| + UI_BoxFlag_ClickToFocus| + UI_BoxFlag_DrawHotEffects| + (!(flags & DF_LineEditFlag_NoBackground)*UI_BoxFlag_DrawBackground)| + (!!(flags & DF_LineEditFlag_Border)*UI_BoxFlag_DrawBorder)| + ((is_auto_focus_hot || is_auto_focus_active)*UI_BoxFlag_KeyboardClickable)| + is_focus_active*(UI_BoxFlag_Clip), + key); + + //- rjf: build indent + if(depth != 0) UI_Parent(box) + { + ui_spacer(ui_em(1.5f*depth, 1.f)); + } + + //- rjf: build expander + if(flags & DF_LineEditFlag_Expander) UI_PrefWidth(ui_px(expander_size_px, 1.f)) UI_Parent(box) + UI_Flags(UI_BoxFlag_DrawSideLeft) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + UI_Signal expander_sig = ui_expanderf(*expanded_out, "expander"); + if(expander_sig.pressed) + { + *expanded_out ^= 1; + } + } + + //- rjf: build expander placeholder + else if(flags & DF_LineEditFlag_ExpanderPlaceholder) UI_Parent(box) UI_PrefWidth(ui_px(expander_size_px, 1.f)) + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Flags(UI_BoxFlag_DrawSideLeft) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(ui_icon_font()) + ui_label(df_g_icon_kind_text_table[DF_IconKind_Dot]); + } + + //- rjf: build expander space + else if(flags & DF_LineEditFlag_ExpanderSpace) UI_Parent(box) + { + UI_Flags(UI_BoxFlag_DrawSideLeft) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_spacer(ui_px(expander_size_px, 1.f)); + } + + //- rjf: build scrollable container box + UI_Box *scrollable_box = &ui_g_nil_box; + UI_Parent(box) UI_PrefWidth(ui_children_sum(0)) + { + scrollable_box = ui_build_box_from_stringf(is_focus_active*(UI_BoxFlag_AllowOverflowX), "scroll_box_%p", edit_buffer); + } + + //- rjf: do non-textual edits (delete, copy, cut) + B32 commit = 0; + if(!is_focus_active && is_focus_hot) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + next = n->next; + UI_NavAction *action = &n->v; + if(action->flags & UI_NavActionFlag_Copy) + { + os_set_clipboard_text(pre_edit_value); + } + if(action->flags & UI_NavActionFlag_Delete) + { + commit = 1; + edit_string_size_out[0] = 0; + } + } + } + + //- rjf: get signal + UI_Signal sig = ui_signal_from_box(box); + sig.commit = sig.commit || commit; + + //- rjf: do start/end editing interaction + B32 focus_started = 0; + if(!is_focus_active) + { + B32 start_editing_via_sig = (sig.double_clicked || sig.keyboard_clicked); + B32 start_editing_via_typing = 0; + if(is_focus_hot) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + { + if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + { + start_editing_via_typing = 1; + break; + } + } + } + if(is_focus_hot && os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + { + start_editing_via_typing = 1; + } + if(start_editing_via_sig || start_editing_via_typing) + { + String8 edit_string = pre_edit_value; + edit_string.size = Min(edit_buffer_size, pre_edit_value.size); + MemoryCopy(edit_buffer, edit_string.str, edit_string.size); + edit_string_size_out[0] = edit_string.size; + ui_set_auto_focus_active_key(key); + ui_kill_action(); + *cursor = txt_pt(1, edit_string.size+1); + *mark = txt_pt(1, 1); + focus_started = 1; + } + } + else if(is_focus_active && sig.keyboard_clicked) + { + ui_set_auto_focus_active_key(ui_key_zero()); + sig.commit = 1; + } + + //- rjf: take navigation actions for editing + B32 changes_made = 0; + if(is_focus_active || focus_started) + { + Temp scratch = scratch_begin(0, 0); + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); + next = n->next; + + // rjf: do not consume anything that doesn't fit a single-line's operations + if(n->v.delta.y != 0) + { + continue; + } + + // rjf: map this action to an op + UI_NavTxtOp op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, edit_string, *cursor, *mark); + + // rjf: perform replace range + if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) + { + String8 new_string = ui_nav_push_string_replace_range(scratch.arena, edit_string, r1s64(op.range.min.column, op.range.max.column), op.replace); + new_string.size = Min(edit_buffer_size, new_string.size); + MemoryCopy(edit_buffer, new_string.str, new_string.size); + edit_string_size_out[0] = new_string.size; + } + + // rjf: perform copy + if(op.flags & UI_NavTxtOpFlag_Copy) + { + os_set_clipboard_text(op.copy); + } + + // rjf: commit op's changed cursor & mark to caller-provided state + *cursor = op.cursor; + *mark = op.mark; + + // rjf: consume event + { + ui_nav_eat_action_node(nav_actions, n); + changes_made = 1; + } + } + scratch_end(scratch); + } + + //- rjf: build scrolled contents + TxtPt mouse_pt = {0}; + F32 cursor_off = 0; + UI_Parent(scrollable_box) + { + if(!is_focus_active && flags & DF_LineEditFlag_CodeContents) + { + String8 display_string = ui_display_part_from_key_string(string); + if(!(flags & DF_LineEditFlag_PreferDisplayString) && pre_edit_value.size != 0) + { + display_string = pre_edit_value; + df_code_label(1.f, 1, display_string); + } + else if(flags & DF_LineEditFlag_DisplayStringIsCode) + { + df_code_label(1.f, 1, display_string); + } + else + { + ui_set_next_text_color(df_rgba_from_theme_color(DF_ThemeColor_WeakText)); + ui_label(display_string); + } + } + else if(!is_focus_active && !(flags & DF_LineEditFlag_CodeContents)) + { + String8 display_string = ui_display_part_from_key_string(string); + if(!(flags & DF_LineEditFlag_PreferDisplayString) && pre_edit_value.size != 0) + { + display_string = pre_edit_value; + } + else + { + ui_set_next_text_color(df_rgba_from_theme_color(DF_ThemeColor_WeakText)); + } + ui_label(display_string); + } + else if(is_focus_active && flags & DF_LineEditFlag_CodeContents) + { + String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); + Temp scratch = scratch_begin(0, 0); + F32 total_text_width = f_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), edit_string).x; + F32 total_editstr_width = total_text_width - !!(flags & (DF_LineEditFlag_Expander|DF_LineEditFlag_ExpanderSpace|DF_LineEditFlag_ExpanderPlaceholder)) * expander_size_px; + ui_set_next_pref_width(ui_px(total_editstr_width+ui_top_font_size()*2, 0.f)); + UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); + D_FancyStringList code_fancy_strings = df_fancy_string_list_from_code_string(scratch.arena, 1.f, 0, edit_string); + ui_box_equip_display_fancy_strings(editstr_box, &code_fancy_strings); + UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); + draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); + draw_data->cursor = *cursor; + draw_data->mark = *mark; + draw_data->cursor_color = ui_top_text_cursor_color(); + draw_data->select_color = ui_top_text_select_color(); + ui_box_equip_custom_draw(editstr_box, ui_line_edit_draw, draw_data); + mouse_pt = txt_pt(1, 1+ui_box_char_pos_from_xy(editstr_box, ui_mouse())); + cursor_off = f_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), str8_prefix(edit_string, cursor->column-1)).x; + scratch_end(scratch); + } + else if(is_focus_active && !(flags & DF_LineEditFlag_CodeContents)) + { + String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); + F32 total_text_width = f_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), edit_string).x; + F32 total_editstr_width = total_text_width - !!(flags & (DF_LineEditFlag_Expander|DF_LineEditFlag_ExpanderSpace|DF_LineEditFlag_ExpanderPlaceholder)) * expander_size_px; + ui_set_next_pref_width(ui_px(total_editstr_width+ui_top_font_size()*2, 0.f)); + UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); + UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); + draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); + draw_data->cursor = *cursor; + draw_data->mark = *mark; + draw_data->cursor_color = ui_top_text_cursor_color(); + draw_data->select_color = ui_top_text_select_color(); + ui_box_equip_display_string(editstr_box, edit_string); + ui_box_equip_custom_draw(editstr_box, ui_line_edit_draw, draw_data); + mouse_pt = txt_pt(1, 1+ui_box_char_pos_from_xy(editstr_box, ui_mouse())); + cursor_off = f_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), str8_prefix(edit_string, cursor->column-1)).x; + } + } + + //- rjf: click+drag + if(is_focus_active && sig.dragging) + { + if(sig.pressed) + { + *mark = mouse_pt; + } + *cursor = mouse_pt; + } + + //- rjf: focus cursor + { + F32 visible_dim_px = dim_2f32(box->rect).x; + if(visible_dim_px != 0) + { + Rng1F32 cursor_range_px = r1f32(cursor_off-ui_top_font_size()*2.f, cursor_off+ui_top_font_size()*2.f); + Rng1F32 visible_range_px = r1f32(scrollable_box->view_off_target.x, scrollable_box->view_off_target.x + visible_dim_px); + cursor_range_px.min = ClampBot(0, cursor_range_px.min); + cursor_range_px.max = ClampBot(0, cursor_range_px.max); + F32 min_delta = cursor_range_px.min-visible_range_px.min; + F32 max_delta = cursor_range_px.max-visible_range_px.max; + min_delta = Min(min_delta, 0); + max_delta = Max(max_delta, 0); + scrollable_box->view_off_target.x += min_delta; + scrollable_box->view_off_target.x += max_delta; + } + if(!is_focus_active) + { + scrollable_box->view_off_target.x = scrollable_box->view_off.x = 0; + } + } + + return sig; +} + +internal UI_Signal +df_line_editf(DF_LineEditFlags flags, S32 depth, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = df_line_edit(flags, depth, cursor, mark, edit_buffer, edit_buffer_size, edit_string_size_out, expanded_out, pre_edit_value, string); + scratch_end(scratch); + return sig; +} + +//////////////////////////////// +//~ rjf: Continuous Frame Requests + +internal void +df_gfx_request_frame(void) +{ + df_gfx_state->num_frames_requested = 4; +} + +//////////////////////////////// +//~ rjf: Main Layer Top-Level Calls + +internal void +df_gfx_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, DF_StateDeltaHistory *hist) +{ + ProfBeginFunction(); + Arena *arena = arena_alloc(); + df_gfx_state = push_array(arena, DF_GfxState, 1); + df_gfx_state->arena = arena; + df_gfx_state->frame_arena = arena_alloc(); + df_gfx_state->num_frames_requested = 2; + df_gfx_state->hist = hist; + df_gfx_state->key_map_arena = arena_alloc(); + df_gfx_state->view_spec_table_size = 256; + df_gfx_state->view_spec_table = push_array(arena, DF_ViewSpec *, df_gfx_state->view_spec_table_size); + df_gfx_state->view_rule_spec_table_size = 1024; + df_gfx_state->view_rule_spec_table = push_array(arena, DF_GfxViewRuleSpec *, df_state->view_rule_spec_table_size); + df_gfx_state->view_rule_block_slots_count = 1024; + df_gfx_state->view_rule_block_slots = push_array(arena, DF_ViewRuleBlockSlot, df_gfx_state->view_rule_block_slots_count); + df_gfx_state->cmd2view_slot_count = 256; + df_gfx_state->cmd2view_slots = push_array(arena, DF_String2ViewSlot, df_gfx_state->cmd2view_slot_count); + df_gfx_state->string_search_arena = arena_alloc(); + df_gfx_state->repaint_hook = window_repaint_entry_point; + df_clear_bindings(); + + // rjf: register gfx layer views + { + DF_ViewSpecInfoArray array = {df_g_gfx_view_kind_spec_info_table, ArrayCount(df_g_gfx_view_kind_spec_info_table)}; + df_register_view_specs(array); + } + + // rjf: register gfx layer view rules + { + DF_GfxViewRuleSpecInfoArray array = {df_g_gfx_view_rule_spec_info_table, ArrayCount(df_g_gfx_view_rule_spec_info_table)}; + df_register_gfx_view_rule_specs(array); + } + + // rjf: register cmd -> views + { + for(U64 idx = 0; idx < ArrayCount(df_g_cmd2view_table_src); idx += 1) + { + df_register_cmd2view(df_g_cmd2view_table_src[idx], df_g_cmd2view_table_dst[idx]); + } + } + + // rjf: set up background text searching thread + { + df_gfx_state->tsrch_slot_count = 64; + df_gfx_state->tsrch_stripe_count = df_gfx_state->tsrch_slot_count/8; + df_gfx_state->tsrch_slots = push_array(df_gfx_state->arena, DF_TextSearchCacheSlot, df_gfx_state->tsrch_slot_count); + df_gfx_state->tsrch_stripe_rw_mutexes = push_array(df_gfx_state->arena, OS_Handle, df_gfx_state->tsrch_stripe_count); + for(U64 stripe_idx = 0; stripe_idx < df_gfx_state->tsrch_stripe_count; stripe_idx += 1) + { + df_gfx_state->tsrch_stripe_rw_mutexes[stripe_idx] = os_rw_mutex_alloc(); + } + df_gfx_state->tsrch_wakeup_mutex = os_mutex_alloc(); + df_gfx_state->tsrch_wakeup_cv = os_condition_variable_alloc(); + //df_gfx_state->tsrch_thread = os_launch_thread(df_text_search_thread_entry_point, 0, 0); + } + ProfEnd(); +} + +internal void +df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds) +{ + ProfBeginFunction(); + arena_clear(df_gfx_state->frame_arena); + df_gfx_state->hover_line_set_this_frame = 0; + + //- rjf: capture is active? -> keep rendering + if(ProfIsCapturing()) + { + df_gfx_request_frame(); + } + + //- rjf: process top-level graphical commands + { + B32 cfg_write_done[DF_CfgSrc_COUNT] = {0}; + Temp scratch = scratch_begin(&arena, 1); + for(DF_CmdNode *cmd_node = cmds->first; + cmd_node != 0; + cmd_node = cmd_node->next) + { + temp_end(scratch); + + // rjf: unpack command + DF_Cmd *cmd = &cmd_node->cmd; + DF_CmdParams params = cmd->params; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: request frame + df_gfx_request_frame(); + + // rjf: process command + DF_CfgSrc cfg_src = (DF_CfgSrc)0; + switch(core_cmd_kind) + { + default:{}break; + + //- rjf: exiting + case DF_CoreCmdKind_Exit: + { + // rjf: save + { + DF_CmdParams params = df_cmd_params_zero(); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WriteUserData)); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WriteProfileData)); + df_gfx_state->last_window_queued_save = 1; + } + + // rjf: close all windows + for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) + { + DF_CmdParams params = df_cmd_params_from_window(window); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow)); + } + }break; + + //- rjf: windows + case DF_CoreCmdKind_OpenWindow: + { + OS_Handle preferred_monitor = {0}; + df_window_open(v2f32(1280, 720), preferred_monitor, DF_CfgSrc_User); + }break; + case DF_CoreCmdKind_CloseWindow: + { + DF_Window *ws = df_window_from_handle(params.window); + if(ws != 0) + { + // NOTE(rjf): if this is the last window, and it is being closed, then + // we need to auto-save, and provide one last chance to process saving + // commands. after doing so, we can retry. + if(ws == df_gfx_state->first_window && ws == df_gfx_state->last_window && df_gfx_state->last_window_queued_save == 0) + { + df_gfx_state->last_window_queued_save = 1; + { + DF_CmdParams params = df_cmd_params_zero(); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WriteUserData)); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_WriteProfileData)); + } + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow)); + } + + // NOTE(rjf): if this is the last window and we've queued the final autosave, + // or if it's not the last window, then we're free to release everything. + else + { + // NOTE(rjf): we need to explicitly release all panel views, because views + // are a global concept and otherwise would leak. + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + df_panel_release_all_views(panel); + } + + df_state_delta_history_release(ws->view_state_hist); + ui_state_release(ws->ui); + DLLRemove(df_gfx_state->first_window, df_gfx_state->last_window, ws); + r_window_unequip(ws->os, ws->r); + os_window_close(ws->os); + arena_release(ws->hover_eval_arena); + arena_release(ws->arena); + SLLStackPush(df_gfx_state->free_window, ws); + } + } + }break; + case DF_CoreCmdKind_ToggleFullscreen: + { + DF_Window *window = df_window_from_handle(params.window); + if(window != 0) + { + os_window_set_fullscreen(window->os, !os_window_is_fullscreen(window->os)); + } + }break; + + //- rjf: commands with implications for graphical systems, but generated + // without context needed - pick selected window & dispatch + case DF_CoreCmdKind_SelectThread: + case DF_CoreCmdKind_SelectThreadView: + case DF_CoreCmdKind_SelectThreadWindow: + case DF_CoreCmdKind_FindThread: + { + DF_Window *window = df_window_from_handle(params.window); + if(window == 0) + { + window = df_gfx_state->first_window; + for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) + { + if(os_window_is_focused(w->os)) + { + window = w; + } + } + if(window != 0) + { + os_window_bring_to_front(window->os); + os_window_focus(window->os); + DF_CmdParams p = params; + p.window = df_handle_from_window(window); + p.panel = df_handle_from_panel(window->focused_panel); + p.view = df_handle_from_view(window->focused_panel->selected_stable_view); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Window); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Panel); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_View); + df_cmd_list_push(arena, cmds, &p, cmd->spec); + } + } + }break; + + //- rjf: loading/applying stateful config changes + case DF_CoreCmdKind_ApplyUserData: + case DF_CoreCmdKind_ApplyProfileData: + { + DF_CfgTable *table = df_cfg_table(); + OS_HandleArray monitors = os_push_monitors_array(scratch.arena); + + //- rjf: get src + DF_CfgSrc src = DF_CfgSrc_User; + for(DF_CfgSrc s = (DF_CfgSrc)0; s < DF_CfgSrc_COUNT; s = (DF_CfgSrc)(s+1)) + { + if(core_cmd_kind == df_g_cfg_src_apply_cmd_kind_table[s]) + { + src = s; + break; + } + } + + //- rjf: get paths + String8 cfg_path = df_cfg_path_from_src(src); + String8 cfg_folder = str8_chop_last_slash(cfg_path); + + //- rjf: eliminate all windows + for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) + { + if(window->cfg_src != src) + { + continue; + } + DF_CmdParams params = df_cmd_params_from_window(window); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow)); + } + + //- rjf: apply fonts + { + F_Tag defaults[DF_FontSlot_COUNT] = + { + f_tag_from_static_data_string(&df_g_default_main_font_bytes), + f_tag_from_static_data_string(&df_g_default_code_font_bytes), + f_tag_from_static_data_string(&df_g_icon_font_bytes), + }; + for(DF_FontSlot slot = (DF_FontSlot)0; slot < DF_FontSlot_COUNT; slot = (DF_FontSlot)(slot+1)) + { + if(f_tag_match(f_tag_zero(), df_gfx_state->cfg_font_tags[slot])) + { + df_gfx_state->cfg_font_tags[slot] = defaults[slot]; + } + } + { + DF_CfgVal *code_font_val = df_cfg_val_from_string(table, str8_lit("code_font")); + DF_CfgVal *main_font_val = df_cfg_val_from_string(table, str8_lit("main_font")); + DF_CfgNode *code_font_cfg = code_font_val->last; + DF_CfgNode *main_font_cfg = main_font_val->last; + String8 code_font_relative_path = code_font_cfg->first->string; + String8 main_font_relative_path = main_font_cfg->first->string; + String8 code_font_path = path_absolute_dst_from_relative_dst_src(scratch.arena, code_font_relative_path, cfg_folder); + String8 main_font_path = path_absolute_dst_from_relative_dst_src(scratch.arena, main_font_relative_path, cfg_folder); + if(code_font_cfg != &df_g_nil_cfg_node && code_font_relative_path.size != 0) + { + df_gfx_state->cfg_font_tags[DF_FontSlot_Code] = f_tag_from_path(code_font_path); + } + if(main_font_cfg != &df_g_nil_cfg_node && main_font_relative_path.size != 0) + { + df_gfx_state->cfg_font_tags[DF_FontSlot_Main] = f_tag_from_path(main_font_path); + } + } + } + + //- rjf: build windows & panel layouts + DF_CfgVal *windows = df_cfg_val_from_string(table, str8_lit("window")); + for(DF_CfgNode *window_node = windows->first; + window_node != &df_g_nil_cfg_node; + window_node = window_node->next) + { + // rjf: skip wrong source + if(window_node->source != src) + { + continue; + } + + // rjf: grab metadata + B32 is_fullscreen = 0; + B32 is_maximized = 0; + Axis2 top_level_split_axis = Axis2_X; + OS_Handle preferred_monitor = os_primary_monitor(); + Vec2F32 size = {0}; + F32 code_font_size_delta = 0.f; + F32 main_font_size_delta = 0.f; + { + for(DF_CfgNode *n = window_node->first; n != &df_g_nil_cfg_node; n = n->next) + { + if(n->flags & DF_CfgNodeFlag_Identifier && + n->first == &df_g_nil_cfg_node && + str8_match(n->string, str8_lit("split_x"), StringMatchFlag_CaseInsensitive)) + { + top_level_split_axis = Axis2_X; + } + if(n->flags & DF_CfgNodeFlag_Identifier && + n->first == &df_g_nil_cfg_node && + str8_match(n->string, str8_lit("split_y"), StringMatchFlag_CaseInsensitive)) + { + top_level_split_axis = Axis2_Y; + } + if(n->flags & DF_CfgNodeFlag_Identifier && + n->first == &df_g_nil_cfg_node && + str8_match(n->string, str8_lit("fullscreen"), StringMatchFlag_CaseInsensitive)) + { + is_fullscreen = 1; + } + if(n->flags & DF_CfgNodeFlag_Identifier && + n->first == &df_g_nil_cfg_node && + str8_match(n->string, str8_lit("maximized"), StringMatchFlag_CaseInsensitive)) + { + is_maximized = 1; + } + } + DF_CfgNode *monitor_cfg = df_cfg_node_child_from_string(window_node, str8_lit("monitor"), StringMatchFlag_CaseInsensitive); + String8 preferred_monitor_name = monitor_cfg->first->string; + for(U64 idx = 0; idx < monitors.count; idx += 1) + { + String8 monitor_name = os_name_from_monitor(scratch.arena, monitors.v[idx]); + if(str8_match(monitor_name, preferred_monitor_name, StringMatchFlag_CaseInsensitive)) + { + preferred_monitor = monitors.v[idx]; + break; + } + } + Vec2F32 preferred_monitor_size = os_dim_from_monitor(preferred_monitor); + DF_CfgNode *size_cfg = df_cfg_node_child_from_string(window_node, str8_lit("size"), StringMatchFlag_CaseInsensitive); + { + String8 x_string = size_cfg->first->string; + String8 y_string = size_cfg->first->next->string; + U64 x_u64 = 0; + U64 y_u64 = 0; + if(!try_u64_from_str8_c_rules(x_string, &x_u64)) + { + x_u64 = (U64)(preferred_monitor_size.x*2/3); + } + if(!try_u64_from_str8_c_rules(y_string, &y_u64)) + { + y_u64 = (U64)(preferred_monitor_size.y*2/3); + } + size.x = (F32)x_u64; + size.y = (F32)y_u64; + } + DF_CfgNode *code_font_size_delta_cfg = df_cfg_node_child_from_string(window_node, str8_lit("code_font_size_delta"), StringMatchFlag_CaseInsensitive); + DF_CfgNode *main_font_size_delta_cfg = df_cfg_node_child_from_string(window_node, str8_lit("main_font_size_delta"), StringMatchFlag_CaseInsensitive); + String8 code_font_size_delta_cfg_string = df_string_from_cfg_node_children(scratch.arena, code_font_size_delta_cfg); + String8 main_font_size_delta_cfg_string = df_string_from_cfg_node_children(scratch.arena, main_font_size_delta_cfg); + code_font_size_delta = (F32)f64_from_str8(code_font_size_delta_cfg_string); + main_font_size_delta = (F32)f64_from_str8(main_font_size_delta_cfg_string); + } + + // rjf: open window + DF_Window *ws = df_window_open(size, preferred_monitor, window_node->source); + ws->code_font_size_delta = code_font_size_delta; + ws->main_font_size_delta = main_font_size_delta; + + // rjf: build panel tree + DF_CfgNode *cfg_panels = df_cfg_node_child_from_string(window_node, str8_lit("panels"), StringMatchFlag_CaseInsensitive); + DF_Panel *panel_parent = ws->root_panel; + panel_parent->split_axis = top_level_split_axis; + DF_CfgNodeRec rec = {0}; + for(DF_CfgNode *n = cfg_panels, *next = &df_g_nil_cfg_node; + n != &df_g_nil_cfg_node; + n = next) + { + // rjf: assume we're just moving to the next one initially... + next = n->next; + + // rjf: grab root panel + DF_Panel *panel = &df_g_nil_panel; + if(n == cfg_panels) + { + panel = ws->root_panel; + panel->size_pct_of_parent.v[panel_parent->split_axis] = panel->size_pct_of_parent_target.v[panel_parent->split_axis] = 1.f; + panel->size_pct_of_parent.v[axis2_flip(panel_parent->split_axis)] = panel->size_pct_of_parent_target.v[axis2_flip(panel_parent->split_axis)] = 1.f; + } + + // rjf: allocate & insert non-root panels - these will have a numeric string, determining + // pct of parent + if(n->flags & DF_CfgNodeFlag_Numeric) + { + panel = df_panel_alloc(ws); + df_panel_insert(panel_parent, panel_parent->last, panel); + panel->split_axis = axis2_flip(panel_parent->split_axis); + panel->size_pct_of_parent.v[panel_parent->split_axis] = panel->size_pct_of_parent_target.v[panel_parent->split_axis] = (F32)f64_from_str8(n->string); + panel->size_pct_of_parent.v[axis2_flip(panel_parent->split_axis)] = panel->size_pct_of_parent_target.v[axis2_flip(panel_parent->split_axis)] = 1.f; + } + + // rjf: do general per-panel work + if(!df_panel_is_nil(panel)) + { + // rjf: determine if this panel has panel children + B32 has_panel_children = 0; + for(DF_CfgNode *child = n->first; child != &df_g_nil_cfg_node; child = child->next) + { + if(child->flags & DF_CfgNodeFlag_Numeric) + { + has_panel_children = 1; + break; + } + } + + // rjf: apply panel options + for(DF_CfgNode *op = n->first; op != &df_g_nil_cfg_node; op = op->next) + { + if(op->first == &df_g_nil_cfg_node && str8_match(op->string, str8_lit("tabs_on_bottom"), StringMatchFlag_CaseInsensitive)) + { + panel->tab_side = Side_Max; + } + if(op->first == &df_g_nil_cfg_node && str8_match(op->string, str8_lit("disable_tab_bar"), StringMatchFlag_CaseInsensitive)) + { + panel->hide_tab_bar = 1; + panel->history_tab_bar_mode = 1; + } + if(op->first == &df_g_nil_cfg_node && str8_match(op->string, str8_lit("history_mode"), StringMatchFlag_CaseInsensitive)) + { + panel->history_tab_bar_mode = 1; + } + } + + // rjf: apply panel views/tabs/commands + DF_View *selected_view = &df_g_nil_view; + for(DF_CfgNode *op = n->first; op != &df_g_nil_cfg_node; op = op->next) + { + DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(op->string); + DF_ViewSpec *view_spec = df_view_spec_from_cmd_spec(cmd_spec); + if(view_spec == &df_g_nil_view_spec || has_panel_children != 0) + { + continue; + } + + // rjf: allocate view & apply view-specific parameterizations + DF_View *view = &df_g_nil_view; + B32 view_is_selected = 0; + DF_ViewSpecFlags view_spec_flags = view_spec->info.flags; + if(view_spec_flags & DF_ViewSpecFlag_CanSerialize) + { + // rjf: allocate view + B32 view_has_cmd_setup = 0; + view = df_view_alloc(); + + // rjf: check if this view is selected + view_is_selected = df_cfg_node_child_from_string(op, str8_lit("selected"), StringMatchFlag_CaseInsensitive) != &df_g_nil_cfg_node; + + // rjf: read entity path + if(view_spec_flags & DF_ViewSpecFlag_CanSerializeEntityPath) + { + String8 saved_path = df_first_cfg_node_child_from_flags(op, DF_CfgNodeFlag_StringLiteral)->string; + String8 saved_path_absolute = path_absolute_dst_from_relative_dst_src(scratch.arena, saved_path, cfg_folder); + DF_Entity *file = df_entity_from_path(saved_path_absolute, DF_EntityFromPathFlag_All); + if(!df_entity_is_nil(file)) + { + DF_CmdParams p = df_cmd_params_zero(); + p.entity = df_handle_from_entity(file); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_view_equip_command(view, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity), &p, str8_lit(""), op); + view_has_cmd_setup = 1; + } + } + + // rjf: default view setup + if(view_has_cmd_setup == 0) + { + DF_CmdParams p = df_cmd_params_zero(); + df_view_equip_command(view, cmd_spec, &p, str8_lit(""), op); + } + } + + // rjf: insert + if(!df_view_is_nil(view)) + { + df_panel_insert_stable_view(panel, panel->last_stable_view, view); + if(view_is_selected) + { + selected_view = view; + } + } + } + + // rjf: select selected view + if(!df_view_is_nil(selected_view)) + { + panel->selected_stable_view = selected_view; + } + + // rjf: recurse from this panel + if(has_panel_children) + { + next = n->first; + panel_parent = panel; + } + else for(DF_CfgNode *p = n; + p != &df_g_nil_cfg_node && p != cfg_panels; + p = p->parent, panel_parent = panel_parent->parent) + { + if(p->next != &df_g_nil_cfg_node) + { + next = p->next; + break; + } + } + } + } + + // rjf: initiate fullscreen + if(is_fullscreen) + { + os_window_set_fullscreen(ws->os, 1); + } + + // rjf: initiate maximize + if(is_maximized) + { + os_window_set_maximized(ws->os, 1); + } + + // rjf: focus the biggest panel + { + DF_Panel *best_leaf_panel = &df_g_nil_panel; + F32 best_leaf_panel_area = 0; + Rng2F32 root_rect = r2f32p(0, 0, 1000, 1000); // NOTE(rjf): we can assume any size - just need proportions. + for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next) + { + if(df_panel_is_nil(panel->first)) + { + Rng2F32 rect = df_rect_from_panel(root_rect, ws->root_panel, panel); + Vec2F32 dim = dim_2f32(rect); + F32 area = dim.x*dim.y; + if(best_leaf_panel_area == 0 || area > best_leaf_panel_area) + { + best_leaf_panel_area = area; + best_leaf_panel = panel; + } + } + } + ws->focused_panel = best_leaf_panel; + } + } + + //- rjf: apply keybindings + df_clear_bindings(); + DF_CfgVal *keybindings = df_cfg_val_from_string(table, str8_lit("keybindings")); + for(DF_CfgNode *keybinding_set = keybindings->first; + keybinding_set != &df_g_nil_cfg_node; + keybinding_set = keybinding_set->next) + { + for(DF_CfgNode *keybind = keybinding_set->first; + keybind != &df_g_nil_cfg_node; + keybind = keybind->next) + { + DF_CmdSpec *cmd_spec = &df_g_nil_cmd_spec; + OS_Key key = OS_Key_Null; + DF_CfgNode *ctrl_cfg = &df_g_nil_cfg_node; + DF_CfgNode *shift_cfg = &df_g_nil_cfg_node; + DF_CfgNode *alt_cfg = &df_g_nil_cfg_node; + for(DF_CfgNode *child = keybind->first; + child != &df_g_nil_cfg_node; + child = child->next) + { + if(str8_match(child->string, str8_lit("ctrl"), StringMatchFlag_CaseInsensitive)) + { + ctrl_cfg = child; + } + else if(str8_match(child->string, str8_lit("shift"), StringMatchFlag_CaseInsensitive)) + { + shift_cfg = child; + } + else if(str8_match(child->string, str8_lit("alt"), StringMatchFlag_CaseInsensitive)) + { + alt_cfg = child; + } + else + { + DF_CmdSpec *spec = df_cmd_spec_from_string(child->string); + if(!df_cmd_spec_is_nil(spec)) + { + cmd_spec = spec; + } + OS_Key k = df_os_key_from_cfg_string(child->string); + if(k != OS_Key_Null) + { + key = k; + } + } + } + if(!df_cmd_spec_is_nil(cmd_spec) && key != OS_Key_Null) + { + OS_EventFlags flags = 0; + if(ctrl_cfg != &df_g_nil_cfg_node) { flags |= OS_EventFlag_Ctrl; } + if(shift_cfg != &df_g_nil_cfg_node) { flags |= OS_EventFlag_Shift; } + if(alt_cfg != &df_g_nil_cfg_node) { flags |= OS_EventFlag_Alt; } + DF_Binding binding = {key, flags}; + df_bind_spec(cmd_spec, binding); + } + } + } + + //- rjf: apply theme colors + MemoryCopy(df_gfx_state->cfg_theme_target.colors, df_g_theme_preset_colors__default_dark, sizeof(df_g_theme_preset_colors__default_dark)); + MemoryCopy(df_gfx_state->cfg_theme.colors, df_g_theme_preset_colors__default_dark, sizeof(df_g_theme_preset_colors__default_dark)); + DF_CfgVal *colors = df_cfg_val_from_string(table, str8_lit("colors")); + for(DF_CfgNode *colors_set = colors->first; + colors_set != &df_g_nil_cfg_node; + colors_set = colors_set->next) + { + for(DF_CfgNode *color = colors_set->first; + color != &df_g_nil_cfg_node; + color = color->next) + { + String8 color_name = color->string; + DF_ThemeColor color_code = DF_ThemeColor_Null; + for(DF_ThemeColor c = DF_ThemeColor_Null; c < DF_ThemeColor_COUNT; c = (DF_ThemeColor)(c+1)) + { + if(str8_match(df_g_theme_color_cfg_string_table[c], color_name, StringMatchFlag_CaseInsensitive)) + { + color_code = c; + break; + } + } + if(color_code != DF_ThemeColor_Null) + { + DF_CfgNode *hex_cfg = color->first; + String8 hex_string = hex_cfg->string; + U64 hex_val = 0; + try_u64_from_str8_c_rules(hex_string, &hex_val); + Vec4F32 color_rgba = rgba_from_u32((U32)hex_val); + df_gfx_state->cfg_theme_target.colors[color_code] = color_rgba; + if(df_frame_index() <= 2) + { + df_gfx_state->cfg_theme.colors[color_code] = color_rgba; + } + } + } + } + + //- rjf: if config opened 0 windows, we need to do some sensible default + if(df_gfx_state->first_window == 0) + { + OS_Handle preferred_monitor = os_primary_monitor(); + Vec2F32 monitor_dim = os_dim_from_monitor(preferred_monitor); + Vec2F32 window_dim = v2f32(monitor_dim.x*4/5, monitor_dim.y*4/5); + DF_Window *ws = df_window_open(window_dim, preferred_monitor, DF_CfgSrc_User); + DF_CmdParams blank_params = df_cmd_params_from_window(ws); + df_cmd_list_push(arena, cmds, &blank_params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ResetToDefaultPanels)); + } + + //- rjf: if config bound 0 keys, we need to do some sensible default + if(df_gfx_state->key_map_total_count == 0) + { + for(U64 idx = 0; idx < ArrayCount(df_g_default_binding_table); idx += 1) + { + DF_StringBindingPair *pair = &df_g_default_binding_table[idx]; + DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(pair->string); + df_bind_spec(cmd_spec, pair->binding); + } + } + }break; + + //- rjf: writing config changes + case DF_CoreCmdKind_WriteUserData: + case DF_CoreCmdKind_WriteProfileData: + { + DF_CfgSrc src = DF_CfgSrc_User; + for(DF_CfgSrc s = (DF_CfgSrc)0; s < DF_CfgSrc_COUNT; s = (DF_CfgSrc)(s+1)) + { + if(core_cmd_kind == df_g_cfg_src_write_cmd_kind_table[s]) + { + src = s; + break; + } + } + if(cfg_write_done[src] == 0) + { + cfg_write_done[src] = 1; + String8 path = df_cfg_path_from_src(src); + String8List strs = df_cfg_strings_from_gfx(scratch.arena, path, src); + String8 data = str8_list_join(scratch.arena, &strs, 0); + df_cfg_push_write_string(src, data); + } + }break; + + //- rjf: code navigation + case DF_CoreCmdKind_FindTextForward: + case DF_CoreCmdKind_FindTextBackward: + { + df_set_search_string(params.string); + }break; + + //- rjf: find next and find prev + case DF_CoreCmdKind_FindNext: + { + DF_CmdParams p = params; + p.string = df_push_search_string(scratch.arena); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindTextForward)); + }break; + case DF_CoreCmdKind_FindPrev: + { + DF_CmdParams p = params; + p.string = df_push_search_string(scratch.arena); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindTextBackward)); + }break; + } + } + scratch_end(scratch); + } + + //- rjf: animate theme + { + DF_Theme *current = &df_gfx_state->cfg_theme; + DF_Theme *target = &df_gfx_state->cfg_theme_target; + F32 rate = 1 - pow_f32(2, (-50.f * df_dt())); + for(DF_ThemeColor color = DF_ThemeColor_Null; + color < DF_ThemeColor_COUNT; + color = (DF_ThemeColor)(color+1)) + { + if(abs_f32(target->colors[color].x - current->colors[color].x) > 0.01f || + abs_f32(target->colors[color].y - current->colors[color].y) > 0.01f || + abs_f32(target->colors[color].z - current->colors[color].z) > 0.01f || + abs_f32(target->colors[color].w - current->colors[color].w) > 0.01f) + { + df_gfx_request_frame(); + } + current->colors[color].x += (target->colors[color].x - current->colors[color].x) * rate; + current->colors[color].y += (target->colors[color].y - current->colors[color].y) * rate; + current->colors[color].z += (target->colors[color].z - current->colors[color].z) * rate; + current->colors[color].w += (target->colors[color].w - current->colors[color].w) * rate; + } + } + + //- rjf: animate alive-transitions for entities + { + F32 rate = 1.f - pow_f32(2.f, -20.f*df_dt()); + for(DF_Entity *e = df_entity_root(); !df_entity_is_nil(e); e = df_entity_rec_df_pre(e, df_entity_root()).next) + { + F32 diff = (1.f - e->alive_t); + e->alive_t += diff * rate; + if(diff >= 0.01f) + { + df_gfx_request_frame(); + } + } + } + + ProfEnd(); +} + +internal void +df_gfx_end_frame(void) +{ + ProfBeginFunction(); + + //- rjf: simulate lag + if(DEV_simulate_lag) + { + Sleep(300); + } + + //- rjf: entities with a death timer -> keep animating + for(DF_Entity *entity = df_entity_root(), *next = 0; !df_entity_is_nil(entity); entity = next) + { + next = df_entity_rec_df_pre(entity, &df_g_nil_entity).next; + if(entity->flags & DF_EntityFlag_DiesWithTime) + { + df_gfx_request_frame(); + } + } + + //- rjf: end drag/drop if needed + if(df_gfx_state->drag_drop_state == DF_DragDropState_Dropping) + { + df_gfx_state->drag_drop_state = DF_DragDropState_Null; + MemoryZeroStruct(&df_g_drag_drop_payload); + } + + //- rjf: clear hover line info + if(df_gfx_state->hover_line_set_this_frame == 0) + { + df_gfx_state->hover_line_binary = df_handle_zero(); + df_gfx_state->hover_line_voff = 0; + } + + //- rjf: clear frame request state + if(df_gfx_state->num_frames_requested > 0) + { + df_gfx_state->num_frames_requested -= 1; + } + + ProfEnd(); +} diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h new file mode 100644 index 00000000..bd729938 --- /dev/null +++ b/src/df/gfx/df_gfx.h @@ -0,0 +1,1053 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DF_GFX_H +#define DF_GFX_H + +//////////////////////////////// +//~ rjf: Basic Types + +typedef struct DF_PathQuery DF_PathQuery; +struct DF_PathQuery +{ + String8 prefix; + String8 path; + String8 search; +}; + +//////////////////////////////// +//~ rjf: Binding Types + +typedef struct DF_Binding DF_Binding; +struct DF_Binding +{ + OS_Key key; + OS_EventFlags flags; +}; + +typedef struct DF_BindingNode DF_BindingNode; +struct DF_BindingNode +{ + DF_BindingNode *next; + DF_Binding binding; +}; + +typedef struct DF_BindingList DF_BindingList; +struct DF_BindingList +{ + DF_BindingNode *first; + DF_BindingNode *last; + U64 count; +}; + +typedef struct DF_StringBindingPair DF_StringBindingPair; +struct DF_StringBindingPair +{ + String8 string; + DF_Binding binding; +}; + +//////////////////////////////// +//~ rjf: Text Searching Types + +typedef struct DF_TextSearchMatch DF_TextSearchMatch; +struct DF_TextSearchMatch +{ + TxtPt pt; +}; + +typedef struct DF_TextSearchMatchChunkNode DF_TextSearchMatchChunkNode; +struct DF_TextSearchMatchChunkNode +{ + DF_TextSearchMatchChunkNode *next; + DF_TextSearchMatch *v; + U64 count; + U64 cap; +}; + +typedef struct DF_TextSearchMatchChunkList DF_TextSearchMatchChunkList; +struct DF_TextSearchMatchChunkList +{ + DF_TextSearchMatchChunkNode *first; + DF_TextSearchMatchChunkNode *last; + U64 node_count; + U64 total_count; +}; + +typedef struct DF_TextSearchMatchArray DF_TextSearchMatchArray; +struct DF_TextSearchMatchArray +{ + DF_TextSearchMatch *v; + U64 count; +}; + +typedef struct DF_TextSearchCacheNode DF_TextSearchCacheNode; +struct DF_TextSearchCacheNode +{ + // rjf: links + DF_TextSearchCacheNode *next; + DF_TextSearchCacheNode *prev; + + // rjf: allocation + Arena *arena; + + // rjf: search parameters + U128 hash; + String8 needle; + DF_TextSliceFlags flags; + TxtPt start_pt; + + // rjf: search results + B32 good; + DF_TextSearchMatchChunkList search_matches; + + // rjf: last time touched + U64 last_time_touched_us; +}; + +typedef struct DF_TextSearchCacheSlot DF_TextSearchCacheSlot; +struct DF_TextSearchCacheSlot +{ + DF_TextSearchCacheNode *first; + DF_TextSearchCacheNode *last; +}; + +//////////////////////////////// +//~ rjf: Key Map Types + +typedef struct DF_KeyMapNode DF_KeyMapNode; +struct DF_KeyMapNode +{ + DF_KeyMapNode *hash_next; + DF_KeyMapNode *hash_prev; + DF_CmdSpec *spec; + DF_Binding binding; +}; + +typedef struct DF_KeyMapSlot DF_KeyMapSlot; +struct DF_KeyMapSlot +{ + DF_KeyMapNode *first; + DF_KeyMapNode *last; +}; + +//////////////////////////////// +//~ rjf: View Functions + +struct DF_View; +struct DF_Panel; +struct DF_Window; + +#define DF_VIEW_SETUP_FUNCTION_SIG(name) void name(struct DF_View *view, DF_CfgNode *cfg_root) +#define DF_VIEW_SETUP_FUNCTION_NAME(name) df_view_setup_##name +#define DF_VIEW_SETUP_FUNCTION_DEF(name) internal DF_VIEW_SETUP_FUNCTION_SIG(DF_VIEW_SETUP_FUNCTION_NAME(name)) +typedef DF_VIEW_SETUP_FUNCTION_SIG(DF_ViewSetupFunctionType); + +#define DF_VIEW_STRING_FROM_STATE_FUNCTION_SIG(name) String8 name(Arena *arena, struct DF_View *view) +#define DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(name) df_view_string_from_state_##name +#define DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(name) internal DF_VIEW_STRING_FROM_STATE_FUNCTION_SIG(DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(name)) +typedef DF_VIEW_STRING_FROM_STATE_FUNCTION_SIG(DF_ViewStringFromStateFunctionType); + +#define DF_VIEW_CMD_FUNCTION_SIG(name) void name(struct DF_Window *ws, struct DF_Panel *panel, struct DF_View *view, struct DF_CmdList *cmds) +#define DF_VIEW_CMD_FUNCTION_NAME(name) df_view_cmds_##name +#define DF_VIEW_CMD_FUNCTION_DEF(name) internal DF_VIEW_CMD_FUNCTION_SIG(DF_VIEW_CMD_FUNCTION_NAME(name)) +typedef DF_VIEW_CMD_FUNCTION_SIG(DF_ViewCmdFunctionType); + +#define DF_VIEW_UI_FUNCTION_SIG(name) void name(struct DF_Window *ws, struct DF_Panel *panel, struct DF_View *view, Rng2F32 rect) +#define DF_VIEW_UI_FUNCTION_NAME(name) df_view_ui_##name +#define DF_VIEW_UI_FUNCTION_DEF(name) internal DF_VIEW_UI_FUNCTION_SIG(DF_VIEW_UI_FUNCTION_NAME(name)) +typedef DF_VIEW_UI_FUNCTION_SIG(DF_ViewUIFunctionType); + +//////////////////////////////// +//~ rjf: View Specification Types + +typedef U32 DF_ViewSpecFlags; +enum +{ + DF_ViewSpecFlag_ParameterizedByEntity = (1<<0), + DF_ViewSpecFlag_CanSerialize = (1<<1), + DF_ViewSpecFlag_CanSerializeEntityPath = (1<<2), +}; + +typedef struct DF_ViewSpecInfo DF_ViewSpecInfo; +struct DF_ViewSpecInfo +{ + DF_ViewSpecFlags flags; + String8 name; + String8 display_string; + DF_NameKind name_kind; + DF_ViewSetupFunctionType *setup_hook; + DF_ViewStringFromStateFunctionType *string_from_state_hook; + DF_ViewCmdFunctionType *cmd_hook; + DF_ViewUIFunctionType *ui_hook; +}; + +typedef struct DF_ViewSpec DF_ViewSpec; +struct DF_ViewSpec +{ + DF_ViewSpec *hash_next; + DF_ViewSpecInfo info; +}; + +typedef struct DF_ViewSpecInfoArray DF_ViewSpecInfoArray; +struct DF_ViewSpecInfoArray +{ + DF_ViewSpecInfo *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: View Types + +typedef struct DF_ArenaExt DF_ArenaExt; +struct DF_ArenaExt +{ + DF_ArenaExt *next; + Arena *arena; +}; + +typedef struct DF_View DF_View; +struct DF_View +{ + // rjf: ownership links ('owners' can have lists of views) + DF_View *next; + DF_View *prev; + + // rjf: call stack links (views can call into other views) + DF_View *callee_view; + DF_View *caller_view; + + // rjf: allocation info + U64 generation; + + // rjf: loading animation state + F32 loading_t; + F32 loading_t_target; + U64 loading_progress_v; + U64 loading_progress_v_target; + + // rjf: update flash animation state + F32 flash_t; + + // rjf: view state + UI_ScrollPt2 scroll_pos; + + // rjf: ctrl context overrides + DF_CtrlCtx ctrl_ctx_overrides; + + // rjf: allocation & user data extensions + Arena *arena; + DF_ArenaExt *first_arena_ext; + DF_ArenaExt *last_arena_ext; + void *user_data; + + // rjf: command data + DF_CmdSpec *cmd_spec; + DF_Handle cmd_entity; + + // rjf: query -> params data + String8 query; + TxtPt query_cursor; + TxtPt query_mark; + U8 query_buffer[1024]; +}; + +//////////////////////////////// +//~ rjf: Panel Types + +typedef struct DF_Panel DF_Panel; +struct DF_Panel +{ + // rjf: tree links/data + DF_Panel *first; + DF_Panel *last; + DF_Panel *next; + DF_Panel *prev; + DF_Panel *parent; + U64 child_count; + + // rjf: allocation data + U64 generation; + + // rjf: split data + Axis2 split_axis; + Vec2F32 off_pct_of_parent; + Vec2F32 off_pct_of_parent_target; + Vec2F32 size_pct_of_parent; + Vec2F32 size_pct_of_parent_target; + + // rjf: tab params + B32 hide_tab_bar; + B32 history_tab_bar_mode; + Side tab_side; + + // rjf: query view stack + DF_View *query_view_stack_top; + + // rjf: stable view stacks (tabs) + DF_View *first_stable_view; + DF_View *last_stable_view; + U64 stable_view_count; + DF_View *selected_stable_view; +}; + +typedef struct DF_PanelRec DF_PanelRec; +struct DF_PanelRec +{ + DF_Panel *next; + int push_count; + int pop_count; +}; + +//////////////////////////////// +//~ rjf: Drag/Drop Types + +typedef enum DF_DragDropState +{ + DF_DragDropState_Null, + DF_DragDropState_Dragging, + DF_DragDropState_Dropping, + DF_DragDropState_COUNT +} +DF_DragDropState; + +typedef struct DF_DragDropPayload DF_DragDropPayload; +struct DF_DragDropPayload +{ + UI_Key key; + DF_Handle panel; + DF_Handle view; + DF_Handle entity; + TxtPt text_point; +}; + +//////////////////////////////// +//~ rjf: View Rule Spec Types + +typedef U32 DF_GfxViewRuleSpecInfoFlags; // NOTE(rjf): see @view_rule_info +enum +{ + DF_GfxViewRuleSpecInfoFlag_VizRowProd = (1<<0), + DF_GfxViewRuleSpecInfoFlag_LineStringize = (1<<1), + DF_GfxViewRuleSpecInfoFlag_RowUI = (1<<2), + DF_GfxViewRuleSpecInfoFlag_BlockUI = (1<<3), +}; + +#define DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_SIG(name) void name(void) +#define DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(name) df_gfx_view_rule_viz_row_prod__##name +#define DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(name) internal DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_SIG(DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(name)) + +#define DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_SIG(name) void name(void) +#define DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(name) df_gfx_view_rule_line_stringize__##name +#define DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(name) internal DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_SIG(DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(name)) + +#define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(name) void name(DF_ExpandKey key, DF_Eval eval, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, struct DF_CfgNode *cfg) +#define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(name) df_gfx_view_rule_row_ui__##name +#define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(name)) + +#define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(name) void name(DF_Window *ws, DF_ExpandKey key, DF_Eval eval, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, struct DF_CfgNode *cfg, Vec2F32 dim) +#define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name) df_gfx_view_rule_block_ui__##name +#define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name)) + +typedef DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_SIG(DF_GfxViewRuleVizRowProdHookFunctionType); +typedef DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_SIG(DF_GfxViewRuleLineStringizeHookFunctionType); +typedef DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(DF_GfxViewRuleRowUIFunctionType); +typedef DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(DF_GfxViewRuleBlockUIFunctionType); + +typedef struct DF_GfxViewRuleSpecInfo DF_GfxViewRuleSpecInfo; +struct DF_GfxViewRuleSpecInfo +{ + String8 string; + DF_GfxViewRuleSpecInfoFlags flags; + DF_GfxViewRuleVizRowProdHookFunctionType *viz_row_prod; + DF_GfxViewRuleLineStringizeHookFunctionType *line_stringize; + DF_GfxViewRuleRowUIFunctionType *row_ui; + DF_GfxViewRuleBlockUIFunctionType *block_ui; +}; + +typedef struct DF_GfxViewRuleSpecInfoArray DF_GfxViewRuleSpecInfoArray; +struct DF_GfxViewRuleSpecInfoArray +{ + DF_GfxViewRuleSpecInfo *v; + U64 count; +}; + +typedef struct DF_GfxViewRuleSpec DF_GfxViewRuleSpec; +struct DF_GfxViewRuleSpec +{ + DF_GfxViewRuleSpec *hash_next; + DF_GfxViewRuleSpecInfo info; +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/df_gfx.meta.h" + +//////////////////////////////// +//~ rjf: Theme Types + +typedef struct DF_Theme DF_Theme; +struct DF_Theme +{ + Vec4F32 colors[DF_ThemeColor_COUNT]; +}; + +typedef enum DF_FontSlot +{ + DF_FontSlot_Main, + DF_FontSlot_Code, + DF_FontSlot_Icons, + DF_FontSlot_COUNT +} +DF_FontSlot; + +//////////////////////////////// +//~ rjf: UI Helper & Widget Types + +//- rjf: line edits + +typedef U32 DF_LineEditFlags; +enum +{ + DF_LineEditFlag_Expander = (1<<0), + DF_LineEditFlag_ExpanderSpace = (1<<1), + DF_LineEditFlag_ExpanderPlaceholder = (1<<2), + DF_LineEditFlag_DisableEdit = (1<<3), + DF_LineEditFlag_CodeContents = (1<<4), + DF_LineEditFlag_Border = (1<<5), + DF_LineEditFlag_NoBackground = (1<<6), + DF_LineEditFlag_PreferDisplayString = (1<<7), + DF_LineEditFlag_DisplayStringIsCode = (1<<8), +}; + +//- rjf: code viewing/editing widgets + +typedef U32 DF_CodeSliceFlags; +enum +{ + DF_CodeSliceFlag_Margin = (1<<0), + DF_CodeSliceFlag_LineNums = (1<<1), +}; + +typedef struct DF_CodeSliceParams DF_CodeSliceParams; +struct DF_CodeSliceParams +{ + // rjf: content + DF_CodeSliceFlags flags; + Rng1S64 line_num_range; + String8 *line_text; + Rng1U64 *line_ranges; + TXTI_TokenArray *line_tokens; + DF_EntityList *line_bps; + DF_EntityList *line_ips; + DF_EntityList *line_pins; + DF_TextLineDasm2SrcInfoList *line_dasm2src; + DF_TextLineSrc2DasmInfoList *line_src2dasm; + DF_EntityList relevant_binaries; + + // rjf: visual parameters + F_Tag font; + F32 font_size; + String8 search_query; + F32 line_height_px; + F32 margin_width_px; + F32 line_num_width_px; + F32 line_text_max_width_px; + DF_EntityList flash_ranges; +}; + +typedef struct DF_CodeSliceSignal DF_CodeSliceSignal; +struct DF_CodeSliceSignal +{ + UI_Signal base; + TxtPt mouse_pt; + TxtRng mouse_expr_rng; + Vec2F32 mouse_expr_baseline_pos; + S64 clicked_margin_line_num; + DF_Entity *dropped_entity; + S64 dropped_entity_line_num; + TxtRng copy_range; + B32 toggle_cursor_watch; + S64 set_next_statement_line_num; + S64 run_to_line_num; + S64 goto_disasm_line_num; + S64 goto_src_line_num; +}; + +//////////////////////////////// +//~ rjf: Auto-Complete Lister Types + +typedef U32 DF_AutoCompListerFlags; +enum +{ + DF_AutoCompListerFlag_Locals = (1<<0), + DF_AutoCompListerFlag_Registers = (1<<1), + DF_AutoCompListerFlag_ViewRules = (1<<2), +}; + +typedef struct DF_AutoCompListerItem DF_AutoCompListerItem; +struct DF_AutoCompListerItem +{ + String8 string; + String8 kind_string; + DF_FuzzyMatchRangeList matches; +}; + +typedef struct DF_AutoCompListerItemChunkNode DF_AutoCompListerItemChunkNode; +struct DF_AutoCompListerItemChunkNode +{ + DF_AutoCompListerItemChunkNode *next; + DF_AutoCompListerItem *v; + U64 count; + U64 cap; +}; + +typedef struct DF_AutoCompListerItemChunkList DF_AutoCompListerItemChunkList; +struct DF_AutoCompListerItemChunkList +{ + DF_AutoCompListerItemChunkNode *first; + DF_AutoCompListerItemChunkNode *last; + U64 chunk_count; + U64 total_count; +}; + +typedef struct DF_AutoCompListerItemArray DF_AutoCompListerItemArray; +struct DF_AutoCompListerItemArray +{ + DF_AutoCompListerItem *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Per-Window State + +typedef struct DF_Window DF_Window; +struct DF_Window +{ + // rjf: links & metadata + DF_Window *next; + DF_Window *prev; + U64 gen; + U64 frames_alive; + DF_CfgSrc cfg_src; + + // rjf: top-level info & handles + Arena *arena; + OS_Handle os; + R_Handle r; + UI_State *ui; + F32 code_font_size_delta; + F32 main_font_size_delta; + + // rjf: view state delta history + DF_StateDeltaHistory *view_state_hist; + + // rjf: context menu info + B32 dev_menu_is_open; + B32 menu_bar_focused; + B32 menu_bar_focused_on_press; + B32 menu_bar_key_held; + B32 menu_bar_focus_press_started; + UI_Key drop_completion_ctx_menu_key; + DF_Handle drop_completion_entity; + DF_Handle drop_completion_panel; + UI_Key entity_ctx_menu_key; + DF_Handle entity_ctx_menu_entity; + U8 entity_ctx_menu_input_buffer[1024]; + U64 entity_ctx_menu_input_size; + TxtPt entity_ctx_menu_input_cursor; + TxtPt entity_ctx_menu_input_mark; + UI_Key tab_ctx_menu_key; + DF_Handle tab_ctx_menu_view; + + // rjf: autocomplete lister state + U64 autocomp_last_frame_idx; + B32 autocomp_force_closed; + UI_Key autocomp_root_key; + DF_CtrlCtx autocomp_ctrl_ctx; + DF_AutoCompListerFlags autocomp_lister_flags; + U8 autocomp_lister_query_buffer[1024]; + U64 autocomp_lister_query_size; + F32 autocomp_num_visible_rows_t; + S64 autocomp_cursor_num; + + // rjf: hover eval stable state + TxtPt hover_eval_txt_cursor; + TxtPt hover_eval_txt_mark; + U8 hover_eval_txt_buffer[1024]; + U64 hover_eval_txt_size; + Arena *hover_eval_arena; + Vec2F32 hover_eval_spawn_pos; + String8 hover_eval_string; + + // rjf: hover eval timer + U64 hover_eval_first_frame_idx; + U64 hover_eval_last_frame_idx; + + // rjf: hover eval params + DF_CtrlCtx hover_eval_ctrl_ctx; + DF_Handle hover_eval_file; + TxtPt hover_eval_file_pt; + U64 hover_eval_vaddr; + F32 hover_eval_num_visible_rows_t; + + // rjf: error state + U8 error_buffer[512]; + U64 error_string_size; + F32 error_t; + + // rjf: context overrides + DF_CtrlCtx ctrl_ctx_overrides; + + // rjf: panel state + DF_Panel *root_panel; + DF_Panel *free_panel; + DF_Panel *focused_panel; + + // rjf: per-frame drawing state + D_Bucket *draw_bucket; +}; + +//////////////////////////////// +//~ rjf: View Rule Block State Types + +typedef struct DF_ViewRuleBlockArenaExt DF_ViewRuleBlockArenaExt; +struct DF_ViewRuleBlockArenaExt +{ + DF_ViewRuleBlockArenaExt *next; + Arena *arena; +}; + +typedef struct DF_ViewRuleBlockNode DF_ViewRuleBlockNode; +struct DF_ViewRuleBlockNode +{ + DF_ViewRuleBlockNode *next; + DF_ExpandKey key; + DF_ViewRuleBlockArenaExt *first_arena_ext; + DF_ViewRuleBlockArenaExt *last_arena_ext; + Arena *user_state_arena; + void *user_state; + U64 user_state_size; +}; + +typedef struct DF_ViewRuleBlockSlot DF_ViewRuleBlockSlot; +struct DF_ViewRuleBlockSlot +{ + DF_ViewRuleBlockNode *first; + DF_ViewRuleBlockNode *last; +}; + +//////////////////////////////// +//~ rjf: Main Per-Process Graphical State + +typedef struct DF_String2ViewNode DF_String2ViewNode; +struct DF_String2ViewNode +{ + DF_String2ViewNode *hash_next; + String8 string; + String8 view_name; +}; + +typedef struct DF_String2ViewSlot DF_String2ViewSlot; +struct DF_String2ViewSlot +{ + DF_String2ViewNode *first; + DF_String2ViewNode *last; +}; + +typedef struct DF_GfxState DF_GfxState; +struct DF_GfxState +{ + // rjf: arenas + Arena *arena; + Arena *frame_arena; + + // rjf: frame request state + U64 num_frames_requested; + + // rjf: history cache + DF_StateDeltaHistory *hist; + + // rjf: key map table + Arena *key_map_arena; + U64 key_map_table_size; + DF_KeyMapSlot *key_map_table; + DF_KeyMapNode *free_key_map_node; + U64 key_map_total_count; + + // rjf: bind change + B32 bind_change_active; + DF_CmdSpec *bind_change_cmd_spec; + DF_Binding bind_change_binding; + + // rjf: string search state + Arena *string_search_arena; + String8 string_search_string; + + // rjf: view specs + U64 view_spec_table_size; + DF_ViewSpec **view_spec_table; + + // rjf: view rule specs + U64 view_rule_spec_table_size; + DF_GfxViewRuleSpec **view_rule_spec_table; + + // rjf: view rule block state + U64 view_rule_block_slots_count; + DF_ViewRuleBlockSlot *view_rule_block_slots; + DF_ViewRuleBlockNode *free_view_rule_block_node; + + // rjf: cmd -> view table + U64 cmd2view_slot_count; + DF_String2ViewSlot *cmd2view_slots; + + // rjf: windows + OS_WindowRepaintFunctionType *repaint_hook; + DF_Window *first_window; + DF_Window *last_window; + DF_Window *free_window; + U64 window_count; + B32 last_window_queued_save; + + // rjf: view state + DF_View *free_view; + U64 free_view_count; + U64 allocated_view_count; + + // rjf: drag/drop state machine + DF_DragDropState drag_drop_state; + + // rjf: hover line info correllation state + DF_Handle hover_line_binary; + U64 hover_line_voff; + B32 hover_line_set_this_frame; + + // rjf: running theme state + DF_Theme cfg_theme_target; + DF_Theme cfg_theme; + F_Tag cfg_font_tags[DF_FontSlot_COUNT]; + + // rjf: text search state + U64 tsrch_slot_count; + U64 tsrch_stripe_count; + DF_TextSearchCacheSlot *tsrch_slots; + OS_Handle *tsrch_stripe_rw_mutexes; + OS_Handle tsrch_wakeup_mutex; + OS_Handle tsrch_wakeup_cv; + OS_Handle tsrch_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +read_only global DF_ViewSpec df_g_nil_view_spec = +{ + &df_g_nil_view_spec, + { + 0, + {0}, + {0}, + DF_NameKind_Null, + DF_VIEW_SETUP_FUNCTION_NAME(Null), + DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Null), + DF_VIEW_CMD_FUNCTION_NAME(Null), + DF_VIEW_UI_FUNCTION_NAME(Null), + }, +}; + +read_only global DF_GfxViewRuleSpec df_g_nil_gfx_view_rule_spec = +{ + &df_g_nil_gfx_view_rule_spec, +}; + +read_only global DF_View df_g_nil_view = +{ + &df_g_nil_view, + &df_g_nil_view, + &df_g_nil_view, + &df_g_nil_view, + 0, + 0, + 0, + 0, + 0, + 0, + {0}, + {0}, + 0, + 0, + 0, + 0, + &df_g_nil_cmd_spec, + {0}, +}; + +read_only global DF_Panel df_g_nil_panel = +{ + &df_g_nil_panel, + &df_g_nil_panel, + &df_g_nil_panel, + &df_g_nil_panel, + &df_g_nil_panel, + 0, +}; + +global DF_GfxState *df_gfx_state = 0; +global DF_DragDropPayload df_g_drag_drop_payload = {0}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal DF_PathQuery df_path_query_from_string(String8 string); +internal DF_FuzzyMatchRangeList df_fuzzy_match_find(Arena *arena, String8List needles, String8 haystack); + +//////////////////////////////// +//~ rjf: View Type Functions + +internal B32 df_view_is_nil(DF_View *view); +internal DF_Handle df_handle_from_view(DF_View *view); +internal DF_View *df_view_from_handle(DF_Handle handle); +internal DF_View *df_view_caller_root_from_view(DF_View *view); + +//////////////////////////////// +//~ rjf: Panel Type Functions + +//- rjf: basic type functions +internal B32 df_panel_is_nil(DF_Panel *panel); +internal DF_Handle df_handle_from_panel(DF_Panel *panel); +internal DF_Panel *df_panel_from_handle(DF_Handle handle); +internal UI_Key df_ui_key_from_panel(DF_Panel *panel); + +//- rjf: panel tree mutation notification +internal void df_panel_notify_mutation(DF_Window *window, DF_Panel *panel); + +//- rjf: tree construction +internal void df_panel_insert(DF_Panel *parent, DF_Panel *prev_child, DF_Panel *new_child); +internal void df_panel_remove(DF_Panel *parent, DF_Panel *child); + +//- rjf: tree walk +internal DF_PanelRec df_panel_rec_df(DF_Panel *panel, U64 sib_off, U64 child_off); +#define df_panel_rec_df_pre(panel) df_panel_rec_df(panel, OffsetOf(DF_Panel, next), OffsetOf(DF_Panel, first)) +#define df_panel_rec_df_post(panel) df_panel_rec_df(panel, OffsetOf(DF_Panel, prev), OffsetOf(DF_Panel, last)) + +//- rjf: panel -> rect calculations +internal Rng2F32 df_rect_from_panel_child(Rng2F32 parent_rect, DF_Panel *parent, DF_Panel *panel); +internal Rng2F32 df_rect_from_panel(Rng2F32 root_rect, DF_Panel *root, DF_Panel *panel); + +//- rjf: view ownership insertion/removal +internal void df_panel_history_new_branch(DF_Panel *panel); +internal void df_panel_insert_stable_view(DF_Panel *panel, DF_View *prev_view, DF_View *view); +internal void df_panel_remove_stable_view(DF_Panel *panel, DF_View *view); +internal DF_View *df_selected_view_stack_from_panel(DF_Panel *panel); +internal DF_View *df_selected_view_from_panel(DF_Panel *panel); +internal DF_View *df_query_view_from_panel(DF_Panel *panel); + +//- rjf: icons & display strings +internal String8 df_display_string_from_view(Arena *arena, DF_CtrlCtx ctrl_ctx, DF_View *view); +internal DF_IconKind df_icon_kind_from_view(DF_View *view); + +//////////////////////////////// +//~ rjf: Window Type Functions + +internal DF_Handle df_handle_from_window(DF_Window *window); +internal DF_Window *df_window_from_handle(DF_Handle handle); + +//////////////////////////////// +//~ rjf: Control Context + +internal DF_CtrlCtx df_ctrl_ctx_from_window(DF_Window *ws); +internal DF_CtrlCtx df_ctrl_ctx_from_view(DF_Window *ws, DF_View *view); + +//////////////////////////////// +//~ rjf: Command Parameters From Context + +internal DF_CmdParams df_cmd_params_from_gfx(void); +internal B32 df_prefer_dasm_from_window(DF_Window *window); +internal DF_CmdParams df_cmd_params_from_window(DF_Window *window); +internal DF_CmdParams df_cmd_params_from_panel(DF_Window *window, DF_Panel *panel); +internal DF_CmdParams df_cmd_params_from_view(DF_Window *window, DF_Panel *panel, DF_View *view); + +//////////////////////////////// +//~ rjf: Global Cross-Window UI Interaction State Functions + +internal B32 df_drag_is_active(void); +internal void df_drag_begin(DF_DragDropPayload *payload); +internal B32 df_drag_drop(DF_DragDropPayload *out_payload); +internal void df_drag_kill(void); +internal void df_queue_drag_drop(void); + +internal void df_set_hovered_line_info(DF_Entity *binary, U64 voff); +internal DF_Entity *df_get_hovered_line_info_binary(void); +internal U64 df_get_hovered_line_info_voff(void); + +//////////////////////////////// +//~ rjf: View Spec State Functions + +internal void df_register_view_specs(DF_ViewSpecInfoArray specs); +internal void df_register_cmd2view(String8 cmd_name, String8 view_name); +internal DF_ViewSpec *df_view_spec_from_string(String8 string); +internal DF_ViewSpec *df_view_spec_from_gfx_view_kind(DF_GfxViewKind gfx_view_kind); +internal DF_ViewSpec *df_view_spec_from_cmd_spec(DF_CmdSpec *cmd_spec); + +//////////////////////////////// +//~ rjf: View Rule Spec State Functions + +internal void df_register_gfx_view_rule_specs(DF_GfxViewRuleSpecInfoArray specs); +internal DF_GfxViewRuleSpec *df_gfx_view_rule_spec_from_string(String8 string); + +//////////////////////////////// +//~ rjf: View State Functions + +internal DF_View *df_view_alloc(void); +internal void df_view_release_single(DF_View *view); +internal void df_view_release(DF_View *view); +internal void df_view_equip_command(DF_View *view, DF_CmdSpec *spec, DF_CmdParams *params, String8 default_query, DF_CfgNode *cfg_root); +internal void df_view_equip_loading_info(DF_View *view, B32 is_loading, U64 progress_v, U64 progress_target); +internal void df_view_clear_user_state(DF_View *view); +internal void *df_view_get_or_push_user_state(DF_View *view, U64 size); +internal Arena *df_view_push_arena_ext(DF_View *view); +#define df_view_user_state(view, type) (type *)df_view_get_or_push_user_state((view), sizeof(type)) + +//////////////////////////////// +//~ rjf: View Rule Instance State Functions + +internal void *df_view_rule_block_get_or_push_user_state(DF_ExpandKey key, U64 size); +#define df_view_rule_block_user_state(key, type) (type *)df_view_rule_block_get_or_push_user_state(key, sizeof(type)) +internal Arena *df_view_rule_block_push_arena_ext(DF_ExpandKey key); + +//////////////////////////////// +//~ rjf: Panel State Functions + +internal DF_Panel *df_panel_alloc(DF_Window *ws); +internal void df_panel_release(DF_Window *ws, DF_Panel *panel); +internal void df_panel_release_all_views(DF_Panel *panel); + +//////////////////////////////// +//~ rjf: Window State Functions + +internal DF_Window *df_window_open(Vec2F32 size, OS_Handle preferred_monitor, DF_CfgSrc cfg_src); + +internal DF_Window *df_window_from_os_handle(OS_Handle os); + +internal void df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, DF_CmdList *cmds); + +//////////////////////////////// +//~ rjf: Eval Viz + +internal String8List df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, DF_CfgTable *cfg_table); +internal DF_EvalVizWindowedRowList df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks); + +//////////////////////////////// +//~ rjf: Hover Eval + +internal void df_set_hover_eval(DF_Window *ws, Vec2F32 pos, DF_CtrlCtx ctrl_ctx, DF_Entity *file, TxtPt pt, U64 vaddr, String8 string); + +//////////////////////////////// +//~ rjf: Auto-Complete Lister + +internal void df_autocomp_lister_item_chunk_list_push(Arena *arena, DF_AutoCompListerItemChunkList *list, U64 cap, DF_AutoCompListerItem *item); +internal DF_AutoCompListerItemArray df_autocomp_lister_item_array_from_chunk_list(Arena *arena, DF_AutoCompListerItemChunkList *list); +internal int df_autocomp_lister_item_qsort_compare(DF_AutoCompListerItem *a, DF_AutoCompListerItem *b); +internal void df_autocomp_lister_item_array_sort__in_place(DF_AutoCompListerItemArray *array); + +internal void df_set_autocomp_lister_query(DF_Window *ws, UI_Key root_key, DF_CtrlCtx ctrl_ctx, DF_AutoCompListerFlags flags, String8 query); + +//////////////////////////////// +//~ rjf: Search Strings + +internal void df_set_search_string(String8 string); +internal String8 df_push_search_string(Arena *arena); + +//////////////////////////////// +//~ rjf: Background Text Searching Thread + +internal void df_text_search_match_chunk_list_push(Arena *arena, DF_TextSearchMatchChunkList *list, U64 cap, DF_TextSearchMatch *match); +internal DF_TextSearchMatchArray df_text_search_match_array_from_chunk_list(Arena *arena, DF_TextSearchMatchChunkList *chunks); +internal U64 df_text_search_little_hash_from_hash(U128 hash); +internal void df_text_search_thread_entry_point(void *p); +internal DF_TextSearchMatchArray df_text_search_match_array_from_hash_needle(Arena *arena, U128 hash, String8 needle, DF_TextSliceFlags text_slice_flags, TxtPt start_pt); +internal DF_TextSearchMatchArray df_text_search_match_array_from_entity_needle(Arena *arena, DF_Entity *entity, String8 needle, DF_TextSliceFlags flags, TxtPt start_pt); +internal int df_text_search_match_array_qsort_compare(TxtPt *a, TxtPt *b); +internal void df_text_search_match_array_sort_in_place(DF_TextSearchMatchArray *array); +internal DF_TextSearchMatch df_text_search_match_array_find_nearest__linear_scan(DF_TextSearchMatchArray *array, TxtPt pt, Side side); + +//////////////////////////////// +//~ rjf: Colors, Fonts, Config + +//- rjf: keybindings +internal OS_Key df_os_key_from_cfg_string(String8 string); +internal void df_clear_bindings(void); +internal DF_BindingList df_bindings_from_spec(Arena *arena, DF_CmdSpec *spec); +internal void df_bind_spec(DF_CmdSpec *spec, DF_Binding binding); +internal void df_unbind_spec(DF_CmdSpec *spec, DF_Binding binding); +internal DF_CmdSpecList df_cmd_spec_list_from_binding(Arena *arena, DF_Binding binding); +internal DF_CmdSpecList df_cmd_spec_list_from_event_flags(Arena *arena, OS_EventFlags flags); + +//- rjf: colors +internal Vec4F32 df_rgba_from_theme_color(DF_ThemeColor color); +internal DF_ThemeColor df_theme_color_from_txti_token_kind(TXTI_TokenKind kind); + +//- rjf: fonts/sizes +internal F_Tag df_font_from_slot(DF_FontSlot slot); +internal F32 df_font_size_from_slot(DF_Window *ws, DF_FontSlot slot); + +//- rjf: config serialization +internal String8List df_cfg_strings_from_gfx(Arena *arena, String8 root_path, DF_CfgSrc source); + +//////////////////////////////// +//~ rjf: UI Helpers + +internal void df_box_equip_fuzzy_match_range_list_vis(UI_Box *box, DF_FuzzyMatchRangeList range_list); + +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Buttons + +internal void df_cmd_binding_button(DF_CmdSpec *spec); +internal UI_Signal df_menu_bar_button(String8 string); +internal UI_Signal df_cmd_spec_button(DF_CmdSpec *spec); +internal void df_cmd_list_menu_buttons(DF_Window *ws, U64 count, DF_CoreCmdKind *cmds, U32 *fastpath_codepoints); +internal UI_Signal df_icon_button(DF_IconKind kind, String8 string); +internal UI_Signal df_icon_buttonf(DF_IconKind kind, char *fmt, ...); +internal void df_entity_tooltips(DF_Entity *entity); +internal void df_entity_desc_button(DF_Window *ws, DF_Entity *entity); +internal void df_entity_src_loc_button(DF_Window *ws, DF_Entity *entity, TxtPt point); + +//////////////////////////////// +//~ rjf: UI Widgets: Text View + +internal UI_BOX_CUSTOM_DRAW(df_thread_box_draw_extensions); +internal UI_BOX_CUSTOM_DRAW(df_bp_box_draw_extensions); +internal DF_CodeSliceSignal df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, String8 string); +internal DF_CodeSliceSignal df_code_slicef(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, char *fmt, ...); + +internal B32 df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); +internal B32 df_do_dasm_controls(DASM_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); + +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Labels + +internal UI_Signal df_error_label(String8 string); +internal B32 df_help_label(String8 string); +internal D_FancyStringList df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, String8 string); +internal void df_code_label(F32 alpha, B32 indirection_size_change, String8 string); + +//////////////////////////////// +//~ rjf: UI Widgets: Line Edit + +internal UI_Signal df_line_edit(DF_LineEditFlags flags, S32 depth, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, String8 string); +internal UI_Signal df_line_editf(DF_LineEditFlags flags, S32 depth, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, char *fmt, ...); + +//////////////////////////////// +//~ rjf: Continuous Frame Requests + +internal void df_gfx_request_frame(void); + +//////////////////////////////// +//~ rjf: Main Layer Top-Level Calls + +internal void df_gfx_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, DF_StateDeltaHistory *hist); +internal void df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds); +internal void df_gfx_end_frame(void); + +#endif // DF_GFX_H diff --git a/src/df/gfx/df_gfx.mc b/src/df/gfx/df_gfx.mc new file mode 100644 index 00000000..160d7362 --- /dev/null +++ b/src/df/gfx/df_gfx.mc @@ -0,0 +1,721 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Embedded Data + +@embed_file df_g_icon_font_bytes: "../data/icons.ttf" +@embed_file df_g_default_main_font_bytes: "../data/Roboto-Regular.ttf" +@embed_file df_g_default_code_font_bytes: "../data/liberation-mono.ttf" +//@embed_file df_g_default_code_font_bytes: "../data/Inconsolata-Regular.ttf" + +//////////////////////////////// +//~ rjf: Default Bindings + +@table(name key ctrl shift alt) +DF_DefaultBindingTable: +{ + //- rjf: low-level target control operations + { "kill_all" F5 0 shift 0 } + { "step_into_inst" F11 0 0 alt } + { "step_over_inst" F10 0 0 alt } + { "step_out" F11 0 shift 0 } + { "halt" X ctrl shift 0 } + { "halt" Pause 0 0 0 } + { "soft_halt_refresh" R 0 0 alt } + + //- rjf: high-level composite target control operations + { "run" F5 0 0 0 } + { "restart" F5 ctrl shift 0 } + { "step_into" F11 0 0 0 } + { "step_over" F10 0 0 0 } + { "run_to_cursor" F10 ctrl 0 0 } + { "set_next_statement" F10 ctrl shift 0 } + + //- rjf: font sizes + { "inc_ui_font_scale" Equal 0 0 alt } + { "dec_ui_font_scale" Minus 0 0 alt } + { "inc_code_font_scale" Equal 0 shift alt } + { "dec_code_font_scale" Minus 0 shift alt } + + //- rjf: windows + { "window" N ctrl shift 0 } + { "toggle_fullscreen" Return ctrl 0 0 } + + //- rjf: panel splitting + { "new_panel_right" P ctrl 0 0 } + { "new_panel_down" Minus ctrl 0 0 } + + //- rjf: panel rotation + { "rotate_panel_columns" 2 ctrl 0 0 } + + //- rjf: focused panel changing + { "next_panel" Comma ctrl 0 0 } + { "prev_panel" Comma ctrl shift 0 } + { "focus_panel_right" Right ctrl shift alt } + { "focus_panel_left" Left ctrl shift alt } + { "focus_panel_up" Up ctrl shift alt } + { "focus_panel_down" Down ctrl shift alt } + + //- rjf: undo/redo + //{ "undo" Z ctrl 0 0 } + //{ "redo" Y ctrl 0 0 } + + //- rjf: focus history + //{ "go_back" Left 0 0 alt } + //{ "go_forward" Right 0 0 alt } + + //- rjf: panel removal + { "close_panel" P ctrl shift 0 } + + //- rjf: panel tab + { "next_tab" PageDown ctrl 0 0 } + { "prev_tab" PageUp ctrl 0 0 } + { "next_tab" Tab ctrl 0 0 } + { "prev_tab" Tab ctrl shift 0 } + { "move_tab_right" PageDown ctrl shift 0 } + { "move_tab_left" PageUp ctrl shift 0 } + { "close_tab" W ctrl 0 0 } + { "tab_bar_top" Up ctrl 0 alt } + { "tab_bar_bottom" Down ctrl 0 alt } + + //- rjf: files + { "open" O ctrl 0 0 } + { "reload_active" R ctrl shift 0 } + { "switch" I ctrl 0 0 } + + //- rjf: setting config paths + { "load_user" O ctrl shift alt } + { "load_profile" O ctrl 0 alt } + + //- rjf: directional movement & text controls + { "move_left" Left 0 0 0 } + { "move_right" Right 0 0 0 } + { "move_up" Up 0 0 0 } + { "move_down" Down 0 0 0 } + { "move_left_select" Left 0 shift 0 } + { "move_right_select" Right 0 shift 0 } + { "move_up_select" Up 0 shift 0 } + { "move_down_select" Down 0 shift 0 } + { "move_left_chunk" Left ctrl 0 0 } + { "move_right_chunk" Right ctrl 0 0 } + { "move_up_chunk" Up ctrl 0 0 } + { "move_down_chunk" Down ctrl 0 0 } + { "move_up_page" PageUp 0 0 0 } + { "move_down_page" PageDown 0 0 0 } + { "move_up_whole" Home ctrl 0 0 } + { "move_down_whole" End ctrl 0 0 } + { "move_left_chunk_select" Left ctrl shift 0 } + { "move_right_chunk_select" Right ctrl shift 0 } + { "move_up_chunk_select" Up ctrl shift 0 } + { "move_down_chunk_select" Down ctrl shift 0 } + { "move_up_page_select" PageUp 0 shift 0 } + { "move_down_page_select" PageDown 0 shift 0 } + { "move_up_whole_select" Home ctrl shift 0 } + { "move_down_whole_select" End ctrl shift 0 } + { "move_home" Home 0 0 0 } + { "move_end" End 0 0 0 } + { "move_home_select" Home 0 shift 0 } + { "move_end_select" End 0 shift 0 } + { "select_all" A ctrl 0 0 } + { "delete_single" Delete 0 0 0 } + { "delete_chunk" Delete ctrl 0 0 } + { "backspace_single" Backspace 0 0 0 } + { "backspace_chunk" Backspace ctrl 0 0 } + { "copy" C ctrl 0 0 } + { "cut" X ctrl 0 0 } + { "paste" V ctrl 0 0 } + { "insert_text" Null 0 0 0 } + + //- rjf: code navigation + { "goto_line" G ctrl 0 0 } + { "goto_address" G 0 0 alt } + { "find_text_forward" F ctrl 0 0 } + { "find_text_backward" R ctrl 0 0 } + { "find_next" F3 0 0 0 } + { "find_prev" F3 shift 0 0 } + + //- rjf: thread finding + { "find_selected_thread" F4 0 0 0 } + + //- rjf: name finding + { "goto_name" J ctrl 0 0 } + { "goto_name_at_cursor" F12 0 0 0 } + + //- rjf: watch expressions + { "toggle_watch_expr_at_cursor" W 0 0 alt } + { "toggle_watch_pin_at_cursor" F9 ctrl 0 0 } + + //- rjf: breakpoints + { "toggle_breakpoint_cursor" F9 0 0 0 } + + //- rjf: targets + { "add_target" T ctrl 0 0 } + + //- rjf: attaching + { "attach" F6 0 shift 0 } + + //- rjf: view drivers + { "commands" F1 0 0 0 } + { "scheduler" S 0 0 alt } + + //- rjf: developer commands + { "clear_diag_log" D ctrl 0 alt } + { "open_diag_log" D ctrl 0 0 } +} + +//////////////////////////////// +//~ rjf: Gfx Layer View Kinds + +@table(name, name_lower, display_string, name_kind, parameterized_by_entity, can_serialize, can_serialize_entity_path, inc_in_docs, docs_desc) +DF_GfxViewTable: +{ + { Null "null" "" Null 0 0 0 0 "" } + { Empty "empty" "" Null 0 0 0 0 "" } + { Commands "commands" "Commands" Null 0 0 0 0 "" } + { FileSystem "file_system" "File System" Null 0 0 0 0 "" } + { SystemProcesses "system_processes" "System Processes" Null 0 0 0 0 "" } + { EntityLister "entity_lister" "Entity List" EntityKindName 0 0 0 0 "" } + { Target "target" "Target" EntityName 1 0 0 0 "" } + { Targets "targets" "Targets" Null 0 1 0 1 "Displays a list of all targets, as well as controls for enabling, disabling, launching, editing, or deleting each target. For more information on targets, read the `Targets` section." } + { FilePathMap "file_path_map" "File Path Map" Null 0 1 0 1 "Displays a table of *path maps*. Each path map is a pair of file or folder paths, one being a 'source' path, and one being a 'destination' path. These pairs are used by the debugger when automatically searching for specific files - for instance, when attempting to snap to a source code location specified by debug info. If debug info refers to a path on the machine on which a target executable was originally built, but that path is not valid on the debugger machine, but some alternative path exists, then path maps may be used to redirect the debugger from the debug info's specified paths to the associated appropriate debugger machine file paths." } + { Scheduler "scheduler" "Scheduler" Null 0 1 0 1 "Displays all processes and threads to which the debugger is currently attached, and contains controls for selecting and freezing threads." } + { CallStack "call_stack" "Call Stack" Null 0 1 0 1 "Displays the call stack of the currently selected thread. Each frame in the call stack contains the associated module, function name, and return address. Allows selection of a particular call stack frame other than the top." } + { Modules "modules" "Modules" Null 0 1 0 1 "Displays a table of all modules currently loaded by any process to which the debugger is attached. This table displays each module's name, virtual address range in the containing process' address space, and which debug info file is being used by the debugger for the associated module." } + { PendingEntity "pending_entity" "Pending Entity" EntityName 1 0 0 0 "" } + { Code "code" "Code" EntityName 1 1 1 0 "" } + { Disassembly "disassembly" "Disassembly" Null 0 1 0 1 "Displays disassembled instructions in a textual form from the selected thread's containing process virtual address space." } + { Watch "watch" "Watch" Null 0 1 0 1 "The familiar 'watch window' debugger interface. Allows the inputting of a number of expressions. Each expression in the table is evaluated within the context of the selected thread's selected call stack frame. If applicable (depending on visualization rules and the expression's type), these expressions may be hierarchically expanded, which displays children as more rows in the table. The values of these expressions may also be edited, and if possible, can be used to write to registers or memory in attached processes. Also contains a new *view rule* column, not found in other major debuggers, which allows per-row specification of various visualization rules. These view rules may be used to visualize and inspect the evaluation of expressions in a variety of ways. To learn more, read the 'View Rules' section." } + { Locals "locals" "Locals" Null 0 1 0 1 "Nearly identical to `Watch`, but automatically filled with local variables found within the selected call stack frame of the selected thread, according to the associated debug info. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } + { Registers "registers" "Registers" Null 0 1 0 1 "Nearly identical to `Watch`, but automatically filled with all register names according to the selected thread's architecture. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } + { Output "output" "Output" Null 0 1 0 1 "Displays textual output from the selected thread's containing process." } + { Memory "memory" "Memory" Null 0 1 1 1 "A familiar hex-editor-like interface for viewing memory of attached processes." } + { Breakpoints "breakpoints" "Breakpoints" Null 0 1 0 1 "Displays a table of all breakpoints, containing information about each breakpoint's name, location, and hit count. Also contains per-breakpoint controls for enabling, deleting, or editing each breakpoint. For more information on breakpoints and their features, read the 'Breakpoints' section." } + { WatchPins "watch_pins" "Watch Pins" Null 0 1 0 1 "Displays a table of all watch pins (watched expressions, like those found in `Watch`, but instead of being within a table, being pinned to some source code location, like breakpoints). This table contains each pin's name, location, and controls for editing or deleting each pin." } + { ExceptionFilters "exception_filters" "Exception Filters" Null 0 1 0 1 "An interface which controls whether or not the debugger will halt attached processes upon encountering specific exception codes for the first time." } + { Theme "theme" "Theme" Null 0 1 0 1 "An interface for modifying the colors used in the debugger's UI. Allows selecting a theme preset, loading a theme from a file, and modifying individual colors within a theme." } +} + +//////////////////////////////// +//~ rjf: Default Command -> View Map + +@table(cmd view entity_kind_lock) +DF_CmdSpec2ViewSpecMap: +{ + {"launch_and_run" "entity_lister" Target } + {"launch_and_init" "entity_lister" Target } + {"kill" "entity_lister" Process } + {"detach" "entity_lister" Process } + {"select_thread" "entity_lister" Thread } + {"select_thread_window" "entity_lister" Thread } + {"select_thread_view" "entity_lister" Thread } + {"freeze_thread" "entity_lister" Thread } + {"thaw_thread" "entity_lister" Thread } + {"freeze_process" "entity_lister" Process } + {"thaw_process" "entity_lister" Process } + {"freeze_machine" "entity_lister" Machine } + {"thaw_machine" "entity_lister" Machine } + {"set_current_path" "file_system" Null } + {"open" "file_system" Null } + {"reload" "entity_lister" File } + {"switch" "entity_lister" File } + {"load_user" "file_system" Null } + {"load_profile" "file_system" Null } + {"find_thread" "entity_lister" Thread } + {"open_thread_disasm" "entity_lister" Thread } + {"open_file_memory" "entity_lister" File } + {"open_process_memory" "entity_lister" Process } + {"remove_breakpoint" "entity_lister" Breakpoint } + {"edit_breakpoint" "entity_lister" Breakpoint } + {"enable_breakpoint" "entity_lister" Breakpoint } + {"disable_breakpoint" "entity_lister" Breakpoint } + {"edit_breakpoint" "entity_lister" Breakpoint } + {"add_target" "file_system" Null } + {"remove_target" "entity_lister" Target } + {"edit_target" "entity_lister" Target } + {"retry_ended_process" "entity_lister" EndedProcess } + {"attach" "system_processes" Null } + {"commands" "commands" Null } + {"target_editor" "target" Null } + {"targets" "targets" Null } + {"file_path_map" "file_path_map" Null } + {"scheduler" "scheduler" Null } + {"call_stack" "call_stack" Null } + {"modules" "modules" Null } + {"pending_entity" "pending_entity" Null } + {"code" "code" Null } + {"watch" "watch" Null } + {"locals" "locals" Null } + {"registers" "registers" Null } + {"output" "output" Null } + {"memory" "memory" Null } + {"disassembly" "disassembly" Null } + {"breakpoints" "breakpoints" Null } + {"watch_pins" "watch_pins" Null } + {"exception_filters" "exception_filters" Null } + {"theme" "theme" Null } + {"pick_file" "file_system" Null } + {"clear_diag_log" "entity_lister" DiagLog } + {"open_diag_log" "entity_lister" DiagLog } +} + +//////////////////////////////// +//~ rjf: Built-In Graphical View Rule Extensions +// +// NOTE(rjf): see @view_rule_info + +@table(string vr ls ru bu) +DF_GfxViewRuleTable: +{ + {"array" - - - -} + {"list" x - - -} + {"dec" - x - -} + {"bin" - x - -} + {"oct" - x - -} + {"hex" - x - -} + {"only" x x - -} + {"omit" x x - -} + {"no_addr" - x - -} + {"rgba" - - x x} + {"text" - - - x} + {"disasm" - - - x} + {"bitmap" - - x x} + {"geo" - - x x} +} + +//////////////////////////////// +//~ rjf: Theme Color Codes + +@table(name display_name name_lower r g b a) +DF_ThemeTable: +{ + {Null "Null" null } + {PlainText "Plain Text" plain_text } + {PlainBackground "Plain Background" plain_background } + {PlainBorder "Plain Border" plain_border } + {PlainOverlay "Plain Overlay" plain_overlay } + {CodeDefault "Code (Default)" code_default } + {CodeFunction "Code (Function)" code_function } + {CodeType "Code (Type)" code_type } + {CodeLocal "Code (Local)" code_local } + {CodeKeyword "Code (Keyword)" code_keyword } + {CodeSymbol "Code (Symbol)" code_symbol } + {CodeNumeric "Code (Numeric)" code_numeric } + {CodeString "Code (String)" code_string } + {CodeMeta "Code (Meta)" code_meta } + {CodeComment "Code (Comment)" code_comment } + {LineInfo0 "Line Info (0)" line_info_0 } + {LineInfo1 "Line Info (1)" line_info_1 } + {LineInfo2 "Line Info (2)" line_info_2 } + {LineInfo3 "Line Info (3)" line_info_3 } + {AltText "Alt Text" alt_text } + {AltBackground "Alt Background" alt_background } + {AltBorder "Alt Border" alt_border } + {AltOverlay "Alt Overlay" alt_overlay } + {TabInactive "Inactive Tab" tab_inactive } + {TabActive "Active Tab" tab_active } + {EntityBackground "Entity Background" entity_background } + {QueryBar "Query Bar" query_bar } + {WeakText "Weak Text" weak_text } + {TextSelection "Text Selection" text_selection } + {Cursor "Cursor" cursor } + {Highlight0 "Highlight (0)" highlight_0 } + {Highlight1 "Highlight (1)" highlight_1 } + {SuccessText "Success Text" success_text } + {SuccessBackground "Success Background" success_background } + {SuccessBorder "Success Border" success_border } + {FailureText "Failure Text" failure_text } + {FailureBackground "Failure Background" failure_background } + {FailureBorder "Failure Border" failure_border } + {ActionText "Action Text" action_text } + {ActionBackground "Action Background" action_background } + {ActionBorder "Action Border" action_border } + {DropSiteOverlay "Drop Site Overlay" drop_site_overlay } + {Thread0 "Thread (0)" thread_0 } + {Thread1 "Thread (1)" thread_1 } + {Thread2 "Thread (2)" thread_2 } + {Thread3 "Thread (3)" thread_3 } + {Thread4 "Thread (4)" thread_4 } + {Thread5 "Thread (5)" thread_5 } + {Thread6 "Thread (6)" thread_6 } + {Thread7 "Thread (7)" thread_7 } + {ThreadUnwound "Thread (Unwound)" thread_unwound } + {InactivePanelOverlay "Inactive Panel Overlay" inactive_panel_overlay } + {DropShadow "Drop Shadow" drop_shadow } +} + +//////////////////////////////// +//~ rjf: Theme Presets + +@table(name_upper name_lower display_string) +DF_ThemePresetTable: +{ + { DefaultDark default_dark "Default (Dark)" } + { DefaultLight default_light "Default (Light)" } + { VSDark vs_dark "VS (Dark)" } + { VSLight vs_light "VS (Light)" } + { SolarizedDark solarized_dark "Solarized (Dark)" } + { SolarizedLight solarized_light "Solarized (Light)" } + { HandmadeHero handmade_hero "Handmade Hero" } + { FourCoder four_coder "4coder" } + { FarManager far_manager "Far Manager" } +} + +@table(name default_dark default_light vs_dark vs_light solarized_dark solarized_light handmade_hero four_coder far_manager) +DF_ThemePresetColorTable: +{ + (null 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff ) + (plain_text 0xe5e5e5ff 0x383838ff 0xe5e5e5ff 0x1e1e1eff 0xe5e5e5ff 0x1e1e1eff 0xa08563ff 0x90b080ff 0x00ffffff ) + (plain_background 0x3333337f 0xedededfe 0x1e1e1eff 0xffffffff 0x002b36ff 0xfcf6e2ff 0x0c0c0cff 0x0c0c0cff 0x000082ff ) + (plain_border 0xffffff19 0x0000001d 0xffffff19 0xcccedb1d 0xffffff19 0xcccedb1d 0xffffff19 0x181818a0 0xffffff19 ) + (plain_overlay 0xffffff33 0x00000033 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 ) + (code_default 0xe5e5e5ff 0x282828ff 0xd4d4d4ff 0x000000ff 0x839496ff 0x74878cff 0xa08563ff 0x90b080ff 0x00ffffff ) + (code_function 0x7fcc99ff 0x2a7a45ff 0xdcdcaaff 0x74531fff 0x1c7dd1ff 0xc39d36ff 0xcc5735ff 0x7fcc99ff 0x49b2ffff ) + (code_type 0x66b2e5ff 0x2c688fff 0x4ec9b0ff 0x2b91afff 0x1c7dd1ff 0x66b2e5ff 0xd8a51dff 0x66b2e5ff 0x49b2ffff ) + (code_local 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff ) + (code_keyword 0xf7bf5eff 0xa47729ff 0x569cd6ff 0x0000ffff 0x63980fff 0xc39d36ff 0xac7b0bff 0xd08f20ff 0xff0000ff ) + (code_symbol 0x994c32ff 0x6c2d18ff 0xb4b4b4ff 0x000000ff 0x839496ff 0x2e5256ff 0x994c32ff 0x994c32ff 0xffffffff ) + (code_numeric 0x4ce54cff 0x2c7d2cff 0xb5cea8ff 0x000000ff 0xcb4b20ff 0x657b83ff 0x6b8e23ff 0x50ff30ff 0x2cff50ff ) + (code_string 0xe5cc66ff 0xcc5a0fff 0xd69d85ff 0xc11515ff 0x2aa198ff 0x5ab4a9ff 0x6b8e23ff 0x50ff30ff 0xe5cc66ff ) + (code_meta 0xe54c4cff 0x8a0c0cff 0x9b9b9bff 0x808080ff 0xe54c4cff 0xe54c4cff 0xdab98fff 0x50ff30ff 0xffff00ff ) + (code_comment 0x7f7f7fff 0x7f7f7fff 0x6a9955ff 0x008000ff 0x7f7f7fff 0xadafb2ff 0x686868ff 0x2090f0ff 0x7f7f7fff ) + (line_info_0 0x3f72993f 0x3e71993f 0xbeb7ff3f 0x3f72993f 0x3f72993f 0x3f72993f 0xaf60103f 0x3f72993f 0x3f72993f ) + (line_info_1 0x3f72994c 0x3f72994c 0xbeb7ff4c 0x3f72994c 0x3f72994c 0x3f72994c 0xaf60104c 0x3f72994c 0x3f72994c ) + (line_info_2 0x3f729972 0x3f729972 0xbeb7ff72 0x3f729972 0x3f729972 0x3f729972 0xaf601072 0x3f729972 0x3f729972 ) + (line_info_3 0x3f72997f 0x3f72997f 0xbeb7ff7f 0x3f72997f 0x3f72997f 0x3f72997f 0xaf60107f 0x3f72997f 0x3f72997f ) + (alt_text 0xe5e5e5ff 0x535353ff 0xf1f1f1ff 0x535353ff 0xe5e5e5ff 0x535353ff 0xa08563ff 0x90b080ff 0x000000ff ) + (alt_background 0x42474c7f 0xfefefebc 0x1b1b1cff 0xfefefebc 0x002b36ff 0xfcf6e2ff 0x0c0c0cff 0x0c0c0cff 0x008184ff ) + (alt_border 0xffffff19 0xffffff19 0x333337ff 0xffffff19 0xffffff19 0xffffff19 0xffffff19 0xffffff19 0xffffff19 ) + (alt_overlay 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 ) + (tab_inactive 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f 0x42474c7f ) + (tab_active 0xa87a4c99 0xc7a27dff 0x007accff 0x007accff 0x28515eff 0xa87a4c99 0xa87a4c99 0xa87a4c99 0xa87a4c99 ) + (entity_background 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 0x4293cc99 ) + (query_bar 0x8e2d4ccc 0xd76489cc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc 0x8e2d4ccc ) + (weak_text 0xffffff7f 0x0000007f 0xffffff7f 0x0000007f 0xffffff7f 0x0000007f 0xa08563af 0x90b080af 0xffffff7f ) + (text_selection 0x99ccff4c 0x7d98b34c 0x99ccff4c 0x7d98b34c 0x99ccff4c 0x7d98b34c 0x99ccff4c 0x99ccff4c 0x99ccff4c ) + (cursor 0x66e566e5 0x101010ff 0x66e566e5 0x101010ff 0x66e566e5 0x101010ff 0x66e566e5 0x66e566e5 0x66e566e5 ) + (highlight_0 0xb27219ff 0xb272189b 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff 0xb27219ff ) + (highlight_1 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff 0x327f19ff ) + (success_text 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff ) + (success_background 0x32b219ff 0x75db61ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff 0x32b219ff ) + (success_border 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 ) + (failure_text 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff 0xe5e5e5ff ) + (failure_background 0xb23219ff 0xf27961ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff ) + (failure_border 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 ) + (action_text 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff ) + (action_background 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff 0x327fb2ff ) + (action_border 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 0xffffff33 ) + (drop_site_overlay 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c ) + (thread_0 0xffcb7fff 0xad7c34ff 0xffcb7fff 0xad7c34ff 0xffcb7fff 0xad7c34ff 0xffcb7fff 0xffcb7fff 0xffcb7fff ) + (thread_1 0xb2ff65ff 0x639b2aff 0xb2ff65ff 0x639b2aff 0xb2ff65ff 0x639b2aff 0xb2ff65ff 0xb2ff65ff 0xb2ff65ff ) + (thread_2 0xff99e5ff 0xa94c91ff 0xff99e5ff 0xa94c91ff 0xff99e5ff 0xa94c91ff 0xff99e5ff 0xff99e5ff 0xff99e5ff ) + (thread_3 0x6598ffff 0x305398ff 0x6598ffff 0x305398ff 0x6598ffff 0x305398ff 0x6598ffff 0x6598ffff 0x6598ffff ) + (thread_4 0x65ffcbff 0x339574ff 0x65ffcbff 0x339574ff 0x65ffcbff 0x339574ff 0x65ffcbff 0x65ffcbff 0x65ffcbff ) + (thread_5 0xff9819ff 0xbf7416ff 0xff9819ff 0xbf7416ff 0xff9819ff 0xbf7416ff 0xff9819ff 0xff9819ff 0xff9819ff ) + (thread_6 0x9932ffff 0x57238bff 0x9932ffff 0x57238bff 0x9932ffff 0x57238bff 0x9932ffff 0x9932ffff 0x9932ffff ) + (thread_7 0x65ff4cff 0x2a7e1cff 0x65ff4cff 0x2a7e1cff 0x65ff4cff 0x2a7e1cff 0x65ff4cff 0x65ff4cff 0x65ff4cff ) + (thread_unwound 0xb2ccd8ff 0x236481ff 0xb2ccd8ff 0x236481ff 0xb2ccd8ff 0x236481ff 0xb2ccd8ff 0xb2ccd8ff 0xb2ccd8ff ) + (inactive_panel_overlay 0x0000003f 0x0000000d 0x0000003f 0x0000000d 0x0000003f 0x0000000d 0x0000003f 0x0000003f 0x0000003f ) + (drop_shadow 0x0000007f 0x0000003b 0x0000007f 0x0000003b 0x0000007f 0x0000003b 0x0000007f 0x0000007f 0x0000007f ) +} + +//////////////////////////////// +//~ rjf: Generators + +//- rjf: enums + +@table_gen_enum +DF_GfxViewKind: +{ + @expand(DF_GfxViewTable a) + `DF_GfxViewKind_$(a.name),` + `DF_GfxViewKind_COUNT`; +} + +@table_gen_enum +DF_ThemeColor: +{ + @expand(DF_ThemeTable, a) + `DF_ThemeColor_$(a.name),`; + `DF_ThemeColor_COUNT`; +} + +@table_gen_enum +DF_ThemePreset: +{ + @expand(DF_ThemePresetTable a) + `DF_ThemePreset_$(a.name),`; + `DF_ThemePreset_COUNT`; +} + +//- rjf: theme preset color tables + +@table_gen_data(type: String8, fallback: `{0}`) +df_g_theme_preset_display_string_table: +{ + @expand(DF_ThemePresetTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__default_dark: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_dark)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__default_light: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_light)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__vs_dark: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_dark)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__vs_light: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_light)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__solarized_dark: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_dark)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__solarized_light: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_light)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__handmade_hero: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.handmade_hero)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__four_coder: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.four_coder)),`; +} + +@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) +df_g_theme_preset_colors__far_manager: +{ + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.far_manager)),`; +} + +@table_gen_data(type: `Vec4F32 *`, fallback: `0`) +df_g_theme_preset_colors_table: +{ + @expand(DF_ThemePresetTable a) `df_g_theme_preset_colors__$(a.name_lower),`; +} + +//- rjf: default cmd -> view tables + +@table_gen_data(type: String8, fallback:`{0}`) +df_g_cmd2view_table_src: +{ + @expand(DF_CmdSpec2ViewSpecMap a) `str8_lit_comp("$(a.cmd)"),` +} + +@table_gen_data(type: String8, fallback:`{0}`) +df_g_cmd2view_table_dst: +{ + @expand(DF_CmdSpec2ViewSpecMap a) `str8_lit_comp("$(a.view)"),` +} + +//- rjf: default bindings table + +@table_gen_data(type: DF_StringBindingPair, fallback: `{0}`) +df_g_default_binding_table: +{ + @expand(DF_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_EventFlag_Ctrl`) $(a.shift != 0 -> `|OS_EventFlag_Shift`) $(a.alt != 0 -> `|OS_EventFlag_Alt`)}},```; +} + +//- rjf: view hook forward declares + +@table_gen +{ + @expand(DF_GfxViewTable a) `DF_VIEW_SETUP_FUNCTION_DEF($(a.name));`; + @expand(DF_GfxViewTable a) `DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF($(a.name));`; + @expand(DF_GfxViewTable a) `DF_VIEW_CMD_FUNCTION_DEF($(a.name));`; + @expand(DF_GfxViewTable a) `DF_VIEW_UI_FUNCTION_DEF($(a.name));`; +} + +//- rjf: gfx view rule function forward declares + +@table_gen +{ + ``; + @expand(DF_GfxViewRuleTable a) + `$(a.vr == "x" -> "DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(" .. a.name_lower .. ");")`; + @expand(DF_GfxViewRuleTable a) + `$(a.ls == "x" -> "DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(" .. a.name_lower .. ");")`; + @expand(DF_GfxViewRuleTable a) + `$(a.ru == "x" -> "DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(" .. a.name_lower .. ");")`; + @expand(DF_GfxViewRuleTable a) + `$(a.bu == "x" -> "DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(" .. a.name_lower .. ");")`; +} + +//- rjf: gfx view rule tables + +@table_gen_data(type: DF_GfxViewRuleSpecInfo, fallback: `{0}`) @c_file +df_g_gfx_view_rule_spec_info_table: +{ + @expand(DF_GfxViewRuleTable a) + ```{ str8_lit_comp("$(a.string)"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*$(a.vr == "x"))|(DF_GfxViewRuleSpecInfoFlag_LineStringize*$(a.ls == "x"))|(DF_GfxViewRuleSpecInfoFlag_RowUI*$(a.ru == "x"))|(DF_GfxViewRuleSpecInfoFlag_BlockUI*$(a.bu == "x")), $(a.vr == "x" -> "DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vr != "x" -> 0), $(a.ls == "x" -> "DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME("..a.name_lower..")") $(a.ls != "x" -> 0), $(a.ru == "x" -> "DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME("..a.name_lower..")") $(a.ru != "x" -> 0), $(a.bu == "x" -> "DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME("..a.name_lower..")") $(a.bu != "x" -> 0), },```; +} + +//- rjf: default view spec info table + +@table_gen_data(type: DF_ViewSpecInfo, fallback: `{0}`) +df_g_gfx_view_kind_spec_info_table: +{ + @expand(DF_GfxViewTable a) ```{(0|$(a.parameterized_by_entity)*DF_ViewSpecFlag_ParameterizedByEntity|$(a.can_serialize)*DF_ViewSpecFlag_CanSerialize|$(a.can_serialize_entity_path)*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("$(a.name_lower)"), str8_lit_comp("$(a.display_string)"), DF_NameKind_$(a.name_kind), DF_VIEW_SETUP_FUNCTION_NAME($(a.name)), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME($(a.name)), DF_VIEW_CMD_FUNCTION_NAME($(a.name)), DF_VIEW_UI_FUNCTION_NAME($(a.name))},```; +} + +//- rjf: theme color string tables + +@table_gen_data(type: String8, fallback: `str8_lit_comp("")`) +df_g_theme_color_display_string_table: +{ + @expand(DF_ThemeTable a) `str8_lit_comp("$(a.display_name)"),`; +} + +@table_gen_data(type: String8, fallback: `str8_lit_comp("")`) +df_g_theme_color_cfg_string_table: +{ + @expand(DF_ThemeTable a) `str8_lit_comp("$(a.name_lower)"),`; +} + +//////////////////////////////// +//~ rjf: Help/Docs/README + +@markdown +raddbg_readme: +{ + @title "The RAD Debugger (ALPHA)"; + @p "The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It currently only supports local-machine Windows x64 debugging, with plans to expand and port in the future."; + + @subtitle "Getting Started"; + @p "To launch the RAD Debugger with your executable and command line arguments, run `raddbg` from the command line like so:"; + @p "```raddbg my_program.exe --foo --bar --baz```"; + @p "For more information, see the 'Command-Line Usage' section."; + @p "Default keyboard shortcuts for common debugger controls include:"; + @unordered_list + { + @p "**Ctrl + O**: Open Source Code File"; + @p "**F10**: Step Over"; + @p "**F11**: Step Into"; + @p "**Shift + F11**: Step Out"; + @p "**F5**: Run"; + @p "**Ctrl + Shift + X**, or **Pause**: Halt All Processes"; + @p "**Shift + F5**: Kill All Processes"; + @p "**Shift + F6**: Attach To Process"; + @p "**Ctrl + F**: Search For Text (Forwards)"; + @p "**F9**: Toggle Breakpoint At Cursor"; + @p "**Ctrl + Comma**: Focus Next Panel"; + @p "**Ctrl + Shift + Comma**: Focus Previous Panel"; + @p "**Ctrl + Shift + Alt + Arrow Key**: Focus Panel In Direction"; + @p "**Ctrl + Tab**: Focus Next Tab"; + @p "**Ctrl + Shift + Tab**: Focus Previous Tab"; + @p "**Ctrl + W**: Close Tab"; + @p "**F1**: Open Command Palette"; + } + @p "For more information, see the 'Commands' section."; + @p "View rules can be used to visualize expressions differently in the watch window. Here are some examples:"; + @unordered_list + { + @p "`array:16`: Visualize a pointer as pointing to a 16-element array."; + @p "`array:(count*2)`: Visualize a pointer as pointing to a `count*2`-element array."; + @p "`list:next`: Visualize a linked list flatly, where each node has a `next` pointer, which points to the next node in the list."; + @p "`hex`: Visualize numeric literals as base-16 (hexadecimal)."; + @p "`dec`: Visualize numeric literals as base-10 (decimal)."; + @p "`oct`: Visualize numeric literals as base-8 (octal)."; + @p "`bin`: Visualize numeric literals as base-2 (binary)."; + @p "`omit:(foo bar baz)`: Prohibits members named `foo`, `bar`, and `baz` from being displayed."; + @p "`only:(foo bar baz)`: Only allows members named `foo`, `bar`, and `baz` to be displayed."; + } + @p "Multiple view rules can be specified on one line, so they can be combined like so:"; + @p "```list:next, hex, omit:next```"; + @p "For more information, see the 'View Rules' section."; + + @subtitle "Command-Line Usage"; + @p "When run normally, either by launching through a file explorer or running from a command line without arguments, `raddbg` will open a new instance of the debugger. But it also supports a number of command line options for a number of other purposes. These options are specified with a `-` or `--` prefix, followed by the name of the option, and if the option requires a parameter, followed by a `:` or `=`, followed by the parameter's content. A list of the possible options follows:"; + @unordered_list + { + @p "`--help` Displays a help menu which documents the possible command line options."; + @p "`--user:` Specifies a path to the user file which the debugger should use instead of the default. The default user file is stored at `%appdata%/raddbg/default.raddbg_user`. For more information on user files, read the 'User & Profile Files' section."; + @p "`--profile:` Specifies a path to the profile file which the debugger should use instead of the default. The default profile file is stored at `%appdata%/raddbg/default.raddbg_profile`. For more information on profile files, read the 'User & Profile Files' section."; + @p "`--auto_run` Specifies that the debugger should immediately run its selected targets upon launching."; + @p "`--auto_step` Specifies that the debugger should immediately step into its selected targets upon launching."; + //@p "`--ipc` Specifies that the launched debugger instance is for communicating a command to another instance of the debugger. In this mode, any non-argument command line contents will be used to express a command. For more information on commands, read the 'Commands' section. For more information on driving another debugger instance with this argument, read the 'Driving Another Debugger Instance' section." + } + @p "On the command line, non-options (meaning any command line arguments *not* prefixed with a `-` or `--`) can also be specified. with normal usage, they are interpreted as the command line for a target (see the 'Targets' section)." + // add when --ipc support is ready: "When driving another debugger instance (using the `--ipc` argument), this additional command line text is used to encode a debugger command."; + @p "The debugger will stop parsing `-` and `--` prefixes as arguments after seeing a standalone `--`, *or* after seeing the first non-option argument, when reading the command line left-to-right. Some examples of command line usage and their interpretations are below:"; + @unordered_list + { + @p "`raddbg --foo --bar --a:b --c=d test.exe` All options are used to configure `raddbg`. `test.exe` is interpreted as a target executable. `b` is interpreted as the parameter for the `a` option. `d` is interpreted as the parameter for the `c` option."; + @p "`raddbg test.exe --foo --bar` `test.exe` is interpreted as a target executable. `--foo --bar` is interpreted as arguments for `test.exe`, and thus are *not* used to configure `raddbg`."; + @p "`raddbg -- test.exe` `test.exe` is interpreted as a target executable."; + //@p "`raddbg --ipc find_code_location \"c:/foo/bar/baz.c:123:1\"` `--ipc` configures `raddbg` to drive another instance of `raddbg`. The remainder of the text is interpreted as a command."; + @p "`raddbg \"C:/path with spaces/test.exe\" --foo --bar` A target is formed from the `test.exe` path, and `--foo --bar` are interpreted as arguments to the `test.exe` target."; + } + + @subtitle "Windows, Panels, & Tabs"; + @p "Each opened *window* in the debugger frontend is subdivided into *panels*. Panels subdivide regions of their window without overlapping. Each panel can contain multiple *tabs*, and can have one tab selected at any time. Tabs can be dragged and dropped between panels. Each tab is used to view one of the many supported debugger interfaces, including source code, disassembly, memory, or watches. When a tab is selected, that interface will fill the tab's containing panel's region of the containing window."; + @p "There are no 'special' windows, panels, or tabs; the debugger is written such that the number of windows, each window's panel organization, and the placement and arrangement of tabs can all be organized in a large variety of ways."; + @p "A list of debugger interfaces, which can occupy tabs, are below:"; + @unordered_list + { + @expand(DF_GfxViewTable a) @p "$(a.inc_in_docs -> '`'..a.display_string..'` '..a.docs_desc)"; + } + + @subtitle "Commands"; + @p "The debugger is operated with *commands*. Commands may be manually executed in the debugger UI through the `Commands` menu (which you can open either in the `View` menu bar list, or by using the keybinding, which is F1 by default). Operations in the debugger UI are implemented with commands, so if it's ever unclear how to accomplish some operation through the UI, a useful fallback is searching for and running the command through the command menu."; + //@p "Commands are also how a debugger instance launched with `--ipc` may communicate with a primary debugger instance."; + //@p "A list of commands, how they're referred to textually (for the purposes of `--ipc` debugger instances), and their descriptions are below:"; + @p "A list of commands and their descriptions are below:"; + @unordered_list + { + @expand(DF_CoreCmdTable a) @p "$(a.lister_omit == 0 -> '`'..a.display_name..'` '..'(`'..a.string..'`) '..a.desc)"; + } + + @subtitle "Targets"; + @p "A *target* is one executable and configuration for launching that executable, including command line arguments and working directory (the directory from which the executable is launched). Each target may also have a custom label (replaces the executable path when visualizing the target), and the name of a custom entry point function (when the default entry points - `main`, `WinMain`, etc. - are not desired when stepping into the program upon launch). The debugger can have several targets at once. Each target can also be enabled or disabled. Some operations work on all enabled targets - for instance, the `Run` or `Kill All` commands (standardly bound as F5 or Shift + F5). Enabling and disabling targets allows one to filter which targets are currently being worked with."; + @p "To add a target, you can run the `Add Target` command. A target is also created automatically from command line arguments - the rules for how this happens can be found in the `Command-Line Usage` section."; + @p "Targets created through command line usage are temporary, meaning they are not persistently saved across runs of the debugger. To change this, you can right click the command-line-created target in the `Targets` view, and click `Save To Profile`. After doing so, the target will be restored across runs, and will no longer need to be specified on the command-line."; + + @subtitle "View Rules"; + @p "*View Rules* are used to transform the way that evaluations in the debugger are visualized. An evaluation is produced by taking an expression string - for instance, the name of a variable - and using debug info and information from an attached process' live runtime (memory, registers, and so on) to interpret it."; + @p "Evaluations may be visualized in a variety of ways. A 64-bit unsigned integer may be visualized as a textual representation of the value with a radix of 10. A 32-bit floating-point value may be visualized as a textual representation of the value. An array of 32-bit floating-point values can be visualized as a list of textual representations of those values."; + @p "But all of these cases may be visualized in a number of other ways, as well. A 64-bit unsigned integer may be more usefully represented with a radix of 16, 8, or 2. An array of 32-bit floating-point values may encode the R, G, B, and A components of a color, or vertex positions for 3D geometry, or samples for a waveform. An array of bytes may encode raw pixel data for an image, or image data in a compressed format. A struct may have several members which are not useful to look at all the time. A struct may form the head of a linked list, and a flat linked list representation may be more preferable than the traditional watch view representation, which adds an additional layer of hierarchical nesting with the expansion of each 'next' pointer in a linked list. When designing the debugger, we felt that the traditional memory view and watch view representations of data in a debugged-process were not sufficient. View rules were added to the traditional watch view structure to allow per-row specification of extra visualization parameters."; + @p "View rules are specified with the name of a view rule, and depending on the view rule, a `:`, followed by parameters for the view rule. These parameters may be whitespace delimited, but importantly, multiple view rules may be specified per-row in a watch view. To explicitly separate the parameters of one view rule from the name of another - for instance, in a case like `array:16 bin`, where `bin` will not be interpreted as a view rule, but as a parameter of `array` - then commas and semicolons may be used to separate the two view rules (`array:16, bin`), or parentheses/braces/brackets may also be used to explicitly delimit the view rule parameters (`array:(16) bin`)."; + @p "A list of currently-supported view rules are below:"; + @unordered_list + { + @expand(DF_CoreViewRuleTable a) @p "$(a.docs == 'x' -> '`'..a.string..'` ('..a.display_name..') '..a.description)"; + } + + @subtitle "Breakpoints"; + @p "Breakpoints interrupt execution of attached processes. They may be placed on specific code addresses, lines of source code, on specific symbol names. In the latter two cases, the higher level locations are resolved to code addresses. If there is no code associated with a line of source code, then the resolution path chooses to use the next closest line of source code in the same file. A symbol name breakpoint will only work if the symbol name is found within loaded debug info."; + @p "Breakpoints may have stop conditions attached to them. When a breakpoint is hit by a thread, before it stops execution, the stop condition is evaluated, and if it evaluates to a nonzero value, only then is execution stopped."; + @p "Each breakpoint has a hit count. Every time a breakpoint causes execution to stop, this counter is increased."; + @p "Processor breakpoints are not currently supported, but planned to be in the future."; + + @subtitle "User & Profile Files"; + @p "Applicable state controlling the debugger's appearance, behavior, targets, breakpoints, and other configurations is saved and reloaded across runs of the debugger through both *user files* and *profile files*. These files are auto-saved. These files are written in a textual format which can be hand-edited as necessary, but they're also continuously re-read and re-written by the debugger. By default, the debugger uses `%appdata%/raddbg/default.raddbg_user` for its user file path, and `%appdata%/raddbg/default.raddbg_profile` for its profile file path. These paths can be overridden on the command line (see the 'Command-Line Usage' section)."; + @p "The *user file* defaultly stores file path maps, windows (including their preferred monitor, placement, and size), each window's panel layout and tabs, keybindings, theme colors, and fonts."; + @p "The *profile file* defaultly stores targets, breakpoints, watch pins, and exception code filters."; + @p "Because both can be hand-edited, however, if you want to store something normally stored in a user file in a profile file, or vice versa, this can be done by hand transferring the textual data from one file to another. There is no path in the debugger's UI to support this transfer, currently, although this is planned."; + + //@subtitle "Driving Another Debugger Instance"; + //@p "When the debugger is launched with the `--ipc` command-line argument, it does not launch another instance of the graphical debugger. Instead, it launches, sends a string encoding a command to a running instance of the graphical debugger, and then terminates. The set of commands which can be sent are identical to those which can be run from the debugger's UI itself, but these commands must be encoded textually (through the other command-line arguments). These commands are described in the 'Commands' section."; +} diff --git a/src/df/gfx/df_view_rule_hooks.c b/src/df/gfx/df_view_rule_hooks.c new file mode 100644 index 00000000..7c2a6426 --- /dev/null +++ b/src/df/gfx/df_view_rule_hooks.c @@ -0,0 +1,1251 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Helpers + +internal Vec4F32 +df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_Entity *process) +{ + Vec4F32 rgba = {0}; + Temp scratch = scratch_begin(0, 0); + TG_Key type_key = eval.type_key; + TG_Kind type_kind = tg_kind_from_key(type_key); + switch(type_kind) + { + default:{}break; + + // rjf: extract r/g/b/a bytes from u32 + case TG_Kind_U32: + case TG_Kind_S32: + { + U32 hex_val = (U32)eval.imm_u64; + rgba = rgba_from_u32(hex_val); + }break; + + // rjf: extract r/g/b/a values from array + case TG_Kind_Array: + if(eval.mode == EVAL_EvalMode_Addr) + { + U64 array_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 array_total_size_capped = ClampTop(array_total_size, 64); + Rng1U64 array_memory_vaddr_rng = r1u64(eval.offset, eval.offset + array_total_size_capped); + String8 array_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, array_memory_vaddr_rng); + TG_Key element_type_key = tg_direct_from_graph_raddbg_key(graph, raddbg, type_key); + TG_Kind element_type_kind = tg_kind_from_key(element_type_key); + U64 element_type_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, element_type_key); + for(U64 element_idx = 0; element_idx < 4; element_idx += 1) + { + U64 offset = element_idx*element_type_size; + if(offset >= array_memory.size) + { + break; + } + switch(element_type_kind) + { + default:{}break; + case TG_Kind_U8: + { + U8 byte = array_memory.str[offset]; + rgba.v[element_idx] = byte/255.f; + }break; + case TG_Kind_F32: + { + rgba.v[element_idx] = *(F32 *)(array_memory.str+offset); + }break; + } + } + }break; + + // rjf: extract r/g/b/a values from struct + case TG_Kind_Struct: + case TG_Kind_Class: + case TG_Kind_Union: + if(eval.mode == EVAL_EvalMode_Addr) + { + U64 struct_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 struct_total_size_capped = ClampTop(struct_total_size, 64); + Rng1U64 struct_memory_vaddr_rng = r1u64(eval.offset, eval.offset + struct_total_size_capped); + String8 struct_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, struct_memory_vaddr_rng); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, raddbg, type_key); + for(U64 element_idx = 0, member_idx = 0; + element_idx < 4 && member_idx < type->count; + member_idx += 1) + { + TG_Member *member = &type->members[member_idx]; + TG_Key member_type_key = member->type_key; + TG_Kind member_type_kind = tg_kind_from_key(member_type_key); + B32 member_is_component = 1; + switch(member_type_kind) + { + default:{member_is_component = 0;}break; + case TG_Kind_U8: + { + rgba.v[element_idx] = struct_memory.str[member->off]/255.f; + }break; + case TG_Kind_F32: + { + rgba.v[element_idx] = *(F32 *)(struct_memory.str + member->off); + }break; + } + if(member_is_component) + { + element_idx += 1; + } + } + }break; + } + scratch_end(scratch); + return rgba; +} + +internal void +df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba) +{ + TG_Key type_key = eval.type_key; + TG_Kind type_kind = tg_kind_from_key(type_key); + switch(type_kind) + { + default:{}break; + + // rjf: extract r/g/b/a bytes from u32 + case TG_Kind_U32: + case TG_Kind_S32: + { + U32 val = u32_from_rgba(rgba); + DF_Eval src_eval = eval; + src_eval.mode = EVAL_EvalMode_Value; + src_eval.imm_u64 = (U64)val; + df_commit_eval_value(graph, raddbg, ctrl_ctx, eval, src_eval); + }break; + +#if 0 + // rjf: extract r/g/b/a values from array + case TG_Kind_Array: + if(eval.mode == EVAL_EvalMode_Addr) + { + U64 array_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 array_total_size_capped = ClampTop(array_total_size, 64); + Rng1U64 array_memory_vaddr_rng = r1u64(eval.offset, eval.offset + array_total_size_capped); + String8 array_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, array_memory_vaddr_rng); + TG_Key element_type_key = tg_direct_from_graph_raddbg_key(graph, raddbg, type_key); + TG_Kind element_type_kind = tg_kind_from_key(element_type_key); + U64 element_type_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, element_type_key); + for(U64 element_idx = 0; element_idx < 4; element_idx += 1) + { + U64 offset = element_idx*element_type_size; + if(offset >= array_memory.size) + { + break; + } + switch(element_type_kind) + { + default:{}break; + case TG_Kind_U8: + { + U8 byte = array_memory.str[offset]; + rgba.v[element_idx] = byte/255.f; + }break; + case TG_Kind_F32: + { + rgba.v[element_idx] = *(F32 *)(array_memory.str+offset); + }break; + } + } + }break; + + // rjf: extract r/g/b/a values from struct + case TG_Kind_Struct: + case TG_Kind_Class: + case TG_Kind_Union: + if(eval.mode == EVAL_EvalMode_Addr) + { + U64 struct_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 struct_total_size_capped = ClampTop(struct_total_size, 64); + Rng1U64 struct_memory_vaddr_rng = r1u64(eval.offset, eval.offset + struct_total_size_capped); + String8 struct_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, struct_memory_vaddr_rng); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, raddbg, type_key); + for(U64 element_idx = 0, member_idx = 0; + element_idx < 4 && member_idx < type->count; + member_idx += 1) + { + TG_Member *member = &type->members[member_idx]; + TG_Key member_type_key = member->type_key; + TG_Kind member_type_kind = tg_kind_from_key(member_type_key); + B32 member_is_component = 1; + switch(member_type_kind) + { + default:{member_is_component = 0;}break; + case TG_Kind_U8: + { + rgba.v[element_idx] = struct_memory.str[member->off]/255.f; + }break; + case TG_Kind_F32: + { + rgba.v[element_idx] = *(F32 *)(struct_memory.str + member->off); + }break; + } + if(member_is_component) + { + element_idx += 1; + } + } + }break; +#endif + } +} + +internal DF_BitmapTopologyInfo +df_view_rule_hooks__bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CfgNode *cfg) +{ + Temp scratch = scratch_begin(0, 0); + DF_BitmapTopologyInfo info = {0}; + { + info.fmt = R_Tex2DFormat_RGBA8; + } + { + DF_CfgNode *width_cfg = df_cfg_node_child_from_string(cfg, str8_lit("w"), 0); + DF_CfgNode *height_cfg = df_cfg_node_child_from_string(cfg, str8_lit("h"), 0); + DF_CfgNode *fmt_cfg = df_cfg_node_child_from_string(cfg, str8_lit("fmt"), 0); + String8List width_expr_strs = {0}; + String8List height_expr_strs = {0}; + for(DF_CfgNode *child = width_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &width_expr_strs, child->string); + } + for(DF_CfgNode *child = height_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &height_expr_strs, child->string); + } + String8 width_expr = str8_list_join(scratch.arena, &width_expr_strs, 0); + String8 height_expr = str8_list_join(scratch.arena, &height_expr_strs, 0); + String8 fmt_string = fmt_cfg->first->string; + DF_Eval width_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, width_expr); + DF_Eval width_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, width_eval); + info.width = width_eval_value.imm_u64; + DF_Eval height_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, height_expr); + DF_Eval height_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, height_eval); + info.height = height_eval_value.imm_u64; + if(fmt_string.size != 0) + { + for(R_Tex2DFormat fmt = (R_Tex2DFormat)0; fmt < R_Tex2DFormat_COUNT; fmt = (R_Tex2DFormat)(fmt+1)) + { + if(str8_match(r_tex2d_format_display_string_table[fmt], fmt_string, StringMatchFlag_CaseInsensitive)) + { + info.fmt = fmt; + break; + } + } + } + } + scratch_end(scratch); + return info; +} + +internal DF_GeoTopologyInfo +df_view_rule_hooks__geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CfgNode *cfg) +{ + Temp scratch = scratch_begin(0, 0); + DF_GeoTopologyInfo result = {0}; + { + StringJoin join = {0}; + join.sep = str8_lit(" "); + DF_CfgNode *count_cfg = df_cfg_node_child_from_string(cfg, str8_lit("count"), 0); + DF_CfgNode *vertices_base_cfg = df_cfg_node_child_from_string(cfg, str8_lit("vertices_base"), 0); + DF_CfgNode *vertices_size_cfg = df_cfg_node_child_from_string(cfg, str8_lit("vertices_size"), 0); + String8List count_expr_strs = {0}; + String8List vertices_base_expr_strs = {0}; + String8List vertices_size_expr_strs = {0}; + for(DF_CfgNode *child = count_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &count_expr_strs, child->string); + } + for(DF_CfgNode *child = vertices_base_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &vertices_base_expr_strs, child->string); + } + for(DF_CfgNode *child = vertices_size_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &vertices_size_expr_strs, child->string); + } + String8 count_expr = str8_list_join(scratch.arena, &count_expr_strs, &join); + String8 vertices_base_expr = str8_list_join(scratch.arena, &vertices_base_expr_strs, &join); + String8 vertices_size_expr = str8_list_join(scratch.arena, &vertices_size_expr_strs, &join); + DF_Eval count_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, count_expr); + DF_Eval vertices_base_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, vertices_base_expr); + DF_Eval vertices_size_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, vertices_size_expr); + DF_Eval count_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, count_eval); + DF_Eval vertices_base_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, vertices_base_eval); + DF_Eval vertices_size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, vertices_size_eval); + U64 vertices_base_vaddr = vertices_base_val_eval.imm_u64 ? vertices_base_val_eval.imm_u64 : vertices_base_val_eval.offset; + result.index_count = count_val_eval.imm_u64; + result.vertices_vaddr_range = r1u64(vertices_base_vaddr, vertices_base_vaddr+vertices_size_val_eval.imm_u64); + } + scratch_end(scratch); + return result; +} + +internal DF_TxtTopologyInfo +df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CfgNode *cfg) +{ + Temp scratch = scratch_begin(0, 0); + DF_TxtTopologyInfo result = zero_struct; + { + StringJoin join = {0}; + join.sep = str8_lit(" "); + DF_CfgNode *size_cfg = df_cfg_node_child_from_string(cfg, str8_lit("size"), 0); + DF_CfgNode *lang_cfg = df_cfg_node_child_from_string(cfg, str8_lit("lang"), 0); + String8List size_expr_strs = {0}; + String8 lang_string = {0}; + for(DF_CfgNode *child = size_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &size_expr_strs, child->string); + } + lang_string = lang_cfg->first->string; + String8 size_expr = str8_list_join(scratch.arena, &size_expr_strs, &join); + DF_Eval size_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, size_expr); + DF_Eval size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, size_eval); + result.lang = txt_lang_kind_from_extension(lang_string); + result.size_cap = size_val_eval.imm_u64; + } + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: "array" + +DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array) +{ + Temp scratch = scratch_begin(&arena, 1); + TG_Key type_key = eval.type_key; + TG_Kind type_kind = tg_kind_from_key(type_key); + if(type_kind == TG_Kind_Ptr || type_kind == TG_Kind_LRef || type_kind == TG_Kind_RRef) + { + DF_CfgNode *array_node = val->last; + if(array_node != &df_g_nil_cfg_node) + { + // rjf: determine array size + U64 array_size = 0; + { + String8List array_size_expr_strs = {0}; + for(DF_CfgNode *child = array_node->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &array_size_expr_strs, child->string); + } + String8 array_size_expr = str8_list_join(scratch.arena, &array_size_expr_strs, 0); + DF_Eval array_size_eval = df_eval_from_string(arena, dbgi_scope, ctrl_ctx, parse_ctx, array_size_expr); + DF_Eval array_size_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, array_size_eval); + eval_error_list_concat_in_place(&eval.errors, &array_size_eval.errors); + array_size = array_size_eval_value.imm_u64; + } + + // rjf: apply array size to type + TG_Key pointee = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, type_key); + TG_Key array_type = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Array, pointee, array_size); + eval.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, array_type, 0); + } + } + scratch_end(scratch); + return eval; +} + +//////////////////////////////// +//~ rjf: "list" + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(list) +{ + +} + +DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(list) +{ + +} + +//////////////////////////////// +//~ rjf: "bswap" + +DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(bswap) +{ + Temp scratch = scratch_begin(&arena, 1); + TG_Key type_key = eval.type_key; + TG_Kind type_kind = tg_kind_from_key(type_key); + U64 type_size_bytes = tg_byte_size_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, type_key); + if(TG_Kind_Char8 <= type_kind && type_kind <= TG_Kind_S256 && + (type_size_bytes == 2 || + type_size_bytes == 4 || + type_size_bytes == 8)) + { + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + if(value_eval.mode == EVAL_EvalMode_Value) + { + switch(type_size_bytes) + { + default:{}break; + case 2:{U16 v = (U16)value_eval.imm_u64; v = bswap_u16(v); value_eval.imm_u64 = (U64)v;}break; + case 4:{U32 v = (U32)value_eval.imm_u64; v = bswap_u32(v); value_eval.imm_u64 = (U64)v;}break; + case 8:{U64 v = value_eval.imm_u64; v = bswap_u64(v); value_eval.imm_u64 = v;}break; + } + } + eval = value_eval; + } + scratch_end(scratch); + return eval; +} + +//////////////////////////////// +//~ rjf: "dec" + +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(dec) +{ + +} + +//////////////////////////////// +//~ rjf: "bin" + +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(bin) +{ + +} + +//////////////////////////////// +//~ rjf: "oct" + +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(oct) +{ + +} + +//////////////////////////////// +//~ rjf: "hex" + +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(hex) +{ + +} + +//////////////////////////////// +//~ rjf: "only" + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(only) +{ + +} + +DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(only) +{ + +} + +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(only) +{ + +} + +//////////////////////////////// +//~ rjf: "omit" + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(omit) +{ + +} + +DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(omit) +{ + +} + +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(omit) +{ + +} + +//////////////////////////////// +//~ rjf: "no_addr" + +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(no_addr) +{ +} + +//////////////////////////////// +//~ rjf: "rgba" + +typedef struct DF_ViewRuleHooks_RGBAState DF_ViewRuleHooks_RGBAState; +struct DF_ViewRuleHooks_RGBAState +{ + Vec4F32 hsva; + U64 memgen_idx; +}; + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(rgba) +{ + DF_EvalVizBlock *block = push_array(arena, DF_EvalVizBlock, 1); + block->kind = DF_EvalVizBlockKind_Canvas; + block->eval_view = eval_view; + block->eval = eval; + block->cfg_table = *cfg_table; + block->parent_key = key; + block->key = df_expand_key_make((U64)eval_view, df_hash_from_expand_key(key), 1); + block->visual_idx_range = r1u64(0, 8); + block->semantic_idx_range = r1u64(0, 1); + block->depth = depth; + SLLQueuePush(out->first, out->last, block); + out->count += 1; + out->total_visual_row_count += 8; + out->total_semantic_row_count += 1; +} + +DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(rgba) +{ + Temp scratch = scratch_begin(0, 0); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + //- rjf: grab hsva + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + Vec4F32 rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdbg, process); + Vec4F32 hsva = hsva_from_rgba(rgba); + + //- rjf: build text box + UI_Box *text_box = &ui_g_nil_box; + UI_WidthFill UI_Font(df_font_from_slot(DF_FontSlot_Code)) + { + text_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + D_FancyStringList fancy_strings = {0}; + { + D_FancyString open_paren = {ui_top_font(), str8_lit("("), ui_top_text_color(), ui_top_font_size(), 0, 0}; + D_FancyString comma = {ui_top_font(), str8_lit(", "), ui_top_text_color(), ui_top_font_size(), 0, 0}; + D_FancyString r_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.x), v4f32(1.f, 0.25f, 0.25f, 1.f), ui_top_font_size(), 4.f, 0}; + D_FancyString g_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.y), v4f32(0.25f, 1.f, 0.25f, 1.f), ui_top_font_size(), 4.f, 0}; + D_FancyString b_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.z), v4f32(0.25f, 0.25f, 1.f, 1.f), ui_top_font_size(), 4.f, 0}; + D_FancyString a_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.w), v4f32(1.f, 1.f, 1.f, 1.f), ui_top_font_size(), 4.f, 0}; + D_FancyString clse_paren = {ui_top_font(), str8_lit(")"), ui_top_text_color(), ui_top_font_size(), 0, 0}; + d_fancy_string_list_push(scratch.arena, &fancy_strings, &open_paren); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &r_fstr); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &comma); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &g_fstr); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &comma); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &b_fstr); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &comma); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &a_fstr); + d_fancy_string_list_push(scratch.arena, &fancy_strings, &clse_paren); + } + ui_box_equip_display_fancy_strings(text_box, &fancy_strings); + } + + //- rjf: build color box + UI_Box *color_box = &ui_g_nil_box; + UI_PrefWidth(ui_em(1.875f, 1.f)) UI_ChildLayoutAxis(Axis2_Y) + { + color_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "color_box"); + UI_Parent(color_box) UI_PrefHeight(ui_em(1.875f, 1.f)) UI_Padding(ui_pct(1, 0)) + { + UI_BackgroundColor(rgba) UI_CornerRadius(ui_top_font_size()*0.5f) + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); + } + } + + //- rjf: space + ui_spacer(ui_em(0.375f, 1.f)); + + //- rjf: hover color box -> show components + UI_Signal sig = ui_signal_from_box(color_box); + if(sig.hovering) + { + ui_do_color_tooltip_hsva(hsva); + } + + scratch_end(scratch); +} + +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) +{ + Temp scratch = scratch_begin(0, 0); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_ViewRuleHooks_RGBAState *state = df_view_rule_block_user_state(key, DF_ViewRuleHooks_RGBAState); + + //- rjf: grab hsva + Vec4F32 rgba = {0}; + Vec4F32 hsva = {0}; + { + if(state->memgen_idx >= ctrl_memgen_idx()) + { + hsva = state->hsva; + rgba = rgba_from_hsva(hsva); + } + else + { + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdbg, process); + state->hsva = hsva = hsva_from_rgba(rgba); + state->memgen_idx = ctrl_memgen_idx(); + } + } + Vec4F32 initial_hsva = hsva; + + //- rjf: build color picker + B32 commit = 0; + UI_Padding(ui_pct(1.f, 0.f)) + { + UI_PrefWidth(ui_px(dim.y, 1.f)) + { + UI_Signal sv_sig = ui_sat_val_pickerf(hsva.x, &hsva.y, &hsva.z, "sat_val_picker"); + commit = commit || sv_sig.released; + } + UI_PrefWidth(ui_em(3.f, 1.f)) + { + UI_Signal h_sig = ui_hue_pickerf(&hsva.x, hsva.y, hsva.z, "hue_picker"); + commit = commit || h_sig.released; + } + UI_PrefWidth(ui_children_sum(1)) UI_Column UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + ui_labelf("Hex"); + ui_labelf("R"); + ui_labelf("G"); + ui_labelf("B"); + ui_labelf("H"); + ui_labelf("S"); + ui_labelf("V"); + ui_labelf("A"); + } + UI_PrefWidth(ui_children_sum(1)) UI_Column UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) + { + String8 hex_string = hex_string_from_rgba_4f32(scratch.arena, rgba); + ui_label(hex_string); + ui_labelf("%.2f", rgba.x); + ui_labelf("%.2f", rgba.y); + ui_labelf("%.2f", rgba.z); + ui_labelf("%.2f", hsva.x); + ui_labelf("%.2f", hsva.y); + ui_labelf("%.2f", hsva.z); + ui_labelf("%.2f", rgba.w); + } + } + + //- rjf: commit edited hsva back + if(commit) + { + Vec4F32 rgba = rgba_from_hsva(hsva); + df_view_rule_hooks__eval_commit_rgba(eval, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, rgba); + state->memgen_idx = ctrl_memgen_idx(); + } + + //- rjf: commit possible edited value to state + state->hsva = hsva; + + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: "text" + +typedef struct DF_ViewRuleHooks_TextState DF_ViewRuleHooks_TextState; +struct DF_ViewRuleHooks_TextState +{ + B32 initialized; + TxtPt cursor; + TxtPt mark; + S64 preferred_column; + U64 last_open_frame_idx; + F32 loaded_t; +}; + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(text) +{ + DF_EvalVizBlock *block = push_array(arena, DF_EvalVizBlock, 1); + block->kind = DF_EvalVizBlockKind_Canvas; + block->eval_view = eval_view; + block->eval = eval; + block->cfg_table = *cfg_table; + block->parent_key = key; + block->key = df_expand_key_make((U64)eval_view, df_hash_from_expand_key(key), 1); + block->visual_idx_range = r1u64(0, 8); + block->semantic_idx_range = r1u64(0, 1); + block->depth = depth; + SLLQueuePush(out->first, out->last, block); + out->count += 1; + out->total_visual_row_count += 8; + out->total_semantic_row_count += 1; +} + +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text) +{ + Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); + DF_ViewRuleHooks_TextState *state = df_view_rule_block_user_state(key, DF_ViewRuleHooks_TextState); + if(!state->initialized) + { + state->initialized = 1; + state->cursor = state->mark = txt_pt(1, 1); + } + if(state->last_open_frame_idx+1 < df_frame_index()) + { + state->loaded_t = 0; + } + state->last_open_frame_idx = df_frame_index(); + { + //- rjf: unpack params + DF_TxtTopologyInfo top = df_view_rule_hooks__txt_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, cfg); + + //- rjf: resolve to address value & range + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr + (top.size_cap ? top.size_cap : 2048)); + + //- rjf: unpack thread/process of eval + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + //- rjf: unique identifying info about this address -> unique key + U128 text_key = {0}; + { + U64 data[] = + { + (U64)process->ctrl_machine_id, + (U64)process->ctrl_handle.u64[0], + vaddr_range.min, + vaddr_range.max, + }; + text_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); + } + + //- rjf: address range -> hash + U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 1); + + //- rjf: hash -> data + String8 data = hs_data_from_hash(hs_scope, hash); + + //- rjf: key * hash -> parsed text info + TXT_TextInfo info = txt_text_info_from_key_hash_lang(txt_scope, text_key, hash, top.lang); + + //- rjf: info -> code slice info + DF_CodeSliceParams code_slice_params = {0}; + { + code_slice_params.flags = DF_CodeSliceFlag_LineNums; + code_slice_params.line_num_range = r1s64(1, info.lines_count); + code_slice_params.line_text = push_array(scratch.arena, String8, info.lines_count); + code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, info.lines_count); + code_slice_params.line_tokens = push_array(scratch.arena, TXTI_TokenArray, info.lines_count); + code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, info.lines_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, info.lines_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, info.lines_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, info.lines_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, info.lines_count); + for(U64 line_idx = 0; line_idx < info.lines_count; line_idx += 1) + { + code_slice_params.line_text[line_idx] = str8_substr(data, info.lines_ranges[line_idx]); + code_slice_params.line_ranges[line_idx] = info.lines_ranges[line_idx]; + } + code_slice_params.font = df_font_from_slot(DF_FontSlot_Code); + code_slice_params.font_size = ui_top_font_size(); + code_slice_params.line_height_px = ui_top_font_size()*1.5f; + code_slice_params.margin_width_px = 0; + code_slice_params.line_num_width_px = ui_top_font_size()*5.f; + code_slice_params.line_text_max_width_px = ui_top_font_size()*2.f*info.lines_max_size; + } + + //- rjf: build code slice + if(info.lines_count != 0) UI_Padding(ui_pct(1, 0)) UI_PrefWidth(ui_px(info.lines_max_size*ui_top_font_size()*1.2f, 1.f)) UI_Column UI_Padding(ui_pct(1, 0)) + { + DF_CodeSliceSignal sig = df_code_slice(ws, ctrl_ctx, parse_ctx, &code_slice_params, &state->cursor, &state->mark, &state->preferred_column, str8_lit("###code_slice")); + } + } + txt_scope_close(txt_scope); + hs_scope_close(hs_scope); + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: "disasm" + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(disasm) +{ + DF_EvalVizBlock *block = push_array(arena, DF_EvalVizBlock, 1); + block->kind = DF_EvalVizBlockKind_Canvas; + block->eval_view = eval_view; + block->eval = eval; + block->cfg_table = *cfg_table; + block->parent_key = key; + block->key = df_expand_key_make((U64)eval_view, df_hash_from_expand_key(key), 1); + block->visual_idx_range = r1u64(0, 8); + block->semantic_idx_range = r1u64(0, 1); + block->depth = depth; + SLLQueuePush(out->first, out->last, block); + out->count += 1; + out->total_visual_row_count += 8; + out->total_semantic_row_count += 1; +} + +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm) +{ + +} + +//////////////////////////////// +//~ rjf: "bitmap" + +typedef struct DF_ViewRuleHooks_BitmapState DF_ViewRuleHooks_BitmapState; +struct DF_ViewRuleHooks_BitmapState +{ + U64 last_open_frame_idx; + F32 loaded_t; +}; + +typedef struct DF_ViewRuleHooks_BitmapBoxDrawData DF_ViewRuleHooks_BitmapBoxDrawData; +struct DF_ViewRuleHooks_BitmapBoxDrawData +{ + Rng2F32 src; + R_Handle texture; + F32 loaded_t; + B32 hovered; + Vec2S32 mouse_px; + F32 ui_per_bmp_px; +}; + +typedef struct DF_ViewRuleHooks_BitmapZoomDrawData DF_ViewRuleHooks_BitmapZoomDrawData; +struct DF_ViewRuleHooks_BitmapZoomDrawData +{ + Rng2F32 src; + R_Handle texture; +}; + +internal UI_BOX_CUSTOM_DRAW(df_view_rule_hooks__bitmap_box_draw) +{ + DF_ViewRuleHooks_BitmapBoxDrawData *draw_data = (DF_ViewRuleHooks_BitmapBoxDrawData *)user_data; + Vec4F32 bg_color = box->background_color; + d_img(box->rect, draw_data->src, draw_data->texture, v4f32(1, 1, 1, 1), 0, 0, 0); + if(draw_data->loaded_t < 0.98f) + { + Rng2F32 clip = box->rect; + for(UI_Box *b = box->parent; !ui_box_is_nil(b); b = b->parent) + { + if(b->flags & UI_BoxFlag_Clip) + { + clip = intersect_2f32(b->rect, clip); + } + } + d_blur(intersect_2f32(clip, box->rect), 10.f-9.f*draw_data->loaded_t, 0); + } + if(r_handle_match(draw_data->texture, r_handle_zero())) + { + d_rect(box->rect, v4f32(0, 0, 0, 1), 0, 0, 0); + } + d_rect(box->rect, v4f32(bg_color.x*bg_color.w, bg_color.y*bg_color.w, bg_color.z*bg_color.w, 1.f-draw_data->loaded_t), 0, 0, 0); + if(draw_data->hovered) + { + Vec4F32 indicator_color = df_rgba_from_theme_color(DF_ThemeColor_PlainBorder); + indicator_color.w = 1.f; + d_rect(pad_2f32(r2f32p(box->rect.x0 + draw_data->mouse_px.x*draw_data->ui_per_bmp_px, + box->rect.y0 + draw_data->mouse_px.y*draw_data->ui_per_bmp_px, + box->rect.x0 + draw_data->mouse_px.x*draw_data->ui_per_bmp_px + draw_data->ui_per_bmp_px, + box->rect.y0 + draw_data->mouse_px.y*draw_data->ui_per_bmp_px + draw_data->ui_per_bmp_px), + 3.f), + indicator_color, 3.f, 4.f, 1.f); + } +} + +internal UI_BOX_CUSTOM_DRAW(df_view_rule_hooks__bitmap_zoom_draw) +{ + DF_ViewRuleHooks_BitmapZoomDrawData *draw_data = (DF_ViewRuleHooks_BitmapZoomDrawData *)user_data; + d_img(box->rect, draw_data->src, draw_data->texture, v4f32(1, 1, 1, 1), 0, 0, 0); +} + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(bitmap) +{ + DF_EvalVizBlock *block = push_array(arena, DF_EvalVizBlock, 1); + block->kind = DF_EvalVizBlockKind_Canvas; + block->eval_view = eval_view; + block->eval = eval; + block->cfg_table = *cfg_table; + block->parent_key = key; + block->key = df_expand_key_make((U64)eval_view, df_hash_from_expand_key(key), 1); + block->visual_idx_range = r1u64(0, 8); + block->semantic_idx_range = r1u64(0, 1); + block->depth = depth; + SLLQueuePush(out->first, out->last, block); + out->count += 1; + out->total_visual_row_count += 8; + out->total_semantic_row_count += 1; +} + +DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(bitmap) +{ + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + DF_BitmapTopologyInfo topology = df_view_rule_hooks__bitmap_topology_info_from_cfg(scope, ctrl_ctx, parse_ctx, cfg); + U64 expected_size = topology.width*topology.height*r_tex2d_format_bytes_per_pixel_table[topology.fmt]; + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_labelf("0x%I64x -> Bitmap (%I64u x %I64u)", base_vaddr, topology.width, topology.height); +} + +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) +{ + Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); + TEX_Scope *tex_scope = tex_scope_open(); + DF_ViewRuleHooks_BitmapState *state = df_view_rule_block_user_state(key, DF_ViewRuleHooks_BitmapState); + if(state->last_open_frame_idx+1 < df_frame_index()) + { + state->loaded_t = 0; + } + state->last_open_frame_idx = df_frame_index(); + + //- rjf: resolve to address value + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + + //- rjf: unpack thread/process of eval + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + //- rjf: unpack image dimensions & form vaddr range + DF_BitmapTopologyInfo topology_info = df_view_rule_hooks__bitmap_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, cfg); + U64 expected_size = topology_info.width*topology_info.height*r_tex2d_format_bytes_per_pixel_table[topology_info.fmt]; + Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr+expected_size); + + //- rjf: unique identifying info about this address -> unique key + U128 texture_key = {0}; + { + U64 data[] = + { + (U64)process->ctrl_machine_id, + (U64)process->ctrl_handle.u64[0], + vaddr_range.min, + vaddr_range.max, + }; + texture_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); + } + + //- rjf: address range -> hash + U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0); + + //- rjf: hash & topology -> texture + TEX_Topology topology = tex_topology_make(v2s32((S32)topology_info.width, (S32)topology_info.height), topology_info.fmt); + R_Handle texture = tex_texture_from_key_hash_topology(tex_scope, texture_key, hash, topology); + + //- rjf: build preview + F32 rate = 1 - pow_f32(2, (-15.f * df_dt())); + if(expected_size != 0) + { + UI_Padding(ui_pct(1.f, 0.f)) + UI_PrefWidth(ui_px(dim.y*((F32)topology_info.width/(F32)topology_info.height), 1.f)) + UI_Column UI_Padding(ui_pct(1.f, 0.f)) + UI_PrefHeight(ui_px(dim.y, 1.f)) + { + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable|UI_BoxFlag_DrawHotEffects, "image_box"); + UI_Signal sig = ui_signal_from_box(box); + F32 ui_per_bmp_px = dim.y / (F32)topology_info.height; + Vec2F32 mouse_ui_px_off = sub_2f32(ui_mouse(), box->rect.p0); + Vec2S32 mouse_bitmap_px_off = v2s32(floor_f32(mouse_ui_px_off.x/ui_per_bmp_px), floor_f32(mouse_ui_px_off.y/ui_per_bmp_px)); + DF_ViewRuleHooks_BitmapBoxDrawData *draw_data = push_array(ui_build_arena(), DF_ViewRuleHooks_BitmapBoxDrawData, 1); + draw_data->texture = texture; + draw_data->src = r2f32(v2f32(0, 0), v2f32((F32)topology_info.width, (F32)topology_info.height)); + draw_data->loaded_t = state->loaded_t; + draw_data->hovered = sig.hovering; + draw_data->mouse_px = mouse_bitmap_px_off; + draw_data->ui_per_bmp_px = ui_per_bmp_px; + ui_box_equip_custom_draw(box, df_view_rule_hooks__bitmap_box_draw, draw_data); + if(r_handle_match(r_handle_zero(), texture)) + { + df_gfx_request_frame(); + state->loaded_t = 0; + } + else + { + state->loaded_t += (1.f - state->loaded_t) * rate; + if(state->loaded_t < 0.99f) + { + df_gfx_request_frame(); + } + } + if(sig.hovering) + { + if(dim.y > (F32)topology_info.height) + { + String8 data = hs_data_from_hash(hs_scope, hash); + U64 bytes_per_pixel = r_tex2d_format_bytes_per_pixel_table[topology.fmt]; + U64 mouse_pixel_off = mouse_bitmap_px_off.y*topology_info.width + mouse_bitmap_px_off.x; + U64 mouse_byte_off = mouse_pixel_off * bytes_per_pixel; + B32 got_color = 0; + Vec4F32 hsva = {0}; + if(mouse_byte_off + bytes_per_pixel <= data.size) + { + got_color = 1; + switch(topology.fmt) + { + default:{got_color = 0;}break; + case R_Tex2DFormat_RGBA8: + { + U8 r = data.str[mouse_byte_off+0]; + U8 g = data.str[mouse_byte_off+1]; + U8 b = data.str[mouse_byte_off+2]; + U8 a = data.str[mouse_byte_off+3]; + Vec4F32 rgba = v4f32(r/255.f, g/255.f, b/255.f, a/255.f); + hsva = hsva_from_rgba(rgba); + }break; + case R_Tex2DFormat_BGRA8: + { + U8 r = data.str[mouse_byte_off+2]; + U8 g = data.str[mouse_byte_off+1]; + U8 b = data.str[mouse_byte_off+0]; + U8 a = data.str[mouse_byte_off+3]; + Vec4F32 rgba = v4f32(r/255.f, g/255.f, b/255.f, a/255.f); + hsva = hsva_from_rgba(rgba); + }break; + case R_Tex2DFormat_R8: + { + U8 r = data.str[mouse_byte_off+0]; + Vec4F32 rgba = v4f32(r/255.f, 0, 0, 1.f); + hsva = hsva_from_rgba(rgba); + }break; + } + } + if(got_color) + { + ui_do_color_tooltip_hsva(hsva); + } + } + else UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Code)) + { + ui_label(r_tex2d_format_display_string_table[topology.fmt]); + ui_labelf("%I64u x %I64u", topology_info.width, topology_info.height); + UI_Padding(ui_em(2.f, 1.f)) + UI_PrefWidth(ui_children_sum(1.f)) + UI_PrefHeight(ui_children_sum(1.f)) + UI_Row + UI_PrefWidth(ui_em(15.f, 1.f)) + UI_PrefHeight(ui_em(15.f, 1.f)) + UI_Padding(ui_em(2.f, 1.f)) + { + UI_Box *zoom_box = ui_build_box_from_key(UI_BoxFlag_DrawBorder, ui_key_zero()); + DF_ViewRuleHooks_BitmapZoomDrawData *draw_data = push_array(ui_build_arena(), DF_ViewRuleHooks_BitmapZoomDrawData, 1); + draw_data->src = r2f32p(mouse_bitmap_px_off.x - 16, mouse_bitmap_px_off.y - 16, mouse_bitmap_px_off.x + 16, mouse_bitmap_px_off.y + 16); + draw_data->texture = texture; + ui_box_equip_custom_draw(zoom_box, df_view_rule_hooks__bitmap_zoom_draw, draw_data); + } + } + } + } + } + + tex_scope_close(tex_scope); + hs_scope_close(hs_scope); + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: "geo" + +typedef struct DF_ViewRuleHooks_GeoState DF_ViewRuleHooks_GeoState; +struct DF_ViewRuleHooks_GeoState +{ + B32 initialized; + U64 last_open_frame_idx; + F32 loaded_t; + F32 pitch; + F32 pitch_target; + F32 yaw; + F32 yaw_target; + F32 zoom; + F32 zoom_target; +}; + +typedef struct DF_ViewRuleHooks_GeoBoxDrawData DF_ViewRuleHooks_GeoBoxDrawData; +struct DF_ViewRuleHooks_GeoBoxDrawData +{ + DF_ExpandKey key; + R_Handle vertex_buffer; + R_Handle index_buffer; + F32 loaded_t; +}; + +internal UI_BOX_CUSTOM_DRAW(df_view_rule_hooks__geo_box_draw) +{ + DF_ViewRuleHooks_GeoBoxDrawData *draw_data = (DF_ViewRuleHooks_GeoBoxDrawData *)user_data; + DF_ViewRuleHooks_GeoState *state = df_view_rule_block_user_state(draw_data->key, DF_ViewRuleHooks_GeoState); + Vec4F32 bg_color = box->background_color; + + // rjf: get clip + Rng2F32 clip = box->rect; + for(UI_Box *b = box->parent; !ui_box_is_nil(b); b = b->parent) + { + if(b->flags & UI_BoxFlag_Clip) + { + clip = intersect_2f32(b->rect, clip); + } + } + + // rjf: calculate eye/target + Vec3F32 target = {0}; + Vec3F32 eye = v3f32(state->zoom*cos_f32(state->yaw)*sin_f32(state->pitch), + state->zoom*sin_f32(state->yaw)*sin_f32(state->pitch), + state->zoom*cos_f32(state->pitch)); + + // rjf: mesh + Vec2F32 box_dim = dim_2f32(box->rect); + R_PassParams_Geo3D *pass = d_geo3d_begin(box->rect, + make_look_at_4x4f32(eye, target, v3f32(0, 0, 1)), + make_perspective_4x4f32(0.25f, box_dim.x/box_dim.y, 0.1f, 500.f)); + pass->clip = clip; + d_mesh(draw_data->vertex_buffer, draw_data->index_buffer, R_GeoTopologyKind_Triangles, R_GeoVertexFlag_TexCoord|R_GeoVertexFlag_Normals|R_GeoVertexFlag_RGB, r_handle_zero(), mat_4x4f32(1.f)); + + // rjf: blur + if(draw_data->loaded_t < 0.98f) + { + d_blur(intersect_2f32(clip, box->rect), 10.f-9.f*draw_data->loaded_t, 0); + } +} + +DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(geo) +{ + DF_EvalVizBlock *block = push_array(arena, DF_EvalVizBlock, 1); + block->kind = DF_EvalVizBlockKind_Canvas; + block->eval_view = eval_view; + block->eval = eval; + block->cfg_table = *cfg_table; + block->parent_key = key; + block->key = df_expand_key_make((U64)eval_view, df_hash_from_expand_key(key), 1); + block->visual_idx_range = r1u64(0, 16); + block->semantic_idx_range = r1u64(0, 1); + block->depth = depth; + SLLQueuePush(out->first, out->last, block); + out->count += 1; + out->total_visual_row_count += 16; + out->total_semantic_row_count += 1; +} + +DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(geo) +{ + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_labelf("0x%I64x -> Geometry", base_vaddr); +} + +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo) +{ + Temp scratch = scratch_begin(0, 0); + GEO_Scope *geo_scope = geo_scope_open(); + DF_ViewRuleHooks_GeoState *state = df_view_rule_block_user_state(key, DF_ViewRuleHooks_GeoState); + if(!state->initialized) + { + state->initialized = 1; + state->zoom_target = 3.5f; + state->yaw = state->yaw_target = -0.125f; + state->pitch = state->pitch_target = -0.125f; + } + if(state->last_open_frame_idx+1 < df_frame_index()) + { + state->loaded_t = 0; + } + state->last_open_frame_idx = df_frame_index(); + + //- rjf: resolve to address value + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + + //- rjf: extract extra geo topology info from view rule + DF_GeoTopologyInfo top = df_view_rule_hooks__geo_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, cfg); + Rng1U64 index_buffer_vaddr_range = r1u64(base_vaddr, base_vaddr+top.index_count*sizeof(U32)); + Rng1U64 vertex_buffer_vaddr_range = top.vertices_vaddr_range; + + //- rjf: unpack thread/process of eval + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + //- rjf: produce unique keys for index buffer + U128 index_buffer_key = {0}; + { + U64 data[] = + { + (U64)process->ctrl_machine_id, + (U64)process->ctrl_handle.u64[0], + index_buffer_vaddr_range.min, + index_buffer_vaddr_range.max, + }; + index_buffer_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); + } + + //- rjf: produce unique keys for vertex buffer + U128 vertex_buffer_key = {0}; + { + U64 data[] = + { + (U64)process->ctrl_machine_id, + (U64)process->ctrl_handle.u64[0], + vertex_buffer_vaddr_range.min, + vertex_buffer_vaddr_range.max, + }; + vertex_buffer_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); + } + + //- rjf: address range -> hash + U128 index_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, index_buffer_vaddr_range, 0); + U128 vertex_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vertex_buffer_vaddr_range, 0); + + //- rjf: get gpu buffers + R_Handle index_buffer = geo_buffer_from_key_hash(geo_scope, index_buffer_key, index_buffer_hash); + R_Handle vertex_buffer = geo_buffer_from_key_hash(geo_scope, vertex_buffer_key, vertex_buffer_hash); + + //- rjf: build preview + F32 rate = 1 - pow_f32(2, (-15.f * df_dt())); + if(top.index_count != 0) + { + UI_Padding(ui_pct(1.f, 0.f)) + UI_PrefWidth(ui_px(dim.y, 1.f)) + UI_Column UI_Padding(ui_pct(1.f, 0.f)) + UI_PrefHeight(ui_px(dim.y, 1.f)) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "geo_box"); + UI_Signal sig = ui_signal_from_box(box); + if(sig.dragging) + { + if(sig.pressed) + { + Vec2F32 data = v2f32(state->yaw_target, state->pitch_target); + ui_store_drag_struct(&data); + } + Vec2F32 drag_delta = ui_drag_delta(); + Vec2F32 drag_start_data = *ui_get_drag_struct(Vec2F32); + state->yaw_target = drag_start_data.x + drag_delta.x/dim_2f32(box->rect).x; + state->pitch_target = drag_start_data.y + drag_delta.y/dim_2f32(box->rect).y; + } + state->zoom += (state->zoom_target - state->zoom) * rate; + state->yaw += (state->yaw_target - state->yaw) * rate; + state->pitch += (state->pitch_target - state->pitch) * rate; + if(abs_f32(state->zoom-state->zoom_target) > 0.001f || + abs_f32(state->yaw-state->yaw_target) > 0.001f || + abs_f32(state->pitch-state->pitch_target) > 0.001f) + { + df_gfx_request_frame(); + } + DF_ViewRuleHooks_GeoBoxDrawData *draw_data = push_array(ui_build_arena(), DF_ViewRuleHooks_GeoBoxDrawData, 1); + draw_data->key = key; + draw_data->vertex_buffer = vertex_buffer; + draw_data->index_buffer = index_buffer; + draw_data->loaded_t = state->loaded_t; + ui_box_equip_custom_draw(box, df_view_rule_hooks__geo_box_draw, draw_data); + if(r_handle_match(r_handle_zero(), vertex_buffer)) + { + df_gfx_request_frame(); + state->loaded_t = 0; + } + else + { + state->loaded_t += (1.f - state->loaded_t) * rate; + if(state->loaded_t < 0.99f) + { + df_gfx_request_frame(); + } + } + } + } + + geo_scope_close(geo_scope); + scratch_end(scratch); +} diff --git a/src/df/gfx/df_view_rule_hooks.h b/src/df/gfx/df_view_rule_hooks.h new file mode 100644 index 00000000..aae2d2fb --- /dev/null +++ b/src/df/gfx/df_view_rule_hooks.h @@ -0,0 +1,41 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DF_VIEW_RULE_HOOKS_H +#define DF_VIEW_RULE_HOOKS_H + +//////////////////////////////// +//~ rjf: Helper Types + +typedef struct DF_BitmapTopologyInfo DF_BitmapTopologyInfo; +struct DF_BitmapTopologyInfo +{ + U64 width; + U64 height; + R_Tex2DFormat fmt; +}; + +typedef struct DF_GeoTopologyInfo DF_GeoTopologyInfo; +struct DF_GeoTopologyInfo +{ + U64 index_count; + Rng1U64 vertices_vaddr_range; +}; + +typedef struct DF_TxtTopologyInfo DF_TxtTopologyInfo; +struct DF_TxtTopologyInfo +{ + TXT_LangKind lang; + U64 size_cap; +}; + +//////////////////////////////// +//~ rjf: Helpers + +internal Vec4F32 df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg); +internal void df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba); +internal DF_BitmapTopologyInfo df_view_rule_hooks__bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CfgNode *cfg); +internal DF_GeoTopologyInfo df_view_rule_hooks__geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CfgNode *cfg); +internal DF_TxtTopologyInfo df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CfgNode *cfg); + +#endif //DF_VIEW_RULE_HOOKS_H diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c new file mode 100644 index 00000000..fb85d352 --- /dev/null +++ b/src/df/gfx/df_views.c @@ -0,0 +1,8855 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Quick Sort Comparisons + +internal int +df_qsort_compare_file_info__default(DF_FileInfo *a, DF_FileInfo *b) +{ + int result = 0; + if(a->props.flags & FilePropertyFlag_IsFolder && !(b->props.flags & FilePropertyFlag_IsFolder)) + { + result = -1; + } + else if(b->props.flags & FilePropertyFlag_IsFolder && !(a->props.flags & FilePropertyFlag_IsFolder)) + { + result = +1; + } + else + { + result = df_qsort_compare_file_info__filename(a, b); + } + return result; +} + +internal int +df_qsort_compare_file_info__default_filtered(DF_FileInfo *a, DF_FileInfo *b) +{ + int result = 0; + if(a->filename.size < b->filename.size) + { + result = -1; + } + else if(a->filename.size > b->filename.size) + { + result = +1; + } + return result; +} + +internal int +df_qsort_compare_file_info__filename(DF_FileInfo *a, DF_FileInfo *b) +{ + return strncmp((char *)a->filename.str, (char *)b->filename.str, Min(a->filename.size, b->filename.size)); +} + +internal int +df_qsort_compare_file_info__last_modified(DF_FileInfo *a, DF_FileInfo *b) +{ + return ((a->props.modified < b->props.modified) ? -1 : + (a->props.modified > b->props.modified) ? +1 : + 0); +} + +internal int +df_qsort_compare_file_info__size(DF_FileInfo *a, DF_FileInfo *b) +{ + return ((a->props.size < b->props.size) ? -1 : + (a->props.size > b->props.size) ? +1 : + 0); +} + +internal int +df_qsort_compare_process_info(DF_ProcessInfo *a, DF_ProcessInfo *b) +{ + int result = 0; + if(a->pid_match_ranges.count > b->pid_match_ranges.count) + { + result = -1; + } + else if(a->pid_match_ranges.count < b->pid_match_ranges.count) + { + result = +1; + } + else if(a->name_match_ranges.count < b->name_match_ranges.count) + { + result = -1; + } + else if(a->name_match_ranges.count > b->name_match_ranges.count) + { + result = +1; + } + else if(a->attached_match_ranges.count < b->attached_match_ranges.count) + { + result = -1; + } + else if(a->attached_match_ranges.count > b->attached_match_ranges.count) + { + result = +1; + } + return result; +} + +internal int +df_qsort_compare_cmd_lister__strength(DF_CmdListerItem *a, DF_CmdListerItem *b) +{ + int result = 0; + if(a->name_match_ranges.count > b->name_match_ranges.count) + { + result = -1; + } + else if(a->name_match_ranges.count < b->name_match_ranges.count) + { + result = +1; + } + else if(a->desc_match_ranges.count > b->desc_match_ranges.count) + { + result = -1; + } + else if(a->desc_match_ranges.count < b->desc_match_ranges.count) + { + result = +1; + } + else if(a->tags_match_ranges.count > b->tags_match_ranges.count) + { + result = -1; + } + else if(a->tags_match_ranges.count < b->tags_match_ranges.count) + { + result = +1; + } + else if(a->registrar_idx < b->registrar_idx) + { + result = -1; + } + else if(a->registrar_idx > b->registrar_idx) + { + result = +1; + } + else if(a->ordering_idx < b->ordering_idx) + { + result = -1; + } + else if(a->ordering_idx > b->ordering_idx) + { + result = +1; + } + return result; +} + +internal int +df_qsort_compare_entity_lister__strength(DF_EntityListerItem *a, DF_EntityListerItem *b) +{ + int result = 0; + if(a->name_match_ranges.count > b->name_match_ranges.count) + { + result = -1; + } + else if(a->name_match_ranges.count < b->name_match_ranges.count) + { + result = +1; + } + return result; +} + +//////////////////////////////// +//~ rjf: Command Lister + +internal DF_CmdListerItemList +df_cmd_lister_item_list_from_needle(Arena *arena, String8 needle) +{ + Temp scratch = scratch_begin(&arena, 1); + DF_CmdSpecList specs = df_push_cmd_spec_list(scratch.arena); + DF_CmdListerItemList result = {0}; + + //- rjf: get search needles + String8List search_needles = {0}; + { + U8 splits[] = {' '}; + search_needles = str8_split(scratch.arena, needle, splits, ArrayCount(splits), 0); + } + + //- rjf: build filtered list of commands + for(DF_CmdSpecNode *n = specs.first; n != 0; n = n->next) + { + DF_CmdSpec *spec = n->spec; + if(!(spec->info.flags & DF_CmdSpecFlag_OmitFromLists)) + { + String8 cmd_display_name = spec->info.display_name; + String8 cmd_desc = spec->info.description; + String8 cmd_tags = spec->info.search_tags; + DF_FuzzyMatchRangeList name_matches = df_fuzzy_match_find(arena, search_needles, cmd_display_name); + DF_FuzzyMatchRangeList desc_matches = df_fuzzy_match_find(arena, search_needles, cmd_desc); + DF_FuzzyMatchRangeList tags_matches = df_fuzzy_match_find(arena, search_needles, cmd_tags); + if(name_matches.count == search_needles.node_count || + desc_matches.count == search_needles.node_count || + tags_matches.count > 0 || + search_needles.node_count == 0) + { + DF_CmdListerItemNode *node = push_array(arena, DF_CmdListerItemNode, 1); + node->item.cmd_spec = spec; + node->item.registrar_idx = spec->registrar_index; + node->item.ordering_idx = spec->ordering_index; + node->item.name_match_ranges = name_matches; + node->item.desc_match_ranges = desc_matches; + node->item.tags_match_ranges = tags_matches; + SLLQueuePush(result.first, result.last, node); + result.count += 1; + } + } + } + + scratch_end(scratch); + return result; +} + +internal DF_CmdListerItemArray +df_cmd_lister_item_array_from_list(Arena *arena, DF_CmdListerItemList list) +{ + DF_CmdListerItemArray result = {0}; + result.count = list.count; + result.v = push_array(arena, DF_CmdListerItem, result.count); + U64 idx = 0; + for(DF_CmdListerItemNode *n = list.first; n != 0; n = n->next, idx += 1) + { + result.v[idx] = n->item; + } + return result; +} + +internal void +df_cmd_lister_item_array_sort_by_strength__in_place(DF_CmdListerItemArray array) +{ + qsort(array.v, array.count, sizeof(DF_CmdListerItem), (int (*)(const void *, const void *))df_qsort_compare_cmd_lister__strength); +} + +//////////////////////////////// +//~ rjf: System Process Lister + +internal DF_ProcessInfoList +df_process_info_list_from_query(Arena *arena, String8 query) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: gather PIDs that we're currently attached to + U64 attached_process_count = 0; + U32 *attached_process_pids = 0; + { + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + attached_process_count = processes.count; + attached_process_pids = push_array(scratch.arena, U32, attached_process_count); + U64 idx = 0; + for(DF_EntityNode *n = processes.first; n != 0; n = n->next, idx += 1) + { + DF_Entity *process = n->entity; + attached_process_pids[idx] = process->ctrl_id; + } + } + + //- rjf: build needles + U8 splits[] = {' '}; + String8List needles = str8_split(scratch.arena, query, splits, ArrayCount(splits), 0);; + + //- rjf: build list + DF_ProcessInfoList list = {0}; + { + DEMON_ProcessIter iter = {0}; + demon_proc_iter_begin(&iter); + for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(scratch.arena, &iter, &info);) + { + // rjf: skip root-level or otherwise 0-pid processes + if(info.pid == 0) + { + continue; + } + + // rjf: determine if this process is attached + B32 is_attached = 0; + for(U64 attached_idx = 0; attached_idx < attached_process_count; attached_idx += 1) + { + if(attached_process_pids[attached_idx] == info.pid) + { + is_attached = 1; + break; + } + } + + // rjf: gather fuzzy matches + DF_FuzzyMatchRangeList attached_match_ranges = {0}; + DF_FuzzyMatchRangeList name_match_ranges = df_fuzzy_match_find(arena, needles, info.name); + DF_FuzzyMatchRangeList pid_match_ranges = df_fuzzy_match_find(arena, needles, push_str8f(scratch.arena, "%i", info.pid)); + if(is_attached) + { + attached_match_ranges = df_fuzzy_match_find(arena, needles, str8_lit("[attached]")); + } + + // rjf: determine if this item is filtered out + B32 matches_query = (query.size == 0 || + (attached_match_ranges.count >= needles.node_count) || + (name_match_ranges.count >= needles.node_count) || + (pid_match_ranges.count >= needles.node_count)); + + // rjf: push if unfiltered + if(matches_query) + { + DF_ProcessInfoNode *n = push_array(arena, DF_ProcessInfoNode, 1); + n->info.info = info; + n->info.info.name = push_str8_copy(arena, info.name); + n->info.is_attached = is_attached; + n->info.attached_match_ranges = attached_match_ranges; + n->info.name_match_ranges = name_match_ranges; + n->info.pid_match_ranges = pid_match_ranges; + SLLQueuePush(list.first, list.last, n); + list.count += 1; + } + } + demon_proc_iter_end(&iter); + } + + scratch_end(scratch); + return list; +} + +internal DF_ProcessInfoArray +df_process_info_array_from_list(Arena *arena, DF_ProcessInfoList list) +{ + DF_ProcessInfoArray array = {0}; + array.count = list.count; + array.v = push_array(arena, DF_ProcessInfo, array.count); + U64 idx = 0; + for(DF_ProcessInfoNode *n = list.first; n != 0; n = n->next, idx += 1) + { + array.v[idx] = n->info; + } + return array; +} + +internal void +df_process_info_array_sort_by_strength__in_place(DF_ProcessInfoArray array) +{ + qsort(array.v, array.count, sizeof(DF_ProcessInfo), (int (*)(const void *, const void *))df_qsort_compare_process_info); +} + +//////////////////////////////// +//~ rjf: Entity Lister + +internal DF_EntityListerItemList +df_entity_lister_item_list_from_needle(Arena *arena, DF_EntityKind kind, DF_EntityFlags omit_flags, String8 needle) +{ + Temp scratch = scratch_begin(&arena, 1); + DF_EntityListerItemList result = {0}; + + //- rjf: get search needles + String8List search_needles = {0}; + { + U8 splits[] = {' '}; + search_needles = str8_split(scratch.arena, needle, splits, ArrayCount(splits), 0); + } + + //- rjf: build filtered list + DF_EntityList ent_list = df_query_cached_entity_list_with_kind(kind); + for(DF_EntityNode *n = ent_list.first; n != 0; n = n->next) + { + DF_Entity *entity = n->entity; + if(!(entity->flags & omit_flags)) + { + String8 display_string = df_display_string_from_entity(scratch.arena, entity); + DF_FuzzyMatchRangeList match_rngs = df_fuzzy_match_find(arena, search_needles, display_string); + if(match_rngs.count != 0 || needle.size == 0) + { + DF_EntityListerItemNode *item_n = push_array(arena, DF_EntityListerItemNode, 1); + item_n->item.entity = entity; + item_n->item.name_match_ranges = match_rngs; + SLLQueuePush(result.first, result.last, item_n); + result.count += 1; + } + } + } + + scratch_end(scratch); + return result; +} + +internal DF_EntityListerItemArray +df_entity_lister_item_array_from_list(Arena *arena, DF_EntityListerItemList list) +{ + DF_EntityListerItemArray result = {0}; + result.count = list.count; + result.v = push_array(arena, DF_EntityListerItem, result.count); + { + U64 idx = 0; + for(DF_EntityListerItemNode *n = list.first; n != 0; n = n->next, idx += 1) + { + result.v[idx] = n->item; + } + } + return result; +} + +internal void +df_entity_lister_item_array_sort_by_strength__in_place(DF_EntityListerItemArray array) +{ + qsort(array.v, array.count, sizeof(DF_EntityListerItem), (int (*)(const void *, const void *))df_qsort_compare_entity_lister__strength); +} + +//////////////////////////////// +//~ rjf: Disassembly View + +internal TXTI_TokenArray +df_txti_token_array_from_dasm_arch_string(Arena *arena, Architecture arch, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + TXTI_TokenChunkList tokens = {0}; + { + TXTI_TokenKind active_token_kind = TXTI_TokenKind_Null; + U64 active_token_start_off = 0; + U64 off = 0; + B32 escaped = 0; + B32 string_is_char = 0; + for(U64 advance = 0; off <= string.size; off += advance) + { + U8 byte = (off+0 < string.size) ? string.str[off+0] : 0; + U8 next_byte = (off+1 < string.size) ? string.str[off+1] : 0; + B32 ender_found = 0; + advance = (active_token_kind != TXTI_TokenKind_Null ? 1 : 0); + if(off == string.size && active_token_kind != TXTI_TokenKind_Null) + { + ender_found = 1; + advance = 1; + } + switch(active_token_kind) + { + default: + case TXTI_TokenKind_Null: + { + if(byte == ' ' || byte == '\t' || byte == '\v' || byte == '\f' || byte == '\r' || byte == '\n') + { + active_token_start_off = off; + active_token_kind = TXTI_TokenKind_Whitespace; + advance = 1; + } + else if(('a' <= byte && byte <= 'z') || ('A' <= byte && byte <= 'Z') || byte == '_') + { + active_token_start_off = off; + active_token_kind = TXTI_TokenKind_Identifier; + advance = 1; + } + else if(byte == '\'') + { + active_token_start_off = off; + active_token_kind = TXTI_TokenKind_String; + advance = 1; + string_is_char = 1; + } + else if(byte == '"') + { + active_token_start_off = off; + active_token_kind = TXTI_TokenKind_String; + advance = 1; + string_is_char = 0; + } + else if(('0' <= byte && byte <= '9') || (byte == '.' && '0' <= next_byte && next_byte <= '9')) + { + active_token_start_off = off; + active_token_kind = TXTI_TokenKind_Numeric; + advance = 1; + } + else if(byte == '~' || byte == '!' || byte == '%' || byte == '^' || + byte == '&' || byte == '*' || byte == '(' || byte == ')' || + byte == '-' || byte == '=' || byte == '+' || byte == '[' || + byte == ']' || byte == '{' || byte == '}' || byte == ';' || + byte == ':' || byte == '?' || byte == '/' || byte == '<' || + byte == '>' || byte == ',' || byte == '.') + { + active_token_start_off = off; + active_token_kind = TXTI_TokenKind_Symbol; + advance = 1; + } + else + { + active_token_start_off = off; + active_token_kind = TXTI_TokenKind_Error; + advance = 1; + } + }break; + case TXTI_TokenKind_Whitespace: + if(byte != ' ' && byte != '\t' && byte != '\v' && byte != '\f') + { + ender_found = 1; + advance = 0; + }break; + case TXTI_TokenKind_Identifier: + if((byte < 'a' || 'z' < byte) && (byte < 'A' || 'Z' < byte) && (byte < '0' || '9' < byte) && byte != '_') + { + ender_found = 1; + advance = 0; + }break; + case TXTI_TokenKind_String: + { + U8 ender_byte = string_is_char ? '\'' : '"'; + if(!escaped && byte == ender_byte) + { + ender_found = 1; + advance = 1; + } + else if(escaped) + { + escaped = 0; + advance = 1; + } + else if(byte == '\\') + { + escaped = 1; + advance = 1; + } + else + { + U8 byte_class = utf8_class[byte>>3]; + if(byte_class > 1) + { + advance = (U64)byte_class; + } + } + }break; + case TXTI_TokenKind_Numeric: + if((byte < 'a' || 'z' < byte) && (byte < 'A' || 'Z' < byte) && (byte < '0' || '9' < byte) && byte != '.') + { + ender_found = 1; + advance = 0; + }break; + case TXTI_TokenKind_Symbol: + if(1) + { + // NOTE(rjf): avoiding maximum munch rule for now + ender_found = 1; + advance = 0; + } + else if(byte != '~' && byte != '!' && byte != '#' && byte != '%' && + byte != '^' && byte != '&' && byte != '*' && byte != '(' && + byte != ')' && byte != '-' && byte != '=' && byte != '+' && + byte != '[' && byte != ']' && byte != '{' && byte != '}' && + byte != ';' && byte != ':' && byte != '?' && byte != '/' && + byte != '<' && byte != '>' && byte != ',' && byte != '.') + { + ender_found = 1; + advance = 0; + }break; + case TXTI_TokenKind_Error: + { + ender_found = 1; + advance = 0; + }break; + } + if(ender_found != 0) + { + TXTI_Token token = {active_token_kind, r1u64(active_token_start_off, off+advance)}; + if(active_token_kind == TXTI_TokenKind_Identifier) + { + String8 token_string = str8_substr(string, token.range); + if(df_info_summary_from_string(arch, token_string).size != 0) + { + token.kind = TXTI_TokenKind_Keyword; + } + } + txti_token_chunk_list_push(arena, &tokens, 1024, &token); + active_token_kind = TXTI_TokenKind_Null; + active_token_start_off = token.range.max; + } + } + } + TXTI_TokenArray result = txti_token_array_from_chunk_list(arena, &tokens); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Eval/Watch Views + +//- rjf: root allocation/deallocation/mutation + +internal DF_EvalRoot * +df_eval_root_alloc(DF_View *view, DF_EvalWatchViewState *ews) +{ + DF_EvalRoot *result = ews->first_free_root; + if(result != 0) + { + SLLStackPop(ews->first_free_root); + result->expr_buffer_string_size = 0; + } + else + { + result = push_array(view->arena, DF_EvalRoot, 1); + result->expr_buffer_cap = 1024; + result->expr_buffer = push_array_no_zero(view->arena, U8, result->expr_buffer_cap); + } + DLLPushBack(ews->first_root, ews->last_root, result); + ews->root_count += 1; + return result; +} + +internal void +df_eval_root_release(DF_EvalWatchViewState *ews, DF_EvalRoot *root) +{ + DLLRemove(ews->first_root, ews->last_root, root); + SLLStackPush(ews->first_free_root, root); + ews->root_count -= 1; +} + +internal void +df_eval_root_equip_string(DF_EvalRoot *root, String8 string) +{ + root->expr_buffer_string_size = Min(string.size, root->expr_buffer_cap); + MemoryCopy(root->expr_buffer, string.str, root->expr_buffer_string_size); +} + +internal DF_EvalRoot * +df_eval_root_from_string(DF_EvalWatchViewState *ews, String8 string) +{ + DF_EvalRoot *root = 0; + for(DF_EvalRoot *r = ews->first_root; r != 0; r = r->next) + { + String8 r_string = df_string_from_eval_root(r); + if(str8_match(r_string, string, 0)) + { + root = r; + break; + } + } + return root; +} + +internal DF_EvalRoot * +df_eval_root_from_expand_key(DF_EvalWatchViewState *ews, DF_ExpandKey expand_key) +{ + DF_EvalRoot *root = 0; + for(DF_EvalRoot *r = ews->first_root; r != 0; r = r->next) + { + DF_ExpandKey r_key = df_expand_key_from_eval_root(r); + if(df_expand_key_match(r_key, expand_key)) + { + root = r; + break; + } + } + return root; +} + +internal String8 +df_string_from_eval_root(DF_EvalRoot *root) +{ + String8 string = str8(root->expr_buffer, root->expr_buffer_string_size); + return string; +} + +internal DF_ExpandKey +df_expand_key_from_eval_root(DF_EvalRoot *root) +{ + String8 root_expr_string = df_string_from_eval_root(root); + U64 root_expr_hash = df_hash_from_string(root_expr_string); + DF_EvalViewKey root_view_key = df_eval_view_key_make((U64)root, root_expr_hash); + DF_EvalView *root_view = df_eval_view_from_key(root_view_key); + DF_ExpandKey key = df_expand_key_make((U64)root_view, 5381, 1); + return key; +} + +//- rjf: windowed watch tree visualization (both single-line and multi-line) + +internal DF_EvalVizBlockList +df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_EvalWatchViewState *ews) +{ + ProfBeginFunction(); + DF_EvalVizBlockList blocks = {0}; + for(DF_EvalRoot *root = ews->first_root; root != 0; root = root->next) + { + String8 root_expr_string = df_string_from_eval_root(root); + U64 root_expr_hash = df_hash_from_string(root_expr_string); + DF_EvalViewKey root_view_key = df_eval_view_key_make((U64)root, root_expr_hash); + DF_EvalView *root_view = df_eval_view_from_key(root_view_key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr(arena, scope, ctrl_ctx, parse_ctx, root_view, root_expr_string); + df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); + } + ProfEnd(); + return blocks; +} + +//- rjf: eval/watch views main hooks + +internal void +df_eval_watch_view_init(DF_EvalWatchViewState *ewv, DF_View *view) +{ + if(ewv->initialized == 0) + { + ewv->initialized = 1; + ewv->expr_column_pct = 0.25f; + ewv->value_column_pct = 0.3f; + ewv->type_column_pct = 0.15f; + ewv->view_rule_column_pct = 0.30f; + } +} + +internal void +df_eval_watch_view_cmds(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWatchViewState *ewv, DF_CmdList *cmds) +{ + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: process + switch(core_cmd_kind) + { + default:break; + + //- rjf: watch expression toggling + case DF_CoreCmdKind_ToggleWatchExpression: + if(cmd->params.string.size != 0) + { + DF_EvalRoot *already_existing_root = df_eval_root_from_string(ewv, cmd->params.string); + if(already_existing_root != 0) + { + df_eval_root_release(ewv, already_existing_root); + } + else + { + DF_EvalRoot *root = df_eval_root_alloc(view, ewv); + df_eval_root_equip_string(root, cmd->params.string); + } + }break; + } + } +} + +internal void +df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect) +{ + ProfBeginFunction(); + DBGI_Scope *scope = dbgi_scope_open(); + Temp scratch = scratch_begin(0, 0); + + ////////////////////////////// + //- rjf: unpack arguments + // + F_Tag code_font = df_font_from_slot(DF_FontSlot_Code); + F32 code_font_size = df_font_size_from_slot(ws, DF_FontSlot_Code); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + U64 thread_ip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); + DF_Entity *module = df_module_from_process_vaddr(process, thread_ip_vaddr); + U64 thread_ip_voff = df_voff_from_vaddr(module, thread_ip_vaddr); + + ////////////////////////////// + //- rjf: process * thread info -> parse_ctx + // + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_module_voff(scope, module, thread_ip_voff); + + ////////////////////////////// + //- rjf: roots -> viz blocks + // + DF_EvalVizBlockList blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ewv); + + ////////////////////////////// + //- rjf: selection state * blocks -> 2D table coordinates + // + Vec2S64 cursor = {0}; + { + cursor.x = ewv->selected_column; + if(df_expand_key_match(df_expand_key_make(0, 0, 0), ewv->selected_parent_key)) + { + cursor.y = 0; + } + else if(df_expand_key_match(df_expand_key_make(1, 1, 1), ewv->selected_parent_key)) + { + cursor.y = blocks.total_semantic_row_count+1; + } + else + { + B32 key_found = 0; + cursor.y = 1; + for(DF_EvalVizBlock *block = blocks.first; block != 0; block = block->next) + { + if(df_expand_key_match(block->parent_key, ewv->selected_parent_key) && + block->key.uniquifier == ewv->selected_key.uniquifier && + block->key.parent_hash == ewv->selected_key.parent_hash && + block->semantic_idx_range.min+1 <= ewv->selected_key.child_num && + ewv->selected_key.child_num < block->semantic_idx_range.max+1) + { + key_found = 1; + cursor.y += ewv->selected_key.child_num - (block->semantic_idx_range.min+1); + break; + } + else + { + cursor.y += dim_1u64(block->semantic_idx_range); + } + } + if(key_found == 0) + { + cursor.y = 1*!!modifiable; + } + } + } + + ////////////////////////////// + //- rjf: do start/end editing interaction + // + B32 edit_begin = 0; + B32 edit_begin_or_expand = 0; + B32 edit_commit = 0; + B32 edit_end = 0; + B32 edit_submit = 0; + String8 edit_autocomplete_string = {0}; + if(!ewv->input_editing && ui_is_focus_active()) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + { + if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + { + edit_begin = 1; + break; + } + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + { + edit_begin = 1; + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + edit_begin_or_expand = 1; + } + } + if(ewv->input_editing && ui_is_focus_active()) + { + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + { + edit_end = 1; + edit_commit = 0; + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + edit_end = 1; + edit_commit = 1; + edit_submit = 1; + } + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + { + if(n->v.flags & UI_NavActionFlag_ReplaceAndCommit) + { + edit_commit = 1; + edit_end = 1; + edit_autocomplete_string = n->v.insertion; + ui_nav_eat_action_node(nav_actions, n); + break; + } + } + } + + ////////////////////////////// + //- rjf: build ui + // + F32 *col_pcts[] = + { + &ewv->expr_column_pct, + &ewv->value_column_pct, + &ewv->type_column_pct, + &ewv->view_rule_column_pct, + }; + B32 pressed = 0; + DF_EvalVizRow *commit_row = 0; + Vec2S64 next_cursor = cursor; + Rng1S64 visible_row_rng = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, blocks.total_semantic_row_count + 1*!!modifiable)); + scroll_list_params.item_range = r1s64(0, 1 + blocks.total_visual_row_count + 1*!!modifiable); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + UI_ScrollListRowBlockChunkList row_block_chunks = {0}; + for(DF_EvalVizBlock *viz_block = blocks.first; viz_block != 0; viz_block = viz_block->next) + { + UI_ScrollListRowBlock block = {0}; + block.row_count = dim_1u64(viz_block->visual_idx_range); + block.item_count = dim_1u64(viz_block->semantic_idx_range); + ui_scroll_list_row_block_chunk_list_push(scratch.arena, &row_block_chunks, 256, &block); + } + if(modifiable) + { + UI_ScrollListRowBlock block = {1, 1}; + ui_scroll_list_row_block_chunk_list_push(scratch.arena, &row_block_chunks, 256, &block); + } + scroll_list_params.row_blocks = ui_scroll_list_row_block_array_from_chunk_list(scratch.arena, &row_block_chunks); + } + UI_BoxFlags disabled_flags = ui_top_flags(); + if(df_ctrl_targets_running()) + { + disabled_flags |= UI_BoxFlag_Disabled; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) + UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, ewv->input_editing ? 0 : &cursor, &visible_row_rng, &scroll_list_sig) + UI_TableF(ArrayCount(col_pcts), col_pcts, "table_header") + { + next_cursor = cursor; + + //- rjf: build table header + if(visible_row_rng.min == 0) UI_TableVector UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + UI_TableCell ui_label(str8_lit("Expression")); + UI_TableCell ui_label(str8_lit("Value")); + UI_TableCell ui_label(str8_lit("Type")); + UI_TableCell if(df_help_label(str8_lit("View Rule"))) UI_Tooltip + { + F32 max_width = ui_top_font_size()*35; + ui_label_multiline(max_width, str8_lit("View rules are used to tweak the way evaluated expressions are visualized. Multiple rules can be specified on each row. They are specified in a key:(value) form.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("array:(N)"); + ui_label_multiline(max_width, str8_lit("Specifies that a pointer points to N elements, rather than only 1.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("omit:(member_1 ... member_n)"); + ui_label_multiline(max_width, str8_lit("Omits a list of member names from appearing in struct, union, or class evaluations.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("only:(member_1 ... member_n)"); + ui_label_multiline(max_width, str8_lit("Specifies that only the specified members should appear in struct, union, or class evaluations.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("list:(next_link_member_name)"); + ui_label_multiline(max_width, str8_lit("Specifies that some struct, union, or class forms the top of a linked list, with next_link_member_name being the member which points at the next element in the list.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("dec"); + ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-10 form.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("hex"); + ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-16 form.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("oct"); + ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-8 form.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("bin"); + ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-2 form.")); + ui_spacer(ui_em(1.5f, 1)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("no_addr"); + ui_label_multiline(max_width, str8_lit("Displays only what pointers point to, if possible, without the pointer's address value.")); + ui_spacer(ui_em(1.5f, 1)); + } + } + + //- rjf: viz blocks -> rows + DF_EvalVizWindowedRowList rows = {0}; + { + rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, default_radix, code_font, code_font_size, r1s64(visible_row_rng.min-1, visible_row_rng.max), &blocks); + } + + //- rjf: record history for windowed rows + if(!df_ctrl_targets_running()) + { + for(DF_EvalVizRow *row = rows.first; row != 0; row = row->next) + { + DF_Eval row_eval = row->eval; + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx.type_graph, parse_ctx.rdbg, &ctrl_ctx, row_eval); + if(value_eval.mode != EVAL_EvalMode_NULL) + { + DF_EvalHistoryVal val = zero_struct; + val.mode = value_eval.mode; + val.offset = value_eval.offset; + MemoryCopyArray(val.imm_u128, value_eval.imm_u128); + df_eval_view_record_history_val(row->eval_view, row->key, val); + } + } + } + + //- rjf: build table + { + //- rjf: build rows + U64 semantic_idx = rows.count_before_semantic; + for(DF_EvalVizRow *row = rows.first; row != 0; row = row->next, semantic_idx += 1) + { + U64 row_hash = df_hash_from_expand_key(row->key); + DF_EvalView *eval_view = row->eval_view; + df_expand_tree_table_animate(&eval_view->expand_tree_table, df_dt()); + B32 row_selected = ((semantic_idx+1) == cursor.y); + B32 row_expanded = df_expand_key_is_set(&eval_view->expand_tree_table, row->key); + DF_EvalHistoryCacheNode *history_cache_node = df_eval_history_cache_node_from_key(eval_view, row->key); + + //- rjf: store root edit commit info + if(row_selected) + { + commit_row = row; + } + + //- rjf: color changed rows + if(history_cache_node && + history_cache_node->last_run_idx == df_ctrl_run_gen() && + history_cache_node->last_run_idx != history_cache_node->first_run_idx && + history_cache_node->values[history_cache_node->newest_val_idx].mode != EVAL_EvalMode_NULL) + { + F32 animation_time_max = 1.f; + F32 animation_time = 1.f;//ClampTop(animation_time_max, history_cache_node->seconds_since_change); + F32 animation_progress = animation_time / animation_time_max; + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + color.w *= 0.25f - (animation_progress * 0.15f); + ui_set_next_overlay_color(color); + ui_set_next_flags(UI_BoxFlag_DrawOverlay); + } + + //- rjf: build canvas row + if(row->flags & DF_EvalVizRowFlag_Canvas) UI_FocusHot(row_selected) + { + ui_set_next_flags(disabled_flags); + ui_set_next_pref_width(ui_pct(1, 0)); + ui_set_next_pref_height(ui_px(scroll_list_params.row_height_px*row->size_in_rows, 1.f)); + UI_Box *vector = ui_build_box_from_stringf(UI_BoxFlag_DrawSideBottom|UI_BoxFlag_RequireFocusBackground|UI_BoxFlag_Clickable, "row_%I64x", row_hash); + UI_Parent(vector) + { + ui_set_next_fixed_y(-1.f * (row->skipped_size_in_rows) * scroll_list_params.row_height_px); + ui_set_next_fixed_height((row->skipped_size_in_rows + row->size_in_rows + row->chopped_size_in_rows) * scroll_list_params.row_height_px); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *canvas_box = ui_build_box_from_stringf(UI_BoxFlag_FloatingY, "###canvas_%I64x", row_hash); + if(row->expand_ui_rule_spec != &df_g_nil_gfx_view_rule_spec && row->expand_ui_rule_spec->info.block_ui) + { + UI_Parent(canvas_box) UI_WidthFill UI_HeightFill + { + Vec2F32 canvas_dim = v2f32(scroll_list_params.dim_px.x - ui_top_font_size()*1.5f, + (row->skipped_size_in_rows+row->size_in_rows+row->chopped_size_in_rows)*scroll_list_params.row_height_px - scroll_list_params.row_height_px); + row->expand_ui_rule_spec->info.block_ui(ws, row->key, row->eval, scope, &ctrl_ctx, &parse_ctx, row->expand_ui_rule_node, canvas_dim); + } + } + } + UI_Signal sig = ui_signal_from_box(vector); + if(sig.pressed) + { + edit_commit = edit_commit || (!row_selected && ewv->input_editing); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_Expr, (semantic_idx+1)); + pressed = 1; + } + } + + //- rjf: build normal row + if(!(row->flags & DF_EvalVizRowFlag_Canvas)) + { + ui_set_next_flags(disabled_flags); + UI_NamedTableVectorF("row_%I64x", row_hash) + { + //- rjf: expression + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_Expr); + B32 can_edit_expr = !(row->depth > 0 || modifiable == 0); + + // rjf: begin editing + if(cell_selected && (edit_begin || (edit_begin_or_expand && !(row->flags & DF_EvalVizRowFlag_CanExpand))) && can_edit_expr) + { + ewv->input_editing = 1; + ewv->input_size = Min(sizeof(ewv->input_buffer), row->expr.size); + MemoryCopy(ewv->input_buffer, row->expr.str, ewv->input_size); + ewv->input_cursor = txt_pt(1, 1+ewv->input_size); + ewv->input_mark = txt_pt(1, 1); + } + + // rjf: build + UI_Signal sig = {0}; + B32 next_expanded = row_expanded; + UI_TableCell UI_Font(code_font) + UI_TextColor(row->depth > 0 ? df_rgba_from_theme_color(DF_ThemeColor_WeakText) : ui_top_text_color()) + UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + B32 expr_editing_active = ui_is_focus_active(); + sig = df_line_editf((DF_LineEditFlag_CodeContents| + DF_LineEditFlag_NoBackground| + DF_LineEditFlag_DisableEdit*(!can_edit_expr)| + DF_LineEditFlag_Expander*!!(row->flags & DF_EvalVizRowFlag_CanExpand)| + DF_LineEditFlag_ExpanderPlaceholder*(row->depth==0)| + DF_LineEditFlag_ExpanderSpace*(row->depth!=0)), + row->depth, + &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, &next_expanded, + row->expr, + "###row_%I64x", row_hash); + edit_commit = edit_commit || sig.commit; + if(sig.hovering && DEV_eval_watch_key_tooltips) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Code)) + { + ui_labelf("Parent Key: %I64x, %I64x, %I64x", row->parent_key.uniquifier, row->parent_key.parent_hash, row->parent_key.child_num); + ui_labelf("Hover Key: %I64x, %I64x, %I64x", row->key.uniquifier, row->key.parent_hash, row->key.child_num); + ui_labelf("Cursor Key: %I64x, %I64x, %I64x", ewv->selected_key.uniquifier, ewv->selected_key.parent_hash, ewv->selected_key.child_num); + } + if(sig.hovering && row->depth == 0 && DEV_eval_compiler_tooltips) UI_Tooltip + { + Temp scratch = scratch_begin(0, 0); + String8 string = row->expr; + + // rjf: lex & parse + EVAL_TokenArray tokens = eval_token_array_from_text(scratch.arena, string); + EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(scratch.arena, &parse_ctx, string, &tokens); + EVAL_ErrorList errors = parse.errors; + ui_labelf("Tokens:"); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + for(U64 idx = 0; idx < tokens.count; idx += 1) + { + EVAL_Token *token = tokens.v+idx; + String8 token_string = str8_substr(string, token->range); + String8 token_kind_name = str8_lit("Token"); + switch(token->kind) + { + default:break; + case EVAL_TokenKind_Identifier: {token_kind_name = str8_lit("Identifier");}break; + case EVAL_TokenKind_Numeric: {token_kind_name = str8_lit("Numeric");}break; + case EVAL_TokenKind_StringLiteral:{token_kind_name = str8_lit("StringLiteral");}break; + case EVAL_TokenKind_CharLiteral: {token_kind_name = str8_lit("CharLiteral");}break; + case EVAL_TokenKind_Symbol: {token_kind_name = str8_lit("Symbol");}break; + } + ui_labelf("%S -> \"%S\"", token_kind_name, token_string); + } + + // rjf: produce IR tree & type + EVAL_IRTreeAndType ir_tree_and_type = {&eval_irtree_nil}; + if(parse.expr != &eval_expr_nil && errors.count == 0) + { + ui_labelf("Type:"); + ir_tree_and_type = eval_irtree_and_type_from_expr(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, parse.expr, &errors); + TG_Key type_key = ir_tree_and_type.type_key; + String8 type_string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, type_key); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_label(type_string); + } + + scratch_end(scratch); + } + if(expr_editing_active && !edit_end) + { + df_set_autocomp_lister_query(ws, sig.box->key, ctrl_ctx, DF_AutoCompListerFlag_Locals, str8(ewv->input_buffer, ewv->input_size)); + } + } + + // rjf: press -> commit if editing & select + if(sig.pressed) + { + edit_commit = edit_commit || (!cell_selected && ewv->input_editing); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_Expr, (semantic_idx+1)); + pressed = 1; + } + + // rjf: keyboard-click & expandable -> expand + if(cell_selected && edit_begin_or_expand && row->flags & DF_EvalVizRowFlag_CanExpand) + { + next_expanded ^= 1; + } + + // rjf: double-click -> start editing + if(sig.double_clicked && !ewv->input_editing && can_edit_expr) + { + ui_kill_action(); + ewv->input_editing = 1; + ewv->input_size = Min(sizeof(ewv->input_buffer), row->expr.size); + MemoryCopy(ewv->input_buffer, row->expr.str, ewv->input_size); + ewv->input_cursor = txt_pt(1, 1+ewv->input_size); + ewv->input_mark = txt_pt(1, 1); + } + + // rjf: commit expansion state + if(next_expanded != row_expanded) + { + df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, row->parent_key, row->key, next_expanded); + } + } + + //- rjf: value + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_Value); + B32 value_is_error = (row->errors.count != 0); + B32 value_is_hook = (!value_is_error && row->value_ui_rule_spec != &df_g_nil_gfx_view_rule_spec); + B32 value_is_complex = (!value_is_error && !value_is_hook && !(row->flags & DF_EvalVizRowFlag_CanEditValue)); + B32 value_is_simple = (!value_is_error && !value_is_hook && (row->flags & DF_EvalVizRowFlag_CanEditValue)); + + // rjf: begin editing + if(cell_selected && (edit_begin || edit_begin_or_expand) && value_is_simple) + { + ewv->input_editing = 1; + ewv->input_size = Min(sizeof(ewv->input_buffer), row->edit_value.size); + MemoryCopy(ewv->input_buffer, row->edit_value.str, ewv->input_size); + ewv->input_cursor = txt_pt(1, 1+ewv->input_size); + ewv->input_mark = txt_pt(1, 1); + } + + // rjf: build + UI_Signal sig = {0}; + UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + // rjf: errors? -> show errors + if(value_is_error) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) UI_Font(df_font_from_slot(DF_FontSlot_Main)) + { + String8List strings = {0}; + for(EVAL_Error *error = row->errors.first; error != 0; error = error->next) + { + str8_list_push(scratch.arena, &strings, error->text); + } + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + String8 error_string = str8_list_join(scratch.arena, &strings, &join); + sig = df_error_label(error_string); + if(sig.hovering) + { + UI_Tooltip + UI_Font(df_font_from_slot(DF_FontSlot_Main)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + { + for(EVAL_Error *error = row->errors.first; error != 0; error = error->next) + { + ui_label(error->text); + } + } + } + } + + // rjf: hook -> call hook + if(value_is_hook) UI_Font(df_font_from_slot(DF_FontSlot_Main)) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###val_%I64x", row_hash); + UI_Parent(box) + { + row->value_ui_rule_spec->info.row_ui(row->key, row->eval, scope, &ctrl_ctx, &parse_ctx, row->value_ui_rule_node); + } + sig = ui_signal_from_box(box); + } + + // rjf: complex values + if(value_is_complex) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###val_%I64x", row_hash); + UI_Parent(box) + { + df_code_label(1.f, 1, row->display_value); + } + sig = ui_signal_from_box(box); + } + + // rjf: simple values (editable) + if(value_is_simple) + { + sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, 0, row->display_value, "%S###val_%I64x", row->display_value, row_hash); + edit_commit = (edit_commit || sig.commit); + } + } + + // rjf: press -> focus & commit if editing & not selected + if(sig.pressed) + { + pressed = 1; + edit_commit = edit_commit || (ewv->input_editing && !cell_selected); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_Value, (semantic_idx+1)); + } + + // rjf: double-click -> start editing + if(sig.double_clicked && value_is_simple) + { + ui_kill_action(); + ewv->input_editing = 1; + ewv->input_size = Min(sizeof(ewv->input_buffer), row->edit_value.size); + MemoryCopy(ewv->input_buffer, row->edit_value.str, ewv->input_size); + ewv->input_cursor = txt_pt(1, 1+ewv->input_size); + ewv->input_mark = txt_pt(1, 1); + } + } + + //- rjf: type + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_Type); + UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + TG_Key key = row->eval.type_key; + String8 string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, key); + string = str8_skip_chop_whitespace(string); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###type_%I64x", row_hash); + if(!tg_key_match(key, tg_key_zero())) UI_Parent(box) + { + df_code_label(1.f, 1, string); + } + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + pressed = 1; + edit_commit = edit_commit || (ewv->input_editing && !cell_selected); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_Type, (semantic_idx+1)); + } + } + } + + //- rjf: view rule + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_ViewRule); + String8 view_rule = df_eval_view_rule_from_key(eval_view, row->key); + + // rjf: begin editing + if(cell_selected && (edit_begin || edit_begin_or_expand)) + { + ewv->input_editing = 1; + ewv->input_size = Min(sizeof(ewv->input_buffer), view_rule.size); + MemoryCopy(ewv->input_buffer, view_rule.str, ewv->input_size); + ewv->input_cursor = txt_pt(1, 1+ewv->input_size); + ewv->input_mark = txt_pt(1, 1); + } + + // rjf: build + UI_Signal sig = {0}; + B32 rule_editing_active = 0; + UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + rule_editing_active = ui_is_focus_active(); + sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, 0, view_rule, "###view_rule_%I64x", row_hash); + edit_commit = edit_commit || sig.commit; + } + + // rjf: press -> commit if not selected, select this cell + if(sig.pressed) + { + pressed = 1; + edit_commit = edit_commit || (ewv->input_editing && !cell_selected); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_ViewRule, (semantic_idx+1)); + } + + // rjf: double-click -> begin editing + if(sig.double_clicked && !ewv->input_editing) + { + ui_kill_action(); + ewv->input_editing = 1; + ewv->input_size = Min(sizeof(ewv->input_buffer), view_rule.size); + MemoryCopy(ewv->input_buffer, view_rule.str, ewv->input_size); + ewv->input_cursor = txt_pt(1, 1+ewv->input_size); + ewv->input_mark = txt_pt(1, 1); + } + + // rjf: autocomplete lister + if(rule_editing_active && !edit_end) + { + df_set_autocomp_lister_query(ws, sig.box->key, ctrl_ctx, DF_AutoCompListerFlag_ViewRules, str8(ewv->input_buffer, ewv->input_size)); + } + } + } + } + } + + //- rjf: empty row for edits + if(visible_row_rng.max >= scroll_list_params.item_range.max-1) if(modifiable) + { + ui_set_next_flags(disabled_flags); + UI_NamedTableVectorF("empty_add_new_row") + { + B32 row_selected = ((semantic_idx+1) == cursor.y); + + //- rjf: expression + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_Expr); + + // rjf: begin editing + if(cell_selected && (edit_begin || edit_begin_or_expand)) + { + ewv->input_editing = 1; + ewv->input_size = 0; + ewv->input_cursor = txt_pt(1, 1); + ewv->input_mark = txt_pt(1, 1); + } + + // rjf: build + UI_Signal sig = {0}; + B32 expr_editing_active = 0; + UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + expr_editing_active = ui_is_focus_active(); + sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, 0, str8_lit(""), "###empty_row_expr"); + edit_commit = edit_commit || sig.commit; + } + + // rjf: press -> select & commit if not selected + if(sig.pressed) + { + pressed = 1; + edit_commit = edit_commit || (ewv->input_editing && !cell_selected); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_Expr, (semantic_idx+1)); + } + + // rjf: double-click -> begin editing + if(sig.double_clicked && !ewv->input_editing) + { + ui_kill_action(); + ewv->input_editing = 1; + ewv->input_size = 0; + ewv->input_cursor = txt_pt(1, 1); + ewv->input_mark = txt_pt(1, 1); + } + + // rjf: autocomplete lister + if(expr_editing_active && !edit_end) + { + df_set_autocomp_lister_query(ws, sig.box->key, ctrl_ctx, DF_AutoCompListerFlag_Locals, str8(ewv->input_buffer, ewv->input_size)); + } + } + + //- rjf: value + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_Value); + UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###val_BLANK"); + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + pressed = 1; + edit_commit = edit_commit || (ewv->input_editing && !cell_selected); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_Value, (semantic_idx+1)); + } + } + } + + //- rjf: type + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_Type); + UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###type_BLANK"); + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + pressed = 1; + edit_commit = edit_commit || (ewv->input_editing && !cell_selected); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_Type, (semantic_idx+1)); + } + } + } + + //- rjf: view rule + { + B32 cell_selected = (row_selected && cursor.x == DF_EvalWatchViewColumnKind_ViewRule); + UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###view_rule_BLANK"); + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + pressed = 1; + edit_commit = edit_commit || (ewv->input_editing && !cell_selected); + next_cursor = v2s64(DF_EvalWatchViewColumnKind_ViewRule, (semantic_idx+1)); + } + } + } + } + } + } + } + + ////////////////////////////// + //- rjf: general table-wide press logic + // + if(pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + ////////////////////////////// + //- rjf: commit edits + // + { + DF_EvalWatchViewColumnKind commit_column = (DF_EvalWatchViewColumnKind)cursor.x; + cursor = next_cursor; + if(edit_commit) + { + ewv->input_editing = 0; + String8 commit_string = str8(ewv->input_buffer, ewv->input_size); + if(edit_autocomplete_string.size != 0) + { + commit_string = edit_autocomplete_string; + } + + //- rjf: committed on empty row -> create new + if(commit_row == 0 && commit_string.size != 0) + { + DF_EvalRoot *root = df_eval_root_alloc(view, ewv); + df_eval_root_equip_string(root, commit_string); + U64 root_expr_hash = df_hash_from_string(commit_string); + DF_EvalViewKey root_view_key = df_eval_view_key_make((U64)root, root_expr_hash); + DF_EvalView *root_view = df_eval_view_from_key(root_view_key); + DF_ExpandKey parent_key = df_expand_key_make((U64)root_view, 0, 0); + DF_ExpandKey key = df_expand_key_make((U64)root_view, 5381, 1); + df_expand_set_expansion(root_view->arena, &root_view->expand_tree_table, parent_key, key, 0); + cursor.y += 1; + } + + //- rjf: committed on a valid row + if(commit_row != 0) + { + switch(commit_column) + { + default:break; + + //- rjf: expression commits + case DF_EvalWatchViewColumnKind_Expr: if(modifiable) + { + if(commit_string.size == 0) + { + DF_EvalRoot *root = df_eval_root_from_expand_key(ewv, commit_row->key); + if(root != 0) + { + df_eval_root_release(ewv, root); + } + } + else + { + DF_EvalRoot *root = df_eval_root_from_expand_key(ewv, commit_row->key); + if(root != 0) + { + df_eval_root_equip_string(root, commit_string); + } + } + }break; + + //- rjf: value commits + case DF_EvalWatchViewColumnKind_Value: + { + Temp scratch = scratch_begin(0, 0); + DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, commit_string); + B32 success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdbg, &ctrl_ctx, commit_row->eval, write_eval); + if(success == 0) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = str8_lit("Could not commit value successfully."); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + scratch_end(scratch); + }break; + + //- rjf: type commits + case DF_EvalWatchViewColumnKind_Type: + { + }break; + + //- rjf: view rule commits + case DF_EvalWatchViewColumnKind_ViewRule: + { + df_eval_view_set_key_rule(commit_row->eval_view, commit_row->key, commit_string); + }break; + } + } + } + } + + ////////////////////////////// + //- rjf: end edits + // + if(edit_end) + { + ewv->input_editing = 0; + } + + ////////////////////////////// + //- rjf: commit was submitted -> advance to next row + // + if(edit_submit) + { + cursor.y += 1; + } + + ////////////////////////////// + //- rjf: commits occurred -> re-compute blocks to adjust to new state + // + if(edit_commit) + { + blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ewv); + } + + ////////////////////////////// + //- rjf: convert new table coordinates back to selection state + // + { + DF_ExpandKey last_selected_key = ewv->selected_key; + DF_ExpandKey last_selected_parent_key = ewv->selected_parent_key; + ewv->selected_column = (DF_EvalWatchViewColumnKind)cursor.x; + ewv->selected_parent_key = df_expand_key_make(0, 0, 0); + ewv->selected_key = df_expand_key_make(0, 0, 0); + S64 scan_y = 1; + if(cursor.y == 0) + { + ewv->selected_parent_key = df_expand_key_make(0, 0, 0); + ewv->selected_key = df_expand_key_make(0, 0, 0); + } + else if(cursor.y >= blocks.total_semantic_row_count+1) + { + ewv->selected_parent_key = df_expand_key_make(1, 1, 1); + ewv->selected_key = df_expand_key_make(1, 1, 1); + } + else + { + DF_EvalVizBlock *block_before_found = 0; + DF_EvalVizBlock *found_block = 0; + DF_EvalVizBlock *prev = 0; + for(DF_EvalVizBlock *block = blocks.first; block != 0; prev = block, block = block->next) + { + S64 advance = (S64)dim_1u64(block->semantic_idx_range); + if(scan_y <= cursor.y && cursor.y < scan_y+advance) + { + block_before_found = prev; + found_block = block; + ewv->selected_parent_key = block->parent_key; + ewv->selected_key = df_expand_key_make(block->key.uniquifier, + block->key.parent_hash, + (cursor.y - scan_y) + block->semantic_idx_range.min + 1); + break; + } + scan_y += advance; + } + + // rjf: go to parent on collapses + if(found_block != 0) + { + DF_ExpandNode *node = df_expand_node_from_key(&found_block->eval_view->expand_tree_table, found_block->parent_key); + if(node != 0) + { + for(DF_ExpandNode *n = node; n != 0; n = n->parent) + { + if(n->expanded == 0) + { + DF_ExpandNode *parent = n->parent; + ewv->selected_key = parent ? n->key : df_expand_key_make((U64)found_block->eval_view, 5381, 1); + ewv->selected_parent_key = parent ? parent->key : df_expand_key_make((U64)found_block->eval_view, 0, 0); + } + } + } + else if(block_before_found != 0 && found_block->depth > 0) + { + ewv->selected_key = block_before_found->key; + ewv->selected_parent_key = block_before_found->parent_key; + } + } + } + if(!df_expand_key_match(ewv->selected_key, last_selected_key) || + !df_expand_key_match(ewv->selected_parent_key, last_selected_parent_key)) + { + ewv->input_editing = 0; + } + } + + scratch_end(scratch); + dbgi_scope_close(scope); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Null @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Null) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Null) { return str8_lit(""); } +DF_VIEW_CMD_FUNCTION_DEF(Null) {} +DF_VIEW_UI_FUNCTION_DEF(Null) {} + +//////////////////////////////// +//~ rjf: Empty @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Empty) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Empty) { return str8_lit(""); } +DF_VIEW_CMD_FUNCTION_DEF(Empty) {} +DF_VIEW_UI_FUNCTION_DEF(Empty) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + UI_WidthFill UI_HeightFill UI_Column UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Padding(ui_pct(1, 0)) + { + DF_EntityList targets = df_push_active_target_list(scratch.arena); + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + + //- rjf: targets state dependent helper + B32 helper_built = 0; + if(processes.count == 0) + { + helper_built = 1; + switch(targets.count) + { + //- rjf: user has no targets. build helper for adding them + case 0: + { + UI_PrefHeight(ui_em(3.75f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(22.f, 1.f)) + UI_CornerRadius(ui_top_font_size()/2.f) + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) + if(df_icon_buttonf(DF_IconKind_Add, "Add Target").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_AddTarget); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + }break; + + //- rjf: user has 1 target. build helper for launching it + case 1: + { + DF_Entity *target = df_first_entity_from_list(&targets); + String8 target_full_path = target->name; + String8 target_name = str8_skip_last_slash(target_full_path); + UI_PrefHeight(ui_em(3.75f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(22.f, 1.f)) + UI_CornerRadius(ui_top_font_size()/2.f) + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) + { + if(df_icon_buttonf(DF_IconKind_Play, "Launch %S", target_name).clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(target); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); + } + ui_spacer(ui_em(1.5f, 1)); + if(df_icon_buttonf(DF_IconKind_Play, "Step Into %S", target_name).clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(target); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndInit)); + } + } + }break; + + //- rjf: user has N targets. + default: + { + helper_built = 0; + }break; + } + } + + //- rjf: or text + if(helper_built) + { + UI_PrefHeight(ui_em(2.25f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_WidthFill + ui_labelf("- or -"); + } + + //- rjf: helper text for command lister activation + UI_PrefHeight(ui_em(2.25f, 1.f)) UI_Row + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextAlignment(UI_TextAlign_Center) + UI_Padding(ui_pct(1, 0)) + { + ui_labelf("use"); + DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Commands); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) + UI_Flags(UI_BoxFlag_DrawBorder) + UI_TextAlignment(UI_TextAlign_Center) + df_cmd_binding_button(spec); + ui_labelf(", or start typing, to open command menu"); + } + } + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Commands @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Commands) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Commands) { return str8_lit(""); } +DF_VIEW_CMD_FUNCTION_DEF(Commands) {} +DF_VIEW_UI_FUNCTION_DEF(Commands) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + + //- rjf: grab state + typedef struct DF_CmdsViewState DF_CmdsViewState; + struct DF_CmdsViewState + { + DF_CmdSpec *selected_cmd_spec; + }; + DF_CmdsViewState *cv = df_view_user_state(view, DF_CmdsViewState); + + //- rjf: build filtered array of commands + DF_CmdListerItemList cmd_list = df_cmd_lister_item_list_from_needle(scratch.arena, view->query); + DF_CmdListerItemArray cmd_array = df_cmd_lister_item_array_from_list(scratch.arena, cmd_list); + df_cmd_lister_item_array_sort_by_strength__in_place(cmd_array); + + //- rjf: submit best match when hitting enter w/ no selection + if(cv->selected_cmd_spec == &df_g_nil_cmd_spec && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + // rjf: complete view + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + + // rjf: perform fast path + { + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + if(cmd_array.count > 0) + { + DF_CmdListerItem *item = &cmd_array.v[0]; + params.cmd_spec = item->cmd_spec; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + } + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + } + + //- rjf: selected kind -> cursor + Vec2S64 cursor = {0}; + { + for(U64 idx = 0; idx < cmd_array.count; idx += 1) + { + if(cmd_array.v[idx].cmd_spec == cv->selected_cmd_spec) + { + cursor.y = (S64)idx+1; + break; + } + } + } + + //- rjf: build contents + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*6.5f); + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, cmd_array.count)); + scroll_list_params.item_range = r1s64(0, cmd_array.count); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + { + //- rjf: build buttons + for(S64 row_idx = visible_row_range.min; + row_idx <= visible_row_range.max && row_idx < cmd_array.count; + row_idx += 1) + { + DF_CmdListerItem *item = &cmd_array.v[row_idx]; + + //- rjf: build context menu for this command + UI_Key item_ctx_menu_key = ui_key_from_stringf(ui_key_zero(), "###%p_cmd_ctx_%p", view, item->cmd_spec); + UI_CtxMenu(item_ctx_menu_key) UI_PrefWidth(ui_em(33, 1)) + { + // rjf: row with icon & name + UI_Row UI_PrefWidth(ui_text_dim(10, 1)) UI_PrefHeight(ui_pct(1, 0)) + { + // rjf: icon + DF_IconKind icon = item->cmd_spec->info.canonical_icon_kind; + if(icon != DF_IconKind_Null) + UI_TextAlignment(UI_TextAlign_Center) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_PrefWidth(ui_em(2.25f, 1.f)) + { + ui_label(df_g_icon_kind_text_table[icon]); + } + + // rjf: display name + ui_label(item->cmd_spec->info.display_name); + } + + // rjf: row with ipc syntax + UI_Row UI_PrefWidth(ui_text_dim(10, 1)) UI_PrefHeight(ui_pct(1, 0)) + { + // rjf: name + UI_TextAlignment(UI_TextAlign_Left) + UI_Font(df_font_from_slot(DF_FontSlot_Code)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Code)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + ui_label(item->cmd_spec->info.string); + + ui_spacer(ui_pct(1, 0)); + + // rjf: args + UI_TextAlignment(UI_TextAlign_Right) + UI_Font(df_font_from_slot(DF_FontSlot_Code)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Code)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + String8 args = df_g_cmd_query_rule_kind_arg_desc_table[item->cmd_spec->info.query_rule]; + ui_label(args.size != 0 ? args : str8_lit("(no arguments)")); + } + } + } + + //- rjf: build row contents + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *box = &ui_g_nil_box; + UI_Focus(cursor.y == row_idx+1) + { + box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "###cmd_button_%p", item->cmd_spec); + } + UI_Parent(box) UI_PrefHeight(ui_em(1.65f, 1.f)) + { + //- rjf: icon + UI_PrefWidth(ui_em(3.f, 1.f)) + UI_HeightFill + UI_Column + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_HeightFill + UI_TextAlignment(UI_TextAlign_Center) + { + DF_IconKind icon = item->cmd_spec->info.canonical_icon_kind; + if(icon != DF_IconKind_Null) + { + ui_label(df_g_icon_kind_text_table[icon]); + } + } + + //- rjf: name + description + ui_set_next_pref_height(ui_pct(1, 0)); + UI_Column UI_Padding(ui_pct(1, 0)) + { + F_Tag font = ui_top_font(); + F32 font_size = ui_top_font_size(); + F_Metrics font_metrics = f_metrics_from_tag_size(font, font_size); + F32 font_line_height = f_line_height_from_metrics(&font_metrics); + String8 cmd_display_name = item->cmd_spec->info.display_name; + String8 cmd_desc = item->cmd_spec->info.description; + UI_Box *name_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##name_%p", cmd_display_name, item->cmd_spec); + UI_Box *desc_box = &ui_g_nil_box; + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefHeight(ui_em(1.8f, 1.f)) + { + desc_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##desc_%p", cmd_desc, item->cmd_spec); + } + df_box_equip_fuzzy_match_range_list_vis(name_box, item->name_match_ranges); + df_box_equip_fuzzy_match_range_list_vis(desc_box, item->desc_match_ranges); + } + + //- rjf: binding + UI_PrefWidth(ui_pct(0.15f, 1.f)) UI_HeightFill UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + df_cmd_binding_button(item->cmd_spec); + } + } + + //- rjf: interact + UI_Signal sig = ui_signal_from_box(box); + if(sig.clicked) + { + // rjf: complete view + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + + // rjf: do fast path + { + DF_CmdParams params = df_cmd_params_from_panel(ws, panel); + params.cmd_spec = item->cmd_spec; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + } + if(sig.right_clicked) + { + ui_ctx_menu_open(item_ctx_menu_key, ui_key_zero(), sub_2f32(ui_mouse(), v2f32(2, 2))); + } + } + } + + //- rjf: map selected num -> selected kind + if(1 <= cursor.y && cursor.y <= cmd_array.count) + { + cv->selected_cmd_spec = cmd_array.v[cursor.y-1].cmd_spec; + } + else + { + cv->selected_cmd_spec = &df_g_nil_cmd_spec; + } + + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: FileSystem @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(FileSystem) +{ +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(FileSystem) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(FileSystem) +{ +} + +DF_VIEW_UI_FUNCTION_DEF(FileSystem) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + String8 query = view->query; + String8 query_normalized = path_normalized_from_string(scratch.arena, query); + B32 query_has_slash = (query.size != 0 && char_to_correct_slash(query.str[query.size-1]) == '/'); + String8 query_normalized_with_opt_slash = push_str8f(scratch.arena, "%S%s", query_normalized, query_has_slash ? "/" : ""); + DF_PathQuery path_query = df_path_query_from_string(query_normalized_with_opt_slash); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); + B32 dir_selection = 0; + + //- rjf: get extra state for this view + DF_FileSystemViewState *fs = df_view_user_state(view, DF_FileSystemViewState); + if(fs->initialized == 0) + { + fs->initialized = 1; + fs->path_state_table_size = 256; + fs->path_state_table = push_array(view->arena, DF_FileSystemViewPathState *, fs->path_state_table_size); + fs->cached_files_arena = df_view_push_arena_ext(view); + fs->col_pcts[0] = 0.60f; + fs->col_pcts[1] = 0.20f; + fs->col_pcts[2] = 0.20f; + } + + //- rjf: grab state for the current path + DF_FileSystemViewPathState *ps = 0; + { + String8 key = query_normalized; + U64 hash = df_hash_from_string(key); + U64 slot = hash % fs->path_state_table_size; + for(DF_FileSystemViewPathState *p = fs->path_state_table[slot]; p != 0; p = p->hash_next) + { + if(str8_match(p->normalized_path, key, 0)) + { + ps = p; + break; + } + } + if(ps == 0) + { + ps = push_array(view->arena, DF_FileSystemViewPathState, 1); + ps->hash_next = fs->path_state_table[slot]; + fs->path_state_table[slot] = ps; + ps->normalized_path = push_str8_copy(view->arena, key); + } + } + + //- rjf: get file array from the current path + U64 file_count = fs->cached_file_count; + DF_FileInfo *files = fs->cached_files; + if(!str8_match(fs->cached_files_path, query_normalized_with_opt_slash, 0) || + fs->cached_files_sort_kind != fs->sort_kind || + fs->cached_files_sort_side != fs->sort_side) + { + arena_clear(fs->cached_files_arena); + + //- rjf: store off path that we're gathering from + fs->cached_files_path = push_str8_copy(fs->cached_files_arena, query_normalized_with_opt_slash); + fs->cached_files_sort_kind = fs->sort_kind; + fs->cached_files_sort_side = fs->sort_side; + + //- rjf: use stored path as the new browse path for the whole frontend + // (multiple file system views may conflict here. that's okay. we'll just always + // choose the most recent change to a file browser path, and live with the + // consequences). + { + DF_CmdParams p = df_cmd_params_zero(); + p.file_path = path_query.path; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetCurrentPath)); + } + + //- rjf: search => fuzzy needles + String8List search_needles = {0}; + { + U8 splits[] = {' '}; + search_needles = str8_split(scratch.arena, path_query.search, splits, ArrayCount(splits), 0); + } + + //- rjf: get files, filtered + U64 new_file_count = 0; + DF_FileInfoNode *first_file = 0; + DF_FileInfoNode *last_file = 0; + { + OS_FileIter *it = os_file_iter_begin(scratch.arena, path_query.path, 0); + for(OS_FileInfo info = {0}; os_file_iter_next(scratch.arena, it, &info);) + { + DF_FuzzyMatchRangeList match_ranges = df_fuzzy_match_find(fs->cached_files_arena, search_needles, info.name); + B32 fits_search = (search_needles.node_count == 0 || match_ranges.count == search_needles.node_count); + B32 fits_dir_only = !!(info.props.flags & FilePropertyFlag_IsFolder) || !dir_selection; + if(fits_search && fits_dir_only) + { + DF_FileInfoNode *node = push_array(scratch.arena, DF_FileInfoNode, 1); + node->file_info.filename = push_str8_copy(fs->cached_files_arena, info.name); + node->file_info.props = info.props; + node->file_info.match_ranges = match_ranges; + SLLQueuePush(first_file, last_file, node); + new_file_count += 1; + } + } + os_file_iter_end(it); + } + + //- rjf: convert list to array + DF_FileInfo *new_files = push_array(fs->cached_files_arena, DF_FileInfo, new_file_count); + { + U64 idx = 0; + for(DF_FileInfoNode *n = first_file; n != 0; n = n->next, idx += 1) + { + new_files[idx] = n->file_info; + } + } + + //- rjf: apply sort + switch(fs->sort_kind) + { + default: + { + if(path_query.search.size != 0) + { + qsort(new_files, new_file_count, sizeof(DF_FileInfo), (int (*)(const void *, const void *))df_qsort_compare_file_info__default_filtered); + } + else + { + qsort(new_files, new_file_count, sizeof(DF_FileInfo), (int (*)(const void *, const void *))df_qsort_compare_file_info__default); + } + }break; + case DF_FileSortKind_Filename: + { + qsort(new_files, new_file_count, sizeof(DF_FileInfo), (int (*)(const void *, const void *))df_qsort_compare_file_info__filename); + }break; + case DF_FileSortKind_LastModified: + { + qsort(new_files, new_file_count, sizeof(DF_FileInfo), (int (*)(const void *, const void *))df_qsort_compare_file_info__last_modified); + }break; + case DF_FileSortKind_Size: + { + qsort(new_files, new_file_count, sizeof(DF_FileInfo), (int (*)(const void *, const void *))df_qsort_compare_file_info__size); + }break; + } + + //- rjf: apply reverse + if(fs->sort_kind != DF_FileSortKind_Null && fs->sort_side == Side_Max) + { + for(U64 idx = 0; idx < new_file_count/2; idx += 1) + { + U64 rev_idx = new_file_count - idx - 1; + Swap(DF_FileInfo, new_files[idx], new_files[rev_idx]); + } + } + + fs->cached_file_count = file_count = new_file_count; + fs->cached_files = files = new_files; + } + + //- rjf: submit best match when hitting enter w/ no selection + if(ps->cursor.y == 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + FileProperties query_normalized_with_opt_slash_props = os_properties_from_file_path(query_normalized_with_opt_slash); + FileProperties path_query_path_props = os_properties_from_file_path(path_query.path); + + // rjf: command search part is empty, but directory matches some file: + if(path_query_path_props.created != 0 && path_query.search.size == 0) + { + // rjf: view return + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + + // rjf: send activation command + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, df_view_caller_root_from_view(view)); + params.file_path = query_normalized_with_opt_slash; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_push_cmd__root(¶ms, view->cmd_spec); + } + } + + // rjf: command argument exactly matches some file: + else if(query_normalized_with_opt_slash_props.created != 0 && path_query.search.size != 0) + { + // rjf: is a folder -> autocomplete to slash + if(query_normalized_with_opt_slash_props.flags & FilePropertyFlag_IsFolder) + { + String8 new_path = push_str8f(scratch.arena, "%S%S/", path_query.path, path_query.search); + DF_CmdParams params = df_cmd_params_zero(); + df_view_equip_command(view, view->cmd_spec, ¶ms, new_path, &df_g_nil_cfg_node); + } + + // rjf: is a file -> complete view + else + { + // rjf: view return + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + + // rjf: send activation command + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, df_view_caller_root_from_view(view)); + params.file_path = query_normalized_with_opt_slash; + df_push_cmd__root(¶ms, view->cmd_spec); + } + } + } + + // rjf: command argument does not exactly match any file, but lister results are in: + else if(file_count != 0) + { + String8 filename = files[0].filename; + if(files[0].props.flags & FilePropertyFlag_IsFolder) + { + String8 existing_path = str8_chop_last_slash(path_query.path); + String8 new_path = push_str8f(scratch.arena, "%S/%S/", existing_path, files[0].filename); + DF_CmdParams params = df_cmd_params_zero(); + df_view_equip_command(view, view->cmd_spec, ¶ms, new_path, &df_g_nil_cfg_node); + } + else + { + // rjf: view return + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + + // rjf: send activation command + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, df_view_caller_root_from_view(view)); + params.file_path = push_str8f(scratch.arena, "%S%S", path_query.path, filename); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_push_cmd__root(¶ms, view->cmd_spec); + } + } + } + + // rjf: command argument does not match any file, and lister is empty (new file) + else + { + // rjf: view return + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + + // rjf: send activation command + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, df_view_caller_root_from_view(view)); + params.file_path = query_normalized_with_opt_slash; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_push_cmd__root(¶ms, view->cmd_spec); + } + } + } + + //- rjf: build non-scrolled table header + U64 row_num = 1; + F32 **col_pcts = push_array(scratch.arena, F32 *, ArrayCount(fs->col_pcts)); + for(U64 idx = 0; idx < ArrayCount(fs->col_pcts); idx += 1) + { + col_pcts[idx] = &fs->col_pcts[idx]; + } + UI_Focus(0) UI_TableF(ArrayCount(fs->col_pcts), col_pcts, "###fs_tbl") + { + UI_TableVector UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + struct + { + DF_FileSortKind kind; + String8 string; + } + kinds[] = + { + { DF_FileSortKind_Filename, str8_lit_comp("Filename") }, + { DF_FileSortKind_LastModified, str8_lit_comp("Last Modified") }, + { DF_FileSortKind_Size, str8_lit_comp("Size") }, + }; + for(U64 idx = 0; idx < ArrayCount(kinds); idx += 1) + { + B32 sorting = fs->sort_kind == kinds[idx].kind; + if(sorting) + { + ui_push_text_color(df_rgba_from_theme_color(DF_ThemeColor_PlainText)); + } + UI_TableCell + { + UI_Signal sig = ui_sort_header(sorting, + fs->cached_files_sort_side == Side_Min, + kinds[idx].string); + if(sig.clicked) + { + if(fs->sort_kind != kinds[idx].kind) + { + fs->sort_kind = kinds[idx].kind; + fs->sort_side = Side_Max; + } + else if(fs->sort_kind == kinds[idx].kind && fs->sort_side == Side_Max) + { + fs->sort_side = Side_Min; + } + else if(fs->sort_kind == kinds[idx].kind && fs->sort_side == Side_Min) + { + fs->sort_kind = DF_FileSortKind_Null; + } + } + } + if(sorting) + { + ui_pop_text_color(); + } + } + } + } + + //- rjf: build file list + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + Vec2F32 content_dim = dim_2f32(rect); + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y-row_height_px*2); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, file_count+1)); + scroll_list_params.item_range = r1s64(0, file_count+1); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &ps->cursor, &visible_row_range, &scroll_list_sig) + { + // rjf: up-one-directory button (at idx 0) + if(visible_row_range.min == 0) + { + // rjf: build + UI_Signal sig = {0}; + UI_FocusHot(ps->cursor.y == row_num) + { + sig = ui_buttonf("###up_one"); + } + + // rjf: make content + UI_Parent(sig.box) + { + // rjf: icons + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(3.f, 1.f)) + UI_TextAlignment(UI_TextAlign_Center) + { + ui_label(df_g_icon_kind_text_table[DF_IconKind_LeftArrow]); + } + + // rjf: text + { + ui_label(str8_lit("Up One Directory")); + } + + row_num += 1; + } + + // rjf: click => up one directory + if(sig.clicked) + { + String8 new_path = str8_chop_last_slash(str8_chop_last_slash(path_query.path)); + new_path = path_normalized_from_string(scratch.arena, new_path); + String8 new_cmd = push_str8f(scratch.arena, "%S/", new_path); + DF_CmdParams params = df_cmd_params_zero(); + df_view_equip_command(view, view->cmd_spec, ¶ms, new_cmd, &df_g_nil_cfg_node); + } + } + + // rjf: file buttons + for(U64 row_idx = Max(visible_row_range.min, 1); + row_idx <= visible_row_range.max && row_idx <= file_count; + row_idx += 1, row_num += 1) + { + U64 file_idx = row_idx-1; + DF_FileInfo *file = &files[file_idx]; + B32 file_kb_focus = (ps->cursor.y == (row_idx+1)); + + // rjf: make button + UI_Signal file_sig = {0}; + UI_FocusHot(file_kb_focus) + { + file_sig = ui_buttonf("##%S_%p", file->filename, view); + } + + // rjf: make content + UI_Parent(file_sig.box) + { + UI_PrefWidth(ui_pct(fs->col_pcts[0], 1)) UI_Row + { + // rjf: icon to signify directory + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(3.f, 1.f)) + UI_TextAlignment(UI_TextAlign_Center) + { + if(file->props.flags & FilePropertyFlag_IsFolder) + { + ui_label((ui_key_match(ui_hot_key(), file_sig.box->key) || file_kb_focus) + ? df_g_icon_kind_text_table[DF_IconKind_FolderOpenFilled] + : df_g_icon_kind_text_table[DF_IconKind_FolderClosedFilled]); + } + else + { + ui_label(df_g_icon_kind_text_table[DF_IconKind_FileOutline]); + } + } + + // rjf: filename + UI_PrefWidth(ui_pct(1, 0)) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##%p", file->filename, view); + df_box_equip_fuzzy_match_range_list_vis(box, file->match_ranges); + } + } + + // rjf: last-modified time + UI_PrefWidth(ui_pct(fs->col_pcts[1], 1)) UI_Row + UI_PrefWidth(ui_pct(1, 0)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + DateTime time = date_time_from_dense_time(file->props.modified); + String8 string = push_date_time_string(scratch.arena, &time); + ui_label(string); + } + + // rjf: file size + UI_PrefWidth(ui_pct(fs->col_pcts[2], 1)) UI_Row + UI_PrefWidth(ui_pct(1, 0)) + { + if(file->props.size != 0) + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(str8_from_memory_size(scratch.arena, file->props.size)); + } + } + } + + // rjf: click => activate this file + if(file_sig.clicked) + { + String8 existing_path = str8_chop_last_slash(path_query.path); + String8 new_path = push_str8f(scratch.arena, "%S/%S/", existing_path, file->filename); + new_path = path_normalized_from_string(scratch.arena, new_path); + if(file->props.flags & FilePropertyFlag_IsFolder) + { + String8 new_cmd = push_str8f(scratch.arena, "%S/", new_path); + DF_CmdParams params = df_cmd_params_zero(); + df_view_equip_command(view, view->cmd_spec, ¶ms, new_cmd, &df_g_nil_cfg_node); + } + else + { + // rjf: view return + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + } + + // rjf: send activation command + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, df_view_caller_root_from_view(view)); + params.file_path = new_path; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_push_cmd__root(¶ms, view->cmd_spec); + } + } + } + } + } + + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: SystemProcesses @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(SystemProcesses) +{ +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(SystemProcesses) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(SystemProcesses) +{ +} + +DF_VIEW_UI_FUNCTION_DEF(SystemProcesses) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + + //- rjf: grab state + typedef struct DF_SystemProcessesViewState DF_SystemProcessesViewState; + struct DF_SystemProcessesViewState + { + B32 initialized; + B32 need_initial_gather; + U32 selected_pid; + Arena *cached_process_arena; + String8 cached_process_arg; + DF_ProcessInfoArray cached_process_array; + }; + DF_SystemProcessesViewState *sp = df_view_user_state(view, DF_SystemProcessesViewState); + if(sp->initialized == 0) + { + sp->initialized = 1; + sp->need_initial_gather = 1; + sp->cached_process_arena = df_view_push_arena_ext(view); + } + + //- rjf: gather list of filtered process infos + DF_ProcessInfoArray process_info_array = sp->cached_process_array; + if(sp->need_initial_gather || !str8_match(sp->cached_process_arg, view->query, 0)) + { + arena_clear(sp->cached_process_arena); + sp->need_initial_gather = 0; + sp->cached_process_arg = push_str8_copy(sp->cached_process_arena, view->query); + DF_ProcessInfoList list = df_process_info_list_from_query(sp->cached_process_arena, view->query); + sp->cached_process_array = df_process_info_array_from_list(sp->cached_process_arena, list); + process_info_array = sp->cached_process_array; + df_process_info_array_sort_by_strength__in_place(process_info_array); + } + + //- rjf: submit best match when hitting enter w/ no selection + if(sp->selected_pid == 0 && process_info_array.count > 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + DF_ProcessInfo *info = &process_info_array.v[0]; + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.id = info->info.pid; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_ID); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + df_push_cmd__root(¶ms, view->cmd_spec); + } + + //- rjf: selected PID -> cursor + Vec2S64 cursor = {0}; + { + for(U64 idx = 0; idx < process_info_array.count; idx += 1) + { + if(process_info_array.v[idx].info.pid == sp->selected_pid) + { + cursor.y = idx+1; + break; + } + } + } + + //- rjf: build contents + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + Vec2F32 content_dim = dim_2f32(rect); + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y-row_height_px); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, process_info_array.count)); + scroll_list_params.item_range = r1s64(0, process_info_array.count); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + { + //- rjf: build rows + for(U64 idx = visible_row_range.min; + idx <= visible_row_range.max && idx < process_info_array.count; + idx += 1) + { + DF_ProcessInfo *info = &process_info_array.v[idx]; + B32 is_attached = info->is_attached; + UI_Signal sig = {0}; + UI_FocusHot(cursor.y == idx+1) + { + sig = ui_buttonf("###proc_%i", info->info.pid); + } + UI_Parent(sig.box) + { + // rjf: icon + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_PrefWidth(ui_em(3.f, 1.f)) + UI_TextAlignment(UI_TextAlign_Center) + { + ui_label(df_g_icon_kind_text_table[DF_IconKind_Threads]); + } + + // rjf: attached indicator + if(is_attached) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight1)) UI_PrefWidth(ui_text_dim(10, 1)) + { + UI_Box *attached_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "[attached]##attached_label_%i", (int)info->info.pid); + df_box_equip_fuzzy_match_range_list_vis(attached_label, info->attached_match_ranges); + } + + // rjf: process name + UI_PrefWidth(ui_text_dim(10, 1)) + { + UI_Box *name_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##name_label_%i", info->info.name, (int)info->info.pid); + df_box_equip_fuzzy_match_range_list_vis(name_label, info->name_match_ranges); + } + + // rjf: process number + UI_PrefWidth(ui_text_dim(1, 1)) UI_TextAlignment(UI_TextAlign_Center) + { + ui_labelf("[PID: "); + UI_Box *pid_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%i##pid_label", info->info.pid); + df_box_equip_fuzzy_match_range_list_vis(pid_label, info->pid_match_ranges); + ui_labelf("]"); + } + } + + // rjf: click => activate this specific process + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.id = info->info.pid; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_ID); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + df_push_cmd__root(¶ms, view->cmd_spec); + } + } + } + + //- rjf: selected num -> selected PID + { + if(1 <= cursor.y && cursor.y <= process_info_array.count) + { + sp->selected_pid = process_info_array.v[cursor.y-1].info.pid; + } + else + { + sp->selected_pid = 0; + } + } + + + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: EntityLister @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(EntityLister) +{ +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(EntityLister) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(EntityLister) +{ +} + +DF_VIEW_UI_FUNCTION_DEF(EntityLister) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DF_CmdSpec *spec = view->cmd_spec; + DF_EntityKind entity_kind = (DF_EntityKind)spec->info.query_info_u64[0]; + DF_EntityFlags entity_flags_omit = spec->info.query_info_u64[1]; + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); + + //- rjf: grab state + typedef struct DF_EntityListerViewState DF_EntityListerViewState; + struct DF_EntityListerViewState + { + DF_Handle selected_entity_handle; + }; + DF_EntityListerViewState *fev = df_view_user_state(view, DF_EntityListerViewState); + DF_Handle selected_entity_handle = fev->selected_entity_handle; + DF_Entity *selected_entity = df_entity_from_handle(selected_entity_handle); + + //- rjf: build filtered array of entities + DF_EntityListerItemList ent_list = df_entity_lister_item_list_from_needle(scratch.arena, entity_kind, entity_flags_omit, view->query); + DF_EntityListerItemArray ent_arr = df_entity_lister_item_array_from_list(scratch.arena, ent_list); + df_entity_lister_item_array_sort_by_strength__in_place(ent_arr); + + //- rjf: submit best match when hitting enter w/ no selection + if(df_entity_is_nil(df_entity_from_handle(fev->selected_entity_handle)) && ent_arr.count != 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + DF_Entity *ent = ent_arr.v[0].entity; + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(ent); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_handle_list_push(scratch.arena, ¶ms.entity_list, params.entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + df_push_cmd__root(¶ms, view->cmd_spec); + } + + //- rjf: selected entity -> cursor + Vec2S64 cursor = {0}; + { + for(U64 idx = 0; idx < ent_arr.count; idx += 1) + { + if(ent_arr.v[idx].entity == selected_entity) + { + cursor.y = (S64)(idx+1); + break; + } + } + } + + //- rjf: build list + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + Vec2F32 content_dim = dim_2f32(rect); + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y-row_height_px); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, ent_arr.count)); + scroll_list_params.item_range = r1s64(0, ent_arr.count); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + { + for(S64 idx = visible_row_range.min; + idx <= visible_row_range.max && idx < ent_arr.count; + idx += 1) + { + DF_EntityListerItem item = ent_arr.v[idx]; + DF_Entity *ent = item.entity; + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *box = &ui_g_nil_box; + UI_FocusHot(idx+1 == cursor.y) + { + box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "###ent_btn_%p", ent); + } + UI_Parent(box) + { + DF_IconKind icon_kind = df_g_entity_kind_icon_kind_table[ent->kind]; + if(icon_kind != DF_IconKind_Null) + { + UI_TextAlignment(UI_TextAlign_Center) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_PrefWidth(ui_text_dim(10, 1)) + ui_label(df_g_icon_kind_text_table[icon_kind]); + } + String8 display_string = df_display_string_from_entity(scratch.arena, ent); + Vec4F32 color = df_rgba_from_entity(ent); + if(color.w != 0) + { + ui_set_next_text_color(color); + } + UI_Box *name_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##label_%p", display_string, ent); + df_box_equip_fuzzy_match_range_list_vis(name_label, item.name_match_ranges); + } + if(ui_signal_from_box(box).clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(ent); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_handle_list_push(scratch.arena, ¶ms.entity_list, params.entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ViewReturn)); + df_push_cmd__root(¶ms, view->cmd_spec); + } + } + } + + //- rjf: selected entity num -> handle + { + fev->selected_entity_handle = (1 <= cursor.y && cursor.y <= ent_arr.count) ? df_handle_from_entity(ent_arr.v[cursor.y-1].entity) : df_handle_zero(); + } + + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Target @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Target) +{ + DF_TargetViewState *tv = df_view_user_state(view, DF_TargetViewState); +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Target) +{ + DF_TargetViewState *tv = df_view_user_state(view, DF_TargetViewState); + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(Target) +{ + DF_TargetViewState *tv = df_view_user_state(view, DF_TargetViewState); + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + + // rjf: process commands + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + // rjf: process command + switch(core_cmd_kind) + { + default:break; + case DF_CoreCmdKind_PickFile: + { + String8 pick_string = cmd->params.file_path; + DF_Entity *storage_entity = entity; + if(tv->pick_dst_kind != DF_EntityKind_Nil) + { + DF_Entity *child = df_entity_child_from_kind(entity, tv->pick_dst_kind); + if(df_entity_is_nil(child)) + { + child = df_entity_alloc(0, entity, tv->pick_dst_kind); + } + storage_entity = child; + } + df_entity_equip_name(0, storage_entity, pick_string); + }break; + } + } +} + +DF_VIEW_UI_FUNCTION_DEF(Target) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + ui_set_focus_active(1); + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + DF_EntityList custom_entry_points = df_push_entity_child_list_with_kind(scratch.arena, entity, DF_EntityKind_EntryPointName); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + + //- rjf: grab state + DF_TargetViewState *tv = df_view_user_state(view, DF_TargetViewState); + if(tv->initialized == 0) + { + tv->initialized = 1; + tv->key_pct = 0.2f; + tv->value_pct = 0.8f; + } + + //- rjf: set up key-value-pair info + struct + { + B32 fill_with_file; + B32 use_code_font; + String8 key; + DF_EntityKind storage_child_kind; + String8 current_text; + } + kv_info[] = + { + { 0, 0, str8_lit("Label"), DF_EntityKind_Nil, entity->name }, + { 1, 0, str8_lit("Executable"), DF_EntityKind_Executable, df_entity_child_from_kind(entity, DF_EntityKind_Executable)->name }, + { 0, 0, str8_lit("Arguments"), DF_EntityKind_Arguments, df_entity_child_from_kind(entity, DF_EntityKind_Arguments)->name }, + { 1, 0, str8_lit("Working Directory"), DF_EntityKind_ExecutionPath, df_entity_child_from_kind(entity, DF_EntityKind_ExecutionPath)->name }, + { 0, 1, str8_lit("Entry Point Override"), DF_EntityKind_EntryPointName, df_entity_child_from_kind(entity, DF_EntityKind_EntryPointName)->name }, + }; + + //- rjf: take controls to start/end editing + B32 edit_begin = 0; + B32 edit_end = 0; + B32 edit_commit = 0; + B32 edit_submit = 0; + if(ui_is_focus_active()) + { + if(!tv->input_editing) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + { + if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + { + edit_begin = 1; + break; + } + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + { + edit_begin = 1; + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + edit_begin = 1; + } + } + if(tv->input_editing) + { + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + { + edit_end = 1; + edit_commit = 0; + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + edit_end = 1; + edit_commit = 1; + edit_submit = 1; + } + } + } + + //- rjf: build + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, (S64)ArrayCount(kv_info))); + scroll_list_params.item_range = r1s64(0, (S64)ArrayCount(kv_info)); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + DF_EntityKind commit_storage_child_kind = DF_EntityKind_Nil; + Vec2S64 next_cursor = tv->cursor; + UI_ScrollListSignal scroll_list_sig = {0}; + UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, tv->input_editing ? 0 : &tv->cursor, &visible_row_range, &scroll_list_sig) + { + next_cursor = tv->cursor; + F32 *col_pcts[] = {&tv->key_pct, &tv->value_pct}; + UI_TableF(ArrayCount(col_pcts), col_pcts, "###target_%p", view) + { + //- rjf: build fixed rows + S64 row_idx = 0; + for(S64 idx = visible_row_range.min; + idx <= visible_row_range.max && idx < ArrayCount(kv_info); + idx += 1, row_idx += 1) + UI_TableVector + { + B32 row_selected = (tv->cursor.y == idx+1); + B32 has_browse = kv_info[idx].fill_with_file; + + //- rjf: key (label) + UI_TableCell UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + if(kv_info[idx].storage_child_kind == DF_EntityKind_EntryPointName) + { + if(df_help_label(str8_lit("Custom Entry Point"))) UI_Tooltip + { + ui_label_multiline(ui_top_font_size()*30.f, str8_lit("By default, the debugger attempts to find a target's entry point with a set of default names, such as:")); + ui_spacer(ui_em(1.5f, 1.f)); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_CodeFunction)) + { + ui_label(str8_lit("WinMain")); + ui_label(str8_lit("wWinMain")); + ui_label(str8_lit("main")); + ui_label(str8_lit("wmain")); + ui_label(str8_lit("WinMainCRTStartup")); + ui_label(str8_lit("wWinMainCRTStartup")); + } + ui_spacer(ui_em(1.5f, 1.f)); + ui_label_multiline(ui_top_font_size()*30.f, str8_lit("A Custom Entry Point can be used to override these default symbol names with a symbol name of your choosing. If a symbol matching the Custom Entry Point is not found, the debugger will fall back to its default rules.")); + } + } + else + { + ui_build_box_from_string(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, kv_info[idx].key); + } + } + + //- rjf: value + UI_TableCell + { + // rjf: value editor + UI_WidthFill UI_Font(kv_info[idx].use_code_font ? df_font_from_slot(DF_FontSlot_Code) : df_font_from_slot(DF_FontSlot_Main)) + { + // rjf: * => focus + B32 value_selected = row_selected && (next_cursor.x == 0 || !has_browse); + + // rjf: begin editing + if(value_selected && edit_begin) + { + tv->input_editing = 1; + tv->input_size = Min(sizeof(tv->input_buffer), kv_info[idx].current_text.size); + MemoryCopy(tv->input_buffer, kv_info[idx].current_text.str, tv->input_size); + tv->input_cursor = txt_pt(1, 1+tv->input_size); + tv->input_mark = txt_pt(1, 1); + } + + // rjf: build main editor ui + UI_Signal sig = {0}; + UI_FocusHot(value_selected) UI_FocusActive(value_selected && tv->input_editing) + { + sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, &tv->input_cursor, &tv->input_mark, tv->input_buffer, sizeof(tv->input_buffer), &tv->input_size, 0, kv_info[idx].current_text, "###kv_editor_%i", (S32)idx); + edit_commit = edit_commit || sig.commit; + } + + // rjf: focus panel on press + if(sig.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + // rjf: begin editing on double-click + if(!tv->input_editing && sig.double_clicked) + { + ui_kill_action(); + tv->input_editing = 1; + tv->input_size = Min(sizeof(tv->input_buffer), kv_info[idx].current_text.size); + MemoryCopy(tv->input_buffer, kv_info[idx].current_text.str, tv->input_size); + tv->input_cursor = txt_pt(1, 1+tv->input_size); + tv->input_mark = txt_pt(1, 1); + } + + // rjf: press on non-selected => commit edit, change selected cell + if(sig.pressed && !value_selected) + { + edit_end = 1; + edit_commit = tv->input_editing; + next_cursor = v2s64(0, idx+1); + } + + // rjf: apply commit deltas + if(sig.commit) + { + next_cursor.y += 1; + } + + // rjf: grab commit destination + if(value_selected) + { + commit_storage_child_kind = kv_info[idx].storage_child_kind; + } + } + + // rjf: browse button to fill text field + if(has_browse) UI_PrefWidth(ui_text_dim(10, 1)) + { + UI_FocusHot(row_selected && next_cursor.x == 1) UI_TextAlignment(UI_TextAlign_Center) + if(ui_buttonf("Browse...").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + tv->pick_dst_kind = kv_info[idx].storage_child_kind; + } + } + } + } + } + } + + //- rjf: apply commit + if(edit_commit) + { + String8 new_string = str8(tv->input_buffer, tv->input_size); + df_state_delta_history_push_batch(df_state_delta_history(), 0); + switch(commit_storage_child_kind) + { + default: + { + DF_Entity *child = df_entity_child_from_kind(entity, commit_storage_child_kind); + if(df_entity_is_nil(child)) + { + child = df_entity_alloc(df_state_delta_history(), entity, commit_storage_child_kind); + } + df_entity_equip_name(df_state_delta_history(), child, new_string); + }break; + case DF_EntityKind_Nil: + { + df_entity_equip_name(df_state_delta_history(), entity, new_string); + }break; + } + } + + //- rjf: apply editing finish + if(edit_end) + { + tv->input_editing = 0; + } + if(edit_submit) + { + next_cursor.y += 1; + } + + //- rjf: apply moves to selection + tv->cursor = next_cursor; + + ui_unset_focus_active(); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Targets @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Targets) +{ +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Targets) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(Targets) +{ +} + +DF_VIEW_UI_FUNCTION_DEF(Targets) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DF_EntityList targets_list = df_query_cached_entity_list_with_kind(DF_EntityKind_Target); + DF_EntityArray targets = df_entity_array_from_list(scratch.arena, &targets_list); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + + //- rjf: grab state + typedef struct DF_TargetsViewState DF_TargetsViewState; + struct DF_TargetsViewState + { + B32 selected_add; + DF_Handle selected_target_handle; + S64 selected_column; + }; + DF_TargetsViewState *tv = df_view_user_state(view, DF_TargetsViewState); + + //- rjf: determine table bounds + Vec2S64 table_bounds = {5, (S64)targets.count+1}; + + //- rjf: selection state => cursor + // NOTE(rjf): 0 => nothing, 1 => add new, 2 => first target + Vec2S64 cursor = {0}; + { + DF_Entity *selected_target = df_entity_from_handle(tv->selected_target_handle); + for(U64 idx = 0; idx < targets.count; idx += 1) + { + if(selected_target == targets.v[idx]) + { + cursor.y = (S64)idx+2; + break; + } + } + if(tv->selected_add) + { + cursor.y = 1; + } + cursor.x = tv->selected_column; + } + + //- rjf: build + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(5, Max(0, (S64)targets.count+1))); + scroll_list_params.item_range = r1s64(0, Max(0, (S64)targets.count+1)); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + { + // rjf: add new ctrl + if(visible_row_range.min == 0) + { + UI_Signal add_sig = {0}; + UI_FocusHot(cursor.y == 1) add_sig = df_icon_buttonf(DF_IconKind_Add, "Add New Target"); + if(add_sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_AddTarget); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + } + + // rjf: target rows + for(S64 row_idx = Max(1, visible_row_range.min); + row_idx <= visible_row_range.max && row_idx <= targets.count; + row_idx += 1) + UI_Row + { + DF_Entity *target = targets.v[row_idx-1]; + B32 row_selected = ((U64)cursor.y == row_idx+1); + + // rjf: enabled + UI_PrefWidth(ui_em(2.25f, 1)) UI_FocusHot(row_selected && cursor.x == 0) + if(df_icon_buttonf(target->b32 ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, "###ebl_%p", target).clicked) + { + df_entity_equip_b32(target, !target->b32); + } + + // rjf: target name + UI_WidthFill UI_FocusHot(row_selected && cursor.x == 1) + { + df_entity_desc_button(ws, target); + } + + // rjf: controls + UI_PrefWidth(ui_em(2.25f, 1.f)) + { + struct + { + DF_IconKind icon; + String8 text; + DF_CoreCmdKind cmd; + } + ctrls[] = + { + { DF_IconKind_PlayStepForward, str8_lit("Launch and Initialize"), DF_CoreCmdKind_LaunchAndInit }, + { DF_IconKind_Play, str8_lit("Launch and Run"), DF_CoreCmdKind_LaunchAndRun }, + { DF_IconKind_Pencil, str8_lit("Edit"), DF_CoreCmdKind_Target }, + { DF_IconKind_Trash, str8_lit("Delete"), DF_CoreCmdKind_RemoveTarget }, + }; + for(U64 ctrl_idx = 0; ctrl_idx < ArrayCount(ctrls); ctrl_idx += 1) + { + UI_Signal sig = {0}; + UI_FocusHot(row_selected && cursor.x == 2+ctrl_idx) + { + sig = df_icon_buttonf(ctrls[ctrl_idx].icon, "###%p_ctrl_%i", target, (int)ctrl_idx); + } + if(sig.hovering) UI_Tooltip + { + ui_label(ctrls[ctrl_idx].text); + } + if(sig.clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(target); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_handle_list_push(scratch.arena, ¶ms.entity_list, params.entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(ctrls[ctrl_idx].cmd)); + } + } + } + } + } + + //- rjf: commit cursor to selection state + { + tv->selected_column = cursor.x; + tv->selected_target_handle = (1 < cursor.y && cursor.y < targets.count+2) ? df_handle_from_entity(targets.v[cursor.y-2]) : df_handle_zero(); + tv->selected_add = (cursor.y == 1); + } + + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: FilePathMap @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(FilePathMap) +{ + DF_FilePathMapViewState *fpms = df_view_user_state(view, DF_FilePathMapViewState); + if(fpms->initialized == 0) + { + fpms->initialized = 1; + fpms->src_column_pct = 0.5f; + fpms->dst_column_pct = 0.5f; + } +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(FilePathMap) +{ + DF_FilePathMapViewState *fpms = df_view_user_state(view, DF_FilePathMapViewState); + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(FilePathMap) +{ + DF_FilePathMapViewState *fpms = df_view_user_state(view, DF_FilePathMapViewState); + + // rjf: process commands + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + //rjf: process + switch(core_cmd_kind) + { + default:break; + case DF_CoreCmdKind_PickFile: + { + String8 pick_string = cmd->params.file_path; + Side pick_side = fpms->pick_file_dst_side; + DF_Entity *storage_entity = df_entity_from_handle(fpms->pick_file_dst_map); + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.entity = df_handle_from_entity(storage_entity); + p.file_path = pick_string; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(pick_side == Side_Min ? + DF_CoreCmdKind_SetFileOverrideLinkSrc : + DF_CoreCmdKind_SetFileOverrideLinkDst)); + }break; + } + } +} + +DF_VIEW_UI_FUNCTION_DEF(FilePathMap) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + ui_set_focus_active(1); + DF_EntityList maps_list = df_query_cached_entity_list_with_kind(DF_EntityKind_OverrideFileLink); + DF_EntityArray maps = df_entity_array_from_list(scratch.arena, &maps_list); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + + //- rjf: grab state + DF_FilePathMapViewState *fpms = df_view_user_state(view, DF_FilePathMapViewState); + + //- rjf: take controls to start/end editing + B32 edit_begin = 0; + B32 edit_end = 0; + B32 edit_commit = 0; + B32 edit_submit = 0; + if(ui_is_focus_active()) + { + if(!fpms->input_editing) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + { + if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + { + edit_begin = 1; + break; + } + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + { + edit_begin = 1; + } + } + if(fpms->input_editing) + { + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + { + edit_end = 1; + edit_commit = 0; + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + edit_end = 1; + edit_commit = 1; + edit_submit = 1; + } + } + } + + //- rjf: build + DF_Handle commit_map = df_handle_zero(); + Side commit_side = Side_Invalid; + F32 *col_pcts[] = { &fpms->src_column_pct, &fpms->dst_column_pct }; + Vec2S64 next_cursor = fpms->cursor; + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, maps.count + 1)); + scroll_list_params.item_range = r1s64(0, maps.count+2); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, fpms->input_editing ? 0 : &fpms->cursor, &visible_row_range, &scroll_list_sig) + UI_TableF(ArrayCount(col_pcts), col_pcts, "###tbl") + { + next_cursor = fpms->cursor; + + //- rjf: header + if(visible_row_range.min == 0) UI_TableVector UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + UI_TableCell if(df_help_label(str8_lit("Source Path"))) UI_Tooltip + { + ui_label_multiline(ui_top_font_size()*30, str8_lit("When the debugger attempts to open a file or folder at a Source Path specified in this table, it will redirect to the file or folder specified by the Destination Path.")); + } + UI_TableCell ui_label(str8_lit("Destination Path")); + } + + //- rjf: map rows + for(S64 row_idx = Max(1, visible_row_range.min); + row_idx <= visible_row_range.max && row_idx <= maps.count+1; + row_idx += 1) UI_TableVector + { + U64 map_idx = row_idx-1; + DF_Entity *map = (map_idx < maps.count ? maps.v[map_idx] : &df_g_nil_entity); + DF_Entity *map_link = df_entity_from_handle(map->entity_handle); + String8 map_src_path = df_full_path_from_entity(scratch.arena, map); + String8 map_dst_path = df_full_path_from_entity(scratch.arena, map_link); + B32 row_selected = (fpms->cursor.y == row_idx); + + //- rjf: src + UI_TableCell UI_WidthFill + { + //- rjf: editor + { + B32 value_selected = (row_selected && fpms->cursor.x == 0); + + // rjf: begin editing + if(value_selected && edit_begin) + { + fpms->input_editing = 1; + fpms->input_size = Min(sizeof(fpms->input_buffer), map_src_path.size); + MemoryCopy(fpms->input_buffer, map_src_path.str, fpms->input_size); + fpms->input_cursor = txt_pt(1, 1+fpms->input_size); + fpms->input_mark = txt_pt(1, 1); + } + + // rjf: build + UI_Signal sig = {0}; + UI_FocusHot(value_selected) UI_FocusActive(value_selected && fpms->input_editing) + { + sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, &fpms->input_cursor, &fpms->input_mark, fpms->input_buffer, sizeof(fpms->input_buffer), &fpms->input_size, 0, map_src_path, "###src_editor_%p", map); + edit_commit = edit_commit || sig.commit; + } + + // rjf: focus panel on press + if(sig.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + // rjf: begin editing on double-click + if(!fpms->input_editing && sig.double_clicked) + { + fpms->input_editing = 1; + fpms->input_size = Min(sizeof(fpms->input_buffer), map_src_path.size); + MemoryCopy(fpms->input_buffer, map_src_path.str, fpms->input_size); + fpms->input_cursor = txt_pt(1, 1+fpms->input_size); + fpms->input_mark = txt_pt(1, 1); + } + + // rjf: press on non-selected => commit edit, change selected cell + if(sig.pressed && !value_selected) + { + edit_end = 1; + edit_commit = fpms->input_editing; + next_cursor.x = 0; + next_cursor.y = map_idx+1; + } + + // rjf: store commit information + if(value_selected) + { + commit_side = Side_Min; + commit_map = df_handle_from_entity(map); + } + } + + //- rjf: browse button + UI_FocusHot(row_selected && fpms->cursor.x == 1) UI_PrefWidth(ui_text_dim(10, 1)) + if(ui_buttonf("Browse...").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + fpms->pick_file_dst_map = df_handle_from_entity(map); + fpms->pick_file_dst_side = Side_Min; + } + } + + //- rjf: dst + UI_TableCell UI_WidthFill + { + //- rjf: editor + { + B32 value_selected = (row_selected && fpms->cursor.x == 2); + + // rjf: begin editing + if(value_selected && edit_begin) + { + fpms->input_editing = 1; + fpms->input_size = Min(sizeof(fpms->input_buffer), map_dst_path.size); + MemoryCopy(fpms->input_buffer, map_dst_path.str, fpms->input_size); + fpms->input_cursor = txt_pt(1, 1+fpms->input_size); + fpms->input_mark = txt_pt(1, 1); + } + + // rjf: build + UI_Signal sig = {0}; + UI_FocusHot(value_selected) UI_FocusActive(value_selected && fpms->input_editing) + { + sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, &fpms->input_cursor, &fpms->input_mark, fpms->input_buffer, sizeof(fpms->input_buffer), &fpms->input_size, 0, map_dst_path, "###dst_editor_%p", map); + edit_commit = edit_commit || sig.commit; + } + + // rjf: focus panel on press + if(sig.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + // rjf: begin editing on double-click + if(!fpms->input_editing && sig.double_clicked) + { + fpms->input_editing = 1; + fpms->input_size = Min(sizeof(fpms->input_buffer), map_dst_path.size); + MemoryCopy(fpms->input_buffer, map_dst_path.str, fpms->input_size); + fpms->input_cursor = txt_pt(1, 1+fpms->input_size); + fpms->input_mark = txt_pt(1, 1); + } + + // rjf: press on non-selected => commit edit, change selected cell + if(sig.pressed && !value_selected) + { + edit_end = 1; + edit_commit = fpms->input_editing; + next_cursor.x = 2; + next_cursor.y = map_idx+1; + } + + // rjf: store commit information + if(value_selected) + { + commit_side = Side_Max; + commit_map = df_handle_from_entity(map); + } + } + + //- rjf: browse button + { + UI_FocusHot(row_selected && fpms->cursor.x == 3) UI_PrefWidth(ui_text_dim(10, 1)) + if(ui_buttonf("Browse...").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + fpms->pick_file_dst_map = df_handle_from_entity(map); + fpms->pick_file_dst_side = Side_Max; + } + } + } + } + } + + //- rjf: apply commit + if(edit_commit && commit_side != Side_Invalid) + { + String8 new_string = str8(fpms->input_buffer, fpms->input_size); + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.entity = commit_map; + p.file_path = new_string; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(commit_side == Side_Min ? + DF_CoreCmdKind_SetFileOverrideLinkSrc : + DF_CoreCmdKind_SetFileOverrideLinkDst)); + } + + //- rjf: apply editing finish + if(edit_end) + { + fpms->input_editing = 0; + } + + //- rjf: move down one row if submitted + if(edit_submit) + { + next_cursor.y += 1; + } + + //- rjf: apply moves to selection + fpms->cursor = next_cursor; + + ui_unset_focus_active(); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Scheduler @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Scheduler) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Scheduler) {return str8_lit("");} +DF_VIEW_CMD_FUNCTION_DEF(Scheduler) {} +DF_VIEW_UI_FUNCTION_DEF(Scheduler) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + + //- rjf: get state + typedef struct DF_SchedulerViewState DF_SchedulerViewState; + struct DF_SchedulerViewState + { + DF_Handle selected_entity; + S64 selected_column; + }; + DF_SchedulerViewState *sv = df_view_user_state(view, DF_SchedulerViewState); + + //- rjf: get entities + DF_EntityList machines = df_query_cached_entity_list_with_kind(DF_EntityKind_Machine); + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + DF_EntityList threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); + + //- rjf: build flat array of entities, arranged into row order + DF_EntityArray entities = {0}; + { + entities.count = machines.count+processes.count+threads.count; + entities.v = push_array_no_zero(scratch.arena, DF_Entity *, entities.count); + U64 idx = 0; + for(DF_EntityNode *machine_n = machines.first; machine_n != 0; machine_n = machine_n->next) + { + DF_Entity *machine = machine_n->entity; + entities.v[idx] = machine; + idx += 1; + for(DF_EntityNode *process_n = processes.first; process_n != 0; process_n = process_n->next) + { + DF_Entity *process = process_n->entity; + if(df_entity_ancestor_from_kind(process, DF_EntityKind_Machine) != machine) + { + continue; + } + entities.v[idx] = process; + idx += 1; + for(DF_EntityNode *thread_n = threads.first; thread_n != 0; thread_n = thread_n->next) + { + DF_Entity *thread = thread_n->entity; + if(df_entity_ancestor_from_kind(thread, DF_EntityKind_Process) != process) + { + continue; + } + entities.v[idx] = thread; + idx += 1; + } + } + } + } + + //- rjf: selected column/entity -> selected cursor + Vec2S64 cursor = {sv->selected_column}; + for(U64 idx = 0; idx < entities.count; idx += 1) + { + if(entities.v[idx] == df_entity_from_handle(sv->selected_entity)) + { + cursor.y = (S64)(idx+1); + break; + } + } + + //- rjf: build table + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(4, entities.count)); + scroll_list_params.item_range = r1s64(0, entities.count); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_TableF(0, 0, "scheduler_table") + { + Vec2S64 next_cursor = cursor; + for(U64 idx = visible_row_range.min; + idx <= visible_row_range.max && idx < entities.count; + idx += 1) + { + DF_Entity *entity = entities.v[idx]; + B32 row_is_selected = (cursor.y == (S64)(idx+1)); + F32 depth = 0.f; + switch(entity->kind) + { + default:{}break; + case DF_EntityKind_Machine:{depth = 0.f;}break; + case DF_EntityKind_Process:{depth = 1.f;}break; + case DF_EntityKind_Thread: {depth = 2.f;}break; + } + Rng1S64 desc_col_rng = r1s64(1, 1); + switch(entity->kind) + { + default:{}break; + case DF_EntityKind_Machine:{desc_col_rng = r1s64(1, 4);}break; + case DF_EntityKind_Process:{desc_col_rng = r1s64(1, 1);}break; + case DF_EntityKind_Thread: {desc_col_rng = r1s64(1, 1);}break; + } + UI_NamedTableVectorF("entity_row_%p", entity) + { + UI_TableCellSized(ui_em(1.5f*depth, 1.f)) {} + UI_TableCellSized(ui_em(2.25f, 1.f)) UI_FocusHot(row_is_selected && cursor.x == 0) + { + B32 frozen_by_solo_mode = (entity->kind == DF_EntityKind_Thread && entity != df_entity_from_handle(ctrl_ctx.thread) && df_state->ctrl_solo_stepping_mode); + B32 frozen = df_entity_is_frozen(entity); + Vec4F32 frozen_color = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + Vec4F32 frozen_in_solo_mode_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + Vec4F32 thawed_color = df_rgba_from_theme_color(DF_ThemeColor_SuccessBackground); + UI_Signal sig = {0}; + UI_BackgroundColor(frozen ? frozen_color : thawed_color) + { + if(frozen_by_solo_mode) + { + ui_set_next_background_color(frozen_in_solo_mode_color); + } + sig = df_icon_buttonf(frozen ? DF_IconKind_Locked : DF_IconKind_Unlocked, "###lock_%p", entity); + } + if(frozen_by_solo_mode && sig.hovering) UI_Tooltip + { + ui_label(str8_lit("This thread is frozen during stepping operations because it isn't selected, and Solo Stepping Mode is enabled.")); + } + if(sig.clicked) + { + DF_CoreCmdKind cmd_kind = frozen ? DF_CoreCmdKind_ThawEntity : DF_CoreCmdKind_FreezeEntity; + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(cmd_kind)); + } + } + UI_TableCellSized(ui_pct(1, 0)) UI_FocusHot(row_is_selected && desc_col_rng.min <= cursor.x && cursor.x <= desc_col_rng.max) + { + df_entity_desc_button(ws, entity); + } + switch(entity->kind) + { + default:{}break; + case DF_EntityKind_Machine: + { + + }break; + case DF_EntityKind_Process: + { + UI_TableCellSized(ui_children_sum(1.f)) UI_FocusHot(row_is_selected && cursor.x == 2) + { + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextAlignment(UI_TextAlign_Center) + if(ui_buttonf("Detach").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Detach)); + } + } + UI_TableCellSized(ui_em(2.25f, 1.f)) UI_FocusHot(row_is_selected && cursor.x == 3) + { + if(df_icon_buttonf(DF_IconKind_Redo, "###retry").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_handle_list_push(scratch.arena, ¶ms.entity_list, df_handle_from_entity(entity)); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_EntityList); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Restart)); + } + } + UI_TableCellSized(ui_em(2.25f, 1.f)) UI_FocusHot(row_is_selected && cursor.x == 4) + { + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureText)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBorder)) + if(df_icon_buttonf(DF_IconKind_X, "###kill").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_handle_list_push(scratch.arena, ¶ms.entity_list, df_handle_from_entity(entity)); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_EntityList); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Kill)); + } + } + }break; + case DF_EntityKind_Thread: + { + UI_TableCellSized(ui_children_sum(1.f)) UI_FocusHot(row_is_selected && cursor.x >= 2) + { + DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); + U64 rip_vaddr = df_query_cached_rip_from_thread(entity); + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + if(!df_entity_is_nil(line_info.file)) + { + UI_PrefWidth(ui_children_sum(0)) df_entity_src_loc_button(ws, line_info.file, line_info.pt); + } + } + }break; + } + } + } + cursor = next_cursor; + } + + //- rjf: selected num -> selected entity + sv->selected_column = cursor.x; + sv->selected_entity = (1 <= cursor.y && cursor.y <= entities.count) ? df_handle_from_entity(entities.v[cursor.y-1]) : df_handle_zero(); + + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: CallStack @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(CallStack) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(CallStack) { return str8_lit(""); } +DF_VIEW_CMD_FUNCTION_DEF(CallStack) {} +DF_VIEW_UI_FUNCTION_DEF(CallStack) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + ui_set_focus_active(1); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + U64 selected_unwind_count = ctrl_ctx.unwind_count; + DF_Entity *process = thread->parent; + Vec4F32 thread_color = df_rgba_from_theme_color(DF_ThemeColor_PlainText); + if(thread->flags & DF_EntityFlag_HasColor) + { + thread_color = df_rgba_from_entity(thread); + } + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + + //- rjf: grab state + typedef struct DF_CallStackViewState DF_CallStackViewState; + struct DF_CallStackViewState + { + B32 initialized; + Vec2S64 cursor; + F32 selection_col_pct; + F32 module_col_pct; + F32 function_name_col_pct; + F32 addr_col_pct; + }; + DF_CallStackViewState *cs = df_view_user_state(view, DF_CallStackViewState); + if(cs->initialized == 0) + { + cs->initialized = 1; + cs->selection_col_pct = 0.05f; + cs->module_col_pct = 0.35f; + cs->function_name_col_pct = 0.4f; + cs->addr_col_pct = 0.2f; + } + + //- rjf: build ui + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, unwind.count)); + scroll_list_params.item_range = r1s64(0, unwind.count+1); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cs->cursor, &visible_row_range, &scroll_list_sig) + { + Vec2S64 next_cursor = cs->cursor; + + //- rjf: build table + if(df_ctrl_targets_running()) + { + ui_set_next_flags(UI_BoxFlag_Disabled); + } + F32 *col_pcts[] = { &cs->selection_col_pct, &cs->module_col_pct, &cs->function_name_col_pct, &cs->addr_col_pct }; + UI_TableF(ArrayCount(col_pcts), col_pcts, "###tbl") + { + //- rjf: header + if(visible_row_range.min == 0) UI_TableVector UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + UI_TableCell {} + UI_TableCell ui_label(str8_lit("Module")); + UI_TableCell ui_label(str8_lit("Function Name")); + UI_TableCell ui_label(str8_lit("Address")); + } + + //- rjf: frame rows + U64 frame_idx = 0; + for(DF_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, frame_idx += 1) + { + // rjf: out of range -> skip (TODO(rjf): this should be an array...) + if(frame_idx+1 < visible_row_range.min || visible_row_range.max < frame_idx+1) + { + continue; + } + + // rjf: determine selection + B32 row_selected = cs->cursor.y == ((S64)frame_idx+1); + + // rjf: regs => rip + U64 rip_vaddr = frame->rip; + + // rjf: rip_vaddr => module + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + + // rjf: module => validity? + B32 frame_valid = !df_entity_is_nil(module); + + // rjf: build row + if(frame_valid) UI_NamedTableVectorF("###callstack_%p_%I64x", view, frame_idx) + { + // rjf: build cell for selection + UI_TableCell + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) + UI_TextColor(thread_color) + UI_WidthFill + UI_TextAlignment(UI_TextAlign_Center) + UI_FocusHot(row_selected && cs->cursor.x == 0) + { + String8 selected_string = selected_unwind_count == frame_idx ? df_g_icon_kind_text_table[DF_IconKind_RightArrow] : str8_lit(""); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%S###selection_%i", selected_string, + (int)frame_idx); + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + next_cursor = v2s64(0, (S64)frame_idx+1); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + if(sig.double_clicked || sig.keyboard_clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.index = frame_idx; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind)); + } + } + + // rjf: build cell for module + UI_TableCell UI_FocusHot(row_selected && cs->cursor.x == 1) + { + df_entity_desc_button(ws, module); + } + + // rjf: build cell for function name + UI_TableCell UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_FocusHot(row_selected && cs->cursor.x == 2) + { + String8 symbol = df_symbol_name_from_process_vaddr(scratch.arena, process, rip_vaddr); + if(symbol.size == 0) + { + symbol = str8_lit("[external code]"); + ui_set_next_text_color(df_rgba_from_theme_color(DF_ThemeColor_WeakText)); + } + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, symbol); + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + next_cursor = v2s64(2, (S64)frame_idx+1); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + if(sig.double_clicked || sig.keyboard_clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.index = frame_idx; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind)); + } + } + + // rjf: build cell for rip + UI_TableCell UI_FocusHot(row_selected && cs->cursor.x == 3) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "0x%I64x", rip_vaddr); + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + next_cursor = v2s64(3, (S64)frame_idx+1); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + if(sig.double_clicked || sig.keyboard_clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.index = frame_idx; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectUnwind)); + } + } + } + + // rjf: end if hit invalid frame + if(frame_valid == 0) + { + break; + } + } + + // rjf: apply moves to selection + cs->cursor = next_cursor; + } + } + + ui_unset_focus_active(); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Modules @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Modules) +{ + DF_ModulesViewState *mv = df_view_user_state(view, DF_ModulesViewState); + if(mv->initialized == 0) + { + mv->initialized = 1; + mv->idx_col_pct = 0.05f; + mv->desc_col_pct = 0.15f; + mv->range_col_pct = 0.30f; + mv->dbg_col_pct = 0.50f; + } +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Modules) {return str8_lit("");} + +DF_VIEW_CMD_FUNCTION_DEF(Modules) +{ + DF_ModulesViewState *mv = df_view_user_state(view, DF_ModulesViewState); + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + //rjf: process + switch(core_cmd_kind) + { + default:break; + case DF_CoreCmdKind_PickFile: + { + Temp scratch = scratch_begin(0, 0); + String8 pick_string = cmd->params.file_path; + DF_Entity *module = df_entity_from_handle(mv->pick_file_dst_entity); + if(module->kind == DF_EntityKind_Module) + { + String8 exe_path = module->name; + String8 dbg_path = pick_string; + dbgi_force_exe_path_dbg_path(exe_path, dbg_path); + } + scratch_end(scratch); + }break; + } + } +} + +DF_VIEW_UI_FUNCTION_DEF(Modules) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + ui_set_focus_active(1); + DBGI_Scope *scope = dbgi_scope_open(); + + //- rjf: get state + DF_ModulesViewState *mv = df_view_user_state(view, DF_ModulesViewState); + F32 *col_pcts[] = {&mv->idx_col_pct, &mv->desc_col_pct, &mv->range_col_pct, &mv->dbg_col_pct}; + + //- rjf: get entities + DF_EntityList processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process); + DF_EntityList modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); + + //- rjf: build flat array of entities, arranged into row order + DF_EntityArray entities = {0}; + { + entities.count = processes.count+modules.count; + entities.v = push_array_no_zero(scratch.arena, DF_Entity *, entities.count); + U64 idx = 0; + for(DF_EntityNode *process_n = processes.first; process_n != 0; process_n = process_n->next) + { + DF_Entity *process = process_n->entity; + entities.v[idx] = process; + idx += 1; + for(DF_EntityNode *module_n = modules.first; module_n != 0; module_n = module_n->next) + { + DF_Entity *module = module_n->entity; + if(df_entity_ancestor_from_kind(module, DF_EntityKind_Process) != process) + { + continue; + } + entities.v[idx] = module; + idx += 1; + } + } + } + + //- rjf: selected column/entity -> selected cursor + Vec2S64 cursor = {mv->selected_column}; + for(U64 idx = 0; idx < entities.count; idx += 1) + { + if(entities.v[idx] == df_entity_from_handle(mv->selected_entity)) + { + cursor.y = (S64)(idx+1); + break; + } + } + + ////////////////////////////// + //- rjf: do start/end editing interaction + // + B32 edit_begin = 0; + B32 edit_commit = 0; + B32 edit_end = 0; + B32 edit_submit = 0; + if(!mv->txt_editing && ui_is_focus_active()) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + { + if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + { + edit_begin = 1; + break; + } + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2) || + os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + edit_begin = 1; + } + } + if(mv->txt_editing && ui_is_focus_active()) + { + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + { + edit_end = 1; + edit_commit = 0; + } + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + edit_end = 1; + edit_commit = 1; + edit_submit = 1; + } + } + + //- rjf: build table + DF_Entity *commit_module = &df_g_nil_entity; + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, entities.count)); + scroll_list_params.item_range = r1s64(0, entities.count); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, mv->txt_editing ? 0 : &cursor, &visible_row_range, &scroll_list_sig) + UI_TableF(ArrayCount(col_pcts), col_pcts, "modules_table") + { + Vec2S64 next_cursor = cursor; + U64 idx_in_process = 0; + for(U64 idx = 0; idx < entities.count; idx += 1) + { + DF_Entity *entity = entities.v[idx]; + B32 row_is_selected = (cursor.y == (S64)(idx+1)); + idx_in_process += (entity->kind == DF_EntityKind_Module); + if(visible_row_range.min <= idx && idx <= visible_row_range.max) + { + switch(entity->kind) + { + default:{}break; + case DF_EntityKind_Process: + { + UI_NamedTableVectorF("process_%p", entity) + { + UI_TableCellSized(ui_pct(1, 0)) UI_FocusHot(row_is_selected) + { + df_entity_desc_button(ws, entity); + } + } + idx_in_process = 0; + }break; + case DF_EntityKind_Module: + UI_NamedTableVectorF("module_%p", entity) + { + UI_TableCell UI_TextAlignment(UI_TextAlign_Center) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + ui_labelf("%I64u", idx_in_process); + } + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 0) + { + df_entity_desc_button(ws, entity); + } + UI_TableCell UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_FocusHot(row_is_selected && cursor.x == 1) + { + UI_Box *range_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "[0x%I64x, 0x%I64x)###vaddr_range_%p", entity->vaddr_rng.min, entity->vaddr_rng.max, entity); + UI_Signal sig = ui_signal_from_box(range_box); + if(sig.pressed) + { + next_cursor = v2s64(1, (S64)idx+1); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + UI_TableCell + { + B32 txt_is_selected = (row_is_selected && cursor.x == 2); + B32 brw_is_selected = (row_is_selected && cursor.x == 3); + + // rjf: unpack module info + DF_Entity *binary = df_binary_file_from_module(entity); + DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); + B32 dbgi_is_valid = (dbgi->dbg_props.modified != 0); + + // rjf: begin editing + if(txt_is_selected && edit_begin) + { + mv->txt_editing = 1; + mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi->dbg_path.size); + MemoryCopy(mv->txt_buffer, dbgi->dbg_path.str, mv->txt_size); + mv->txt_cursor = txt_pt(1, 1+mv->txt_size); + mv->txt_mark = txt_pt(1, 1); + } + + // rjf: build + UI_Signal sig = {0}; + UI_FocusHot(txt_is_selected) UI_FocusActive(txt_is_selected && mv->txt_editing) UI_WidthFill + { + UI_TextColor(!dbgi_is_valid ? df_rgba_from_theme_color(DF_ThemeColor_FailureBackground) : ui_top_text_color()) + sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, &mv->txt_cursor, &mv->txt_mark, mv->txt_buffer, sizeof(mv->txt_buffer), &mv->txt_size, 0, dbgi->dbg_path, "###dbg_path_%p", entity); + edit_commit = (edit_commit || sig.commit); + } + + // rjf: press -> focus + if(sig.pressed) + { + edit_commit = (mv->txt_editing && !txt_is_selected); + next_cursor = v2s64(2, (S64)idx+1); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + // rjf: double-click -> begin editing + if(sig.double_clicked && !mv->txt_editing) + { + ui_kill_action(); + mv->txt_editing = 1; + mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi->dbg_path.size); + MemoryCopy(mv->txt_buffer, dbgi->dbg_path.str, mv->txt_size); + mv->txt_cursor = txt_pt(1, 1+mv->txt_size); + mv->txt_mark = txt_pt(1, 1); + } + + // rjf: store commit info + if(txt_is_selected && edit_commit) + { + commit_module = entity; + } + + // rjf: build browse button + UI_FocusHot(brw_is_selected) UI_PrefWidth(ui_text_dim(10, 1)) + { + if(ui_buttonf("Browse...").clicked || (brw_is_selected && edit_begin)) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + mv->pick_file_dst_entity = df_handle_from_entity(entity); + } + } + } + }break; + } + } + } + cursor = next_cursor; + } + + //- rjf: apply commits + if(edit_commit) + { + mv->txt_editing = 0; + if(!df_entity_is_nil(commit_module)) + { + String8 exe_path = commit_module->name; + String8 dbg_path = str8(mv->txt_buffer, mv->txt_size); + dbgi_force_exe_path_dbg_path(exe_path, dbg_path); + } + if(edit_submit) + { + cursor.y += 1; + } + } + + //- rjf: apply edit state changes + if(edit_end) + { + mv->txt_editing = 0; + } + + //- rjf: selected num -> selected entity + mv->selected_column = cursor.x; + mv->selected_entity = (1 <= cursor.y && cursor.y <= entities.count) ? df_handle_from_entity(entities.v[cursor.y-1]) : df_handle_zero(); + + dbgi_scope_close(scope); + ui_unset_focus_active(); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: PendingEntity @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(PendingEntity) +{ + DF_PendingEntityViewState *pves = df_view_user_state(view, DF_PendingEntityViewState); + pves->deferred_cmd_arena = df_view_push_arena_ext(view); + pves->complete_cfg_arena = df_view_push_arena_ext(view); + pves->complete_cfg_root = df_cfg_tree_copy(pves->complete_cfg_arena, cfg_root); +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(PendingEntity) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(PendingEntity) +{ + Temp scratch = scratch_begin(0, 0); + DF_PendingEntityViewState *pves = df_view_user_state(view, DF_PendingEntityViewState); + + //- rjf: process commands + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + // rjf: process + switch(core_cmd_kind) + { + default:break; + + // rjf: pick file + case DF_CoreCmdKind_PickFile: + { + DF_Entity *missing_file = df_entity_from_handle(pves->pick_file_override_target); + String8 pick_string = cmd->params.file_path; + if(!df_entity_is_nil(missing_file) && pick_string.size != 0) + { + DF_Entity *replacement = df_entity_from_path(pick_string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + view->cmd_entity = df_handle_from_entity(replacement); + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.entity = df_handle_from_entity(missing_file); + p.file_path = pick_string; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetFileReplacementPath)); + } + }break; + + // rjf: gather deferred commands to redispatch when entity is ready + case DF_CoreCmdKind_GoToLine: + case DF_CoreCmdKind_GoToAddress: + case DF_CoreCmdKind_CenterCursor: + case DF_CoreCmdKind_ContainCursor: + { + df_cmd_list_push(pves->deferred_cmd_arena, &pves->deferred_cmds, &cmd->params, cmd->spec); + }break; + } + } + + //- rjf: determine if entity is ready, and which viewer to use + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + DF_CoreCmdKind viewer_cmd_kind = DF_CoreCmdKind_Null; + B32 entity_is_ready = 0; + switch(entity->kind) + { + default:{}break; + case DF_EntityKind_File: + { + entity_is_ready = 1; + viewer_cmd_kind = DF_CoreCmdKind_Code; + }break; + } + + //- rjf: if entity is ready, dispatch all deferred commands + if(entity_is_ready) + { + for(DF_CmdNode *cmd_node = pves->deferred_cmds.first; cmd_node != 0; cmd_node = cmd_node->next) + { + DF_Cmd *cmd = &cmd_node->cmd; + df_push_cmd__root(&cmd->params, cmd->spec); + } + arena_clear(pves->deferred_cmd_arena); + MemoryZeroStruct(&pves->deferred_cmds); + } + + //- rjf: if entity is ready, move cfg tree to scratch for new command + DF_CfgNode *cfg_root = &df_g_nil_cfg_node; + if(entity_is_ready) + { + cfg_root = df_cfg_tree_copy(scratch.arena, pves->complete_cfg_root); + } + + //- rjf: if entity is ready, replace this view with the correct one, if any viewer is specified + if(entity_is_ready && viewer_cmd_kind != DF_CoreCmdKind_Null) + { + DF_CmdSpec *spec = df_cmd_spec_from_string(cfg_root->string); + if(df_cmd_spec_is_nil(spec)) + { + spec = df_cmd_spec_from_core_cmd_kind(viewer_cmd_kind); + } + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_view_equip_command(view, spec, ¶ms, str8_lit(""), cfg_root); + df_panel_notify_mutation(ws, panel); + } + + //- rjf: if entity is ready, but we have no viewer for it, then just close this tab + if(entity_is_ready && viewer_cmd_kind == DF_CoreCmdKind_Null) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseTab)); + } + + scratch_end(scratch); +} + +DF_VIEW_UI_FUNCTION_DEF(PendingEntity) +{ + // rjf: grab state + DF_PendingEntityViewState *pves = df_view_user_state(view, DF_PendingEntityViewState); + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + + // rjf: entity is missing -> notify user + if(entity->flags & DF_EntityFlag_IsMissing) + { + UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_pct(1, 0)) + { + Temp scratch = scratch_begin(0, 0); + String8 full_path = df_full_path_from_entity(scratch.arena, entity); + UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_em(3, 1)) + UI_Row UI_Padding(ui_pct(1, 0)) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) + { + UI_Font(ui_icon_font()) ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); + ui_labelf("Could not find \"%S\".", full_path); + } + UI_PrefHeight(ui_em(3, 1)) + UI_Row UI_Padding(ui_pct(1, 0)) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) + UI_CornerRadius(ui_top_font_size()/3) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_Focus(1) + if(ui_buttonf("Find alternative...").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + pves->pick_file_override_target = df_handle_from_entity(entity); + } + scratch_end(scratch); + } + } + + // rjf: entity is still loading -> loading animation + else + { + view->loading_t = view->loading_t_target = 1.f; + df_gfx_request_frame(); + } +} + +//////////////////////////////// +//~ rjf: Code @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Code) +{ + // rjf: set up state + DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); + if(tv->initialized == 0) + { + tv->initialized = 1; + tv->cursor = tv->mark = txt_pt(1, 1); + tv->preferred_column = 1; + tv->find_text_arena = df_view_push_arena_ext(view); + } + + // rjf: deserialize cursor + DF_CfgNode *cursor_cfg = df_cfg_node_child_from_string(cfg_root, str8_lit("cursor"), StringMatchFlag_CaseInsensitive); + if(cursor_cfg != &df_g_nil_cfg_node) + { + TxtPt cursor = txt_pt(1, 1); + cursor.line = s64_from_str8(cursor_cfg->first->string, 10); + cursor.column = s64_from_str8(cursor_cfg->first->first->string, 10); + if(cursor.line == 0) { cursor.line = 1; } + if(cursor.column == 0) { cursor.column = 1; } + tv->cursor = tv->mark = cursor; + tv->center_cursor = 1; + } + + // rjf: default to loading + df_view_equip_loading_info(view, 1, 0, 0); + view->loading_t_target = 1.f; +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Code) +{ + DF_CodeViewState *tvs = df_view_user_state(view, DF_CodeViewState); + String8 string = push_str8f(arena, " cursor:%I64d:%I64d", tvs->cursor.line, tvs->cursor.column); + return string; +} + +DF_VIEW_CMD_FUNCTION_DEF(Code) +{ + DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + // rjf: process + switch(core_cmd_kind) + { + default: break; + case DF_CoreCmdKind_GoToLine: + { + tv->goto_line_num = cmd->params.text_point.line; + }break; + case DF_CoreCmdKind_CenterCursor: + { + tv->center_cursor = 1; + }break; + case DF_CoreCmdKind_ContainCursor: + { + tv->contain_cursor = 1; + }break; + case DF_CoreCmdKind_FindTextForward: + { + arena_clear(tv->find_text_arena); + tv->find_text_fwd = push_str8_copy(tv->find_text_arena, cmd->params.string); + }break; + case DF_CoreCmdKind_FindTextBackward: + { + arena_clear(tv->find_text_arena); + tv->find_text_bwd = push_str8_copy(tv->find_text_arena, cmd->params.string); + }break; + case DF_CoreCmdKind_ToggleBreakpointAtCursor: + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = view->cmd_entity; + params.text_point = tv->cursor; + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_TextBreakpoint)); + tv->contain_cursor = 1; + }break; + case DF_CoreCmdKind_ToggleWatchPinAtCursor: + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = view->cmd_entity; + params.text_point = tv->cursor; + params.string = cmd->params.string; + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchPin)); + tv->contain_cursor = 1; + }break; + case DF_CoreCmdKind_RunToCursor: + { + Temp scratch = scratch_begin(0, 0); + DF_Entity *thread = df_entity_from_handle(cmd->params.entity); + S64 line_num = tv->cursor.line; + DF_TextLineSrc2DasmInfoListArray src2dasm = df_text_line_src2dasm_info_list_array_from_src_line_range(scratch.arena, entity, r1s64(line_num, line_num)); + if(!df_entity_is_nil(thread) && src2dasm.count != 0) + { + DF_TextLineSrc2DasmInfoList *src2dasm_list = &src2dasm.v[0]; + if(src2dasm_list->first != 0) + { + Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; + DF_Entity *binary = src2dasm_list->first->v.binary; + DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); + U64 thread_dst_voff = voff_rng.min; + if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.vaddr = df_vaddr_from_voff(thread_dst_module, thread_dst_voff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunToAddress)); + } + } + } + scratch_end(scratch); + }break; + case DF_CoreCmdKind_SetNextStatement: + { + Temp scratch = scratch_begin(0, 0); + DF_Entity *thread = df_entity_from_handle(cmd->params.entity); + S64 line_num = (cmd->params.text_point.line == 0 ? tv->cursor.line : cmd->params.text_point.line); + DF_TextLineSrc2DasmInfoListArray src2dasm = df_text_line_src2dasm_info_list_array_from_src_line_range(scratch.arena, entity, r1s64(line_num, line_num)); + if(!df_entity_is_nil(thread) && src2dasm.count != 0) + { + DF_TextLineSrc2DasmInfoList *src2dasm_list = &src2dasm.v[0]; + if(src2dasm_list->first != 0) + { + Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; + DF_Entity *binary = src2dasm_list->first->v.binary; + DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); + U64 thread_dst_voff = voff_rng.min; + if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(thread); + params.vaddr = df_vaddr_from_voff(thread_dst_module, thread_dst_voff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetThreadIP)); + } + } + } + scratch_end(scratch); + }break; + case DF_CoreCmdKind_GoToNameAtCursor: + { + Temp scratch = scratch_begin(0, 0); + TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); + TxtRng expr_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(tv->cursor, tv->mark)) + { + expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + } + String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); + + // rjf: go to name + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); + + scratch_end(scratch); + }break; + case DF_CoreCmdKind_ToggleWatchExpressionAtCursor: + { + Temp scratch = scratch_begin(0, 0); + TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); + TxtRng expr_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(tv->cursor, tv->mark)) + { + expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + } + String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); + + // rjf: toggle watch expr + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); + + // rjf: flash marker for grabbed expr + DF_Entity *flash_marker = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); + df_entity_equip_death_timer(flash_marker, 0.5f); + df_entity_equip_txt_pt(flash_marker, expr_range.min); + df_entity_equip_txt_pt_alt(flash_marker, expr_range.max); + df_entity_equip_color_rgba(flash_marker, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + scratch_end(scratch); + }break; + case DF_CoreCmdKind_PickFile: + { + DF_Entity *missing_file = df_entity_from_handle(tv->pick_file_override_target); + String8 pick_string = cmd->params.file_path; + if(!df_entity_is_nil(missing_file) && pick_string.size != 0) + { + DF_Entity *replacement = df_entity_from_path(pick_string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); + view->cmd_entity = df_handle_from_entity(replacement); + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.entity = df_handle_from_entity(missing_file); + p.file_path = pick_string; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetFileReplacementPath)); + } + }break; + } + } +} + +DF_VIEW_UI_FUNCTION_DEF(Code) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); + ui_set_focus_active(1); + + ////////////////////////////// + //- rjf: extract invariants + // + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + F_Tag code_font = df_font_from_slot(DF_FontSlot_Code); + F32 code_font_size = df_font_size_from_slot(ws, DF_FontSlot_Code); + F_Metrics code_font_metrics = f_metrics_from_tag_size(code_font, code_font_size); + F32 code_line_height = ceil_f32(f_line_height_from_metrics(&code_font_metrics) * 1.4f); + F32 big_glyph_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_lit("H")).x; + Vec2F32 panel_box_dim = dim_2f32(rect); + Vec2F32 bottom_bar_dim = {panel_box_dim.x, ui_em(1.8f, 0).value}; + F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); + Vec2F32 code_area_dim = v2f32(panel_box_dim.x - scroll_bar_dim, panel_box_dim.y - scroll_bar_dim - bottom_bar_dim.y); + S64 num_possible_visible_lines = (S64)(code_area_dim.y/code_line_height)+1; + B32 is_focused = ui_is_focus_active(); + + ////////////////////////////// + //- rjf: unpack ctrl ctx & make parse ctx + // + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + U64 unwind_count = ctrl_ctx.unwind_count; + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_module_voff(scope, module, rip_voff); + + ////////////////////////////// + //- rjf: unpack entity info + // + B32 entity_is_missing = !!(entity->flags & DF_EntityFlag_IsMissing && !(entity->flags & DF_EntityFlag_Output)); + TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); + TXTI_BufferInfo txti_buffer_info = txti_buffer_info_from_handle(scratch.arena, txti_handle); + B32 txti_buffer_is_ready = ((txti_buffer_info.timestamp != 0 || entity->flags & DF_EntityFlag_Output) && + (txti_buffer_info.bytes_processed == txti_buffer_info.bytes_to_process || txti_buffer_info.buffer_apply_gen != 0)); + + ////////////////////////////// + //- rjf: buffer is pending -> equip view with loading information + // + if(!entity_is_missing && !txti_buffer_is_ready) + { + df_view_equip_loading_info(view, 1, txti_buffer_info.bytes_processed, txti_buffer_info.bytes_to_process); + } + + ////////////////////////////// + //- rjf: determine visible line range / count + // + Rng1S64 visible_line_num_range = r1s64(view->scroll_pos.y.idx + (S64)(view->scroll_pos.y.off) + 1 - !!(view->scroll_pos.y.off < 0), + view->scroll_pos.y.idx + (S64)(view->scroll_pos.y.off) + 1 + num_possible_visible_lines); + Rng1S64 target_visible_line_num_range = r1s64(view->scroll_pos.y.idx + 1, + view->scroll_pos.y.idx + 1 + num_possible_visible_lines); + U64 visible_line_count = 0; + { + visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)txti_buffer_info.total_line_count); + visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)txti_buffer_info.total_line_count); + visible_line_num_range.min = Max(1, visible_line_num_range.min); + visible_line_num_range.max = Max(1, visible_line_num_range.max); + target_visible_line_num_range.min = Clamp(1, target_visible_line_num_range.min, (S64)txti_buffer_info.total_line_count); + target_visible_line_num_range.max = Clamp(1, target_visible_line_num_range.max, (S64)txti_buffer_info.total_line_count); + target_visible_line_num_range.min = Max(1, target_visible_line_num_range.min); + target_visible_line_num_range.max = Max(1, target_visible_line_num_range.max); + visible_line_count = (U64)dim_1s64(visible_line_num_range)+1; + } + + ////////////////////////////// + //- rjf: calculate scroll bounds + // + S64 line_size_x = 0; + Rng1S64 scroll_idx_rng[Axis2_COUNT] = {0}; + { + line_size_x = (txti_buffer_info.max_line_size*big_glyph_advance*3)/2; + line_size_x = ClampBot(line_size_x, (S64)big_glyph_advance*120); + line_size_x = ClampBot(line_size_x, (S64)code_area_dim.x); + scroll_idx_rng[Axis2_X] = r1s64(0, line_size_x-(S64)code_area_dim.x); + scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)txti_buffer_info.total_line_count-1); + } + + ////////////////////////////// + //- rjf: calculate line-range-dependent info + // + F32 margin_width_px = big_glyph_advance*3.5f; + F32 line_num_width_px = big_glyph_advance * (log10(visible_line_num_range.max) + 3); + TXTI_Slice slice = txti_slice_from_handle_line_range(scratch.arena, txti_handle, visible_line_num_range); + + ////////////////////////////// + //- rjf: get active search query + // + String8 search_query = {0}; + Side search_query_side = Side_Invalid; + B32 search_query_is_active = 0; + { + for(DF_View *v = view->callee_view; !df_view_is_nil(v); v = v->callee_view) + { + DF_CoreCmdKind query_core_cmd_kind = df_core_cmd_kind_from_string(v->cmd_spec->info.string); + if(query_core_cmd_kind == DF_CoreCmdKind_FindTextForward || + query_core_cmd_kind == DF_CoreCmdKind_FindTextBackward) + { + search_query = v->query; + search_query_is_active = 1; + search_query_side = (query_core_cmd_kind == DF_CoreCmdKind_FindTextForward) ? Side_Max : Side_Min; + break; + } + } + } + + ////////////////////////////// + //- rjf: prepare code slice info bundle, for the viewable region of text + // + DF_CodeSliceParams code_slice_params = {0}; + if(txti_buffer_is_ready) + { + // rjf: fill basics + code_slice_params.flags = DF_CodeSliceFlag_Margin|DF_CodeSliceFlag_LineNums; + code_slice_params.line_num_range = visible_line_num_range; + code_slice_params.line_text = slice.line_text; + code_slice_params.line_ranges = slice.line_ranges; + code_slice_params.line_tokens = slice.line_tokens; + code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, slice.line_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, slice.line_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, slice.line_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, slice.line_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, slice.line_count); + code_slice_params.font = code_font; + code_slice_params.font_size = code_font_size; + code_slice_params.line_height_px = code_line_height; + code_slice_params.search_query = search_query; + code_slice_params.margin_width_px = margin_width_px; + code_slice_params.line_num_width_px = line_num_width_px; + code_slice_params.line_text_max_width_px = (F32)line_size_x; + code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, entity, DF_EntityKind_FlashMarker); + + // rjf: find visible breakpoints + ProfScope("find visible breakpoints") + { + for(DF_Entity *bp = entity->first; !df_entity_is_nil(bp); bp = bp->next) + { + if(bp->deleted || bp->kind != DF_EntityKind_Breakpoint) { continue; } + if(visible_line_num_range.min <= bp->text_point.line && bp->text_point.line <= visible_line_num_range.max) + { + U64 slice_line_idx = (bp->text_point.line-visible_line_num_range.min); + df_entity_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); + } + } + } + + // rjf: find live threads mapping to this file + ProfScope("find live threads mapping to this file") + { + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); + DF_EntityList threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); + for(DF_EntityNode *thread_n = threads.first; thread_n != 0; thread_n = thread_n->next) + { + DF_Entity *thread = thread_n->entity; + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0; + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); + U64 last_inst_on_unwound_rip_vaddr = rip_vaddr - !!unwind_count; + DF_Entity *module = df_module_from_process_vaddr(process, last_inst_on_unwound_rip_vaddr); + U64 rip_voff = df_voff_from_vaddr(module, last_inst_on_unwound_rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + if(dasm2src_info.file == entity && visible_line_num_range.min <= dasm2src_info.pt.line && dasm2src_info.pt.line < visible_line_num_range.max) + { + U64 slice_line_idx = dasm2src_info.pt.line-visible_line_num_range.min; + df_entity_list_push(scratch.arena, &code_slice_params.line_ips[slice_line_idx], thread); + } + } + } + + // rjf: find visible watch pins + ProfScope("find visible watch pins") + { + for(DF_Entity *wp = entity->first; !df_entity_is_nil(wp); wp = wp->next) + { + if(wp->deleted || wp->kind != DF_EntityKind_WatchPin) { continue; } + if(visible_line_num_range.min <= wp->text_point.line && wp->text_point.line < visible_line_num_range.max) + { + U64 slice_line_idx = (wp->text_point.line-visible_line_num_range.min); + df_entity_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); + } + } + } + + // rjf: find all src -> dasm info + ProfScope("find all src -> dasm info") + { + DF_TextLineSrc2DasmInfoListArray src2dasm = df_text_line_src2dasm_info_list_array_from_src_line_range(scratch.arena, entity, visible_line_num_range); + if(src2dasm.count != 0) + { + MemoryCopy(code_slice_params.line_src2dasm, src2dasm.v, sizeof(DF_TextLineSrc2DasmInfoList)*src2dasm.count); + } + code_slice_params.relevant_binaries = src2dasm.binaries; + } + } + + ////////////////////////////// + //- rjf: build missing & override interface + // + if(entity_is_missing) + { + UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_pct(1, 0)) + { + Temp scratch = scratch_begin(0, 0); + String8 full_path = df_full_path_from_entity(scratch.arena, entity); + UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_em(3, 1)) + UI_Row UI_Padding(ui_pct(1, 0)) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) + { + UI_Font(ui_icon_font()) ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); + ui_labelf("Could not find \"%S\".", full_path); + } + UI_PrefHeight(ui_em(3, 1)) + UI_Row UI_Padding(ui_pct(1, 0)) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) + UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) + UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) + UI_CornerRadius(ui_top_font_size()/3) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_Focus(1) + if(ui_buttonf("Find alternative...").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + tv->pick_file_override_target = df_handle_from_entity(entity); + } + scratch_end(scratch); + } + } + + ////////////////////////////// + //- rjf: build container + // + UI_Box *container_box = &ui_g_nil_box; + if(txti_buffer_is_ready) + { + ui_set_next_pref_width(ui_px(code_area_dim.x, 1)); + ui_set_next_pref_height(ui_px(code_area_dim.y, 1)); + ui_set_next_child_layout_axis(Axis2_Y); + container_box = ui_build_box_from_stringf(UI_BoxFlag_Clip| + UI_BoxFlag_Scroll| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_AllowOverflowX| + UI_BoxFlag_AllowOverflowY, + "###code_area_%p", view); + } + + ////////////////////////////// + //- rjf: cancelled search query -> center cursor + // + if(!search_query_is_active && tv->drifted_for_search) + { + tv->drifted_for_search = 0; + tv->center_cursor = 1; + } + + ////////////////////////////// + //- rjf: search query -> matches + // + DF_TextSearchMatchArray search_query_matches = {0}; +#if !DE2CTRL + { + search_query_matches = df_text_search_match_array_from_entity_needle(scratch.arena, entity, search_query, entity_line_string_flags, tv->cursor); + df_text_search_match_array_sort_in_place(&search_query_matches); + } +#endif + + ////////////////////////////// + //- rjf: do searching operations + // + if(txti_buffer_is_ready) + { + //- rjf: find text (forward) + if(tv->find_text_fwd.size != 0) + { + Temp scratch = scratch_begin(0, 0); + B32 found = 0; + B32 first = 1; + S64 line_num_start = tv->cursor.line; + S64 line_num_last = (S64)txti_buffer_info.total_line_count; + for(S64 line_num = line_num_start;; first = 0) + { + // rjf: pop scratch + temp_end(scratch); + + // rjf: gather line info + String8 line_string = txti_string_from_handle_line_num(scratch.arena, txti_handle, line_num); + U64 search_start = 0; + if(tv->cursor.line == line_num && first) + { + search_start = tv->cursor.column; + } + + // rjf: search string + U64 needle_pos = str8_find_needle(line_string, search_start, tv->find_text_fwd, StringMatchFlag_CaseInsensitive); + if(needle_pos < line_string.size) + { + tv->cursor.line = line_num; + tv->cursor.column = needle_pos+1; + tv->mark = tv->cursor; + found = 1; + break; + } + + // rjf: break if circled back around to cursor + else if(line_num == line_num_start && !first) + { + break; + } + + // rjf: increment + line_num += 1; + if(line_num > line_num_last) + { + line_num = 1; + } + } + tv->center_cursor = found; + if(found == 0) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = push_str8f(scratch.arena, "Could not find \"%S\"", tv->find_text_fwd); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + scratch_end(scratch); + } + + //- rjf: find text (backward) + if(tv->find_text_bwd.size != 0) + { + Temp scratch = scratch_begin(0, 0); + B32 found = 0; + B32 first = 1; + S64 line_num_start = tv->cursor.line; + S64 line_num_last = (S64)txti_buffer_info.total_line_count; + for(S64 line_num = line_num_start;; first = 0) + { + // rjf: pop scratch + temp_end(scratch); + + // rjf: gather line info + String8 line_string = txti_string_from_handle_line_num(scratch.arena, txti_handle, line_num); + if(tv->cursor.line == line_num && first) + { + line_string = str8_prefix(line_string, tv->cursor.column-1); + } + + // rjf: search string + U64 next_needle_pos = line_string.size; + for(U64 needle_pos = 0; needle_pos < line_string.size;) + { + needle_pos = str8_find_needle(line_string, needle_pos, tv->find_text_bwd, StringMatchFlag_CaseInsensitive); + if(needle_pos < line_string.size) + { + next_needle_pos = needle_pos; + needle_pos += 1; + } + } + if(next_needle_pos < line_string.size) + { + tv->cursor.line = line_num; + tv->cursor.column = next_needle_pos+1; + tv->mark = tv->cursor; + found = 1; + break; + } + + // rjf: break if circled back around to cursor line + else if(line_num == line_num_start && !first) + { + break; + } + + // rjf: increment + line_num -= 1; + if(line_num == 0) + { + line_num = line_num_last; + } + } + tv->center_cursor = found; + if(found == 0) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = push_str8f(scratch.arena, "Could not find \"%S\"", tv->find_text_bwd); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + scratch_end(scratch); + } + + MemoryZeroStruct(&tv->find_text_fwd); + MemoryZeroStruct(&tv->find_text_bwd); + arena_clear(tv->find_text_arena); + } + + ////////////////////////////// + //- rjf: do goto line + // + if(txti_buffer_is_ready) if(tv->goto_line_num != 0) + { + S64 line_num = tv->goto_line_num; + tv->goto_line_num = 0; + line_num = Clamp(1, line_num, txti_buffer_info.total_line_count); + tv->cursor = tv->mark = txt_pt(line_num, 1); + tv->center_cursor = !tv->contain_cursor || (line_num < target_visible_line_num_range.min+8 || target_visible_line_num_range.max-8 < line_num); + } + + ////////////////////////////// + //- rjf: do keyboard interaction + // + B32 snap[Axis2_COUNT] = {0}; + if(txti_buffer_is_ready && is_focused) + { + snap[Axis2_X] = snap[Axis2_Y] = df_do_txti_controls(txti_handle, ClampBot(num_possible_visible_lines, 10) - 10, &tv->cursor, &tv->mark, &tv->preferred_column); + } + + ////////////////////////////// + //- rjf: build container contents + // + if(txti_buffer_is_ready) UI_Parent(container_box) + { + //- rjf: build fractional space + container_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; + container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1); + + //- rjf: build code slice + DF_CodeSliceSignal sig = {0}; + UI_Focus(is_focused) + { + sig = df_code_slicef(ws, &ctrl_ctx, &parse_ctx, &code_slice_params, &tv->cursor, &tv->mark, &tv->preferred_column, "txt_view_%p", view); + } + + //- rjf: hover eval + if(!sig.base.dragging && sig.mouse_expr_rng.min.line != 0 && sig.base.event_flags == 0) + { + TxtRng expr_rng = sig.mouse_expr_rng; + String8 expr = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_rng); + if(expr.size != 0) + { + DF_Eval eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, expr); + if(eval.mode != EVAL_EvalMode_NULL) + { + df_set_hover_eval(ws, sig.mouse_expr_baseline_pos, ctrl_ctx, entity, sig.mouse_pt, 0, expr); + } + } + } + + //- rjf: press code slice? -> focus panel + if(sig.base.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + //- rjf: dragging? -> contain cursor + if(sig.base.dragging && sig.base.event_flags == 0) + { + tv->contain_cursor = 1; + } + + //- rjf: ctrl+pressed? -> go to name + if(sig.base.pressed && sig.base.event_flags & OS_EventFlag_Ctrl) + { + ui_kill_action(); + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + params.string = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, txti_expr_range_from_handle_pt(txti_handle, sig.mouse_pt)); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); + } + + //- rjf: clicked margin? -> place breakpoint + if(sig.clicked_margin_line_num != 0) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.text_point = txt_pt(sig.clicked_margin_line_num, 1); + params.entity = df_handle_from_entity(entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_TextBreakpoint)); + } + + //- rjf: dropped entity onto line? -> do drop + if(sig.dropped_entity_line_num != 0 && !df_entity_is_nil(sig.dropped_entity)) + { + DF_Entity *dropped_entity = sig.dropped_entity; + switch(dropped_entity->kind) + { + default:{}break; + case DF_EntityKind_Breakpoint: + case DF_EntityKind_WatchPin: + { + DF_StateDeltaHistory *hist = df_state_delta_history(); + df_state_delta_history_push_batch(hist, &dropped_entity->generation); + df_state_delta_history_push_struct_delta(hist, &dropped_entity->text_point); + df_entity_change_parent(hist, dropped_entity, dropped_entity->parent, entity); + df_entity_equip_txt_pt(dropped_entity, txt_pt(sig.dropped_entity_line_num, 1)); + if(dropped_entity->flags & DF_EntityFlag_HasVAddr) + { + df_state_delta_history_push_struct_delta(hist, &dropped_entity->vaddr); + df_entity_equip_vaddr(dropped_entity, 0); + } + }break; + case DF_EntityKind_Thread: + if(contains_1s64(visible_line_num_range, sig.dropped_entity_line_num)) + { + U64 line_idx = (sig.dropped_entity_line_num-visible_line_num_range.min); + DF_TextLineSrc2DasmInfoList *src2dasm_list = &code_slice_params.line_src2dasm[line_idx]; + if(src2dasm_list->first != 0) + { + Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; + DF_Entity *binary = src2dasm_list->first->v.binary; + DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *thread_dst_module = df_module_from_thread_candidates(dropped_entity, &possible_modules); + U64 thread_dst_voff = voff_rng.min; + if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(dropped_entity); + params.vaddr = df_vaddr_from_voff(thread_dst_module, thread_dst_voff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetThreadIP)); + } + } + }break; + } + } + + //- rjf: copy text + if(!txt_pt_match(sig.copy_range.min, sig.copy_range.max)) + { + Temp temp = temp_begin(scratch.arena); + DF_Entity *flash_range = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); + df_entity_equip_death_timer(flash_range, 0.5f); + df_entity_equip_color_rgba(flash_range, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + df_entity_equip_txt_pt(flash_range, sig.copy_range.min); + df_entity_equip_txt_pt_alt(flash_range, sig.copy_range.max); + String8 text = txti_string_from_handle_txt_rng(temp.arena, txti_handle, sig.copy_range); + os_set_clipboard_text(text); + temp_end(temp); + } + + //- rjf: toggle cursor watch + if(sig.toggle_cursor_watch) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpressionAtCursor)); + } + + //- rjf: set next statement + if(sig.set_next_statement_line_num != 0 && contains_1s64(visible_line_num_range, sig.set_next_statement_line_num)) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.text_point = txt_pt(sig.set_next_statement_line_num, 1); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetNextStatement)); + } + + //- rjf: run-to-line + if(sig.run_to_line_num != 0 && contains_1s64(visible_line_num_range, sig.run_to_line_num)) + { + U64 line_idx = (sig.run_to_line_num-visible_line_num_range.min); + DF_TextLineSrc2DasmInfoList *src2dasm_list = &code_slice_params.line_src2dasm[line_idx]; + if(src2dasm_list->first != 0) + { + Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; + DF_Entity *binary = src2dasm_list->first->v.binary; + DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); + DF_Entity *module = thread_dst_module; + if(df_entity_is_nil(module)) + { + module = df_first_entity_from_list(&possible_modules); + } + U64 voff = voff_rng.min; + if(!df_entity_is_nil(module) && voff != 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.vaddr = df_vaddr_from_voff(module, voff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunToAddress)); + } + } + } + + //- rjf: go to disasm + if(sig.goto_disasm_line_num != 0 && contains_1s64(visible_line_num_range, sig.goto_disasm_line_num)) + { + U64 line_idx = (sig.goto_disasm_line_num-visible_line_num_range.min); + DF_TextLineSrc2DasmInfoList *src2dasm_list = &code_slice_params.line_src2dasm[line_idx]; + if(src2dasm_list->first != 0) + { + Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; + DF_Entity *binary = src2dasm_list->first->v.binary; + DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = thread_dst_module; + if(df_entity_is_nil(module)) + { + module = df_first_entity_from_list(&possible_modules); + } + U64 voff = voff_rng.min; + if(!df_entity_is_nil(module) && voff != 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(process); + params.vaddr = df_vaddr_from_voff(module, voff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + } + } + } + + ////////////////////////////// + //- rjf: apply post-build view snapping rules + // + if(txti_buffer_is_ready) + { + // rjf: center first match + TxtPt next_match = df_text_search_match_array_find_nearest__linear_scan(&search_query_matches, tv->cursor, search_query_side).pt; + if(search_query.size != 0 && next_match.line != 0) + { + // TODO(rjf): [ ] @de2ctrl +#if !DE2CTRL + DF_TextSlice match_line_slice = df_text_slice_from_entity(scratch.arena, entity, r1s64(next_match.line, next_match.line), entity_line_string_flags); + String8 match_line = match_line_slice.visible_range_text; + F32 match_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(match_line, next_match.column-1)).x; + container_box->view_off_target.x = match_advance - code_area_dim.x/2; + container_box->view_off_target.y = next_match.line*code_line_height - code_area_dim.y/2 + code_line_height*1.5f; + container_box->view_off_target.x = ClampBot(container_box->view_off_target.x, 0); + container_box->view_off_target.y = ClampBot(container_box->view_off_target.y, 0); + tv->drifted_for_search = 1; +#endif + } + + // rjf: contain => snap + if(tv->contain_cursor) + { + tv->contain_cursor = 0; + snap[Axis2_X] = 1; + snap[Axis2_Y] = 1; + } + + // rjf: center cursor + if(tv->center_cursor) + { + tv->center_cursor = 0; + String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + F32 cursor_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x; + + // rjf: scroll x + { + S64 new_idx = (S64)(cursor_advance - code_area_dim.x/2); + new_idx = Clamp(scroll_idx_rng[Axis2_X].min, new_idx, scroll_idx_rng[Axis2_X].max); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + snap[Axis2_X] = 0; + } + + // rjf: scroll y + { + S64 new_idx = (tv->cursor.line-1) - num_possible_visible_lines/2 + 2; + new_idx = Clamp(scroll_idx_rng[Axis2_Y].min, new_idx, scroll_idx_rng[Axis2_Y].max); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + snap[Axis2_Y] = 0; + } + } + + // rjf: snap in X + if(snap[Axis2_X]) + { + String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + S64 cursor_off = (S64)(f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x + margin_width_px + line_num_width_px); + Rng1S64 visible_pixel_range = + { + view->scroll_pos.x.idx, + view->scroll_pos.x.idx + (S64)code_area_dim.x, + }; + Rng1S64 cursor_pixel_range = + { + cursor_off - (S64)(big_glyph_advance*4) - (S64)(margin_width_px + line_num_width_px), + cursor_off + (S64)(big_glyph_advance*4), + }; + S64 min_delta = Min(0, cursor_pixel_range.min - visible_pixel_range.min); + S64 max_delta = Max(0, cursor_pixel_range.max - visible_pixel_range.max); + S64 new_idx = view->scroll_pos.x.idx+min_delta+max_delta; + new_idx = Clamp(scroll_idx_rng[Axis2_X].min, new_idx, scroll_idx_rng[Axis2_X].max); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + } + + // rjf: snap in Y + if(snap[Axis2_Y]) + { + Rng1S64 cursor_visibility_range = r1s64(tv->cursor.line-4, tv->cursor.line+4); + cursor_visibility_range.min = ClampBot(0, cursor_visibility_range.min); + cursor_visibility_range.max = ClampBot(0, cursor_visibility_range.max); + S64 min_delta = Min(0, cursor_visibility_range.min-(target_visible_line_num_range.min)); + S64 max_delta = Max(0, cursor_visibility_range.max-(target_visible_line_num_range.min+num_possible_visible_lines)); + S64 new_idx = view->scroll_pos.y.idx+min_delta+max_delta; + new_idx = Clamp(0, new_idx, (S64)txti_buffer_info.total_line_count-1); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + } + + ////////////////////////////// + //- rjf: build horizontal scroll bar + // + if(txti_buffer_is_ready) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(code_area_dim.y); + ui_set_next_fixed_width(panel_box_dim.x - scroll_bar_dim); + ui_set_next_fixed_height(scroll_bar_dim); + { + view->scroll_pos.x = ui_scroll_bar(Axis2_X, + ui_px(scroll_bar_dim, 1.f), + view->scroll_pos.x, + scroll_idx_rng[Axis2_X], + (S64)code_area_dim.x); + } + } + + ////////////////////////////// + //- rjf: build vertical scroll bar + // + if(txti_buffer_is_ready) + { + ui_set_next_fixed_x(code_area_dim.x); + ui_set_next_fixed_y(0); + ui_set_next_fixed_width(scroll_bar_dim); + ui_set_next_fixed_height(panel_box_dim.y - bottom_bar_dim.y - scroll_bar_dim); + { + view->scroll_pos.y = ui_scroll_bar(Axis2_Y, + ui_px(scroll_bar_dim, 1.f), + view->scroll_pos.y, + scroll_idx_rng[Axis2_Y], + num_possible_visible_lines); + } + } + + ////////////////////////////// + //- rjf: top-level container interaction (scrolling) + // + if(txti_buffer_is_ready) + { + UI_Signal sig = ui_signal_from_box(container_box); + if(sig.scroll.x != 0) + { + S64 new_idx = view->scroll_pos.x.idx+sig.scroll.x*big_glyph_advance; + new_idx = clamp_1s64(scroll_idx_rng[Axis2_X], new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + } + if(sig.scroll.y != 0) + { + S64 new_idx = view->scroll_pos.y.idx + sig.scroll.y; + new_idx = clamp_1s64(scroll_idx_rng[Axis2_Y], new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + ui_scroll_pt_clamp_idx(&view->scroll_pos.x, scroll_idx_rng[Axis2_X]); + ui_scroll_pt_clamp_idx(&view->scroll_pos.y, scroll_idx_rng[Axis2_Y]); + } + + ////////////////////////////// + //- rjf: build bottom info bar + // + if(txti_buffer_is_ready) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(code_area_dim.y + scroll_bar_dim); + ui_set_next_pref_width(ui_px(bottom_bar_dim.x, 1)); + ui_set_next_pref_height(ui_px(bottom_bar_dim.y, 1)); + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_AltBackground)); + ui_set_next_flags(UI_BoxFlag_DrawBackground); + UI_Row + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(code_font) + { + String8 full_path = df_full_path_from_entity(scratch.arena, entity); + TXTI_Handle handle = txti_handle_from_path(full_path); + TXTI_BufferInfo info = txti_buffer_info_from_handle(scratch.arena, handle); + ui_label(full_path); + ui_spacer(ui_em(1.5f, 1)); + ui_labelf("Row: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); + ui_spacer(ui_pct(1, 0)); + ui_labelf("(read only)"); + ui_labelf("%s", + info.line_end_kind == TXTI_LineEndKind_LF ? "lf" : + info.line_end_kind == TXTI_LineEndKind_CRLF ? "crlf" : + "bin"); + } + } + + ui_unset_focus_active(); + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Disassembly @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Disassembly) +{ + DF_DisasmViewState *dv = df_view_user_state(view, DF_DisasmViewState); + if(dv->initialized == 0) + { + dv->initialized = 1; + dv->cursor = txt_pt(1, 1); + dv->mark = txt_pt(1, 1); + dv->preferred_column = 1; + dv->find_text_arena = df_view_push_arena_ext(view); + } +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Disassembly) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(Disassembly) +{ + Temp scratch = scratch_begin(0, 0); + DF_DisasmViewState *dv = df_view_user_state(view, DF_DisasmViewState); + DF_Entity *process = df_entity_from_handle(dv->process); + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CmdParams params = cmd->params; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + // rjf: process + switch(core_cmd_kind) + { + default: break; + case DF_CoreCmdKind_GoToAddress: + { + if(!df_entity_is_nil(df_entity_from_handle(params.entity))) + { + dv->process = params.entity; + } + dv->base_vaddr = params.vaddr; + dv->goto_vaddr = params.vaddr; + dv->cursor = dv->mark = txt_pt(1, 1); + }break; + case DF_CoreCmdKind_GoToLine: + { + dv->goto_line_num = cmd->params.text_point.line; + }break; + case DF_CoreCmdKind_CenterCursor: + { + dv->center_cursor = 1; + }break; + case DF_CoreCmdKind_ContainCursor: + { + dv->contain_cursor = 1; + }break; + case DF_CoreCmdKind_FindTextForward: + { + arena_clear(dv->find_text_arena); + dv->find_text_fwd = push_str8_copy(dv->find_text_arena, cmd->params.string); + }break; + case DF_CoreCmdKind_FindTextBackward: + { + arena_clear(dv->find_text_arena); + dv->find_text_bwd = push_str8_copy(dv->find_text_arena, cmd->params.string); + }break; + case DF_CoreCmdKind_ToggleBreakpointAtCursor: + { + DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); + DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); + DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); + if(insts.count != 0) + { + U64 off = dasm_inst_array_off_from_idx(&insts, dv->cursor.line-1); + U64 vaddr = dasm_info.vaddr_range.min+off; + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.vaddr = vaddr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_AddressBreakpoint)); + dv->contain_cursor = 1; + } + }break; + case DF_CoreCmdKind_ToggleWatchPinAtCursor: + { + DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); + DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); + DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); + if(insts.count != 0) + { + U64 off = dasm_inst_array_off_from_idx(&insts, dv->cursor.line-1); + U64 vaddr = dasm_info.vaddr_range.min+off; + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.vaddr = vaddr; + p.string = params.string; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_VirtualAddr); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchPin)); + } + }break; + case DF_CoreCmdKind_RunToCursor: + { + DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); + DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); + DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); + if(insts.count != 0) + { + U64 off = dasm_inst_array_off_from_idx(&insts, dv->cursor.line-1); + U64 vaddr = dasm_info.vaddr_range.min+off; + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.vaddr = vaddr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunToAddress)); + } + }break; + case DF_CoreCmdKind_SetNextStatement: + { + DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); + DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); + DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); + DF_Entity *thread = df_entity_from_handle(params.entity); + S64 line_num = (cmd->params.text_point.line == 0 ? dv->cursor.line : cmd->params.text_point.line); + if(insts.count != 0) + { + U64 off = dasm_inst_array_off_from_idx(&insts, line_num-1); + U64 vaddr = dasm_info.vaddr_range.min+off; + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.vaddr = vaddr; + params.entity = df_handle_from_entity(thread); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetThreadIP)); + } + }break; + case DF_CoreCmdKind_GoToNameAtCursor: + { + // TODO(rjf) +#if 0 + Temp scratch = scratch_begin(0, 0); + TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); + TxtRng expr_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(tv->cursor, tv->mark)) + { + expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + } + String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); + + // rjf: go to name + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); + + scratch_end(scratch); +#endif + }break; + case DF_CoreCmdKind_ToggleWatchExpressionAtCursor: + { + // TODO(rjf) +#if 0 + Temp scratch = scratch_begin(0, 0); + TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); + TxtRng expr_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(tv->cursor, tv->mark)) + { + expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + } + String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); + + // rjf: toggle watch expr + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); + + // rjf: flash marker for grabbed expr + DF_Entity *flash_marker = df_entity_alloc(entity, DF_EntityKind_FlashMarker); + df_entity_equip_death_timer(flash_marker, 0.5f); + df_entity_equip_txt_pt(flash_marker, expr_range.min); + df_entity_equip_txt_pt_alt(flash_marker, expr_range.max); + df_entity_equip_color_rgba(flash_marker, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + scratch_end(scratch); +#endif + }break; + } + } + scratch_end(scratch); +} + +DF_VIEW_UI_FUNCTION_DEF(Disassembly) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + DF_DisasmViewState *dv = df_view_user_state(view, DF_DisasmViewState); + ui_set_focus_active(1); + + ////////////////////////////// + //- rjf: extract invariants + // + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + + ////////////////////////////// + //- rjf: unpack ctrl ctx & make parse ctx + // + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); + U64 unwind_count = ctrl_ctx.unwind_count; + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(selected_thread, unwind_count); + DF_Entity *selected_thread_process = df_entity_ancestor_from_kind(selected_thread, DF_EntityKind_Process); + DF_Entity *selected_thread_module = df_module_from_process_vaddr(selected_thread_process, rip_vaddr); + U64 rip_voff = df_voff_from_vaddr(selected_thread_module, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_module_voff(scope, selected_thread_module, rip_voff); + F_Tag code_font = df_font_from_slot(DF_FontSlot_Code); + F32 code_font_size = df_font_size_from_slot(ws, DF_FontSlot_Code); + F_Metrics code_font_metrics = f_metrics_from_tag_size(code_font, code_font_size); + F32 code_line_height = ceil_f32(f_line_height_from_metrics(&code_font_metrics) * 1.4f); + F32 big_glyph_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_lit("H")).x; + Vec2F32 panel_box_dim = dim_2f32(rect); + Vec2F32 bottom_bar_dim = {panel_box_dim.x, ui_top_font_size()*1.8f}; + F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); + Vec2F32 code_area_dim = v2f32(panel_box_dim.x - scroll_bar_dim, panel_box_dim.y - scroll_bar_dim - bottom_bar_dim.y); + S64 num_possible_visible_lines = (S64)(code_area_dim.y/code_line_height)+1; + B32 is_focused = ui_is_focus_active(); + + ////////////////////////////// + //- rjf: no disasm process open? -> snap to selected thread + // + if(df_entity_is_nil(df_entity_from_handle(dv->process))) + { + dv->process = df_handle_from_entity(selected_thread_process); + dv->base_vaddr = rip_vaddr; + dv->goto_vaddr = rip_vaddr; + } + + ////////////////////////////// + //- rjf: unpack entity info + // + DF_Entity *process = df_entity_from_handle(dv->process); + DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); + DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); + Rng1U64 disasm_vaddr_rng = dasm_info.vaddr_range; + DF_Entity *module = df_module_from_process_vaddr(process, disasm_vaddr_rng.min); + DF_Entity *binary = df_binary_file_from_module(module); + DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); + B32 has_disasm = (insts.count != 0); + B32 is_loading = (!has_disasm && !df_entity_is_nil(process) && dim_1u64(disasm_vaddr_rng) != 0 && !df_ctrl_targets_running()); + + ////////////////////////////// + //- rjf: is loading -> equip view with loading information + // + if(is_loading) + { + df_view_equip_loading_info(view, is_loading, dasm_info.bytes_processed, dasm_info.bytes_to_process); + } + + ////////////////////////////// + //- rjf: determine visible line range / count + // + Rng1S64 visible_line_num_range = r1s64(view->scroll_pos.y.idx + (S64)(view->scroll_pos.y.off) + 1 - !!(view->scroll_pos.y.off < 0), + view->scroll_pos.y.idx + (S64)(view->scroll_pos.y.off) + 1 + num_possible_visible_lines); + U64 visible_line_count = 0; + { + visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)insts.count); + visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)insts.count); + visible_line_count = (U64)dim_1s64(visible_line_num_range)+1; + } + + ////////////////////////////// + //- rjf: calculate line-range-dependent info + // + F32 margin_width_px = big_glyph_advance*3.5f; + F32 line_num_width_px = big_glyph_advance * (log10(visible_line_num_range.max) + 3); + + ////////////////////////////// + //- rjf: calculate scroll bounds + // + S64 line_size_x = 0; + Rng1S64 scroll_idx_rng[Axis2_COUNT] = {0}; + { + line_size_x = (200*big_glyph_advance); + line_size_x = ClampBot(line_size_x, (S64)big_glyph_advance*120); + line_size_x = ClampBot(line_size_x, (S64)code_area_dim.x); + scroll_idx_rng[Axis2_X] = r1s64(0, line_size_x-(S64)code_area_dim.x); + scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)insts.count-1); + } + + ////////////////////////////// + //- rjf: get active search query + // + String8 search_query = {0}; + Side search_query_side = Side_Invalid; + B32 search_query_is_active = 0; + { + for(DF_View *v = view->callee_view; !df_view_is_nil(v); v = v->callee_view) + { + DF_CoreCmdKind query_core_cmd_kind = df_core_cmd_kind_from_string(v->cmd_spec->info.string); + if(query_core_cmd_kind == DF_CoreCmdKind_FindTextForward || + query_core_cmd_kind == DF_CoreCmdKind_FindTextBackward) + { + search_query = v->query; + search_query_is_active = 1; + search_query_side = (query_core_cmd_kind == DF_CoreCmdKind_FindTextForward) ? Side_Max : Side_Min; + break; + } + } + } + + ////////////////////////////// + //- rjf: prepare code slice info bundle, for the viewable region of text + // + DF_CodeSliceParams code_slice_params = {0}; + { + // rjf: fill basics + code_slice_params.flags = DF_CodeSliceFlag_Margin|DF_CodeSliceFlag_LineNums; + code_slice_params.line_num_range = visible_line_num_range; + code_slice_params.line_text = push_array(scratch.arena, String8, visible_line_count); + code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, visible_line_count); + code_slice_params.line_tokens = push_array(scratch.arena, TXTI_TokenArray, visible_line_count); + code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, visible_line_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, visible_line_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, visible_line_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, visible_line_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, visible_line_count); + code_slice_params.font = code_font; + code_slice_params.font_size = code_font_size; + code_slice_params.line_height_px = code_line_height; + code_slice_params.search_query = search_query; + code_slice_params.margin_width_px = margin_width_px; + code_slice_params.line_num_width_px = line_num_width_px; + code_slice_params.line_text_max_width_px = (F32)line_size_x; + code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, process, DF_EntityKind_FlashMarker); + df_entity_list_push(scratch.arena, &code_slice_params.relevant_binaries, binary); + + // rjf: fill line text + for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) + { + U64 idx = line_num-visible_line_num_range.min; + DASM_Inst *inst = &insts.v[visible_line_num_range.min+idx-1]; + String8 symbol_name = {0}; + if(inst->addr != 0) + { + symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, df_voff_from_vaddr(module, inst->addr)); + } + code_slice_params.line_text[idx] = push_str8f(scratch.arena, "0x%016I64x %S%s%S%s", + disasm_vaddr_rng.min + inst->off, + inst->string, + symbol_name.size ? " (" : "", + symbol_name, + symbol_name.size ? ")" : ""); + } + + // rjf: fill line ranges + for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) + { + U64 idx = line_num-visible_line_num_range.min; + code_slice_params.line_ranges[idx] = r1u64(0, code_slice_params.line_text[idx].size); + } + + // rjf: fill line tokens + for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) + { + U64 idx = line_num-visible_line_num_range.min; + TXTI_TokenArray tokens = df_txti_token_array_from_dasm_arch_string(scratch.arena, df_architecture_from_entity(process), code_slice_params.line_text[idx]); + code_slice_params.line_tokens[idx] = tokens; + } + + // rjf: find live threads mapping to this disassembly + { + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); + DF_EntityList threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); + for(DF_EntityNode *thread_n = threads.first; thread_n != 0; thread_n = thread_n->next) + { + DF_Entity *thread = thread_n->entity; + U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0; + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); + if(contains_1u64(disasm_vaddr_rng, rip_vaddr)) + { + U64 rip_off = rip_vaddr - disasm_vaddr_rng.min; + S64 line_num = dasm_inst_array_idx_from_off__linear_scan(&insts, rip_off)+1; + if(contains_1s64(visible_line_num_range, line_num)) + { + U64 slice_line_idx = (line_num-visible_line_num_range.min); + df_entity_list_push(scratch.arena, &code_slice_params.line_ips[slice_line_idx], thread); + } + } + } + } + + // rjf: find breakpoints mapping to this disassembly + { + DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + for(DF_EntityNode *n = bps.first; n != 0; n = n->next) + { + DF_Entity *bp = n->entity; + if(bp->flags & DF_EntityFlag_HasVAddr && contains_1u64(disasm_vaddr_rng, bp->vaddr)) + { + U64 off = bp->vaddr-disasm_vaddr_rng.min; + U64 idx = dasm_inst_array_idx_from_off__linear_scan(&insts, off); + S64 line_num = (S64)(idx+1); + if(contains_1s64(visible_line_num_range, line_num)) + { + U64 slice_line_idx = (line_num-visible_line_num_range.min); + df_entity_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); + } + } + } + } + + // rjf: find watch pins mapping to this disassembly + { + DF_EntityList pins = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin); + for(DF_EntityNode *n = pins.first; n != 0; n = n->next) + { + DF_Entity *pin = n->entity; + if(pin->flags & DF_EntityFlag_HasVAddr && contains_1u64(disasm_vaddr_rng, pin->vaddr)) + { + U64 off = pin->vaddr-disasm_vaddr_rng.min; + U64 idx = dasm_inst_array_idx_from_off__linear_scan(&insts, off); + S64 line_num = (S64)(idx+1); + if(contains_1s64(visible_line_num_range, line_num)) + { + U64 slice_line_idx = (line_num-visible_line_num_range.min); + df_entity_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], pin); + } + } + } + } + + // rjf: fill dasm -> src info + { + DF_Entity *module = df_module_from_process_vaddr(process, disasm_vaddr_rng.min); + DF_Entity *binary = df_binary_file_from_module(module); + for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) + { + U64 vaddr = disasm_vaddr_rng.min + dasm_inst_array_off_from_idx(&insts, line_num-1); + U64 voff = df_voff_from_vaddr(module, vaddr); + U64 slice_idx = line_num-visible_line_num_range.min; + DF_TextLineDasm2SrcInfoNode *dasm2src_n = push_array(scratch.arena, DF_TextLineDasm2SrcInfoNode, 1); + SLLQueuePush(code_slice_params.line_dasm2src[slice_idx].first, code_slice_params.line_dasm2src[slice_idx].last, dasm2src_n); + code_slice_params.line_dasm2src[slice_idx].count += 1; + dasm2src_n->v = df_text_line_dasm2src_info_from_binary_voff(binary, voff); + } + } + } + + ////////////////////////////// + //- rjf: do keyboard interaction + // + B32 snap[Axis2_COUNT] = {0}; + if(!is_loading && is_focused && visible_line_num_range.max > visible_line_num_range.min) + { + snap[Axis2_X] = snap[Axis2_Y] = df_do_dasm_controls(dasm_handle, ClampBot(visible_line_count, 10) - 10, &dv->cursor, &dv->mark, &dv->preferred_column); + } + + ////////////////////////////// + //- rjf: do goto vaddr + // + if(!is_loading && dv->goto_vaddr != 0) + { + U64 vaddr = dv->goto_vaddr; + dv->goto_vaddr = 0; + U64 line_idx = dasm_inst_array_idx_from_off__linear_scan(&insts, vaddr-disasm_vaddr_rng.min); + S64 line_num = (S64)(line_idx+1); + dv->cursor = dv->mark = txt_pt(line_num, 1); + dv->center_cursor = !dv->contain_cursor || (line_num < visible_line_num_range.min+8 || visible_line_num_range.max-8 < line_num); + } + + ////////////////////////////// + //- rjf: build container + // + UI_Box *container_box = &ui_g_nil_box; + if(has_disasm) + { + ui_set_next_pref_width(ui_px(code_area_dim.x, 1)); + ui_set_next_pref_height(ui_px(code_area_dim.y, 1)); + ui_set_next_child_layout_axis(Axis2_Y); + container_box = ui_build_box_from_stringf(UI_BoxFlag_Clip| + UI_BoxFlag_Scroll| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_AllowOverflowX| + UI_BoxFlag_AllowOverflowY, + "###code_area_%p", view); + } + + ////////////////////////////// + //- rjf: build container contents + // + if(has_disasm) UI_Parent(container_box) + { + //- rjf: build fractional space + container_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; + container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1); + + //- rjf: build code slice + DF_CodeSliceSignal sig = {0}; + UI_Focus(is_focused) + { + sig = df_code_slicef(ws, &ctrl_ctx, &parse_ctx, &code_slice_params, &dv->cursor, &dv->mark, &dv->preferred_column, "dasm_slice_%p", view); + } + + //- rjf: hover eval + if(!sig.base.dragging && sig.mouse_expr_rng.min.line != 0 && contains_1s64(visible_line_num_range, sig.mouse_expr_rng.min.line) && sig.mouse_expr_rng.max.line == sig.mouse_expr_rng.min.line && sig.base.event_flags == 0) + { + U64 line_idx = sig.mouse_expr_rng.min.line-visible_line_num_range.min; + String8 expr = str8_substr(code_slice_params.line_text[line_idx], r1u64(sig.mouse_expr_rng.min.column-1, sig.mouse_expr_rng.max.column-1)); + if(expr.size != 0) + { + DF_Eval eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, expr); + if(eval.mode != EVAL_EvalMode_NULL) + { + U64 off = dasm_inst_array_off_from_idx(&insts, sig.mouse_expr_rng.min.line-1); + U64 vaddr = disasm_vaddr_rng.min+off; + df_set_hover_eval(ws, sig.mouse_expr_baseline_pos, ctrl_ctx, process, sig.mouse_pt, vaddr, expr); + } + } + } + + //- rjf: press code slice? -> focus panel + if(sig.base.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + //- rjf: dragging? -> contain cursor + if(sig.base.dragging && sig.base.event_flags == 0) + { + dv->contain_cursor = 1; + } + + //- rjf: clicked margin? -> place breakpoint + if(sig.clicked_margin_line_num != 0) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.clicked_margin_line_num-1); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_AddressBreakpoint)); + } + + //- rjf: dropped entity onto line? -> do drop + if(sig.dropped_entity_line_num != 0 && !df_entity_is_nil(sig.dropped_entity)) + { + U64 drop_vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.dropped_entity_line_num-1); + DF_Entity *dropped_entity = sig.dropped_entity; + switch(dropped_entity->kind) + { + default:{}break; + case DF_EntityKind_Breakpoint: + case DF_EntityKind_WatchPin: + { + DF_StateDeltaHistory *hist = df_state_delta_history(); + df_state_delta_history_push_batch(hist, &dropped_entity->generation); + df_state_delta_history_push_struct_delta(hist, &dropped_entity->vaddr); + df_entity_change_parent(hist, dropped_entity, dropped_entity->parent, df_entity_root()); + df_entity_equip_vaddr(dropped_entity, drop_vaddr); + }break; + case DF_EntityKind_Thread: + if(contains_1s64(visible_line_num_range, sig.dropped_entity_line_num)) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(dropped_entity); + params.vaddr = drop_vaddr; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetThreadIP)); + }break; + } + } + + //- rjf: copy text + if(!txt_pt_match(sig.copy_range.min, sig.copy_range.max)) + { + // TODO(rjf) +#if 0 + Temp temp = temp_begin(scratch.arena); + DF_Entity *flash_range = df_entity_alloc(entity, DF_EntityKind_FlashMarker); + df_entity_equip_death_timer(flash_range, 0.5f); + df_entity_equip_color_rgba(flash_range, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + df_entity_equip_txt_pt(flash_range, sig.copy_range.min); + df_entity_equip_txt_pt_alt(flash_range, sig.copy_range.max); + String8 text = txti_string_from_handle_txt_rng(temp.arena, txti_handle, sig.copy_range); + os_set_clipboard_text(text); + temp_end(temp); +#endif + } + + //- rjf: toggle cursor watch + if(sig.toggle_cursor_watch) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpressionAtCursor)); + } + + //- rjf: set next statement + if(sig.set_next_statement_line_num != 0 && contains_1s64(visible_line_num_range, sig.set_next_statement_line_num)) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.text_point = txt_pt(sig.set_next_statement_line_num, 1); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetNextStatement)); + } + + //- rjf: run-to-line + if(sig.run_to_line_num != 0 && contains_1s64(visible_line_num_range, sig.run_to_line_num)) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.run_to_line_num-1); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunToAddress)); + } + + //- rjf: go to source + if(sig.goto_src_line_num != 0 && contains_1s64(visible_line_num_range, sig.goto_src_line_num)) + { + U64 vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.goto_src_line_num-1); + DF_Entity *module = df_module_from_process_vaddr(process, vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 voff = df_voff_from_vaddr(module, vaddr); + DF_TextLineDasm2SrcInfo dasm2src = df_text_line_dasm2src_info_from_binary_voff(binary, voff); + String8 file_path = df_full_path_from_entity(scratch.arena, dasm2src.file); + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.text_point = dasm2src.pt; + params.file_path = file_path; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + } + + ////////////////////////////// + //- rjf: apply post-build view snapping rules + // + if(!is_loading) + { + // rjf: contain => snap + if(dv->contain_cursor) + { + dv->contain_cursor = 0; + snap[Axis2_X] = 1; + snap[Axis2_Y] = 1; + } + + // rjf: center cursor + if(dv->center_cursor) + { + dv->center_cursor = 0; + + // rjf: scroll x +#if 0 + { + String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + F32 cursor_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x; + S64 new_idx = (S64)(cursor_advance - code_area_dim.x/2); + new_idx = Clamp(scroll_idx_rng[Axis2_X].min, new_idx, scroll_idx_rng[Axis2_X].max); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + snap[Axis2_X] = 0; + } +#endif + + // rjf: scroll y + { + S64 new_idx = (dv->cursor.line-1) - num_possible_visible_lines/2 + 2; + new_idx = Clamp(scroll_idx_rng[Axis2_Y].min, new_idx, scroll_idx_rng[Axis2_Y].max); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + snap[Axis2_Y] = 0; + } + } + + // rjf: snap in X + if(snap[Axis2_X]) + { +#if 0 + String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + S64 cursor_off = (S64)(f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x + margin_width_px + line_num_width_px); + Rng1S64 visible_pixel_range = + { + view->scroll_pos.x.idx, + view->scroll_pos.x.idx + (S64)code_area_dim.x, + }; + Rng1S64 cursor_pixel_range = + { + cursor_off - (S64)(big_glyph_advance*4) - (S64)(margin_width_px + line_num_width_px), + cursor_off + (S64)(big_glyph_advance*4), + }; + S64 min_delta = Min(0, cursor_pixel_range.min - visible_pixel_range.min); + S64 max_delta = Max(0, cursor_pixel_range.max - visible_pixel_range.max); + S64 new_idx = view->scroll_pos.x.idx+min_delta+max_delta; + new_idx = Clamp(scroll_idx_rng[Axis2_X].min, new_idx, scroll_idx_rng[Axis2_X].max); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); +#endif + } + + // rjf: snap in Y + if(snap[Axis2_Y]) + { + Rng1S64 cursor_visibility_range = r1s64(dv->cursor.line-4, dv->cursor.line+4); + cursor_visibility_range.min = Clamp(0, cursor_visibility_range.min, (S64)insts.count); + cursor_visibility_range.max = Clamp(0, cursor_visibility_range.max, (S64)insts.count); + S64 min_delta = Min(0, cursor_visibility_range.min-visible_line_num_range.min); + S64 max_delta = Max(0, cursor_visibility_range.max-visible_line_num_range.max); + S64 new_idx = view->scroll_pos.y.idx+min_delta+max_delta; + new_idx = Clamp(0, new_idx, (S64)insts.count-1); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + } + + ////////////////////////////// + //- rjf: build horizontal scroll bar + // + if(has_disasm) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(code_area_dim.y); + ui_set_next_fixed_width(panel_box_dim.x - scroll_bar_dim); + ui_set_next_fixed_height(scroll_bar_dim); + { + view->scroll_pos.x = ui_scroll_bar(Axis2_X, + ui_px(scroll_bar_dim, 1.f), + view->scroll_pos.x, + scroll_idx_rng[Axis2_X], + (S64)code_area_dim.x); + } + } + + ////////////////////////////// + //- rjf: build vertical scroll bar + // + if(has_disasm) + { + ui_set_next_fixed_x(code_area_dim.x); + ui_set_next_fixed_y(0); + ui_set_next_fixed_width(scroll_bar_dim); + ui_set_next_fixed_height(panel_box_dim.y - bottom_bar_dim.y - scroll_bar_dim); + { + view->scroll_pos.y = ui_scroll_bar(Axis2_Y, + ui_px(scroll_bar_dim, 1.f), + view->scroll_pos.y, + scroll_idx_rng[Axis2_Y], + num_possible_visible_lines); + } + } + + ////////////////////////////// + //- rjf: top-level container interaction (scrolling) + // + if(!is_loading) + { + UI_Signal sig = ui_signal_from_box(container_box); + if(sig.scroll.x != 0) + { + S64 new_idx = view->scroll_pos.x.idx+sig.scroll.x*big_glyph_advance; + new_idx = clamp_1s64(scroll_idx_rng[Axis2_X], new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + } + if(sig.scroll.y != 0) + { + S64 new_idx = view->scroll_pos.y.idx + sig.scroll.y; + new_idx = clamp_1s64(scroll_idx_rng[Axis2_Y], new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + ui_scroll_pt_clamp_idx(&view->scroll_pos.x, scroll_idx_rng[Axis2_X]); + ui_scroll_pt_clamp_idx(&view->scroll_pos.y, scroll_idx_rng[Axis2_Y]); + } + + ////////////////////////////// + //- rjf: build bottom info bar + // + if(has_disasm) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(code_area_dim.y + scroll_bar_dim); + ui_set_next_pref_width(ui_px(bottom_bar_dim.x, 1)); + ui_set_next_pref_height(ui_px(bottom_bar_dim.y, 1)); + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_AltBackground)); + ui_set_next_flags(UI_BoxFlag_DrawBackground); + UI_Row + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(code_font) + { + DF_Entity *module = df_module_from_process_vaddr(process, disasm_vaddr_rng.min); + U64 cursor_vaddr = (1 <= dv->cursor.line && dv->cursor.line <= insts.count) ? (disasm_vaddr_rng.min+insts.v[dv->cursor.line-1].off) : 0; + ui_labelf("%S", path_normalized_from_string(scratch.arena, module->name)); + ui_spacer(ui_em(1.5f, 1)); + ui_labelf("Address: 0x%I64x, Row: %I64d, Col: %I64d", cursor_vaddr, dv->cursor.line, dv->cursor.column); + ui_spacer(ui_pct(1, 0)); + ui_labelf("(read only)"); + ui_labelf("bin"); + } + } + + ui_unset_focus_active(); + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Watch @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Watch) +{ + ProfBeginFunction(); + DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); + df_eval_watch_view_init(ewv, view); + + // rjf: add roots for watches + for(DF_CfgNode *expr = cfg_root->first; expr != &df_g_nil_cfg_node; expr = expr->next) + { + if(expr->flags & DF_CfgNodeFlag_StringLiteral) + { + DF_EvalRoot *root = df_eval_root_alloc(view, ewv); + df_eval_root_equip_string(root, expr->string); + if(expr->first != &df_g_nil_cfg_node) + { + U64 root_expr_hash = df_hash_from_string(expr->string); + DF_EvalViewKey root_view_key = df_eval_view_key_make((U64)root, root_expr_hash); + DF_EvalView *root_view = df_eval_view_from_key(root_view_key); + DF_ExpandKey root_key = df_expand_key_make((U64)root_view, 5381, 1); + String8 view_rule = expr->first->string; + df_eval_view_set_key_rule(root_view, root_key, view_rule); + } + } + } + ProfEnd(); +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Watch) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List strs = {0}; + DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); + for(DF_EvalRoot *root = ewv->first_root; root != 0; root = root->next) + { + String8 string = df_string_from_eval_root(root); + str8_list_pushf(arena, &strs, "\"%S\"", string); + U64 root_expr_hash = df_hash_from_string(string); + DF_EvalViewKey root_view_key = df_eval_view_key_make((U64)root, root_expr_hash); + DF_EvalView *root_view = df_eval_view_from_key(root_view_key); + DF_ExpandKey root_key = df_expand_key_make((U64)root_view, 5381, 1); + String8 view_rule = df_eval_view_rule_from_key(root_view, root_key); + if(view_rule.size != 0) + { + str8_list_pushf(arena, &strs, ":{\"%S\"}", view_rule); + } + if(root->next != 0) + { + str8_list_pushf(arena, &strs, " "); + } + } + String8 string = str8_list_join(arena, &strs, 0); + scratch_end(scratch); + return string; +} + +DF_VIEW_CMD_FUNCTION_DEF(Watch) +{ + ProfBeginFunction(); + DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); + df_eval_watch_view_cmds(ws, panel, view, ewv, cmds); + ProfEnd(); +} + +DF_VIEW_UI_FUNCTION_DEF(Watch) +{ + ProfBeginFunction(); + ui_set_focus_active(1); + DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); + df_eval_watch_view_build(ws, panel, view, ewv, 1, 10, rect); + ui_unset_focus_active(); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Locals @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Locals) +{ + DF_EvalThreadDerivedReadOnlyWatchViewState *ls = df_view_user_state(view, DF_EvalThreadDerivedReadOnlyWatchViewState); + df_eval_watch_view_init(&ls->ewv, view); +} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Locals) { return str8_lit(""); } +DF_VIEW_CMD_FUNCTION_DEF(Locals) {} +DF_VIEW_UI_FUNCTION_DEF(Locals) +{ + ProfBeginFunction(); + ui_set_focus_active(1); + + // rjf: gather state + DF_EvalThreadDerivedReadOnlyWatchViewState *ls = df_view_user_state(view, DF_EvalThreadDerivedReadOnlyWatchViewState); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); + DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); + U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + Architecture thread_arch = df_architecture_from_entity(thread); + + // rjf: invalidated? -> gather + if(binary != df_entity_from_handle(ls->cached_binary) || + thread_rip_vaddr != ls->cached_vaddr || + thread_arch != ls->cached_architecture) + { + // rjf: record cached data's key + ls->cached_architecture = thread_arch; + ls->cached_binary = df_handle_from_entity(binary); + ls->cached_vaddr = thread_rip_vaddr; + + // rjf: get new locals map + EVAL_String2NumMap *locals = df_query_cached_locals_map_from_binary_voff(binary, thread_rip_voff); + + // rjf: eliminate roots which have disappeared + for(DF_EvalRoot *root = ls->ewv.first_root, *next = 0; root != 0; root = next) + { + next = root->next; + String8 root_string = str8(root->expr_buffer, root->expr_buffer_string_size); + U64 num = eval_num_from_string(locals, root_string); + if(num == 0) + { + df_eval_root_release(&ls->ewv, root); + } + } + + // rjf: add roots for missing locals + for(U64 slot_idx = 0; slot_idx < locals->slots_count; slot_idx += 1) + { + for(EVAL_String2NumMapNode *n = locals->slots[slot_idx].first; + n != 0; + n = n->next) + { + String8 string = n->string; + DF_EvalRoot *root = df_eval_root_from_string(&ls->ewv, string); + if(root == 0) + { + root = df_eval_root_alloc(view, &ls->ewv); + df_eval_root_equip_string(root, string); + } + } + } + } + + // rjf: build + df_eval_watch_view_build(ws, panel, view, &ls->ewv, 0, 10, rect); + + ui_unset_focus_active(); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Registers @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Registers) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Registers) { return str8_lit(""); } +DF_VIEW_CMD_FUNCTION_DEF(Registers) {} +DF_VIEW_UI_FUNCTION_DEF(Registers) +{ + ProfBeginFunction(); + ui_set_focus_active(1); + + // rjf: gather state + DF_RegistersViewState *rv = df_view_user_state(view, DF_RegistersViewState); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + Architecture arch = df_architecture_from_entity(thread); + DF_RegistersViewArchState *rva = &rv->arch_state[arch]; + + // rjf: initialize arch-specific state + if(rva->initialized == 0) + { + rva->initialized = 1; + df_eval_watch_view_init(&rva->ewv, view); + + // rjf: get string tables + U64 reg_names_count = regs_reg_code_count_from_architecture(arch); + String8 *reg_names_base = regs_reg_code_string_table_from_architecture(arch); + String8Array reg_names = {reg_names_base, reg_names_count}; + U64 alias_names_count = regs_alias_code_count_from_architecture(arch); + String8 *alias_names_base = regs_alias_code_string_table_from_architecture(arch); + String8Array alias_names = {alias_names_base, alias_names_count}; + + // rjf: add roots + for(U64 idx = 1; idx < reg_names.count; idx += 1) + { + String8 reg_name = reg_names.strings[idx]; + DF_EvalRoot *root = df_eval_root_alloc(view, &rva->ewv); + df_eval_root_equip_string(root, reg_name); + } + for(U64 idx = 1; idx < alias_names.count; idx += 1) + { + String8 alias_name = alias_names.strings[idx]; + DF_EvalRoot *root = df_eval_root_alloc(view, &rva->ewv); + df_eval_root_equip_string(root, alias_name); + } + } + + // rjf: build + df_eval_watch_view_build(ws, panel, view, &rva->ewv, 0, 16, rect); + + ui_unset_focus_active(); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Output @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Output) +{ + // rjf: set up state + DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); + if(tv->initialized == 0) + { + tv->initialized = 1; + tv->cursor = tv->mark = txt_pt(1, 1); + tv->preferred_column = 1; + tv->find_text_arena = df_view_push_arena_ext(view); + } + + // rjf: default to loading + df_view_equip_loading_info(view, 1, 0, 0); + view->loading_t_target = 1.f; +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Output) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(Output) +{ + DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); + DF_Entity *entity = df_entity_from_handle(view->cmd_entity); + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + // rjf: process + switch(core_cmd_kind) + { + default: break; + case DF_CoreCmdKind_GoToLine: + { + tv->goto_line_num = cmd->params.text_point.line; + }break; + case DF_CoreCmdKind_CenterCursor: + { + tv->center_cursor = 1; + }break; + case DF_CoreCmdKind_ContainCursor: + { + tv->contain_cursor = 1; + }break; + case DF_CoreCmdKind_FindTextForward: + { + arena_clear(tv->find_text_arena); + tv->find_text_fwd = push_str8_copy(tv->find_text_arena, cmd->params.string); + }break; + case DF_CoreCmdKind_FindTextBackward: + { + arena_clear(tv->find_text_arena); + tv->find_text_bwd = push_str8_copy(tv->find_text_arena, cmd->params.string); + }break; + case DF_CoreCmdKind_ToggleBreakpointAtCursor: + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = view->cmd_entity; + params.text_point = tv->cursor; + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_TextBreakpoint)); + tv->contain_cursor = 1; + }break; + case DF_CoreCmdKind_ToggleWatchPinAtCursor: + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = view->cmd_entity; + params.text_point = tv->cursor; + params.string = cmd->params.string; + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchPin)); + tv->contain_cursor = 1; + }break; + } + } +} + +DF_VIEW_UI_FUNCTION_DEF(Output) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + DBGI_Scope *scope = dbgi_scope_open(); + DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); + ui_set_focus_active(1); + + ////////////////////////////// + //- rjf: extract invariants + // + DF_Entity *entity = df_log_from_entity(df_entity_root()); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + F_Tag code_font = df_font_from_slot(DF_FontSlot_Code); + F32 code_font_size = df_font_size_from_slot(ws, DF_FontSlot_Code); + F_Metrics code_font_metrics = f_metrics_from_tag_size(code_font, code_font_size); + F32 code_line_height = ceil_f32(f_line_height_from_metrics(&code_font_metrics) * 1.4f); + F32 big_glyph_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_lit("H")).x; + Vec2F32 panel_box_dim = dim_2f32(rect); + Vec2F32 bottom_bar_dim = {panel_box_dim.x, ui_top_font_size()*1.8f}; + F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); + Vec2F32 code_area_dim = v2f32(panel_box_dim.x - scroll_bar_dim, panel_box_dim.y - scroll_bar_dim - bottom_bar_dim.y); + S64 num_possible_visible_lines = (S64)(code_area_dim.y/code_line_height)+1; + B32 is_focused = ui_is_focus_active(); + + ////////////////////////////// + //- rjf: unpack ctrl ctx & make parse ctx + // + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + U64 unwind_count = ctrl_ctx.unwind_count; + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_module_voff(scope, module, rip_voff); + + ////////////////////////////// + //- rjf: unpack entity info + // + TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); + TXTI_BufferInfo txti_buffer_info = txti_buffer_info_from_handle(scratch.arena, txti_handle); + B32 txti_buffer_is_ready = ((txti_buffer_info.timestamp != 0 || entity->flags & DF_EntityFlag_Output) && + (txti_buffer_info.bytes_processed == txti_buffer_info.bytes_to_process || txti_buffer_info.buffer_apply_gen != 0)); + + ////////////////////////////// + //- rjf: buffer is pending -> equip view with loading information + // + if(!txti_buffer_is_ready) + { + df_view_equip_loading_info(view, 1, txti_buffer_info.bytes_processed, txti_buffer_info.bytes_to_process); + } + + ////////////////////////////// + //- rjf: determine visible line range / count + // + Rng1S64 visible_line_num_range = r1s64(view->scroll_pos.y.idx + (S64)(view->scroll_pos.y.off) + 1 - !!(view->scroll_pos.y.off < 0), + view->scroll_pos.y.idx + (S64)(view->scroll_pos.y.off) + 1 + num_possible_visible_lines); + Rng1S64 target_visible_line_num_range = r1s64(view->scroll_pos.y.idx + 1, + view->scroll_pos.y.idx + 1 + num_possible_visible_lines); + U64 visible_line_count = 0; + { + visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)txti_buffer_info.total_line_count); + visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)txti_buffer_info.total_line_count); + visible_line_num_range.min = Max(1, visible_line_num_range.min); + visible_line_num_range.max = Max(1, visible_line_num_range.max); + target_visible_line_num_range.min = Clamp(1, target_visible_line_num_range.min, (S64)txti_buffer_info.total_line_count); + target_visible_line_num_range.max = Clamp(1, target_visible_line_num_range.max, (S64)txti_buffer_info.total_line_count); + target_visible_line_num_range.min = Max(1, target_visible_line_num_range.min); + target_visible_line_num_range.max = Max(1, target_visible_line_num_range.max); + visible_line_count = (U64)dim_1s64(visible_line_num_range)+1; + } + + ////////////////////////////// + //- rjf: calculate scroll bounds + // + S64 line_size_x = 0; + Rng1S64 scroll_idx_rng[Axis2_COUNT] = {0}; + { + line_size_x = (txti_buffer_info.max_line_size*big_glyph_advance*3)/2; + line_size_x = ClampBot(line_size_x, (S64)big_glyph_advance*120); + line_size_x = ClampBot(line_size_x, (S64)code_area_dim.x); + scroll_idx_rng[Axis2_X] = r1s64(0, line_size_x-(S64)code_area_dim.x); + scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)txti_buffer_info.total_line_count-1); + } + + ////////////////////////////// + //- rjf: calculate line-range-dependent info + // + F32 margin_width_px = big_glyph_advance*3.5f; + F32 line_num_width_px = big_glyph_advance * (log10(visible_line_num_range.max) + 3); + TXTI_Slice slice = txti_slice_from_handle_line_range(scratch.arena, txti_handle, visible_line_num_range); + + ////////////////////////////// + //- rjf: get active search query + // + String8 search_query = {0}; + Side search_query_side = Side_Invalid; + B32 search_query_is_active = 0; + { + for(DF_View *v = view->callee_view; !df_view_is_nil(v); v = v->callee_view) + { + DF_CoreCmdKind query_core_cmd_kind = df_core_cmd_kind_from_string(v->cmd_spec->info.string); + if(query_core_cmd_kind == DF_CoreCmdKind_FindTextForward || + query_core_cmd_kind == DF_CoreCmdKind_FindTextBackward) + { + search_query = v->query; + search_query_is_active = 1; + search_query_side = (query_core_cmd_kind == DF_CoreCmdKind_FindTextForward) ? Side_Max : Side_Min; + break; + } + } + } + + ////////////////////////////// + //- rjf: prepare code slice info bundle, for the viewable region of text + // + DF_CodeSliceParams code_slice_params = {0}; + if(txti_buffer_is_ready) + { + // rjf: fill basics + code_slice_params.flags = DF_CodeSliceFlag_LineNums; + code_slice_params.line_num_range = visible_line_num_range; + code_slice_params.line_text = slice.line_text; + code_slice_params.line_ranges = slice.line_ranges; + code_slice_params.line_tokens = slice.line_tokens; + code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, slice.line_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, slice.line_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, slice.line_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, slice.line_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, slice.line_count); + code_slice_params.font = code_font; + code_slice_params.font_size = code_font_size; + code_slice_params.line_height_px = code_line_height; + code_slice_params.search_query = search_query; + code_slice_params.margin_width_px = margin_width_px; + code_slice_params.line_num_width_px = line_num_width_px; + code_slice_params.line_text_max_width_px = (F32)line_size_x; + code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, entity, DF_EntityKind_FlashMarker); + } + + ////////////////////////////// + //- rjf: build container + // + UI_Box *container_box = &ui_g_nil_box; + if(txti_buffer_is_ready) + { + ui_set_next_pref_width(ui_px(code_area_dim.x, 1)); + ui_set_next_pref_height(ui_px(code_area_dim.y, 1)); + ui_set_next_child_layout_axis(Axis2_Y); + container_box = ui_build_box_from_stringf(UI_BoxFlag_Clip| + UI_BoxFlag_Scroll| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_AllowOverflowX| + UI_BoxFlag_AllowOverflowY, + "###code_area_%p", view); + } + + ////////////////////////////// + //- rjf: cancelled search query -> center cursor + // + if(!search_query_is_active && tv->drifted_for_search) + { + tv->drifted_for_search = 0; + tv->center_cursor = 1; + } + + ////////////////////////////// + //- rjf: search query -> matches + // + DF_TextSearchMatchArray search_query_matches = {0}; +#if !DE2CTRL + { + search_query_matches = df_text_search_match_array_from_entity_needle(scratch.arena, entity, search_query, entity_line_string_flags, tv->cursor); + df_text_search_match_array_sort_in_place(&search_query_matches); + } +#endif + + ////////////////////////////// + //- rjf: do searching operations + // + if(txti_buffer_is_ready) + { + //- rjf: find text (forward) + if(tv->find_text_fwd.size != 0) + { + Temp scratch = scratch_begin(0, 0); + B32 found = 0; + B32 first = 1; + S64 line_num_start = tv->cursor.line; + S64 line_num_last = (S64)txti_buffer_info.total_line_count; + for(S64 line_num = line_num_start;; first = 0) + { + // rjf: pop scratch + temp_end(scratch); + + // rjf: gather line info + String8 line_string = txti_string_from_handle_line_num(scratch.arena, txti_handle, line_num); + U64 search_start = 0; + if(tv->cursor.line == line_num && first) + { + search_start = tv->cursor.column; + } + + // rjf: search string + U64 needle_pos = str8_find_needle(line_string, search_start, tv->find_text_fwd, StringMatchFlag_CaseInsensitive); + if(needle_pos < line_string.size) + { + tv->cursor.line = line_num; + tv->cursor.column = needle_pos+1; + tv->mark = tv->cursor; + found = 1; + break; + } + + // rjf: break if circled back around to cursor + else if(line_num == line_num_start && !first) + { + break; + } + + // rjf: increment + line_num += 1; + if(line_num > line_num_last) + { + line_num = 1; + } + } + tv->center_cursor = found; + if(found == 0) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = push_str8f(scratch.arena, "Could not find \"%S\"", tv->find_text_fwd); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + scratch_end(scratch); + } + + //- rjf: find text (backward) + if(tv->find_text_bwd.size != 0) + { + Temp scratch = scratch_begin(0, 0); + B32 found = 0; + B32 first = 1; + S64 line_num_start = tv->cursor.line; + S64 line_num_last = (S64)txti_buffer_info.total_line_count; + for(S64 line_num = line_num_start;; first = 0) + { + // rjf: pop scratch + temp_end(scratch); + + // rjf: gather line info + String8 line_string = txti_string_from_handle_line_num(scratch.arena, txti_handle, line_num); + if(tv->cursor.line == line_num && first) + { + line_string = str8_prefix(line_string, tv->cursor.column-1); + } + + // rjf: search string + U64 next_needle_pos = line_string.size; + for(U64 needle_pos = 0; needle_pos < line_string.size;) + { + needle_pos = str8_find_needle(line_string, needle_pos, tv->find_text_bwd, StringMatchFlag_CaseInsensitive); + if(needle_pos < line_string.size) + { + next_needle_pos = needle_pos; + needle_pos += 1; + } + } + if(next_needle_pos < line_string.size) + { + tv->cursor.line = line_num; + tv->cursor.column = next_needle_pos+1; + tv->mark = tv->cursor; + found = 1; + break; + } + + // rjf: break if circled back around to cursor line + else if(line_num == line_num_start && !first) + { + break; + } + + // rjf: increment + line_num -= 1; + if(line_num == 0) + { + line_num = line_num_last; + } + } + tv->center_cursor = found; + if(found == 0) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = push_str8f(scratch.arena, "Could not find \"%S\"", tv->find_text_bwd); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + scratch_end(scratch); + } + + MemoryZeroStruct(&tv->find_text_fwd); + MemoryZeroStruct(&tv->find_text_bwd); + arena_clear(tv->find_text_arena); + } + + ////////////////////////////// + //- rjf: do goto line + // + if(txti_buffer_is_ready) if(tv->goto_line_num != 0) + { + S64 line_num = tv->goto_line_num; + tv->goto_line_num = 0; + line_num = Clamp(1, line_num, txti_buffer_info.total_line_count); + tv->cursor = tv->mark = txt_pt(line_num, 1); + tv->center_cursor = !tv->contain_cursor || (line_num < target_visible_line_num_range.min+8 || target_visible_line_num_range.max-8 < line_num); + } + + ////////////////////////////// + //- rjf: do keyboard interaction + // + B32 snap[Axis2_COUNT] = {0}; + if(txti_buffer_is_ready && is_focused && visible_line_num_range.max > visible_line_num_range.min) + { + snap[Axis2_X] = snap[Axis2_Y] = df_do_txti_controls(txti_handle, ClampBot(visible_line_count, 10) - 10, &tv->cursor, &tv->mark, &tv->preferred_column); + } + + ////////////////////////////// + //- rjf: build container contents + // + if(txti_buffer_is_ready) UI_Parent(container_box) + { + //- rjf: build fractional space + container_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; + container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1); + + //- rjf: build code slice + DF_CodeSliceSignal sig = {0}; + UI_Focus(is_focused) + { + sig = df_code_slicef(ws, &ctrl_ctx, &parse_ctx, &code_slice_params, &tv->cursor, &tv->mark, &tv->preferred_column, "txt_view_%p", view); + } + + //- rjf: hover eval + if(!sig.base.dragging && sig.mouse_expr_rng.min.line != 0) + { + TxtRng expr_rng = sig.mouse_expr_rng; + String8 expr = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_rng); + if(expr.size != 0) + { + DF_Eval eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, expr); + if(eval.mode != EVAL_EvalMode_NULL) + { + df_set_hover_eval(ws, sig.mouse_expr_baseline_pos, ctrl_ctx, entity, sig.mouse_pt, 0, expr); + } + } + } + + //- rjf: press code slice? -> focus panel + if(sig.base.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + //- rjf: dragging? -> contain cursor + if(sig.base.dragging) + { + tv->contain_cursor = 1; + } + + //- rjf: copy text + if(!txt_pt_match(sig.copy_range.min, sig.copy_range.max)) + { + Temp temp = temp_begin(scratch.arena); + DF_Entity *flash_range = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); + df_entity_equip_death_timer(flash_range, 0.5f); + df_entity_equip_color_rgba(flash_range, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + df_entity_equip_txt_pt(flash_range, sig.copy_range.min); + df_entity_equip_txt_pt_alt(flash_range, sig.copy_range.max); + String8 text = txti_string_from_handle_txt_rng(temp.arena, txti_handle, sig.copy_range); + os_set_clipboard_text(text); + temp_end(temp); + } + } + + ////////////////////////////// + //- rjf: apply post-build view snapping rules + // + if(txti_buffer_is_ready) + { + // rjf: center first match + TxtPt next_match = df_text_search_match_array_find_nearest__linear_scan(&search_query_matches, tv->cursor, search_query_side).pt; + if(search_query.size != 0 && next_match.line != 0) + { + // TODO(rjf): [ ] @de2ctrl +#if !DE2CTRL + DF_TextSlice match_line_slice = df_text_slice_from_entity(scratch.arena, entity, r1s64(next_match.line, next_match.line), entity_line_string_flags); + String8 match_line = match_line_slice.visible_range_text; + F32 match_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(match_line, next_match.column-1)).x; + container_box->view_off_target.x = match_advance - code_area_dim.x/2; + container_box->view_off_target.y = next_match.line*code_line_height - code_area_dim.y/2 + code_line_height*1.5f; + container_box->view_off_target.x = ClampBot(container_box->view_off_target.x, 0); + container_box->view_off_target.y = ClampBot(container_box->view_off_target.y, 0); + tv->drifted_for_search = 1; +#endif + } + + // rjf: contain => snap + if(tv->contain_cursor) + { + tv->contain_cursor = 0; + snap[Axis2_X] = 1; + snap[Axis2_Y] = 1; + } + + // rjf: center cursor + if(tv->center_cursor) + { + tv->center_cursor = 0; + String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + F32 cursor_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x; + + // rjf: scroll x + { + S64 new_idx = (S64)(cursor_advance - code_area_dim.x/2); + new_idx = Clamp(scroll_idx_rng[Axis2_X].min, new_idx, scroll_idx_rng[Axis2_X].max); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + snap[Axis2_X] = 0; + } + + // rjf: scroll y + { + S64 new_idx = (tv->cursor.line-1) - num_possible_visible_lines/2 + 2; + new_idx = Clamp(scroll_idx_rng[Axis2_Y].min, new_idx, scroll_idx_rng[Axis2_Y].max); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + snap[Axis2_Y] = 0; + } + } + + // rjf: snap in X + if(snap[Axis2_X]) + { + String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + S64 cursor_off = (S64)(f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x + margin_width_px + line_num_width_px); + Rng1S64 visible_pixel_range = + { + view->scroll_pos.x.idx, + view->scroll_pos.x.idx + (S64)code_area_dim.x, + }; + Rng1S64 cursor_pixel_range = + { + cursor_off - (S64)(big_glyph_advance*4) - (S64)(margin_width_px + line_num_width_px), + cursor_off + (S64)(big_glyph_advance*4), + }; + S64 min_delta = Min(0, cursor_pixel_range.min - visible_pixel_range.min); + S64 max_delta = Max(0, cursor_pixel_range.max - visible_pixel_range.max); + S64 new_idx = view->scroll_pos.x.idx+min_delta+max_delta; + new_idx = Clamp(scroll_idx_rng[Axis2_X].min, new_idx, scroll_idx_rng[Axis2_X].max); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + } + + // rjf: snap in Y + if(snap[Axis2_Y]) + { + Rng1S64 cursor_visibility_range = r1s64(tv->cursor.line-4, tv->cursor.line+4); + cursor_visibility_range.min = Clamp(0, cursor_visibility_range.min, (S64)txti_buffer_info.total_line_count); + cursor_visibility_range.max = Clamp(0, cursor_visibility_range.max, (S64)txti_buffer_info.total_line_count); + S64 min_delta = Min(0, cursor_visibility_range.min-target_visible_line_num_range.min); + S64 max_delta = Max(0, cursor_visibility_range.max-target_visible_line_num_range.max); + S64 new_idx = view->scroll_pos.y.idx+min_delta+max_delta; + new_idx = Clamp(0, new_idx, (S64)txti_buffer_info.total_line_count-1); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + } + + ////////////////////////////// + //- rjf: build horizontal scroll bar + // + if(txti_buffer_is_ready) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(code_area_dim.y); + ui_set_next_fixed_width(panel_box_dim.x - scroll_bar_dim); + ui_set_next_fixed_height(scroll_bar_dim); + { + view->scroll_pos.x = ui_scroll_bar(Axis2_X, + ui_px(scroll_bar_dim, 1.f), + view->scroll_pos.x, + scroll_idx_rng[Axis2_X], + (S64)code_area_dim.x); + } + } + + ////////////////////////////// + //- rjf: build vertical scroll bar + // + if(txti_buffer_is_ready) + { + ui_set_next_fixed_x(code_area_dim.x); + ui_set_next_fixed_y(0); + ui_set_next_fixed_width(scroll_bar_dim); + ui_set_next_fixed_height(panel_box_dim.y - bottom_bar_dim.y - scroll_bar_dim); + { + view->scroll_pos.y = ui_scroll_bar(Axis2_Y, + ui_px(scroll_bar_dim, 1.f), + view->scroll_pos.y, + scroll_idx_rng[Axis2_Y], + num_possible_visible_lines); + } + } + + ////////////////////////////// + //- rjf: top-level container interaction (scrolling) + // + if(txti_buffer_is_ready) + { + UI_Signal sig = ui_signal_from_box(container_box); + if(sig.scroll.x != 0) + { + S64 new_idx = view->scroll_pos.x.idx+sig.scroll.x*big_glyph_advance; + new_idx = clamp_1s64(scroll_idx_rng[Axis2_X], new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.x, new_idx); + } + if(sig.scroll.y != 0) + { + S64 new_idx = view->scroll_pos.y.idx + sig.scroll.y; + new_idx = clamp_1s64(scroll_idx_rng[Axis2_Y], new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + ui_scroll_pt_clamp_idx(&view->scroll_pos.x, scroll_idx_rng[Axis2_X]); + ui_scroll_pt_clamp_idx(&view->scroll_pos.y, scroll_idx_rng[Axis2_Y]); + } + + ////////////////////////////// + //- rjf: build bottom info bar + // + if(txti_buffer_is_ready) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(code_area_dim.y + scroll_bar_dim); + ui_set_next_pref_width(ui_px(bottom_bar_dim.x, 1)); + ui_set_next_pref_height(ui_px(bottom_bar_dim.y, 1)); + ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_AltBackground)); + ui_set_next_flags(UI_BoxFlag_DrawBackground); + UI_Row + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_Font(code_font) + { + ui_labelf("Row: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); + ui_spacer(ui_pct(1, 0)); + ui_labelf("(read only)"); + } + } + + ui_unset_focus_active(); + dbgi_scope_close(scope); + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Memory @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Memory) +{ + DF_MemoryViewState *mv = df_view_user_state(view, DF_MemoryViewState); + if(mv->initialized == 0) + { + mv->initialized = 1; + mv->num_columns = 16; + mv->bytes_per_cell = 1; + mv->last_viewed_memory_cache_arena = df_view_push_arena_ext(view); + } +} + +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Memory) +{ + return str8_lit(""); +} + +DF_VIEW_CMD_FUNCTION_DEF(Memory) +{ + DF_MemoryViewState *mv = df_view_user_state(view, DF_MemoryViewState); + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + DF_CmdParams *params = &cmd->params; + switch(core_cmd_kind) + { + default: break; + case DF_CoreCmdKind_CenterCursor: + if(df_view_from_handle(params->view) == view) + { + mv->center_cursor = 1; + }break; + case DF_CoreCmdKind_ContainCursor: + if(df_view_from_handle(params->view) == view) + { + mv->contain_cursor = 1; + }break; + case DF_CoreCmdKind_GoToAddress: + { + // NOTE(rjf): go-to-address occurs with disassembly snaps, and we don't + // generally want to respond to those in thise view, so just skip any + // go-to-address commands that haven't been *explicitly* parameterized + // with this view. + if(df_view_from_handle(params->view) == view) + { + mv->cursor = mv->mark = params->vaddr; + mv->center_cursor = 1; + } + }break; + case DF_CoreCmdKind_SetColumns: + if(df_view_from_handle(params->view) == view) + { + U64 num_columns = params->index; + mv->num_columns = Clamp(1, num_columns, 64); + if(mv->num_columns % mv->bytes_per_cell != 0) + { + mv->bytes_per_cell = 1; + } + mv->center_cursor = 1; + }break; + } + } +} + +DF_VIEW_UI_FUNCTION_DEF(Memory) +{ + Temp scratch = scratch_begin(0, 0); + ProfBeginFunction(); + + ////////////////////////////// + //- rjf: unpack state + // + DF_MemoryViewState *mv = df_view_user_state(view, DF_MemoryViewState); + + ////////////////////////////// + //- rjf: unpack entity params + // + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); + DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + ////////////////////////////// + //- rjf: unpack visual params + // + F_Tag font = df_font_from_slot(DF_FontSlot_Code); + F32 font_size = df_font_size_from_slot(ws, DF_FontSlot_Code); + F32 big_glyph_advance = f_dim_from_tag_size_string(font, font_size, str8_lit("H")).x; + F32 row_height_px = floor_f32(font_size*2.f); + F32 cell_width_px = floor_f32(font_size*2.f * mv->bytes_per_cell); + F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); + Vec2F32 panel_dim = dim_2f32(rect); + F32 footer_dim = font_size*10.f; + Rng2F32 header_rect = r2f32p(0, 0, panel_dim.x, row_height_px); + Rng2F32 footer_rect = r2f32p(0, panel_dim.y-footer_dim, panel_dim.x, panel_dim.y); + Rng2F32 content_rect = r2f32p(0, row_height_px, panel_dim.x-scroll_bar_dim, footer_rect.y0); + + ////////////////////////////// + //- rjf: determine legal scroll range + // + Rng1S64 scroll_idx_rng = r1s64(0, 0x7FFFFFFFFFFFull/mv->num_columns); + + ////////////////////////////// + //- rjf: determine info about visible range of rows + // + Rng1S64 viz_range_rows = {0}; + Rng1U64 viz_range_bytes = {0}; + S64 num_possible_visible_rows = 0; + { + num_possible_visible_rows = dim_2f32(content_rect).y/row_height_px; + viz_range_rows.min = view->scroll_pos.y.idx + (S64)view->scroll_pos.y.off - !!(view->scroll_pos.y.off<0); + viz_range_rows.max = view->scroll_pos.y.idx + (S64)view->scroll_pos.y.off + num_possible_visible_rows, + viz_range_rows.min = clamp_1s64(scroll_idx_rng, viz_range_rows.min); + viz_range_rows.max = clamp_1s64(scroll_idx_rng, viz_range_rows.max); + viz_range_bytes.min = viz_range_rows.min*mv->num_columns; + viz_range_bytes.max = (viz_range_rows.max+1)*mv->num_columns+1; + } + + ////////////////////////////// + //- rjf: take keyboard controls + // + UI_Focus(1) if(ui_is_focus_active()) + { + U64 next_cursor = mv->cursor; + U64 next_mark = mv->mark; + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + next = n->next; + UI_NavAction *action = &n->v; + Vec2S64 cell_delta = {0}; + switch(action->delta_unit) + { + default:{}break; + case UI_NavDeltaUnit_Element: + { + cell_delta.x = (S64)action->delta.x; + cell_delta.y = (S64)action->delta.y; + }break; + case UI_NavDeltaUnit_Chunk: + case UI_NavDeltaUnit_Whole: + { + if(action->delta.x < 0) + { + cell_delta.x = -(S64)(mv->cursor%mv->num_columns); + } + else if(action->delta.x > 0) + { + cell_delta.x = (mv->num_columns-1) - (S64)(mv->cursor%mv->num_columns); + } + if(action->delta.y < 0) + { + cell_delta.y = -4; + } + else if(action->delta.y > 0) + { + cell_delta.y = +4; + } + }break; + } + B32 good_action = 0; + if(action->delta.x != 0 || action->delta.y != 0) + { + good_action = 1; + } + if(good_action && action->flags & UI_NavActionFlag_ZeroDeltaOnSelect && mv->cursor != mv->mark) + { + MemoryZeroStruct(&cell_delta); + } + if(good_action) + { + cell_delta.x = ClampBot(cell_delta.x, (S64)-next_cursor); + cell_delta.y = ClampBot(cell_delta.y, (S64)-(next_cursor/mv->num_columns)); + next_cursor += cell_delta.x; + next_cursor += cell_delta.y*mv->num_columns; + next_cursor = ClampTop(0x7FFFFFFFFFFFull, next_cursor); + } + if(good_action && action->flags & UI_NavActionFlag_PickSelectSide && mv->cursor != mv->mark) + { + if(action->delta.x < 0 || action->delta.y < 0) + { + next_cursor = Min(mv->cursor, mv->mark); + } + else + { + next_cursor = Max(mv->cursor, mv->mark); + } + } + if(good_action && !(action->flags & UI_NavActionFlag_KeepMark)) + { + next_mark = next_cursor; + } + if(good_action) + { + mv->contain_cursor = 1; + ui_nav_eat_action_node(nav_actions, n); + } + } + mv->cursor = next_cursor; + mv->mark = next_mark; + } + + ////////////////////////////// + //- rjf: center cursor + // + if(mv->center_cursor) + { + mv->center_cursor = 0; + S64 cursor_row_idx = mv->cursor/mv->num_columns; + S64 new_idx = (cursor_row_idx-num_possible_visible_rows/2+1); + new_idx = clamp_1s64(scroll_idx_rng, new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + + ////////////////////////////// + //- rjf: contain cursor + // + if(mv->contain_cursor) + { + mv->contain_cursor = 0; + S64 cursor_row_idx = mv->cursor/mv->num_columns; + Rng1S64 cursor_viz_range = r1s64(clamp_1s64(scroll_idx_rng, cursor_row_idx-2), clamp_1s64(scroll_idx_rng, cursor_row_idx+3)); + S64 min_delta = Min(0, cursor_viz_range.min-viz_range_rows.min); + S64 max_delta = Max(0, cursor_viz_range.max-viz_range_rows.max); + S64 new_idx = view->scroll_pos.y.idx+min_delta+max_delta; + new_idx = clamp_1s64(scroll_idx_rng, new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + + ////////////////////////////// + //- rjf: produce fancy string runs for all possible byte values in all cells + // + D_FancyStringList byte_fancy_strings[256] = {0}; + { + Vec4F32 full_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight1); + Vec4F32 zero_color = df_rgba_from_theme_color(DF_ThemeColor_WeakText); + for(U64 idx = 0; idx < ArrayCount(byte_fancy_strings); idx += 1) + { + U8 byte = (U8)idx; + F32 pct = (byte/255.f); + Vec4F32 text_color = mix_4f32(zero_color, full_color, pct); + if(byte == 0) + { + text_color.w *= 0.5f; + } + D_FancyString fstr = {font, push_str8f(scratch.arena, "%02x", byte), text_color, font_size, 0, 0}; + d_fancy_string_list_push(scratch.arena, &byte_fancy_strings[idx], &fstr); + } + } + + ////////////////////////////// + //- rjf: grab windowed memory + // + U64 visible_memory_size = dim_1u64(viz_range_bytes); + U8 *visible_memory = 0; + { + Rng1U64 chunk_aligned_range_bytes = r1u64(AlignDownPow2(viz_range_bytes.min, KB(4)), AlignPow2(viz_range_bytes.max, KB(4))); + U64 current_run_idx = ctrl_run_idx(); + B32 range_changed = (chunk_aligned_range_bytes.min != mv->last_viewed_memory_cache_range.min || + chunk_aligned_range_bytes.max != mv->last_viewed_memory_cache_range.max); + B32 run_happened = (current_run_idx != mv->last_viewed_memory_cache_run_idx); + if(range_changed || run_happened) + { + Temp scratch = scratch_begin(0, 0); + + // rjf: try to read new memory for this range + U64 bytes_to_read = dim_1u64(chunk_aligned_range_bytes); + U8 *buffer = push_array_no_zero(scratch.arena, U8, bytes_to_read); + U64 half1_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min, chunk_aligned_range_bytes.min+bytes_to_read/2), buffer+0); + U64 half2_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min+bytes_to_read/2, chunk_aligned_range_bytes.max), buffer+bytes_to_read/2); + + // rjf: worked? -> clear cache & store + if(half1_bytes_read+half2_bytes_read >= bytes_to_read) + { + arena_clear(mv->last_viewed_memory_cache_arena); + mv->last_viewed_memory_cache_buffer = push_array_no_zero(mv->last_viewed_memory_cache_arena, U8, bytes_to_read); + MemoryCopy(mv->last_viewed_memory_cache_buffer, buffer, bytes_to_read); + } + + // rjf: didn't work, but range didn't change? -> no-op + if(half1_bytes_read == 0 && half2_bytes_read == 0 && !range_changed) + { + // NOTE(rjf): nothing - use stale memory from cache. + } + + // rjf: didn't work, but range DID change? -> clear cache + if(half1_bytes_read == 0 && half2_bytes_read == 0 && range_changed) + { + arena_clear(mv->last_viewed_memory_cache_arena); + mv->last_viewed_memory_cache_buffer = push_array(mv->last_viewed_memory_cache_arena, U8, bytes_to_read); + } + + // rjf: didn't fully work, but changed? -> clear cache memory, fill what we can, zero the rest. + if(half1_bytes_read+half2_bytes_read < bytes_to_read && half1_bytes_read+half2_bytes_read != 0) + { + arena_clear(mv->last_viewed_memory_cache_arena); + mv->last_viewed_memory_cache_buffer = push_array(mv->last_viewed_memory_cache_arena, U8, bytes_to_read); + MemoryCopy(mv->last_viewed_memory_cache_buffer+0, buffer+0, half1_bytes_read); + MemoryCopy(mv->last_viewed_memory_cache_buffer+bytes_to_read/2, buffer+bytes_to_read/2, half2_bytes_read); + } + + // rjf: update cache stamps + if(!df_ctrl_targets_running()) + { + mv->last_viewed_memory_cache_range = chunk_aligned_range_bytes; + mv->last_viewed_memory_cache_run_idx = current_run_idx; + } + + scratch_end(scratch); + } + visible_memory = mv->last_viewed_memory_cache_buffer + viz_range_bytes.min-chunk_aligned_range_bytes.min; + } + + ////////////////////////////// + //- rjf: grab annotations for windowed range of memory + // + typedef struct Annotation Annotation; + struct Annotation + { + Annotation *next; + String8 name_string; + String8 kind_string; + String8 type_string; + Vec4F32 color; + Rng1U64 vaddr_range; + }; + typedef struct AnnotationList AnnotationList; + struct AnnotationList + { + Annotation *first; + Annotation *last; + }; + AnnotationList *visible_memory_annotations = push_array(scratch.arena, AnnotationList, visible_memory_size); + { + DF_Unwind unwind = df_query_cached_unwind_from_thread(thread); + + //- rjf: fill unwind frame annotations + if(unwind.first != 0) + { + U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, unwind.first->regs); + for(DF_UnwindFrame *f = unwind.first->next; f != 0; f = f->next) + { + U64 f_stack_top = regs_rsp_from_arch_block(thread->arch, f->regs); + Rng1U64 frame_vaddr_range = r1u64(last_stack_top, f_stack_top); + Rng1U64 frame_vaddr_range_in_viz = intersect_1u64(frame_vaddr_range, viz_range_bytes); + last_stack_top = f_stack_top; + if(dim_1u64(frame_vaddr_range_in_viz) != 0) + { + DF_Entity *module = df_module_from_process_vaddr(process, f->rip); + DF_Entity *binary = df_binary_file_from_module(module); + U64 rip_voff = df_voff_from_vaddr(module, f->rip); + String8 symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + Annotation *annotation = push_array(scratch.arena, Annotation, 1); + annotation->name_string = symbol_name.size != 0 ? symbol_name : str8_lit("[external code]"); + annotation->kind_string = str8_lit("Call Stack Frame"); + annotation->color = symbol_name.size != 0 ? df_rgba_from_theme_color(DF_ThemeColor_CodeFunction) : df_rgba_from_theme_color(DF_ThemeColor_WeakText); + annotation->vaddr_range = frame_vaddr_range; + for(U64 vaddr = frame_vaddr_range_in_viz.min; vaddr < frame_vaddr_range_in_viz.max; vaddr += 1) + { + U64 visible_byte_idx = vaddr - viz_range_bytes.min; + SLLQueuePush(visible_memory_annotations[visible_byte_idx].first, visible_memory_annotations[visible_byte_idx].last, annotation); + } + } + } + } + + //- rjf: fill selected thread stack range annotation + if(unwind.first != 0) + { + U64 stack_base_vaddr = thread->stack_base; + U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, unwind.first->regs); + Rng1U64 stack_vaddr_range = r1u64(stack_base_vaddr, stack_top_vaddr); + Rng1U64 stack_vaddr_range_in_viz = intersect_1u64(stack_vaddr_range, viz_range_bytes); + if(dim_1u64(stack_vaddr_range_in_viz) != 0) + { + Annotation *annotation = push_array(scratch.arena, Annotation, 1); + annotation->name_string = df_display_string_from_entity(scratch.arena, thread); + annotation->kind_string = str8_lit("Stack"); + annotation->color = thread->flags & DF_EntityFlag_HasColor ? df_rgba_from_entity(thread) : df_rgba_from_theme_color(DF_ThemeColor_PlainText); + annotation->vaddr_range = stack_vaddr_range; + for(U64 vaddr = stack_vaddr_range_in_viz.min; vaddr < stack_vaddr_range_in_viz.max; vaddr += 1) + { + U64 visible_byte_idx = vaddr - viz_range_bytes.min; + SLLQueuePush(visible_memory_annotations[visible_byte_idx].first, visible_memory_annotations[visible_byte_idx].last, annotation); + } + } + } + + //- rjf: fill local variable annotations + { + Vec4F32 color_gen_table[] = + { + df_rgba_from_theme_color(DF_ThemeColor_Thread0), + df_rgba_from_theme_color(DF_ThemeColor_Thread1), + df_rgba_from_theme_color(DF_ThemeColor_Thread2), + df_rgba_from_theme_color(DF_ThemeColor_Thread3), + df_rgba_from_theme_color(DF_ThemeColor_Thread4), + df_rgba_from_theme_color(DF_ThemeColor_Thread5), + df_rgba_from_theme_color(DF_ThemeColor_Thread6), + df_rgba_from_theme_color(DF_ThemeColor_Thread7), + }; + DBGI_Scope *scope = dbgi_scope_open(); + U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); + DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); + U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_module_voff(scope, module, thread_rip_voff); + RADDBG_Parsed *rdbg = parse_ctx.rdbg; + for(U64 idx = 0; idx < parse_ctx.locals_map->slots_count; idx += 1) + { + for(EVAL_String2NumMapNode *n = parse_ctx.locals_map->slots[idx].first; n != 0; n = n->next) + { + String8 local_name = n->string; + DF_Eval local_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, local_name); + if(local_eval.mode == EVAL_EvalMode_Addr) + { + TG_Kind local_eval_type_kind = tg_kind_from_key(local_eval.type_key); + U64 local_eval_type_size = tg_byte_size_from_graph_raddbg_key(parse_ctx.type_graph, rdbg, local_eval.type_key); + Rng1U64 vaddr_rng = r1u64(local_eval.offset, local_eval.offset+local_eval_type_size); + Rng1U64 vaddr_rng_in_visible = intersect_1u64(viz_range_bytes, vaddr_rng); + if(vaddr_rng_in_visible.max != vaddr_rng_in_visible.min) + { + Annotation *annotation = push_array(scratch.arena, Annotation, 1); + { + annotation->name_string = push_str8_copy(scratch.arena, local_name); + annotation->kind_string = str8_lit("Local"); + annotation->type_string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, local_eval.type_key); + annotation->color = color_gen_table[(vaddr_rng.min/8)%ArrayCount(color_gen_table)]; + annotation->vaddr_range = vaddr_rng; + } + for(U64 vaddr = vaddr_rng_in_visible.min; vaddr < vaddr_rng_in_visible.max; vaddr += 1) + { + SLLQueuePushFront(visible_memory_annotations[vaddr-viz_range_bytes.min].first, visible_memory_annotations[vaddr-viz_range_bytes.min].last, annotation); + } + } + } + } + } + dbgi_scope_close(scope); + } + } + + ////////////////////////////// + //- rjf: build main container + // + UI_Box *container_box = &ui_g_nil_box; + { + Vec2F32 dim = dim_2f32(rect); + ui_set_next_fixed_width(dim.x); + ui_set_next_fixed_height(dim.y); + ui_set_next_child_layout_axis(Axis2_Y); + container_box = ui_build_box_from_stringf(0, "memory_view_container_%p", view); + } + + ////////////////////////////// + //- rjf: build header + // + UI_Box *header_box = &ui_g_nil_box; + UI_Parent(container_box) + { + UI_WidthFill UI_PrefHeight(ui_px(row_height_px, 1.f)) UI_Row + header_box = ui_build_box_from_stringf(UI_BoxFlag_DrawSideBottom, "table_header"); + UI_Parent(header_box) + UI_Font(font) + UI_FontSize(font_size) + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + UI_PrefWidth(ui_px(big_glyph_advance*18.f, 1.f)) ui_labelf("Address"); + UI_PrefWidth(ui_px(cell_width_px, 1.f)) + UI_TextAlignment(UI_TextAlign_Center) + { + Rng1U64 col_selection_rng = r1u64(mv->cursor%mv->num_columns, mv->mark%mv->num_columns); + for(U64 row_off = 0; row_off < mv->num_columns*mv->bytes_per_cell; row_off += mv->bytes_per_cell) + { + if(col_selection_rng.min <= row_off && row_off <= col_selection_rng.max) + { + ui_set_next_text_color(df_rgba_from_theme_color(DF_ThemeColor_PlainText)); + } + ui_labelf("%I64X", row_off); + } + } + ui_spacer(ui_px(big_glyph_advance*1.5f, 1.f)); + UI_WidthFill ui_labelf("ASCII"); + } + } + + ////////////////////////////// + //- rjf: build scroll bar + // + UI_Parent(container_box) + { + ui_set_next_fixed_x(content_rect.x1); + ui_set_next_fixed_y(content_rect.y0); + ui_set_next_fixed_width(scroll_bar_dim); + ui_set_next_fixed_height(dim_2f32(content_rect).y); + { + view->scroll_pos.y = ui_scroll_bar(Axis2_Y, + ui_px(scroll_bar_dim, 1.f), + view->scroll_pos.y, + scroll_idx_rng, + num_possible_visible_rows); + } + } + + ////////////////////////////// + //- rjf: build scrollable box + // + UI_Box *scrollable_box = &ui_g_nil_box; + UI_Parent(container_box) + { + ui_set_next_fixed_x(content_rect.x0); + ui_set_next_fixed_y(content_rect.y0); + ui_set_next_fixed_width(dim_2f32(content_rect).x); + ui_set_next_fixed_height(dim_2f32(content_rect).y); + ui_set_next_child_layout_axis(Axis2_Y); + scrollable_box = ui_build_box_from_stringf(UI_BoxFlag_Clip| + UI_BoxFlag_Scroll| + UI_BoxFlag_AllowOverflowX| + UI_BoxFlag_AllowOverflowY, + "scrollable_box"); + scrollable_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; + scrollable_box->view_off.y = scrollable_box->view_off_target.y = floor_f32(row_height_px*mod_f32(view->scroll_pos.y.off, 1.f) + row_height_px*(view->scroll_pos.y.off < 0)); + } + + ////////////////////////////// + //- rjf: build row container/overlay + // + UI_Box *row_container_box = &ui_g_nil_box; + UI_Box *row_overlay_box = &ui_g_nil_box; + UI_Parent(scrollable_box) UI_WidthFill UI_HeightFill + { + ui_set_next_child_layout_axis(Axis2_Y); + ui_set_next_hover_cursor(OS_Cursor_IBar); + row_container_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "row_container"); + UI_Parent(row_container_box) + { + row_overlay_box = ui_build_box_from_stringf(UI_BoxFlag_Floating, "row_overlay"); + } + } + + ////////////////////////////// + //- rjf: interact with row container + // + U64 mouse_hover_byte_num = 0; + { + UI_Signal sig = ui_signal_from_box(row_container_box); + + // rjf: calculate hovered byte + if(sig.hovering || sig.dragging) + { + Vec2F32 mouse_rel = sub_2f32(ui_mouse(), row_container_box->rect.p0); + U64 row_idx = ClampBot(0, mouse_rel.y) / row_height_px; + + // rjf: try from cells + if(mouse_hover_byte_num == 0) + { + U64 col_idx = ClampBot(mouse_rel.x-big_glyph_advance*18.f, 0)/cell_width_px; + if(col_idx < mv->num_columns) + { + mouse_hover_byte_num = viz_range_bytes.min + row_idx*mv->num_columns + col_idx + 1; + } + } + + // rjf: try from ascii + if(mouse_hover_byte_num == 0) + { + U64 col_idx = ClampBot(mouse_rel.x - (big_glyph_advance*18.f + cell_width_px*mv->num_columns + big_glyph_advance*1.5f), 0)/big_glyph_advance; + col_idx = ClampTop(col_idx, mv->num_columns-1); + mouse_hover_byte_num = viz_range_bytes.min + row_idx*mv->num_columns + col_idx + 1; + } + + mouse_hover_byte_num = Clamp(1, mouse_hover_byte_num, 0x7FFFFFFFFFFFull+1); + } + + // rjf: press -> focus panel + if(sig.pressed) + { + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + + // rjf: click & drag -> select + if(sig.dragging && mouse_hover_byte_num != 0) + { + mv->contain_cursor = 1; + mv->cursor = mouse_hover_byte_num-1; + if(sig.pressed) + { + mv->mark = mv->cursor; + } + } + + // rjf: ctrl+scroll -> change font size + if(sig.hovering) + { + for(OS_Event *event = ui_events()->first, *next = 0; event != 0; event = next) + { + next = event->next; + if(os_handle_match(event->window, ui_window()) && event->kind == OS_EventKind_Scroll && event->flags & OS_EventFlag_Ctrl) + { + os_eat_event(ui_events(), event); + if(event->delta.y < 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_IncCodeFontScale)); + } + else if(event->delta.y > 0) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DecCodeFontScale)); + } + } + } + } + } + + ////////////////////////////// + //- rjf: build rows + // + UI_Parent(row_container_box) UI_Font(font) UI_FontSize(font_size) + { + Rng1U64 selection = r1u64(mv->cursor, mv->mark); + U8 *row_ascii_buffer = push_array(scratch.arena, U8, mv->num_columns); + UI_WidthFill UI_PrefHeight(ui_px(row_height_px, 1.f)) + for(S64 row_idx = viz_range_rows.min; row_idx <= viz_range_rows.max; row_idx += 1) + { + Rng1U64 row_range_bytes = r1u64(row_idx*mv->num_columns, (row_idx+1)*mv->num_columns); + B32 row_is_boundary = 0; + Vec4F32 row_boundary_color = {0}; + if(row_range_bytes.min%64 == 0) + { + row_is_boundary = 1; + row_boundary_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + } + ui_set_next_border_color(row_boundary_color); + UI_Box *row = ui_build_box_from_stringf(UI_BoxFlag_DrawSideTop*!!row_is_boundary, "row_%I64x", row_range_bytes.min); + UI_Parent(row) + { + UI_PrefWidth(ui_px(big_glyph_advance*18.f, 1.f)) + { + ui_set_next_text_color((selection.max >= row_range_bytes.min && selection.min < row_range_bytes.max) + ? df_rgba_from_theme_color(DF_ThemeColor_PlainText) + : df_rgba_from_theme_color(DF_ThemeColor_WeakText)); + ui_labelf("%016I64X", row_range_bytes.min); + } + UI_PrefWidth(ui_px(cell_width_px, 1.f)) + UI_TextAlignment(UI_TextAlign_Center) + UI_CornerRadius(0) + { + Vec4F32 full_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight1); + Vec4F32 zero_color = df_rgba_from_theme_color(DF_ThemeColor_WeakText); + for(U64 col_idx = 0; col_idx < mv->num_columns; col_idx += 1) + { + U64 visible_byte_idx = (row_idx-viz_range_rows.min)*mv->num_columns + col_idx; + U64 global_byte_idx = viz_range_bytes.min+visible_byte_idx; + U64 global_byte_num = global_byte_idx+1; + U8 byte_value = visible_memory[visible_byte_idx]; + Annotation *annotation = visible_memory_annotations[visible_byte_idx].first; + UI_BoxFlags cell_flags = 0; + Vec4F32 cell_border_rgba = {0}; + Vec4F32 cell_bg_rgba = {0}; + if(global_byte_num == mouse_hover_byte_num) + { + cell_flags |= UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawSideTop|UI_BoxFlag_DrawSideBottom|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_DrawSideRight; + cell_border_rgba = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + } + if(annotation != 0) + { + cell_flags |= UI_BoxFlag_DrawBackground; + cell_bg_rgba = annotation->color; + if(contains_1u64(annotation->vaddr_range, mouse_hover_byte_num-1)) + { + cell_bg_rgba.w *= 0.15f; + } + else + { + cell_bg_rgba.w *= 0.08f; + } + } + if(selection.min <= global_byte_idx && global_byte_idx <= selection.max) + { + cell_flags |= UI_BoxFlag_DrawBackground; + cell_bg_rgba = df_rgba_from_theme_color(DF_ThemeColor_TextSelection); + } + if(cell_flags & (UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawSideTop|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideBottom)) + { + ui_set_next_border_color(cell_border_rgba); + } + if(cell_flags & UI_BoxFlag_DrawBackground) + { + ui_set_next_background_color(cell_bg_rgba); + } + UI_Box *cell_box = ui_build_box_from_key(UI_BoxFlag_DrawText|cell_flags, ui_key_zero()); + ui_box_equip_display_fancy_strings(cell_box, &byte_fancy_strings[byte_value]); + { + F32 off = 0; + for(Annotation *a = annotation; a != 0; a = a->next) + { + if(global_byte_idx == a->vaddr_range.min) UI_Parent(row_overlay_box) + { + ui_set_next_background_color(annotation->color); + ui_set_next_fixed_x(big_glyph_advance*18.f + col_idx*cell_width_px + -cell_width_px/8.f + off); + ui_set_next_fixed_y((row_idx-viz_range_rows.min)*row_height_px + -cell_width_px/8.f); + ui_set_next_fixed_width(cell_width_px/4.f); + ui_set_next_fixed_height(cell_width_px/4.f); + ui_set_next_corner_radius_00(cell_width_px/8.f); + ui_set_next_corner_radius_01(cell_width_px/8.f); + ui_set_next_corner_radius_10(cell_width_px/8.f); + ui_set_next_corner_radius_11(cell_width_px/8.f); + ui_build_box_from_key(UI_BoxFlag_Floating|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, ui_key_zero()); + off += cell_width_px/8.f + cell_width_px/16.f; + } + } + } + if(annotation != 0 && mouse_hover_byte_num == global_byte_num) UI_Tooltip UI_FontSize(ui_top_font_size()) UI_PrefHeight(ui_px(ui_top_font_size()*1.75f, 1.f)) + { + for(Annotation *a = annotation; a != 0; a = a->next) + { + UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(10, 1)) + { + UI_TextColor(a->color) UI_Font(font) ui_label(a->name_string); + UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(a->kind_string); + } + if(a->type_string.size != 0) + { + df_code_label(1.f, 1, a->type_string); + } + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(str8_from_memory_size(scratch.arena, dim_1u64(a->vaddr_range))); + if(a->next != 0) + { + ui_spacer(ui_em(1.5f, 1.f)); + } + } + } + } + } + ui_spacer(ui_px(big_glyph_advance*1.5f, 1.f)); + UI_WidthFill + { + MemoryZero(row_ascii_buffer, mv->num_columns); + for(U64 col_idx = 0; col_idx < mv->num_columns; col_idx += 1) + { + U8 byte_value = visible_memory[(row_idx-viz_range_rows.min)*mv->num_columns + col_idx]; + row_ascii_buffer[col_idx] = byte_value; + if(byte_value <= 32 || 127 < byte_value) + { + row_ascii_buffer[col_idx] = '.'; + } + } + String8 ascii_text = str8(row_ascii_buffer, mv->num_columns); + UI_Box *ascii_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S###ascii_row_%I64x", ascii_text, row_range_bytes.min); + if(selection.max >= row_range_bytes.min && selection.min < row_range_bytes.max) + { + Rng1U64 selection_in_row = intersect_1u64(row_range_bytes, selection); + D_Bucket *bucket = d_bucket_make(); + D_BucketScope(bucket) + { + Vec2F32 text_pos = ui_box_text_position(ascii_box); + d_rect(r2f32p(text_pos.x + f_dim_from_tag_size_string(font, font_size, str8_prefix(ascii_text, selection_in_row.min+0-row_range_bytes.min)).x - font_size/8.f, + ascii_box->rect.y0, + text_pos.x + f_dim_from_tag_size_string(font, font_size, str8_prefix(ascii_text, selection_in_row.max+1-row_range_bytes.min)).x + font_size/4.f, + ascii_box->rect.y1), + df_rgba_from_theme_color(DF_ThemeColor_TextSelection), + 0, 0, 1.f); + } + ui_box_equip_draw_bucket(ascii_box, bucket); + } + if(mouse_hover_byte_num != 0 && contains_1u64(row_range_bytes, mouse_hover_byte_num-1)) + { + D_Bucket *bucket = d_bucket_make(); + D_BucketScope(bucket) + { + Vec2F32 text_pos = ui_box_text_position(ascii_box); + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); + d_rect(r2f32p(text_pos.x + f_dim_from_tag_size_string(font, font_size, str8_prefix(ascii_text, mouse_hover_byte_num-1-row_range_bytes.min)).x - font_size/8.f, + ascii_box->rect.y0, + text_pos.x + f_dim_from_tag_size_string(font, font_size, str8_prefix(ascii_text, mouse_hover_byte_num+0-row_range_bytes.min)).x + font_size/4.f, + ascii_box->rect.y1), + color, + 1.f, 3.f, 1.f); + } + ui_box_equip_draw_bucket(ascii_box, bucket); + } + } + } + } + } + + ////////////////////////////// + //- rjf: build footer + // + UI_Box *footer_box = &ui_g_nil_box; + UI_Parent(container_box) + { + ui_set_next_fixed_x(footer_rect.x0); + ui_set_next_fixed_y(footer_rect.y0); + ui_set_next_fixed_width(dim_2f32(footer_rect).x); + ui_set_next_fixed_height(dim_2f32(footer_rect).y); + footer_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, "footer"); + UI_Parent(footer_box) UI_Font(font) UI_FontSize(font_size) + { + UI_PrefWidth(ui_em(7.5f, 1.f)) UI_HeightFill UI_Column UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + UI_PrefHeight(ui_px(row_height_px, 0.f)) + { + ui_labelf("Address:"); + ui_labelf("U8:"); + ui_labelf("U16:"); + ui_labelf("U32:"); + ui_labelf("U64:"); + } + UI_PrefWidth(ui_em(45.f, 1.f)) UI_HeightFill UI_Column UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_CodeNumeric)) + UI_PrefHeight(ui_px(row_height_px, 0.f)) + { + B32 cursor_in_range = (viz_range_bytes.min <= mv->cursor && mv->cursor+8 <= viz_range_bytes.max); + ui_labelf("%016X", mv->cursor); + if(cursor_in_range) + { + U64 as_u8 = 0; + U64 as_u16 = 0; + U64 as_u32 = 0; + U64 as_u64 = 0; + U64 cursor_off = mv->cursor-viz_range_bytes.min; + as_u8 = (U64)*(U8 *)(visible_memory + cursor_off); + as_u16 = (U64)*(U16*)(visible_memory + cursor_off); + as_u32 = (U64)*(U32*)(visible_memory + cursor_off); + as_u64 = (U64)*(U64*)(visible_memory + cursor_off); + ui_labelf("%02X (%I64u)", as_u8, as_u8); + ui_labelf("%04X (%I64u)", as_u16, as_u16); + ui_labelf("%08X (%I64u)", as_u32, as_u32); + ui_labelf("%016X (%I64u)", as_u64, as_u64); + } + } + } + } + + ////////////////////////////// + //- rjf: scroll + // + { + UI_Signal sig = ui_signal_from_box(scrollable_box); + if(sig.scroll.y != 0) + { + S64 new_idx = view->scroll_pos.y.idx + sig.scroll.y; + new_idx = clamp_1s64(scroll_idx_rng, new_idx); + ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); + } + } + + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Breakpoints @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Breakpoints) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Breakpoints) {return str8_lit("");} +DF_VIEW_CMD_FUNCTION_DEF(Breakpoints) {} +DF_VIEW_UI_FUNCTION_DEF(Breakpoints) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: get state + typedef struct DF_BreakpointsViewState DF_BreakpointsViewState; + struct DF_BreakpointsViewState + { + B32 initialized; + DF_Handle selected_entity; + S64 selected_column; + F32 enabled_col_pct; + F32 desc_col_pct; + F32 loc_col_pct; + F32 hit_col_pct; + F32 del_col_pct; + }; + DF_BreakpointsViewState *bv = df_view_user_state(view, DF_BreakpointsViewState); + if(bv->initialized == 0) + { + bv->initialized = 1; + bv->enabled_col_pct = 0.05f; + bv->desc_col_pct = 0.25f; + bv->loc_col_pct = 0.50f; + bv->hit_col_pct = 0.15f; + bv->del_col_pct = 0.05f; + } + F32 *col_pcts[] = {&bv->enabled_col_pct, &bv->desc_col_pct, &bv->loc_col_pct, &bv->hit_col_pct, &bv->del_col_pct}; + + //- rjf: get entities + DF_EntityList entities_list = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); + DF_EntityArray entities = df_entity_array_from_list(scratch.arena, &entities_list); + + //- rjf: selected column/entity -> selected cursor + Vec2S64 cursor = {bv->selected_column}; + for(U64 idx = 0; idx < entities.count; idx += 1) + { + if(entities.v[idx] == df_entity_from_handle(bv->selected_entity)) + { + cursor.y = (S64)(idx+1); + break; + } + } + + //- rjf: build table + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(4, entities.count)); + scroll_list_params.item_range = r1s64(0, entities.count+1); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_TableF(ArrayCount(col_pcts), col_pcts, "breakpoints_table") + { + if(visible_row_range.min == 0) UI_TableVector UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + UI_TableCell{} + UI_TableCell{ui_labelf("Name");} + UI_TableCell{ui_labelf("Location");} + UI_TableCell{ui_labelf("Hit Count");} + UI_TableCell{} + } + Vec2S64 next_cursor = cursor; + for(U64 idx = Max(1, visible_row_range.min); idx <= visible_row_range.max && idx <= entities.count; idx += 1) + { + DF_Entity *entity = entities.v[idx-1]; + B32 row_is_selected = (cursor.y == (S64)(idx)); + UI_NamedTableVectorF("breakpoint_%p", entity) + { + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 0) + { + if(df_icon_buttonf(entity->b32 ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, "###ebl_%p", entity).clicked) + { + df_entity_equip_b32(entity, !entity->b32); + } + } + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 1) + { + df_entity_desc_button(ws, entity); + } + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 2) + { + B32 loc_is_code = 0; + String8 loc_string = {0}; + DF_Entity *file_parent = df_entity_ancestor_from_kind(entity, DF_EntityKind_File); + DF_Entity *symbol_name = df_entity_child_from_kind(entity, DF_EntityKind_EntryPointName); + if(!df_entity_is_nil(file_parent)) + { + loc_string = push_str8f(scratch.arena, "%S:%I64u:%I64u", file_parent->name, entity->text_point.line, entity->text_point.column); + } + else if(!df_entity_is_nil(symbol_name)) + { + loc_string = symbol_name->name; + loc_is_code = 1; + } + else if(entity->flags & DF_EntityFlag_HasVAddr) + { + loc_string = push_str8f(scratch.arena, "0x%016I64x", entity->vaddr); + loc_is_code = 1; + } + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "loc_%p", entity); + UI_Parent(box) + { + UI_Font(loc_is_code ? df_font_from_slot(DF_FontSlot_Code) : ui_top_font()) + { + ui_label(loc_string); + } + } + UI_Signal sig = ui_signal_from_box(box); + if(sig.double_clicked || sig.keyboard_clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.file_path = df_full_path_from_entity(scratch.arena, file_parent); + params.text_point = entity->text_point; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + if(sig.pressed) + { + next_cursor = v2s64(2, (S64)(idx)); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 3) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###cnd_%p", entity); + UI_Parent(box) + { + String8 hit_count_string = str8_from_u64(scratch.arena, entity->u64, 10, 0, 0); + UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, hit_count_string); + } + UI_Signal sig = ui_signal_from_box(box); + if(sig.pressed) + { + next_cursor = v2s64(3, (S64)(idx)); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 4) + { + if(df_icon_buttonf(DF_IconKind_Trash, "###del_%p", entity).clicked) + { + df_entity_mark_for_deletion(entity); + } + } + } + } + cursor = next_cursor; + } + + //- rjf: selected num -> selected entity + bv->selected_column = cursor.x; + bv->selected_entity = (1 <= cursor.y && cursor.y <= entities.count) ? df_handle_from_entity(entities.v[cursor.y-1]) : df_handle_zero(); + + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: WatchPins @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(WatchPins) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(WatchPins) {return str8_lit("");} +DF_VIEW_CMD_FUNCTION_DEF(WatchPins) {} +DF_VIEW_UI_FUNCTION_DEF(WatchPins) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: get state + typedef struct DF_WatchPinsViewState DF_WatchPinsViewState; + struct DF_WatchPinsViewState + { + B32 initialized; + DF_Handle selected_entity; + S64 selected_column; + F32 desc_col_pct; + F32 loc_col_pct; + F32 del_col_pct; + }; + DF_WatchPinsViewState *pv = df_view_user_state(view, DF_WatchPinsViewState); + if(pv->initialized == 0) + { + pv->initialized = 1; + pv->desc_col_pct = 0.35f; + pv->loc_col_pct = 0.60f; + pv->del_col_pct = 0.05f; + } + F32 *col_pcts[] = {&pv->desc_col_pct, &pv->loc_col_pct, &pv->del_col_pct}; + + //- rjf: get entities + DF_EntityList entities_list = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin); + DF_EntityArray entities = df_entity_array_from_list(scratch.arena, &entities_list); + + //- rjf: selected column/entity -> selected cursor + Vec2S64 cursor = {pv->selected_column}; + for(U64 idx = 0; idx < entities.count; idx += 1) + { + if(entities.v[idx] == df_entity_from_handle(pv->selected_entity)) + { + cursor.y = (S64)(idx+1); + break; + } + } + + //- rjf: build table + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); + scroll_list_params.dim_px = dim_2f32(rect); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(2, entities.count)); + scroll_list_params.item_range = r1s64(0, entities.count+1); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_TableF(ArrayCount(col_pcts), col_pcts, "pins_table") + { + if(visible_row_range.min == 0) UI_TableVector UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) + { + UI_TableCell{ui_labelf("Name");} + UI_TableCell{ui_labelf("Location");} + UI_TableCell{} + } + Vec2S64 next_cursor = cursor; + for(U64 idx = Max(1, visible_row_range.min); idx <= visible_row_range.max && idx <= entities.count; idx += 1) + { + DF_Entity *entity = entities.v[idx-1]; + B32 row_is_selected = (cursor.y == (S64)(idx)); + UI_NamedTableVectorF("pin_%p", entity) + { + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 0) + { + df_entity_desc_button(ws, entity); + } + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 1) + { + String8 loc_string = {0}; + DF_Entity *file_parent = df_entity_ancestor_from_kind(entity, DF_EntityKind_File); + if(!df_entity_is_nil(file_parent)) + { + loc_string = push_str8f(scratch.arena, "%S:%I64u:%I64u", file_parent->name, entity->text_point.line, entity->text_point.column); + } + else if(entity->flags & DF_EntityFlag_HasVAddr) + { + loc_string = push_str8f(scratch.arena, "0x%016I64x", entity->vaddr); + } + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%S###loc_%p", loc_string, entity); + UI_Signal sig = ui_signal_from_box(box); + if(sig.double_clicked || sig.keyboard_clicked) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.file_path = df_full_path_from_entity(scratch.arena, file_parent); + params.text_point = entity->text_point; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_FilePath); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + if(sig.pressed) + { + next_cursor = v2s64(1, (S64)(idx)); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + UI_TableCell UI_FocusHot(row_is_selected && cursor.x == 2) + { + if(df_icon_buttonf(DF_IconKind_Trash, "###del_%p", entity).clicked) + { + df_entity_mark_for_deletion(entity); + } + } + } + } + cursor = next_cursor; + } + + //- rjf: selected num -> selected entity + pv->selected_column = cursor.x; + pv->selected_entity = (1 <= cursor.y && cursor.y <= entities.count) ? df_handle_from_entity(entities.v[cursor.y-1]) : df_handle_zero(); + + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: ExceptionFilters @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(ExceptionFilters) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(ExceptionFilters) {return str8_lit("");} +DF_VIEW_CMD_FUNCTION_DEF(ExceptionFilters) {} +DF_VIEW_UI_FUNCTION_DEF(ExceptionFilters) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + + //- rjf: get state + typedef struct DF_ExceptionFiltersViewState DF_ExceptionFiltersViewState; + struct DF_ExceptionFiltersViewState + { + Vec2S64 cursor; + }; + DF_ExceptionFiltersViewState *sv = df_view_user_state(view, DF_ExceptionFiltersViewState); + + //- rjf: get list of options + typedef struct DF_ExceptionFiltersOption DF_ExceptionFiltersOption; + struct DF_ExceptionFiltersOption + { + String8 name; + B32 is_enabled; + CTRL_ExceptionCodeKind exception_code_kind; + }; + typedef struct DF_ExceptionFiltersOptionChunkNode DF_ExceptionFiltersOptionChunkNode; + struct DF_ExceptionFiltersOptionChunkNode + { + DF_ExceptionFiltersOptionChunkNode *next; + DF_ExceptionFiltersOption *v; + U64 cap; + U64 count; + }; + typedef struct DF_ExceptionFiltersOptionChunkList DF_ExceptionFiltersOptionChunkList; + struct DF_ExceptionFiltersOptionChunkList + { + DF_ExceptionFiltersOptionChunkNode *first; + DF_ExceptionFiltersOptionChunkNode *last; + U64 option_count; + U64 node_count; + }; + typedef struct DF_ExceptionFiltersOptionArray DF_ExceptionFiltersOptionArray; + struct DF_ExceptionFiltersOptionArray + { + DF_ExceptionFiltersOption *v; + U64 count; + }; + DF_ExceptionFiltersOptionChunkList opts_list = {0}; + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)(CTRL_ExceptionCodeKind_Null+1); + k < CTRL_ExceptionCodeKind_COUNT; + k = (CTRL_ExceptionCodeKind)(k+1)) + { + DF_ExceptionFiltersOptionChunkNode *node = opts_list.last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(scratch.arena, DF_ExceptionFiltersOptionChunkNode, 1); + node->cap = 256; + node->v = push_array_no_zero(scratch.arena, DF_ExceptionFiltersOption, node->cap); + SLLQueuePush(opts_list.first, opts_list.last, node); + opts_list.node_count += 1; + } + node->v[node->count].name = push_str8f(scratch.arena, "0x%x %S", ctrl_exception_code_kind_code_table[k], ctrl_exception_code_kind_display_string_table[k]); + node->v[node->count].is_enabled = !!(df_state->ctrl_exception_code_filters[k/64] & (1ull<<(k%64))); + node->v[node->count].exception_code_kind = k; + node->count += 1; + opts_list.option_count += 1; + } + DF_ExceptionFiltersOptionArray opts = {0}; + { + opts.count = opts_list.option_count; + opts.v = push_array_no_zero(scratch.arena, DF_ExceptionFiltersOption, opts.count); + U64 idx = 0; + for(DF_ExceptionFiltersOptionChunkNode *n = opts_list.first; n != 0; n = n->next) + { + MemoryCopy(opts.v+idx, n->v, n->count*sizeof(DF_ExceptionFiltersOption)); + idx += n->count; + } + } + + //- rjf: build option table + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + Vec2F32 rect_dim = dim_2f32(rect); + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = rect_dim; + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, opts.count)); + scroll_list_params.item_range = r1s64(0, opts.count); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &sv->cursor, &visible_row_range, &scroll_list_sig) + { + for(S64 row = visible_row_range.min; row <= visible_row_range.max && row < opts.count; row += 1) UI_FocusHot(sv->cursor.y == row+1) + { + DF_ExceptionFiltersOption *opt = &opts.v[row]; + UI_Signal sig = df_icon_buttonf(opt->is_enabled ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, "%S", opt->name); + if(sig.clicked) + { + if(opt->exception_code_kind != CTRL_ExceptionCodeKind_Null) + { + CTRL_ExceptionCodeKind k = opt->exception_code_kind; + if(opt->is_enabled) + { + df_state->ctrl_exception_code_filters[k/64] &= ~(1ull<<(k%64)); + } + else + { + df_state->ctrl_exception_code_filters[k/64] |= (1ull<<(k%64)); + } + } + } + } + } + + scratch_end(scratch); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Theme @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(Theme) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Theme) {return str8_lit("");} + +DF_VIEW_CMD_FUNCTION_DEF(Theme) +{ + for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) + { + DF_Cmd *cmd = &n->cmd; + DF_CoreCmdKind core_cmd_kind = df_core_cmd_kind_from_string(cmd->spec->info.string); + + // rjf: mismatched view => skip + if(df_view_caller_root_from_view(df_view_from_handle(cmd->params.view)) != view) + { + continue; + } + + //rjf: process + switch(core_cmd_kind) + { + default:break; + case DF_CoreCmdKind_PickFile: + { + Temp scratch = scratch_begin(0, 0); + String8 path = cmd->params.file_path; + String8 data = os_data_from_file_path(scratch.arena, path); + DF_CfgTable cfg_table = {0}; + df_cfg_table_push_unparsed_string(scratch.arena, &cfg_table, data, DF_CfgSrc_User); + DF_CfgVal *colors = df_cfg_val_from_string(&cfg_table, str8_lit("colors")); + for(DF_CfgNode *colors_set = colors->first; + colors_set != &df_g_nil_cfg_node; + colors_set = colors_set->next) + { + for(DF_CfgNode *color = colors_set->first; + color != &df_g_nil_cfg_node; + color = color->next) + { + String8 color_name = color->string; + DF_ThemeColor color_code = DF_ThemeColor_Null; + for(DF_ThemeColor c = DF_ThemeColor_Null; c < DF_ThemeColor_COUNT; c = (DF_ThemeColor)(c+1)) + { + if(str8_match(df_g_theme_color_cfg_string_table[c], color_name, StringMatchFlag_CaseInsensitive)) + { + color_code = c; + break; + } + } + if(color_code != DF_ThemeColor_Null) + { + DF_CfgNode *hex_cfg = color->first; + String8 hex_string = hex_cfg->string; + U64 hex_val = 0; + try_u64_from_str8_c_rules(hex_string, &hex_val); + Vec4F32 color_rgba = rgba_from_u32((U32)hex_val); + df_gfx_state->cfg_theme_target.colors[color_code] = color_rgba; + } + } + } + scratch_end(scratch); + }break; + } + } +} + +DF_VIEW_UI_FUNCTION_DEF(Theme) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + + //- rjf: get state + typedef struct DF_ThemeViewState DF_ThemeViewState; + struct DF_ThemeViewState + { + Vec2S64 cursor; + TxtPt txt_cursor; + TxtPt txt_mark; + U8 txt_buffer[1024]; + U64 txt_size; + DF_ThemeColor color_ctx_menu_color; + Vec4F32 color_ctx_menu_color_hsva; + }; + DF_ThemeViewState *sv = df_view_user_state(view, DF_ThemeViewState); + + //- rjf: build preset ctx menu + UI_Key preset_ctx_menu_key = ui_key_from_stringf(ui_key_zero(), "%p_preset_ctx_menu", view); + UI_CtxMenu(preset_ctx_menu_key) UI_PrefWidth(ui_em(30.f, 1.f)) + { + for(DF_ThemePreset preset = (DF_ThemePreset)0; + preset < DF_ThemePreset_COUNT; + preset = (DF_ThemePreset)(preset+1)) + { + Vec4F32 *colors = df_g_theme_preset_colors_table[preset]; + Vec4F32 bg_color = colors[DF_ThemeColor_PlainBackground]; + Vec4F32 tx_color = colors[DF_ThemeColor_PlainText]; + Vec4F32 bd_color = colors[DF_ThemeColor_PlainBorder]; + ui_set_next_background_color(bg_color); + ui_set_next_text_color(tx_color); + ui_set_next_border_color(bd_color); + if(ui_buttonf("%S", df_g_theme_preset_display_string_table[preset]).clicked) + { + MemoryCopy(df_gfx_state->cfg_theme_target.colors, colors, sizeof(df_gfx_state->cfg_theme_target.colors)); + } + } + } + + //- rjf: produce per-color context menu keys + UI_Key *color_ctx_menu_keys = push_array(scratch.arena, UI_Key, DF_ThemeColor_COUNT); + { + for(DF_ThemeColor color = (DF_ThemeColor)(DF_ThemeColor_Null+1); + color < DF_ThemeColor_COUNT; + color = (DF_ThemeColor)(color+1)) + { + color_ctx_menu_keys[color] = ui_key_from_stringf(ui_key_zero(), "###settings_color_ctx_menu_%I64x", (U64)color); + } + } + + //- rjf: do color context menus + for(DF_ThemeColor color = (DF_ThemeColor)(DF_ThemeColor_Null+1); + color < DF_ThemeColor_COUNT; + color = (DF_ThemeColor)(color+1)) + { + UI_PrefWidth(ui_em(28.5f, 1)) UI_PrefHeight(ui_children_sum(1.f)) UI_CtxMenu(color_ctx_menu_keys[color]) UI_Padding(ui_em(1.5f, 1.f)) + { + // rjf: build title + UI_Row + { + ui_spacer(ui_em(1.5f, 1.f)); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(df_g_theme_color_display_string_table[color]); + } + + ui_spacer(ui_em(1.5f, 1.f)); + + // rjf: build picker + { + ui_set_next_pref_height(ui_em(22.f, 1.f)); + UI_Row UI_Padding(ui_pct(1, 0)) + { + UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_em(22.f, 1.f)) UI_Flags(UI_BoxFlag_FocusNavSkip) + { + ui_sat_val_pickerf(sv->color_ctx_menu_color_hsva.x, &sv->color_ctx_menu_color_hsva.y, &sv->color_ctx_menu_color_hsva.z, "###settings_satval_picker"); + } + + ui_spacer(ui_em(0.75f, 1.f)); + + UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(22.f, 1.f)) UI_Flags(UI_BoxFlag_FocusNavSkip) + ui_hue_pickerf(&sv->color_ctx_menu_color_hsva.x, sv->color_ctx_menu_color_hsva.y, sv->color_ctx_menu_color_hsva.z, "###settings_hue_picker"); + + UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(22.f, 1.f)) UI_Flags(UI_BoxFlag_FocusNavSkip) + ui_alpha_pickerf(&sv->color_ctx_menu_color_hsva.w, "###settings_alpha_picker"); + } + } + + ui_spacer(ui_em(1.5f, 1.f)); + + // rjf: build line edits + UI_Row + UI_WidthFill + UI_Padding(ui_em(1.5f, 1.f)) + UI_PrefHeight(ui_children_sum(1.f)) + UI_Column + UI_PrefHeight(ui_em(2.25f, 1.f)) + { + Vec4F32 hsva = sv->color_ctx_menu_color_hsva; + Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z); + Vec3F32 rgb = rgb_from_hsv(hsv); + Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, sv->color_ctx_menu_color_hsva.w); + String8 hex_string = hex_string_from_rgba_4f32(scratch.arena, rgba); + hex_string = push_str8f(scratch.arena, "#%S", hex_string); + String8 r_string = push_str8f(scratch.arena, "%.2f", rgba.x); + String8 g_string = push_str8f(scratch.arena, "%.2f", rgba.y); + String8 b_string = push_str8f(scratch.arena, "%.2f", rgba.z); + String8 h_string = push_str8f(scratch.arena, "%.2f", hsva.x); + String8 s_string = push_str8f(scratch.arena, "%.2f", hsva.y); + String8 v_string = push_str8f(scratch.arena, "%.2f", hsva.z); + String8 a_string = push_str8f(scratch.arena, "%.2f", rgba.w); + UI_Row UI_Font(df_font_from_slot(DF_FontSlot_Code)) + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("Hex"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, hex_string, "###hex_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_rgba = rgba_from_hex_string_4f32(string); + Vec4F32 new_hsva = hsva_from_rgba(new_rgba); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + ui_spacer(ui_em(0.75f, 1.f)); + UI_Row + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("R"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, r_string, "###r_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_rgba = v4f32((F32)f64_from_str8(string), rgba.y, rgba.z, rgba.w); + Vec4F32 new_hsva = hsva_from_rgba(new_rgba); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + UI_Row + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("G"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, g_string, "###g_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_rgba = v4f32(rgba.x, (F32)f64_from_str8(string), rgba.z, rgba.w); + Vec4F32 new_hsva = hsva_from_rgba(new_rgba); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + UI_Row + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("B"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, b_string, "###b_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_rgba = v4f32(rgba.x, rgba.y, (F32)f64_from_str8(string), rgba.w); + Vec4F32 new_hsva = hsva_from_rgba(new_rgba); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + ui_spacer(ui_em(0.75f, 1.f)); + UI_Row + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("H"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, h_string, "###h_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_hsva = v4f32((F32)f64_from_str8(string), hsva.y, hsva.z, hsva.w); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + UI_Row + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("S"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, s_string, "###s_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_hsva = v4f32(hsva.x, (F32)f64_from_str8(string), hsva.z, hsva.w); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + UI_Row + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("V"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, v_string, "###v_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_hsva = v4f32(hsva.x, hsva.y, (F32)f64_from_str8(string), hsva.w); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + ui_spacer(ui_em(0.75f, 1.f)); + UI_Row + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("A"); + UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, a_string, "###a_edit"); + if(sig.commit) + { + String8 string = str8(sv->txt_buffer, sv->txt_size); + Vec4F32 new_hsva = v4f32(hsva.x, hsva.y, hsva.z, (F32)f64_from_str8(string)); + sv->color_ctx_menu_color_hsva = new_hsva; + } + } + } + + // rjf: commit state to theme + Vec4F32 hsva = sv->color_ctx_menu_color_hsva; + Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z); + Vec3F32 rgb = rgb_from_hsv(hsv); + Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, sv->color_ctx_menu_color_hsva.w); + df_gfx_state->cfg_theme_target.colors[sv->color_ctx_menu_color] = rgba; + } + } + + //- rjf: build non-scrolled header + UI_PrefHeight(ui_px(row_height_px, 1.f)) UI_Row + { + // rjf: preset selector + UI_FocusHot(sv->cursor.y == 1 && sv->cursor.x == 0) + { + UI_Signal preset_sig = df_icon_buttonf(DF_IconKind_Palette, "Apply Preset"); + if(preset_sig.clicked) + { + ui_ctx_menu_open(preset_ctx_menu_key, preset_sig.box->key, v2f32(0, dim_2f32(preset_sig.box->rect).y)); + } + } + + // rjf: load-from-file + UI_FocusHot(sv->cursor.y == 1 && sv->cursor.x == 1) + { + if(df_icon_buttonf(DF_IconKind_FileOutline, "Load From File").clicked) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + } + } + } + + //- rjf: build palette table + Rng1S64 visible_row_range = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + Vec2F32 rect_dim = dim_2f32(rect); + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = v2f32(rect_dim.x, rect_dim.y-row_height_px); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(1, DF_ThemeColor_COUNT)); + scroll_list_params.item_range = r1s64(0, DF_ThemeColor_COUNT-1); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(1) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &sv->cursor, &visible_row_range, &scroll_list_sig) + { + for(S64 row = visible_row_range.min; row <= visible_row_range.max; row += 1) + { + DF_ThemeColor color = (DF_ThemeColor)(row+1); + if(DF_ThemeColor_Null < color && color < DF_ThemeColor_COUNT) UI_FocusHot(sv->cursor.y == row+2) + { + Vec4F32 rgba = df_rgba_from_theme_color(color); + Vec3F32 rgb = v3f32(rgba.x, rgba.y, rgba.z); + Vec3F32 hsv = hsv_from_rgb(rgb); + Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); + ui_set_next_pref_width(ui_pct(1, 0)); + ui_set_next_background_color(v4f32(0, 0, 0, 0)); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *color_row = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_Clickable, + "###color_%I64x", (U64)color); + UI_Parent(color_row) + { + Vec4F32 text_rgba = rgba; + text_rgba.w = ClampBot(text_rgba.w, 0.2f); + UI_WidthFill UI_TextColor(text_rgba) ui_label(df_g_theme_color_display_string_table[color]); + ui_set_next_pref_width(ui_top_pref_height()); + UI_HeightFill UI_Column UI_Padding(ui_em(0.3f, 1)) + { + ui_set_next_background_color(rgba); + ui_set_next_corner_radius_00(ui_top_font_size()/4.f); + ui_set_next_corner_radius_01(ui_top_font_size()/4.f); + ui_set_next_corner_radius_10(ui_top_font_size()/4.f); + ui_set_next_corner_radius_11(ui_top_font_size()/4.f); + UI_Box *color_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, "###color_box"); + UI_Signal color_sig = ui_signal_from_box(color_box); + if(color_sig.hovering) + { + ui_do_color_tooltip_hsva(hsva); + } + } + ui_spacer(ui_em(0.3f, 1)); + } + UI_Signal color_row_sig = ui_signal_from_box(color_row); + if(color_row_sig.clicked || color_row_sig.right_clicked) + { + ui_ctx_menu_open(color_ctx_menu_keys[color], color_row->key, v2f32(0, color_row->rect.y1-color_row->rect.y0)); + sv->color_ctx_menu_color = color; + sv->color_ctx_menu_color_hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); + DF_CmdParams p = df_cmd_params_from_panel(ws, panel); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); + } + } + } + } + + scratch_end(scratch); + ProfEnd(); +} diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h new file mode 100644 index 00000000..d0593172 --- /dev/null +++ b/src/df/gfx/df_views.h @@ -0,0 +1,464 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEBUG_FRONTEND_VIEWS_H +#define DEBUG_FRONTEND_VIEWS_H + +//////////////////////////////// +//~ rjf: FileSystem @view_types + +typedef enum DF_FileSortKind +{ + DF_FileSortKind_Null, + DF_FileSortKind_Filename, + DF_FileSortKind_LastModified, + DF_FileSortKind_Size, + DF_FileSortKind_COUNT +} +DF_FileSortKind; + +typedef struct DF_FileInfo DF_FileInfo; +struct DF_FileInfo +{ + String8 filename; + FileProperties props; + DF_FuzzyMatchRangeList match_ranges; +}; + +typedef struct DF_FileInfoNode DF_FileInfoNode; +struct DF_FileInfoNode +{ + DF_FileInfoNode *next; + DF_FileInfo file_info; +}; + +typedef struct DF_FileSystemViewPathState DF_FileSystemViewPathState; +struct DF_FileSystemViewPathState +{ + DF_FileSystemViewPathState *hash_next; + String8 normalized_path; + Vec2S64 cursor; +}; + +typedef struct DF_FileSystemViewState DF_FileSystemViewState; +struct DF_FileSystemViewState +{ + B32 initialized; + U64 path_state_table_size; + DF_FileSystemViewPathState **path_state_table; + DF_FileSortKind sort_kind; + Side sort_side; + Arena *cached_files_arena; + String8 cached_files_path; + DF_FileSortKind cached_files_sort_kind; + Side cached_files_sort_side; + U64 cached_file_count; + DF_FileInfo *cached_files; + F32 col_pcts[3]; +}; + +//////////////////////////////// +//~ rjf: Commands @view_types + +typedef struct DF_CmdListerItem DF_CmdListerItem; +struct DF_CmdListerItem +{ + DF_CmdSpec *cmd_spec; + U64 registrar_idx; + U64 ordering_idx; + DF_FuzzyMatchRangeList name_match_ranges; + DF_FuzzyMatchRangeList desc_match_ranges; + DF_FuzzyMatchRangeList tags_match_ranges; +}; + +typedef struct DF_CmdListerItemNode DF_CmdListerItemNode; +struct DF_CmdListerItemNode +{ + DF_CmdListerItemNode *next; + DF_CmdListerItem item; +}; + +typedef struct DF_CmdListerItemList DF_CmdListerItemList; +struct DF_CmdListerItemList +{ + DF_CmdListerItemNode *first; + DF_CmdListerItemNode *last; + U64 count; +}; + +typedef struct DF_CmdListerItemArray DF_CmdListerItemArray; +struct DF_CmdListerItemArray +{ + DF_CmdListerItem *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: PendingEntity @view_types + +typedef struct DF_PendingEntityViewState DF_PendingEntityViewState; +struct DF_PendingEntityViewState +{ + Arena *deferred_cmd_arena; + DF_CmdList deferred_cmds; + DF_Handle pick_file_override_target; + Arena *complete_cfg_arena; + DF_CfgNode *complete_cfg_root; +}; + +//////////////////////////////// +//~ rjf: EntityLister @view_types + +typedef struct DF_EntityListerItem DF_EntityListerItem; +struct DF_EntityListerItem +{ + DF_Entity *entity; + DF_FuzzyMatchRangeList name_match_ranges; +}; + +typedef struct DF_EntityListerItemNode DF_EntityListerItemNode; +struct DF_EntityListerItemNode +{ + DF_EntityListerItemNode *next; + DF_EntityListerItem item; +}; + +typedef struct DF_EntityListerItemList DF_EntityListerItemList; +struct DF_EntityListerItemList +{ + DF_EntityListerItemNode *first; + DF_EntityListerItemNode *last; + U64 count; +}; + +typedef struct DF_EntityListerItemArray DF_EntityListerItemArray; +struct DF_EntityListerItemArray +{ + DF_EntityListerItem *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: SystemProcesses @view_types + +typedef struct DF_ProcessInfo DF_ProcessInfo; +struct DF_ProcessInfo +{ + DEMON_ProcessInfo info; + B32 is_attached; + DF_FuzzyMatchRangeList attached_match_ranges; + DF_FuzzyMatchRangeList name_match_ranges; + DF_FuzzyMatchRangeList pid_match_ranges; +}; + +typedef struct DF_ProcessInfoNode DF_ProcessInfoNode; +struct DF_ProcessInfoNode +{ + DF_ProcessInfoNode *next; + DF_ProcessInfo info; +}; + +typedef struct DF_ProcessInfoList DF_ProcessInfoList; +struct DF_ProcessInfoList +{ + DF_ProcessInfoNode *first; + DF_ProcessInfoNode *last; + U64 count; +}; + +typedef struct DF_ProcessInfoArray DF_ProcessInfoArray; +struct DF_ProcessInfoArray +{ + DF_ProcessInfo *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Breakpoint @view_types + +typedef struct DF_BreakpointViewState DF_BreakpointViewState; +struct DF_BreakpointViewState +{ + B32 initialized; + Vec2S32 selected_p; + F32 key_pct; + F32 val_pct; +}; + +//////////////////////////////// +//~ rjf: Target @view_types + +typedef struct DF_TargetViewState DF_TargetViewState; +struct DF_TargetViewState +{ + B32 initialized; + + // rjf: pick file kind + DF_EntityKind pick_dst_kind; + + // rjf: selection cursor + Vec2S64 cursor; + + // rjf: text input state + TxtPt input_cursor; + TxtPt input_mark; + U8 input_buffer[1024]; + U64 input_size; + B32 input_editing; + + // rjf: table column pcts + F32 key_pct; + F32 value_pct; +}; + +//////////////////////////////// +//~ rjf: FilePathMap @view_types + +typedef struct DF_FilePathMapViewState DF_FilePathMapViewState; +struct DF_FilePathMapViewState +{ + B32 initialized; + Vec2S64 cursor; + TxtPt input_cursor; + TxtPt input_mark; + U8 input_buffer[1024]; + U64 input_size; + B32 input_editing; + DF_Handle pick_file_dst_map; + Side pick_file_dst_side; + F32 src_column_pct; + F32 dst_column_pct; +}; + +//////////////////////////////// +//~ rjf: Modules @view_types + +typedef struct DF_ModulesViewState DF_ModulesViewState; +struct DF_ModulesViewState +{ + B32 initialized; + DF_Handle selected_entity; + S64 selected_column; + B32 txt_editing; + TxtPt txt_cursor; + TxtPt txt_mark; + U8 txt_buffer[1024]; + U64 txt_size; + DF_Handle pick_file_dst_entity; + F32 idx_col_pct; + F32 desc_col_pct; + F32 range_col_pct; + F32 dbg_col_pct; +}; + +//////////////////////////////// +//~ rjf: Watch, Locals, Registers @view_types + +typedef struct DF_EvalRoot DF_EvalRoot; +struct DF_EvalRoot +{ + DF_EvalRoot *next; + DF_EvalRoot *prev; + U64 expr_buffer_string_size; + U64 expr_buffer_cap; + U8 *expr_buffer; +}; + +typedef enum DF_EvalWatchViewColumnKind +{ + DF_EvalWatchViewColumnKind_Expr, + DF_EvalWatchViewColumnKind_Value, + DF_EvalWatchViewColumnKind_Type, + DF_EvalWatchViewColumnKind_ViewRule, + DF_EvalWatchViewColumnKind_COUNT +} +DF_EvalWatchViewColumnKind; + +typedef struct DF_EvalWatchViewState DF_EvalWatchViewState; +struct DF_EvalWatchViewState +{ + B32 initialized; + + // rjf; selection state + DF_EvalWatchViewColumnKind selected_column; + DF_ExpandKey selected_parent_key; + DF_ExpandKey selected_key; + + // rjf: text input state + TxtPt input_cursor; + TxtPt input_mark; + U8 input_buffer[1024]; + U64 input_size; + B32 input_editing; + + // rjf: table column width state + F32 expr_column_pct; + F32 value_column_pct; + F32 type_column_pct; + F32 view_rule_column_pct; + + // rjf: top-level expression state + DF_EvalRoot *first_root; + DF_EvalRoot *last_root; + DF_EvalRoot *first_free_root; + U64 root_count; +}; + +typedef struct DF_EvalThreadDerivedReadOnlyWatchViewState DF_EvalThreadDerivedReadOnlyWatchViewState; +struct DF_EvalThreadDerivedReadOnlyWatchViewState +{ + Architecture cached_architecture; + DF_Handle cached_binary; + U64 cached_vaddr; + DF_EvalWatchViewState ewv; +}; + +typedef struct DF_RegistersViewArchState DF_RegistersViewArchState; +struct DF_RegistersViewArchState +{ + B32 initialized; + DF_EvalWatchViewState ewv; +}; + +typedef struct DF_RegistersViewState DF_RegistersViewState; +struct DF_RegistersViewState +{ + DF_RegistersViewArchState arch_state[Architecture_COUNT]; +}; + +//////////////////////////////// +//~ rjf: Code @view_types + +typedef struct DF_CodeViewState DF_CodeViewState; +struct DF_CodeViewState +{ + // rjf: stable state + B32 initialized; + TxtPt cursor; + TxtPt mark; + S64 preferred_column; + B32 drifted_for_search; + DF_Handle pick_file_override_target; + + // rjf: per-frame command info + S64 goto_line_num; + B32 center_cursor; + B32 contain_cursor; + Arena *find_text_arena; + String8 find_text_fwd; + String8 find_text_bwd; +}; + +//////////////////////////////// +//~ rjf: Disassembly @view_types + +typedef struct DF_DisasmViewState DF_DisasmViewState; +struct DF_DisasmViewState +{ + // rjf: stable state + B32 initialized; + DF_Handle process; + U64 base_vaddr; + TxtPt cursor; + TxtPt mark; + S64 preferred_column; + B32 drifted_for_search; + + // rjf: per-frame command info + S64 goto_line_num; + U64 goto_vaddr; + B32 center_cursor; + B32 contain_cursor; + Arena *find_text_arena; + String8 find_text_fwd; + String8 find_text_bwd; +}; + +//////////////////////////////// +//~ rjf: Memory @view_types + +typedef struct DF_MemoryViewState DF_MemoryViewState; +struct DF_MemoryViewState +{ + B32 initialized; + + // rjf: last-viewed-memory cache + Arena *last_viewed_memory_cache_arena; + U8 *last_viewed_memory_cache_buffer; + Rng1U64 last_viewed_memory_cache_range; + U64 last_viewed_memory_cache_run_idx; + + // rjf: control state + U64 cursor; + U64 mark; + + // rjf: organization state + U64 num_columns; + U64 bytes_per_cell; + + // rjf: command pass-through data + B32 center_cursor; + B32 contain_cursor; +}; + +//////////////////////////////// +//~ rjf: Quick Sort Comparisons + +internal int df_qsort_compare_file_info__default(DF_FileInfo *a, DF_FileInfo *b); +internal int df_qsort_compare_file_info__default_filtered(DF_FileInfo *a, DF_FileInfo *b); +internal int df_qsort_compare_file_info__filename(DF_FileInfo *a, DF_FileInfo *b); +internal int df_qsort_compare_file_info__last_modified(DF_FileInfo *a, DF_FileInfo *b); +internal int df_qsort_compare_file_info__size(DF_FileInfo *a, DF_FileInfo *b); +internal int df_qsort_compare_process_info(DF_ProcessInfo *a, DF_ProcessInfo *b); +internal int df_qsort_compare_cmd_lister__strength(DF_CmdListerItem *a, DF_CmdListerItem *b); +internal int df_qsort_compare_entity_lister__strength(DF_EntityListerItem *a, DF_EntityListerItem *b); + +//////////////////////////////// +//~ rjf: Command Lister + +internal DF_CmdListerItemList df_cmd_lister_item_list_from_needle(Arena *arena, String8 needle); +internal DF_CmdListerItemArray df_cmd_lister_item_array_from_list(Arena *arena, DF_CmdListerItemList list); +internal void df_cmd_lister_item_array_sort_by_strength__in_place(DF_CmdListerItemArray array); + +//////////////////////////////// +//~ rjf: System Process Lister + +internal DF_ProcessInfoList df_process_info_list_from_query(Arena *arena, String8 query); +internal DF_ProcessInfoArray df_process_info_array_from_list(Arena *arena, DF_ProcessInfoList list); +internal void df_process_info_array_sort_by_strength__in_place(DF_ProcessInfoArray array); + +//////////////////////////////// +//~ rjf: Entity Lister + +internal DF_EntityListerItemList df_entity_lister_item_list_from_needle(Arena *arena, DF_EntityKind kind, + DF_EntityFlags omit_flags, + String8 needle); +internal DF_EntityListerItemArray df_entity_lister_item_array_from_list(Arena *arena, DF_EntityListerItemList list); +internal void df_entity_lister_item_array_sort_by_strength__in_place(DF_EntityListerItemArray array); + +//////////////////////////////// +//~ rjf: Disassembly View + +internal TXTI_TokenArray df_txti_token_array_from_dasm_arch_string(Arena *arena, Architecture arch, String8 string); + +//////////////////////////////// +//~ rjf: Eval/Watch Views + +//- rjf: root allocation/deallocation/mutation +internal DF_EvalRoot * df_eval_root_alloc(DF_View *view, DF_EvalWatchViewState *ews); +internal void df_eval_root_release(DF_EvalWatchViewState *ews, DF_EvalRoot *root); +internal void df_eval_root_equip_string(DF_EvalRoot *root, String8 string); +internal DF_EvalRoot * df_eval_root_from_string(DF_EvalWatchViewState *ews, String8 string); +internal DF_EvalRoot * df_eval_root_from_expand_key(DF_EvalWatchViewState *ews, DF_ExpandKey expand_key); +internal String8 df_string_from_eval_root(DF_EvalRoot *root); +internal DF_ExpandKey df_expand_key_from_eval_root(DF_EvalRoot *root); + +//- rjf: windowed watch tree visualization +internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_EvalWatchViewState *ews); + +//- rjf: eval/watch views main hooks +internal void df_eval_watch_view_init(DF_EvalWatchViewState *ewv, DF_View *view); +internal void df_eval_watch_view_cmds(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWatchViewState *ewv, DF_CmdList *cmds); +internal void df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect); + +#endif // DEBUG_FRONTEND_VIEWS_H diff --git a/src/df/gfx/generated/df_gfx.meta.c b/src/df/gfx/generated/df_gfx.meta.c new file mode 100644 index 00000000..d43cb23e --- /dev/null +++ b/src/df/gfx/generated/df_gfx.meta.c @@ -0,0 +1,23 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +DF_GfxViewRuleSpecInfo df_g_gfx_view_rule_spec_info_table[] = +{ +{ str8_lit_comp("array"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, 0, 0, 0, }, +{ str8_lit_comp("list"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(list) , 0, 0, 0, }, +{ str8_lit_comp("dec"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(dec) , 0, 0, }, +{ str8_lit_comp("bin"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(bin) , 0, 0, }, +{ str8_lit_comp("oct"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(oct) , 0, 0, }, +{ str8_lit_comp("hex"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(hex) , 0, 0, }, +{ str8_lit_comp("only"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(only) , DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(only) , 0, 0, }, +{ str8_lit_comp("omit"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(omit) , DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(omit) , 0, 0, }, +{ str8_lit_comp("no_addr"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(no_addr) , 0, 0, }, +{ str8_lit_comp("rgba"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(rgba) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(rgba) , }, +{ str8_lit_comp("text"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, 0, DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(text) , }, +{ str8_lit_comp("disasm"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, 0, DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(disasm) , }, +{ str8_lit_comp("bitmap"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(bitmap) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(bitmap) , }, +{ str8_lit_comp("geo"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(geo) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(geo) , }, +}; + diff --git a/src/df/gfx/generated/df_gfx.meta.h b/src/df/gfx/generated/df_gfx.meta.h new file mode 100644 index 00000000..b66fe31e --- /dev/null +++ b/src/df/gfx/generated/df_gfx.meta.h @@ -0,0 +1,5707 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef DF_GFX_META_H +#define DF_GFX_META_H + +typedef enum DF_GfxViewKind +{ +DF_GfxViewKind_Null, +DF_GfxViewKind_Empty, +DF_GfxViewKind_Commands, +DF_GfxViewKind_FileSystem, +DF_GfxViewKind_SystemProcesses, +DF_GfxViewKind_EntityLister, +DF_GfxViewKind_Target, +DF_GfxViewKind_Targets, +DF_GfxViewKind_FilePathMap, +DF_GfxViewKind_Scheduler, +DF_GfxViewKind_CallStack, +DF_GfxViewKind_Modules, +DF_GfxViewKind_PendingEntity, +DF_GfxViewKind_Code, +DF_GfxViewKind_Disassembly, +DF_GfxViewKind_Watch, +DF_GfxViewKind_Locals, +DF_GfxViewKind_Registers, +DF_GfxViewKind_Output, +DF_GfxViewKind_Memory, +DF_GfxViewKind_Breakpoints, +DF_GfxViewKind_WatchPins, +DF_GfxViewKind_ExceptionFilters, +DF_GfxViewKind_Theme, +DF_GfxViewKind_COUNT +} DF_GfxViewKind; + +typedef enum DF_ThemeColor +{ +DF_ThemeColor_Null, +DF_ThemeColor_PlainText, +DF_ThemeColor_PlainBackground, +DF_ThemeColor_PlainBorder, +DF_ThemeColor_PlainOverlay, +DF_ThemeColor_CodeDefault, +DF_ThemeColor_CodeFunction, +DF_ThemeColor_CodeType, +DF_ThemeColor_CodeLocal, +DF_ThemeColor_CodeKeyword, +DF_ThemeColor_CodeSymbol, +DF_ThemeColor_CodeNumeric, +DF_ThemeColor_CodeString, +DF_ThemeColor_CodeMeta, +DF_ThemeColor_CodeComment, +DF_ThemeColor_LineInfo0, +DF_ThemeColor_LineInfo1, +DF_ThemeColor_LineInfo2, +DF_ThemeColor_LineInfo3, +DF_ThemeColor_AltText, +DF_ThemeColor_AltBackground, +DF_ThemeColor_AltBorder, +DF_ThemeColor_AltOverlay, +DF_ThemeColor_TabInactive, +DF_ThemeColor_TabActive, +DF_ThemeColor_EntityBackground, +DF_ThemeColor_QueryBar, +DF_ThemeColor_WeakText, +DF_ThemeColor_TextSelection, +DF_ThemeColor_Cursor, +DF_ThemeColor_Highlight0, +DF_ThemeColor_Highlight1, +DF_ThemeColor_SuccessText, +DF_ThemeColor_SuccessBackground, +DF_ThemeColor_SuccessBorder, +DF_ThemeColor_FailureText, +DF_ThemeColor_FailureBackground, +DF_ThemeColor_FailureBorder, +DF_ThemeColor_ActionText, +DF_ThemeColor_ActionBackground, +DF_ThemeColor_ActionBorder, +DF_ThemeColor_DropSiteOverlay, +DF_ThemeColor_Thread0, +DF_ThemeColor_Thread1, +DF_ThemeColor_Thread2, +DF_ThemeColor_Thread3, +DF_ThemeColor_Thread4, +DF_ThemeColor_Thread5, +DF_ThemeColor_Thread6, +DF_ThemeColor_Thread7, +DF_ThemeColor_ThreadUnwound, +DF_ThemeColor_InactivePanelOverlay, +DF_ThemeColor_DropShadow, +DF_ThemeColor_COUNT +} DF_ThemeColor; + +typedef enum DF_ThemePreset +{ +DF_ThemePreset_DefaultDark, +DF_ThemePreset_DefaultLight, +DF_ThemePreset_VSDark, +DF_ThemePreset_VSLight, +DF_ThemePreset_SolarizedDark, +DF_ThemePreset_SolarizedLight, +DF_ThemePreset_HandmadeHero, +DF_ThemePreset_FourCoder, +DF_ThemePreset_FarManager, +DF_ThemePreset_COUNT +} DF_ThemePreset; + +DF_VIEW_SETUP_FUNCTION_DEF(Null); +DF_VIEW_SETUP_FUNCTION_DEF(Empty); +DF_VIEW_SETUP_FUNCTION_DEF(Commands); +DF_VIEW_SETUP_FUNCTION_DEF(FileSystem); +DF_VIEW_SETUP_FUNCTION_DEF(SystemProcesses); +DF_VIEW_SETUP_FUNCTION_DEF(EntityLister); +DF_VIEW_SETUP_FUNCTION_DEF(Target); +DF_VIEW_SETUP_FUNCTION_DEF(Targets); +DF_VIEW_SETUP_FUNCTION_DEF(FilePathMap); +DF_VIEW_SETUP_FUNCTION_DEF(Scheduler); +DF_VIEW_SETUP_FUNCTION_DEF(CallStack); +DF_VIEW_SETUP_FUNCTION_DEF(Modules); +DF_VIEW_SETUP_FUNCTION_DEF(PendingEntity); +DF_VIEW_SETUP_FUNCTION_DEF(Code); +DF_VIEW_SETUP_FUNCTION_DEF(Disassembly); +DF_VIEW_SETUP_FUNCTION_DEF(Watch); +DF_VIEW_SETUP_FUNCTION_DEF(Locals); +DF_VIEW_SETUP_FUNCTION_DEF(Registers); +DF_VIEW_SETUP_FUNCTION_DEF(Output); +DF_VIEW_SETUP_FUNCTION_DEF(Memory); +DF_VIEW_SETUP_FUNCTION_DEF(Breakpoints); +DF_VIEW_SETUP_FUNCTION_DEF(WatchPins); +DF_VIEW_SETUP_FUNCTION_DEF(ExceptionFilters); +DF_VIEW_SETUP_FUNCTION_DEF(Theme); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Null); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Empty); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Commands); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(FileSystem); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(SystemProcesses); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(EntityLister); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Target); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Targets); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(FilePathMap); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Scheduler); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(CallStack); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Modules); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(PendingEntity); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Code); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Disassembly); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Watch); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Locals); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Registers); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Output); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Memory); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Breakpoints); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(WatchPins); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(ExceptionFilters); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Theme); +DF_VIEW_CMD_FUNCTION_DEF(Null); +DF_VIEW_CMD_FUNCTION_DEF(Empty); +DF_VIEW_CMD_FUNCTION_DEF(Commands); +DF_VIEW_CMD_FUNCTION_DEF(FileSystem); +DF_VIEW_CMD_FUNCTION_DEF(SystemProcesses); +DF_VIEW_CMD_FUNCTION_DEF(EntityLister); +DF_VIEW_CMD_FUNCTION_DEF(Target); +DF_VIEW_CMD_FUNCTION_DEF(Targets); +DF_VIEW_CMD_FUNCTION_DEF(FilePathMap); +DF_VIEW_CMD_FUNCTION_DEF(Scheduler); +DF_VIEW_CMD_FUNCTION_DEF(CallStack); +DF_VIEW_CMD_FUNCTION_DEF(Modules); +DF_VIEW_CMD_FUNCTION_DEF(PendingEntity); +DF_VIEW_CMD_FUNCTION_DEF(Code); +DF_VIEW_CMD_FUNCTION_DEF(Disassembly); +DF_VIEW_CMD_FUNCTION_DEF(Watch); +DF_VIEW_CMD_FUNCTION_DEF(Locals); +DF_VIEW_CMD_FUNCTION_DEF(Registers); +DF_VIEW_CMD_FUNCTION_DEF(Output); +DF_VIEW_CMD_FUNCTION_DEF(Memory); +DF_VIEW_CMD_FUNCTION_DEF(Breakpoints); +DF_VIEW_CMD_FUNCTION_DEF(WatchPins); +DF_VIEW_CMD_FUNCTION_DEF(ExceptionFilters); +DF_VIEW_CMD_FUNCTION_DEF(Theme); +DF_VIEW_UI_FUNCTION_DEF(Null); +DF_VIEW_UI_FUNCTION_DEF(Empty); +DF_VIEW_UI_FUNCTION_DEF(Commands); +DF_VIEW_UI_FUNCTION_DEF(FileSystem); +DF_VIEW_UI_FUNCTION_DEF(SystemProcesses); +DF_VIEW_UI_FUNCTION_DEF(EntityLister); +DF_VIEW_UI_FUNCTION_DEF(Target); +DF_VIEW_UI_FUNCTION_DEF(Targets); +DF_VIEW_UI_FUNCTION_DEF(FilePathMap); +DF_VIEW_UI_FUNCTION_DEF(Scheduler); +DF_VIEW_UI_FUNCTION_DEF(CallStack); +DF_VIEW_UI_FUNCTION_DEF(Modules); +DF_VIEW_UI_FUNCTION_DEF(PendingEntity); +DF_VIEW_UI_FUNCTION_DEF(Code); +DF_VIEW_UI_FUNCTION_DEF(Disassembly); +DF_VIEW_UI_FUNCTION_DEF(Watch); +DF_VIEW_UI_FUNCTION_DEF(Locals); +DF_VIEW_UI_FUNCTION_DEF(Registers); +DF_VIEW_UI_FUNCTION_DEF(Output); +DF_VIEW_UI_FUNCTION_DEF(Memory); +DF_VIEW_UI_FUNCTION_DEF(Breakpoints); +DF_VIEW_UI_FUNCTION_DEF(WatchPins); +DF_VIEW_UI_FUNCTION_DEF(ExceptionFilters); +DF_VIEW_UI_FUNCTION_DEF(Theme); + +DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(list); +DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(only); +DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(omit); +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(dec); +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(bin); +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(oct); +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(hex); +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(only); +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(omit); +DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(no_addr); +DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(rgba); +DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(bitmap); +DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(geo); +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba); +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text); +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm); +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap); +DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo); +String8 df_g_theme_preset_display_string_table[] = +{ +str8_lit_comp("Default (Dark)"), +str8_lit_comp("Default (Light)"), +str8_lit_comp("VS (Dark)"), +str8_lit_comp("VS (Light)"), +str8_lit_comp("Solarized (Dark)"), +str8_lit_comp("Solarized (Light)"), +str8_lit_comp("Handmade Hero"), +str8_lit_comp("4coder"), +str8_lit_comp("Far Manager"), +}; + +Vec4F32 df_g_theme_preset_colors__default_dark[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x3333337f), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x7fcc99ff), +rgba_from_u32_lit_comp(0x66b2e5ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xf7bf5eff), +rgba_from_u32_lit_comp(0x994c32ff), +rgba_from_u32_lit_comp(0x4ce54cff), +rgba_from_u32_lit_comp(0xe5cc66ff), +rgba_from_u32_lit_comp(0xe54c4cff), +rgba_from_u32_lit_comp(0x7f7f7fff), +rgba_from_u32_lit_comp(0x3f72993f), +rgba_from_u32_lit_comp(0x3f72994c), +rgba_from_u32_lit_comp(0x3f729972), +rgba_from_u32_lit_comp(0x3f72997f), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xffcb7fff), +rgba_from_u32_lit_comp(0xb2ff65ff), +rgba_from_u32_lit_comp(0xff99e5ff), +rgba_from_u32_lit_comp(0x6598ffff), +rgba_from_u32_lit_comp(0x65ffcbff), +rgba_from_u32_lit_comp(0xff9819ff), +rgba_from_u32_lit_comp(0x9932ffff), +rgba_from_u32_lit_comp(0x65ff4cff), +rgba_from_u32_lit_comp(0xb2ccd8ff), +rgba_from_u32_lit_comp(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__default_light[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x383838ff), +rgba_from_u32_lit_comp(0xedededfe), +rgba_from_u32_lit_comp(0x0000001d), +rgba_from_u32_lit_comp(0x00000033), +rgba_from_u32_lit_comp(0x282828ff), +rgba_from_u32_lit_comp(0x2a7a45ff), +rgba_from_u32_lit_comp(0x2c688fff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xa47729ff), +rgba_from_u32_lit_comp(0x6c2d18ff), +rgba_from_u32_lit_comp(0x2c7d2cff), +rgba_from_u32_lit_comp(0xcc5a0fff), +rgba_from_u32_lit_comp(0x8a0c0cff), +rgba_from_u32_lit_comp(0x7f7f7fff), +rgba_from_u32_lit_comp(0x3e71993f), +rgba_from_u32_lit_comp(0x3f72994c), +rgba_from_u32_lit_comp(0x3f729972), +rgba_from_u32_lit_comp(0x3f72997f), +rgba_from_u32_lit_comp(0x535353ff), +rgba_from_u32_lit_comp(0xfefefebc), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xc7a27dff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0xd76489cc), +rgba_from_u32_lit_comp(0x0000007f), +rgba_from_u32_lit_comp(0x7d98b34c), +rgba_from_u32_lit_comp(0x101010ff), +rgba_from_u32_lit_comp(0xb272189b), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x75db61ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xf27961ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xad7c34ff), +rgba_from_u32_lit_comp(0x639b2aff), +rgba_from_u32_lit_comp(0xa94c91ff), +rgba_from_u32_lit_comp(0x305398ff), +rgba_from_u32_lit_comp(0x339574ff), +rgba_from_u32_lit_comp(0xbf7416ff), +rgba_from_u32_lit_comp(0x57238bff), +rgba_from_u32_lit_comp(0x2a7e1cff), +rgba_from_u32_lit_comp(0x236481ff), +rgba_from_u32_lit_comp(0x0000000d), +rgba_from_u32_lit_comp(0x0000003b), +}; + +Vec4F32 df_g_theme_preset_colors__vs_dark[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x1e1e1eff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xd4d4d4ff), +rgba_from_u32_lit_comp(0xdcdcaaff), +rgba_from_u32_lit_comp(0x4ec9b0ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0x569cd6ff), +rgba_from_u32_lit_comp(0xb4b4b4ff), +rgba_from_u32_lit_comp(0xb5cea8ff), +rgba_from_u32_lit_comp(0xd69d85ff), +rgba_from_u32_lit_comp(0x9b9b9bff), +rgba_from_u32_lit_comp(0x6a9955ff), +rgba_from_u32_lit_comp(0xbeb7ff3f), +rgba_from_u32_lit_comp(0xbeb7ff4c), +rgba_from_u32_lit_comp(0xbeb7ff72), +rgba_from_u32_lit_comp(0xbeb7ff7f), +rgba_from_u32_lit_comp(0xf1f1f1ff), +rgba_from_u32_lit_comp(0x1b1b1cff), +rgba_from_u32_lit_comp(0x333337ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0x007accff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xffcb7fff), +rgba_from_u32_lit_comp(0xb2ff65ff), +rgba_from_u32_lit_comp(0xff99e5ff), +rgba_from_u32_lit_comp(0x6598ffff), +rgba_from_u32_lit_comp(0x65ffcbff), +rgba_from_u32_lit_comp(0xff9819ff), +rgba_from_u32_lit_comp(0x9932ffff), +rgba_from_u32_lit_comp(0x65ff4cff), +rgba_from_u32_lit_comp(0xb2ccd8ff), +rgba_from_u32_lit_comp(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__vs_light[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x1e1e1eff), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0xcccedb1d), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x000000ff), +rgba_from_u32_lit_comp(0x74531fff), +rgba_from_u32_lit_comp(0x2b91afff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0x0000ffff), +rgba_from_u32_lit_comp(0x000000ff), +rgba_from_u32_lit_comp(0x000000ff), +rgba_from_u32_lit_comp(0xc11515ff), +rgba_from_u32_lit_comp(0x808080ff), +rgba_from_u32_lit_comp(0x008000ff), +rgba_from_u32_lit_comp(0x3f72993f), +rgba_from_u32_lit_comp(0x3f72994c), +rgba_from_u32_lit_comp(0x3f729972), +rgba_from_u32_lit_comp(0x3f72997f), +rgba_from_u32_lit_comp(0x535353ff), +rgba_from_u32_lit_comp(0xfefefebc), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0x007accff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0x0000007f), +rgba_from_u32_lit_comp(0x7d98b34c), +rgba_from_u32_lit_comp(0x101010ff), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xad7c34ff), +rgba_from_u32_lit_comp(0x639b2aff), +rgba_from_u32_lit_comp(0xa94c91ff), +rgba_from_u32_lit_comp(0x305398ff), +rgba_from_u32_lit_comp(0x339574ff), +rgba_from_u32_lit_comp(0xbf7416ff), +rgba_from_u32_lit_comp(0x57238bff), +rgba_from_u32_lit_comp(0x2a7e1cff), +rgba_from_u32_lit_comp(0x236481ff), +rgba_from_u32_lit_comp(0x0000000d), +rgba_from_u32_lit_comp(0x0000003b), +}; + +Vec4F32 df_g_theme_preset_colors__solarized_dark[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x002b36ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x839496ff), +rgba_from_u32_lit_comp(0x1c7dd1ff), +rgba_from_u32_lit_comp(0x1c7dd1ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0x63980fff), +rgba_from_u32_lit_comp(0x839496ff), +rgba_from_u32_lit_comp(0xcb4b20ff), +rgba_from_u32_lit_comp(0x2aa198ff), +rgba_from_u32_lit_comp(0xe54c4cff), +rgba_from_u32_lit_comp(0x7f7f7fff), +rgba_from_u32_lit_comp(0x3f72993f), +rgba_from_u32_lit_comp(0x3f72994c), +rgba_from_u32_lit_comp(0x3f729972), +rgba_from_u32_lit_comp(0x3f72997f), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x002b36ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0x28515eff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xffcb7fff), +rgba_from_u32_lit_comp(0xb2ff65ff), +rgba_from_u32_lit_comp(0xff99e5ff), +rgba_from_u32_lit_comp(0x6598ffff), +rgba_from_u32_lit_comp(0x65ffcbff), +rgba_from_u32_lit_comp(0xff9819ff), +rgba_from_u32_lit_comp(0x9932ffff), +rgba_from_u32_lit_comp(0x65ff4cff), +rgba_from_u32_lit_comp(0xb2ccd8ff), +rgba_from_u32_lit_comp(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__solarized_light[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x1e1e1eff), +rgba_from_u32_lit_comp(0xfcf6e2ff), +rgba_from_u32_lit_comp(0xcccedb1d), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x74878cff), +rgba_from_u32_lit_comp(0xc39d36ff), +rgba_from_u32_lit_comp(0x66b2e5ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xc39d36ff), +rgba_from_u32_lit_comp(0x2e5256ff), +rgba_from_u32_lit_comp(0x657b83ff), +rgba_from_u32_lit_comp(0x5ab4a9ff), +rgba_from_u32_lit_comp(0xe54c4cff), +rgba_from_u32_lit_comp(0xadafb2ff), +rgba_from_u32_lit_comp(0x3f72993f), +rgba_from_u32_lit_comp(0x3f72994c), +rgba_from_u32_lit_comp(0x3f729972), +rgba_from_u32_lit_comp(0x3f72997f), +rgba_from_u32_lit_comp(0x535353ff), +rgba_from_u32_lit_comp(0xfcf6e2ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0x0000007f), +rgba_from_u32_lit_comp(0x7d98b34c), +rgba_from_u32_lit_comp(0x101010ff), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xad7c34ff), +rgba_from_u32_lit_comp(0x639b2aff), +rgba_from_u32_lit_comp(0xa94c91ff), +rgba_from_u32_lit_comp(0x305398ff), +rgba_from_u32_lit_comp(0x339574ff), +rgba_from_u32_lit_comp(0xbf7416ff), +rgba_from_u32_lit_comp(0x57238bff), +rgba_from_u32_lit_comp(0x2a7e1cff), +rgba_from_u32_lit_comp(0x236481ff), +rgba_from_u32_lit_comp(0x0000000d), +rgba_from_u32_lit_comp(0x0000003b), +}; + +Vec4F32 df_g_theme_preset_colors__handmade_hero[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xa08563ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xa08563ff), +rgba_from_u32_lit_comp(0xcc5735ff), +rgba_from_u32_lit_comp(0xd8a51dff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xac7b0bff), +rgba_from_u32_lit_comp(0x994c32ff), +rgba_from_u32_lit_comp(0x6b8e23ff), +rgba_from_u32_lit_comp(0x6b8e23ff), +rgba_from_u32_lit_comp(0xdab98fff), +rgba_from_u32_lit_comp(0x686868ff), +rgba_from_u32_lit_comp(0xaf60103f), +rgba_from_u32_lit_comp(0xaf60104c), +rgba_from_u32_lit_comp(0xaf601072), +rgba_from_u32_lit_comp(0xaf60107f), +rgba_from_u32_lit_comp(0xa08563ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xa08563af), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xffcb7fff), +rgba_from_u32_lit_comp(0xb2ff65ff), +rgba_from_u32_lit_comp(0xff99e5ff), +rgba_from_u32_lit_comp(0x6598ffff), +rgba_from_u32_lit_comp(0x65ffcbff), +rgba_from_u32_lit_comp(0xff9819ff), +rgba_from_u32_lit_comp(0x9932ffff), +rgba_from_u32_lit_comp(0x65ff4cff), +rgba_from_u32_lit_comp(0xb2ccd8ff), +rgba_from_u32_lit_comp(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__four_coder[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x90b080ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0x181818a0), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x90b080ff), +rgba_from_u32_lit_comp(0x7fcc99ff), +rgba_from_u32_lit_comp(0x66b2e5ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd08f20ff), +rgba_from_u32_lit_comp(0x994c32ff), +rgba_from_u32_lit_comp(0x50ff30ff), +rgba_from_u32_lit_comp(0x50ff30ff), +rgba_from_u32_lit_comp(0x50ff30ff), +rgba_from_u32_lit_comp(0x2090f0ff), +rgba_from_u32_lit_comp(0x3f72993f), +rgba_from_u32_lit_comp(0x3f72994c), +rgba_from_u32_lit_comp(0x3f729972), +rgba_from_u32_lit_comp(0x3f72997f), +rgba_from_u32_lit_comp(0x90b080ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0x90b080af), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xffcb7fff), +rgba_from_u32_lit_comp(0xb2ff65ff), +rgba_from_u32_lit_comp(0xff99e5ff), +rgba_from_u32_lit_comp(0x6598ffff), +rgba_from_u32_lit_comp(0x65ffcbff), +rgba_from_u32_lit_comp(0xff9819ff), +rgba_from_u32_lit_comp(0x9932ffff), +rgba_from_u32_lit_comp(0x65ff4cff), +rgba_from_u32_lit_comp(0xb2ccd8ff), +rgba_from_u32_lit_comp(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__far_manager[] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x00ffffff), +rgba_from_u32_lit_comp(0x000082ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x00ffffff), +rgba_from_u32_lit_comp(0x49b2ffff), +rgba_from_u32_lit_comp(0x49b2ffff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xff0000ff), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x2cff50ff), +rgba_from_u32_lit_comp(0xe5cc66ff), +rgba_from_u32_lit_comp(0xffff00ff), +rgba_from_u32_lit_comp(0x7f7f7fff), +rgba_from_u32_lit_comp(0x3f72993f), +rgba_from_u32_lit_comp(0x3f72994c), +rgba_from_u32_lit_comp(0x3f729972), +rgba_from_u32_lit_comp(0x3f72997f), +rgba_from_u32_lit_comp(0x000000ff), +rgba_from_u32_lit_comp(0x008184ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xffcb7fff), +rgba_from_u32_lit_comp(0xb2ff65ff), +rgba_from_u32_lit_comp(0xff99e5ff), +rgba_from_u32_lit_comp(0x6598ffff), +rgba_from_u32_lit_comp(0x65ffcbff), +rgba_from_u32_lit_comp(0xff9819ff), +rgba_from_u32_lit_comp(0x9932ffff), +rgba_from_u32_lit_comp(0x65ff4cff), +rgba_from_u32_lit_comp(0xb2ccd8ff), +rgba_from_u32_lit_comp(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 * df_g_theme_preset_colors_table[] = +{ +df_g_theme_preset_colors__default_dark, +df_g_theme_preset_colors__default_light, +df_g_theme_preset_colors__vs_dark, +df_g_theme_preset_colors__vs_light, +df_g_theme_preset_colors__solarized_dark, +df_g_theme_preset_colors__solarized_light, +df_g_theme_preset_colors__handmade_hero, +df_g_theme_preset_colors__four_coder, +df_g_theme_preset_colors__far_manager, +}; + +String8 df_g_cmd2view_table_src[] = +{ +str8_lit_comp("launch_and_run"), +str8_lit_comp("launch_and_init"), +str8_lit_comp("kill"), +str8_lit_comp("detach"), +str8_lit_comp("select_thread"), +str8_lit_comp("select_thread_window"), +str8_lit_comp("select_thread_view"), +str8_lit_comp("freeze_thread"), +str8_lit_comp("thaw_thread"), +str8_lit_comp("freeze_process"), +str8_lit_comp("thaw_process"), +str8_lit_comp("freeze_machine"), +str8_lit_comp("thaw_machine"), +str8_lit_comp("set_current_path"), +str8_lit_comp("open"), +str8_lit_comp("reload"), +str8_lit_comp("switch"), +str8_lit_comp("load_user"), +str8_lit_comp("load_profile"), +str8_lit_comp("find_thread"), +str8_lit_comp("open_thread_disasm"), +str8_lit_comp("open_file_memory"), +str8_lit_comp("open_process_memory"), +str8_lit_comp("remove_breakpoint"), +str8_lit_comp("edit_breakpoint"), +str8_lit_comp("enable_breakpoint"), +str8_lit_comp("disable_breakpoint"), +str8_lit_comp("edit_breakpoint"), +str8_lit_comp("add_target"), +str8_lit_comp("remove_target"), +str8_lit_comp("edit_target"), +str8_lit_comp("retry_ended_process"), +str8_lit_comp("attach"), +str8_lit_comp("commands"), +str8_lit_comp("target_editor"), +str8_lit_comp("targets"), +str8_lit_comp("file_path_map"), +str8_lit_comp("scheduler"), +str8_lit_comp("call_stack"), +str8_lit_comp("modules"), +str8_lit_comp("pending_entity"), +str8_lit_comp("code"), +str8_lit_comp("watch"), +str8_lit_comp("locals"), +str8_lit_comp("registers"), +str8_lit_comp("output"), +str8_lit_comp("memory"), +str8_lit_comp("disassembly"), +str8_lit_comp("breakpoints"), +str8_lit_comp("watch_pins"), +str8_lit_comp("exception_filters"), +str8_lit_comp("theme"), +str8_lit_comp("pick_file"), +str8_lit_comp("clear_diag_log"), +str8_lit_comp("open_diag_log"), +}; + +String8 df_g_cmd2view_table_dst[] = +{ +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("file_system"), +str8_lit_comp("file_system"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("file_system"), +str8_lit_comp("file_system"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("file_system"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("system_processes"), +str8_lit_comp("commands"), +str8_lit_comp("target"), +str8_lit_comp("targets"), +str8_lit_comp("file_path_map"), +str8_lit_comp("scheduler"), +str8_lit_comp("call_stack"), +str8_lit_comp("modules"), +str8_lit_comp("pending_entity"), +str8_lit_comp("code"), +str8_lit_comp("watch"), +str8_lit_comp("locals"), +str8_lit_comp("registers"), +str8_lit_comp("output"), +str8_lit_comp("memory"), +str8_lit_comp("disassembly"), +str8_lit_comp("breakpoints"), +str8_lit_comp("watch_pins"), +str8_lit_comp("exception_filters"), +str8_lit_comp("theme"), +str8_lit_comp("file_system"), +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +}; + +DF_StringBindingPair df_g_default_binding_table[] = +{ +{str8_lit_comp("kill_all"), {OS_Key_F5, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("step_into_inst"), {OS_Key_F11, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("step_over_inst"), {OS_Key_F10, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("step_out"), {OS_Key_F11, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("halt"), {OS_Key_X, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("halt"), {OS_Key_Pause, 0 }}, +{str8_lit_comp("soft_halt_refresh"), {OS_Key_R, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("run"), {OS_Key_F5, 0 }}, +{str8_lit_comp("restart"), {OS_Key_F5, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("step_into"), {OS_Key_F11, 0 }}, +{str8_lit_comp("step_over"), {OS_Key_F10, 0 }}, +{str8_lit_comp("run_to_cursor"), {OS_Key_F10, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("set_next_statement"), {OS_Key_F10, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("inc_ui_font_scale"), {OS_Key_Equal, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("dec_ui_font_scale"), {OS_Key_Minus, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("inc_code_font_scale"), {OS_Key_Equal, 0 |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("dec_code_font_scale"), {OS_Key_Minus, 0 |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("window"), {OS_Key_N, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("toggle_fullscreen"), {OS_Key_Return, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("new_panel_right"), {OS_Key_P, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("new_panel_down"), {OS_Key_Minus, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("rotate_panel_columns"), {OS_Key_2, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("next_panel"), {OS_Key_Comma, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("prev_panel"), {OS_Key_Comma, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("focus_panel_right"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("focus_panel_left"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("focus_panel_up"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("focus_panel_down"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("close_panel"), {OS_Key_P, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("next_tab"), {OS_Key_PageDown, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("prev_tab"), {OS_Key_PageUp, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("next_tab"), {OS_Key_Tab, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("prev_tab"), {OS_Key_Tab, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_tab_right"), {OS_Key_PageDown, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_tab_left"), {OS_Key_PageUp, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("close_tab"), {OS_Key_W, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("tab_bar_top"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("tab_bar_bottom"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("open"), {OS_Key_O, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("reload_active"), {OS_Key_R, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("switch"), {OS_Key_I, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("load_user"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("load_profile"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("move_left"), {OS_Key_Left, 0 }}, +{str8_lit_comp("move_right"), {OS_Key_Right, 0 }}, +{str8_lit_comp("move_up"), {OS_Key_Up, 0 }}, +{str8_lit_comp("move_down"), {OS_Key_Down, 0 }}, +{str8_lit_comp("move_left_select"), {OS_Key_Left, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_right_select"), {OS_Key_Right, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_select"), {OS_Key_Up, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_select"), {OS_Key_Down, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_left_chunk"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_right_chunk"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_up_chunk"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_down_chunk"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_up_page"), {OS_Key_PageUp, 0 }}, +{str8_lit_comp("move_down_page"), {OS_Key_PageDown, 0 }}, +{str8_lit_comp("move_up_whole"), {OS_Key_Home, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_down_whole"), {OS_Key_End, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_left_chunk_select"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_right_chunk_select"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_chunk_select"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_chunk_select"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_page_select"), {OS_Key_PageUp, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_page_select"), {OS_Key_PageDown, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_whole_select"), {OS_Key_Home, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_whole_select"), {OS_Key_End, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_home"), {OS_Key_Home, 0 }}, +{str8_lit_comp("move_end"), {OS_Key_End, 0 }}, +{str8_lit_comp("move_home_select"), {OS_Key_Home, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_end_select"), {OS_Key_End, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("select_all"), {OS_Key_A, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("delete_single"), {OS_Key_Delete, 0 }}, +{str8_lit_comp("delete_chunk"), {OS_Key_Delete, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("backspace_single"), {OS_Key_Backspace, 0 }}, +{str8_lit_comp("backspace_chunk"), {OS_Key_Backspace, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("copy"), {OS_Key_C, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("cut"), {OS_Key_X, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("paste"), {OS_Key_V, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("insert_text"), {OS_Key_Null, 0 }}, +{str8_lit_comp("goto_line"), {OS_Key_G, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("goto_address"), {OS_Key_G, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("find_text_forward"), {OS_Key_F, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("find_text_backward"), {OS_Key_R, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("find_next"), {OS_Key_F3, 0 }}, +{str8_lit_comp("find_prev"), {OS_Key_F3, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("find_selected_thread"), {OS_Key_F4, 0 }}, +{str8_lit_comp("goto_name"), {OS_Key_J, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("goto_name_at_cursor"), {OS_Key_F12, 0 }}, +{str8_lit_comp("toggle_watch_expr_at_cursor"), {OS_Key_W, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("toggle_watch_pin_at_cursor"), {OS_Key_F9, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("toggle_breakpoint_cursor"), {OS_Key_F9, 0 }}, +{str8_lit_comp("add_target"), {OS_Key_T, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("attach"), {OS_Key_F6, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("commands"), {OS_Key_F1, 0 }}, +{str8_lit_comp("scheduler"), {OS_Key_S, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("clear_diag_log"), {OS_Key_D, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("open_diag_log"), {OS_Key_D, 0 |OS_EventFlag_Ctrl }}, +}; + +DF_ViewSpecInfo df_g_gfx_view_kind_spec_info_table[] = +{ +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("null"), str8_lit_comp(""), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Null), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Null), DF_VIEW_CMD_FUNCTION_NAME(Null), DF_VIEW_UI_FUNCTION_NAME(Null)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("empty"), str8_lit_comp(""), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Empty), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Empty), DF_VIEW_CMD_FUNCTION_NAME(Empty), DF_VIEW_UI_FUNCTION_NAME(Empty)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("commands"), str8_lit_comp("Commands"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Commands), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Commands), DF_VIEW_CMD_FUNCTION_NAME(Commands), DF_VIEW_UI_FUNCTION_NAME(Commands)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("file_system"), str8_lit_comp("File System"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(FileSystem), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(FileSystem), DF_VIEW_CMD_FUNCTION_NAME(FileSystem), DF_VIEW_UI_FUNCTION_NAME(FileSystem)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("system_processes"), str8_lit_comp("System Processes"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(SystemProcesses), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(SystemProcesses), DF_VIEW_CMD_FUNCTION_NAME(SystemProcesses), DF_VIEW_UI_FUNCTION_NAME(SystemProcesses)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("entity_lister"), str8_lit_comp("Entity List"), DF_NameKind_EntityKindName, DF_VIEW_SETUP_FUNCTION_NAME(EntityLister), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(EntityLister), DF_VIEW_CMD_FUNCTION_NAME(EntityLister), DF_VIEW_UI_FUNCTION_NAME(EntityLister)}, +{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("target"), str8_lit_comp("Target"), DF_NameKind_EntityName, DF_VIEW_SETUP_FUNCTION_NAME(Target), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Target), DF_VIEW_CMD_FUNCTION_NAME(Target), DF_VIEW_UI_FUNCTION_NAME(Target)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("targets"), str8_lit_comp("Targets"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Targets), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Targets), DF_VIEW_CMD_FUNCTION_NAME(Targets), DF_VIEW_UI_FUNCTION_NAME(Targets)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("file_path_map"), str8_lit_comp("File Path Map"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(FilePathMap), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(FilePathMap), DF_VIEW_CMD_FUNCTION_NAME(FilePathMap), DF_VIEW_UI_FUNCTION_NAME(FilePathMap)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("scheduler"), str8_lit_comp("Scheduler"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Scheduler), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Scheduler), DF_VIEW_CMD_FUNCTION_NAME(Scheduler), DF_VIEW_UI_FUNCTION_NAME(Scheduler)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("call_stack"), str8_lit_comp("Call Stack"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(CallStack), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(CallStack), DF_VIEW_CMD_FUNCTION_NAME(CallStack), DF_VIEW_UI_FUNCTION_NAME(CallStack)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("modules"), str8_lit_comp("Modules"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Modules), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Modules), DF_VIEW_CMD_FUNCTION_NAME(Modules), DF_VIEW_UI_FUNCTION_NAME(Modules)}, +{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("pending_entity"), str8_lit_comp("Pending Entity"), DF_NameKind_EntityName, DF_VIEW_SETUP_FUNCTION_NAME(PendingEntity), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(PendingEntity), DF_VIEW_CMD_FUNCTION_NAME(PendingEntity), DF_VIEW_UI_FUNCTION_NAME(PendingEntity)}, +{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|1*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("code"), str8_lit_comp("Code"), DF_NameKind_EntityName, DF_VIEW_SETUP_FUNCTION_NAME(Code), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Code), DF_VIEW_CMD_FUNCTION_NAME(Code), DF_VIEW_UI_FUNCTION_NAME(Code)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("disassembly"), str8_lit_comp("Disassembly"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Disassembly), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Disassembly), DF_VIEW_CMD_FUNCTION_NAME(Disassembly), DF_VIEW_UI_FUNCTION_NAME(Disassembly)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("watch"), str8_lit_comp("Watch"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Watch), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Watch), DF_VIEW_CMD_FUNCTION_NAME(Watch), DF_VIEW_UI_FUNCTION_NAME(Watch)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("locals"), str8_lit_comp("Locals"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Locals), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Locals), DF_VIEW_CMD_FUNCTION_NAME(Locals), DF_VIEW_UI_FUNCTION_NAME(Locals)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("registers"), str8_lit_comp("Registers"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Registers), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Registers), DF_VIEW_CMD_FUNCTION_NAME(Registers), DF_VIEW_UI_FUNCTION_NAME(Registers)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("output"), str8_lit_comp("Output"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Output), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Output), DF_VIEW_CMD_FUNCTION_NAME(Output), DF_VIEW_UI_FUNCTION_NAME(Output)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|1*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("memory"), str8_lit_comp("Memory"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Memory), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Memory), DF_VIEW_CMD_FUNCTION_NAME(Memory), DF_VIEW_UI_FUNCTION_NAME(Memory)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoints"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Breakpoints), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Breakpoints), DF_VIEW_CMD_FUNCTION_NAME(Breakpoints), DF_VIEW_UI_FUNCTION_NAME(Breakpoints)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pins"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(WatchPins), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(WatchPins), DF_VIEW_CMD_FUNCTION_NAME(WatchPins), DF_VIEW_UI_FUNCTION_NAME(WatchPins)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("exception_filters"), str8_lit_comp("Exception Filters"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(ExceptionFilters), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(ExceptionFilters), DF_VIEW_CMD_FUNCTION_NAME(ExceptionFilters), DF_VIEW_UI_FUNCTION_NAME(ExceptionFilters)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath), str8_lit_comp("theme"), str8_lit_comp("Theme"), DF_NameKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Theme), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Theme), DF_VIEW_CMD_FUNCTION_NAME(Theme), DF_VIEW_UI_FUNCTION_NAME(Theme)}, +}; + +String8 df_g_theme_color_display_string_table[] = +{ +str8_lit_comp("Null"), +str8_lit_comp("Plain Text"), +str8_lit_comp("Plain Background"), +str8_lit_comp("Plain Border"), +str8_lit_comp("Plain Overlay"), +str8_lit_comp("Code (Default)"), +str8_lit_comp("Code (Function)"), +str8_lit_comp("Code (Type)"), +str8_lit_comp("Code (Local)"), +str8_lit_comp("Code (Keyword)"), +str8_lit_comp("Code (Symbol)"), +str8_lit_comp("Code (Numeric)"), +str8_lit_comp("Code (String)"), +str8_lit_comp("Code (Meta)"), +str8_lit_comp("Code (Comment)"), +str8_lit_comp("Line Info (0)"), +str8_lit_comp("Line Info (1)"), +str8_lit_comp("Line Info (2)"), +str8_lit_comp("Line Info (3)"), +str8_lit_comp("Alt Text"), +str8_lit_comp("Alt Background"), +str8_lit_comp("Alt Border"), +str8_lit_comp("Alt Overlay"), +str8_lit_comp("Inactive Tab"), +str8_lit_comp("Active Tab"), +str8_lit_comp("Entity Background"), +str8_lit_comp("Query Bar"), +str8_lit_comp("Weak Text"), +str8_lit_comp("Text Selection"), +str8_lit_comp("Cursor"), +str8_lit_comp("Highlight (0)"), +str8_lit_comp("Highlight (1)"), +str8_lit_comp("Success Text"), +str8_lit_comp("Success Background"), +str8_lit_comp("Success Border"), +str8_lit_comp("Failure Text"), +str8_lit_comp("Failure Background"), +str8_lit_comp("Failure Border"), +str8_lit_comp("Action Text"), +str8_lit_comp("Action Background"), +str8_lit_comp("Action Border"), +str8_lit_comp("Drop Site Overlay"), +str8_lit_comp("Thread (0)"), +str8_lit_comp("Thread (1)"), +str8_lit_comp("Thread (2)"), +str8_lit_comp("Thread (3)"), +str8_lit_comp("Thread (4)"), +str8_lit_comp("Thread (5)"), +str8_lit_comp("Thread (6)"), +str8_lit_comp("Thread (7)"), +str8_lit_comp("Thread (Unwound)"), +str8_lit_comp("Inactive Panel Overlay"), +str8_lit_comp("Drop Shadow"), +}; + +String8 df_g_theme_color_cfg_string_table[] = +{ +str8_lit_comp("null"), +str8_lit_comp("plain_text"), +str8_lit_comp("plain_background"), +str8_lit_comp("plain_border"), +str8_lit_comp("plain_overlay"), +str8_lit_comp("code_default"), +str8_lit_comp("code_function"), +str8_lit_comp("code_type"), +str8_lit_comp("code_local"), +str8_lit_comp("code_keyword"), +str8_lit_comp("code_symbol"), +str8_lit_comp("code_numeric"), +str8_lit_comp("code_string"), +str8_lit_comp("code_meta"), +str8_lit_comp("code_comment"), +str8_lit_comp("line_info_0"), +str8_lit_comp("line_info_1"), +str8_lit_comp("line_info_2"), +str8_lit_comp("line_info_3"), +str8_lit_comp("alt_text"), +str8_lit_comp("alt_background"), +str8_lit_comp("alt_border"), +str8_lit_comp("alt_overlay"), +str8_lit_comp("tab_inactive"), +str8_lit_comp("tab_active"), +str8_lit_comp("entity_background"), +str8_lit_comp("query_bar"), +str8_lit_comp("weak_text"), +str8_lit_comp("text_selection"), +str8_lit_comp("cursor"), +str8_lit_comp("highlight_0"), +str8_lit_comp("highlight_1"), +str8_lit_comp("success_text"), +str8_lit_comp("success_background"), +str8_lit_comp("success_border"), +str8_lit_comp("failure_text"), +str8_lit_comp("failure_background"), +str8_lit_comp("failure_border"), +str8_lit_comp("action_text"), +str8_lit_comp("action_background"), +str8_lit_comp("action_border"), +str8_lit_comp("drop_site_overlay"), +str8_lit_comp("thread_0"), +str8_lit_comp("thread_1"), +str8_lit_comp("thread_2"), +str8_lit_comp("thread_3"), +str8_lit_comp("thread_4"), +str8_lit_comp("thread_5"), +str8_lit_comp("thread_6"), +str8_lit_comp("thread_7"), +str8_lit_comp("thread_unwound"), +str8_lit_comp("inactive_panel_overlay"), +str8_lit_comp("drop_shadow"), +}; + +read_only global U8 df_g_icon_font_bytes__data[] = +{ +0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x80,0x00,0x03,0x00,0x70,0x47,0x53,0x55,0x42,0x20,0x8b,0x25,0x7a,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x54,0x4f,0x53,0x2f,0x32,0x56,0x44,0x49,0xa0,0x00,0x00,0x01,0x50,0x00,0x00,0x00,0x60,0x63,0x6d,0x61,0x70,0x2a,0x09,0xe2,0xc2,0x00,0x00,0x01,0xb0,0x00,0x00,0x05,0xec,0x63,0x76,0x74,0x20, +0x0e,0x5d,0x06,0x6d,0x00,0x00,0x53,0xc0,0x00,0x00,0x00,0x38,0x66,0x70,0x67,0x6d,0x62,0x31,0xfb,0x7b,0x00,0x00,0x53,0xf8,0x00,0x00,0x0e,0x0c,0x67,0x61,0x73,0x70,0x00,0x00,0x00,0x10,0x00,0x00,0x53,0xb8,0x00,0x00,0x00,0x08,0x67,0x6c,0x79,0x66,0x3f,0x82,0x6a,0x1b,0x00,0x00,0x07,0x9c,0x00,0x00,0x43,0x86,0x68,0x65,0x61,0x64, +0x26,0x89,0x5f,0x83,0x00,0x00,0x4b,0x24,0x00,0x00,0x00,0x36,0x68,0x68,0x65,0x61,0x07,0x79,0x03,0xdb,0x00,0x00,0x4b,0x5c,0x00,0x00,0x00,0x24,0x68,0x6d,0x74,0x78,0xf3,0xce,0xff,0xc8,0x00,0x00,0x4b,0x80,0x00,0x00,0x01,0x30,0x6c,0x6f,0x63,0x61,0x8c,0xcb,0x7c,0x1e,0x00,0x00,0x4c,0xb0,0x00,0x00,0x00,0x9a,0x6d,0x61,0x78,0x70, +0x01,0xe3,0x0f,0x19,0x00,0x00,0x4d,0x4c,0x00,0x00,0x00,0x20,0x6e,0x61,0x6d,0x65,0xcd,0x9d,0x1a,0x1b,0x00,0x00,0x4d,0x6c,0x00,0x00,0x02,0xcd,0x70,0x6f,0x73,0x74,0x95,0xf6,0x72,0x8f,0x00,0x00,0x50,0x3c,0x00,0x00,0x03,0x79,0x70,0x72,0x65,0x70,0xeb,0x48,0xca,0x9d,0x00,0x00,0x62,0x04,0x00,0x00,0x00,0xa7,0x00,0x01,0x00,0x00, +0x00,0x0a,0x00,0x30,0x00,0x3e,0x00,0x02,0x44,0x46,0x4c,0x54,0x00,0x0e,0x6c,0x61,0x74,0x6e,0x00,0x1a,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x6c,0x69,0x67,0x61,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x04, +0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x01,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x03,0x35,0x01,0x90,0x00,0x05,0x00,0x00,0x02,0x7a,0x02,0xbc,0x00,0x00,0x00,0x8c,0x02,0x7a,0x02,0xbc,0x00,0x00,0x01,0xe0,0x00,0x31,0x01,0x02,0x00,0x00,0x02,0x00,0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x66,0x45,0x64,0x00,0xc0,0x00,0x21,0xe8,0x00,0x03,0x52,0xff,0x6a,0x00,0x5a,0x03,0xac,0x00,0x96,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x04, +0x00,0x00,0x02,0x58,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x52,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x2c,0x00,0x03,0x00,0x0a,0x00,0x00,0x02,0x58,0x00,0x04,0x01,0x26,0x00,0x00,0x00,0x20,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x23,0x00,0x27,0x00,0x2b,0x00,0x2e,0x00,0x31,0x00,0x35,0x00,0x39,0x00,0x3c,0x00,0x50,0x00,0x5b,0x00,0x5e, +0x00,0x73,0x00,0x7b,0x00,0x7d,0xe8,0x00,0xff,0xff,0x00,0x00,0x00,0x21,0x00,0x27,0x00,0x2b,0x00,0x2d,0x00,0x30,0x00,0x33,0x00,0x37,0x00,0x3c,0x00,0x3e,0x00,0x52,0x00,0x5d,0x00,0x61,0x00,0x75,0x00,0x7d,0xe8,0x00,0xff,0xff,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,0x01,0x00,0x20,0x00,0x24,0x00,0x24,0x00,0x24,0x00,0x26,0x00,0x28,0x00,0x2c,0x00,0x30,0x00,0x30,0x00,0x54,0x00,0x66,0x00,0x68,0x00,0x8c,0x00,0x98,0x00,0x98,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,0x00,0x09,0x00,0x0a, +0x00,0x0b,0x00,0x0c,0x00,0x0d,0x00,0x0e,0x00,0x0f,0x00,0x10,0x00,0x11,0x00,0x12,0x00,0x13,0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x18,0x00,0x19,0x00,0x1a,0x00,0x1b,0x00,0x1c,0x00,0x1d,0x00,0x1e,0x00,0x1f,0x00,0x20,0x00,0x21,0x00,0x22,0x00,0x23,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2a, +0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a,0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x3e,0x00,0x3f,0x00,0x40,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x47,0x00,0x48,0x00,0x49,0x00,0x4a, +0x00,0x4b,0x00,0x00,0x01,0x06,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,0x01,0x02,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x06,0x07,0x00,0x08,0x09,0x00,0x0a,0x0b,0x0c,0x00,0x0d, +0x0e,0x0f,0x00,0x00,0x10,0x00,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x00,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x00,0x2e,0x2f,0x00,0x00,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x00,0x43,0x44,0x45, +0x46,0x47,0x48,0x49,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x03,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x27, +0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x31, +0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x0e, +0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x41, +0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x43,0x00,0x00,0x00,0x43,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x46, +0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x1e, +0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x4e,0x00,0x00,0x00,0x4e,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x52, +0x00,0x00,0x00,0x52,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x57, +0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x2e, +0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x65, +0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x6a,0x00,0x00,0x00,0x6a, +0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x6b,0x00,0x00,0x00,0x6b,0x00,0x00,0x00,0x3a,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x3b,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x6e,0x00,0x00,0x00,0x6e,0x00,0x00,0x00,0x3d,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x3e, +0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x43,0x00,0x00,0x00,0x76, +0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x79,0x00,0x00,0x00,0x79,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x7a,0x00,0x00,0x00,0x7a,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x7b,0x00,0x00,0x00,0x7b, +0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x7d,0x00,0x00,0x00,0x7d,0x00,0x00,0x00,0x4a,0x00,0x00,0xe8,0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x00,0x4b,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x49,0x4b,0xb0,0x24,0x50,0x58,0x40,0x13,0x00,0x01,0x00,0x02,0x01,0x02,0x63,0x04,0x01,0x00,0x00,0x03,0x5f, +0x00,0x03,0x03,0x10,0x00,0x4e,0x1b,0x40,0x19,0x00,0x03,0x04,0x01,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x02,0x02,0x01,0x57,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x01,0x02,0x4f,0x59,0x40,0x0f,0x02,0x00,0x1e,0x1b,0x16,0x13,0x0a,0x07,0x00,0x0f,0x02,0x0f,0x05,0x07,0x16,0x2b,0x01,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32, +0x36,0x35,0x11,0x34,0x26,0x17,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x71,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x34,0x7c,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x02,0xc3,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x59, +0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x60,0x00,0x06,0x00,0x00,0xff,0xba,0x02,0x80,0x03,0x02,0x00,0x13,0x00,0x1c,0x00,0x25,0x00,0x39,0x00,0x42,0x00,0x4b,0x00,0x84,0x40,0x0d,0x39,0x30,0x2f,0x26,0x0d,0x0c,0x03,0x02,0x08,0x02,0x04,0x01,0x4c,0x4b,0xb0,0x16,0x50,0x58,0x40,0x25,0x08,0x0c,0x02,0x04,0x0b,0x01, +0x02,0x03,0x04,0x02,0x69,0x09,0x01,0x05,0x05,0x01,0x61,0x07,0x01,0x01,0x01,0x10,0x4d,0x0d,0x0a,0x02,0x03,0x03,0x00,0x61,0x06,0x01,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x23,0x07,0x01,0x01,0x09,0x01,0x05,0x04,0x01,0x05,0x69,0x08,0x0c,0x02,0x04,0x0b,0x01,0x02,0x03,0x04,0x02,0x69,0x0d,0x0a,0x02,0x03,0x03,0x00,0x61,0x06,0x01, +0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x1f,0x44,0x43,0x1e,0x1d,0x48,0x47,0x43,0x4b,0x44,0x4b,0x41,0x40,0x3d,0x3c,0x35,0x34,0x2b,0x2a,0x22,0x21,0x1d,0x25,0x1e,0x25,0x13,0x14,0x19,0x17,0x0e,0x07,0x1a,0x2b,0x13,0x14,0x07,0x11,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x03,0x34,0x26,0x22, +0x06,0x14,0x16,0x32,0x36,0x03,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x01,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07,0x27,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0xf0,0x48,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x32, +0x2a,0x38,0x28,0x28,0x38,0x2a,0x46,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x01,0xdc,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x48,0x74,0x28,0x38,0x2a,0x2a,0x38,0x28,0x44,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x02,0x8a,0x4c,0x22,0xfe,0x86,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0xfd,0x76,0x1e,0x28, +0x28,0x3a,0x28,0x28,0x02,0x30,0x28,0x3a,0x28,0x28,0x3a,0x28,0xfe,0x5c,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c,0x22,0x6e,0x1c,0x28,0x28,0x3a,0x28,0x28,0xfd,0x46,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x00,0x05,0x00,0x00,0xff,0xb1,0x03,0x12,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f, +0x00,0x37,0x00,0x5b,0x00,0x88,0x40,0x10,0x4b,0x39,0x02,0x08,0x06,0x29,0x21,0x19,0x11,0x09,0x01,0x06,0x01,0x00,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x2a,0x0a,0x01,0x08,0x00,0x06,0x08,0x59,0x0d,0x0b,0x02,0x06,0x04,0x02,0x02,0x00,0x01,0x06,0x00,0x69,0x00,0x07,0x07,0x0c,0x5f,0x00,0x0c,0x0c,0x10,0x4d,0x05,0x03,0x02,0x01, +0x01,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x40,0x28,0x00,0x0c,0x00,0x07,0x06,0x0c,0x07,0x67,0x0a,0x01,0x08,0x00,0x06,0x08,0x59,0x0d,0x0b,0x02,0x06,0x04,0x02,0x02,0x00,0x01,0x06,0x00,0x69,0x05,0x03,0x02,0x01,0x01,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x59,0x40,0x16,0x59,0x58,0x55,0x52,0x4f,0x4d,0x47,0x46,0x43, +0x40,0x26,0x22,0x13,0x26,0x26,0x26,0x26,0x26,0x23,0x0e,0x07,0x1f,0x2b,0x25,0x11,0x34,0x26,0x2b,0x01,0x22,0x06,0x15,0x11,0x14,0x16,0x3b,0x01,0x32,0x36,0x37,0x11,0x34,0x26,0x2b,0x01,0x22,0x06,0x15,0x11,0x14,0x16,0x3b,0x01,0x32,0x36,0x37,0x11,0x34,0x26,0x2b,0x01,0x22,0x06,0x15,0x11,0x14,0x16,0x3b,0x01,0x32,0x36,0x01,0x33, +0x27,0x26,0x27,0x23,0x06,0x07,0x05,0x15,0x14,0x06,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x37,0x3e,0x01,0x37,0x33,0x32,0x16,0x1f,0x01,0x33,0x32,0x16,0x01,0x1e,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8f,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08, +0x0a,0x8e,0x0a,0x07,0x24,0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0xfe,0xd1,0xfa,0x1b,0x04,0x05,0xb1,0x06,0x04,0x01,0xeb,0x0a,0x08,0x36,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x35,0x08,0x0a,0x0a,0x08,0xac,0x27,0x09,0x2c,0x16,0xb2,0x17,0x2a,0x09,0x27,0xad,0x08,0x0a,0x52,0x01,0x89,0x08,0x0a,0x0a,0x08,0xfe,0x77,0x08,0x0a,0x0a,0x08, +0x01,0x89,0x08,0x0a,0x0a,0x08,0xfe,0x77,0x08,0x0a,0x0a,0x08,0x01,0x89,0x08,0x0a,0x0a,0x08,0xfe,0x77,0x08,0x0a,0x0a,0x02,0x32,0x41,0x05,0x01,0x01,0x05,0x53,0x24,0x08,0x0a,0xfd,0xef,0x2e,0x44,0x42,0x2e,0x02,0x13,0x0a,0x08,0x24,0x08,0x0a,0x5d,0x15,0x1c,0x01,0x1e,0x14,0x5d,0x0a,0x00,0x00,0x03,0x00,0x00,0xff,0xba,0x00,0xf0, +0x03,0x02,0x00,0x13,0x00,0x1c,0x00,0x25,0x00,0x62,0x40,0x09,0x13,0x0a,0x09,0x00,0x04,0x05,0x02,0x01,0x4c,0x4b,0xb0,0x16,0x50,0x58,0x40,0x1e,0x00,0x02,0x00,0x05,0x04,0x02,0x05,0x69,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x10,0x4d,0x06,0x01,0x04,0x04,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x1c,0x00,0x01,0x00, +0x03,0x02,0x01,0x03,0x69,0x00,0x02,0x00,0x05,0x04,0x02,0x05,0x69,0x06,0x01,0x04,0x04,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x0f,0x1e,0x1d,0x22,0x21,0x1d,0x25,0x1e,0x25,0x13,0x17,0x19,0x14,0x07,0x07,0x1a,0x2b,0x37,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07, +0x27,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0xa8,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x48,0x74,0x28,0x38,0x2a,0x2a,0x38,0x28,0x44,0x1c,0x2a,0x2a,0x38,0x28,0x28,0xa2,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c,0x22,0x6e,0x1c, +0x28,0x28,0x3a,0x28,0x28,0xfd,0x46,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x00,0x00,0x00,0x02,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x23,0x00,0x30,0x00,0x6f,0x40,0x0a,0x0d,0x01,0x00,0x01,0x1f,0x01,0x04,0x03,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x26,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04, +0x01,0x03,0x04,0x7e,0x00,0x01,0x01,0x07,0x61,0x00,0x07,0x07,0x10,0x4d,0x00,0x04,0x04,0x06,0x62,0x00,0x06,0x06,0x11,0x06,0x4e,0x1b,0x40,0x24,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04,0x01,0x03,0x04,0x7e,0x00,0x07,0x00,0x01,0x00,0x07,0x01,0x67,0x00,0x04,0x04,0x06,0x62,0x00,0x06,0x06,0x11,0x06,0x4e, +0x59,0x40,0x0b,0x15,0x15,0x23,0x24,0x25,0x23,0x24,0x14,0x08,0x07,0x1e,0x2b,0x01,0x35,0x34,0x26,0x07,0x23,0x35,0x34,0x26,0x27,0x23,0x22,0x06,0x07,0x15,0x23,0x22,0x06,0x17,0x15,0x14,0x16,0x37,0x33,0x15,0x14,0x16,0x17,0x33,0x32,0x36,0x37,0x35,0x33,0x32,0x36,0x37,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x02, +0xa7,0x16,0x0e,0x8f,0x16,0x0e,0x47,0x0f,0x14,0x01,0x8f,0x0e,0x16,0x01,0x14,0x0f,0x8f,0x16,0x0e,0x47,0x0f,0x14,0x01,0x8f,0x0e,0x16,0xb2,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x3a,0x48,0x0e,0x16,0x01,0x8f,0x0f,0x14,0x01,0x16,0x0e,0x8f,0x14,0x0f,0x48,0x0e,0x16,0x01,0x8f,0x0f,0x14,0x01,0x16,0x0e,0x8f, +0x14,0x33,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x02,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0f,0x00,0x1c,0x00,0x3c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x15,0x00,0x00,0x00,0x03,0x61,0x00,0x03,0x03,0x10,0x4d,0x00,0x01,0x01,0x02,0x61,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x13,0x00,0x03,0x00,0x00,0x01, +0x03,0x00,0x67,0x00,0x01,0x01,0x02,0x61,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0xb6,0x15,0x15,0x35,0x24,0x04,0x07,0x1a,0x2b,0x01,0x35,0x34,0x26,0x07,0x21,0x22,0x06,0x17,0x15,0x14,0x16,0x37,0x21,0x32,0x36,0x37,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x02,0xa7,0x16,0x0e,0xfe,0x53,0x0e,0x16,0x01,0x14,0x0f,0x01, +0xad,0x0e,0x16,0xb2,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x3a,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48,0x0e,0x16,0x01,0x14,0x33,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x01,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0c,0x00,0x28,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0b,0x00,0x01,0x01, +0x10,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0b,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0xb4,0x15,0x13,0x02,0x07,0x18,0x2b,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x03,0x59,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x5e,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4, +0x74,0x74,0xc4,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x3c,0x01,0xed,0x00,0x0e,0x00,0x1e,0x40,0x1b,0x00,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x57,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x35,0x14,0x02,0x07,0x18,0x2b,0x01,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x26,0x34,0x36,0x33,0x21,0x32,0x16,0x02, +0x3b,0x0a,0xfa,0x0b,0x1c,0x0b,0xfa,0x0b,0x16,0x0e,0x01,0xf4,0x0e,0x16,0x01,0xc9,0x0e,0x0b,0xfa,0x0b,0x0b,0xfa,0x0b,0x1c,0x16,0x16,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0xa0,0x03,0x0b,0x00,0x2d,0x00,0x42,0x00,0x8b,0x40,0x0a,0x3b,0x01,0x04,0x06,0x25,0x01,0x05,0x04,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x30,0x00, +0x07,0x01,0x02,0x01,0x07,0x02,0x80,0x00,0x06,0x02,0x04,0x02,0x06,0x04,0x80,0x00,0x04,0x05,0x02,0x04,0x05,0x7e,0x00,0x05,0x03,0x02,0x05,0x03,0x7e,0x00,0x03,0x00,0x00,0x03,0x00,0x64,0x00,0x02,0x02,0x01,0x5f,0x00,0x01,0x01,0x10,0x02,0x4e,0x1b,0x40,0x36,0x00,0x07,0x01,0x02,0x01,0x07,0x02,0x80,0x00,0x06,0x02,0x04,0x02,0x06, +0x04,0x80,0x00,0x04,0x05,0x02,0x04,0x05,0x7e,0x00,0x05,0x03,0x02,0x05,0x03,0x7e,0x00,0x01,0x00,0x02,0x06,0x01,0x02,0x67,0x00,0x03,0x00,0x00,0x03,0x57,0x00,0x03,0x03,0x00,0x60,0x00,0x00,0x03,0x00,0x50,0x59,0x40,0x0b,0x14,0x17,0x15,0x27,0x35,0x39,0x35,0x33,0x08,0x07,0x1e,0x2b,0x01,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x35, +0x11,0x34,0x36,0x37,0x21,0x32,0x17,0x1e,0x01,0x0f,0x01,0x06,0x23,0x27,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x3d,0x01,0x34,0x3f,0x01,0x36,0x33,0x32,0x17,0x16,0x13,0x01,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x01,0x36,0x32,0x1f,0x01,0x16,0x14,0x03,0x12,0x5e,0x43,0xfe,0x30, +0x43,0x5e,0x5e,0x43,0x01,0xd0,0x23,0x1e,0x09,0x03,0x07,0x1b,0x06,0x07,0x05,0x0d,0x0c,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x05,0x24,0x06,0x07,0x03,0x04,0x0b,0x81,0xfe,0x39,0x0d,0x24,0x0e,0xf0,0x0e,0x0e,0x3d,0x0e,0x24,0x0e,0x93,0x01,0x69,0x0d,0x24,0x0e,0x3e,0x0d,0x01,0x4b,0xb1,0x43,0x5e,0x5e,0x43,0x01, +0xd0,0x42,0x5e,0x01,0x0e,0x04,0x13,0x06,0x1c,0x05,0x01,0x03,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x8d,0x08,0x05,0x23,0x06,0x02,0x04,0x01,0x05,0xfe,0x3a,0x0e,0x0e,0xf0,0x0d,0x24,0x0e,0x3e,0x0d,0x0d,0x93,0x01,0x69,0x0d,0x0d,0x3d,0x0e,0x24,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xff,0xb1,0x03,0x12,0x03,0x0b,0x00,0x0f, +0x00,0x1f,0x00,0x2f,0x00,0x3b,0x00,0x43,0x00,0x67,0x00,0xcf,0x40,0x10,0x57,0x45,0x02,0x06,0x08,0x29,0x21,0x19,0x11,0x09,0x01,0x06,0x00,0x01,0x02,0x4c,0x4b,0xb0,0x09,0x50,0x58,0x40,0x2f,0x00,0x09,0x0e,0x08,0x06,0x09,0x72,0x0f,0x0d,0x02,0x08,0x0c,0x0a,0x02,0x06,0x01,0x08,0x06,0x68,0x05,0x03,0x02,0x01,0x04,0x02,0x02,0x00, +0x07,0x01,0x00,0x69,0x00,0x0e,0x0e,0x10,0x4d,0x00,0x07,0x07,0x0b,0x5f,0x00,0x0b,0x0b,0x11,0x0b,0x4e,0x1b,0x4b,0xb0,0x24,0x50,0x58,0x40,0x30,0x00,0x09,0x0e,0x08,0x0e,0x09,0x08,0x80,0x0f,0x0d,0x02,0x08,0x0c,0x0a,0x02,0x06,0x01,0x08,0x06,0x68,0x05,0x03,0x02,0x01,0x04,0x02,0x02,0x00,0x07,0x01,0x00,0x69,0x00,0x0e,0x0e,0x10, +0x4d,0x00,0x07,0x07,0x0b,0x5f,0x00,0x0b,0x0b,0x11,0x0b,0x4e,0x1b,0x40,0x2d,0x00,0x0e,0x09,0x0e,0x85,0x00,0x09,0x08,0x09,0x85,0x0f,0x0d,0x02,0x08,0x0c,0x0a,0x02,0x06,0x01,0x08,0x06,0x68,0x05,0x03,0x02,0x01,0x04,0x02,0x02,0x00,0x07,0x01,0x00,0x69,0x00,0x07,0x07,0x0b,0x5f,0x00,0x0b,0x0b,0x11,0x0b,0x4e,0x59,0x59,0x40,0x1a, +0x65,0x64,0x61,0x5e,0x5b,0x59,0x53,0x52,0x4f,0x4c,0x49,0x47,0x41,0x3f,0x14,0x24,0x14,0x26,0x26,0x26,0x26,0x26,0x23,0x10,0x07,0x1f,0x2b,0x01,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x2b, +0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x13,0x11,0x21,0x11,0x14,0x1e,0x01,0x33,0x21,0x32,0x3e,0x01,0x01,0x33,0x27,0x26,0x27,0x23,0x06,0x07,0x05,0x15,0x14,0x06,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x37,0x3e,0x01,0x37,0x33,0x32,0x16,0x1f,0x01, +0x33,0x32,0x16,0x01,0x1e,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8f,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8e,0x0a,0x07,0x24,0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0x48,0xfe,0x0c,0x08,0x08,0x02,0x01,0xd0,0x02,0x08,0x08,0xfe,0x89,0xfa,0x1b,0x04,0x05,0xb1,0x06,0x04,0x01,0xeb,0x0a,0x08,0x36,0x34,0x25, +0xfe,0x30,0x25,0x34,0x01,0x35,0x08,0x0a,0x0a,0x08,0xac,0x27,0x09,0x2c,0x16,0xb2,0x17,0x2a,0x09,0x27,0xad,0x08,0x0a,0x01,0xb7,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0x08,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0x08,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0xfe,0x64,0x02,0x11, +0xfd,0xef,0x0c,0x14,0x0a,0x0a,0x14,0x02,0x65,0x41,0x05,0x01,0x01,0x05,0x53,0x24,0x08,0x0a,0xfd,0xef,0x2e,0x44,0x42,0x2e,0x02,0x13,0x0a,0x08,0x24,0x08,0x0a,0x5d,0x15,0x1c,0x01,0x1e,0x14,0x5d,0x0a,0x00,0x00,0x01,0x00,0x00,0xff,0x9c,0x03,0xac,0x03,0x20,0x00,0x2a,0x00,0x34,0x40,0x09,0x20,0x1e,0x16,0x12,0x04,0x00,0x01,0x01, +0x4c,0x4b,0xb0,0x17,0x50,0x58,0x40,0x0b,0x00,0x01,0x01,0x10,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0b,0x00,0x00,0x00,0x01,0x61,0x00,0x01,0x01,0x10,0x00,0x4e,0x59,0xb5,0x1b,0x1a,0x13,0x02,0x07,0x17,0x2b,0x25,0x16,0x1d,0x01,0x21,0x35,0x34,0x37,0x3e,0x01,0x35,0x34,0x26,0x27,0x2e,0x03,0x27,0x34,0x36,0x3f,0x01,0x26, +0x27,0x26,0x36,0x32,0x16,0x0f,0x01,0x16,0x15,0x0e,0x03,0x07,0x0e,0x01,0x15,0x14,0x16,0x02,0xe0,0xcc,0xfc,0x54,0xcc,0x5e,0x44,0x2c,0x0a,0x02,0x0e,0x0e,0x0e,0x02,0x0a,0x04,0x04,0x08,0x04,0x04,0x5a,0xe0,0x5c,0x06,0x0c,0x12,0x02,0x0e,0x0e,0x0e,0x02,0x08,0x2e,0x46,0x80,0x48,0x32,0x6a,0x6a,0x32,0x48,0x22,0x46,0x3c,0x16,0x36, +0x2e,0x0c,0x0c,0x04,0x1e,0x1c,0x10,0x14,0x02,0x04,0x32,0x26,0x36,0x74,0x74,0x36,0x58,0x08,0x22,0x1c,0x1e,0x04,0x0c,0x0c,0x30,0x34,0x16,0x3c,0x46,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xb6,0x03,0xe8,0x03,0x08,0x00,0x18,0x00,0x20,0x00,0x2d,0x00,0xcc,0xb5,0x25,0x01,0x09,0x0b,0x01,0x4c,0x4b,0xb0,0x0c,0x50,0x58,0x40,0x30, +0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x72,0x0c,0x01,0x05,0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x00,0x07,0x07,0x02,0x5f,0x00,0x02,0x02,0x10,0x4d,0x0a,0x01,0x08,0x08,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x4b,0xb0,0x1f,0x50,0x58,0x40,0x31,0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x09, +0x80,0x0c,0x01,0x05,0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x00,0x07,0x07,0x02,0x5f,0x00,0x02,0x02,0x10,0x4d,0x0a,0x01,0x08,0x08,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x40,0x2f,0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x09,0x80,0x00,0x02,0x00,0x07,0x01,0x02,0x07,0x67,0x0c,0x01,0x05, +0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x0a,0x01,0x08,0x08,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x59,0x59,0x40,0x1e,0x21,0x21,0x00,0x00,0x21,0x2d,0x21,0x2d,0x2c,0x2b,0x29,0x26,0x23,0x22,0x20,0x1d,0x1b,0x1a,0x00,0x18,0x00,0x18,0x12,0x24,0x35,0x22,0x11,0x0e,0x07,0x1b,0x2b,0x01,0x15, +0x21,0x13,0x36,0x3b,0x01,0x36,0x3f,0x01,0x3e,0x01,0x3b,0x01,0x32,0x16,0x17,0x16,0x17,0x33,0x32,0x17,0x13,0x21,0x35,0x03,0x07,0x21,0x27,0x26,0x2b,0x01,0x22,0x13,0x35,0x21,0x06,0x07,0x06,0x23,0x21,0x22,0x35,0x27,0x21,0x15,0x01,0xc8,0xfe,0x38,0x0a,0x04,0x60,0xa0,0x10,0x15,0x17,0x0e,0x12,0x1c,0xde,0x1a,0x14,0x0c,0x12,0x2a, +0xa0,0x60,0x04,0x0a,0xfe,0x3a,0xa4,0x1c,0x01,0x24,0x1c,0x0e,0x1c,0x98,0x1c,0x96,0x01,0xae,0x06,0x04,0x06,0x54,0xfd,0x12,0x5a,0x0a,0x01,0xae,0x01,0x46,0x64,0x01,0x24,0x6c,0x1a,0x29,0x2d,0x1a,0x0c,0x0e,0x18,0x20,0x50,0x6c,0xfe,0xdc,0x64,0x01,0x62,0x36,0x36,0x1a,0xfd,0x8a,0x64,0x58,0x4e,0x54,0x54,0xa6,0x64,0x00,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x67,0x02,0x7c,0x00,0x0d,0x00,0x1e,0x40,0x1b,0x00,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x17,0x13,0x02,0x07,0x18,0x2b,0x01,0x11,0x14,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x16,0x01,0x65,0x14,0x20,0x09,0xfa, +0x0a,0x0a,0xfa,0x0b,0x1c,0x18,0x02,0x58,0xfe,0x0c,0x0e,0x16,0x0b,0xfa,0x0b,0x1c,0x0b,0xfa,0x0b,0x16,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x41,0x02,0x7d,0x00,0x0e,0x00,0x0a,0xb7,0x00,0x00,0x00,0x76,0x14,0x01,0x07,0x17,0x2b,0x01,0x14,0x0f,0x01,0x06,0x22,0x26,0x35,0x11,0x34,0x3e,0x01,0x1f,0x01,0x16,0x01,0x41,0x0a,0xfa,0x0b, +0x1c,0x16,0x16,0x1c,0x0b,0xfa,0x0a,0x01,0x5e,0x0e,0x0b,0xfa,0x0b,0x16,0x0e,0x01,0xf4,0x0f,0x14,0x02,0x0c,0xfa,0x0a,0x00,0x00,0x01,0xff,0xff,0x00,0x00,0x02,0x3b,0x01,0xc9,0x00,0x0e,0x00,0x18,0x40,0x15,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x15,0x32,0x02,0x07,0x18,0x2b,0x25,0x14, +0x06,0x27,0x21,0x22,0x2e,0x01,0x3f,0x01,0x36,0x32,0x1f,0x01,0x16,0x02,0x3b,0x14,0x0f,0xfe,0x0c,0x0f,0x14,0x02,0x0c,0xfa,0x0a,0x1e,0x0a,0xfa,0x0a,0xab,0x0e,0x16,0x01,0x14,0x1e,0x0b,0xfa,0x0a,0x0a,0xfa,0x0b,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x5e,0x02,0x51,0x00,0x15,0x00,0x1e,0x40,0x1b,0x03,0x01,0x00,0x01, +0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x17,0x19,0x02,0x07,0x18,0x2b,0x01,0x14,0x0f,0x01,0x17,0x16,0x14,0x0f,0x01,0x06,0x22,0x27,0x01,0x26,0x34,0x37,0x01,0x36,0x32,0x1f,0x01,0x16,0x01,0x5e,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x0e,0x06,0xfe,0xfc,0x06,0x06,0x01,0x04,0x05, +0x10,0x04,0x1c,0x06,0x02,0x22,0x07,0x05,0xdc,0xdb,0x06,0x0e,0x06,0x1c,0x05,0x05,0x01,0x05,0x05,0x0e,0x06,0x01,0x04,0x06,0x06,0x1c,0x05,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x4c,0x02,0x51,0x00,0x15,0x00,0x1e,0x40,0x1b,0x0b,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01, +0x00,0x51,0x1c,0x14,0x02,0x07,0x18,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x27,0x26,0x34,0x3f,0x01,0x36,0x32,0x17,0x01,0x16,0x01,0x4c,0x05,0xfe,0xfb,0x05,0x0e,0x06,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x10,0x04,0x01,0x05,0x05,0x01,0x3a,0x07,0x05,0xfe,0xfb,0x05,0x05,0x1c,0x06,0x0e,0x06, +0xdb,0xdc,0x05,0x0e,0x06,0x1c,0x06,0x06,0xfe,0xfc,0x05,0x00,0x00,0x03,0xff,0xfc,0xff,0x90,0x03,0x9a,0x03,0x2c,0x00,0x08,0x00,0x16,0x00,0x3f,0x00,0x83,0x40,0x0b,0x38,0x36,0x02,0x03,0x05,0x13,0x01,0x02,0x03,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x24,0x00,0x05,0x06,0x03,0x06,0x05,0x03,0x80,0x00,0x06,0x00,0x03,0x02,0x06, +0x03,0x69,0x08,0x01,0x02,0x00,0x01,0x02,0x01,0x66,0x00,0x04,0x04,0x00,0x61,0x07,0x01,0x00,0x00,0x12,0x04,0x4e,0x1b,0x40,0x2b,0x00,0x05,0x06,0x03,0x06,0x05,0x03,0x80,0x07,0x01,0x00,0x00,0x04,0x06,0x00,0x04,0x69,0x00,0x06,0x00,0x03,0x02,0x06,0x03,0x69,0x08,0x01,0x02,0x01,0x01,0x02,0x59,0x08,0x01,0x02,0x02,0x01,0x62,0x00, +0x01,0x02,0x01,0x52,0x59,0x40,0x19,0x0a,0x09,0x01,0x00,0x27,0x26,0x22,0x20,0x1d,0x1b,0x11,0x0e,0x09,0x16,0x0a,0x16,0x05,0x04,0x00,0x08,0x01,0x08,0x09,0x07,0x16,0x2b,0x01,0x36,0x00,0x12,0x00,0x04,0x00,0x02,0x00,0x13,0x32,0x36,0x35,0x36,0x26,0x2b,0x01,0x22,0x06,0x07,0x14,0x16,0x17,0x13,0x36,0x35,0x34,0x26,0x23,0x22,0x07, +0x06,0x07,0x15,0x33,0x35,0x34,0x37,0x36,0x32,0x17,0x16,0x15,0x14,0x07,0x06,0x0f,0x01,0x06,0x0f,0x01,0x06,0x07,0x06,0x07,0x15,0x33,0x35,0x34,0x37,0x36,0x3f,0x01,0x36,0x01,0xc6,0xbe,0x01,0x10,0x06,0xfe,0xf6,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0c,0xbc,0x1e,0x26,0x02,0x26,0x1e,0x02,0x1c,0x26,0x02,0x26,0x1c,0xa8,0x1a,0x6a,0x52, +0x40,0x28,0x44,0x04,0x6e,0x10,0x10,0x4e,0x0c,0x10,0x10,0x08,0x0c,0x16,0x0a,0x0a,0x15,0x0b,0x06,0x0e,0x04,0x6c,0x04,0x06,0x16,0x1c,0x2e,0x03,0x2a,0x02,0xfe,0xf8,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0a,0x01,0x7c,0x01,0x12,0xfd,0x1e,0x26,0x1c,0x1e,0x26,0x24,0x1c,0x1e,0x26,0x02,0x01,0x48,0x22,0x2c,0x4e,0x4c,0x1a,0x2a,0x68,0x04, +0x04,0x1a,0x1c,0x18,0x14,0x14,0x18,0x12,0x16,0x0c,0x08,0x0f,0x07,0x08,0x11,0x09,0x08,0x14,0x3a,0x08,0x04,0x0c,0x10,0x14,0x10,0x12,0x22,0x00,0x00,0x02,0x00,0x00,0xff,0xbd,0x03,0x4d,0x03,0x0b,0x00,0x08,0x00,0x1d,0x00,0x56,0xb5,0x00,0x01,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x10,0x00,0x00,0x00,0x02,0x5f,0x00, +0x02,0x02,0x10,0x4d,0x00,0x01,0x01,0x11,0x01,0x4e,0x1b,0x4b,0xb0,0x2a,0x50,0x58,0x40,0x0e,0x00,0x02,0x00,0x00,0x01,0x02,0x00,0x69,0x00,0x01,0x01,0x11,0x01,0x4e,0x1b,0x40,0x15,0x00,0x01,0x00,0x01,0x86,0x00,0x02,0x00,0x00,0x02,0x57,0x00,0x02,0x02,0x00,0x61,0x00,0x00,0x02,0x00,0x51,0x59,0x59,0xb5,0x38,0x1a,0x12,0x03,0x07, +0x19,0x2b,0x13,0x34,0x26,0x0e,0x01,0x1e,0x02,0x36,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x2e,0x01,0x3d,0x01,0x34,0x36,0x37,0x33,0x32,0x16,0x17,0x01,0x16,0xfa,0x2a,0x3a,0x2c,0x02,0x28,0x3e,0x26,0x02,0x55,0x14,0xfe,0xee,0x16,0x3b,0x14,0xfe,0x71,0x15,0x1e,0x2a,0x1d,0xe9,0x1d,0x48,0x15,0x01,0x8f,0x14,0x02,0x58,0x1e,0x2a, +0x02,0x26,0x40,0x24,0x06,0x30,0xfe,0xd9,0x1e,0x15,0xfe,0xee,0x15,0x15,0x01,0x8f,0x15,0x48,0x1d,0xe8,0x1d,0x2a,0x01,0x1e,0x15,0xfe,0x71,0x15,0x00,0x0d,0x00,0x00,0xff,0xea,0x03,0xca,0x02,0xd2,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x0f,0x00,0x13,0x00,0x17,0x00,0x1b,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x2b,0x00,0x2f,0x00,0x33, +0x00,0xfd,0x4b,0xb0,0x32,0x50,0x58,0x40,0x49,0x18,0x12,0x0c,0x03,0x06,0x00,0x07,0x00,0x06,0x07,0x80,0x20,0x19,0x13,0x1d,0x0d,0x05,0x07,0x03,0x00,0x07,0x03,0x7e,0x17,0x11,0x0b,0x03,0x05,0x02,0x04,0x02,0x05,0x04,0x80,0x16,0x10,0x0a,0x03,0x04,0x01,0x02,0x04,0x01,0x7e,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x1a,0x01,0x01,0x02, +0x01,0x63,0x14,0x1e,0x0f,0x08,0x1b,0x05,0x03,0x03,0x00,0x60,0x00,0x00,0x00,0x13,0x03,0x4e,0x1b,0x40,0x54,0x18,0x12,0x0c,0x03,0x06,0x00,0x07,0x00,0x06,0x07,0x80,0x20,0x19,0x13,0x1d,0x0d,0x05,0x07,0x03,0x00,0x07,0x03,0x7e,0x17,0x11,0x0b,0x03,0x05,0x02,0x04,0x02,0x05,0x04,0x80,0x16,0x10,0x0a,0x03,0x04,0x01,0x02,0x04,0x01, +0x7e,0x00,0x00,0x14,0x1e,0x0f,0x08,0x1b,0x05,0x03,0x02,0x00,0x03,0x67,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x05,0x01,0x02,0x58,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x02,0x01,0x5f,0x1a,0x01,0x01,0x02,0x01,0x4f,0x59,0x40,0x52,0x30,0x30,0x28,0x28,0x1c,0x1c,0x18,0x18,0x10,0x10,0x04,0x04,0x00,0x00,0x30,0x33,0x30,0x33,0x32,0x31, +0x2f,0x2e,0x2d,0x2c,0x28,0x2b,0x28,0x2b,0x2a,0x29,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x1c,0x1f,0x1c,0x1f,0x1e,0x1d,0x18,0x1b,0x18,0x1b,0x1a,0x19,0x17,0x16,0x15,0x14,0x10,0x13,0x10,0x13,0x12,0x11,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x04,0x07,0x04,0x07,0x06,0x05,0x00,0x03,0x00,0x03,0x11,0x21,0x07,0x17,0x2b,0x15, +0x11,0x21,0x11,0x01,0x15,0x33,0x35,0x03,0x33,0x35,0x23,0x13,0x23,0x15,0x33,0x17,0x35,0x23,0x1d,0x01,0x33,0x35,0x23,0x13,0x35,0x23,0x15,0x05,0x15,0x33,0x35,0x03,0x33,0x35,0x23,0x13,0x23,0x15,0x33,0x17,0x35,0x23,0x1d,0x01,0x33,0x35,0x23,0x13,0x35,0x23,0x15,0x03,0xca,0xfe,0x3d,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xe1,0x9e, +0x9e,0x9e,0x9e,0x9e,0xfd,0x5b,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0xe1,0x9d,0x9d,0x9d,0x9d,0x9d,0x16,0x02,0xe8,0xfd,0x18,0x01,0xc4,0x9f,0x9f,0xfe,0x80,0x9d,0x01,0xc4,0x9e,0xe2,0x9f,0x9f,0xe1,0x9d,0x01,0x26,0x9e,0x9e,0x43,0x9f,0x9f,0xfe,0x80,0x9d,0x01,0xc4,0x9e,0xe2,0x9f,0x9f,0xe1,0x9d,0x01,0x26,0x9e,0x9e,0x00,0x00,0x00, +0x00,0x02,0xff,0xff,0xff,0xf9,0x04,0x19,0x03,0x0b,0x00,0x12,0x00,0x29,0x00,0x47,0x4b,0xb0,0x26,0x50,0x58,0x40,0x15,0x00,0x04,0x00,0x02,0x01,0x04,0x02,0x68,0x00,0x01,0x00,0x00,0x01,0x00,0x63,0x00,0x03,0x03,0x10,0x03,0x4e,0x1b,0x40,0x1d,0x00,0x03,0x04,0x03,0x85,0x00,0x04,0x00,0x02,0x01,0x04,0x02,0x68,0x00,0x01,0x00,0x00, +0x01,0x57,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x59,0xb7,0x23,0x3a,0x23,0x36,0x35,0x05,0x07,0x1b,0x2b,0x01,0x14,0x0f,0x01,0x0e,0x01,0x23,0x21,0x22,0x2e,0x01,0x3f,0x01,0x3e,0x01,0x33,0x21,0x32,0x16,0x27,0x15,0x21,0x22,0x06,0x0f,0x02,0x27,0x26,0x37,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16, +0x04,0x19,0x12,0xbb,0x18,0x56,0x26,0xfd,0xa1,0x13,0x1c,0x01,0x11,0xbc,0x18,0x56,0x25,0x02,0x5f,0x13,0x1e,0xc0,0xfe,0x30,0x35,0x72,0x23,0xbc,0x02,0x01,0x01,0x01,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x2f,0x34,0x48,0x01,0x3f,0x11,0x14,0xdd,0x1c,0x28,0x0e,0x22,0x14,0xdd,0x1c,0x28,0x0e,0xaf,0x5a,0x34,0x29,0xdd,0x03,0x07,0x05,0x02, +0x02,0x18,0x33,0x4a,0x4a,0x33,0x12,0x4a,0x00,0x01,0x00,0x00,0xff,0xf9,0x03,0xa1,0x03,0x0b,0x00,0x14,0x00,0x35,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0d,0x00,0x02,0x00,0x00,0x02,0x00,0x64,0x00,0x01,0x01,0x10,0x01,0x4e,0x1b,0x40,0x15,0x00,0x01,0x02,0x01,0x85,0x00,0x02,0x00,0x00,0x02,0x57,0x00,0x02,0x02,0x00,0x60,0x00,0x00,0x02, +0x00,0x50,0x59,0xb5,0x23,0x35,0x33,0x03,0x07,0x19,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x03,0xa1,0x4a,0x33,0xfd,0x59,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x77,0x33,0x4a,0x01,0xff,0xfe,0x77,0x33,0x4a,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33,0x12, +0x4a,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf2,0x02,0xf8,0x02,0xcc,0x00,0x06,0x00,0x1f,0x40,0x1c,0x01,0x01,0x00,0x49,0x03,0x02,0x02,0x00,0x01,0x00,0x86,0x00,0x01,0x01,0x13,0x01,0x4e,0x00,0x00,0x00,0x06,0x00,0x06,0x11,0x12,0x04,0x07,0x18,0x2b,0x09,0x02,0x33,0x11,0x21,0x11,0x02,0xf8,0xfe,0x84,0xfe,0x84,0xc0,0x01,0x78, +0x01,0x6e,0xfe,0x84,0x01,0x7c,0x01,0x5e,0xfe,0xa2,0x00,0x00,0x00,0x02,0xff,0xf7,0xff,0xe2,0x03,0xdb,0x03,0x12,0x00,0x17,0x00,0x20,0x00,0x42,0x4b,0xb0,0x1c,0x50,0x58,0x40,0x11,0x00,0x02,0x01,0x02,0x85,0x03,0x01,0x01,0x01,0x00,0x61,0x00,0x00,0x00,0x14,0x00,0x4e,0x1b,0x40,0x17,0x00,0x02,0x01,0x02,0x85,0x03,0x01,0x01,0x00, +0x00,0x01,0x59,0x03,0x01,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x59,0x40,0x0c,0x19,0x18,0x1d,0x1c,0x18,0x20,0x19,0x20,0x2f,0x04,0x07,0x17,0x2b,0x01,0x1e,0x01,0x06,0x07,0x06,0x26,0x06,0x07,0x06,0x1e,0x01,0x07,0x0e,0x02,0x23,0x22,0x26,0x37,0x3e,0x01,0x37,0x24,0x03,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x03,0x59, +0x48,0x3a,0x12,0x1a,0x10,0x4c,0x54,0x26,0x1e,0x12,0x32,0x02,0x02,0x44,0xb8,0x7c,0xba,0xd2,0x0a,0x08,0xc0,0x78,0x01,0x22,0x48,0x1e,0x2c,0x2c,0x3e,0x2c,0x2c,0x02,0x6e,0x30,0x7c,0x54,0x06,0x04,0x1c,0x08,0x2a,0x2e,0x3a,0x48,0x0e,0x1a,0x4a,0x4a,0xca,0x90,0x76,0xea,0x22,0x54,0xfd,0x8a,0x2c,0x40,0x2a,0x2a,0x40,0x2c,0x00,0x00, +0x00,0x02,0x00,0x00,0xff,0x6a,0x03,0x59,0x03,0x52,0x00,0x06,0x00,0x18,0x00,0x33,0x40,0x30,0x01,0x01,0x00,0x03,0x01,0x4c,0x00,0x03,0x00,0x03,0x85,0x04,0x01,0x00,0x01,0x00,0x85,0x00,0x01,0x02,0x02,0x01,0x57,0x00,0x01,0x01,0x02,0x60,0x00,0x02,0x01,0x02,0x50,0x00,0x00,0x18,0x16,0x11,0x0e,0x0b,0x09,0x00,0x06,0x00,0x06,0x05, +0x07,0x16,0x2b,0x01,0x11,0x16,0x1f,0x01,0x16,0x17,0x05,0x14,0x16,0x17,0x21,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x21,0x02,0x3b,0x0d,0x08,0xe3,0x08,0x08,0xfe,0xb1,0x20,0x16,0x01,0x2f,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x01,0xbe,0x02,0x34,0x01,0x08,0x08,0x08,0xe4,0x07,0x0d,0x12,0x16,0x1e, +0x01,0xfd,0xb3,0x17,0x1e,0x01,0x20,0x16,0x03,0x7c,0x17,0x1e,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x08,0x00,0x6a,0x00,0x72,0x40,0x15,0x65,0x59,0x4c,0x41,0x04,0x00,0x04,0x3b,0x0a,0x02,0x01,0x00,0x34,0x28,0x1b,0x10,0x04,0x03,0x01,0x03,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x20,0x00,0x00, +0x00,0x05,0x5f,0x00,0x05,0x05,0x10,0x4d,0x00,0x03,0x03,0x04,0x61,0x06,0x01,0x04,0x04,0x13,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x1e,0x00,0x05,0x00,0x00,0x01,0x05,0x00,0x69,0x00,0x03,0x03,0x04,0x61,0x06,0x01,0x04,0x04,0x13,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59, +0x40,0x0f,0x5c,0x5b,0x53,0x51,0x49,0x48,0x2b,0x2a,0x22,0x20,0x13,0x12,0x07,0x07,0x18,0x2b,0x01,0x34,0x26,0x22,0x0e,0x01,0x16,0x32,0x36,0x25,0x15,0x14,0x06,0x0f,0x01,0x06,0x07,0x16,0x17,0x16,0x14,0x07,0x0e,0x01,0x27,0x22,0x2f,0x01,0x06,0x07,0x06,0x07,0x06,0x2b,0x01,0x22,0x26,0x35,0x27,0x26,0x27,0x07,0x06,0x22,0x27,0x26, +0x27,0x26,0x34,0x37,0x3e,0x01,0x37,0x26,0x2f,0x01,0x2e,0x01,0x27,0x35,0x34,0x36,0x3f,0x01,0x36,0x37,0x26,0x27,0x26,0x34,0x37,0x3e,0x01,0x33,0x32,0x1f,0x01,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x32,0x16,0x1f,0x01,0x16,0x17,0x37,0x36,0x32,0x17,0x16,0x17,0x16,0x14,0x07,0x0e,0x01,0x07,0x16,0x1f,0x01,0x1e,0x01,0x02,0x3b,0x52, +0x78,0x52,0x02,0x56,0x74,0x56,0x01,0x1c,0x08,0x07,0x68,0x0a,0x0b,0x13,0x28,0x06,0x05,0x0f,0x50,0x0d,0x07,0x07,0x4d,0x19,0x1a,0x09,0x07,0x04,0x10,0x7c,0x08,0x0c,0x10,0x1b,0x17,0x4f,0x06,0x10,0x06,0x46,0x16,0x04,0x05,0x08,0x28,0x0a,0x0f,0x08,0x66,0x07,0x08,0x01,0x0a,0x05,0x68,0x08,0x0e,0x17,0x25,0x06,0x05,0x0f,0x50,0x0d, +0x07,0x08,0x4d,0x18,0x1a,0x09,0x08,0x03,0x11,0x7c,0x07,0x0c,0x01,0x0f,0x1c,0x17,0x4f,0x05,0x0f,0x07,0x48,0x14,0x04,0x04,0x09,0x28,0x0a,0x0f,0x08,0x66,0x07,0x0a,0x01,0x5e,0x3b,0x54,0x54,0x76,0x54,0x54,0x78,0x7c,0x07,0x0c,0x01,0x10,0x1e,0x15,0x1b,0x32,0x06,0x0e,0x06,0x15,0x50,0x01,0x05,0x3c,0x0d,0x08,0x4c,0x1c,0x10,0x0a, +0x07,0x67,0x09,0x0c,0x3c,0x05,0x06,0x40,0x1e,0x05,0x0e,0x06,0x0c,0x32,0x0f,0x1c,0x1b,0x0f,0x01,0x0c,0x07,0x7c,0x07,0x0c,0x01,0x10,0x19,0x1a,0x20,0x2d,0x07,0x0c,0x07,0x14,0x50,0x05,0x3c,0x0d,0x08,0x4c,0x1c,0x10,0x0a,0x07,0x67,0x09,0x0b,0x3b,0x05,0x05,0x43,0x1c,0x05,0x0e,0x06,0x0c,0x32,0x0f,0x1c,0x1a,0x10,0x01,0x0c,0x00, +0x00,0x09,0x00,0x00,0xff,0xf9,0x03,0xe8,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x4f,0x00,0x5f,0x00,0x6f,0x00,0x7f,0x00,0x8f,0x00,0x80,0x4b,0xb0,0x26,0x50,0x58,0x40,0x26,0x0f,0x09,0x02,0x03,0x0e,0x08,0x02,0x02,0x01,0x03,0x02,0x67,0x0b,0x05,0x02,0x01,0x0a,0x04,0x02,0x00,0x01,0x00,0x63,0x10,0x0c,0x02,0x06, +0x06,0x07,0x5f,0x11,0x0d,0x02,0x07,0x07,0x10,0x06,0x4e,0x1b,0x40,0x2e,0x11,0x0d,0x02,0x07,0x10,0x0c,0x02,0x06,0x03,0x07,0x06,0x67,0x0f,0x09,0x02,0x03,0x0e,0x08,0x02,0x02,0x01,0x03,0x02,0x67,0x0b,0x05,0x02,0x01,0x00,0x00,0x01,0x57,0x0b,0x05,0x02,0x01,0x01,0x00,0x5f,0x0a,0x04,0x02,0x00,0x01,0x00,0x4f,0x59,0x40,0x1e,0x8e, +0x8b,0x86,0x83,0x7e,0x7b,0x76,0x73,0x6e,0x6b,0x66,0x63,0x5e,0x5b,0x56,0x53,0x4e,0x4b,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x33,0x12,0x07,0x1f,0x2b,0x25,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x13,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15, +0x14,0x06,0x07,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x27,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x17,0x33,0x32,0x16,0x01,0x15, +0x14,0x06,0x2b,0x01,0x22,0x26,0x27,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x37,0x33,0x32,0x16,0x13,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x1e,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17, +0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0xfe,0x9c,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0xfe,0x9c,0x20,0x16,0xb2,0x17, +0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0x9a,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c,0x16,0x20,0x01,0x1e,0x01,0x06,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01,0x20,0xfe,0xcd,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c, +0x16,0x20,0x01,0x1e,0x02,0x24,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0xfe,0xcc,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01,0x20,0xfe,0xcd,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c,0x16,0x20,0x01,0x1e,0x02,0x24,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0xfe,0xcc,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01, +0x20,0x01,0x08,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0x00,0x05,0x00,0x00,0xff,0x6a,0x03,0xe8,0x03,0x52,0x00,0x10,0x00,0x14,0x00,0x25,0x00,0x2f,0x00,0x39,0x00,0x65,0x40,0x62,0x33,0x29,0x02,0x07,0x08,0x21,0x01,0x05,0x02,0x1d,0x15,0x0d,0x0c,0x04,0x00,0x05,0x03,0x4c,0x04,0x01,0x05,0x01,0x4b,0x0a,0x01,0x08,0x09,0x01, +0x07,0x01,0x08,0x07,0x67,0x00,0x02,0x05,0x01,0x02,0x57,0x06,0x0c,0x03,0x0b,0x04,0x01,0x00,0x05,0x00,0x01,0x05,0x69,0x06,0x0c,0x03,0x0b,0x04,0x01,0x01,0x00,0x5f,0x04,0x01,0x00,0x01,0x00,0x4f,0x11,0x11,0x00,0x00,0x37,0x35,0x32,0x31,0x2d,0x2b,0x28,0x27,0x24,0x22,0x1f,0x1e,0x1b,0x19,0x11,0x14,0x11,0x14,0x13,0x12,0x00,0x10, +0x00,0x0f,0x37,0x0d,0x07,0x17,0x2b,0x01,0x11,0x14,0x06,0x07,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x13,0x36,0x33,0x21,0x11,0x23,0x11,0x01,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x22,0x26,0x27,0x11,0x33,0x32,0x17,0x25,0x15,0x23,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x05,0x15,0x23,0x35,0x34,0x36,0x3b,0x01,0x32, +0x16,0x01,0x89,0x16,0x0e,0x14,0x10,0xfe,0xe3,0x0f,0x14,0x01,0x8b,0x04,0x0d,0x01,0x9f,0x8e,0x02,0x3b,0x16,0x0e,0xfe,0xe3,0x0f,0x14,0x01,0x0f,0x14,0x01,0xed,0x0d,0x04,0xfe,0x3e,0xc5,0x0a,0x08,0xa1,0x08,0x0a,0x01,0x77,0xc5,0x0a,0x08,0xa1,0x08,0x0a,0x02,0x9f,0xfe,0x54,0x0f,0x14,0x01,0xfe,0xbf,0x0f,0x14,0x01,0x16,0x0e,0x01, +0x1d,0x01,0xe8,0x0c,0xfe,0x78,0x01,0x88,0xfe,0x0c,0xfe,0xe3,0x0f,0x14,0x01,0x16,0x0e,0x01,0x41,0x16,0x0e,0x01,0xac,0x0c,0xad,0x7d,0x7d,0x08,0x0a,0x0a,0x08,0x7d,0x7d,0x08,0x0a,0x0a,0x00,0x08,0xff,0xff,0xff,0xf8,0x03,0xe9,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x4f,0x00,0x5f,0x00,0x6f,0x00,0x7f,0x00,0xad, +0x40,0x28,0x79,0x78,0x71,0x49,0x48,0x41,0x06,0x08,0x09,0x69,0x61,0x60,0x29,0x21,0x20,0x06,0x04,0x05,0x59,0x58,0x51,0x50,0x19,0x18,0x11,0x10,0x08,0x02,0x03,0x39,0x38,0x31,0x09,0x08,0x01,0x06,0x00,0x01,0x04,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x2a,0x0d,0x01,0x05,0x0c,0x01,0x04,0x03,0x05,0x04,0x67,0x0b,0x01,0x03,0x0a,0x01, +0x02,0x01,0x03,0x02,0x67,0x07,0x01,0x01,0x06,0x01,0x00,0x01,0x00,0x63,0x0e,0x01,0x08,0x08,0x09,0x5f,0x0f,0x01,0x09,0x09,0x10,0x08,0x4e,0x1b,0x40,0x31,0x0f,0x01,0x09,0x0e,0x01,0x08,0x05,0x09,0x08,0x67,0x0d,0x01,0x05,0x0c,0x01,0x04,0x03,0x05,0x04,0x67,0x0b,0x01,0x03,0x0a,0x01,0x02,0x01,0x03,0x02,0x67,0x07,0x01,0x01,0x00, +0x00,0x01,0x57,0x07,0x01,0x01,0x01,0x00,0x5f,0x06,0x01,0x00,0x01,0x00,0x4f,0x59,0x40,0x1a,0x7d,0x7b,0x75,0x73,0x6d,0x6b,0x65,0x64,0x5d,0x5b,0x55,0x54,0x4d,0x4c,0x26,0x26,0x17,0x26,0x17,0x17,0x17,0x17,0x14,0x10,0x07,0x1f,0x2b,0x37,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x27,0x15,0x14, +0x06,0x27,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x27,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x37,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15,0x14, +0x06,0x27,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x21,0x32,0x16,0x27,0x15,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x27,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x8f,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01, +0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x03,0x58,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0xfc,0xa6,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x03,0x58,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x01,0x0a,0x08,0xfd, +0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x01,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x76,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0xd0,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0xce,0x6b,0x07,0x0a,0x01,0x0c,0x06,0x6b,0x08,0x0a,0x0a,0xfe,0x4c,0x6b,0x07,0x0c, +0x01,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0x02,0x7d,0x6b,0x08,0x0a,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0xfe,0x4d,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0xce,0x6b,0x07,0x0a,0x01,0x0c,0x06,0x6b,0x08,0x0a,0x0a,0xcf,0x6b,0x08,0x0a,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x02,0x83, +0x03,0x0b,0x00,0x07,0x00,0x1f,0x00,0x47,0x4b,0xb0,0x26,0x50,0x58,0x40,0x14,0x05,0x03,0x02,0x00,0x00,0x02,0x00,0x02,0x63,0x00,0x01,0x01,0x04,0x61,0x00,0x04,0x04,0x10,0x01,0x4e,0x1b,0x40,0x1c,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x69,0x05,0x03,0x02,0x00,0x02,0x02,0x00,0x59,0x05,0x03,0x02,0x00,0x00,0x02,0x5f,0x00,0x02,0x00, +0x02,0x4f,0x59,0x40,0x09,0x23,0x13,0x25,0x36,0x13,0x10,0x06,0x07,0x1c,0x2b,0x13,0x21,0x35,0x34,0x26,0x0e,0x01,0x17,0x05,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x17,0x33,0x35,0x34,0x36,0x32,0x16,0x07,0x15,0x33,0x32,0x16,0xb3,0x01,0x1d,0x54,0x76,0x54,0x01,0x01,0xd0,0x20,0x16,0xfd,0xe9,0x17,0x1e,0x01,0x20, +0x16,0x11,0x94,0xcc,0x96,0x02,0x12,0x17,0x1e,0x01,0xa5,0x6c,0x3b,0x54,0x02,0x50,0x3d,0xa1,0xfe,0xbe,0x16,0x1e,0x01,0x20,0x15,0x01,0x42,0x16,0x20,0x01,0x6c,0x66,0x94,0x94,0x66,0x6c,0x1e,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xe2,0x02,0xda,0x02,0xda,0x00,0x06,0x00,0x26,0x40,0x23,0x06,0x01,0x01,0x00,0x01,0x4c,0x00,0x01, +0x00,0x4a,0x05,0x01,0x01,0x49,0x00,0x00,0x01,0x01,0x00,0x57,0x00,0x00,0x00,0x01,0x5f,0x00,0x01,0x00,0x01,0x4f,0x11,0x11,0x02,0x07,0x18,0x2b,0x01,0x15,0x21,0x11,0x21,0x15,0x01,0x01,0x7a,0x01,0x60,0xfe,0xa0,0xfe,0x86,0x02,0xda,0xbe,0xfe,0x86,0xc0,0x01,0x7c,0x00,0x00,0x02,0xff,0xff,0xff,0xb1,0x04,0x2f,0x03,0x52,0x00,0x0f, +0x00,0x2f,0x00,0x2e,0x40,0x2b,0x09,0x01,0x02,0x01,0x00,0x20,0x01,0x03,0x02,0x02,0x4c,0x00,0x05,0x00,0x00,0x01,0x05,0x00,0x67,0x00,0x01,0x04,0x01,0x02,0x03,0x01,0x02,0x67,0x00,0x03,0x03,0x11,0x03,0x4e,0x35,0x26,0x36,0x26,0x26,0x14,0x06,0x07,0x1c,0x2b,0x01,0x11,0x34,0x26,0x27,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x33,0x21, +0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x14,0x1e,0x01,0x17,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x34,0x3e,0x01,0x35,0x21,0x22,0x26,0x37,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0xe8,0x0a,0x08,0xfc,0x83,0x07,0x0a,0x01,0x0c,0x06,0x03,0x7d,0x07,0x0c,0x46,0x34,0x25,0xfe,0xd1,0x12,0x10,0x01,0x14,0x0f,0xfe,0xe2,0x0f,0x14,0x01, +0x12,0x12,0xfe,0xd0,0x24,0x36,0x01,0x34,0x25,0x03,0x7d,0x25,0x34,0x01,0x28,0x01,0xd1,0x07,0x0a,0x01,0x0c,0x06,0xfe,0x2f,0x07,0x0a,0x0a,0x01,0xd8,0xfd,0xa1,0x25,0x34,0x01,0x14,0x2e,0x22,0x07,0x0e,0x16,0x16,0x0e,0x08,0x22,0x2c,0x15,0x36,0x24,0x02,0x5f,0x25,0x34,0x34,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xe1,0x02,0xf8, +0x02,0xdb,0x00,0x21,0x00,0x31,0x00,0x71,0xb6,0x11,0x06,0x02,0x00,0x03,0x01,0x4c,0x4b,0xb0,0x1a,0x50,0x58,0x40,0x18,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x69,0x00,0x04,0x04,0x02,0x61,0x00,0x02,0x02,0x13,0x4d,0x00,0x01,0x01,0x14,0x01,0x4e,0x1b,0x4b,0xb0,0x1d,0x50,0x58,0x40,0x16,0x00,0x02,0x00,0x04,0x03,0x02,0x04,0x69,0x00, +0x03,0x00,0x00,0x01,0x03,0x00,0x69,0x00,0x01,0x01,0x14,0x01,0x4e,0x1b,0x40,0x1d,0x00,0x01,0x00,0x01,0x86,0x00,0x02,0x00,0x04,0x03,0x02,0x04,0x69,0x00,0x03,0x00,0x00,0x03,0x59,0x00,0x03,0x03,0x00,0x61,0x00,0x00,0x03,0x00,0x51,0x59,0x59,0xb7,0x15,0x2b,0x1d,0x25,0x22,0x05,0x07,0x1b,0x2b,0x01,0x0e,0x01,0x23,0x22,0x26,0x27, +0x0f,0x01,0x06,0x23,0x22,0x26,0x35,0x34,0x3f,0x02,0x2e,0x01,0x35,0x34,0x37,0x3e,0x01,0x32,0x17,0x16,0x17,0x16,0x15,0x14,0x07,0x06,0x25,0x1e,0x01,0x33,0x32,0x3e,0x01,0x34,0x2e,0x01,0x22,0x0e,0x01,0x15,0x14,0x16,0x02,0xa8,0x29,0x66,0x36,0x31,0x5d,0x28,0x33,0x82,0x15,0x18,0x1e,0x2d,0x0f,0x81,0x7e,0x20,0x22,0x27,0x25,0x80, +0x95,0x40,0x3f,0x26,0x26,0x14,0x14,0xfe,0x99,0x19,0x40,0x21,0x2d,0x4f,0x2e,0x2f,0x4e,0x5b,0x4f,0x2f,0x1a,0x01,0x00,0x29,0x2a,0x22,0x20,0x7d,0x82,0x0f,0x2f,0x1e,0x1a,0x13,0x82,0x33,0x26,0x5e,0x32,0x4b,0x40,0x3f,0x4b,0x27,0x25,0x3f,0x41,0x4a,0x38,0x32,0x34,0x24,0x18,0x1a,0x2e,0x4f,0x5d,0x4e,0x2e,0x2f,0x4e,0x2d,0x22,0x40, +0x00,0x02,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0c,0x00,0x19,0x00,0x47,0x4b,0xb0,0x26,0x50,0x58,0x40,0x16,0x04,0x01,0x00,0x00,0x03,0x61,0x00,0x03,0x03,0x10,0x4d,0x00,0x01,0x01,0x02,0x61,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x14,0x00,0x03,0x04,0x01,0x00,0x01,0x03,0x00,0x69,0x00,0x01,0x01,0x02,0x61,0x00,0x02, +0x02,0x11,0x02,0x4e,0x59,0x40,0x0f,0x01,0x00,0x17,0x16,0x11,0x10,0x07,0x06,0x00,0x0c,0x01,0x0c,0x05,0x07,0x16,0x2b,0x01,0x22,0x0e,0x02,0x1e,0x01,0x32,0x3e,0x01,0x2e,0x02,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x01,0xad,0x53,0x8c,0x50,0x02,0x54,0x88,0xaa,0x86,0x56,0x04,0x4e,0x8e,0x01,0x5b,0x72,0xc6, +0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x02,0x8e,0x52,0x8c,0xa4,0x8c,0x52,0x52,0x8c,0xa4,0x8c,0x52,0xfe,0xd0,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0xb1,0x03,0x4d,0x02,0xff,0x00,0x06,0x00,0x14,0x00,0x19,0x00,0x24,0x00,0xaa,0x40,0x17,0x1e,0x01,0x02,0x05,0x1d,0x16, +0x0e,0x07,0x04,0x03,0x02,0x19,0x03,0x02,0x03,0x00,0x03,0x01,0x01,0x01,0x00,0x04,0x4c,0x4b,0xb0,0x09,0x50,0x58,0x40,0x23,0x00,0x05,0x02,0x05,0x85,0x00,0x02,0x03,0x02,0x85,0x00,0x03,0x00,0x00,0x03,0x70,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x72,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x4b,0xb0,0x12,0x50, +0x58,0x40,0x22,0x00,0x05,0x02,0x05,0x85,0x00,0x02,0x03,0x02,0x85,0x00,0x03,0x00,0x03,0x85,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x72,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x40,0x23,0x00,0x05,0x02,0x05,0x85,0x00,0x02,0x03,0x02,0x85,0x00,0x03,0x00,0x03,0x85,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x04,0x80, +0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x59,0x59,0x40,0x12,0x00,0x00,0x21,0x20,0x18,0x17,0x10,0x0f,0x09,0x08,0x00,0x06,0x00,0x06,0x14,0x07,0x07,0x17,0x2b,0x17,0x37,0x27,0x07,0x15,0x33,0x15,0x01,0x34,0x23,0x22,0x07,0x01,0x06,0x15,0x14,0x33,0x32,0x37,0x01,0x36,0x27,0x17,0x01,0x23,0x35,0x01,0x14,0x0f,0x01, +0x27,0x37,0x36,0x32,0x1f,0x01,0x16,0xcb,0x32,0x83,0x33,0x48,0x01,0x5f,0x0c,0x05,0x04,0xfe,0xd1,0x04,0x0d,0x05,0x04,0x01,0x2f,0x03,0x1e,0xe8,0xfe,0x30,0xe8,0x03,0x4d,0x14,0x5d,0xe8,0x5d,0x14,0x3b,0x16,0x83,0x14,0x07,0x33,0x83,0x33,0x3c,0x47,0x02,0x06,0x0c,0x04,0xfe,0xd2,0x04,0x06,0x0c,0x04,0x01,0x2e,0x04,0x71,0xe8,0xfe, +0x2f,0xe9,0x01,0x9a,0x1d,0x15,0x5d,0xe9,0x5c,0x15,0x15,0x83,0x16,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xe2,0x02,0xda,0x02,0xda,0x00,0x06,0x00,0x26,0x40,0x23,0x01,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x01,0x4a,0x02,0x01,0x00,0x49,0x00,0x01,0x00,0x00,0x01,0x57,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x11,0x13, +0x02,0x07,0x18,0x2b,0x09,0x02,0x35,0x21,0x11,0x21,0x01,0x5e,0x01,0x7c,0xfe,0x84,0xfe,0xa2,0x01,0x5e,0x02,0xda,0xfe,0x84,0xfe,0x84,0xc0,0x01,0x7a,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xab,0x03,0x6b,0x03,0x20,0x00,0x0f,0x00,0x13,0x00,0x1f,0x00,0x38,0x40,0x35,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x0b, +0x03,0x02,0x01,0x4c,0x00,0x02,0x02,0x00,0x5f,0x04,0x01,0x00,0x00,0x10,0x4d,0x00,0x03,0x03,0x01,0x5f,0x00,0x01,0x01,0x11,0x01,0x4e,0x01,0x00,0x13,0x12,0x11,0x10,0x09,0x06,0x00,0x0f,0x01,0x0e,0x05,0x07,0x16,0x2b,0x13,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x05,0x21,0x11,0x21,0x01,0x07, +0x17,0x07,0x17,0x37,0x17,0x37,0x27,0x37,0x27,0x07,0x87,0x0c,0x11,0x11,0x0c,0x02,0xc6,0x0c,0x11,0x11,0x0c,0xfd,0x58,0x02,0x8b,0xfd,0x75,0x01,0x87,0x2d,0x52,0x52,0x2d,0x53,0x52,0x2e,0x53,0x53,0x2e,0x52,0x03,0x1f,0x12,0x0c,0xfc,0xc8,0x0c,0x11,0x11,0x0c,0x03,0x38,0x0c,0x12,0x3b,0xfd,0x02,0x02,0xcb,0x2e,0x52,0x53,0x2d,0x52, +0x52,0x2d,0x53,0x52,0x2e,0x52,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x84,0x03,0x8f,0x03,0x33,0x00,0x02,0x00,0x10,0x00,0x3c,0x00,0x68,0x00,0xf2,0x40,0x0b,0x01,0x01,0x0a,0x02,0x62,0x36,0x02,0x07,0x06,0x02,0x4c,0x4b,0xb0,0x0c,0x50,0x58,0x40,0x32,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x03,0x00,0x0a,0x03,0x57,0x0e,0x05,0x02,0x02, +0x0f,0x01,0x0a,0x06,0x02,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x04,0x11,0x02,0x00,0x00,0x13,0x00,0x4e,0x1b,0x4b,0xb0,0x16,0x50,0x58,0x40,0x36,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x03,0x04,0x0a,0x03,0x57,0x0e,0x05,0x02,0x02,0x0f,0x01,0x0a,0x06,0x02,0x0a, +0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x00,0x04,0x04,0x13,0x4d,0x11,0x01,0x00,0x00,0x13,0x00,0x4e,0x1b,0x40,0x39,0x12,0x01,0x01,0x03,0x01,0x85,0x11,0x01,0x00,0x04,0x02,0x04,0x00,0x02,0x80,0x00,0x03,0x04,0x0a,0x03,0x57,0x0e,0x05,0x02,0x02,0x0f,0x01,0x0a,0x06, +0x02,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x00,0x04,0x04,0x13,0x04,0x4e,0x59,0x59,0x40,0x2d,0x04,0x03,0x00,0x00,0x68,0x66,0x5e,0x5c,0x5b,0x59,0x4d,0x4b,0x4a,0x48,0x3f,0x3d,0x3c,0x3a,0x32,0x30,0x2f,0x2d,0x21,0x1f,0x1e,0x1c,0x13,0x11,0x0c,0x0b,0x0a,0x09, +0x08,0x07,0x03,0x10,0x04,0x0f,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x01,0x07,0x27,0x25,0x22,0x06,0x1d,0x01,0x33,0x35,0x21,0x15,0x33,0x35,0x34,0x26,0x23,0x13,0x33,0x32,0x16,0x1d,0x01,0x14,0x16,0x17,0x16,0x17,0x16,0x3b,0x01,0x15,0x23,0x22,0x07,0x06,0x07,0x06,0x07,0x06,0x1d,0x01,0x14,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32, +0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x36,0x37,0x36,0x37,0x36,0x3d,0x01,0x34,0x37,0x3e,0x02,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07,0x16,0x1d,0x01,0x14,0x3b,0x01,0x02,0x90,0x63,0x64,0xfe,0xcd,0x0d,0x13,0x3f,0x01,0x58, +0x3f,0x12,0x0d,0x55,0x1b,0x47,0x45,0x07,0x0b,0x09,0x12,0x0e,0x1c,0x0f,0x0f,0x1a,0x12,0x0f,0x0c,0x08,0x05,0x03,0x0f,0x22,0x34,0x27,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa8,0x1b,0x47,0x44,0x04,0x04,0x0b,0x09,0x23,0x18,0x10,0x10,0x1c,0x20,0x0a,0x08,0x05,0x04,0x07,0x07,0x23,0x33,0x27,0x1b,0x15,0x55,0x4e,0x4e,0x55,0x15,0x02, +0xb1,0xac,0xac,0x82,0x12,0x0d,0xe7,0xc7,0x2e,0x4e,0x0d,0x12,0xfe,0xfa,0x42,0x44,0x54,0x14,0x1b,0x09,0x0a,0x05,0x05,0x33,0x05,0x03,0x0a,0x08,0x0f,0x0d,0x14,0x80,0x1d,0x33,0x23,0x13,0x34,0x52,0x7f,0x5a,0x0a,0x09,0x5c,0x54,0x54,0xfd,0x8a,0x43,0x43,0x7e,0x0e,0x12,0x0e,0x0a,0x09,0x0b,0x33,0x08,0x09,0x08,0x0f,0x14,0x0d,0x57, +0x21,0x16,0x19,0x24,0x12,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf2,0x02,0xf8,0x02,0xcc,0x00,0x06,0x00,0x17,0x40,0x14,0x06,0x01,0x00,0x4a,0x02,0x01,0x00,0x01,0x00,0x85,0x00,0x01,0x01,0x76,0x11,0x11,0x10,0x03,0x07,0x19,0x2b,0x01,0x23,0x11,0x21,0x11,0x23,0x01,0x02,0xf8,0xc0,0xfe, +0x88,0xc0,0x01,0x7c,0x01,0x50,0xfe,0xa2,0x01,0x5e,0x01,0x7c,0x00,0x01,0x00,0x00,0x00,0x00,0x03,0xa5,0x02,0x98,0x00,0x15,0x00,0x1d,0x40,0x1a,0x0f,0x01,0x00,0x01,0x01,0x4c,0x00,0x02,0x01,0x02,0x85,0x00,0x01,0x00,0x01,0x85,0x00,0x00,0x00,0x76,0x14,0x17,0x14,0x03,0x07,0x19,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x26, +0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x01,0x36,0x32,0x1f,0x01,0x16,0x03,0xa5,0x10,0xfe,0x20,0x10,0x2c,0x10,0xfe,0xea,0x0f,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0x01,0x6e,0x10,0x2c,0x10,0x4c,0x10,0x02,0x16,0x16,0x10,0xfe,0x20,0x0f,0x0f,0x01,0x16,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa5,0x01,0x6f,0x10,0x10,0x4c,0x0f,0x00,0x03,0xff,0xf5, +0xff,0xb1,0x03,0xf3,0x03,0x52,0x00,0x0f,0x00,0x21,0x00,0x33,0x00,0x33,0x40,0x30,0x1b,0x11,0x02,0x03,0x02,0x09,0x01,0x02,0x01,0x00,0x02,0x4c,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x67,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x01,0x04,0x5f,0x00,0x04,0x04,0x11,0x04,0x4e,0x17,0x38,0x27,0x27,0x26,0x23,0x06,0x07,0x1c, +0x2b,0x25,0x35,0x34,0x26,0x2b,0x01,0x22,0x06,0x1d,0x01,0x14,0x16,0x17,0x33,0x32,0x36,0x27,0x13,0x34,0x27,0x26,0x2b,0x01,0x22,0x07,0x06,0x15,0x17,0x14,0x16,0x37,0x33,0x32,0x36,0x03,0x01,0x16,0x07,0x0e,0x01,0x07,0x21,0x22,0x26,0x27,0x26,0x37,0x01,0x3e,0x01,0x32,0x16,0x02,0x3b,0x0a,0x07,0x6c,0x07,0x0a,0x0a,0x07,0x6c,0x07, +0x0a,0x01,0x0a,0x05,0x07,0x07,0x7a,0x06,0x08,0x05,0x09,0x0c,0x07,0x67,0x08,0x0c,0x08,0x01,0xac,0x14,0x15,0x09,0x22,0x12,0xfc,0xa6,0x12,0x22,0x09,0x15,0x14,0x01,0xad,0x09,0x22,0x26,0x22,0x53,0x6a,0x08,0x0a,0x0a,0x08,0x6a,0x08,0x0a,0x01,0x0c,0xd7,0x01,0x01,0x06,0x04,0x06,0x06,0x04,0x08,0xff,0x05,0x08,0x01,0x06,0x02,0x10, +0xfc,0xee,0x23,0x23,0x11,0x12,0x01,0x14,0x10,0x23,0x23,0x03,0x12,0x11,0x14,0x14,0x00,0x04,0x00,0x00,0xff,0x79,0x03,0xd1,0x03,0x3c,0x00,0x0f,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x36,0x40,0x33,0x07,0x01,0x05,0x03,0x01,0x01,0x05,0x01,0x63,0x06,0x01,0x04,0x04,0x00,0x5f,0x09,0x02,0x08,0x03,0x00,0x00,0x12,0x04,0x4e,0x11,0x10, +0x01,0x00,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x19,0x16,0x10,0x1f,0x11,0x1e,0x09,0x06,0x00,0x0f,0x01,0x0e,0x0a,0x07,0x16,0x2b,0x13,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x33,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x05,0x21,0x11,0x21,0x01,0x21, +0x11,0x21,0x38,0x0d,0x13,0x13,0x0d,0x01,0x7c,0x0d,0x12,0x12,0x0d,0x80,0x0d,0x12,0x12,0x0d,0x01,0x7d,0x0d,0x12,0x12,0x0d,0xfc,0xa6,0x01,0x3e,0xfe,0xc2,0x01,0xfc,0x01,0x3e,0xfe,0xc2,0x03,0x3b,0x12,0x0d,0xfc,0x7d,0x0d,0x12,0x12,0x0d,0x03,0x83,0x0d,0x12,0x12,0x0d,0xfc,0x7d,0x0d,0x12,0x12,0x0d,0x03,0x83,0x0d,0x12,0x3e,0xfc, +0xbb,0x03,0x45,0xfc,0xbb,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x7e,0x03,0xd6,0x03,0x37,0x00,0x0f,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x3d,0x40,0x3a,0x00,0x04,0x00,0x01,0x02,0x04,0x01,0x67,0x00,0x02,0x09,0x01,0x07,0x06,0x02,0x07,0x67,0x00,0x06,0x00,0x03,0x06,0x03,0x63,0x08,0x01,0x05,0x05,0x00,0x5f,0x00,0x00,0x00,0x12, +0x05,0x4e,0x24,0x24,0x20,0x20,0x24,0x27,0x24,0x27,0x26,0x25,0x20,0x23,0x20,0x23,0x14,0x35,0x35,0x35,0x32,0x0a,0x07,0x1b,0x2b,0x01,0x34,0x26,0x23,0x21,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x15,0x34,0x26,0x23,0x21,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x03,0x11,0x21,0x11,0x01,0x11,0x21, +0x11,0x03,0xd5,0x12,0x0d,0xfc,0x7d,0x0d,0x13,0x13,0x0d,0x03,0x83,0x0d,0x12,0x12,0x0d,0xfc,0x7d,0x0d,0x13,0x13,0x0d,0x03,0x83,0x0d,0x12,0x3f,0xfc,0xbc,0x03,0x44,0xfc,0xbc,0x03,0x17,0x0d,0x12,0x12,0x0d,0xfe,0x84,0x0d,0x12,0x12,0x0d,0x80,0x0d,0x12,0x12,0x0d,0xfe,0x83,0x0d,0x12,0x12,0x0d,0x03,0x5a,0xfe,0xc2,0x01,0x3e,0xfe, +0x04,0xfe,0xc1,0x01,0x3f,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x89,0x03,0xdc,0x03,0x38,0x00,0x02,0x00,0x10,0x00,0x39,0x00,0x62,0x00,0xcc,0x40,0x0b,0x01,0x01,0x06,0x0a,0x5c,0x33,0x02,0x07,0x06,0x02,0x4c,0x4b,0xb0,0x21,0x50,0x58,0x40,0x3f,0x12,0x01,0x01,0x03,0x01,0x85,0x04,0x11,0x02,0x00,0x03,0x02,0x03,0x00,0x02,0x80, +0x0e,0x05,0x02,0x02,0x0a,0x03,0x02,0x0a,0x7e,0x00,0x03,0x0f,0x01,0x0a,0x06,0x03,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x6a,0x10,0x01,0x09,0x08,0x08,0x09,0x59,0x10,0x01,0x09,0x09,0x08,0x61,0x0b,0x01,0x08,0x09,0x08,0x51,0x1b,0x40,0x45,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x04,0x03,0x00,0x03,0x04,0x00,0x80, +0x11,0x01,0x00,0x02,0x03,0x00,0x02,0x7e,0x0e,0x05,0x02,0x02,0x0a,0x03,0x02,0x0a,0x7e,0x00,0x03,0x0f,0x01,0x0a,0x06,0x03,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x6a,0x10,0x01,0x09,0x08,0x08,0x09,0x59,0x10,0x01,0x09,0x09,0x08,0x61,0x0b,0x01,0x08,0x09,0x08,0x51,0x59,0x40,0x2d,0x04,0x03,0x00,0x00,0x62,0x60, +0x58,0x56,0x55,0x53,0x4a,0x48,0x47,0x45,0x3c,0x3a,0x39,0x37,0x2f,0x2d,0x2c,0x2a,0x1f,0x1d,0x1c,0x1a,0x13,0x11,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x03,0x10,0x04,0x0f,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x01,0x07,0x27,0x25,0x22,0x06,0x1d,0x01,0x33,0x35,0x21,0x15,0x33,0x35,0x34,0x26,0x23,0x01,0x33,0x32,0x16,0x1d,0x01,0x14, +0x1e,0x02,0x3b,0x01,0x15,0x23,0x22,0x07,0x0e,0x02,0x1d,0x01,0x14,0x07,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x3e,0x02,0x3d,0x01,0x34,0x3e,0x02,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07, +0x16,0x1d,0x01,0x14,0x3b,0x01,0x03,0xdc,0x63,0x64,0xfd,0x31,0x0d,0x13,0x3f,0x02,0xf4,0x3f,0x12,0x0d,0xfe,0xb9,0x1b,0x47,0x45,0x07,0x16,0x22,0x18,0x10,0x10,0x16,0x16,0x10,0x14,0x07,0x08,0x06,0x21,0x38,0x25,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa8,0x1b,0x47,0x44,0x04,0x04,0x0b,0x09,0x23,0x18,0x10,0x10,0x1c,0x1f,0x15,0x07, +0x0f,0x21,0x34,0x27,0x1b,0x15,0x55,0x4d,0x4e,0x54,0x15,0x02,0x85,0xad,0xad,0xb3,0x12,0x0d,0xe7,0xc7,0x6d,0x8d,0x0d,0x12,0xfe,0xfa,0x42,0x44,0x54,0x14,0x1b,0x13,0x0a,0x33,0x04,0x04,0x12,0x1c,0x14,0x80,0x1d,0x1a,0x19,0x23,0x13,0x34,0x52,0x7f,0x5a,0x0a,0x09,0x5c,0x54,0x54,0xfd,0x8a,0x43,0x43,0x7e,0x0e,0x12,0x0e,0x0a,0x09, +0x0b,0x33,0x08,0x13,0x1a,0x14,0x57,0x20,0x30,0x23,0x13,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x03,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x23,0x00,0x33,0x00,0x43,0x00,0x7b,0x40,0x0f,0x18,0x01,0x03,0x04,0x13,0x01,0x02,0x00,0x03,0x06,0x01,0x01,0x00,0x03,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x24,0x05,0x01, +0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x00,0x01,0x07,0x04,0x01,0x69,0x00,0x07,0x00,0x08,0x07,0x08,0x63,0x00,0x06,0x06,0x09,0x5f,0x00,0x09,0x09,0x10,0x06,0x4e,0x1b,0x40,0x2a,0x00,0x09,0x00,0x06,0x04,0x09,0x06,0x67,0x05,0x01,0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x00,0x01,0x07,0x04,0x01,0x69,0x00, +0x07,0x08,0x08,0x07,0x57,0x00,0x07,0x07,0x08,0x5f,0x00,0x08,0x07,0x08,0x4f,0x59,0x40,0x0e,0x42,0x3f,0x35,0x35,0x36,0x14,0x23,0x26,0x14,0x23,0x23,0x0a,0x07,0x1f,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3d,0x01,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x35,0x34,0x36,0x3b,0x01,0x32,0x16, +0x1d,0x01,0x33,0x32,0x16,0x13,0x11,0x34,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x83,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x47,0x34,0x25, +0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x48,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x01,0x94,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x07,0x0a,0xc5,0x08,0x0a,0x0a,0x08,0xc5,0x0a,0xfe,0xff,0x01,0xd0,0x25,0x34,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x01,0xf4,0xfe, +0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x60,0x00,0x00,0x03,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x59,0xb6,0x09,0x01,0x02,0x00,0x01,0x01,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x1a,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x67,0x00,0x03,0x00,0x04,0x03,0x04,0x63,0x00,0x02,0x02,0x05, +0x5f,0x00,0x05,0x05,0x10,0x02,0x4e,0x1b,0x40,0x20,0x00,0x05,0x00,0x02,0x01,0x05,0x02,0x67,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x67,0x00,0x03,0x04,0x04,0x03,0x57,0x00,0x03,0x03,0x04,0x5f,0x00,0x04,0x03,0x04,0x4f,0x59,0x40,0x09,0x35,0x35,0x35,0x36,0x26,0x23,0x06,0x07,0x1c,0x2b,0x01,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x3d, +0x01,0x34,0x36,0x33,0x21,0x32,0x16,0x13,0x11,0x34,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x83,0x0a,0x08,0xfe,0x30,0x08,0x0a,0x0a,0x08,0x01,0xd0,0x08,0x0a,0x47,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01, +0xd0,0x25,0x34,0x48,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x01,0x94,0x24,0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0x0a,0xfe,0xff,0x01,0xd0,0x25,0x34,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x01,0xf4,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x60,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x58, +0x01,0xd4,0x00,0x15,0x00,0x21,0xb1,0x06,0x64,0x44,0x40,0x16,0x07,0x01,0x00,0x02,0x01,0x4c,0x00,0x02,0x00,0x02,0x85,0x01,0x01,0x00,0x00,0x76,0x17,0x14,0x14,0x03,0x07,0x19,0x2b,0xb1,0x06,0x00,0x44,0x25,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x07,0x06,0x22,0x2f,0x01,0x26,0x34,0x37,0x01,0x36,0x32,0x17,0x01,0x16,0x02,0x58,0x06, +0x1c,0x05,0x0e,0x06,0xdc,0xdb,0x05,0x10,0x04,0x1c,0x06,0x06,0x01,0x04,0x05,0x0e,0x06,0x01,0x04,0x06,0xbd,0x07,0x05,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x0e,0x06,0x01,0x04,0x06,0x06,0xfe,0xfc,0x05,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xff,0x89,0x03,0x42,0x03,0x33,0x00,0x0f,0x00,0x19,0x00,0x33,0x00,0x3f,0x00,0x4b, +0x00,0x57,0x00,0x8c,0x40,0x89,0x56,0x01,0x0c,0x0d,0x44,0x01,0x0a,0x0b,0x3e,0x01,0x08,0x09,0x03,0x4c,0x00,0x02,0x03,0x05,0x03,0x02,0x05,0x80,0x00,0x05,0x0d,0x03,0x05,0x0d,0x7e,0x00,0x0b,0x0c,0x0a,0x0c,0x0b,0x0a,0x80,0x00,0x0a,0x09,0x0c,0x0a,0x09,0x7e,0x00,0x09,0x08,0x0c,0x09,0x08,0x7e,0x10,0x01,0x08,0x07,0x0c,0x08,0x07, +0x7e,0x00,0x0d,0x11,0x01,0x0c,0x0b,0x0d,0x0c,0x67,0x00,0x07,0x00,0x01,0x07,0x01,0x64,0x06,0x04,0x0f,0x03,0x03,0x03,0x00,0x5f,0x0e,0x01,0x00,0x00,0x12,0x03,0x4e,0x4e,0x4c,0x36,0x34,0x10,0x10,0x01,0x00,0x54,0x52,0x4c,0x57,0x4e,0x57,0x48,0x45,0x42,0x40,0x3c,0x3a,0x34,0x3f,0x36,0x3f,0x32,0x2f,0x2a,0x28,0x25,0x22,0x1f,0x1d, +0x10,0x19,0x10,0x19,0x16,0x13,0x09,0x06,0x00,0x0f,0x01,0x0e,0x12,0x07,0x16,0x2b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x17,0x15,0x14,0x16,0x3b,0x01,0x32,0x36,0x3d,0x01,0x13,0x11,0x34,0x26,0x07,0x23,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x37,0x35,0x23,0x22,0x06,0x17,0x11,0x14,0x16, +0x33,0x21,0x32,0x36,0x27,0x21,0x22,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x07,0x14,0x27,0x21,0x22,0x26,0x37,0x34,0x33,0x21,0x32,0x15,0x14,0x06,0x27,0x21,0x22,0x35,0x34,0x36,0x17,0x21,0x32,0x16,0x07,0x14,0x02,0xa6,0x41,0x5a,0x01,0x5c,0x40,0xfd,0xf6,0x41,0x5a,0x01,0x5c,0x40,0x68,0x20,0x15,0xd0,0x16,0x1e,0x9c,0x1e,0x15,0x35, +0x3c,0x2c,0xd0,0x2b,0x3e,0x01,0x35,0x15,0x20,0x01,0x1e,0x16,0x02,0x0a,0x15,0x1e,0x68,0xfe,0x60,0x1a,0x0e,0x0c,0x01,0xa0,0x0b,0x10,0x01,0x1a,0xfe,0x60,0x0b,0x10,0x01,0x1a,0x01,0xa0,0x1a,0x0e,0x0c,0xfe,0x60,0x1a,0x0e,0x0c,0x01,0xa0,0x0b,0x10,0x01,0x03,0x33,0x5c,0x40,0xfd,0x8f,0x41,0x5c,0x5c,0x41,0x02,0x71,0x41,0x5a,0x01, +0x68,0x34,0x15,0x20,0x20,0x15,0x34,0xfd,0x5b,0x02,0x71,0x15,0x20,0x01,0x34,0x2b,0x3c,0x01,0x3e,0x2a,0x34,0x1e,0x16,0xfd,0x8f,0x15,0x20,0x20,0x49,0x19,0x0c,0x0e,0x01,0x10,0x0b,0x19,0x9d,0x0e,0x0c,0x19,0x19,0x0b,0x10,0x9d,0x19,0x0b,0x10,0x01,0x0e,0x0c,0x19,0x00,0x00,0x03,0x00,0x00,0xff,0xf9,0x04,0x29,0x03,0x0b,0x00,0x11, +0x00,0x27,0x00,0x45,0x00,0x88,0xb5,0x24,0x01,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x2b,0x00,0x07,0x04,0x03,0x04,0x07,0x03,0x80,0x00,0x03,0x02,0x04,0x03,0x02,0x7e,0x08,0x09,0x02,0x02,0x00,0x00,0x01,0x02,0x00,0x68,0x00,0x01,0x00,0x05,0x01,0x05,0x63,0x00,0x04,0x04,0x06,0x5f,0x00,0x06,0x06,0x10,0x04,0x4e,0x1b, +0x40,0x31,0x00,0x07,0x04,0x03,0x04,0x07,0x03,0x80,0x00,0x03,0x02,0x04,0x03,0x02,0x7e,0x00,0x06,0x00,0x04,0x07,0x06,0x04,0x67,0x08,0x09,0x02,0x02,0x00,0x00,0x01,0x02,0x00,0x68,0x00,0x01,0x05,0x05,0x01,0x57,0x00,0x01,0x01,0x05,0x5f,0x00,0x05,0x01,0x05,0x4f,0x59,0x40,0x17,0x13,0x12,0x42,0x40,0x3d,0x3b,0x38,0x35,0x30,0x2d, +0x21,0x1e,0x19,0x16,0x12,0x27,0x13,0x27,0x36,0x31,0x0a,0x07,0x18,0x2b,0x01,0x34,0x23,0x21,0x22,0x06,0x0f,0x01,0x06,0x15,0x14,0x33,0x21,0x32,0x36,0x3f,0x01,0x36,0x25,0x21,0x35,0x34,0x26,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x26,0x07,0x23,0x22,0x06,0x15,0x11,0x37,0x3e,0x01,0x05,0x14,0x0f,0x01,0x0e,0x01,0x23,0x21,0x22,0x26, +0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x17,0x15,0x33,0x32,0x16,0x17,0x16,0x03,0xe2,0x1e,0xfd,0xa1,0x16,0x34,0x0d,0xa4,0x0b,0x1e,0x02,0x5f,0x17,0x32,0x0f,0xa4,0x0a,0xfd,0x83,0x01,0xad,0x20,0x16,0xfe,0xbf,0x17,0x1e,0x01,0x1e,0x17,0xb3,0x16,0x20,0x8f,0x19,0x50,0x02,0xea,0x19,0xa5,0x18,0x52,0x25, +0xfd,0xa1,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x2f,0x34,0x48,0x01,0x6b,0x1e,0x34,0x0b,0x08,0x01,0x4b,0x13,0x18,0x11,0xcb,0x0d,0x09,0x14,0x1a,0x10,0xcb,0x0c,0x64,0x5a,0x16,0x20,0x01,0x20,0x16,0x24,0x16,0x20,0x01,0x1e,0x17,0xfe,0x24,0xaf,0x1e,0x26,0x5a,0x23,0x20,0xcb,0x1e,0x26,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33, +0x12,0x4a,0x33,0x5a,0x1a,0x1b,0x11,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xdc,0x01,0xcc,0x00,0x08,0x00,0x20,0x40,0x1d,0x02,0x01,0x00,0x01,0x01,0x00,0x59,0x02,0x01,0x00,0x00,0x01,0x61,0x00,0x01,0x00,0x01,0x51,0x01,0x00,0x05,0x04,0x00,0x08,0x01,0x08,0x03,0x07,0x16,0x2b,0x13,0x32,0x16,0x14,0x06,0x22,0x26,0x34,0x36,0x6e, +0x2e,0x40,0x40,0x5c,0x40,0x40,0x01,0xcc,0x40,0x5a,0x42,0x42,0x5a,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0xb8,0x03,0x94,0x03,0x1f,0x00,0x02,0x00,0x10,0x00,0x39,0x00,0x66,0x01,0x0d,0x40,0x0b,0x60,0x33,0x02,0x07,0x06,0x01,0x01,0x02,0x07,0x02,0x4c,0x4b,0xb0,0x13,0x50,0x58,0x40,0x38,0x00,0x02,0x07,0x09,0x07,0x02,0x09,0x80, +0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x08,0x12,0x04,0x11,0x05,0x00,0x01,0x09,0x00,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x1b,0x4b,0xb0,0x1a,0x50,0x58,0x40,0x3f,0x00,0x02,0x07,0x09,0x07,0x02,0x09,0x80, +0x12,0x04,0x11,0x03,0x00,0x08,0x01,0x08,0x00,0x01,0x80,0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x01,0x08,0x00,0x09,0x08,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x1b,0x40,0x45,0x00,0x02,0x07,0x09,0x07,0x02, +0x09,0x80,0x11,0x01,0x00,0x08,0x04,0x08,0x00,0x04,0x80,0x12,0x01,0x04,0x01,0x08,0x04,0x01,0x7e,0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x01,0x08,0x00,0x09,0x08,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x59, +0x59,0x40,0x2d,0x03,0x03,0x00,0x00,0x66,0x64,0x5c,0x5a,0x59,0x57,0x4a,0x48,0x47,0x45,0x3c,0x3a,0x39,0x37,0x2f,0x2d,0x2c,0x2a,0x20,0x1e,0x1d,0x1b,0x13,0x11,0x03,0x10,0x03,0x10,0x0d,0x0a,0x07,0x06,0x05,0x04,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x25,0x37,0x17,0x07,0x15,0x21,0x35,0x23,0x15,0x14,0x16,0x33,0x21,0x32,0x36, +0x3d,0x01,0x01,0x33,0x32,0x16,0x1d,0x01,0x14,0x17,0x1e,0x02,0x3b,0x01,0x15,0x23,0x22,0x0e,0x02,0x1d,0x01,0x14,0x07,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x3e,0x01,0x37,0x36,0x3d,0x01,0x34, +0x37,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07,0x16,0x1d,0x01,0x14,0x3b,0x01,0x02,0xcd,0x64,0x63,0x82,0xfe,0xa7,0x3e,0x12,0x0d,0x01,0x97,0x0d,0x13,0xfe,0xa0,0x1c,0x47,0x44,0x04,0x05,0x11,0x25,0x18,0x10,0x10,0x1c,0x20,0x14,0x07,0x07,0x07,0x22,0x35,0x26,0x1c,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa7, +0x1b,0x48,0x44,0x04,0x05,0x09,0x0a,0x23,0x18,0x0f,0x0f,0x1d,0x20,0x13,0x03,0x04,0x07,0x08,0x10,0x10,0x1b,0x1b,0x27,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0x6a,0xac,0xac,0x09,0x6a,0xb3,0xd3,0x0d,0x12,0x12,0x0d,0x8a,0x02,0xbe,0x42,0x44,0x54,0x14,0x0c,0x10,0x10,0x0c,0x33,0x08,0x14,0x19,0x15,0x80,0x21,0x16,0x19,0x23,0x12,0x33, +0x52,0x7f,0x59,0x0b,0x09,0x5c,0x54,0x54,0xfd,0x8b,0x42,0x43,0x7e,0x14,0x0c,0x10,0x08,0x0b,0x09,0x33,0x09,0x12,0x0e,0x0c,0x15,0x56,0x1a,0x1e,0x18,0x12,0x10,0x0b,0x09,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x00,0x00,0x03,0xff,0xfe,0x00,0x00,0x03,0xe8,0x02,0x60,0x00,0x20,0x00,0x24,0x00,0x28,0x00,0x36,0x40,0x33, +0x00,0x00,0x08,0x06,0x07,0x03,0x04,0x03,0x00,0x04,0x67,0x05,0x01,0x03,0x01,0x01,0x03,0x57,0x05,0x01,0x03,0x03,0x01,0x5f,0x02,0x01,0x01,0x03,0x01,0x4f,0x25,0x25,0x21,0x21,0x25,0x28,0x25,0x28,0x27,0x26,0x21,0x24,0x21,0x24,0x14,0x27,0x2a,0x18,0x09,0x07,0x1a,0x2b,0x11,0x26,0x37,0x25,0x36,0x17,0x16,0x0f,0x01,0x21,0x27,0x26, +0x37,0x36,0x17,0x05,0x16,0x07,0x03,0x06,0x23,0x21,0x26,0x2f,0x01,0x26,0x0f,0x01,0x06,0x23,0x21,0x26,0x27,0x37,0x17,0x21,0x37,0x33,0x17,0x21,0x37,0x02,0x0a,0x01,0x68,0x1d,0x0c,0x0b,0x19,0xe3,0x02,0x92,0xe4,0x19,0x0b,0x0e,0x1d,0x01,0x6a,0x0b,0x02,0x1b,0x08,0x19,0xfe,0xc7,0x19,0x06,0x31,0x27,0x35,0x32,0x06,0x1a,0xfe,0xc8, +0x1b,0x04,0x27,0x13,0x01,0x04,0x2b,0xdd,0x29,0x01,0x03,0x14,0x01,0x82,0x0d,0x0c,0xba,0x0b,0x1b,0x21,0x0c,0x68,0x68,0x10,0x1d,0x1b,0x0b,0xba,0x0c,0x0d,0xff,0x00,0x1e,0x02,0x18,0xdf,0x19,0x18,0xe0,0x1a,0x02,0x1c,0xe2,0xbd,0xbd,0xbd,0xbd,0x00,0x00,0x03,0x00,0x00,0xff,0x6a,0x03,0x59,0x03,0x52,0x00,0x13,0x00,0x1a,0x00,0x23, +0x00,0x39,0x40,0x36,0x14,0x01,0x02,0x04,0x01,0x4c,0x00,0x01,0x00,0x04,0x02,0x01,0x04,0x67,0x00,0x02,0x00,0x03,0x05,0x02,0x03,0x67,0x06,0x01,0x05,0x00,0x00,0x05,0x57,0x06,0x01,0x05,0x05,0x00,0x5f,0x00,0x00,0x05,0x00,0x4f,0x1b,0x1b,0x1b,0x23,0x1b,0x23,0x13,0x26,0x14,0x35,0x36,0x07,0x07,0x1b,0x2b,0x01,0x1e,0x01,0x15,0x11, +0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x17,0x07,0x15,0x33,0x26,0x2f,0x01,0x26,0x13,0x11,0x23,0x22,0x26,0x27,0x35,0x21,0x11,0x03,0x33,0x10,0x16,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x01,0xf4,0x16,0x36,0x0f,0x4a,0xd2,0x05,0x07,0xaf,0x06,0xc6,0xe8,0x17,0x1e,0x01,0xfe,0x53,0x02,0x7e, +0x10,0x34,0x18,0xfd,0x7e,0x17,0x1e,0x01,0x20,0x16,0x03,0x7c,0x17,0x1e,0x01,0x16,0x10,0x26,0xd2,0x11,0x06,0xaf,0x07,0xfc,0xb0,0x02,0x3c,0x20,0x15,0xe9,0xfc,0xa6,0x00,0x01,0x00,0x00,0xff,0xaa,0x03,0x11,0x03,0x13,0x00,0x0b,0x00,0x06,0xb3,0x07,0x02,0x01,0x32,0x2b,0x09,0x01,0x06,0x26,0x35,0x11,0x34,0x36,0x17,0x01,0x16,0x14, +0x03,0x04,0xfd,0x1b,0x0d,0x12,0x12,0x0d,0x02,0xe5,0x0d,0x01,0x4d,0xfe,0x64,0x07,0x0a,0x0f,0x03,0x36,0x0e,0x0c,0x08,0xfe,0x64,0x07,0x14,0x00,0x00,0x01,0xff,0xff,0xff,0xae,0x02,0x3c,0x03,0x0f,0x00,0x1d,0x00,0x31,0xb7,0x1b,0x1a,0x12,0x03,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0b,0x00,0x00,0x00,0x10,0x4d,0x00, +0x01,0x01,0x11,0x01,0x4e,0x1b,0x40,0x0b,0x00,0x00,0x00,0x01,0x5f,0x00,0x01,0x01,0x11,0x01,0x4e,0x59,0xb4,0x35,0x3d,0x02,0x07,0x18,0x2b,0x17,0x06,0x26,0x37,0x11,0x34,0x36,0x17,0x01,0x16,0x17,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x07,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x37,0x11,0x06,0x07,0x19,0x0a,0x10,0x01,0x0e,0x0b,0x01, +0x8c,0x05,0x03,0x14,0x0f,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48,0x0e,0x16,0x01,0x03,0x05,0x47,0x0b,0x06,0x0f,0x03,0x36,0x0e,0x08,0x0c,0xfe,0x74,0x05,0x05,0x01,0x7a,0x0e,0x16,0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x01,0x7b,0x06,0x05,0x00,0x00,0x00,0x03,0xff,0xfc,0xff,0x90,0x03,0x9a,0x03,0x2c,0x00,0x08,0x00,0x13,0x00,0x29, +0x00,0xa7,0x40,0x0d,0x0c,0x01,0x03,0x02,0x23,0x22,0x18,0x17,0x04,0x05,0x07,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x32,0x00,0x03,0x02,0x06,0x02,0x03,0x06,0x80,0x00,0x06,0x07,0x02,0x06,0x07,0x7e,0x00,0x07,0x05,0x02,0x07,0x05,0x7e,0x00,0x05,0x04,0x02,0x05,0x04,0x7e,0x0a,0x01,0x04,0x00,0x01,0x04,0x01,0x66,0x09,0x01,0x02, +0x02,0x00,0x61,0x08,0x01,0x00,0x00,0x12,0x02,0x4e,0x1b,0x40,0x39,0x00,0x03,0x02,0x06,0x02,0x03,0x06,0x80,0x00,0x06,0x07,0x02,0x06,0x07,0x7e,0x00,0x07,0x05,0x02,0x07,0x05,0x7e,0x00,0x05,0x04,0x02,0x05,0x04,0x7e,0x08,0x01,0x00,0x09,0x01,0x02,0x03,0x00,0x02,0x69,0x0a,0x01,0x04,0x01,0x01,0x04,0x59,0x0a,0x01,0x04,0x04,0x01, +0x62,0x00,0x01,0x04,0x01,0x52,0x59,0x40,0x1f,0x15,0x14,0x0a,0x09,0x01,0x00,0x26,0x24,0x20,0x1e,0x1b,0x19,0x14,0x29,0x15,0x29,0x10,0x0e,0x09,0x13,0x0a,0x13,0x05,0x04,0x00,0x08,0x01,0x08,0x0b,0x07,0x16,0x2b,0x01,0x36,0x00,0x12,0x00,0x04,0x00,0x02,0x00,0x17,0x22,0x06,0x15,0x06,0x16,0x33,0x32,0x36,0x35,0x34,0x03,0x32,0x36, +0x37,0x27,0x06,0x23,0x22,0x3f,0x01,0x36,0x23,0x22,0x06,0x07,0x17,0x36,0x33,0x32,0x0f,0x01,0x06,0x01,0xc6,0xbe,0x01,0x10,0x06,0xfe,0xf6,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0c,0xf2,0x2a,0x2e,0x02,0x22,0x20,0x26,0x2e,0xb4,0x1e,0x6c,0x34,0x12,0x30,0x18,0x0e,0x0a,0x2a,0x1a,0x30,0x1e,0x76,0x38,0x10,0x34,0x16,0x0c,0x0c,0x24,0x1a, +0x03,0x2a,0x02,0xfe,0xf8,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0a,0x01,0x7c,0x01,0x12,0x96,0x30,0x1a,0x1c,0x20,0x2c,0x20,0x3a,0xfd,0xae,0x34,0x34,0x18,0x24,0x26,0xa0,0x60,0x3a,0x2e,0x1a,0x22,0x22,0x98,0x68,0x00,0x01,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x31,0x00,0x6a,0x40,0x0b,0x2a,0x01,0x03,0x05,0x25,0x1d,0x02,0x04, +0x03,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x24,0x00,0x04,0x03,0x01,0x03,0x04,0x01,0x80,0x00,0x01,0x02,0x03,0x01,0x02,0x7e,0x00,0x03,0x03,0x05,0x61,0x00,0x05,0x05,0x10,0x4d,0x00,0x02,0x02,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x22,0x00,0x04,0x03,0x01,0x03,0x04,0x01,0x80,0x00,0x01,0x02,0x03,0x01,0x02,0x7e, +0x00,0x05,0x00,0x03,0x04,0x05,0x03,0x69,0x00,0x02,0x02,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x09,0x29,0x35,0x17,0x23,0x17,0x24,0x06,0x07,0x1c,0x2b,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x26,0x34,0x3f,0x01,0x36,0x16,0x17,0x1e,0x01,0x33,0x32,0x3e,0x03,0x2e,0x02,0x22,0x06,0x07,0x17,0x16,0x06,0x2b,0x01,0x22, +0x26,0x27,0x35,0x34,0x36,0x1f,0x01,0x3e,0x01,0x33,0x32,0x1e,0x02,0x03,0x59,0x44,0x72,0xa0,0x56,0x60,0xae,0x3c,0x04,0x05,0x4c,0x06,0x11,0x04,0x29,0x76,0x43,0x3a,0x68,0x50,0x2a,0x02,0x2e,0x4c,0x6c,0x6f,0x64,0x28,0x4d,0x11,0x13,0x17,0xfa,0x0f,0x14,0x01,0x2c,0x11,0x48,0x3c,0x9a,0x52,0x57,0x9e,0x74,0x42,0x01,0x5e,0x57,0x9e, +0x74,0x44,0x52,0x49,0x06,0x0e,0x04,0x4d,0x05,0x01,0x06,0x35,0x3a,0x2e,0x4c,0x6a,0x74,0x6a,0x4c,0x2e,0x28,0x25,0x4d,0x10,0x2d,0x16,0x0e,0xfa,0x18,0x13,0x12,0x48,0x39,0x3e,0x44,0x74,0x9e,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf9,0x02,0x83,0x03,0x53,0x00,0x23,0x00,0x3a,0x40,0x37,0x00,0x04,0x05,0x00,0x05,0x04,0x00,0x80, +0x00,0x03,0x00,0x05,0x04,0x03,0x05,0x69,0x02,0x06,0x02,0x00,0x01,0x01,0x00,0x59,0x02,0x06,0x02,0x00,0x00,0x01,0x5f,0x00,0x01,0x00,0x01,0x4f,0x01,0x00,0x20,0x1f,0x1b,0x18,0x14,0x13,0x10,0x0e,0x09,0x06,0x00,0x23,0x01,0x23,0x07,0x07,0x16,0x2b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x17, +0x33,0x35,0x34,0x36,0x1e,0x01,0x07,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x34,0x26,0x22,0x06,0x17,0x15,0x02,0x4d,0x17,0x1e,0x01,0x20,0x16,0xfd,0xe9,0x17,0x1e,0x01,0x20,0x16,0x11,0x94,0xcc,0x96,0x02,0x14,0x0f,0x24,0x0e,0x16,0x54,0x76,0x54,0x01,0x01,0xa5,0x1e,0x17,0xfe,0xbe,0x16,0x1e,0x01,0x20,0x15,0x01,0x42,0x16,0x20,0x01, +0xb3,0x67,0x94,0x02,0x90,0x69,0x0e,0x16,0x16,0x0e,0x3b,0x54,0x54,0x3b,0xb3,0x00,0x00,0x08,0x00,0x00,0xff,0x9f,0x03,0x8f,0x03,0x1d,0x00,0x04,0x00,0x09,0x00,0x0e,0x00,0x13,0x00,0x1b,0x00,0x23,0x00,0x2b,0x00,0x33,0x00,0x41,0x40,0x3e,0x21,0x20,0x15,0x14,0x0e,0x01,0x06,0x00,0x4a,0x31,0x30,0x25,0x24,0x10,0x09,0x06,0x01,0x49, +0x05,0x04,0x02,0x08,0x04,0x00,0x01,0x00,0x85,0x07,0x06,0x09,0x03,0x04,0x01,0x01,0x76,0x0f,0x0f,0x00,0x00,0x2d,0x2c,0x29,0x28,0x1d,0x1c,0x19,0x18,0x0f,0x13,0x0f,0x13,0x0b,0x0a,0x06,0x05,0x00,0x04,0x00,0x04,0x0a,0x07,0x16,0x2b,0x01,0x35,0x1e,0x01,0x17,0x07,0x33,0x0e,0x01,0x07,0x03,0x23,0x3e,0x01,0x37,0x11,0x15,0x2e,0x01, +0x27,0x01,0x35,0x1e,0x01,0x17,0x23,0x2e,0x01,0x01,0x23,0x3e,0x01,0x37,0x15,0x0e,0x01,0x01,0x15,0x2e,0x01,0x27,0x33,0x1e,0x01,0x01,0x33,0x0e,0x01,0x07,0x35,0x3e,0x01,0x02,0x09,0x3c,0x56,0x10,0xa2,0xa2,0x10,0x56,0x3c,0x71,0xa2,0x10,0x56,0x3c,0x3c,0x56,0x10,0x01,0x13,0x98,0xda,0x14,0x71,0x12,0x9a,0xfe,0x11,0x71,0x13,0xda, +0x99,0x6a,0x98,0x01,0x02,0x9a,0xd8,0x14,0x71,0x12,0x9a,0x01,0xef,0x71,0x15,0xd8,0x99,0x69,0x9a,0x01,0x97,0xa2,0x10,0x58,0x3a,0x71,0x3b,0x58,0x0f,0x01,0x13,0x3b,0x56,0x11,0xfe,0xed,0xa2,0x10,0x56,0x3c,0x01,0x86,0x71,0x13,0xda,0x99,0x6b,0x98,0xfe,0xfd,0x98,0xda,0x14,0x71,0x12,0x98,0xfe,0x0f,0x72,0x13,0xdc,0x98,0x6b,0x98, +0x01,0x03,0x99,0xda,0x14,0x72,0x12,0x98,0x00,0x04,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x03,0x00,0x21,0x00,0x31,0x00,0x45,0x00,0x8d,0x40,0x11,0x2b,0x2a,0x23,0x22,0x04,0x08,0x04,0x01,0x4c,0x0d,0x01,0x04,0x06,0x01,0x08,0x02,0x4b,0x4b,0xb0,0x26,0x50,0x58,0x40,0x2f,0x00,0x08,0x04,0x03,0x04,0x08,0x03,0x80,0x00,0x03, +0x06,0x04,0x03,0x06,0x7e,0x00,0x06,0x00,0x01,0x00,0x06,0x01,0x68,0x07,0x01,0x04,0x04,0x0a,0x5f,0x00,0x0a,0x0a,0x10,0x4d,0x05,0x02,0x02,0x00,0x00,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x40,0x2d,0x00,0x08,0x04,0x03,0x04,0x08,0x03,0x80,0x00,0x03,0x06,0x04,0x03,0x06,0x7e,0x00,0x0a,0x07,0x01,0x04,0x08,0x0a,0x04,0x67, +0x00,0x06,0x00,0x01,0x00,0x06,0x01,0x68,0x05,0x02,0x02,0x00,0x00,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x59,0x40,0x10,0x40,0x3d,0x38,0x35,0x17,0x26,0x33,0x11,0x13,0x3b,0x11,0x11,0x10,0x0b,0x07,0x1f,0x2b,0x17,0x21,0x35,0x21,0x05,0x33,0x11,0x34,0x26,0x2f,0x01,0x2e,0x01,0x07,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x35, +0x23,0x11,0x33,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x07,0x03,0x35,0x34,0x26,0x2b,0x01,0x22,0x06,0x17,0x15,0x14,0x16,0x37,0x33,0x32,0x36,0x05,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x1f,0x01,0x1e,0x01,0xd6,0x01,0xad,0xfe,0x53,0x01,0xf4,0x48,0x0c,0x05,0x9d,0x05,0x1c,0x08,0x1e,0x17,0xfe, +0xbe,0x16,0x1e,0x01,0x48,0x48,0x20,0x15,0x01,0xd1,0x16,0x20,0x01,0xd6,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x64,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x02,0x05,0x17,0x36,0x0f,0x9c,0x10,0x16,0x07,0xd6,0xd6,0x01,0xf4,0x08,0x1a,0x07,0x9c,0x06,0x0c,0x01,0xe8,0x16,0x20,0x20,0x16,0xe8,0xfd,0x36, +0xe8,0x16,0x20,0x20,0x16,0x01,0x1e,0xb2,0x08,0x0a,0x0a,0x08,0xb2,0x07,0x0c,0x01,0x0a,0x0a,0xfd,0xfa,0x16,0x20,0x20,0x16,0x02,0xee,0x16,0x20,0x18,0x0e,0x9d,0x0f,0x36,0x00,0x00,0x00,0x00,0x02,0xff,0xff,0xff,0xb1,0x03,0xe8,0x03,0x0b,0x00,0x03,0x00,0x13,0x00,0x3c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x15,0x00,0x01,0x01,0x03,0x5f, +0x00,0x03,0x03,0x10,0x4d,0x00,0x00,0x00,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x13,0x00,0x03,0x00,0x01,0x00,0x03,0x01,0x67,0x00,0x00,0x00,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0xb6,0x35,0x34,0x11,0x10,0x04,0x07,0x1a,0x2b,0x37,0x21,0x11,0x21,0x25,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x37,0x11,0x34,0x36, +0x37,0x21,0x32,0x16,0x8f,0x02,0xca,0xfd,0x36,0x03,0x59,0x34,0x25,0xfc,0xca,0x24,0x36,0x01,0x34,0x25,0x03,0x36,0x25,0x34,0x40,0x01,0xad,0xc4,0xfd,0x5a,0x25,0x34,0x01,0x36,0x24,0x02,0xa6,0x25,0x34,0x01,0x36,0x00,0x00,0x00,0x00,0x03,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x08,0x00,0x15,0x00,0x22,0x00,0x59,0x4b,0xb0, +0x26,0x50,0x58,0x40,0x1e,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x69,0x06,0x01,0x02,0x02,0x05,0x61,0x00,0x05,0x05,0x10,0x4d,0x00,0x03,0x03,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x40,0x1c,0x00,0x05,0x06,0x01,0x02,0x01,0x05,0x02,0x69,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x69,0x00,0x03,0x03,0x04,0x61,0x00,0x04,0x04,0x11, +0x04,0x4e,0x59,0x40,0x11,0x0a,0x09,0x20,0x1f,0x1a,0x19,0x10,0x0f,0x09,0x15,0x0a,0x15,0x13,0x12,0x07,0x07,0x18,0x2b,0x01,0x14,0x06,0x22,0x2e,0x01,0x36,0x32,0x16,0x27,0x22,0x0e,0x02,0x1e,0x01,0x32,0x3e,0x01,0x2e,0x02,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x02,0x3b,0x52,0x78,0x52,0x02,0x56,0x74,0x56, +0x90,0x53,0x8c,0x50,0x02,0x54,0x88,0xaa,0x86,0x56,0x04,0x4e,0x8e,0x01,0x5b,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x5e,0x3b,0x54,0x54,0x76,0x54,0x54,0xf5,0x52,0x8c,0xa4,0x8c,0x52,0x52,0x8c,0xa4,0x8c,0x52,0xfe,0xd0,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x00,0x00,0x02,0x00,0x00, +0xff,0x6a,0x02,0x83,0x03,0x0b,0x00,0x0b,0x00,0x2e,0x00,0x65,0xb6,0x07,0x01,0x02,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x1d,0x00,0x03,0x02,0x03,0x86,0x09,0x05,0x02,0x01,0x04,0x01,0x02,0x03,0x01,0x02,0x67,0x08,0x06,0x02,0x00,0x00,0x07,0x5f,0x00,0x07,0x07,0x10,0x00,0x4e,0x1b,0x40,0x24,0x00,0x03,0x02,0x03,0x86, +0x00,0x07,0x08,0x06,0x02,0x00,0x01,0x07,0x00,0x69,0x09,0x05,0x02,0x01,0x02,0x02,0x01,0x59,0x09,0x05,0x02,0x01,0x01,0x02,0x5f,0x04,0x01,0x02,0x01,0x02,0x4f,0x59,0x40,0x0e,0x2d,0x2c,0x13,0x33,0x11,0x14,0x22,0x33,0x15,0x15,0x13,0x0a,0x07,0x1f,0x2b,0x01,0x35,0x34,0x26,0x22,0x06,0x1d,0x01,0x14,0x16,0x32,0x36,0x05,0x14,0x06, +0x27,0x23,0x03,0x0e,0x01,0x07,0x23,0x22,0x27,0x03,0x23,0x22,0x26,0x27,0x34,0x36,0x33,0x11,0x22,0x2e,0x01,0x36,0x37,0x21,0x32,0x16,0x14,0x06,0x27,0x11,0x32,0x16,0x01,0x0c,0x0a,0x10,0x0a,0x0a,0x10,0x0a,0x01,0x77,0x16,0x0e,0xef,0x1d,0x01,0x0a,0x06,0x01,0x0f,0x02,0x2b,0xe1,0x0f,0x14,0x01,0x58,0x37,0x1d,0x2a,0x02,0x2e,0x1b, +0x01,0x65,0x1d,0x2a,0x2a,0x1d,0x37,0x58,0x01,0x70,0xfa,0x08,0x0a,0x0a,0x08,0xfa,0x08,0x0a,0x0a,0xbd,0x0e,0x16,0x01,0xfe,0xf2,0x07,0x08,0x01,0x0f,0x01,0x0f,0x14,0x0f,0x45,0x6e,0x01,0x1e,0x2a,0x3a,0x2a,0x01,0x2c,0x38,0x2c,0x01,0xfe,0xe2,0x6e,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5b,0x03,0x0b,0x00,0x24,0x00,0x47,0x00,0x81, +0x40,0x13,0x43,0x25,0x02,0x06,0x09,0x2f,0x01,0x05,0x06,0x17,0x01,0x03,0x02,0x08,0x01,0x01,0x03,0x04,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x29,0x00,0x09,0x07,0x01,0x05,0x02,0x09,0x05,0x67,0x00,0x06,0x06,0x08,0x61,0x00,0x08,0x08,0x10,0x4d,0x04,0x01,0x02,0x02,0x01,0x61,0x00,0x01,0x01,0x14,0x4d,0x00,0x03,0x03,0x00,0x61,0x00, +0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x27,0x00,0x08,0x00,0x06,0x05,0x08,0x06,0x69,0x00,0x09,0x07,0x01,0x05,0x02,0x09,0x05,0x67,0x04,0x01,0x02,0x02,0x01,0x61,0x00,0x01,0x01,0x14,0x4d,0x00,0x03,0x03,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x0e,0x46,0x45,0x26,0x25,0x25,0x36,0x25,0x26,0x35,0x14,0x24,0x0a,0x07,0x1f, +0x2b,0x01,0x14,0x15,0x0e,0x01,0x23,0x22,0x26,0x27,0x07,0x06,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x32,0x16,0x06,0x0f,0x01,0x1e,0x01,0x37,0x32,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x32,0x16,0x13,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x36,0x3f,0x01,0x26,0x23,0x22,0x06,0x07,0x06,0x07,0x06,0x2b,0x01,0x22,0x26,0x37,0x35,0x3e, +0x01,0x33,0x32,0x16,0x17,0x37,0x36,0x32,0x16,0x03,0x4b,0x24,0xe4,0x99,0x51,0x98,0x3c,0x48,0x0b,0x1c,0x16,0x16,0x0e,0xfa,0x0e,0x16,0x02,0x09,0x4d,0x28,0x64,0x37,0x4a,0x82,0x27,0x06,0x18,0x04,0x0c,0x6b,0x08,0x0a,0x0e,0x14,0x10,0xfa,0x0e,0x16,0x02,0x09,0x4d,0x52,0x70,0x4b,0x82,0x27,0x06,0x17,0x05,0x0c,0x6f,0x07,0x0c,0x01, +0x24,0xe6,0x99,0x51,0x9a,0x3c,0x48,0x0b,0x1c,0x18,0x01,0x05,0x03,0x01,0x96,0xba,0x3e,0x39,0x48,0x0b,0x16,0x0e,0xfa,0x0e,0x16,0x16,0x1c,0x0b,0x4d,0x24,0x2a,0x01,0x4a,0x3e,0x0a,0x38,0x0d,0x0c,0x01,0xb8,0xfa,0x0e,0x16,0x16,0x1c,0x0b,0x4d,0x4d,0x4a,0x3e,0x0a,0x38,0x0d,0x0c,0x06,0x04,0x96,0xba,0x3e,0x39,0x48,0x0b,0x16,0x00, +0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x39,0x40,0x09,0x18,0x10,0x08,0x00,0x04,0x00,0x01,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0d,0x03,0x01,0x01,0x01,0x10,0x4d,0x02,0x01,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0d,0x03,0x01,0x01,0x01,0x00,0x5f,0x02,0x01,0x00,0x00,0x11,0x00,0x4e,0x59, +0xb6,0x35,0x35,0x35,0x33,0x04,0x07,0x1a,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x05,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0x59,0x14,0x10,0xfe,0xe3,0x0f,0x14,0x01,0x16,0x0e,0x01,0x1d,0x0f,0x16,0xfe,0x0b,0x14,0x10,0xfe,0xe3,0x0f,0x14, +0x01,0x16,0x0e,0x01,0x1d,0x0f,0x16,0x02,0xe7,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x00,0x01,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x0f,0x00,0x30,0xb6,0x08,0x00,0x02,0x00,0x01,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0b,0x00,0x01,0x01, +0x10,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0b,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0xb4,0x35,0x33,0x02,0x07,0x18,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0x59,0x14,0x10,0xfc,0xef,0x0f,0x14,0x01,0x16,0x0e,0x03,0x11,0x0f,0x16,0x02,0xe7,0xfc, +0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x00,0x00,0x00,0x01,0xff,0xfe,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x30,0x00,0x69,0x40,0x0a,0x2d,0x01,0x01,0x05,0x09,0x01,0x00,0x01,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x24,0x00,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x00,0x03,0x02,0x01,0x03,0x02,0x7e,0x00,0x01,0x01,0x05, +0x61,0x00,0x05,0x05,0x10,0x4d,0x00,0x02,0x02,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x40,0x22,0x00,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x00,0x03,0x02,0x01,0x03,0x02,0x7e,0x00,0x05,0x00,0x01,0x00,0x05,0x01,0x69,0x00,0x02,0x02,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x59,0x40,0x09,0x27,0x27,0x13,0x27,0x24,0x33,0x06, +0x07,0x1c,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3f,0x01,0x26,0x23,0x22,0x0e,0x02,0x14,0x1e,0x02,0x33,0x32,0x36,0x37,0x3e,0x01,0x1f,0x01,0x1e,0x01,0x07,0x0e,0x01,0x07,0x22,0x2e,0x02,0x3e,0x03,0x33,0x32,0x16,0x17,0x37,0x36,0x16,0x03,0x59,0x14,0x10,0xfa,0x17,0x13,0x11,0x4d,0x52,0x70,0x3a,0x6a,0x4c,0x2e,0x2e,0x4c, +0x6a,0x3a,0x42,0x76,0x29,0x04,0x11,0x06,0x4c,0x05,0x02,0x06,0x3c,0xae,0x5f,0x57,0xa0,0x70,0x48,0x04,0x40,0x78,0x98,0x5b,0x52,0x98,0x3d,0x48,0x11,0x2c,0x02,0xc3,0xfa,0x0e,0x16,0x2d,0x10,0x4d,0x4d,0x2e,0x4c,0x6a,0x74,0x6a,0x4c,0x2e,0x3a,0x35,0x06,0x01,0x05,0x4d,0x04,0x0e,0x06,0x4a,0x50,0x01,0x44,0x74,0x9e,0xae,0x9e,0x74, +0x44,0x3e,0x39,0x48,0x12,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x58,0x01,0xe6,0x00,0x15,0x00,0x19,0x40,0x16,0x0f,0x01,0x00,0x01,0x01,0x4c,0x02,0x01,0x01,0x00,0x01,0x85,0x00,0x00,0x00,0x76,0x14,0x17,0x14,0x03,0x07,0x19,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x37, +0x36,0x32,0x1f,0x01,0x16,0x02,0x58,0x06,0xfe,0xfc,0x05,0x10,0x04,0xfe,0xfc,0x06,0x06,0x1c,0x05,0x0e,0x06,0xdb,0xdc,0x05,0x10,0x04,0x1c,0x06,0x01,0xb7,0x07,0x05,0xfe,0xfb,0x05,0x05,0x01,0x05,0x05,0x0e,0x06,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x00,0x00,0x00,0x03,0xff,0xfd,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x0c, +0x00,0x1c,0x00,0x2e,0x00,0x6a,0x40,0x0d,0x28,0x1e,0x02,0x05,0x04,0x16,0x15,0x0e,0x03,0x03,0x02,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x1e,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x67,0x00,0x04,0x04,0x00,0x61,0x06,0x01,0x00,0x00,0x10,0x4d,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x11,0x01,0x4e,0x1b,0x40,0x1c,0x06,0x01,0x00, +0x00,0x04,0x05,0x00,0x04,0x67,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x67,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x11,0x01,0x4e,0x59,0x40,0x13,0x01,0x00,0x2c,0x2a,0x23,0x21,0x1a,0x18,0x12,0x10,0x07,0x06,0x00,0x0c,0x01,0x0c,0x07,0x07,0x16,0x2b,0x01,0x32,0x1e,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x13,0x35,0x34,0x26, +0x2b,0x01,0x22,0x06,0x07,0x15,0x14,0x16,0x17,0x33,0x32,0x36,0x27,0x13,0x34,0x27,0x26,0x2b,0x01,0x22,0x07,0x06,0x15,0x13,0x14,0x16,0x3b,0x01,0x32,0x36,0x01,0xad,0x74,0xc6,0x72,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xc1,0x0a,0x07,0x6b,0x08,0x0a,0x01,0x0c,0x07,0x6b,0x07,0x0a,0x01,0x0a,0x06,0x05,0x08,0x7b,0x08,0x05,0x06, +0x0a,0x0a,0x09,0x67,0x08,0x0a,0x03,0x0b,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0xfd,0x48,0x6a,0x08,0x0a,0x0a,0x08,0x6a,0x08,0x0a,0x01,0x0c,0xc7,0x01,0x5a,0x07,0x03,0x05,0x05,0x03,0x07,0xfe,0xa6,0x06,0x08,0x08,0x00,0x01,0x00,0x00,0xff,0xef,0x02,0xd4,0x02,0x86,0x00,0x24,0x00,0x26,0x40,0x23,0x22,0x19,0x10,0x07, +0x04,0x00,0x02,0x01,0x4c,0x03,0x01,0x02,0x00,0x00,0x02,0x59,0x03,0x01,0x02,0x02,0x00,0x61,0x01,0x01,0x00,0x02,0x00,0x51,0x14,0x1c,0x14,0x14,0x04,0x07,0x1a,0x2b,0x25,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x07,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x27,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x37,0x36,0x32,0x1f,0x01,0x16, +0x14,0x0f,0x01,0x17,0x16,0x02,0xd4,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa4,0xa4,0x10,0x10,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x0f,0x0f,0xa4,0xa4,0x0f,0x70,0x16,0x10,0x4c,0x0f,0x0f,0xa5,0xa5,0x0f,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa4,0xa4,0x10, +0x10,0x4c,0x0f,0x2e,0x0f,0xa4,0xa4,0x0f,0x00,0x03,0x00,0x00,0xff,0xb1,0x03,0xc5,0x03,0x0b,0x00,0x0c,0x00,0x1c,0x00,0x2c,0x00,0x5c,0x40,0x0b,0x25,0x1d,0x02,0x04,0x05,0x00,0x01,0x01,0x00,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x1d,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x04,0x05,0x5f,0x00,0x05,0x05,0x10,0x4d, +0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x1b,0x00,0x05,0x00,0x04,0x03,0x05,0x04,0x67,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0x40,0x09,0x35,0x35,0x35,0x35,0x24,0x32,0x06,0x07,0x1c,0x2b,0x01,0x34,0x26,0x07,0x23,0x22,0x0e,0x01,0x16,0x17, +0x33,0x32,0x36,0x25,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x37,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x37,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x02,0x5f,0x14,0x10,0x8e,0x0f,0x14,0x02,0x18,0x0d,0x8e,0x0f,0x16,0x01,0x41,0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x23,0x14, +0x0f,0xfc,0xa6,0x0e,0x16,0x01,0x14,0x0f,0x03,0x5a,0x0e,0x16,0x01,0x82,0x0e,0x16,0x01,0x14,0x1e,0x14,0x01,0x16,0x79,0xfd,0xe8,0x0e,0x16,0x16,0x0e,0x02,0x18,0x0e,0x16,0x16,0xec,0x8f,0x0e,0x16,0x16,0x0e,0x8f,0x0e,0x16,0x16,0x00,0x05,0x00,0x00,0xff,0x88,0x03,0xac,0x03,0x34,0x00,0x43,0x00,0x4c,0x00,0x55,0x00,0x5e,0x00,0x67, +0x00,0x61,0x40,0x5e,0x3c,0x33,0x02,0x05,0x0a,0x1a,0x0f,0x02,0x01,0x05,0x2b,0x22,0x19,0x10,0x09,0x00,0x06,0x08,0x01,0x03,0x4c,0x07,0x01,0x05,0x03,0x01,0x01,0x08,0x05,0x01,0x67,0x00,0x0a,0x0f,0x0c,0x02,0x08,0x09,0x0a,0x08,0x69,0x10,0x0e,0x0d,0x03,0x09,0x04,0x02,0x02,0x00,0x09,0x00,0x65,0x00,0x0b,0x0b,0x06,0x61,0x00,0x06, +0x06,0x12,0x0b,0x4e,0x60,0x5f,0x64,0x63,0x5f,0x67,0x60,0x67,0x5d,0x5c,0x59,0x58,0x54,0x53,0x50,0x4f,0x4b,0x4a,0x15,0x36,0x16,0x37,0x18,0x36,0x16,0x36,0x14,0x11,0x07,0x1f,0x2b,0x25,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x34,0x2b,0x01,0x22,0x27,0x15,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x06,0x2b, +0x01,0x22,0x0e,0x01,0x1d,0x01,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x34,0x36,0x3b,0x01,0x32,0x3d,0x01,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07,0x15,0x14,0x3b,0x01,0x32,0x16,0x15,0x05,0x34,0x26,0x22,0x06,0x14,0x16,0x32,0x36,0x13,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x34,0x26,0x22,0x06,0x14,0x16, +0x32,0x36,0x05,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x03,0x64,0x48,0x46,0x64,0x46,0x48,0x4c,0x64,0x2c,0x22,0x48,0x46,0x64,0x46,0x48,0x1e,0x2e,0x64,0x22,0x26,0x06,0x48,0x46,0x64,0x46,0x48,0x56,0x58,0x64,0x4c,0x48,0x46,0x64,0x46,0x48,0x4e,0x64,0x56,0x56,0xfd,0x5a,0x2a,0x38,0x28,0x28,0x38,0x2a,0xd4,0x28,0x38,0x2a,0x2a, +0x38,0x28,0x8a,0x2a,0x38,0x28,0x28,0x38,0x2a,0x01,0x18,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x70,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x72,0x4e,0x0c,0xcc,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0xcc,0x0c,0x26,0x1c,0x0c,0x72,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x72,0x40,0x6c,0x34,0x8c,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c, +0x22,0x8c,0x34,0x6c,0x40,0xe2,0x1e,0x28,0x28,0x3a,0x28,0x28,0x02,0xd8,0x1c,0x28,0x28,0x3a,0x28,0x28,0xfd,0x26,0x1e,0x28,0x28,0x3a,0x28,0x28,0x28,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x23,0x00,0x33,0x00,0x6f,0x40,0x0a,0x0d,0x01,0x00,0x01,0x1f,0x01,0x04,0x03,0x02,0x4c, +0x4b,0xb0,0x24,0x50,0x58,0x40,0x26,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04,0x01,0x03,0x04,0x7e,0x00,0x01,0x01,0x07,0x5f,0x00,0x07,0x07,0x10,0x4d,0x00,0x04,0x04,0x06,0x60,0x00,0x06,0x06,0x11,0x06,0x4e,0x1b,0x40,0x24,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04,0x01,0x03,0x04, +0x7e,0x00,0x07,0x00,0x01,0x00,0x07,0x01,0x67,0x00,0x04,0x04,0x06,0x60,0x00,0x06,0x06,0x11,0x06,0x4e,0x59,0x40,0x0b,0x35,0x35,0x23,0x33,0x16,0x23,0x24,0x23,0x08,0x07,0x1e,0x2b,0x01,0x35,0x34,0x26,0x07,0x23,0x35,0x34,0x26,0x27,0x23,0x22,0x06,0x07,0x15,0x23,0x22,0x06,0x07,0x15,0x14,0x16,0x37,0x33,0x15,0x14,0x16,0x3b,0x01, +0x32,0x36,0x37,0x35,0x33,0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0xca,0x14,0x0f,0xb3,0x16,0x0e,0x47,0x0f,0x14,0x01,0xb2,0x0f,0x14,0x01,0x16,0x0e,0xb2,0x16,0x0e,0x47,0x0f,0x14,0x01,0xb3,0x0e,0x16,0x8e,0x5e,0x43,0xfd,0xe9,0x43,0x5e,0x5e,0x43,0x02,0x17,0x43,0x5e,0x01, +0x3a,0x48,0x0e,0x16,0x01,0xb3,0x0f,0x14,0x01,0x16,0x0e,0xb3,0x14,0x0f,0x48,0x0e,0x16,0x01,0xb3,0x0e,0x16,0x16,0x0e,0xb3,0x14,0x01,0x3f,0xfd,0xe8,0x42,0x5e,0x01,0x60,0x41,0x02,0x18,0x42,0x5e,0x01,0x60,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x3c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x15,0x00, +0x00,0x00,0x03,0x5f,0x00,0x03,0x03,0x10,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x13,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0xb6,0x35,0x35,0x26,0x33,0x04,0x07,0x1a,0x2b,0x01,0x35,0x34,0x26,0x07,0x21,0x22,0x06,0x07,0x15,0x14,0x16, +0x37,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0xca,0x14,0x0f,0xfe,0x0c,0x0f,0x14,0x01,0x16,0x0e,0x01,0xf4,0x0e,0x16,0x8e,0x5e,0x43,0xfd,0xe9,0x43,0x5e,0x5e,0x43,0x02,0x17,0x43,0x5e,0x01,0x3a,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48,0x0e,0x16,0x01,0x14,0x01,0x3f,0xfd, +0xe8,0x42,0x5e,0x01,0x60,0x41,0x02,0x18,0x42,0x5e,0x01,0x60,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0xa1,0x03,0x0b,0x00,0x17,0x00,0x2c,0x00,0x51,0x4b,0xb0,0x26,0x50,0x58,0x40,0x1a,0x00,0x05,0x00,0x00,0x02,0x05,0x00,0x67,0x00,0x02,0x00,0x03,0x02,0x03,0x63,0x00,0x01,0x01,0x04,0x5f,0x00,0x04,0x04,0x10,0x01,0x4e,0x1b,0x40,0x20, +0x00,0x04,0x00,0x01,0x05,0x04,0x01,0x67,0x00,0x05,0x00,0x00,0x02,0x05,0x00,0x67,0x00,0x02,0x03,0x03,0x02,0x57,0x00,0x02,0x02,0x03,0x5f,0x00,0x03,0x02,0x03,0x4f,0x59,0x40,0x09,0x23,0x35,0x35,0x35,0x35,0x33,0x06,0x07,0x1c,0x2b,0x25,0x11,0x34,0x26,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x26,0x07,0x23,0x22,0x06,0x15,0x11,0x14, +0x16,0x33,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x03,0x59,0x1e,0x17,0xfe,0x77,0x17,0x1e,0x01,0x1e,0x17,0xb3,0x16,0x20,0x20,0x16,0x02,0xa7,0x16,0x20,0x47,0x4a,0x33,0xfd,0x59,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x77,0x33,0x4a,0x76,0x01, +0x89,0x16,0x20,0x01,0x20,0x16,0x24,0x16,0x20,0x01,0x1e,0x17,0xfd,0xe8,0x16,0x20,0x20,0x01,0x9f,0xfe,0x77,0x33,0x4a,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33,0x12,0x4a,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0xf3,0xb7,0xb3,0x5f,0x0f,0x3c,0xf5,0x00,0x0f,0x03,0xe8,0x00,0x00,0x00,0x00,0xe1,0xa1,0x0d,0xf0, +0x00,0x00,0x00,0x00,0xe1,0xa1,0x0d,0xf1,0xff,0xf5,0xff,0x6a,0x04,0x2f,0x03,0x53,0x00,0x00,0x00,0x08,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x03,0x52,0xff,0x6a,0x00,0x00,0x04,0x2f,0xff,0xf5,0xff,0xf5,0x04,0x2f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c, +0x03,0xe8,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x80,0x00,0x00,0x03,0x11,0x00,0x00,0x00,0xf0,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x59,0xff,0xfd,0x03,0x59,0xff,0xfd,0x02,0x3b,0x00,0x00,0x03,0xa0,0x00,0x00,0x03,0x11,0x00,0x00,0x03,0xac,0x00,0x00,0x03,0xe8,0x00,0x00,0x01,0x65,0x00,0x00,0x01,0x65,0x00,0x00,0x02,0x3b,0xff,0xff, +0x01,0x65,0x00,0x00,0x01,0x65,0x00,0x00,0x03,0x98,0xff,0xfc,0x03,0x59,0x00,0x00,0x03,0xca,0x00,0x00,0x04,0x2f,0xff,0xff,0x03,0xa0,0x00,0x00,0x02,0xf8,0x00,0x00,0x03,0xd4,0xff,0xf7,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0xff,0xff,0x02,0x82,0x00,0x00,0x02,0xda,0x00,0x00, +0x04,0x2f,0xff,0xff,0x02,0xf8,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x59,0x00,0x00,0x02,0xda,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x02,0xf8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0xff,0xf5,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0x11,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x82,0x00,0x00, +0x03,0x42,0x00,0x00,0x04,0x2f,0x00,0x00,0x00,0xdc,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe7,0xff,0xfe,0x03,0x59,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x3b,0xff,0xff,0x03,0x98,0xff,0xfc,0x03,0x59,0x00,0x00,0x02,0x82,0x00,0x00,0x03,0xa0,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xe8,0xff,0xff,0x03,0x59,0xff,0xfd,0x02,0x82,0x00,0x00, +0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0xff,0xfe,0x02,0x82,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x11,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xac,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x01,0x0a,0x01,0xce,0x02,0x3a,0x02,0xb8,0x03,0x06, +0x03,0x34,0x03,0x60,0x04,0x0c,0x05,0x06,0x05,0x62,0x06,0x12,0x06,0x3c,0x06,0x5e,0x06,0x88,0x06,0xc0,0x06,0xf8,0x07,0xa0,0x08,0x00,0x08,0xd2,0x09,0x36,0x09,0x74,0x09,0x98,0x09,0xf2,0x0a,0x3a,0x0b,0x12,0x0c,0x18,0x0c,0xa4,0x0d,0xae,0x0e,0x06,0x0e,0x2c,0x0e,0x8e,0x0f,0x12,0x0f,0x64,0x0f,0xfa,0x10,0x22,0x10,0x76,0x11,0x7a, +0x11,0x98,0x11,0xd0,0x12,0x3a,0x12,0x96,0x12,0xf6,0x13,0xdc,0x14,0x78,0x14,0xee,0x15,0x28,0x15,0xec,0x16,0x96,0x16,0xba,0x17,0xc8,0x18,0x2a,0x18,0x82,0x18,0xa0,0x18,0xea,0x19,0x86,0x1a,0x06,0x1a,0x5a,0x1a,0xd6,0x1b,0x84,0x1b,0xc8,0x1c,0x30,0x1c,0xaa,0x1d,0x52,0x1d,0xa2,0x1d,0xd8,0x1e,0x56,0x1e,0x8c,0x1f,0x08,0x1f,0x56, +0x1f,0xc8,0x20,0x84,0x21,0x06,0x21,0x58,0x21,0xc3,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4c,0x00,0x90,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x42,0x00,0x7b,0x00,0x8d,0x00,0x00,0x00,0xba,0x0e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0xde,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x35,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x07,0x00,0x3d,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x08,0x00,0x44,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x4c,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x0b,0x00,0x54,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x06,0x00,0x08,0x00,0x5f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x2b,0x00,0x67,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x13,0x00,0x92,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x00,0x00,0x6a,0x00,0xa5,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x01,0x00,0x10,0x01,0x0f,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x02,0x00,0x0e, +0x01,0x1f,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x03,0x00,0x10,0x01,0x2d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x04,0x00,0x10,0x01,0x3d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x05,0x00,0x16,0x01,0x4d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x06,0x00,0x10,0x01,0x63,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0a,0x00,0x56,0x01,0x73,0x00,0x03, +0x00,0x01,0x04,0x09,0x00,0x0b,0x00,0x26,0x01,0xc9,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x43,0x29,0x20,0x32,0x30,0x32,0x33,0x20,0x62,0x79,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x61,0x75,0x74,0x68,0x6f,0x72,0x73,0x20,0x40,0x20,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x2e,0x63,0x6f,0x6d,0x66, +0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x30,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x47,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x76, +0x67,0x32,0x74,0x74,0x66,0x20,0x66,0x72,0x6f,0x6d,0x20,0x46,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x20,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x2e,0x63,0x6f,0x6d,0x00,0x43,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00, +0x74,0x00,0x20,0x00,0x28,0x00,0x43,0x00,0x29,0x00,0x20,0x00,0x32,0x00,0x30,0x00,0x32,0x00,0x33,0x00,0x20,0x00,0x62,0x00,0x79,0x00,0x20,0x00,0x6f,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x69,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x20,0x00,0x61,0x00,0x75,0x00,0x74,0x00,0x68,0x00,0x6f,0x00,0x72,0x00,0x73,0x00,0x20,0x00,0x40,0x00, +0x20,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x52,0x00,0x65,0x00,0x67,0x00,0x75,0x00,0x6c,0x00,0x61,0x00,0x72,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00, +0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x56,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x31,0x00,0x2e,0x00,0x30,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x47,0x00, +0x65,0x00,0x6e,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x65,0x00,0x64,0x00,0x20,0x00,0x62,0x00,0x79,0x00,0x20,0x00,0x73,0x00,0x76,0x00,0x67,0x00,0x32,0x00,0x74,0x00,0x74,0x00,0x66,0x00,0x20,0x00,0x66,0x00,0x72,0x00,0x6f,0x00,0x6d,0x00,0x20,0x00,0x46,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00, +0x6f,0x00,0x20,0x00,0x70,0x00,0x72,0x00,0x6f,0x00,0x6a,0x00,0x65,0x00,0x63,0x00,0x74,0x00,0x2e,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x00,0x00,0x00,0x02,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x01,0x02,0x01,0x03,0x01,0x04,0x01,0x05,0x01,0x06,0x01,0x07,0x01,0x08,0x01,0x09,0x01,0x0a,0x01,0x0b,0x01,0x0c,0x01,0x0d,0x01,0x0e,0x01,0x0f,0x01,0x10,0x01,0x11,0x01,0x12, +0x01,0x13,0x01,0x14,0x01,0x15,0x01,0x16,0x01,0x17,0x01,0x18,0x01,0x19,0x01,0x1a,0x01,0x1b,0x01,0x1c,0x01,0x1d,0x01,0x1e,0x01,0x1f,0x01,0x20,0x01,0x21,0x01,0x22,0x01,0x23,0x01,0x24,0x01,0x25,0x01,0x26,0x01,0x27,0x01,0x28,0x01,0x29,0x01,0x2a,0x01,0x2b,0x01,0x2c,0x01,0x2d,0x01,0x2e,0x01,0x2f,0x01,0x30,0x01,0x31,0x01,0x32, +0x01,0x33,0x01,0x34,0x01,0x35,0x01,0x36,0x01,0x37,0x01,0x38,0x01,0x39,0x01,0x3a,0x01,0x3b,0x01,0x3c,0x01,0x3d,0x01,0x3e,0x01,0x3f,0x01,0x40,0x01,0x41,0x01,0x42,0x01,0x43,0x01,0x44,0x01,0x45,0x01,0x46,0x01,0x47,0x01,0x48,0x01,0x49,0x01,0x4a,0x01,0x4b,0x01,0x4c,0x01,0x4d,0x00,0x0b,0x63,0x68,0x65,0x63,0x6b,0x2d,0x65,0x6d, +0x70,0x74,0x79,0x0d,0x66,0x6c,0x6f,0x77,0x2d,0x70,0x61,0x72,0x61,0x6c,0x6c,0x65,0x6c,0x05,0x74,0x72,0x61,0x73,0x68,0x09,0x66,0x6c,0x6f,0x77,0x2d,0x6c,0x69,0x6e,0x65,0x0c,0x70,0x6c,0x75,0x73,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x0d,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x06,0x63,0x69,0x72, +0x63,0x6c,0x65,0x08,0x64,0x6f,0x77,0x6e,0x2d,0x64,0x69,0x72,0x05,0x63,0x68,0x65,0x63,0x6b,0x0b,0x74,0x72,0x61,0x73,0x68,0x2d,0x65,0x6d,0x70,0x74,0x79,0x04,0x75,0x73,0x65,0x72,0x09,0x62,0x72,0x69,0x65,0x66,0x63,0x61,0x73,0x65,0x08,0x6c,0x65,0x66,0x74,0x2d,0x64,0x69,0x72,0x09,0x72,0x69,0x67,0x68,0x74,0x2d,0x64,0x69,0x72, +0x06,0x75,0x70,0x2d,0x64,0x69,0x72,0x0a,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x6c,0x65,0x66,0x74,0x0b,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x72,0x69,0x67,0x68,0x74,0x0c,0x68,0x65,0x6c,0x70,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x03,0x74,0x61,0x67,0x04,0x67,0x72,0x69,0x64,0x0b,0x66,0x6f,0x6c,0x64,0x65,0x72,0x2d,0x6f,0x70,0x65,0x6e, +0x06,0x66,0x6f,0x6c,0x64,0x65,0x72,0x09,0x64,0x6f,0x77,0x6e,0x2d,0x62,0x6f,0x6c,0x64,0x07,0x70,0x61,0x6c,0x65,0x74,0x74,0x65,0x07,0x64,0x6f,0x63,0x2d,0x69,0x6e,0x76,0x03,0x63,0x6f,0x67,0x02,0x74,0x68,0x0a,0x62,0x69,0x6e,0x6f,0x63,0x75,0x6c,0x61,0x72,0x73,0x04,0x6c,0x69,0x73,0x74,0x04,0x6c,0x6f,0x63,0x6b,0x09,0x6c,0x65, +0x66,0x74,0x2d,0x62,0x6f,0x6c,0x64,0x07,0x64,0x65,0x73,0x6b,0x74,0x6f,0x70,0x06,0x73,0x65,0x61,0x72,0x63,0x68,0x0c,0x63,0x69,0x72,0x63,0x6c,0x65,0x2d,0x65,0x6d,0x70,0x74,0x79,0x06,0x70,0x65,0x6e,0x63,0x69,0x6c,0x0a,0x72,0x69,0x67,0x68,0x74,0x2d,0x62,0x6f,0x6c,0x64,0x0b,0x63,0x6c,0x6f,0x73,0x65,0x5f,0x70,0x61,0x6e,0x65, +0x6c,0x08,0x73,0x74,0x65,0x70,0x69,0x6e,0x74,0x6f,0x07,0x75,0x70,0x2d,0x62,0x6f,0x6c,0x64,0x02,0x6f,0x6b,0x09,0x61,0x74,0x74,0x65,0x6e,0x74,0x69,0x6f,0x6e,0x10,0x68,0x6f,0x72,0x69,0x7a,0x6f,0x6e,0x74,0x61,0x6c,0x5f,0x73,0x70,0x6c,0x69,0x74,0x0e,0x76,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x5f,0x73,0x70,0x6c,0x69,0x74,0x08, +0x73,0x74,0x65,0x70,0x6f,0x76,0x65,0x72,0x10,0x70,0x6c,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x2d,0x61,0x6c,0x74,0x11,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x2d,0x61,0x6c,0x74,0x08,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x75,0x70,0x09,0x63,0x6c,0x69,0x70,0x62,0x6f,0x61,0x72,0x64,0x11,0x66, +0x6f,0x6c,0x64,0x65,0x72,0x2d,0x6f,0x70,0x65,0x6e,0x2d,0x65,0x6d,0x70,0x74,0x79,0x03,0x64,0x6f,0x74,0x07,0x73,0x74,0x65,0x70,0x6f,0x75,0x74,0x07,0x67,0x6c,0x61,0x73,0x73,0x65,0x73,0x03,0x64,0x6f,0x63,0x04,0x70,0x6c,0x61,0x79,0x06,0x74,0x6f,0x2d,0x65,0x6e,0x64,0x0c,0x69,0x6e,0x66,0x6f,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65, +0x64,0x03,0x63,0x63,0x77,0x0d,0x6c,0x6f,0x63,0x6b,0x2d,0x6f,0x70,0x65,0x6e,0x2d,0x61,0x6c,0x74,0x06,0x74,0x61,0x72,0x67,0x65,0x74,0x06,0x66,0x6c,0x6f,0x70,0x70,0x79,0x0f,0x77,0x69,0x6e,0x64,0x6f,0x77,0x2d,0x6d,0x61,0x78,0x69,0x6d,0x69,0x7a,0x65,0x0b,0x64,0x6f,0x74,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x03,0x70,0x69, +0x6e,0x09,0x61,0x72,0x72,0x6f,0x77,0x73,0x2d,0x63,0x77,0x05,0x70,0x61,0x75,0x73,0x65,0x04,0x73,0x74,0x6f,0x70,0x02,0x63,0x77,0x0a,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x64,0x6f,0x77,0x6e,0x11,0x61,0x74,0x74,0x65,0x6e,0x74,0x69,0x6f,0x6e,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x06,0x63,0x61,0x6e,0x63,0x65,0x6c,0x03,0x62,0x6f, +0x78,0x09,0x66,0x6c,0x6f,0x77,0x2d,0x74,0x72,0x65,0x65,0x0c,0x70,0x6c,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x0d,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x0c,0x66,0x6f,0x6c,0x64,0x65,0x72,0x2d,0x65,0x6d,0x70,0x74,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0xff,0xff,0x00,0x0f, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x7e,0x01,0x1e,0x00,0x7d,0x00,0x7d,0x01,0x1e,0x03,0x18,0xff,0xb1,0x03,0x38,0x02,0xc8,0xff,0xd0,0xff,0xb1,0x03,0x18,0xff,0xb1,0x03,0x38,0x02,0xc8,0xff,0xd0,0xff,0xb1,0xb0,0x00,0x2c,0x20,0xb0,0x00,0x55,0x58, +0x45,0x59,0x20,0x20,0x4b,0xb8,0x00,0x0e,0x51,0x4b,0xb0,0x06,0x53,0x5a,0x58,0xb0,0x34,0x1b,0xb0,0x28,0x59,0x60,0x66,0x20,0x8a,0x55,0x58,0xb0,0x02,0x25,0x61,0xb9,0x08,0x00,0x08,0x00,0x63,0x63,0x23,0x62,0x1b,0x21,0x21,0xb0,0x00,0x59,0xb0,0x00,0x43,0x23,0x44,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0x2d,0xb0,0x01,0x2c,0xb0,0x20, +0x60,0x66,0x2d,0xb0,0x02,0x2c,0x23,0x21,0x23,0x21,0x2d,0xb0,0x03,0x2c,0x20,0x64,0xb3,0x03,0x14,0x15,0x00,0x42,0x43,0xb0,0x13,0x43,0x20,0x60,0x60,0x42,0xb1,0x02,0x14,0x43,0x42,0xb1,0x25,0x03,0x43,0xb0,0x02,0x43,0x54,0x78,0x20,0xb0,0x0c,0x23,0xb0,0x02,0x43,0x43,0x61,0x64,0xb0,0x04,0x50,0x78,0xb2,0x02,0x02,0x02,0x43,0x60, +0x42,0xb0,0x21,0x65,0x1c,0x21,0xb0,0x02,0x43,0x43,0xb2,0x0e,0x15,0x01,0x42,0x1c,0x20,0xb0,0x02,0x43,0x23,0x42,0xb2,0x13,0x01,0x13,0x43,0x60,0x42,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb2,0x16,0x01,0x02,0x43,0x60,0x42,0x2d,0xb0,0x04,0x2c,0xb0,0x03,0x2b,0xb0,0x15,0x43,0x58,0x23,0x21,0x23,0x21,0xb0,0x16,0x43,0x43,0x23,0xb0, +0x00,0x50,0x58,0x65,0x59,0x1b,0x20,0x64,0x20,0xb0,0xc0,0x50,0xb0,0x04,0x26,0x5a,0xb2,0x28,0x01,0x0d,0x43,0x45,0x63,0x45,0xb0,0x06,0x45,0x58,0x21,0xb0,0x03,0x25,0x59,0x52,0x5b,0x58,0x21,0x23,0x21,0x1b,0x8a,0x58,0x20,0xb0,0x50,0x50,0x58,0x21,0xb0,0x40,0x59,0x1b,0x20,0xb0,0x38,0x50,0x58,0x21,0xb0,0x38,0x59,0x59,0x20,0xb1, +0x01,0x0d,0x43,0x45,0x63,0x45,0x61,0x64,0xb0,0x28,0x50,0x58,0x21,0xb1,0x01,0x0d,0x43,0x45,0x63,0x45,0x20,0xb0,0x30,0x50,0x58,0x21,0xb0,0x30,0x59,0x1b,0x20,0xb0,0xc0,0x50,0x58,0x20,0x66,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x0a,0x50,0x58,0x60,0x1b,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x0a,0x60,0x1b,0x20,0xb0,0x36,0x50,0x58,0x21, +0xb0,0x36,0x60,0x1b,0x60,0x59,0x59,0x59,0x1b,0xb0,0x02,0x25,0xb0,0x0c,0x43,0x63,0xb0,0x00,0x52,0x58,0xb0,0x00,0x4b,0xb0,0x0a,0x50,0x58,0x21,0xb0,0x0c,0x43,0x1b,0x4b,0xb0,0x1e,0x50,0x58,0x21,0xb0,0x1e,0x4b,0x61,0xb8,0x10,0x00,0x63,0xb0,0x0c,0x43,0x63,0xb8,0x05,0x00,0x62,0x59,0x59,0x64,0x61,0x59,0xb0,0x01,0x2b,0x59,0x59, +0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x59,0x20,0x64,0xb0,0x16,0x43,0x23,0x42,0x59,0x2d,0xb0,0x05,0x2c,0x20,0x45,0x20,0xb0,0x04,0x25,0x61,0x64,0x20,0xb0,0x07,0x43,0x50,0x58,0xb0,0x07,0x23,0x42,0xb0,0x08,0x23,0x42,0x1b,0x21,0x21,0x59,0xb0,0x01,0x60,0x2d,0xb0,0x06,0x2c,0x23,0x21,0x23,0x21,0xb0,0x03,0x2b,0x20,0x64,0xb1,0x07, +0x62,0x42,0x20,0xb0,0x08,0x23,0x42,0xb0,0x06,0x45,0x58,0x1b,0xb1,0x01,0x0d,0x43,0x45,0x63,0xb1,0x01,0x0d,0x43,0xb0,0x01,0x60,0x45,0x63,0xb0,0x05,0x2a,0x21,0x20,0xb0,0x08,0x43,0x20,0x8a,0x20,0x8a,0xb0,0x01,0x2b,0xb1,0x30,0x05,0x25,0xb0,0x04,0x26,0x51,0x58,0x60,0x50,0x1b,0x61,0x52,0x59,0x58,0x23,0x59,0x21,0x59,0x20,0xb0, +0x40,0x53,0x58,0xb0,0x01,0x2b,0x1b,0x21,0xb0,0x40,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x2d,0xb0,0x07,0x2c,0xb0,0x09,0x43,0x2b,0xb2,0x00,0x02,0x00,0x43,0x60,0x42,0x2d,0xb0,0x08,0x2c,0xb0,0x09,0x23,0x42,0x23,0x20,0xb0,0x00,0x23,0x42,0x61,0xb0,0x02,0x62,0x66,0xb0,0x01,0x63,0xb0,0x01,0x60,0xb0,0x07,0x2a,0x2d,0xb0,0x09, +0x2c,0x20,0x20,0x45,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x44,0xb0,0x01,0x60,0x2d,0xb0,0x0a,0x2c,0xb2,0x09,0x0e,0x00,0x43,0x45,0x42,0x2a,0x21,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0x2d,0xb0,0x0b,0x2c,0xb0,0x00,0x43,0x23,0x44,0xb2,0x00,0x01,0x00, +0x43,0x60,0x42,0x2d,0xb0,0x0c,0x2c,0x20,0x20,0x45,0x20,0xb0,0x01,0x2b,0x23,0xb0,0x00,0x43,0xb0,0x04,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x00,0x1b,0xb0,0x30,0x50,0x58,0xb0,0x20,0x1b,0xb0,0x40,0x59,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb0,0x03,0x25,0x23,0x61,0x44,0x44,0xb0, +0x01,0x60,0x2d,0xb0,0x0d,0x2c,0x20,0x20,0x45,0x20,0xb0,0x01,0x2b,0x23,0xb0,0x00,0x43,0xb0,0x04,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64,0xb0,0x24,0x50,0x58,0xb0,0x00,0x1b,0xb0,0x40,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb0,0x03,0x25,0x23,0x61,0x44,0x44,0xb0,0x01,0x60,0x2d,0xb0,0x0e,0x2c,0x20,0xb0,0x00,0x23,0x42, +0xb3,0x0d,0x0c,0x00,0x03,0x45,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x2a,0x21,0x2d,0xb0,0x0f,0x2c,0xb1,0x02,0x02,0x45,0xb0,0x64,0x61,0x44,0x2d,0xb0,0x10,0x2c,0xb0,0x01,0x60,0x20,0x20,0xb0,0x0f,0x43,0x4a,0xb0,0x00,0x50,0x58,0x20,0xb0,0x0f,0x23,0x42,0x59,0xb0,0x10,0x43,0x4a,0xb0,0x00,0x52,0x58,0x20,0xb0,0x10,0x23,0x42,0x59, +0x2d,0xb0,0x11,0x2c,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0x20,0xb8,0x04,0x00,0x63,0x8a,0x23,0x61,0xb0,0x11,0x43,0x60,0x20,0x8a,0x60,0x20,0xb0,0x11,0x23,0x42,0x23,0x2d,0xb0,0x12,0x2c,0x4b,0x54,0x58,0xb1,0x04,0x64,0x44,0x59,0x24,0xb0,0x0d,0x65,0x23,0x78,0x2d,0xb0,0x13,0x2c,0x4b,0x51,0x58,0x4b,0x53,0x58,0xb1,0x04,0x64, +0x44,0x59,0x1b,0x21,0x59,0x24,0xb0,0x13,0x65,0x23,0x78,0x2d,0xb0,0x14,0x2c,0xb1,0x00,0x12,0x43,0x55,0x58,0xb1,0x12,0x12,0x43,0xb0,0x01,0x61,0x42,0xb0,0x11,0x2b,0x59,0xb0,0x00,0x43,0xb0,0x02,0x25,0x42,0xb1,0x0f,0x02,0x25,0x42,0xb1,0x10,0x02,0x25,0x42,0xb0,0x01,0x16,0x23,0x20,0xb0,0x03,0x25,0x50,0x58,0xb1,0x01,0x00,0x43, +0x60,0xb0,0x04,0x25,0x42,0x8a,0x8a,0x20,0x8a,0x23,0x61,0xb0,0x10,0x2a,0x21,0x23,0xb0,0x01,0x61,0x20,0x8a,0x23,0x61,0xb0,0x10,0x2a,0x21,0x1b,0xb1,0x01,0x00,0x43,0x60,0xb0,0x02,0x25,0x42,0xb0,0x02,0x25,0x61,0xb0,0x10,0x2a,0x21,0x59,0xb0,0x0f,0x43,0x47,0xb0,0x10,0x43,0x47,0x60,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0, +0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb1,0x00,0x00,0x13,0x23,0x44,0xb0,0x01,0x43,0xb0,0x00,0x3e,0xb2,0x01,0x01,0x01,0x43,0x60,0x42,0x2d,0xb0,0x15,0x2c,0x00,0xb1,0x00,0x02,0x45,0x54,0x58,0xb0,0x12,0x23,0x42, +0x20,0x45,0xb0,0x0e,0x23,0x42,0xb0,0x0d,0x23,0xb0,0x01,0x60,0x42,0x20,0x60,0xb7,0x18,0x18,0x01,0x00,0x11,0x00,0x13,0x00,0x42,0x42,0x42,0x8a,0x60,0x20,0xb0,0x14,0x23,0x42,0xb0,0x01,0x61,0xb1,0x14,0x08,0x2b,0xb0,0x8b,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x16,0x2c,0xb1,0x00,0x15,0x2b,0x2d,0xb0,0x17,0x2c,0xb1,0x01,0x15,0x2b,0x2d, +0xb0,0x18,0x2c,0xb1,0x02,0x15,0x2b,0x2d,0xb0,0x19,0x2c,0xb1,0x03,0x15,0x2b,0x2d,0xb0,0x1a,0x2c,0xb1,0x04,0x15,0x2b,0x2d,0xb0,0x1b,0x2c,0xb1,0x05,0x15,0x2b,0x2d,0xb0,0x1c,0x2c,0xb1,0x06,0x15,0x2b,0x2d,0xb0,0x1d,0x2c,0xb1,0x07,0x15,0x2b,0x2d,0xb0,0x1e,0x2c,0xb1,0x08,0x15,0x2b,0x2d,0xb0,0x1f,0x2c,0xb1,0x09,0x15,0x2b,0x2d, +0xb0,0x2b,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x06,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x5d,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2c,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x16,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x71,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2d,0x2c,0x23,0x20,0xb0, +0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x26,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x72,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x20,0x2c,0x00,0xb0,0x0f,0x2b,0xb1,0x00,0x02,0x45,0x54,0x58,0xb0,0x12,0x23,0x42,0x20,0x45,0xb0,0x0e,0x23,0x42,0xb0,0x0d,0x23,0xb0,0x01,0x60,0x42,0x20,0x60,0xb0,0x01,0x61,0xb5,0x18,0x18,0x01,0x00,0x11, +0x00,0x42,0x42,0x8a,0x60,0xb1,0x14,0x08,0x2b,0xb0,0x8b,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x21,0x2c,0xb1,0x00,0x20,0x2b,0x2d,0xb0,0x22,0x2c,0xb1,0x01,0x20,0x2b,0x2d,0xb0,0x23,0x2c,0xb1,0x02,0x20,0x2b,0x2d,0xb0,0x24,0x2c,0xb1,0x03,0x20,0x2b,0x2d,0xb0,0x25,0x2c,0xb1,0x04,0x20,0x2b,0x2d,0xb0,0x26,0x2c,0xb1,0x05,0x20,0x2b,0x2d, +0xb0,0x27,0x2c,0xb1,0x06,0x20,0x2b,0x2d,0xb0,0x28,0x2c,0xb1,0x07,0x20,0x2b,0x2d,0xb0,0x29,0x2c,0xb1,0x08,0x20,0x2b,0x2d,0xb0,0x2a,0x2c,0xb1,0x09,0x20,0x2b,0x2d,0xb0,0x2e,0x2c,0x20,0x3c,0xb0,0x01,0x60,0x2d,0xb0,0x2f,0x2c,0x20,0x60,0xb0,0x18,0x60,0x20,0x43,0x23,0xb0,0x01,0x60,0x43,0xb0,0x02,0x25,0x61,0xb0,0x01,0x60,0xb0, +0x2e,0x2a,0x21,0x2d,0xb0,0x30,0x2c,0xb0,0x2f,0x2b,0xb0,0x2f,0x2a,0x2d,0xb0,0x31,0x2c,0x20,0x20,0x47,0x20,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x61,0x38,0x23,0x20,0x8a,0x55,0x58,0x20,0x47,0x20,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62, +0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x61,0x38,0x1b,0x21,0x59,0x2d,0xb0,0x32,0x2c,0x00,0xb1,0x00,0x02,0x45,0x54,0x58,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x16,0xb0,0x31,0x2a,0xb1,0x05,0x01,0x15,0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x33,0x2c,0x00,0xb0,0x0f,0x2b,0xb1,0x00,0x02, +0x45,0x54,0x58,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x16,0xb0,0x31,0x2a,0xb1,0x05,0x01,0x15,0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x34,0x2c,0x20,0x35,0xb0,0x01,0x60,0x2d,0xb0,0x35,0x2c,0x00,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x45,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01, +0x63,0xb0,0x01,0x2b,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0xb0,0x01,0x2b,0xb0,0x00,0x16,0xb4,0x00,0x00,0x00,0x00,0x00,0x44,0x3e,0x23,0x38,0xb1,0x34,0x01,0x15,0x2a,0x21,0x2d,0xb0,0x36,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62, +0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb0,0x00,0x43,0x61,0x38,0x2d,0xb0,0x37,0x2c,0x2e,0x17,0x3c,0x2d,0xb0,0x38,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb0,0x00,0x43,0x61,0xb0,0x01,0x43, +0x63,0x38,0x2d,0xb0,0x39,0x2c,0xb1,0x02,0x00,0x16,0x25,0x20,0x2e,0x20,0x47,0xb0,0x00,0x23,0x42,0xb0,0x02,0x25,0x49,0x8a,0x8a,0x47,0x23,0x47,0x23,0x61,0x20,0x58,0x62,0x1b,0x21,0x59,0xb0,0x01,0x23,0x42,0xb2,0x38,0x01,0x01,0x15,0x14,0x2a,0x2d,0xb0,0x3a,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x04,0x25,0xb0,0x04,0x25, +0x47,0x23,0x47,0x23,0x61,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43,0x2b,0x65,0x8a,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x3b,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x04,0x25,0xb0,0x04,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x06,0x23,0x42,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58, +0x20,0xb0,0x40,0x51,0x58,0xb3,0x04,0x20,0x05,0x20,0x1b,0xb3,0x04,0x26,0x05,0x1a,0x59,0x42,0x42,0x23,0x20,0xb0,0x0a,0x43,0x20,0x8a,0x23,0x47,0x23,0x47,0x23,0x61,0x23,0x46,0x60,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x20,0xb0,0x01,0x2b,0x20,0x8a,0x8a,0x61,0x20, +0xb0,0x04,0x43,0x60,0x64,0x23,0xb0,0x05,0x43,0x61,0x64,0x50,0x58,0xb0,0x04,0x43,0x61,0x1b,0xb0,0x05,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x61,0x23,0x20,0x20,0xb0,0x04,0x26,0x23,0x46,0x61,0x38,0x1b,0x23,0xb0,0x0a,0x43,0x46,0xb0,0x02,0x25,0xb0,0x0a, +0x43,0x47,0x23,0x47,0x23,0x61,0x60,0x20,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x20,0xb0,0x01,0x2b,0x23,0xb0,0x06,0x43,0x60,0xb0,0x01,0x2b,0xb0,0x05,0x25,0x61,0xb0,0x05,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63, +0xb0,0x04,0x26,0x61,0x20,0xb0,0x04,0x25,0x60,0x64,0x23,0xb0,0x03,0x25,0x60,0x64,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x23,0x20,0x20,0xb0,0x04,0x26,0x23,0x46,0x61,0x38,0x59,0x2d,0xb0,0x3c,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0x20,0x20,0xb0,0x05,0x26,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x23,0x3c,0x38,0x2d,0xb0,0x3d, +0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0xb0,0x0a,0x23,0x42,0x20,0x20,0x20,0x46,0x23,0x47,0xb0,0x01,0x2b,0x23,0x61,0x38,0x2d,0xb0,0x3e,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x03,0x25,0xb0,0x02,0x25,0x47,0x23,0x47,0x23,0x61,0xb0,0x00,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x02,0x25,0xb0,0x02,0x25,0x47, +0x23,0x47,0x23,0x61,0x20,0xb0,0x05,0x25,0xb0,0x04,0x25,0x47,0x23,0x47,0x23,0x61,0xb0,0x06,0x25,0xb0,0x05,0x25,0x49,0xb0,0x02,0x25,0x61,0xb9,0x08,0x00,0x08,0x00,0x63,0x63,0x23,0x20,0x58,0x62,0x1b,0x21,0x59,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x2e,0x23,0x20, +0x20,0x3c,0x8a,0x38,0x23,0x21,0x59,0x2d,0xb0,0x3f,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0xb0,0x0a,0x43,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x40,0x2c,0x23,0x20,0x2e, +0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x41,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x52,0x1b,0x50,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x42,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25, +0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x52,0x1b,0x50,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x43,0x2c,0xb0,0x3a,0x2b,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20, +0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x44,0x2c,0xb0,0x3b,0x2b,0x8a,0x20,0x20,0x3c,0xb0,0x06,0x23,0x42,0x8a,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0xb0,0x06,0x43,0x2e,0xb0,0x30,0x2b,0x2d,0xb0,0x45,0x2c,0xb0,0x00, +0x16,0xb0,0x04,0x25,0xb0,0x04,0x26,0x20,0x20,0x20,0x46,0x23,0x47,0x61,0xb0,0x0c,0x23,0x42,0x2e,0x47,0x23,0x47,0x23,0x61,0xb0,0x0b,0x43,0x2b,0x23,0x20,0x3c,0x20,0x2e,0x23,0x38,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x46,0x2c,0xb1,0x0a,0x04,0x25,0x42,0xb0,0x00,0x16,0xb0,0x04,0x25,0xb0,0x04,0x25,0x20,0x2e,0x47,0x23,0x47,0x23, +0x61,0x20,0xb0,0x06,0x23,0x42,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x04,0x20,0x05,0x20,0x1b,0xb3,0x04,0x26,0x05,0x1a,0x59,0x42,0x42,0x23,0x20,0x47,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x20,0xb0,0x01, +0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x04,0x43,0x60,0x64,0x23,0xb0,0x05,0x43,0x61,0x64,0x50,0x58,0xb0,0x04,0x43,0x61,0x1b,0xb0,0x05,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x61,0xb0,0x02,0x25,0x46,0x61,0x38,0x23,0x20,0x3c,0x23,0x38,0x1b,0x21,0x20,0x20, +0x46,0x23,0x47,0xb0,0x01,0x2b,0x23,0x61,0x38,0x21,0x59,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x47,0x2c,0xb1,0x00,0x3a,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x48,0x2c,0xb1,0x00,0x3b,0x2b,0x21,0x23,0x20,0x20,0x3c,0xb0,0x06,0x23,0x42,0x23,0x38,0xb1,0x30,0x01,0x14,0x2b,0xb0,0x06,0x43,0x2e,0xb0,0x30,0x2b,0x2d,0xb0,0x49, +0x2c,0xb0,0x00,0x15,0x20,0x47,0xb0,0x00,0x23,0x42,0xb2,0x00,0x01,0x01,0x15,0x14,0x13,0x2e,0xb0,0x36,0x2a,0x2d,0xb0,0x4a,0x2c,0xb0,0x00,0x15,0x20,0x47,0xb0,0x00,0x23,0x42,0xb2,0x00,0x01,0x01,0x15,0x14,0x13,0x2e,0xb0,0x36,0x2a,0x2d,0xb0,0x4b,0x2c,0xb1,0x00,0x01,0x14,0x13,0xb0,0x37,0x2a,0x2d,0xb0,0x4c,0x2c,0xb0,0x39,0x2a, +0x2d,0xb0,0x4d,0x2c,0xb0,0x00,0x16,0x45,0x23,0x20,0x2e,0x20,0x46,0x8a,0x23,0x61,0x38,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x4e,0x2c,0xb0,0x0a,0x23,0x42,0xb0,0x4d,0x2b,0x2d,0xb0,0x4f,0x2c,0xb2,0x00,0x00,0x46,0x2b,0x2d,0xb0,0x50,0x2c,0xb2,0x00,0x01,0x46,0x2b,0x2d,0xb0,0x51,0x2c,0xb2,0x01,0x00,0x46,0x2b,0x2d,0xb0,0x52,0x2c, +0xb2,0x01,0x01,0x46,0x2b,0x2d,0xb0,0x53,0x2c,0xb2,0x00,0x00,0x47,0x2b,0x2d,0xb0,0x54,0x2c,0xb2,0x00,0x01,0x47,0x2b,0x2d,0xb0,0x55,0x2c,0xb2,0x01,0x00,0x47,0x2b,0x2d,0xb0,0x56,0x2c,0xb2,0x01,0x01,0x47,0x2b,0x2d,0xb0,0x57,0x2c,0xb3,0x00,0x00,0x00,0x43,0x2b,0x2d,0xb0,0x58,0x2c,0xb3,0x00,0x01,0x00,0x43,0x2b,0x2d,0xb0,0x59, +0x2c,0xb3,0x01,0x00,0x00,0x43,0x2b,0x2d,0xb0,0x5a,0x2c,0xb3,0x01,0x01,0x00,0x43,0x2b,0x2d,0xb0,0x5b,0x2c,0xb3,0x00,0x00,0x01,0x43,0x2b,0x2d,0xb0,0x5c,0x2c,0xb3,0x00,0x01,0x01,0x43,0x2b,0x2d,0xb0,0x5d,0x2c,0xb3,0x01,0x00,0x01,0x43,0x2b,0x2d,0xb0,0x5e,0x2c,0xb3,0x01,0x01,0x01,0x43,0x2b,0x2d,0xb0,0x5f,0x2c,0xb2,0x00,0x00, +0x45,0x2b,0x2d,0xb0,0x60,0x2c,0xb2,0x00,0x01,0x45,0x2b,0x2d,0xb0,0x61,0x2c,0xb2,0x01,0x00,0x45,0x2b,0x2d,0xb0,0x62,0x2c,0xb2,0x01,0x01,0x45,0x2b,0x2d,0xb0,0x63,0x2c,0xb2,0x00,0x00,0x48,0x2b,0x2d,0xb0,0x64,0x2c,0xb2,0x00,0x01,0x48,0x2b,0x2d,0xb0,0x65,0x2c,0xb2,0x01,0x00,0x48,0x2b,0x2d,0xb0,0x66,0x2c,0xb2,0x01,0x01,0x48, +0x2b,0x2d,0xb0,0x67,0x2c,0xb3,0x00,0x00,0x00,0x44,0x2b,0x2d,0xb0,0x68,0x2c,0xb3,0x00,0x01,0x00,0x44,0x2b,0x2d,0xb0,0x69,0x2c,0xb3,0x01,0x00,0x00,0x44,0x2b,0x2d,0xb0,0x6a,0x2c,0xb3,0x01,0x01,0x00,0x44,0x2b,0x2d,0xb0,0x6b,0x2c,0xb3,0x00,0x00,0x01,0x44,0x2b,0x2d,0xb0,0x6c,0x2c,0xb3,0x00,0x01,0x01,0x44,0x2b,0x2d,0xb0,0x6d, +0x2c,0xb3,0x01,0x00,0x01,0x44,0x2b,0x2d,0xb0,0x6e,0x2c,0xb3,0x01,0x01,0x01,0x44,0x2b,0x2d,0xb0,0x6f,0x2c,0xb1,0x00,0x3c,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x70,0x2c,0xb1,0x00,0x3c,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x71,0x2c,0xb1,0x00,0x3c,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x72,0x2c,0xb0,0x00,0x16,0xb1,0x00,0x3c,0x2b, +0xb0,0x42,0x2b,0x2d,0xb0,0x73,0x2c,0xb1,0x01,0x3c,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x74,0x2c,0xb1,0x01,0x3c,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x75,0x2c,0xb0,0x00,0x16,0xb1,0x01,0x3c,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x76,0x2c,0xb1,0x00,0x3d,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x77,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x40,0x2b, +0x2d,0xb0,0x78,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x79,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x7a,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x7b,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x7c,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x7d,0x2c,0xb1,0x00,0x3e,0x2b,0x2e, +0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x7e,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x7f,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x80,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x81,0x2c,0xb1,0x01,0x3e,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x82,0x2c,0xb1,0x01,0x3e,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x83,0x2c, +0xb1,0x01,0x3e,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x84,0x2c,0xb1,0x00,0x3f,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x85,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x86,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x87,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x88,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x40, +0x2b,0x2d,0xb0,0x89,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x8a,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x8b,0x2c,0xb2,0x0b,0x00,0x03,0x45,0x50,0x58,0xb0,0x06,0x1b,0xb2,0x04,0x02,0x03,0x45,0x58,0x23,0x21,0x1b,0x21,0x59,0x59,0x42,0x2b,0xb0,0x08,0x65,0xb0,0x03,0x24,0x50,0x78,0xb1,0x05,0x01,0x15,0x45, +0x58,0x30,0x59,0x2d,0x00,0x4b,0xb8,0x00,0xc8,0x52,0x58,0xb1,0x01,0x01,0x8e,0x59,0xb0,0x01,0xb9,0x08,0x00,0x08,0x00,0x63,0x70,0xb1,0x00,0x07,0x42,0xb2,0x19,0x01,0x00,0x2a,0xb1,0x00,0x07,0x42,0xb3,0x0d,0x09,0x01,0x0a,0x2a,0xb1,0x00,0x07,0x42,0xb3,0x16,0x06,0x01,0x0a,0x2a,0xb1,0x00,0x08,0x42,0xba,0x03,0x80,0x00,0x01,0x00, +0x0b,0x2a,0xb1,0x00,0x09,0x42,0xba,0x00,0x80,0x00,0x01,0x00,0x0b,0x2a,0xb9,0x00,0x03,0x00,0x00,0x44,0xb1,0x24,0x01,0x88,0x51,0x58,0xb0,0x40,0x88,0x58,0xb9,0x00,0x03,0x00,0x64,0x44,0xb1,0x28,0x01,0x88,0x51,0x58,0xb8,0x08,0x00,0x88,0x58,0xb9,0x00,0x03,0x00,0x00,0x44,0x59,0x1b,0xb1,0x27,0x01,0x88,0x51,0x58,0xba,0x08,0x80, +0x00,0x01,0x04,0x40,0x88,0x63,0x54,0x58,0xb9,0x00,0x03,0x00,0x00,0x44,0x59,0x59,0x59,0x59,0x59,0xb3,0x10,0x06,0x01,0x0e,0x2a,0xb8,0x01,0xff,0x85,0xb0,0x04,0x8d,0xb1,0x02,0x00,0x44,0xb3,0x05,0x64,0x06,0x00,0x44,0x44,0x00, +}; + +read_only global String8 df_g_icon_font_bytes = {df_g_icon_font_bytes__data, sizeof(df_g_icon_font_bytes__data)}; +read_only global U8 df_g_default_main_font_bytes__data[] = +{ +0x00,0x01,0x00,0x00,0x00,0x13,0x01,0x00,0x00,0x04,0x00,0x30,0x44,0x53,0x49,0x47,0x00,0x00,0x00,0x01,0x00,0x02,0x6b,0x84,0x00,0x00,0x00,0x08,0x47,0x44,0x45,0x46,0x18,0x60,0x18,0x61,0x00,0x00,0x01,0x3c,0x00,0x00,0x00,0x48,0x47,0x50,0x4f,0x53,0x15,0x2a,0x60,0x11,0x00,0x00,0x01,0x84,0x00,0x00,0x8b,0xa0,0x47,0x53,0x55,0x42, +0xc8,0x26,0xca,0x04,0x00,0x00,0x8d,0x24,0x00,0x00,0x02,0x96,0x4f,0x53,0x2f,0x32,0xb8,0xa3,0x29,0xc5,0x00,0x00,0x8f,0xbc,0x00,0x00,0x00,0x60,0x63,0x6d,0x61,0x70,0x11,0xca,0x4e,0x34,0x00,0x00,0x90,0x1c,0x00,0x00,0x06,0xd6,0x63,0x76,0x74,0x20,0x07,0x19,0x19,0xc9,0x00,0x02,0x61,0xe4,0x00,0x00,0x00,0x26,0x66,0x70,0x67,0x6d, +0x94,0xa8,0xf4,0x54,0x00,0x02,0x62,0x0c,0x00,0x00,0x09,0x25,0x67,0x61,0x73,0x70,0x00,0x00,0x00,0x10,0x00,0x02,0x61,0xdc,0x00,0x00,0x00,0x08,0x67,0x6c,0x79,0x66,0xc4,0xd2,0x88,0x18,0x00,0x00,0x96,0xf4,0x00,0x01,0x5a,0xf4,0x68,0x65,0x61,0x64,0x14,0xa0,0xb2,0xb9,0x00,0x01,0xf1,0xe8,0x00,0x00,0x00,0x36,0x68,0x68,0x65,0x61, +0x0c,0xf7,0x0a,0xd3,0x00,0x01,0xf2,0x20,0x00,0x00,0x00,0x24,0x68,0x6d,0x74,0x78,0x6e,0xd8,0x76,0xc7,0x00,0x01,0xf2,0x44,0x00,0x00,0x10,0x34,0x6b,0x65,0x72,0x6e,0x77,0x61,0x6c,0x7d,0x00,0x02,0x02,0x78,0x00,0x00,0x30,0x12,0x6c,0x6f,0x63,0x61,0x04,0x9d,0x5b,0x88,0x00,0x02,0x32,0x8c,0x00,0x00,0x08,0x1c,0x6d,0x61,0x78,0x70, +0x05,0x55,0x0a,0x7d,0x00,0x02,0x3a,0xa8,0x00,0x00,0x00,0x20,0x6e,0x61,0x6d,0x65,0x02,0xa4,0x9f,0xae,0x00,0x02,0x3a,0xc8,0x00,0x00,0x03,0x3e,0x70,0x6f,0x73,0x74,0xd8,0xe3,0x62,0xc5,0x00,0x02,0x3e,0x08,0x00,0x00,0x23,0xd3,0x70,0x72,0x65,0x70,0x0e,0xfb,0xc8,0x9f,0x00,0x02,0x6b,0x34,0x00,0x00,0x00,0x4d,0x00,0x01,0x00,0x00, +0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x08,0x01,0xa9,0x01,0xa9,0x00,0x01,0x02,0x2e,0x02,0x34,0x00,0x01,0x03,0x24,0x03,0x2f,0x00,0x01,0x03,0x48,0x03,0x48,0x00,0x01,0x03,0x4f,0x03,0x50,0x00,0x01,0x03,0x52,0x03,0x52,0x00,0x01,0x03,0x68,0x03,0x6a,0x00,0x01,0x03,0xfb,0x03,0xfb,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0a,0x00,0x1e,0x00,0x2c,0x00,0x01,0x44,0x46,0x4c,0x54,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x01,0x00,0x00,0x00,0x01,0x6b,0x65,0x72,0x6e,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x0e,0x4b,0xb8,0x54,0x92, +0x70,0x84,0x00,0x01,0x77,0xc6,0x00,0x04,0x00,0x00,0x01,0x99,0x03,0x3c,0x03,0x42,0x03,0x48,0x03,0xba,0x03,0xc4,0x03,0xd6,0x03,0xfc,0x04,0x12,0x04,0x1c,0x04,0x3e,0x04,0x60,0x04,0x66,0x04,0xb4,0x04,0xe2,0x05,0x04,0x05,0x26,0x05,0x4c,0x05,0x72,0x05,0x78,0x06,0x62,0x06,0x68,0x06,0x8e,0x06,0xb4,0x07,0x16,0x07,0xa8,0x07,0xca, +0x07,0xe8,0x08,0x02,0x08,0x08,0x08,0x16,0x08,0x38,0x08,0x52,0x08,0x60,0x08,0x7e,0x08,0x84,0x08,0xa2,0x09,0x14,0x09,0x86,0x09,0xf8,0x0a,0x6a,0x0a,0xdc,0x0b,0x4e,0x0b,0x60,0x0b,0x76,0x0b,0x8c,0x0b,0xa2,0x0b,0xb8,0x0b,0xda,0x0b,0xfc,0x0c,0x1e,0x0c,0x40,0x0c,0x66,0x0c,0x88,0x0c,0xae,0x0c,0xd4,0x0c,0xfa,0x0d,0x20,0x0d,0x46, +0x0d,0x4c,0x0d,0x52,0x0d,0x58,0x0d,0x5e,0x0d,0xf0,0x0e,0x0e,0x0e,0x2c,0x0e,0x4a,0x0e,0x68,0x0e,0x86,0x0e,0xa4,0x0e,0xaa,0x0e,0xb0,0x0e,0xb6,0x0e,0xbc,0x0e,0xde,0x0f,0x00,0x0f,0x22,0x0f,0x44,0x0f,0x66,0x0f,0x84,0x0f,0x9e,0x0f,0xbc,0x10,0x2e,0x10,0x4c,0x10,0xbe,0x10,0xdc,0x11,0x4e,0x11,0x6c,0x11,0x7e,0x11,0x90,0x11,0xa2, +0x11,0xb4,0x11,0xda,0x12,0x00,0x12,0x16,0x12,0x1c,0x12,0x32,0x12,0x38,0x12,0x4e,0x12,0x54,0x12,0x6a,0x12,0x70,0x12,0x86,0x12,0x8c,0x12,0xae,0x12,0xd0,0x12,0xf2,0x13,0x14,0x13,0x36,0x13,0x58,0x13,0x5e,0x13,0xac,0x13,0xda,0x14,0x08,0x14,0x36,0x14,0x64,0x14,0x86,0x14,0xa8,0x14,0xca,0x14,0xf0,0x15,0x12,0x15,0x38,0x15,0x5a, +0x15,0x80,0x15,0xa2,0x15,0xb0,0x15,0xbe,0x15,0xcc,0x16,0xb6,0x17,0xa0,0x18,0x8a,0x18,0x90,0x18,0x96,0x18,0x9c,0x18,0xa2,0x18,0xa8,0x18,0xae,0x18,0xd4,0x19,0x66,0x19,0x84,0x1a,0x16,0x1a,0x38,0x1a,0x5a,0x1a,0x7c,0x1a,0xee,0x1b,0x0c,0x1b,0x12,0x1b,0x84,0x1b,0x9a,0x1b,0xbc,0x1b,0xde,0x1c,0x04,0x1c,0x96,0x1d,0x08,0x1d,0x12, +0x1d,0xd8,0x1e,0x4a,0x1e,0x60,0x1e,0x82,0x1e,0xa4,0x1e,0xca,0x1e,0xec,0x1f,0x3a,0x1f,0xac,0x1f,0xce,0x1f,0xf0,0x1f,0xf6,0x20,0x1c,0x20,0x42,0x20,0x4c,0x21,0x36,0x21,0xc8,0x21,0xce,0x22,0x30,0x22,0x36,0x22,0x58,0x22,0xea,0x22,0xf0,0x23,0x0e,0x23,0x18,0x23,0x42,0x23,0x58,0x23,0x72,0x23,0x90,0x23,0x96,0x23,0xb8,0x23,0xd2, +0x23,0xd8,0x24,0x0e,0x24,0x14,0x24,0x2e,0x24,0x50,0x24,0x66,0x24,0x7c,0x24,0xaa,0x25,0x70,0x25,0x92,0x25,0xb4,0x25,0xba,0x25,0xe0,0x26,0x06,0x26,0x28,0x26,0x76,0x26,0xc4,0x26,0xe6,0x27,0x58,0x27,0x7a,0x27,0x84,0x28,0x4a,0x28,0x78,0x28,0x8e,0x28,0xf0,0x29,0x06,0x29,0x28,0x29,0x76,0x29,0x98,0x29,0xba,0x29,0xdc,0x2a,0x02, +0x2a,0x28,0x2a,0x3a,0x2b,0x24,0x2b,0x72,0x2b,0xd4,0x2b,0xf6,0x2c,0x18,0x2c,0x4a,0x2c,0x70,0x2c,0x96,0x2c,0xa0,0x2c,0xaa,0x2c,0xc8,0x2c,0xe2,0x2c,0xf4,0x2c,0xfe,0x2d,0x14,0x2d,0x1a,0x2d,0x20,0x2d,0x36,0x2d,0x58,0x2d,0x72,0x2d,0xb0,0x2d,0xce,0x2d,0xe8,0x2d,0xee,0x2e,0x08,0x2e,0x1e,0x2e,0x40,0x2e,0x62,0x2e,0x7c,0x2e,0x82, +0x2e,0x88,0x2e,0x8e,0x2e,0x98,0x2e,0xba,0x2e,0xdc,0x2e,0xfa,0x2f,0x20,0x2f,0x42,0x2f,0xb4,0x2f,0xd6,0x2f,0xfc,0x30,0x1a,0x30,0x40,0x30,0x5e,0x30,0x78,0x31,0x3e,0x31,0x48,0x32,0x0e,0x32,0x70,0x32,0x76,0x32,0xc4,0x33,0x12,0x33,0x60,0x33,0xae,0x33,0xd0,0x33,0xe2,0x34,0xcc,0x35,0x5e,0x35,0x7c,0x36,0x0e,0x36,0x70,0x36,0x76, +0x36,0x98,0x36,0xfa,0x37,0x00,0x37,0x22,0x37,0x44,0x37,0x66,0x37,0xd8,0x37,0xf6,0x38,0x68,0x38,0x86,0x38,0x9c,0x38,0xa2,0x38,0xa8,0x38,0xae,0x39,0x10,0x39,0x16,0x39,0x3c,0x39,0x5e,0x39,0x80,0x39,0x9a,0x39,0xe8,0x3a,0x06,0x3a,0x54,0x3a,0x72,0x3a,0xc0,0x3a,0xde,0x3b,0xa4,0x3b,0xae,0x3b,0xb8,0x3c,0x1a,0x3c,0x20,0x3c,0x92, +0x3c,0xb0,0x3c,0xd2,0x3c,0xf8,0x3d,0x1e,0x3d,0x44,0x3d,0xb6,0x3d,0xd4,0x3e,0x46,0x3e,0x64,0x3e,0xd6,0x3e,0xf4,0x3f,0x66,0x3f,0x84,0x3f,0xf6,0x40,0x14,0x40,0x86,0x40,0xa4,0x41,0x16,0x41,0x34,0x41,0xa6,0x41,0xc4,0x42,0x36,0x42,0x54,0x42,0xc6,0x42,0xe4,0x43,0x56,0x43,0x74,0x43,0xe6,0x44,0x04,0x44,0x1a,0x44,0x20,0x44,0x36, +0x44,0x3c,0x44,0x52,0x44,0x58,0x44,0x6e,0x44,0x74,0x44,0x8a,0x44,0x90,0x44,0xa6,0x44,0xac,0x44,0xc2,0x44,0xc8,0x44,0xde,0x44,0xe4,0x45,0x06,0x45,0x28,0x45,0x4e,0x45,0x70,0x45,0x96,0x45,0xb8,0x45,0xde,0x46,0x00,0x46,0x26,0x46,0x48,0x46,0x6e,0x46,0x90,0x46,0xb6,0x46,0xd8,0x46,0xfe,0x47,0x20,0x47,0x42,0x47,0x48,0x47,0x4e, +0x47,0xe0,0x47,0xfe,0x48,0x90,0x48,0xae,0x49,0x40,0x49,0x5e,0x49,0xf0,0x4a,0x0e,0x4a,0x34,0x4a,0x3a,0x4a,0x40,0x4a,0x46,0x4a,0x4c,0x4a,0x52,0x4a,0x58,0x4a,0x5e,0x4a,0x84,0x4a,0x8e,0x4a,0x94,0x4a,0xa6,0x4a,0xd0,0x4a,0xe6,0x4a,0xf8,0x4b,0x0a,0x4b,0x30,0x4b,0x36,0x4b,0x4c,0x4b,0x56,0x4b,0x68,0x4b,0x8e,0x4b,0xa4,0x00,0x01, +0x00,0x5a,0x00,0x0b,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51, +0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x02,0x02,0x16, +0x00,0x0b,0x02,0xb9,0xff,0xe6,0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x05, +0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x02,0x00,0x55,0xff,0xe6,0x03,0x71,0xff,0xc0,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4, +0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9,0x02,0x0d, +0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x0b,0x00,0x5a,0xff,0xa4,0x03,0x71,0x00,0x13, +0x03,0x75,0xff,0xf3,0x03,0x79,0xff,0xf1,0x03,0x82,0xff,0xf2,0x03,0xdb,0xff,0xf1,0x03,0xec,0xff,0x3b,0x03,0xed,0xff,0xda,0x03,0xee,0xff,0x54,0x03,0xef,0xff,0x91,0x03,0xf1,0xff,0x3f,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1, +0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8, +0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x57,0x00,0x0e,0x00,0x88,0xff,0x9f,0x01,0x8e,0xff,0xf5,0x01,0x95,0xff,0xde,0x01,0x9b,0xff,0xe5,0x01,0xc0,0xff,0xa8,0x01,0xe0,0xff,0xca,0x02,0xab,0xff,0xe3,0x03,0x71,0xff,0xc6,0x00,0x01,0x03,0x71,0x00,0x0e,0x00,0x3a,0x00,0x55,0xff,0xb5, +0x00,0x5a,0xff,0xc7,0x00,0x6d,0xfe,0xb8,0x00,0x7d,0xff,0x28,0x00,0x88,0xff,0x4d,0x00,0xa8,0xff,0x8e,0x00,0xba,0xff,0xa1,0x01,0x80,0xff,0xae,0x01,0x8e,0xff,0xc9,0x01,0x8f,0xff,0x7e,0x01,0x93,0xff,0x67,0x01,0x9a,0xff,0x87,0x01,0x9b,0xff,0x65,0x01,0x9e,0xff,0x9e,0x01,0xa0,0xff,0x6a,0x01,0xa1,0xff,0xa9,0x01,0xa2,0xff,0x73, +0x01,0xa3,0xff,0x5e,0x01,0xc0,0xff,0xa5,0x01,0xd8,0x00,0x0f,0x01,0xdd,0xff,0xe4,0x01,0xde,0xff,0xa0,0x01,0xe0,0xff,0x74,0x01,0xe3,0xff,0x80,0x01,0xee,0xff,0xb2,0x01,0xf7,0xff,0x7d,0x01,0xf9,0xff,0x80,0x01,0xfb,0xff,0x79,0x02,0x0b,0xff,0x7d,0x02,0x0d,0xff,0x7f,0x02,0x27,0xff,0x98,0x02,0x2b,0xff,0xda,0x02,0x3a,0xff,0x81, +0x02,0x3c,0xff,0x98,0x02,0x48,0xff,0x7d,0x02,0x4c,0xff,0xb3,0x02,0x52,0xff,0xa0,0x02,0x64,0xff,0x7c,0x02,0x66,0xff,0x7c,0x02,0x67,0xff,0x9a,0x02,0x68,0xff,0x6c,0x02,0x83,0xff,0xe6,0x02,0xab,0xff,0x6b,0x02,0xb0,0xff,0x92,0x02,0xb2,0xff,0xad,0x02,0xb6,0xff,0x7b,0x02,0xb9,0x00,0x0f,0x02,0xba,0xff,0x91,0x02,0xbb,0xff,0xf2, +0x03,0x71,0xff,0xaf,0x03,0x75,0xff,0xb9,0x03,0x79,0xff,0xb9,0x03,0x82,0xff,0xb9,0x03,0xdb,0xff,0xb9,0x03,0xeb,0xff,0xbc,0x03,0xec,0xff,0xf1,0x03,0xef,0xff,0xf1,0x03,0xf0,0xff,0xed,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x09,0x00,0x0c,0x00,0x14,0x00,0x40,0x00,0x11,0x00,0x55,0xff,0xe2,0x00,0x60,0x00,0x13,0x03,0x71,0xff,0xb4, +0x03,0x75,0xff,0xd9,0x03,0x79,0xff,0xd9,0x03,0x82,0xff,0xd9,0x03,0xdb,0xff,0xd9,0x00,0x09,0x00,0x0c,0x00,0x0f,0x00,0x40,0x00,0x0c,0x00,0x55,0xff,0xeb,0x00,0x60,0x00,0x0e,0x03,0x71,0xff,0xcb,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0, +0x01,0x92,0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c,0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c, +0x02,0xba,0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d, +0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2, +0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x08,0x00,0x5a,0xff,0xe5,0x01,0x80,0xff,0xcb,0x01,0xa2,0xff,0xe4,0x03,0x71,0x00,0x0d,0x03,0x75,0xff,0xed, +0x03,0x79,0xff,0xeb,0x03,0x82,0xff,0xec,0x03,0xdb,0xff,0xec,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x06,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec, +0x02,0xba,0xff,0xec,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x03,0x00,0x0c,0x00,0x14,0x00,0x40,0x00,0x12,0x00,0x60,0x00,0x13,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x06,0x01,0x9e,0xff,0xea, +0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x03,0x00,0x49,0x00,0x0f,0x00,0x57,0x00,0x11,0x00,0x5a,0x00,0x11,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1, +0x00,0x01,0x02,0x27,0xff,0xf1,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95, +0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82, +0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5, +0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd, +0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64, +0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x1c,0x00,0x22,0xff,0xc3, +0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2, +0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80, +0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba, +0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8, +0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7, +0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a, +0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x08,0x01,0xc0,0x00,0x15, +0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08, +0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9, +0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf, +0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95, +0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x88, +0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0, +0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60, +0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0, +0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3, +0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1, +0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3, +0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x08, +0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba, +0xff,0xec,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0, +0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0, +0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x06,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x1c, +0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd, +0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c, +0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f, +0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4, +0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8, +0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7, +0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed, +0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed,0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed,0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3, +0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0, +0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee, +0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0, +0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64, +0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63, +0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0, +0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9,0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b, +0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x0b,0x00,0x5a,0xff,0xa4,0x03,0x71,0x00,0x13,0x03,0x75,0xff,0xf3,0x03,0x79,0xff,0xf1, +0x03,0x82,0xff,0xf2,0x03,0xdb,0xff,0xf1,0x03,0xec,0xff,0x3b,0x03,0xed,0xff,0xda,0x03,0xee,0xff,0x54,0x03,0xef,0xff,0x91,0x03,0xf1,0xff,0x3f,0x00,0x0b,0x00,0x5a,0xff,0xa4,0x03,0x71,0x00,0x13,0x03,0x75,0xff,0xf3,0x03,0x79,0xff,0xf1,0x03,0x82,0xff,0xf2,0x03,0xdb,0xff,0xf1,0x03,0xec,0xff,0x3b,0x03,0xed,0xff,0xda,0x03,0xee, +0xff,0x54,0x03,0xef,0xff,0x91,0x03,0xf1,0xff,0x3f,0x00,0x0b,0x00,0x5a,0xff,0xa4,0x03,0x71,0x00,0x13,0x03,0x75,0xff,0xf3,0x03,0x79,0xff,0xf1,0x03,0x82,0xff,0xf2,0x03,0xdb,0xff,0xf1,0x03,0xec,0xff,0x3b,0x03,0xed,0xff,0xda,0x03,0xee,0xff,0x54,0x03,0xef,0xff,0x91,0x03,0xf1,0xff,0x3f,0x00,0x0b,0x00,0x5a,0xff,0xa4,0x03,0x71, +0x00,0x13,0x03,0x75,0xff,0xf3,0x03,0x79,0xff,0xf1,0x03,0x82,0xff,0xf2,0x03,0xdb,0xff,0xf1,0x03,0xec,0xff,0x3b,0x03,0xed,0xff,0xda,0x03,0xee,0xff,0x54,0x03,0xef,0xff,0x91,0x03,0xf1,0xff,0x3f,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3, +0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4, +0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea, +0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea, +0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0, +0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x03,0x00,0x49,0x00,0x0f,0x00,0x57,0x00,0x11,0x00,0x5a,0x00,0x11,0x00,0x03,0x00,0x49,0x00,0x0f,0x00,0x57,0x00,0x11,0x00,0x5a,0x00,0x11, +0x00,0x03,0x00,0x49,0x00,0x0f,0x00,0x57,0x00,0x11,0x00,0x5a,0x00,0x11,0x00,0x3a,0x00,0x55,0xff,0xb5,0x00,0x5a,0xff,0xc7,0x00,0x6d,0xfe,0xb8,0x00,0x7d,0xff,0x28,0x00,0x88,0xff,0x4d,0x00,0xa8,0xff,0x8e,0x00,0xba,0xff,0xa1,0x01,0x80,0xff,0xae,0x01,0x8e,0xff,0xc9,0x01,0x8f,0xff,0x7e,0x01,0x93,0xff,0x67,0x01,0x9a,0xff,0x87, +0x01,0x9b,0xff,0x65,0x01,0x9e,0xff,0x9e,0x01,0xa0,0xff,0x6a,0x01,0xa1,0xff,0xa9,0x01,0xa2,0xff,0x73,0x01,0xa3,0xff,0x5e,0x01,0xc0,0xff,0xa5,0x01,0xd8,0x00,0x0f,0x01,0xdd,0xff,0xe4,0x01,0xde,0xff,0xa0,0x01,0xe0,0xff,0x74,0x01,0xe3,0xff,0x80,0x01,0xee,0xff,0xb2,0x01,0xf7,0xff,0x7d,0x01,0xf9,0xff,0x80,0x01,0xfb,0xff,0x79, +0x02,0x0b,0xff,0x7d,0x02,0x0d,0xff,0x7f,0x02,0x27,0xff,0x98,0x02,0x2b,0xff,0xda,0x02,0x3a,0xff,0x81,0x02,0x3c,0xff,0x98,0x02,0x48,0xff,0x7d,0x02,0x4c,0xff,0xb3,0x02,0x52,0xff,0xa0,0x02,0x64,0xff,0x7c,0x02,0x66,0xff,0x7c,0x02,0x67,0xff,0x9a,0x02,0x68,0xff,0x6c,0x02,0x83,0xff,0xe6,0x02,0xab,0xff,0x6b,0x02,0xb0,0xff,0x92, +0x02,0xb2,0xff,0xad,0x02,0xb6,0xff,0x7b,0x02,0xb9,0x00,0x0f,0x02,0xba,0xff,0x91,0x02,0xbb,0xff,0xf2,0x03,0x71,0xff,0xaf,0x03,0x75,0xff,0xb9,0x03,0x79,0xff,0xb9,0x03,0x82,0xff,0xb9,0x03,0xdb,0xff,0xb9,0x03,0xeb,0xff,0xbc,0x03,0xec,0xff,0xf1,0x03,0xef,0xff,0xf1,0x03,0xf0,0xff,0xed,0x00,0x3a,0x00,0x55,0xff,0xb5,0x00,0x5a, +0xff,0xc7,0x00,0x6d,0xfe,0xb8,0x00,0x7d,0xff,0x28,0x00,0x88,0xff,0x4d,0x00,0xa8,0xff,0x8e,0x00,0xba,0xff,0xa1,0x01,0x80,0xff,0xae,0x01,0x8e,0xff,0xc9,0x01,0x8f,0xff,0x7e,0x01,0x93,0xff,0x67,0x01,0x9a,0xff,0x87,0x01,0x9b,0xff,0x65,0x01,0x9e,0xff,0x9e,0x01,0xa0,0xff,0x6a,0x01,0xa1,0xff,0xa9,0x01,0xa2,0xff,0x73,0x01,0xa3, +0xff,0x5e,0x01,0xc0,0xff,0xa5,0x01,0xd8,0x00,0x0f,0x01,0xdd,0xff,0xe4,0x01,0xde,0xff,0xa0,0x01,0xe0,0xff,0x74,0x01,0xe3,0xff,0x80,0x01,0xee,0xff,0xb2,0x01,0xf7,0xff,0x7d,0x01,0xf9,0xff,0x80,0x01,0xfb,0xff,0x79,0x02,0x0b,0xff,0x7d,0x02,0x0d,0xff,0x7f,0x02,0x27,0xff,0x98,0x02,0x2b,0xff,0xda,0x02,0x3a,0xff,0x81,0x02,0x3c, +0xff,0x98,0x02,0x48,0xff,0x7d,0x02,0x4c,0xff,0xb3,0x02,0x52,0xff,0xa0,0x02,0x64,0xff,0x7c,0x02,0x66,0xff,0x7c,0x02,0x67,0xff,0x9a,0x02,0x68,0xff,0x6c,0x02,0x83,0xff,0xe6,0x02,0xab,0xff,0x6b,0x02,0xb0,0xff,0x92,0x02,0xb2,0xff,0xad,0x02,0xb6,0xff,0x7b,0x02,0xb9,0x00,0x0f,0x02,0xba,0xff,0x91,0x02,0xbb,0xff,0xf2,0x03,0x71, +0xff,0xaf,0x03,0x75,0xff,0xb9,0x03,0x79,0xff,0xb9,0x03,0x82,0xff,0xb9,0x03,0xdb,0xff,0xb9,0x03,0xeb,0xff,0xbc,0x03,0xec,0xff,0xf1,0x03,0xef,0xff,0xf1,0x03,0xf0,0xff,0xed,0x00,0x3a,0x00,0x55,0xff,0xb5,0x00,0x5a,0xff,0xc7,0x00,0x6d,0xfe,0xb8,0x00,0x7d,0xff,0x28,0x00,0x88,0xff,0x4d,0x00,0xa8,0xff,0x8e,0x00,0xba,0xff,0xa1, +0x01,0x80,0xff,0xae,0x01,0x8e,0xff,0xc9,0x01,0x8f,0xff,0x7e,0x01,0x93,0xff,0x67,0x01,0x9a,0xff,0x87,0x01,0x9b,0xff,0x65,0x01,0x9e,0xff,0x9e,0x01,0xa0,0xff,0x6a,0x01,0xa1,0xff,0xa9,0x01,0xa2,0xff,0x73,0x01,0xa3,0xff,0x5e,0x01,0xc0,0xff,0xa5,0x01,0xd8,0x00,0x0f,0x01,0xdd,0xff,0xe4,0x01,0xde,0xff,0xa0,0x01,0xe0,0xff,0x74, +0x01,0xe3,0xff,0x80,0x01,0xee,0xff,0xb2,0x01,0xf7,0xff,0x7d,0x01,0xf9,0xff,0x80,0x01,0xfb,0xff,0x79,0x02,0x0b,0xff,0x7d,0x02,0x0d,0xff,0x7f,0x02,0x27,0xff,0x98,0x02,0x2b,0xff,0xda,0x02,0x3a,0xff,0x81,0x02,0x3c,0xff,0x98,0x02,0x48,0xff,0x7d,0x02,0x4c,0xff,0xb3,0x02,0x52,0xff,0xa0,0x02,0x64,0xff,0x7c,0x02,0x66,0xff,0x7c, +0x02,0x67,0xff,0x9a,0x02,0x68,0xff,0x6c,0x02,0x83,0xff,0xe6,0x02,0xab,0xff,0x6b,0x02,0xb0,0xff,0x92,0x02,0xb2,0xff,0xad,0x02,0xb6,0xff,0x7b,0x02,0xb9,0x00,0x0f,0x02,0xba,0xff,0x91,0x02,0xbb,0xff,0xf2,0x03,0x71,0xff,0xaf,0x03,0x75,0xff,0xb9,0x03,0x79,0xff,0xb9,0x03,0x82,0xff,0xb9,0x03,0xdb,0xff,0xb9,0x03,0xeb,0xff,0xbc, +0x03,0xec,0xff,0xf1,0x03,0xef,0xff,0xf1,0x03,0xf0,0xff,0xed,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x09,0x00,0x0c,0x00,0x0f,0x00,0x40,0x00,0x0c,0x00,0x55,0xff,0xeb,0x00,0x60, +0x00,0x0e,0x03,0x71,0xff,0xcb,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd, +0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda, +0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0, +0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0, +0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd, +0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x08,0x00,0x5a,0xff,0xe5,0x01,0x80,0xff,0xcb,0x01,0xa2,0xff,0xe4,0x03,0x71,0x00,0x0d,0x03,0x75,0xff,0xed,0x03,0x79,0xff,0xeb,0x03,0x82,0xff,0xec,0x03,0xdb,0xff,0xec,0x00,0x08,0x00,0x5a,0xff,0xe5, +0x01,0x80,0xff,0xcb,0x01,0xa2,0xff,0xe4,0x03,0x71,0x00,0x0d,0x03,0x75,0xff,0xed,0x03,0x79,0xff,0xeb,0x03,0x82,0xff,0xec,0x03,0xdb,0xff,0xec,0x00,0x08,0x00,0x5a,0xff,0xe5,0x01,0x80,0xff,0xcb,0x01,0xa2,0xff,0xe4,0x03,0x71,0x00,0x0d,0x03,0x75,0xff,0xed,0x03,0x79,0xff,0xeb,0x03,0x82,0xff,0xec,0x03,0xdb,0xff,0xec,0x00,0x1c, +0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd, +0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c, +0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee, +0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef, +0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08, +0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71, +0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0, +0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd, +0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8, +0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee, +0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x02,0x02,0x16,0x00,0x0b,0x02,0xb9,0xff,0xe6,0x00,0x31,0x00,0x55,0xff,0x6d,0x00,0x5a,0xff,0x8c,0x00,0x6d,0xfd,0xbf,0x00,0x7d,0xfe,0x7d,0x00,0x88,0xfe,0xbc,0x00,0xa8,0xff,0x2b,0x00,0xba,0xff,0x4b,0x01,0x80,0xff,0x61,0x01,0x8e,0xff,0x8f,0x01,0x8f,0xff,0x0f,0x01,0x93, +0xfe,0xe8,0x01,0x9a,0xff,0x1f,0x01,0x9b,0xfe,0xe5,0x01,0x9e,0xff,0x46,0x01,0xa0,0xfe,0xed,0x01,0xa1,0xff,0x59,0x01,0xa2,0xfe,0xfd,0x01,0xa3,0xfe,0xd9,0x01,0xc0,0xff,0x52,0x01,0xd8,0x00,0x05,0x01,0xdd,0xff,0xbd,0x01,0xde,0xff,0x49,0x01,0xe0,0xfe,0xfe,0x01,0xe3,0xff,0x13,0x01,0xee,0xff,0x68,0x01,0xf7,0xff,0x0e,0x01,0xf9, +0xff,0x13,0x01,0xfb,0xff,0x07,0x02,0x0b,0xff,0x0e,0x02,0x0d,0xff,0x11,0x02,0x27,0xff,0x3c,0x02,0x2b,0xff,0xac,0x02,0x3a,0xff,0x15,0x02,0x3c,0xff,0x3c,0x02,0x48,0xff,0x0e,0x02,0x4c,0xff,0x6a,0x02,0x52,0xff,0x49,0x02,0x64,0xff,0x0c,0x02,0x66,0xff,0x0c,0x02,0x67,0xff,0x3f,0x02,0x68,0xfe,0xf1,0x02,0x83,0xff,0xc0,0x02,0xab, +0xfe,0xef,0x02,0xb0,0xff,0x31,0x02,0xb2,0xff,0x5f,0x02,0xb6,0xff,0x0a,0x02,0xb9,0x00,0x05,0x02,0xba,0xff,0x30,0x02,0xbb,0xff,0xd5,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13, +0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1, +0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x08,0x00,0x5a,0xff,0xe5,0x01,0x80,0xff,0xcb,0x01,0xa2,0xff,0xe4,0x03,0x71,0x00,0x0d,0x03,0x75,0xff,0xed,0x03,0x79,0xff,0xeb,0x03,0x82,0xff,0xec, +0x03,0xdb,0xff,0xec,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0, +0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7, +0x01,0xee,0xff,0xb9,0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x1c,0x00,0x22, +0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83, +0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5, +0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x01,0x01,0x95,0x00,0x0d,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79, +0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x57,0x00,0x0e,0x00,0x88,0xff,0x9f,0x01,0x8e,0xff,0xf5,0x01,0x95,0xff,0xde,0x01,0x9b,0xff,0xe5,0x01,0xc0,0xff,0xa8,0x01,0xe0,0xff,0xca,0x02,0xab,0xff,0xe3, +0x03,0x71,0xff,0xc6,0x00,0x02,0x01,0x80,0xff,0xc2,0x01,0x95,0x00,0x10,0x00,0x3a,0x00,0x55,0xff,0xb5,0x00,0x5a,0xff,0xc7,0x00,0x6d,0xfe,0xb8,0x00,0x7d,0xff,0x28,0x00,0x88,0xff,0x4d,0x00,0xa8,0xff,0x8e,0x00,0xba,0xff,0xa1,0x01,0x80,0xff,0xae,0x01,0x8e,0xff,0xc9,0x01,0x8f,0xff,0x7e,0x01,0x93,0xff,0x67,0x01,0x9a,0xff,0x87, +0x01,0x9b,0xff,0x65,0x01,0x9e,0xff,0x9e,0x01,0xa0,0xff,0x6a,0x01,0xa1,0xff,0xa9,0x01,0xa2,0xff,0x73,0x01,0xa3,0xff,0x5e,0x01,0xc0,0xff,0xa5,0x01,0xd8,0x00,0x0f,0x01,0xdd,0xff,0xe4,0x01,0xde,0xff,0xa0,0x01,0xe0,0xff,0x74,0x01,0xe3,0xff,0x80,0x01,0xee,0xff,0xb2,0x01,0xf7,0xff,0x7d,0x01,0xf9,0xff,0x80,0x01,0xfb,0xff,0x79, +0x02,0x0b,0xff,0x7d,0x02,0x0d,0xff,0x7f,0x02,0x27,0xff,0x98,0x02,0x2b,0xff,0xda,0x02,0x3a,0xff,0x81,0x02,0x3c,0xff,0x98,0x02,0x48,0xff,0x7d,0x02,0x4c,0xff,0xb3,0x02,0x52,0xff,0xa0,0x02,0x64,0xff,0x7c,0x02,0x66,0xff,0x7c,0x02,0x67,0xff,0x9a,0x02,0x68,0xff,0x6c,0x02,0x83,0xff,0xe6,0x02,0xab,0xff,0x6b,0x02,0xb0,0xff,0x92, +0x02,0xb2,0xff,0xad,0x02,0xb6,0xff,0x7b,0x02,0xb9,0x00,0x0f,0x02,0xba,0xff,0x91,0x02,0xbb,0xff,0xf2,0x03,0x71,0xff,0xaf,0x03,0x75,0xff,0xb9,0x03,0x79,0xff,0xb9,0x03,0x82,0xff,0xb9,0x03,0xdb,0xff,0xb9,0x03,0xeb,0xff,0xbc,0x03,0xec,0xff,0xf1,0x03,0xef,0xff,0xf1,0x03,0xf0,0xff,0xed,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c, +0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90, +0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec, +0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x01,0x01,0x95,0xff,0xe2,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0,0x01,0x92,0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c, +0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c,0x02,0xba,0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x01,0x01,0x9b,0xff,0xf2,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0, +0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae, +0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8, +0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x01,0x01,0x95,0x00,0x0e,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b, +0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x02,0x01,0x9e,0xff,0xed,0x01,0xa1,0xff,0xec,0x00,0x0a,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xe6,0x01,0x92,0xff,0xeb,0x01,0x93,0xff,0xe9,0x01,0x98,0xff,0xf0,0x01,0x9a,0xff,0xe7,0x01,0x9e,0xff,0xe3,0x01,0xa0,0xff,0xce,0x01,0xa2,0xff,0xd4, +0x01,0xa3,0xff,0xdb,0x00,0x05,0x01,0x92,0xff,0xec,0x01,0x95,0x00,0x0f,0x01,0x9a,0xff,0xea,0x01,0x9e,0xff,0xdc,0x01,0xa0,0xff,0xe7,0x00,0x06,0x00,0x49,0xff,0xe9,0x01,0x92,0xff,0xee,0x01,0x95,0x00,0x10,0x01,0x9a,0xff,0xec,0x01,0x9e,0xff,0xbe,0x01,0xa1,0xff,0xda,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a, +0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x01,0x01,0x95,0x00,0x0f,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x06,0x01,0x9e,0xff,0xea, +0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x01,0x01,0x9e,0x00,0x0b,0x00,0x0d,0x00,0x49,0x00,0x0c,0x01,0x8e,0xff,0xed,0x01,0x9a,0x00,0x0b,0x01,0x9e,0x00,0x0c,0x03,0x71,0xff,0xbf,0x03,0x75,0xff,0xee,0x03,0x79,0xff,0xec,0x03,0x82,0xff,0xed,0x03,0xdb,0xff,0xec, +0x03,0xeb,0xff,0xf5,0x03,0xec,0x00,0x0e,0x03,0xee,0x00,0x0d,0x03,0xf1,0x00,0x0d,0x00,0x01,0x01,0xa1,0xff,0xe1,0x00,0x06,0x00,0x49,0x00,0x0b,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xf2,0x01,0xa0,0xff,0xf1,0x01,0xa1,0x00,0x0f,0x01,0xa3,0xff,0xef,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d, +0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x0b, +0x01,0xd8,0xff,0xd4,0x01,0xee,0xff,0xc9,0x02,0x0d,0xff,0xe5,0x02,0x2b,0xff,0xe3,0x02,0x4c,0xff,0xc4,0x02,0x63,0xff,0xe1,0x02,0xaf,0xff,0xd4,0x02,0xb0,0xff,0xf5,0x02,0xb1,0xff,0xe7,0x02,0xb9,0xff,0xd2,0x02,0xba,0xff,0xc9,0x00,0x31,0x00,0x55,0xff,0x6d,0x00,0x5a,0xff,0x8c,0x00,0x6d,0xfd,0xbf,0x00,0x7d,0xfe,0x7d,0x00,0x88, +0xfe,0xbc,0x00,0xa8,0xff,0x2b,0x00,0xba,0xff,0x4b,0x01,0x80,0xff,0x61,0x01,0x8e,0xff,0x8f,0x01,0x8f,0xff,0x0f,0x01,0x93,0xfe,0xe8,0x01,0x9a,0xff,0x1f,0x01,0x9b,0xfe,0xe5,0x01,0x9e,0xff,0x46,0x01,0xa0,0xfe,0xed,0x01,0xa1,0xff,0x59,0x01,0xa2,0xfe,0xfd,0x01,0xa3,0xfe,0xd9,0x01,0xc0,0xff,0x52,0x01,0xd8,0x00,0x05,0x01,0xdd, +0xff,0xbd,0x01,0xde,0xff,0x49,0x01,0xe0,0xfe,0xfe,0x01,0xe3,0xff,0x13,0x01,0xee,0xff,0x68,0x01,0xf7,0xff,0x0e,0x01,0xf9,0xff,0x13,0x01,0xfb,0xff,0x07,0x02,0x0b,0xff,0x0e,0x02,0x0d,0xff,0x11,0x02,0x27,0xff,0x3c,0x02,0x2b,0xff,0xac,0x02,0x3a,0xff,0x15,0x02,0x3c,0xff,0x3c,0x02,0x48,0xff,0x0e,0x02,0x4c,0xff,0x6a,0x02,0x52, +0xff,0x49,0x02,0x64,0xff,0x0c,0x02,0x66,0xff,0x0c,0x02,0x67,0xff,0x3f,0x02,0x68,0xfe,0xf1,0x02,0x83,0xff,0xc0,0x02,0xab,0xfe,0xef,0x02,0xb0,0xff,0x31,0x02,0xb2,0xff,0x5f,0x02,0xb6,0xff,0x0a,0x02,0xb9,0x00,0x05,0x02,0xba,0xff,0x30,0x02,0xbb,0xff,0xd5,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4, +0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x09,0x01,0xd8, +0xff,0xc3,0x01,0xee,0xff,0xcf,0x02,0x4c,0xff,0xce,0x02,0x63,0xff,0xe7,0x02,0x67,0xff,0xdf,0x02,0xaf,0xff,0xd1,0x02,0xb1,0xff,0xec,0x02,0xb9,0xff,0xa0,0x02,0xba,0xff,0xd1,0x00,0x09,0x01,0xd8,0xff,0xc3,0x01,0xee,0xff,0xcf,0x02,0x4c,0xff,0xce,0x02,0x63,0xff,0xe7,0x02,0x67,0xff,0xdf,0x02,0xaf,0xff,0xd1,0x02,0xb1,0xff,0xec, +0x02,0xb9,0xff,0xa0,0x02,0xba,0xff,0xd1,0x00,0x08,0x01,0xd8,0xff,0xc9,0x01,0xee,0xff,0xdf,0x02,0x0d,0xff,0xed,0x02,0x2b,0xff,0xeb,0x02,0x4c,0xff,0xdf,0x02,0x67,0xff,0xe9,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xe0,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9, +0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x13,0x01,0xc0,0xff,0xae,0x01,0xd8, +0x00,0x12,0x01,0xde,0xff,0xe0,0x01,0xe0,0xff,0xad,0x01,0xe3,0xff,0xd6,0x01,0xf7,0xff,0xdf,0x01,0xfb,0xff,0xd2,0x02,0x0b,0xff,0xe0,0x02,0x27,0xff,0xce,0x02,0x3a,0xff,0xdd,0x02,0x3c,0xff,0xe2,0x02,0x48,0xff,0xe0,0x02,0x52,0xff,0xe0,0x02,0x64,0xff,0xe9,0x02,0x66,0xff,0xde,0x02,0x68,0xff,0xda,0x02,0xab,0xff,0xbd,0x02,0xb6, +0xff,0xdf,0x02,0xb9,0x00,0x11,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82, +0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79, +0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x08,0x01,0xd8,0xff,0xe6,0x01,0xee,0xff,0xd0,0x02,0x4c,0xff,0xce,0x02,0x63,0xff,0xe8,0x02,0xaf,0xff,0xe7,0x02,0xb1,0xff,0xed,0x02,0xb9,0xff,0xe6,0x02,0xba,0xff,0xd0,0x00,0x02,0x02,0x16, +0x00,0x0b,0x02,0xb9,0xff,0xe6,0x00,0x31,0x00,0x55,0xff,0x6d,0x00,0x5a,0xff,0x8c,0x00,0x6d,0xfd,0xbf,0x00,0x7d,0xfe,0x7d,0x00,0x88,0xfe,0xbc,0x00,0xa8,0xff,0x2b,0x00,0xba,0xff,0x4b,0x01,0x80,0xff,0x61,0x01,0x8e,0xff,0x8f,0x01,0x8f,0xff,0x0f,0x01,0x93,0xfe,0xe8,0x01,0x9a,0xff,0x1f,0x01,0x9b,0xfe,0xe5,0x01,0x9e,0xff,0x46, +0x01,0xa0,0xfe,0xed,0x01,0xa1,0xff,0x59,0x01,0xa2,0xfe,0xfd,0x01,0xa3,0xfe,0xd9,0x01,0xc0,0xff,0x52,0x01,0xd8,0x00,0x05,0x01,0xdd,0xff,0xbd,0x01,0xde,0xff,0x49,0x01,0xe0,0xfe,0xfe,0x01,0xe3,0xff,0x13,0x01,0xee,0xff,0x68,0x01,0xf7,0xff,0x0e,0x01,0xf9,0xff,0x13,0x01,0xfb,0xff,0x07,0x02,0x0b,0xff,0x0e,0x02,0x0d,0xff,0x11, +0x02,0x27,0xff,0x3c,0x02,0x2b,0xff,0xac,0x02,0x3a,0xff,0x15,0x02,0x3c,0xff,0x3c,0x02,0x48,0xff,0x0e,0x02,0x4c,0xff,0x6a,0x02,0x52,0xff,0x49,0x02,0x64,0xff,0x0c,0x02,0x66,0xff,0x0c,0x02,0x67,0xff,0x3f,0x02,0x68,0xfe,0xf1,0x02,0x83,0xff,0xc0,0x02,0xab,0xfe,0xef,0x02,0xb0,0xff,0x31,0x02,0xb2,0xff,0x5f,0x02,0xb6,0xff,0x0a, +0x02,0xb9,0x00,0x05,0x02,0xba,0xff,0x30,0x02,0xbb,0xff,0xd5,0x00,0x0b,0x01,0xc0,0x00,0x14,0x01,0xd8,0xff,0xe0,0x01,0xe0,0x00,0x13,0x02,0x63,0xff,0xe1,0x02,0x64,0xff,0xe0,0x02,0x68,0xff,0xe1,0x02,0x83,0xff,0xe9,0x02,0xaf,0xff,0xdf,0x02,0xb1,0xff,0xde,0x02,0xb9,0xff,0xdf,0x02,0xbb,0xff,0xf2,0x00,0x05,0x00,0x49,0xff,0xee, +0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0,0x01,0x92,0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c, +0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c,0x02,0xba,0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x05,0x00,0x1a,0xff,0xf2,0x01,0xd8,0xff,0xf1,0x02,0xaf,0xff,0xf2, +0x02,0xb1,0xff,0xf2,0x02,0xb9,0xff,0xf2,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9, +0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0, +0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0, +0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed, +0x03,0xf0,0xff,0xf5,0x00,0x09,0x00,0x57,0x00,0x0e,0x00,0x88,0xff,0x9f,0x01,0x8e,0xff,0xf5,0x01,0x95,0xff,0xde,0x01,0x9b,0xff,0xe5,0x01,0xc0,0xff,0xa8,0x01,0xe0,0xff,0xca,0x02,0xab,0xff,0xe3,0x03,0x71,0xff,0xc6,0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed,0x00,0x3a,0x00,0x55, +0xff,0xb5,0x00,0x5a,0xff,0xc7,0x00,0x6d,0xfe,0xb8,0x00,0x7d,0xff,0x28,0x00,0x88,0xff,0x4d,0x00,0xa8,0xff,0x8e,0x00,0xba,0xff,0xa1,0x01,0x80,0xff,0xae,0x01,0x8e,0xff,0xc9,0x01,0x8f,0xff,0x7e,0x01,0x93,0xff,0x67,0x01,0x9a,0xff,0x87,0x01,0x9b,0xff,0x65,0x01,0x9e,0xff,0x9e,0x01,0xa0,0xff,0x6a,0x01,0xa1,0xff,0xa9,0x01,0xa2, +0xff,0x73,0x01,0xa3,0xff,0x5e,0x01,0xc0,0xff,0xa5,0x01,0xd8,0x00,0x0f,0x01,0xdd,0xff,0xe4,0x01,0xde,0xff,0xa0,0x01,0xe0,0xff,0x74,0x01,0xe3,0xff,0x80,0x01,0xee,0xff,0xb2,0x01,0xf7,0xff,0x7d,0x01,0xf9,0xff,0x80,0x01,0xfb,0xff,0x79,0x02,0x0b,0xff,0x7d,0x02,0x0d,0xff,0x7f,0x02,0x27,0xff,0x98,0x02,0x2b,0xff,0xda,0x02,0x3a, +0xff,0x81,0x02,0x3c,0xff,0x98,0x02,0x48,0xff,0x7d,0x02,0x4c,0xff,0xb3,0x02,0x52,0xff,0xa0,0x02,0x64,0xff,0x7c,0x02,0x66,0xff,0x7c,0x02,0x67,0xff,0x9a,0x02,0x68,0xff,0x6c,0x02,0x83,0xff,0xe6,0x02,0xab,0xff,0x6b,0x02,0xb0,0xff,0x92,0x02,0xb2,0xff,0xad,0x02,0xb6,0xff,0x7b,0x02,0xb9,0x00,0x0f,0x02,0xba,0xff,0x91,0x02,0xbb, +0xff,0xf2,0x03,0x71,0xff,0xaf,0x03,0x75,0xff,0xb9,0x03,0x79,0xff,0xb9,0x03,0x82,0xff,0xb9,0x03,0xdb,0xff,0xb9,0x03,0xeb,0xff,0xbc,0x03,0xec,0xff,0xf1,0x03,0xef,0xff,0xf1,0x03,0xf0,0xff,0xed,0x00,0x13,0x01,0xc0,0xff,0xae,0x01,0xd8,0x00,0x12,0x01,0xde,0xff,0xe0,0x01,0xe0,0xff,0xad,0x01,0xe3,0xff,0xd6,0x01,0xf7,0xff,0xdf, +0x01,0xfb,0xff,0xd2,0x02,0x0b,0xff,0xe0,0x02,0x27,0xff,0xce,0x02,0x3a,0xff,0xdd,0x02,0x3c,0xff,0xe2,0x02,0x48,0xff,0xe0,0x02,0x52,0xff,0xe0,0x02,0x64,0xff,0xe9,0x02,0x66,0xff,0xde,0x02,0x68,0xff,0xda,0x02,0xab,0xff,0xbd,0x02,0xb6,0xff,0xdf,0x02,0xb9,0x00,0x11,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0,0x01,0x92, +0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c,0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c,0x02,0xba, +0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0, +0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x0c,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xe6,0x01,0xd9,0xff,0xf4,0x01,0xe0,0x00,0x12,0x01,0xee,0xff,0xe7,0x02,0x4c,0xff,0xe7,0x02,0x63,0xff,0xe5,0x02,0x64,0xff,0xe8,0x02,0xaf,0xff,0xe6, +0x02,0xb1,0xff,0xe6,0x02,0xb9,0xff,0xe6,0x02,0xba,0xff,0xe7,0x00,0x09,0x01,0xd8,0xff,0xc3,0x01,0xee,0xff,0xcf,0x02,0x4c,0xff,0xce,0x02,0x63,0xff,0xe7,0x02,0x67,0xff,0xdf,0x02,0xaf,0xff,0xd1,0x02,0xb1,0xff,0xec,0x02,0xb9,0xff,0xa0,0x02,0xba,0xff,0xd1,0x00,0x09,0x01,0xd8,0xff,0xc3,0x01,0xee,0xff,0xcf,0x02,0x4c,0xff,0xce, +0x02,0x63,0xff,0xe7,0x02,0x67,0xff,0xdf,0x02,0xaf,0xff,0xd1,0x02,0xb1,0xff,0xec,0x02,0xb9,0xff,0xa0,0x02,0xba,0xff,0xd1,0x00,0x02,0x01,0xc0,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x02,0x01,0xc0,0xff,0xe1,0x01,0xe0,0xff,0xe4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0, +0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x06,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xee,0x02,0x0d,0xff,0xf4,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xef,0x02,0xba,0xff,0xef,0x00,0x04,0x01,0xee,0xff,0xf4,0x02,0x0d,0xff,0xf5,0x02,0x4c,0xff,0xf5,0x02,0xba,0xff,0xf5,0x00,0x02,0x01,0xe0,0xff,0xc9,0x02,0x27,0xff,0xee, +0x00,0x05,0x01,0xe0,0x00,0x14,0x01,0xee,0xff,0xed,0x02,0x4c,0xff,0xed,0x02,0x64,0xff,0xed,0x02,0xba,0xff,0xed,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x01,0x02,0x27,0xff,0xf1,0x00,0x05,0x02,0x27,0xff,0xeb,0x03,0x75,0xff,0xeb,0x03,0x79,0xff,0xe9,0x03,0x82,0xff,0xeb,0x03,0xdb,0xff,0xeb,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1, +0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x06,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x0f,0x00,0x49,0x00,0x0d,0x01,0xe0,0xff,0xc8,0x02,0x27, +0xff,0xec,0x02,0x2b,0x00,0x0c,0x02,0xb0,0x00,0x0b,0x02,0xb2,0x00,0x0b,0x03,0x71,0xff,0xbf,0x03,0x75,0xff,0xee,0x03,0x79,0xff,0xec,0x03,0x82,0xff,0xed,0x03,0xdb,0xff,0xec,0x03,0xeb,0xff,0xf5,0x03,0xec,0x00,0x0e,0x03,0xee,0x00,0x0d,0x03,0xf1,0x00,0x0d,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b, +0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x06,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x01,0x02,0x27,0xff,0xf1,0x00,0x06,0x01,0xe0,0x00,0x14,0x01,0xee,0xff,0xf0,0x01,0xfb,0x00,0x0c,0x02,0x4c, +0xff,0xf0,0x02,0x64,0xff,0xf0,0x02,0xba,0xff,0xf0,0x00,0x05,0x01,0xe0,0x00,0x12,0x01,0xee,0xff,0xe3,0x02,0x4c,0xff,0xe2,0x02,0x64,0xff,0xe3,0x02,0xba,0xff,0xe3,0x00,0x08,0x01,0xee,0xff,0xba,0x02,0x0d,0xff,0xd9,0x02,0x2b,0xff,0xdb,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xed,0x02,0xb0,0xff,0xf0,0x02,0xb2,0xff,0xf2,0x02,0xba, +0xff,0xba,0x00,0x08,0x01,0xee,0xff,0xba,0x02,0x0d,0xff,0xd9,0x02,0x2b,0xff,0xdb,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xed,0x02,0xb0,0xff,0xf0,0x02,0xb2,0xff,0xf2,0x02,0xba,0xff,0xba,0x00,0x06,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x01, +0x01,0xe0,0xff,0xef,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x02,0x01,0xe0,0xff,0xc9,0x02,0x27,0xff,0xee,0x00,0x08,0x01,0xee,0xff,0xba,0x02,0x0d,0xff,0xd9,0x02,0x2b,0xff,0xdb,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xed,0x02,0xb0,0xff,0xf0,0x02,0xb2,0xff,0xf2,0x02,0xba,0xff,0xba,0x00,0x08,0x01,0xee, +0xff,0xba,0x02,0x0d,0xff,0xd9,0x02,0x2b,0xff,0xdb,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xed,0x02,0xb0,0xff,0xf0,0x02,0xb2,0xff,0xf2,0x02,0xba,0xff,0xba,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x09,0x01,0xd8, +0xff,0xc3,0x01,0xee,0xff,0xcf,0x02,0x4c,0xff,0xce,0x02,0x63,0xff,0xe7,0x02,0x67,0xff,0xdf,0x02,0xaf,0xff,0xd1,0x02,0xb1,0xff,0xec,0x02,0xb9,0xff,0xa0,0x02,0xba,0xff,0xd1,0x00,0x08,0x01,0xee,0xff,0xba,0x02,0x0d,0xff,0xd9,0x02,0x2b,0xff,0xdb,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xed,0x02,0xb0,0xff,0xf0,0x02,0xb2,0xff,0xf2, +0x02,0xba,0xff,0xba,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67, +0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea, +0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x0c,0x00,0x14,0x00,0x40,0x00,0x11,0x00,0x55,0xff,0xe2,0x00,0x60,0x00,0x13,0x03,0x71,0xff,0xb4,0x03,0x75,0xff,0xd9,0x03,0x79,0xff,0xd9,0x03,0x82,0xff,0xd9,0x03,0xdb,0xff,0xd9,0x00,0x07, +0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x09,0x00,0x0c,0x00,0x14,0x00,0x40,0x00,0x11,0x00,0x55,0xff,0xe2,0x00,0x60,0x00,0x13,0x03,0x71,0xff,0xb4,0x03,0x75,0xff,0xd9,0x03,0x79,0xff,0xd9,0x03,0x82,0xff,0xd9,0x03,0xdb, +0xff,0xd9,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x06,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x31,0x00,0x55,0xff,0x6d, +0x00,0x5a,0xff,0x8c,0x00,0x6d,0xfd,0xbf,0x00,0x7d,0xfe,0x7d,0x00,0x88,0xfe,0xbc,0x00,0xa8,0xff,0x2b,0x00,0xba,0xff,0x4b,0x01,0x80,0xff,0x61,0x01,0x8e,0xff,0x8f,0x01,0x8f,0xff,0x0f,0x01,0x93,0xfe,0xe8,0x01,0x9a,0xff,0x1f,0x01,0x9b,0xfe,0xe5,0x01,0x9e,0xff,0x46,0x01,0xa0,0xfe,0xed,0x01,0xa1,0xff,0x59,0x01,0xa2,0xfe,0xfd, +0x01,0xa3,0xfe,0xd9,0x01,0xc0,0xff,0x52,0x01,0xd8,0x00,0x05,0x01,0xdd,0xff,0xbd,0x01,0xde,0xff,0x49,0x01,0xe0,0xfe,0xfe,0x01,0xe3,0xff,0x13,0x01,0xee,0xff,0x68,0x01,0xf7,0xff,0x0e,0x01,0xf9,0xff,0x13,0x01,0xfb,0xff,0x07,0x02,0x0b,0xff,0x0e,0x02,0x0d,0xff,0x11,0x02,0x27,0xff,0x3c,0x02,0x2b,0xff,0xac,0x02,0x3a,0xff,0x15, +0x02,0x3c,0xff,0x3c,0x02,0x48,0xff,0x0e,0x02,0x4c,0xff,0x6a,0x02,0x52,0xff,0x49,0x02,0x64,0xff,0x0c,0x02,0x66,0xff,0x0c,0x02,0x67,0xff,0x3f,0x02,0x68,0xfe,0xf1,0x02,0x83,0xff,0xc0,0x02,0xab,0xfe,0xef,0x02,0xb0,0xff,0x31,0x02,0xb2,0xff,0x5f,0x02,0xb6,0xff,0x0a,0x02,0xb9,0x00,0x05,0x02,0xba,0xff,0x30,0x02,0xbb,0xff,0xd5, +0x00,0x02,0x01,0xe0,0xff,0xc9,0x02,0x27,0xff,0xee,0x00,0x31,0x00,0x55,0xff,0x6d,0x00,0x5a,0xff,0x8c,0x00,0x6d,0xfd,0xbf,0x00,0x7d,0xfe,0x7d,0x00,0x88,0xfe,0xbc,0x00,0xa8,0xff,0x2b,0x00,0xba,0xff,0x4b,0x01,0x80,0xff,0x61,0x01,0x8e,0xff,0x8f,0x01,0x8f,0xff,0x0f,0x01,0x93,0xfe,0xe8,0x01,0x9a,0xff,0x1f,0x01,0x9b,0xfe,0xe5, +0x01,0x9e,0xff,0x46,0x01,0xa0,0xfe,0xed,0x01,0xa1,0xff,0x59,0x01,0xa2,0xfe,0xfd,0x01,0xa3,0xfe,0xd9,0x01,0xc0,0xff,0x52,0x01,0xd8,0x00,0x05,0x01,0xdd,0xff,0xbd,0x01,0xde,0xff,0x49,0x01,0xe0,0xfe,0xfe,0x01,0xe3,0xff,0x13,0x01,0xee,0xff,0x68,0x01,0xf7,0xff,0x0e,0x01,0xf9,0xff,0x13,0x01,0xfb,0xff,0x07,0x02,0x0b,0xff,0x0e, +0x02,0x0d,0xff,0x11,0x02,0x27,0xff,0x3c,0x02,0x2b,0xff,0xac,0x02,0x3a,0xff,0x15,0x02,0x3c,0xff,0x3c,0x02,0x48,0xff,0x0e,0x02,0x4c,0xff,0x6a,0x02,0x52,0xff,0x49,0x02,0x64,0xff,0x0c,0x02,0x66,0xff,0x0c,0x02,0x67,0xff,0x3f,0x02,0x68,0xfe,0xf1,0x02,0x83,0xff,0xc0,0x02,0xab,0xfe,0xef,0x02,0xb0,0xff,0x31,0x02,0xb2,0xff,0x5f, +0x02,0xb6,0xff,0x0a,0x02,0xb9,0x00,0x05,0x02,0xba,0xff,0x30,0x02,0xbb,0xff,0xd5,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0,0x01,0x92,0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c, +0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c,0x02,0xba,0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x01,0x02,0x27,0xff,0xf1,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80, +0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9,0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82, +0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9,0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb, +0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9,0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2,0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83, +0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x13,0x00,0x5a,0xff,0xc1,0x01,0x80,0xff,0xc5,0x01,0x9e,0xff,0xb4,0x01,0xdd,0xff,0xd7,0x01,0xee,0xff,0xb9,0x02,0x0d,0xff,0xb2,0x02,0x27,0xff,0xd2, +0x02,0x2b,0xff,0xc8,0x02,0x4c,0xff,0xa0,0x02,0x64,0xff,0xc5,0x02,0x83,0xff,0xe4,0x02,0xb0,0xff,0xcc,0x02,0xb2,0xff,0xcc,0x02,0xba,0xff,0xcb,0x02,0xbb,0xff,0xef,0x03,0x75,0xff,0xe8,0x03,0x79,0xff,0xe6,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64, +0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x04,0x00,0x0c,0xff,0xe6,0x00,0x40,0xff,0xf4,0x00,0x60,0xff,0xef,0x02,0x68,0xff,0xed,0x00,0x3a,0x00,0x55,0xff,0xb5,0x00,0x5a,0xff,0xc7,0x00,0x6d,0xfe,0xb8,0x00,0x7d,0xff,0x28,0x00,0x88,0xff,0x4d,0x00,0xa8,0xff,0x8e,0x00,0xba, +0xff,0xa1,0x01,0x80,0xff,0xae,0x01,0x8e,0xff,0xc9,0x01,0x8f,0xff,0x7e,0x01,0x93,0xff,0x67,0x01,0x9a,0xff,0x87,0x01,0x9b,0xff,0x65,0x01,0x9e,0xff,0x9e,0x01,0xa0,0xff,0x6a,0x01,0xa1,0xff,0xa9,0x01,0xa2,0xff,0x73,0x01,0xa3,0xff,0x5e,0x01,0xc0,0xff,0xa5,0x01,0xd8,0x00,0x0f,0x01,0xdd,0xff,0xe4,0x01,0xde,0xff,0xa0,0x01,0xe0, +0xff,0x74,0x01,0xe3,0xff,0x80,0x01,0xee,0xff,0xb2,0x01,0xf7,0xff,0x7d,0x01,0xf9,0xff,0x80,0x01,0xfb,0xff,0x79,0x02,0x0b,0xff,0x7d,0x02,0x0d,0xff,0x7f,0x02,0x27,0xff,0x98,0x02,0x2b,0xff,0xda,0x02,0x3a,0xff,0x81,0x02,0x3c,0xff,0x98,0x02,0x48,0xff,0x7d,0x02,0x4c,0xff,0xb3,0x02,0x52,0xff,0xa0,0x02,0x64,0xff,0x7c,0x02,0x66, +0xff,0x7c,0x02,0x67,0xff,0x9a,0x02,0x68,0xff,0x6c,0x02,0x83,0xff,0xe6,0x02,0xab,0xff,0x6b,0x02,0xb0,0xff,0x92,0x02,0xb2,0xff,0xad,0x02,0xb6,0xff,0x7b,0x02,0xb9,0x00,0x0f,0x02,0xba,0xff,0x91,0x02,0xbb,0xff,0xf2,0x03,0x71,0xff,0xaf,0x03,0x75,0xff,0xb9,0x03,0x79,0xff,0xb9,0x03,0x82,0xff,0xb9,0x03,0xdb,0xff,0xb9,0x03,0xeb, +0xff,0xbc,0x03,0xec,0xff,0xf1,0x03,0xef,0xff,0xf1,0x03,0xf0,0xff,0xed,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1, +0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3, +0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x24, +0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee, +0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb, +0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0,0x01,0x92,0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c, +0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c,0x02,0xba,0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x01,0x02,0x27,0xff,0xf1,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0, +0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0,0x01,0x92,0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12, +0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c,0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c,0x02,0xba,0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x01,0x02,0x27, +0xff,0xf1,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1, +0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82, +0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79, +0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57, +0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf, +0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3, +0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x18,0x01,0x80,0xff,0xd4,0x01,0x8e,0xff,0xf0,0x01,0x92,0xff,0xed,0x01,0x95, +0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c,0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d,0x02,0xb1,0x00,0x0c,0x02,0xba,0xff,0xd6,0x02,0xbb, +0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x01,0x02,0x27,0xff,0xf1,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08, +0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba, +0xff,0xec,0x00,0x06,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xe8,0x01,0xe0,0xff,0xee,0x01,0xee,0xff,0xeb,0x02,0x4c,0xff,0xec,0x02,0xba,0xff,0xec,0x00,0x13,0x01,0xc0,0xff,0xae,0x01,0xd8,0x00,0x12,0x01,0xde,0xff,0xe0,0x01,0xe0,0xff,0xad,0x01,0xe3,0xff,0xd6,0x01,0xf7,0xff,0xdf,0x01,0xfb,0xff,0xd2,0x02,0x0b,0xff,0xe0,0x02,0x27, +0xff,0xce,0x02,0x3a,0xff,0xdd,0x02,0x3c,0xff,0xe2,0x02,0x48,0xff,0xe0,0x02,0x52,0xff,0xe0,0x02,0x64,0xff,0xe9,0x02,0x66,0xff,0xde,0x02,0x68,0xff,0xda,0x02,0xab,0xff,0xbd,0x02,0xb6,0xff,0xdf,0x02,0xb9,0x00,0x11,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c, +0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x13,0x01,0xc0,0xff,0xae,0x01,0xd8,0x00,0x12,0x01,0xde,0xff,0xe0,0x01,0xe0,0xff,0xad,0x01,0xe3,0xff,0xd6,0x01,0xf7,0xff,0xdf,0x01,0xfb,0xff,0xd2,0x02,0x0b,0xff,0xe0,0x02,0x27,0xff,0xce,0x02,0x3a,0xff,0xdd,0x02,0x3c,0xff,0xe2,0x02,0x48,0xff,0xe0,0x02,0x52,0xff,0xe0,0x02,0x64, +0xff,0xe9,0x02,0x66,0xff,0xde,0x02,0x68,0xff,0xda,0x02,0xab,0xff,0xbd,0x02,0xb6,0xff,0xdf,0x02,0xb9,0x00,0x11,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x13,0x01,0xc0,0xff,0xae,0x01,0xd8,0x00,0x12,0x01,0xde, +0xff,0xe0,0x01,0xe0,0xff,0xad,0x01,0xe3,0xff,0xd6,0x01,0xf7,0xff,0xdf,0x01,0xfb,0xff,0xd2,0x02,0x0b,0xff,0xe0,0x02,0x27,0xff,0xce,0x02,0x3a,0xff,0xdd,0x02,0x3c,0xff,0xe2,0x02,0x48,0xff,0xe0,0x02,0x52,0xff,0xe0,0x02,0x64,0xff,0xe9,0x02,0x66,0xff,0xde,0x02,0x68,0xff,0xda,0x02,0xab,0xff,0xbd,0x02,0xb6,0xff,0xdf,0x02,0xb9, +0x00,0x11,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x31,0x00,0x55,0xff,0x6d,0x00,0x5a,0xff,0x8c,0x00,0x6d,0xfd,0xbf,0x00,0x7d,0xfe,0x7d,0x00,0x88,0xfe,0xbc,0x00,0xa8,0xff,0x2b,0x00,0xba,0xff,0x4b,0x01,0x80, +0xff,0x61,0x01,0x8e,0xff,0x8f,0x01,0x8f,0xff,0x0f,0x01,0x93,0xfe,0xe8,0x01,0x9a,0xff,0x1f,0x01,0x9b,0xfe,0xe5,0x01,0x9e,0xff,0x46,0x01,0xa0,0xfe,0xed,0x01,0xa1,0xff,0x59,0x01,0xa2,0xfe,0xfd,0x01,0xa3,0xfe,0xd9,0x01,0xc0,0xff,0x52,0x01,0xd8,0x00,0x05,0x01,0xdd,0xff,0xbd,0x01,0xde,0xff,0x49,0x01,0xe0,0xfe,0xfe,0x01,0xe3, +0xff,0x13,0x01,0xee,0xff,0x68,0x01,0xf7,0xff,0x0e,0x01,0xf9,0xff,0x13,0x01,0xfb,0xff,0x07,0x02,0x0b,0xff,0x0e,0x02,0x0d,0xff,0x11,0x02,0x27,0xff,0x3c,0x02,0x2b,0xff,0xac,0x02,0x3a,0xff,0x15,0x02,0x3c,0xff,0x3c,0x02,0x48,0xff,0x0e,0x02,0x4c,0xff,0x6a,0x02,0x52,0xff,0x49,0x02,0x64,0xff,0x0c,0x02,0x66,0xff,0x0c,0x02,0x67, +0xff,0x3f,0x02,0x68,0xfe,0xf1,0x02,0x83,0xff,0xc0,0x02,0xab,0xfe,0xef,0x02,0xb0,0xff,0x31,0x02,0xb2,0xff,0x5f,0x02,0xb6,0xff,0x0a,0x02,0xb9,0x00,0x05,0x02,0xba,0xff,0x30,0x02,0xbb,0xff,0xd5,0x00,0x02,0x01,0xe0,0xff,0xc9,0x02,0x27,0xff,0xee,0x00,0x02,0x01,0xe0,0xff,0xc9,0x02,0x27,0xff,0xee,0x00,0x18,0x01,0x80,0xff,0xd4, +0x01,0x8e,0xff,0xf0,0x01,0x92,0xff,0xed,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xe0,0x01,0xa0,0xff,0xe7,0x01,0xa2,0xff,0xe5,0x01,0xa3,0xff,0xee,0x01,0xc0,0x00,0x12,0x01,0xdd,0xff,0xe9,0x01,0xee,0xff,0xd7,0x02,0x4c,0xff,0xd7,0x02,0x64,0xff,0xd3,0x02,0x67,0xff,0xd6,0x02,0x68,0xff,0xc5,0x02,0x83,0xff,0xe7,0x02,0xaf,0x00,0x0d, +0x02,0xb1,0x00,0x0c,0x02,0xba,0xff,0xd6,0x02,0xbb,0xff,0xf2,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe9,0x00,0x01,0x02,0x27,0xff,0xf1,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11, +0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5, +0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4, +0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x0c,0x00,0x0f,0x00,0x40,0x00,0x0c,0x00,0x55,0xff,0xeb,0x00,0x60,0x00,0x0e,0x03,0x71,0xff,0xcb,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x09,0x00,0x0c,0x00,0x0f, +0x00,0x40,0x00,0x0c,0x00,0x55,0xff,0xeb,0x00,0x60,0x00,0x0e,0x03,0x71,0xff,0xcb,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82,0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x09,0x00,0x0c,0x00,0x0f,0x00,0x40,0x00,0x0c,0x00,0x55,0xff,0xeb,0x00,0x60,0x00,0x0e,0x03,0x71,0xff,0xcb,0x03,0x75,0xff,0xe9,0x03,0x79,0xff,0xe7,0x03,0x82, +0xff,0xe7,0x03,0xdb,0xff,0xe7,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b, +0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d, +0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5, +0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd, +0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1, +0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5, +0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef, +0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75, +0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2, +0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b, +0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d, +0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5, +0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd, +0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1, +0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5, +0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef, +0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75, +0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2, +0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b, +0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d, +0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5, +0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd, +0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef,0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1, +0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75,0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5, +0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2,0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x1c,0x00,0x22,0xff,0xc3,0x00,0x57,0xff,0xef, +0x00,0x5a,0xff,0xdf,0x01,0x45,0xff,0xee,0x01,0x80,0xff,0xe5,0x01,0x82,0xff,0xd1,0x01,0x95,0x00,0x11,0x01,0x9e,0xff,0xc8,0x01,0xc0,0x00,0x13,0x01,0xd8,0xff,0xc5,0x01,0xee,0xff,0xca,0x02,0x4c,0xff,0x9f,0x02,0x63,0xff,0x51,0x02,0x64,0xff,0x7b,0x02,0x67,0xff,0xca,0x02,0x68,0xff,0xdd,0x02,0x83,0xff,0xf2,0x02,0xaf,0xff,0x75, +0x02,0xb1,0xff,0xca,0x02,0xb9,0xff,0x4f,0x02,0xba,0xff,0x8c,0x03,0x79,0xff,0xf5,0x03,0x82,0xff,0xf5,0x03,0xec,0xff,0xc7,0x03,0xed,0xff,0xf1,0x03,0xee,0xff,0xcd,0x03,0xef,0xff,0xdd,0x03,0xf1,0xff,0xc4,0x00,0x07,0x01,0xee,0xff,0xf0,0x02,0x0d,0xff,0xf1,0x02,0x2b,0xff,0xf3,0x02,0x4c,0xff,0xf1,0x02,0xb0,0xff,0xf3,0x02,0xb2, +0xff,0xe9,0x02,0xba,0xff,0xd3,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05, +0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea, +0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed, +0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x05,0x00,0x49,0xff,0xee,0x00,0x5a,0xff,0xea,0x03,0xee,0xff,0xf0,0x03,0xef,0xff,0xed,0x03,0xf1,0xff,0xf0,0x00,0x01,0x01,0xee,0xff,0xf5,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3, +0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x08,0x01,0xc0,0x00,0x15,0x01,0xe0,0x00,0x15,0x02,0x63,0xff,0xe4,0x02,0x64,0xff,0xe5,0x02,0x67,0xff,0xe4,0x02,0xaf,0xff,0xe3,0x02,0xb1,0xff,0xe2,0x02,0xb9,0xff,0xe4,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf, +0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0, +0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf, +0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba, +0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c, +0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d, +0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1, +0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5, +0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5,0x02,0xba,0xff,0xec,0x00,0x08,0x01,0x9e,0xff,0xea,0x01,0xa1,0xff,0xea,0x01,0xee,0xff,0xea,0x02,0x0d,0xff,0xf0,0x02,0x2b,0xff,0xf1,0x02,0x4c,0xff,0xeb,0x02,0xb0,0xff,0xf5, +0x02,0xba,0xff,0xec,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x01,0x03,0x71,0xff,0xeb,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8, +0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d, +0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1, +0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e, +0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82, +0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40, +0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60,0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93, +0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0,0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0, +0xff,0xef,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b,0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x24,0x00,0x09,0xff,0xe2,0x00,0x0c,0x00,0x14,0x00,0x0d,0xff,0xcf,0x00,0x40,0x00,0x12,0x00,0x49,0xff,0xea,0x00,0x55,0xff,0xd8,0x00,0x57,0xff,0xea,0x00,0x60, +0x00,0x13,0x00,0x6d,0xff,0xae,0x00,0x7d,0xff,0xcd,0x00,0x88,0xff,0xa0,0x00,0xa8,0xff,0xc1,0x00,0xba,0xff,0xc0,0x01,0x80,0xff,0xd0,0x01,0x8c,0xff,0xea,0x01,0x8e,0xff,0xee,0x01,0x8f,0xff,0xc6,0x01,0x90,0x00,0x0d,0x01,0x92,0xff,0xe9,0x01,0x93,0xff,0xd6,0x01,0x9a,0xff,0xe8,0x01,0x9b,0xff,0xba,0x01,0x9e,0xff,0xe9,0x01,0xa0, +0xff,0xcb,0x01,0xa1,0xff,0xe8,0x01,0xa2,0xff,0xda,0x01,0xa3,0xff,0xc7,0x03,0x3d,0xff,0xd3,0x03,0x71,0xff,0xab,0x03,0x75,0xff,0xcd,0x03,0x79,0xff,0xcb,0x03,0x82,0xff,0xcb,0x03,0xdb,0xff,0xcb,0x03,0xec,0xff,0xf3,0x03,0xef,0xff,0xf3,0x03,0xf0,0xff,0xef,0x00,0x07,0x00,0x49,0x00,0x0d,0x01,0x8e,0xff,0xf5,0x01,0x9a,0x00,0x0b, +0x01,0x9b,0xff,0xea,0x01,0x9e,0x00,0x0c,0x01,0xe0,0xff,0xc8,0x02,0x27,0xff,0xf1,0x00,0x09,0x00,0x88,0xff,0xdf,0x01,0x79,0xff,0xf3,0x01,0x7d,0xff,0xf0,0x01,0x95,0xff,0xea,0x01,0xc0,0xff,0xdf,0x01,0xd8,0xff,0xe0,0x02,0xb9,0xff,0xe0,0x03,0x71,0xff,0xed,0x03,0xf0,0xff,0xf5,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x01,0x00,0x5a, +0x00,0x0b,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x01,0x00,0x5a,0x00,0x0b,0x00,0x09,0x03,0x75,0xff,0xf2,0x03,0x79,0xff,0xf2,0x03,0x82,0xff,0xf2,0x03,0xdb,0xff,0xf2,0x03,0xec,0xff,0xc0,0x03,0xed,0xff,0xec,0x03,0xee,0xff,0xc7,0x03,0xef, +0xff,0xd8,0x03,0xf1,0xff,0xbf,0x00,0x02,0x03,0xee,0xff,0xee,0x03,0xef,0xff,0xf5,0x00,0x01,0x03,0x71,0xff,0xd2,0x00,0x04,0x03,0x75,0xff,0xeb,0x03,0x79,0xff,0xe9,0x03,0x82,0xff,0xeb,0x03,0xdb,0xff,0xeb,0x00,0x0a,0x03,0x71,0x00,0x11,0x03,0x75,0xff,0xf0,0x03,0x79,0xff,0xee,0x03,0x82,0xff,0xef,0x03,0xdb,0xff,0xf0,0x03,0xec, +0xff,0xbb,0x03,0xed,0xff,0xec,0x03,0xee,0xff,0xb7,0x03,0xef,0xff,0xd5,0x03,0xf1,0xff,0xb4,0x00,0x05,0x03,0x71,0xff,0xf3,0x03,0xec,0xff,0xee,0x03,0xee,0xff,0xf1,0x03,0xf0,0xff,0xec,0x03,0xf1,0xff,0xea,0x00,0x04,0x03,0xec,0xff,0xe9,0x03,0xee,0xff,0xeb,0x03,0xef,0xff,0xf1,0x03,0xf1,0xff,0xe5,0x00,0x04,0x03,0xec,0xff,0xf2, +0x03,0xee,0xff,0xf1,0x03,0xef,0xff,0xf5,0x03,0xf1,0xff,0xee,0x00,0x09,0x03,0x71,0xff,0xbf,0x03,0x75,0xff,0xee,0x03,0x79,0xff,0xec,0x03,0x82,0xff,0xed,0x03,0xdb,0xff,0xec,0x03,0xeb,0xff,0xf5,0x03,0xec,0x00,0x0e,0x03,0xee,0x00,0x0d,0x03,0xf1,0x00,0x0d,0x00,0x01,0x03,0x71,0xff,0xef,0x00,0x05,0x03,0x71,0xff,0xc7,0x03,0x75, +0xff,0xf2,0x03,0x79,0xff,0xf0,0x03,0x82,0xff,0xf0,0x03,0xdb,0xff,0xf0,0x00,0x02,0x03,0x71,0xff,0xdc,0x03,0xec,0x00,0x0e,0x00,0x04,0x03,0x75,0xff,0xed,0x03,0x79,0xff,0xeb,0x03,0x82,0xff,0xeb,0x03,0xdb,0xff,0xeb,0x00,0x09,0x03,0x71,0xff,0xc0,0x03,0x75,0xff,0xed,0x03,0x79,0xff,0xeb,0x03,0x82,0xff,0xeb,0x03,0xdb,0xff,0xeb, +0x03,0xec,0x00,0x0f,0x03,0xee,0x00,0x10,0x03,0xef,0x00,0x0d,0x03,0xf1,0x00,0x10,0x00,0x05,0x03,0x71,0x00,0x0c,0x03,0x75,0xff,0xf0,0x03,0x79,0xff,0xf0,0x03,0x82,0xff,0xf0,0x03,0xdb,0xff,0xf0,0x00,0x01,0x03,0x71,0xff,0xd5,0x00,0x01,0x2f,0x52,0x00,0x04,0x00,0x00,0x00,0x0b,0x00,0x20,0x00,0x76,0x03,0x78,0x03,0xf2,0x04,0x58, +0x04,0x9a,0x05,0xb8,0x06,0xae,0x06,0xcc,0x07,0x0e,0x07,0xf4,0x00,0x15,0x00,0x39,0x00,0x14,0x00,0x3a,0x00,0x12,0x00,0x3c,0x00,0x16,0x00,0x9f,0x00,0x16,0x01,0x36,0x00,0x12,0x01,0x38,0x00,0x16,0x01,0x3a,0x00,0x16,0x01,0x69,0x00,0x16,0x01,0x7f,0x00,0x16,0x01,0x85,0x00,0x16,0x02,0x20,0x00,0x14,0x02,0x22,0x00,0x14,0x02,0x59, +0x00,0x16,0x02,0x5b,0x00,0x16,0x02,0xc3,0x00,0x12,0x02,0xc5,0x00,0x12,0x02,0xc7,0x00,0x12,0x03,0x1b,0x00,0x16,0x03,0x1d,0x00,0x16,0x03,0x1f,0x00,0x16,0x03,0x21,0x00,0x16,0x00,0xc0,0x00,0x0f,0xff,0x16,0x00,0x11,0xff,0x16,0x00,0x1d,0xff,0x16,0x00,0x24,0xff,0xc5,0x00,0x44,0xff,0xde,0x00,0x46,0xff,0xeb,0x00,0x47,0xff,0xeb, +0x00,0x48,0xff,0xeb,0x00,0x4a,0xff,0xeb,0x00,0x52,0xff,0xeb,0x00,0x54,0xff,0xeb,0x00,0x58,0xff,0xea,0x00,0x59,0xff,0xe8,0x00,0x5c,0xff,0xe8,0x00,0x82,0xff,0xc5,0x00,0x83,0xff,0xc5,0x00,0x84,0xff,0xc5,0x00,0x85,0xff,0xc5,0x00,0x86,0xff,0xc5,0x00,0x87,0xff,0xc5,0x00,0xa2,0xff,0xde,0x00,0xa3,0xff,0xde,0x00,0xa4,0xff,0xde, +0x00,0xa5,0xff,0xde,0x00,0xa6,0xff,0xde,0x00,0xa7,0xff,0xde,0x00,0xa9,0xff,0xeb,0x00,0xaa,0xff,0xeb,0x00,0xab,0xff,0xeb,0x00,0xac,0xff,0xeb,0x00,0xad,0xff,0xeb,0x00,0xb4,0xff,0xeb,0x00,0xb5,0xff,0xeb,0x00,0xb6,0xff,0xeb,0x00,0xb7,0xff,0xeb,0x00,0xb8,0xff,0xeb,0x00,0xbb,0xff,0xea,0x00,0xbc,0xff,0xea,0x00,0xbd,0xff,0xea, +0x00,0xbe,0xff,0xea,0x00,0xbf,0xff,0xe8,0x00,0xc1,0xff,0xe8,0x00,0xc2,0xff,0xc5,0x00,0xc3,0xff,0xde,0x00,0xc4,0xff,0xc5,0x00,0xc5,0xff,0xde,0x00,0xc6,0xff,0xc5,0x00,0xc7,0xff,0xde,0x00,0xc9,0xff,0xeb,0x00,0xcb,0xff,0xeb,0x00,0xcd,0xff,0xeb,0x00,0xcf,0xff,0xeb,0x00,0xd1,0xff,0xeb,0x00,0xd5,0xff,0xeb,0x00,0xd7,0xff,0xeb, +0x00,0xd9,0xff,0xeb,0x00,0xdb,0xff,0xeb,0x00,0xdd,0xff,0xeb,0x00,0xdf,0xff,0xeb,0x00,0xe1,0xff,0xeb,0x00,0xe3,0xff,0xeb,0x00,0xe5,0xff,0xeb,0x01,0x0f,0xff,0xeb,0x01,0x11,0xff,0xeb,0x01,0x13,0xff,0xeb,0x01,0x15,0xff,0xeb,0x01,0x2b,0xff,0xea,0x01,0x2d,0xff,0xea,0x01,0x2f,0xff,0xea,0x01,0x31,0xff,0xea,0x01,0x33,0xff,0xea, +0x01,0x35,0xff,0xea,0x01,0x39,0xff,0xe8,0x01,0x44,0xff,0xeb,0x01,0x46,0xff,0xea,0x01,0x48,0xff,0xc5,0x01,0x49,0xff,0xde,0x01,0x63,0xff,0xc5,0x01,0x6c,0xff,0xc5,0x01,0x6f,0xff,0xc5,0x01,0x76,0xff,0xc5,0x01,0x86,0xff,0xeb,0x01,0x8a,0xff,0xea,0x01,0x8b,0xff,0xeb,0x01,0x8d,0xff,0xe8,0x01,0x97,0xff,0xe8,0x01,0x99,0xff,0xeb, +0x01,0x9c,0xff,0xeb,0x01,0x9d,0xff,0xeb,0x01,0x9f,0xff,0xea,0x01,0xa5,0xff,0xea,0x01,0xa6,0xff,0xeb,0x01,0xa7,0xff,0xea,0x01,0xbc,0xff,0xc5,0x01,0xdc,0xff,0xde,0x01,0xe1,0xff,0xeb,0x01,0xea,0xff,0xeb,0x01,0xed,0xff,0xeb,0x01,0xef,0xff,0xe8,0x01,0xf0,0xff,0xeb,0x01,0xfc,0xff,0xeb,0x01,0xfd,0xff,0xeb,0x02,0x00,0xff,0xeb, +0x02,0x0a,0xff,0xe8,0x02,0x12,0xff,0xc5,0x02,0x1f,0xff,0xeb,0x02,0x21,0xff,0xe8,0x02,0x23,0xff,0xe8,0x02,0x25,0xff,0xeb,0x02,0x29,0xff,0xeb,0x02,0x2d,0xff,0xeb,0x02,0x54,0xff,0xeb,0x02,0x56,0xff,0xeb,0x02,0x5a,0xff,0xe8,0x02,0x7b,0xff,0xc5,0x02,0x7c,0xff,0xde,0x02,0x7d,0xff,0xc5,0x02,0x7e,0xff,0xde,0x02,0x82,0xff,0xeb, +0x02,0x84,0xff,0xeb,0x02,0x86,0xff,0xeb,0x02,0x92,0xff,0xeb,0x02,0x94,0xff,0xeb,0x02,0x96,0xff,0xeb,0x02,0x9a,0xff,0xe8,0x02,0x9c,0xff,0xe8,0x02,0x9e,0xff,0xe8,0x02,0xac,0xff,0xeb,0x02,0xad,0xff,0xeb,0x02,0xae,0xff,0xeb,0x02,0xb8,0xff,0xeb,0x02,0xbf,0xff,0xc5,0x02,0xc0,0xff,0xde,0x02,0xc9,0xff,0xc5,0x02,0xca,0xff,0xde, +0x02,0xcb,0xff,0xc5,0x02,0xcc,0xff,0xde,0x02,0xcd,0xff,0xc5,0x02,0xce,0xff,0xde,0x02,0xcf,0xff,0xc5,0x02,0xd0,0xff,0xde,0x02,0xd1,0xff,0xc5,0x02,0xd2,0xff,0xde,0x02,0xd3,0xff,0xc5,0x02,0xd4,0xff,0xde,0x02,0xd5,0xff,0xc5,0x02,0xd6,0xff,0xde,0x02,0xd7,0xff,0xc5,0x02,0xd8,0xff,0xde,0x02,0xd9,0xff,0xc5,0x02,0xda,0xff,0xde, +0x02,0xdb,0xff,0xc5,0x02,0xdc,0xff,0xde,0x02,0xdd,0xff,0xc5,0x02,0xde,0xff,0xde,0x02,0xdf,0xff,0xc5,0x02,0xe0,0xff,0xde,0x02,0xe2,0xff,0xeb,0x02,0xe4,0xff,0xeb,0x02,0xe6,0xff,0xeb,0x02,0xe8,0xff,0xeb,0x02,0xea,0xff,0xeb,0x02,0xec,0xff,0xeb,0x02,0xee,0xff,0xeb,0x02,0xf0,0xff,0xeb,0x02,0xf6,0xff,0xeb,0x02,0xf8,0xff,0xeb, +0x02,0xfa,0xff,0xeb,0x02,0xfc,0xff,0xeb,0x02,0xfe,0xff,0xeb,0x03,0x00,0xff,0xeb,0x03,0x02,0xff,0xeb,0x03,0x04,0xff,0xeb,0x03,0x06,0xff,0xeb,0x03,0x08,0xff,0xeb,0x03,0x0a,0xff,0xeb,0x03,0x0c,0xff,0xeb,0x03,0x0e,0xff,0xea,0x03,0x10,0xff,0xea,0x03,0x12,0xff,0xea,0x03,0x14,0xff,0xea,0x03,0x16,0xff,0xea,0x03,0x18,0xff,0xea, +0x03,0x1a,0xff,0xea,0x03,0x1c,0xff,0xe8,0x03,0x1e,0xff,0xe8,0x03,0x20,0xff,0xe8,0x03,0x22,0xff,0xe8,0x03,0x36,0xff,0x16,0x03,0x3a,0xff,0x16,0x03,0x3e,0xff,0x16,0x03,0x3f,0xff,0x16,0x00,0x1e,0x00,0x37,0xff,0xd5,0x00,0x39,0xff,0xe4,0x00,0x3a,0xff,0xec,0x00,0x3c,0xff,0xdd,0x00,0x9f,0xff,0xdd,0x01,0x24,0xff,0xd5,0x01,0x26, +0xff,0xd5,0x01,0x36,0xff,0xec,0x01,0x38,0xff,0xdd,0x01,0x3a,0xff,0xdd,0x01,0x69,0xff,0xdd,0x01,0x7f,0xff,0xdd,0x01,0x85,0xff,0xdd,0x01,0xae,0xff,0xd5,0x01,0xb7,0xff,0xd5,0x01,0xce,0xff,0xd5,0x02,0x20,0xff,0xe4,0x02,0x22,0xff,0xe4,0x02,0x4b,0xff,0xd5,0x02,0x57,0xff,0xd5,0x02,0x59,0xff,0xdd,0x02,0x5b,0xff,0xdd,0x02,0x5f, +0xff,0xd5,0x02,0xc3,0xff,0xec,0x02,0xc5,0xff,0xec,0x02,0xc7,0xff,0xec,0x03,0x1b,0xff,0xdd,0x03,0x1d,0xff,0xdd,0x03,0x1f,0xff,0xdd,0x03,0x21,0xff,0xdd,0x00,0x19,0x00,0x37,0xff,0xb0,0x00,0x39,0xff,0xed,0x00,0x3c,0xff,0xd0,0x00,0x9f,0xff,0xd0,0x01,0x24,0xff,0xb0,0x01,0x26,0xff,0xb0,0x01,0x38,0xff,0xd0,0x01,0x3a,0xff,0xd0, +0x01,0x69,0xff,0xd0,0x01,0x7f,0xff,0xd0,0x01,0x85,0xff,0xd0,0x01,0xae,0xff,0xb0,0x01,0xb7,0xff,0xb0,0x01,0xce,0xff,0xb0,0x02,0x20,0xff,0xed,0x02,0x22,0xff,0xed,0x02,0x4b,0xff,0xb0,0x02,0x57,0xff,0xb0,0x02,0x59,0xff,0xd0,0x02,0x5b,0xff,0xd0,0x02,0x5f,0xff,0xb0,0x03,0x1b,0xff,0xd0,0x03,0x1d,0xff,0xd0,0x03,0x1f,0xff,0xd0, +0x03,0x21,0xff,0xd0,0x00,0x10,0x00,0x2d,0xff,0xee,0x00,0x38,0xff,0xee,0x00,0x9b,0xff,0xee,0x00,0x9c,0xff,0xee,0x00,0x9d,0xff,0xee,0x00,0x9e,0xff,0xee,0x00,0xf6,0xff,0xee,0x01,0x2a,0xff,0xee,0x01,0x2c,0xff,0xee,0x01,0x2e,0xff,0xee,0x01,0x30,0xff,0xee,0x01,0x32,0xff,0xee,0x01,0x34,0xff,0xee,0x01,0xb4,0xff,0xee,0x03,0x0d, +0xff,0xee,0x03,0x0f,0xff,0xee,0x00,0x47,0x00,0x05,0x00,0x10,0x00,0x0a,0x00,0x10,0x00,0x46,0xff,0xe8,0x00,0x47,0xff,0xe8,0x00,0x48,0xff,0xe8,0x00,0x4a,0xff,0xe8,0x00,0x54,0xff,0xe8,0x00,0xa9,0xff,0xe8,0x00,0xaa,0xff,0xe8,0x00,0xab,0xff,0xe8,0x00,0xac,0xff,0xe8,0x00,0xad,0xff,0xe8,0x00,0xc9,0xff,0xe8,0x00,0xcb,0xff,0xe8, +0x00,0xcd,0xff,0xe8,0x00,0xcf,0xff,0xe8,0x00,0xd1,0xff,0xe8,0x00,0xd5,0xff,0xe8,0x00,0xd7,0xff,0xe8,0x00,0xd9,0xff,0xe8,0x00,0xdb,0xff,0xe8,0x00,0xdd,0xff,0xe8,0x00,0xdf,0xff,0xe8,0x00,0xe1,0xff,0xe8,0x00,0xe3,0xff,0xe8,0x00,0xe5,0xff,0xe8,0x01,0x15,0xff,0xe8,0x01,0x44,0xff,0xe8,0x01,0x51,0x00,0x10,0x01,0x86,0xff,0xe8, +0x01,0x8b,0xff,0xe8,0x01,0x9c,0xff,0xe8,0x01,0x9d,0xff,0xe8,0x01,0xe1,0xff,0xe8,0x01,0xed,0xff,0xe8,0x01,0xf0,0xff,0xe8,0x01,0xfc,0xff,0xe8,0x01,0xfd,0xff,0xe8,0x02,0x00,0xff,0xe8,0x02,0x25,0xff,0xe8,0x02,0x29,0xff,0xe8,0x02,0x2d,0xff,0xe8,0x02,0x54,0xff,0xe8,0x02,0x56,0xff,0xe8,0x02,0x82,0xff,0xe8,0x02,0x84,0xff,0xe8, +0x02,0x86,0xff,0xe8,0x02,0x94,0xff,0xe8,0x02,0xac,0xff,0xe8,0x02,0xad,0xff,0xe8,0x02,0xae,0xff,0xe8,0x02,0xb8,0xff,0xe8,0x02,0xe2,0xff,0xe8,0x02,0xe4,0xff,0xe8,0x02,0xe6,0xff,0xe8,0x02,0xe8,0xff,0xe8,0x02,0xea,0xff,0xe8,0x02,0xec,0xff,0xe8,0x02,0xee,0xff,0xe8,0x02,0xf0,0xff,0xe8,0x03,0x04,0xff,0xe8,0x03,0x06,0xff,0xe8, +0x03,0x08,0xff,0xe8,0x03,0x0c,0xff,0xe8,0x03,0x34,0x00,0x10,0x03,0x35,0x00,0x10,0x03,0x37,0x00,0x10,0x03,0x38,0x00,0x10,0x03,0x39,0x00,0x10,0x03,0x41,0x00,0x10,0x03,0x42,0x00,0x10,0x00,0x3d,0x00,0x46,0xff,0xec,0x00,0x47,0xff,0xec,0x00,0x48,0xff,0xec,0x00,0x4a,0xff,0xec,0x00,0x54,0xff,0xec,0x00,0xa9,0xff,0xec,0x00,0xaa, +0xff,0xec,0x00,0xab,0xff,0xec,0x00,0xac,0xff,0xec,0x00,0xad,0xff,0xec,0x00,0xc9,0xff,0xec,0x00,0xcb,0xff,0xec,0x00,0xcd,0xff,0xec,0x00,0xcf,0xff,0xec,0x00,0xd1,0xff,0xec,0x00,0xd5,0xff,0xec,0x00,0xd7,0xff,0xec,0x00,0xd9,0xff,0xec,0x00,0xdb,0xff,0xec,0x00,0xdd,0xff,0xec,0x00,0xdf,0xff,0xec,0x00,0xe1,0xff,0xec,0x00,0xe3, +0xff,0xec,0x00,0xe5,0xff,0xec,0x01,0x15,0xff,0xec,0x01,0x44,0xff,0xec,0x01,0x86,0xff,0xec,0x01,0x8b,0xff,0xec,0x01,0x9c,0xff,0xec,0x01,0x9d,0xff,0xec,0x01,0xe1,0xff,0xec,0x01,0xed,0xff,0xec,0x01,0xf0,0xff,0xec,0x01,0xfc,0xff,0xec,0x01,0xfd,0xff,0xec,0x02,0x00,0xff,0xec,0x02,0x25,0xff,0xec,0x02,0x29,0xff,0xec,0x02,0x2d, +0xff,0xec,0x02,0x54,0xff,0xec,0x02,0x56,0xff,0xec,0x02,0x82,0xff,0xec,0x02,0x84,0xff,0xec,0x02,0x86,0xff,0xec,0x02,0x94,0xff,0xec,0x02,0xac,0xff,0xec,0x02,0xad,0xff,0xec,0x02,0xae,0xff,0xec,0x02,0xb8,0xff,0xec,0x02,0xe2,0xff,0xec,0x02,0xe4,0xff,0xec,0x02,0xe6,0xff,0xec,0x02,0xe8,0xff,0xec,0x02,0xea,0xff,0xec,0x02,0xec, +0xff,0xec,0x02,0xee,0xff,0xec,0x02,0xf0,0xff,0xec,0x03,0x04,0xff,0xec,0x03,0x06,0xff,0xec,0x03,0x08,0xff,0xec,0x03,0x0c,0xff,0xec,0x00,0x07,0x00,0x0f,0xff,0x84,0x00,0x11,0xff,0x84,0x00,0x1d,0xff,0x84,0x03,0x36,0xff,0x84,0x03,0x3a,0xff,0x84,0x03,0x3e,0xff,0x84,0x03,0x3f,0xff,0x84,0x00,0x10,0x00,0x2d,0xff,0xec,0x00,0x38, +0xff,0xec,0x00,0x9b,0xff,0xec,0x00,0x9c,0xff,0xec,0x00,0x9d,0xff,0xec,0x00,0x9e,0xff,0xec,0x00,0xf6,0xff,0xec,0x01,0x2a,0xff,0xec,0x01,0x2c,0xff,0xec,0x01,0x2e,0xff,0xec,0x01,0x30,0xff,0xec,0x01,0x32,0xff,0xec,0x01,0x34,0xff,0xec,0x01,0xb4,0xff,0xec,0x03,0x0d,0xff,0xec,0x03,0x0f,0xff,0xec,0x00,0x39,0x00,0x26,0xff,0xf3, +0x00,0x2a,0xff,0xf3,0x00,0x32,0xff,0xf3,0x00,0x34,0xff,0xf3,0x00,0x89,0xff,0xf3,0x00,0x94,0xff,0xf3,0x00,0x95,0xff,0xf3,0x00,0x96,0xff,0xf3,0x00,0x97,0xff,0xf3,0x00,0x98,0xff,0xf3,0x00,0x9a,0xff,0xf3,0x00,0xc8,0xff,0xf3,0x00,0xca,0xff,0xf3,0x00,0xcc,0xff,0xf3,0x00,0xce,0xff,0xf3,0x00,0xde,0xff,0xf3,0x00,0xe0,0xff,0xf3, +0x00,0xe2,0xff,0xf3,0x00,0xe4,0xff,0xf3,0x01,0x0e,0xff,0xf3,0x01,0x10,0xff,0xf3,0x01,0x12,0xff,0xf3,0x01,0x14,0xff,0xf3,0x01,0x43,0xff,0xf3,0x01,0x4c,0xff,0xf3,0x01,0x68,0xff,0xf3,0x01,0x73,0xff,0xf3,0x01,0x7a,0xff,0xf3,0x01,0xb0,0xff,0xf3,0x01,0xca,0xff,0xf3,0x01,0xcd,0xff,0xf3,0x02,0x0c,0xff,0xf3,0x02,0x1e,0xff,0xf3, +0x02,0x24,0xff,0xf3,0x02,0x26,0xff,0xf3,0x02,0x28,0xff,0xf3,0x02,0x2a,0xff,0xf3,0x02,0x2c,0xff,0xf3,0x02,0x53,0xff,0xf3,0x02,0x55,0xff,0xf3,0x02,0x91,0xff,0xf3,0x02,0x93,0xff,0xf3,0x02,0x95,0xff,0xf3,0x02,0xb7,0xff,0xf3,0x02,0xf5,0xff,0xf3,0x02,0xf7,0xff,0xf3,0x02,0xf9,0xff,0xf3,0x02,0xfb,0xff,0xf3,0x02,0xfd,0xff,0xf3, +0x02,0xff,0xff,0xf3,0x03,0x01,0xff,0xf3,0x03,0x03,0xff,0xf3,0x03,0x05,0xff,0xf3,0x03,0x07,0xff,0xf3,0x03,0x09,0xff,0xf3,0x03,0x0b,0xff,0xf3,0x03,0x23,0xff,0xf3,0x00,0x39,0x00,0x26,0xff,0xe6,0x00,0x2a,0xff,0xe6,0x00,0x32,0xff,0xe6,0x00,0x34,0xff,0xe6,0x00,0x89,0xff,0xe6,0x00,0x94,0xff,0xe6,0x00,0x95,0xff,0xe6,0x00,0x96, +0xff,0xe6,0x00,0x97,0xff,0xe6,0x00,0x98,0xff,0xe6,0x00,0x9a,0xff,0xe6,0x00,0xc8,0xff,0xe6,0x00,0xca,0xff,0xe6,0x00,0xcc,0xff,0xe6,0x00,0xce,0xff,0xe6,0x00,0xde,0xff,0xe6,0x00,0xe0,0xff,0xe6,0x00,0xe2,0xff,0xe6,0x00,0xe4,0xff,0xe6,0x01,0x0e,0xff,0xe6,0x01,0x10,0xff,0xe6,0x01,0x12,0xff,0xe6,0x01,0x14,0xff,0xe6,0x01,0x43, +0xff,0xe6,0x01,0x4c,0xff,0xe6,0x01,0x68,0xff,0xe6,0x01,0x73,0xff,0xe6,0x01,0x7a,0xff,0xe6,0x01,0xb0,0xff,0xe6,0x01,0xca,0xff,0xe6,0x01,0xcd,0xff,0xe6,0x02,0x0c,0xff,0xe6,0x02,0x1e,0xff,0xe6,0x02,0x24,0xff,0xe6,0x02,0x26,0xff,0xe6,0x02,0x28,0xff,0xe6,0x02,0x2a,0xff,0xe6,0x02,0x2c,0xff,0xe6,0x02,0x53,0xff,0xe6,0x02,0x55, +0xff,0xe6,0x02,0x91,0xff,0xe6,0x02,0x93,0xff,0xe6,0x02,0x95,0xff,0xe6,0x02,0xb7,0xff,0xe6,0x02,0xf5,0xff,0xe6,0x02,0xf7,0xff,0xe6,0x02,0xf9,0xff,0xe6,0x02,0xfb,0xff,0xe6,0x02,0xfd,0xff,0xe6,0x02,0xff,0xff,0xe6,0x03,0x01,0xff,0xe6,0x03,0x03,0xff,0xe6,0x03,0x05,0xff,0xe6,0x03,0x07,0xff,0xe6,0x03,0x09,0xff,0xe6,0x03,0x0b, +0xff,0xe6,0x03,0x23,0xff,0xe6,0x00,0x01,0x26,0x92,0x00,0x04,0x00,0x00,0x00,0x1f,0x00,0x48,0x01,0x22,0x01,0xc0,0x04,0x5a,0x06,0x20,0x06,0xf2,0x07,0xe8,0x09,0xae,0x09,0xe0,0x0b,0x5a,0x0b,0x8c,0x0c,0x0a,0x0d,0xec,0x0e,0x5e,0x0f,0x2c,0x11,0x3a,0x11,0xec,0x13,0x4e,0x14,0x04,0x14,0x86,0x14,0xe0,0x15,0xa2,0x16,0x18,0x16,0x2a, +0x16,0x54,0x17,0xa6,0x19,0xe8,0x1a,0x0a,0x1b,0x20,0x1b,0x9e,0x1b,0xc8,0x00,0x36,0x00,0x24,0xff,0xe4,0x00,0x3b,0xff,0xd2,0x00,0x3c,0xff,0xd3,0x00,0x82,0xff,0xe4,0x00,0x83,0xff,0xe4,0x00,0x84,0xff,0xe4,0x00,0x85,0xff,0xe4,0x00,0x86,0xff,0xe4,0x00,0x87,0xff,0xe4,0x00,0x9f,0xff,0xd3,0x00,0xc2,0xff,0xe4,0x00,0xc4,0xff,0xe4, +0x00,0xc6,0xff,0xe4,0x01,0x38,0xff,0xd3,0x01,0x3a,0xff,0xd3,0x01,0x48,0xff,0xe4,0x01,0x63,0xff,0xe4,0x01,0x69,0xff,0xd3,0x01,0x6c,0xff,0xe4,0x01,0x6f,0xff,0xe4,0x01,0x76,0xff,0xe4,0x01,0x7f,0xff,0xd3,0x01,0x81,0xff,0xd2,0x01,0x85,0xff,0xd3,0x01,0xbc,0xff,0xe4,0x01,0xc2,0xff,0xd2,0x01,0xd1,0xff,0xd2,0x02,0x12,0xff,0xe4, +0x02,0x41,0xff,0xd2,0x02,0x59,0xff,0xd3,0x02,0x5b,0xff,0xd3,0x02,0x5d,0xff,0xd2,0x02,0x6c,0xff,0xd2,0x02,0x7b,0xff,0xe4,0x02,0x7d,0xff,0xe4,0x02,0x87,0xff,0xd2,0x02,0xa7,0xff,0xd2,0x02,0xbf,0xff,0xe4,0x02,0xc9,0xff,0xe4,0x02,0xcb,0xff,0xe4,0x02,0xcd,0xff,0xe4,0x02,0xcf,0xff,0xe4,0x02,0xd1,0xff,0xe4,0x02,0xd3,0xff,0xe4, +0x02,0xd5,0xff,0xe4,0x02,0xd7,0xff,0xe4,0x02,0xd9,0xff,0xe4,0x02,0xdb,0xff,0xe4,0x02,0xdd,0xff,0xe4,0x02,0xdf,0xff,0xe4,0x03,0x1b,0xff,0xd3,0x03,0x1d,0xff,0xd3,0x03,0x1f,0xff,0xd3,0x03,0x21,0xff,0xd3,0x00,0x27,0x00,0x0f,0xff,0x1e,0x00,0x11,0xff,0x1e,0x00,0x1d,0xff,0x1e,0x00,0x24,0xff,0xcd,0x00,0x82,0xff,0xcd,0x00,0x83, +0xff,0xcd,0x00,0x84,0xff,0xcd,0x00,0x85,0xff,0xcd,0x00,0x86,0xff,0xcd,0x00,0x87,0xff,0xcd,0x00,0xc2,0xff,0xcd,0x00,0xc4,0xff,0xcd,0x00,0xc6,0xff,0xcd,0x01,0x48,0xff,0xcd,0x01,0x63,0xff,0xcd,0x01,0x6c,0xff,0xcd,0x01,0x6f,0xff,0xcd,0x01,0x76,0xff,0xcd,0x01,0xbc,0xff,0xcd,0x02,0x12,0xff,0xcd,0x02,0x7b,0xff,0xcd,0x02,0x7d, +0xff,0xcd,0x02,0xbf,0xff,0xcd,0x02,0xc9,0xff,0xcd,0x02,0xcb,0xff,0xcd,0x02,0xcd,0xff,0xcd,0x02,0xcf,0xff,0xcd,0x02,0xd1,0xff,0xcd,0x02,0xd3,0xff,0xcd,0x02,0xd5,0xff,0xcd,0x02,0xd7,0xff,0xcd,0x02,0xd9,0xff,0xcd,0x02,0xdb,0xff,0xcd,0x02,0xdd,0xff,0xcd,0x02,0xdf,0xff,0xcd,0x03,0x36,0xff,0x1e,0x03,0x3a,0xff,0x1e,0x03,0x3e, +0xff,0x1e,0x03,0x3f,0xff,0x1e,0x00,0xa6,0x00,0x46,0xff,0xdc,0x00,0x47,0xff,0xdc,0x00,0x48,0xff,0xdc,0x00,0x4a,0xff,0xdc,0x00,0x50,0xff,0xf3,0x00,0x51,0xff,0xf3,0x00,0x52,0xff,0xd6,0x00,0x53,0xff,0xf3,0x00,0x54,0xff,0xdc,0x00,0x58,0xff,0xdd,0x00,0x59,0xff,0xe1,0x00,0x5c,0xff,0xe1,0x00,0xa9,0xff,0xdc,0x00,0xaa,0xff,0xdc, +0x00,0xab,0xff,0xdc,0x00,0xac,0xff,0xdc,0x00,0xad,0xff,0xdc,0x00,0xb3,0xff,0xf3,0x00,0xb4,0xff,0xd6,0x00,0xb5,0xff,0xd6,0x00,0xb6,0xff,0xd6,0x00,0xb7,0xff,0xd6,0x00,0xb8,0xff,0xd6,0x00,0xbb,0xff,0xdd,0x00,0xbc,0xff,0xdd,0x00,0xbd,0xff,0xdd,0x00,0xbe,0xff,0xdd,0x00,0xbf,0xff,0xe1,0x00,0xc1,0xff,0xe1,0x00,0xc9,0xff,0xdc, +0x00,0xcb,0xff,0xdc,0x00,0xcd,0xff,0xdc,0x00,0xcf,0xff,0xdc,0x00,0xd1,0xff,0xdc,0x00,0xd5,0xff,0xdc,0x00,0xd7,0xff,0xdc,0x00,0xd9,0xff,0xdc,0x00,0xdb,0xff,0xdc,0x00,0xdd,0xff,0xdc,0x00,0xdf,0xff,0xdc,0x00,0xe1,0xff,0xdc,0x00,0xe3,0xff,0xdc,0x00,0xe5,0xff,0xdc,0x01,0x06,0xff,0xf3,0x01,0x08,0xff,0xf3,0x01,0x0a,0xff,0xf3, +0x01,0x0b,0xff,0xf3,0x01,0x0f,0xff,0xd6,0x01,0x11,0xff,0xd6,0x01,0x13,0xff,0xd6,0x01,0x15,0xff,0xdc,0x01,0x2b,0xff,0xdd,0x01,0x2d,0xff,0xdd,0x01,0x2f,0xff,0xdd,0x01,0x31,0xff,0xdd,0x01,0x33,0xff,0xdd,0x01,0x35,0xff,0xdd,0x01,0x39,0xff,0xe1,0x01,0x44,0xff,0xdc,0x01,0x46,0xff,0xdd,0x01,0x86,0xff,0xdc,0x01,0x88,0xff,0xf3, +0x01,0x8a,0xff,0xdd,0x01,0x8b,0xff,0xdc,0x01,0x8d,0xff,0xe1,0x01,0x91,0xff,0xf3,0x01,0x97,0xff,0xe1,0x01,0x99,0xff,0xd6,0x01,0x9c,0xff,0xdc,0x01,0x9d,0xff,0xdc,0x01,0x9f,0xff,0xdd,0x01,0xa5,0xff,0xdd,0x01,0xa6,0xff,0xd6,0x01,0xa7,0xff,0xdd,0x01,0xdf,0xff,0xf3,0x01,0xe1,0xff,0xdc,0x01,0xe4,0xff,0xf3,0x01,0xe5,0xff,0xf3, +0x01,0xe6,0xff,0xf3,0x01,0xe8,0xff,0xf3,0x01,0xe9,0xff,0xf3,0x01,0xea,0xff,0xd6,0x01,0xeb,0xff,0xf3,0x01,0xec,0xff,0xf3,0x01,0xed,0xff,0xdc,0x01,0xef,0xff,0xe1,0x01,0xf0,0xff,0xdc,0x01,0xf2,0xff,0xf3,0x01,0xf4,0xff,0xf3,0x01,0xf5,0xff,0xf3,0x01,0xf8,0xff,0xf3,0x01,0xfa,0xff,0xf3,0x01,0xfc,0xff,0xdc,0x01,0xfd,0xff,0xdc, +0x01,0xff,0xff,0xf3,0x02,0x00,0xff,0xdc,0x02,0x06,0xff,0xf3,0x02,0x08,0xff,0xf3,0x02,0x09,0xff,0xf3,0x02,0x0a,0xff,0xe1,0x02,0x1f,0xff,0xd6,0x02,0x21,0xff,0xe1,0x02,0x23,0xff,0xe1,0x02,0x25,0xff,0xdc,0x02,0x29,0xff,0xdc,0x02,0x2d,0xff,0xdc,0x02,0x36,0xff,0xf3,0x02,0x46,0xff,0xf3,0x02,0x4e,0xff,0xf3,0x02,0x50,0xff,0xf3, +0x02,0x54,0xff,0xdc,0x02,0x56,0xff,0xdc,0x02,0x5a,0xff,0xe1,0x02,0x73,0xff,0xf3,0x02,0x75,0xff,0xf3,0x02,0x79,0xff,0xf3,0x02,0x82,0xff,0xdc,0x02,0x84,0xff,0xdc,0x02,0x86,0xff,0xdc,0x02,0x8e,0xff,0xf3,0x02,0x90,0xff,0xf3,0x02,0x92,0xff,0xd6,0x02,0x94,0xff,0xdc,0x02,0x96,0xff,0xd6,0x02,0x9a,0xff,0xe1,0x02,0x9c,0xff,0xe1, +0x02,0x9e,0xff,0xe1,0x02,0xa2,0xff,0xf3,0x02,0xa4,0xff,0xf3,0x02,0xa6,0xff,0xf3,0x02,0xac,0xff,0xdc,0x02,0xad,0xff,0xdc,0x02,0xae,0xff,0xdc,0x02,0xb8,0xff,0xdc,0x02,0xc2,0xff,0xf3,0x02,0xe2,0xff,0xdc,0x02,0xe4,0xff,0xdc,0x02,0xe6,0xff,0xdc,0x02,0xe8,0xff,0xdc,0x02,0xea,0xff,0xdc,0x02,0xec,0xff,0xdc,0x02,0xee,0xff,0xdc, +0x02,0xf0,0xff,0xdc,0x02,0xf6,0xff,0xd6,0x02,0xf8,0xff,0xd6,0x02,0xfa,0xff,0xd6,0x02,0xfc,0xff,0xd6,0x02,0xfe,0xff,0xd6,0x03,0x00,0xff,0xd6,0x03,0x02,0xff,0xd6,0x03,0x04,0xff,0xdc,0x03,0x06,0xff,0xdc,0x03,0x08,0xff,0xdc,0x03,0x0a,0xff,0xd6,0x03,0x0c,0xff,0xdc,0x03,0x0e,0xff,0xdd,0x03,0x10,0xff,0xdd,0x03,0x12,0xff,0xdd, +0x03,0x14,0xff,0xdd,0x03,0x16,0xff,0xdd,0x03,0x18,0xff,0xdd,0x03,0x1a,0xff,0xdd,0x03,0x1c,0xff,0xe1,0x03,0x1e,0xff,0xe1,0x03,0x20,0xff,0xe1,0x03,0x22,0xff,0xe1,0x00,0x71,0x00,0x05,0xff,0xda,0x00,0x0a,0xff,0xda,0x00,0x46,0xff,0xf0,0x00,0x47,0xff,0xf0,0x00,0x48,0xff,0xf0,0x00,0x4a,0xff,0xf0,0x00,0x54,0xff,0xf0,0x00,0x58, +0xff,0xef,0x00,0x59,0xff,0xdc,0x00,0x5c,0xff,0xdc,0x00,0xa9,0xff,0xf0,0x00,0xaa,0xff,0xf0,0x00,0xab,0xff,0xf0,0x00,0xac,0xff,0xf0,0x00,0xad,0xff,0xf0,0x00,0xbb,0xff,0xef,0x00,0xbc,0xff,0xef,0x00,0xbd,0xff,0xef,0x00,0xbe,0xff,0xef,0x00,0xbf,0xff,0xdc,0x00,0xc1,0xff,0xdc,0x00,0xc9,0xff,0xf0,0x00,0xcb,0xff,0xf0,0x00,0xcd, +0xff,0xf0,0x00,0xcf,0xff,0xf0,0x00,0xd1,0xff,0xf0,0x00,0xd5,0xff,0xf0,0x00,0xd7,0xff,0xf0,0x00,0xd9,0xff,0xf0,0x00,0xdb,0xff,0xf0,0x00,0xdd,0xff,0xf0,0x00,0xdf,0xff,0xf0,0x00,0xe1,0xff,0xf0,0x00,0xe3,0xff,0xf0,0x00,0xe5,0xff,0xf0,0x01,0x15,0xff,0xf0,0x01,0x2b,0xff,0xef,0x01,0x2d,0xff,0xef,0x01,0x2f,0xff,0xef,0x01,0x31, +0xff,0xef,0x01,0x33,0xff,0xef,0x01,0x35,0xff,0xef,0x01,0x39,0xff,0xdc,0x01,0x44,0xff,0xf0,0x01,0x46,0xff,0xef,0x01,0x51,0xff,0xda,0x01,0x86,0xff,0xf0,0x01,0x8a,0xff,0xef,0x01,0x8b,0xff,0xf0,0x01,0x8d,0xff,0xdc,0x01,0x97,0xff,0xdc,0x01,0x9c,0xff,0xf0,0x01,0x9d,0xff,0xf0,0x01,0x9f,0xff,0xef,0x01,0xa5,0xff,0xef,0x01,0xa7, +0xff,0xef,0x01,0xe1,0xff,0xf0,0x01,0xed,0xff,0xf0,0x01,0xef,0xff,0xdc,0x01,0xf0,0xff,0xf0,0x01,0xfc,0xff,0xf0,0x01,0xfd,0xff,0xf0,0x02,0x00,0xff,0xf0,0x02,0x0a,0xff,0xdc,0x02,0x21,0xff,0xdc,0x02,0x23,0xff,0xdc,0x02,0x25,0xff,0xf0,0x02,0x29,0xff,0xf0,0x02,0x2d,0xff,0xf0,0x02,0x54,0xff,0xf0,0x02,0x56,0xff,0xf0,0x02,0x5a, +0xff,0xdc,0x02,0x82,0xff,0xf0,0x02,0x84,0xff,0xf0,0x02,0x86,0xff,0xf0,0x02,0x94,0xff,0xf0,0x02,0x9a,0xff,0xdc,0x02,0x9c,0xff,0xdc,0x02,0x9e,0xff,0xdc,0x02,0xac,0xff,0xf0,0x02,0xad,0xff,0xf0,0x02,0xae,0xff,0xf0,0x02,0xb8,0xff,0xf0,0x02,0xe2,0xff,0xf0,0x02,0xe4,0xff,0xf0,0x02,0xe6,0xff,0xf0,0x02,0xe8,0xff,0xf0,0x02,0xea, +0xff,0xf0,0x02,0xec,0xff,0xf0,0x02,0xee,0xff,0xf0,0x02,0xf0,0xff,0xf0,0x03,0x04,0xff,0xf0,0x03,0x06,0xff,0xf0,0x03,0x08,0xff,0xf0,0x03,0x0c,0xff,0xf0,0x03,0x0e,0xff,0xef,0x03,0x10,0xff,0xef,0x03,0x12,0xff,0xef,0x03,0x14,0xff,0xef,0x03,0x16,0xff,0xef,0x03,0x18,0xff,0xef,0x03,0x1a,0xff,0xef,0x03,0x1c,0xff,0xdc,0x03,0x1e, +0xff,0xdc,0x03,0x20,0xff,0xdc,0x03,0x22,0xff,0xdc,0x03,0x34,0xff,0xda,0x03,0x35,0xff,0xda,0x03,0x37,0xff,0xda,0x03,0x38,0xff,0xda,0x03,0x39,0xff,0xda,0x03,0x41,0xff,0xda,0x03,0x42,0xff,0xda,0x00,0x34,0x00,0x05,0xff,0xa0,0x00,0x0a,0xff,0xa0,0x00,0x58,0xff,0xf1,0x00,0x59,0xff,0xc5,0x00,0x5c,0xff,0xc5,0x00,0xbb,0xff,0xf1, +0x00,0xbc,0xff,0xf1,0x00,0xbd,0xff,0xf1,0x00,0xbe,0xff,0xf1,0x00,0xbf,0xff,0xc5,0x00,0xc1,0xff,0xc5,0x01,0x2b,0xff,0xf1,0x01,0x2d,0xff,0xf1,0x01,0x2f,0xff,0xf1,0x01,0x31,0xff,0xf1,0x01,0x33,0xff,0xf1,0x01,0x35,0xff,0xf1,0x01,0x39,0xff,0xc5,0x01,0x46,0xff,0xf1,0x01,0x51,0xff,0xa0,0x01,0x8a,0xff,0xf1,0x01,0x8d,0xff,0xc5, +0x01,0x97,0xff,0xc5,0x01,0x9f,0xff,0xf1,0x01,0xa5,0xff,0xf1,0x01,0xa7,0xff,0xf1,0x01,0xef,0xff,0xc5,0x02,0x0a,0xff,0xc5,0x02,0x21,0xff,0xc5,0x02,0x23,0xff,0xc5,0x02,0x5a,0xff,0xc5,0x02,0x9a,0xff,0xc5,0x02,0x9c,0xff,0xc5,0x02,0x9e,0xff,0xc5,0x03,0x0e,0xff,0xf1,0x03,0x10,0xff,0xf1,0x03,0x12,0xff,0xf1,0x03,0x14,0xff,0xf1, +0x03,0x16,0xff,0xf1,0x03,0x18,0xff,0xf1,0x03,0x1a,0xff,0xf1,0x03,0x1c,0xff,0xc5,0x03,0x1e,0xff,0xc5,0x03,0x20,0xff,0xc5,0x03,0x22,0xff,0xc5,0x03,0x34,0xff,0xa0,0x03,0x35,0xff,0xa0,0x03,0x37,0xff,0xa0,0x03,0x38,0xff,0xa0,0x03,0x39,0xff,0xa0,0x03,0x41,0xff,0xa0,0x03,0x42,0xff,0xa0,0x00,0x3d,0x00,0x46,0xff,0xe7,0x00,0x47, +0xff,0xe7,0x00,0x48,0xff,0xe7,0x00,0x4a,0xff,0xe7,0x00,0x54,0xff,0xe7,0x00,0xa9,0xff,0xe7,0x00,0xaa,0xff,0xe7,0x00,0xab,0xff,0xe7,0x00,0xac,0xff,0xe7,0x00,0xad,0xff,0xe7,0x00,0xc9,0xff,0xe7,0x00,0xcb,0xff,0xe7,0x00,0xcd,0xff,0xe7,0x00,0xcf,0xff,0xe7,0x00,0xd1,0xff,0xe7,0x00,0xd5,0xff,0xe7,0x00,0xd7,0xff,0xe7,0x00,0xd9, +0xff,0xe7,0x00,0xdb,0xff,0xe7,0x00,0xdd,0xff,0xe7,0x00,0xdf,0xff,0xe7,0x00,0xe1,0xff,0xe7,0x00,0xe3,0xff,0xe7,0x00,0xe5,0xff,0xe7,0x01,0x15,0xff,0xe7,0x01,0x44,0xff,0xe7,0x01,0x86,0xff,0xe7,0x01,0x8b,0xff,0xe7,0x01,0x9c,0xff,0xe7,0x01,0x9d,0xff,0xe7,0x01,0xe1,0xff,0xe7,0x01,0xed,0xff,0xe7,0x01,0xf0,0xff,0xe7,0x01,0xfc, +0xff,0xe7,0x01,0xfd,0xff,0xe7,0x02,0x00,0xff,0xe7,0x02,0x25,0xff,0xe7,0x02,0x29,0xff,0xe7,0x02,0x2d,0xff,0xe7,0x02,0x54,0xff,0xe7,0x02,0x56,0xff,0xe7,0x02,0x82,0xff,0xe7,0x02,0x84,0xff,0xe7,0x02,0x86,0xff,0xe7,0x02,0x94,0xff,0xe7,0x02,0xac,0xff,0xe7,0x02,0xad,0xff,0xe7,0x02,0xae,0xff,0xe7,0x02,0xb8,0xff,0xe7,0x02,0xe2, +0xff,0xe7,0x02,0xe4,0xff,0xe7,0x02,0xe6,0xff,0xe7,0x02,0xe8,0xff,0xe7,0x02,0xea,0xff,0xe7,0x02,0xec,0xff,0xe7,0x02,0xee,0xff,0xe7,0x02,0xf0,0xff,0xe7,0x03,0x04,0xff,0xe7,0x03,0x06,0xff,0xe7,0x03,0x08,0xff,0xe7,0x03,0x0c,0xff,0xe7,0x00,0x71,0x00,0x05,0x00,0x0c,0x00,0x0a,0x00,0x0c,0x00,0x46,0xff,0xe8,0x00,0x47,0xff,0xe8, +0x00,0x48,0xff,0xe8,0x00,0x4a,0xff,0xe8,0x00,0x52,0xff,0xea,0x00,0x54,0xff,0xe8,0x00,0x59,0x00,0x0b,0x00,0x5c,0x00,0x0b,0x00,0xa9,0xff,0xe8,0x00,0xaa,0xff,0xe8,0x00,0xab,0xff,0xe8,0x00,0xac,0xff,0xe8,0x00,0xad,0xff,0xe8,0x00,0xb4,0xff,0xea,0x00,0xb5,0xff,0xea,0x00,0xb6,0xff,0xea,0x00,0xb7,0xff,0xea,0x00,0xb8,0xff,0xea, +0x00,0xbf,0x00,0x0b,0x00,0xc1,0x00,0x0b,0x00,0xc9,0xff,0xe8,0x00,0xcb,0xff,0xe8,0x00,0xcd,0xff,0xe8,0x00,0xcf,0xff,0xe8,0x00,0xd1,0xff,0xe8,0x00,0xd5,0xff,0xe8,0x00,0xd7,0xff,0xe8,0x00,0xd9,0xff,0xe8,0x00,0xdb,0xff,0xe8,0x00,0xdd,0xff,0xe8,0x00,0xdf,0xff,0xe8,0x00,0xe1,0xff,0xe8,0x00,0xe3,0xff,0xe8,0x00,0xe5,0xff,0xe8, +0x01,0x0f,0xff,0xea,0x01,0x11,0xff,0xea,0x01,0x13,0xff,0xea,0x01,0x15,0xff,0xe8,0x01,0x39,0x00,0x0b,0x01,0x44,0xff,0xe8,0x01,0x51,0x00,0x0c,0x01,0x86,0xff,0xe8,0x01,0x8b,0xff,0xe8,0x01,0x8d,0x00,0x0b,0x01,0x97,0x00,0x0b,0x01,0x99,0xff,0xea,0x01,0x9c,0xff,0xe8,0x01,0x9d,0xff,0xe8,0x01,0xa6,0xff,0xea,0x01,0xe1,0xff,0xe8, +0x01,0xea,0xff,0xea,0x01,0xed,0xff,0xe8,0x01,0xef,0x00,0x0b,0x01,0xf0,0xff,0xe8,0x01,0xfc,0xff,0xe8,0x01,0xfd,0xff,0xe8,0x02,0x00,0xff,0xe8,0x02,0x0a,0x00,0x0b,0x02,0x1f,0xff,0xea,0x02,0x21,0x00,0x0b,0x02,0x23,0x00,0x0b,0x02,0x25,0xff,0xe8,0x02,0x29,0xff,0xe8,0x02,0x2d,0xff,0xe8,0x02,0x54,0xff,0xe8,0x02,0x56,0xff,0xe8, +0x02,0x5a,0x00,0x0b,0x02,0x82,0xff,0xe8,0x02,0x84,0xff,0xe8,0x02,0x86,0xff,0xe8,0x02,0x92,0xff,0xea,0x02,0x94,0xff,0xe8,0x02,0x96,0xff,0xea,0x02,0x9a,0x00,0x0b,0x02,0x9c,0x00,0x0b,0x02,0x9e,0x00,0x0b,0x02,0xac,0xff,0xe8,0x02,0xad,0xff,0xe8,0x02,0xae,0xff,0xe8,0x02,0xb8,0xff,0xe8,0x02,0xe2,0xff,0xe8,0x02,0xe4,0xff,0xe8, +0x02,0xe6,0xff,0xe8,0x02,0xe8,0xff,0xe8,0x02,0xea,0xff,0xe8,0x02,0xec,0xff,0xe8,0x02,0xee,0xff,0xe8,0x02,0xf0,0xff,0xe8,0x02,0xf6,0xff,0xea,0x02,0xf8,0xff,0xea,0x02,0xfa,0xff,0xea,0x02,0xfc,0xff,0xea,0x02,0xfe,0xff,0xea,0x03,0x00,0xff,0xea,0x03,0x02,0xff,0xea,0x03,0x04,0xff,0xe8,0x03,0x06,0xff,0xe8,0x03,0x08,0xff,0xe8, +0x03,0x0a,0xff,0xea,0x03,0x0c,0xff,0xe8,0x03,0x1c,0x00,0x0b,0x03,0x1e,0x00,0x0b,0x03,0x20,0x00,0x0b,0x03,0x22,0x00,0x0b,0x03,0x34,0x00,0x0c,0x03,0x35,0x00,0x0c,0x03,0x37,0x00,0x0c,0x03,0x38,0x00,0x0c,0x03,0x39,0x00,0x0c,0x03,0x41,0x00,0x0c,0x03,0x42,0x00,0x0c,0x00,0x0c,0x00,0x5b,0xff,0xed,0x00,0x5d,0xff,0xed,0x01,0x3c, +0xff,0xed,0x01,0x3e,0xff,0xed,0x01,0x40,0xff,0xed,0x01,0xe2,0xff,0xed,0x01,0xf1,0xff,0xed,0x02,0x42,0xff,0xed,0x02,0x5e,0xff,0xed,0x02,0x6d,0xff,0xed,0x02,0x88,0xff,0xed,0x02,0xa8,0xff,0xed,0x00,0x5e,0x00,0x05,0x00,0x0b,0x00,0x0a,0x00,0x0b,0x00,0x46,0xff,0xeb,0x00,0x47,0xff,0xeb,0x00,0x48,0xff,0xeb,0x00,0x4a,0xff,0xeb, +0x00,0x52,0xff,0xe9,0x00,0x54,0xff,0xeb,0x00,0xa9,0xff,0xeb,0x00,0xaa,0xff,0xeb,0x00,0xab,0xff,0xeb,0x00,0xac,0xff,0xeb,0x00,0xad,0xff,0xeb,0x00,0xb4,0xff,0xe9,0x00,0xb5,0xff,0xe9,0x00,0xb6,0xff,0xe9,0x00,0xb7,0xff,0xe9,0x00,0xb8,0xff,0xe9,0x00,0xc9,0xff,0xeb,0x00,0xcb,0xff,0xeb,0x00,0xcd,0xff,0xeb,0x00,0xcf,0xff,0xeb, +0x00,0xd1,0xff,0xeb,0x00,0xd5,0xff,0xeb,0x00,0xd7,0xff,0xeb,0x00,0xd9,0xff,0xeb,0x00,0xdb,0xff,0xeb,0x00,0xdd,0xff,0xeb,0x00,0xdf,0xff,0xeb,0x00,0xe1,0xff,0xeb,0x00,0xe3,0xff,0xeb,0x00,0xe5,0xff,0xeb,0x01,0x0f,0xff,0xe9,0x01,0x11,0xff,0xe9,0x01,0x13,0xff,0xe9,0x01,0x15,0xff,0xeb,0x01,0x44,0xff,0xeb,0x01,0x51,0x00,0x0b, +0x01,0x86,0xff,0xeb,0x01,0x8b,0xff,0xeb,0x01,0x99,0xff,0xe9,0x01,0x9c,0xff,0xeb,0x01,0x9d,0xff,0xeb,0x01,0xa6,0xff,0xe9,0x01,0xe1,0xff,0xeb,0x01,0xea,0xff,0xe9,0x01,0xed,0xff,0xeb,0x01,0xf0,0xff,0xeb,0x01,0xfc,0xff,0xeb,0x01,0xfd,0xff,0xeb,0x02,0x00,0xff,0xeb,0x02,0x1f,0xff,0xe9,0x02,0x25,0xff,0xeb,0x02,0x29,0xff,0xeb, +0x02,0x2d,0xff,0xeb,0x02,0x54,0xff,0xeb,0x02,0x56,0xff,0xeb,0x02,0x82,0xff,0xeb,0x02,0x84,0xff,0xeb,0x02,0x86,0xff,0xeb,0x02,0x92,0xff,0xe9,0x02,0x94,0xff,0xeb,0x02,0x96,0xff,0xe9,0x02,0xac,0xff,0xeb,0x02,0xad,0xff,0xeb,0x02,0xae,0xff,0xeb,0x02,0xb8,0xff,0xeb,0x02,0xe2,0xff,0xeb,0x02,0xe4,0xff,0xeb,0x02,0xe6,0xff,0xeb, +0x02,0xe8,0xff,0xeb,0x02,0xea,0xff,0xeb,0x02,0xec,0xff,0xeb,0x02,0xee,0xff,0xeb,0x02,0xf0,0xff,0xeb,0x02,0xf6,0xff,0xe9,0x02,0xf8,0xff,0xe9,0x02,0xfa,0xff,0xe9,0x02,0xfc,0xff,0xe9,0x02,0xfe,0xff,0xe9,0x03,0x00,0xff,0xe9,0x03,0x02,0xff,0xe9,0x03,0x04,0xff,0xeb,0x03,0x06,0xff,0xeb,0x03,0x08,0xff,0xeb,0x03,0x0a,0xff,0xe9, +0x03,0x0c,0xff,0xeb,0x03,0x34,0x00,0x0b,0x03,0x35,0x00,0x0b,0x03,0x37,0x00,0x0b,0x03,0x38,0x00,0x0b,0x03,0x39,0x00,0x0b,0x03,0x41,0x00,0x0b,0x03,0x42,0x00,0x0b,0x00,0x0c,0x00,0x5b,0xff,0xf2,0x00,0x5d,0xff,0xf2,0x01,0x3c,0xff,0xf2,0x01,0x3e,0xff,0xf2,0x01,0x40,0xff,0xf2,0x01,0xe2,0xff,0xf2,0x01,0xf1,0xff,0xf2,0x02,0x42, +0xff,0xf2,0x02,0x5e,0xff,0xf2,0x02,0x6d,0xff,0xf2,0x02,0x88,0xff,0xf2,0x02,0xa8,0xff,0xf2,0x00,0x1f,0x00,0x59,0xff,0xf4,0x00,0x5b,0xff,0xf2,0x00,0x5c,0xff,0xf4,0x00,0x5d,0xff,0xf3,0x00,0xbf,0xff,0xf4,0x00,0xc1,0xff,0xf4,0x01,0x39,0xff,0xf4,0x01,0x3c,0xff,0xf3,0x01,0x3e,0xff,0xf3,0x01,0x40,0xff,0xf3,0x01,0x8d,0xff,0xf4, +0x01,0x97,0xff,0xf4,0x01,0xe2,0xff,0xf2,0x01,0xef,0xff,0xf4,0x01,0xf1,0xff,0xf2,0x02,0x0a,0xff,0xf4,0x02,0x21,0xff,0xf4,0x02,0x23,0xff,0xf4,0x02,0x42,0xff,0xf2,0x02,0x5a,0xff,0xf4,0x02,0x5e,0xff,0xf2,0x02,0x6d,0xff,0xf2,0x02,0x88,0xff,0xf2,0x02,0x9a,0xff,0xf4,0x02,0x9c,0xff,0xf4,0x02,0x9e,0xff,0xf4,0x02,0xa8,0xff,0xf2, +0x03,0x1c,0xff,0xf4,0x03,0x1e,0xff,0xf4,0x03,0x20,0xff,0xf4,0x03,0x22,0xff,0xf4,0x00,0x78,0x00,0x05,0xff,0xca,0x00,0x0a,0xff,0xca,0x00,0x37,0xff,0xd2,0x00,0x39,0xff,0xd4,0x00,0x3b,0xff,0xf4,0x00,0x3c,0xff,0xd3,0x00,0x50,0xff,0xd1,0x00,0x51,0xff,0xd1,0x00,0x53,0xff,0xd1,0x00,0x59,0xff,0xe6,0x00,0x5b,0xff,0xef,0x00,0x5c, +0xff,0xe6,0x00,0x9f,0xff,0xd3,0x00,0xb3,0xff,0xd1,0x00,0xbf,0xff,0xe6,0x00,0xc1,0xff,0xe6,0x01,0x06,0xff,0xd1,0x01,0x08,0xff,0xd1,0x01,0x0a,0xff,0xd1,0x01,0x0b,0xff,0xd1,0x01,0x24,0xff,0xd2,0x01,0x26,0xff,0xd2,0x01,0x38,0xff,0xd3,0x01,0x39,0xff,0xe6,0x01,0x3a,0xff,0xd3,0x01,0x51,0xff,0xca,0x01,0x69,0xff,0xd3,0x01,0x7f, +0xff,0xd3,0x01,0x81,0xff,0xf4,0x01,0x85,0xff,0xd3,0x01,0x88,0xff,0xd1,0x01,0x8d,0xff,0xe6,0x01,0x91,0xff,0xd1,0x01,0x97,0xff,0xe6,0x01,0xae,0xff,0xd2,0x01,0xb7,0xff,0xd2,0x01,0xba,0xff,0xed,0x01,0xc2,0xff,0xf4,0x01,0xce,0xff,0xd2,0x01,0xcf,0xff,0xed,0x01,0xd1,0xff,0xf4,0x01,0xd3,0xff,0xe1,0x01,0xdf,0xff,0xd1,0x01,0xe2, +0xff,0xef,0x01,0xe4,0xff,0xd1,0x01,0xe5,0xff,0xd1,0x01,0xe6,0xff,0xd1,0x01,0xe8,0xff,0xd1,0x01,0xe9,0xff,0xd1,0x01,0xeb,0xff,0xd1,0x01,0xec,0xff,0xd1,0x01,0xef,0xff,0xe6,0x01,0xf1,0xff,0xef,0x01,0xf2,0xff,0xd1,0x01,0xf4,0xff,0xd1,0x01,0xf5,0xff,0xd1,0x01,0xf8,0xff,0xd1,0x01,0xfa,0xff,0xd1,0x01,0xff,0xff,0xd1,0x02,0x06, +0xff,0xd1,0x02,0x08,0xff,0xd1,0x02,0x09,0xff,0xd1,0x02,0x0a,0xff,0xe6,0x02,0x20,0xff,0xd4,0x02,0x21,0xff,0xe6,0x02,0x22,0xff,0xd4,0x02,0x23,0xff,0xe6,0x02,0x36,0xff,0xd1,0x02,0x41,0xff,0xf4,0x02,0x42,0xff,0xef,0x02,0x46,0xff,0xd1,0x02,0x4b,0xff,0xd2,0x02,0x4e,0xff,0xd1,0x02,0x50,0xff,0xd1,0x02,0x57,0xff,0xd2,0x02,0x59, +0xff,0xd3,0x02,0x5a,0xff,0xe6,0x02,0x5b,0xff,0xd3,0x02,0x5d,0xff,0xf4,0x02,0x5e,0xff,0xef,0x02,0x5f,0xff,0xd2,0x02,0x61,0xff,0xe1,0x02,0x6c,0xff,0xf4,0x02,0x6d,0xff,0xef,0x02,0x73,0xff,0xd1,0x02,0x75,0xff,0xd1,0x02,0x76,0xff,0xe1,0x02,0x79,0xff,0xd1,0x02,0x87,0xff,0xf4,0x02,0x88,0xff,0xef,0x02,0x8e,0xff,0xd1,0x02,0x90, +0xff,0xd1,0x02,0x99,0xff,0xed,0x02,0x9a,0xff,0xe6,0x02,0x9b,0xff,0xed,0x02,0x9c,0xff,0xe6,0x02,0x9d,0xff,0xed,0x02,0x9e,0xff,0xe6,0x02,0x9f,0xff,0xe1,0x02,0xa2,0xff,0xd1,0x02,0xa4,0xff,0xd1,0x02,0xa6,0xff,0xd1,0x02,0xa7,0xff,0xf4,0x02,0xa8,0xff,0xef,0x02,0xc2,0xff,0xd1,0x03,0x1b,0xff,0xd3,0x03,0x1c,0xff,0xe6,0x03,0x1d, +0xff,0xd3,0x03,0x1e,0xff,0xe6,0x03,0x1f,0xff,0xd3,0x03,0x20,0xff,0xe6,0x03,0x21,0xff,0xd3,0x03,0x22,0xff,0xe6,0x03,0x34,0xff,0xca,0x03,0x35,0xff,0xca,0x03,0x37,0xff,0xca,0x03,0x38,0xff,0xca,0x03,0x39,0xff,0xca,0x03,0x41,0xff,0xca,0x03,0x42,0xff,0xca,0x00,0x1c,0x00,0x37,0xff,0xbe,0x00,0x59,0xff,0xef,0x00,0x5c,0xff,0xef, +0x00,0xbf,0xff,0xef,0x00,0xc1,0xff,0xef,0x01,0x24,0xff,0xbe,0x01,0x26,0xff,0xbe,0x01,0x39,0xff,0xef,0x01,0x8d,0xff,0xef,0x01,0x97,0xff,0xef,0x01,0xae,0xff,0xbe,0x01,0xb7,0xff,0xbe,0x01,0xce,0xff,0xbe,0x01,0xef,0xff,0xef,0x02,0x0a,0xff,0xef,0x02,0x21,0xff,0xef,0x02,0x23,0xff,0xef,0x02,0x4b,0xff,0xbe,0x02,0x57,0xff,0xbe, +0x02,0x5a,0xff,0xef,0x02,0x5f,0xff,0xbe,0x02,0x9a,0xff,0xef,0x02,0x9c,0xff,0xef,0x02,0x9e,0xff,0xef,0x03,0x1c,0xff,0xef,0x03,0x1e,0xff,0xef,0x03,0x20,0xff,0xef,0x03,0x22,0xff,0xef,0x00,0x33,0x00,0x37,0xff,0xe6,0x00,0x39,0xff,0xe7,0x00,0x3b,0xff,0xf2,0x00,0x3c,0xff,0xe7,0x00,0x5b,0xff,0xf1,0x00,0x9f,0xff,0xe7,0x01,0x24, +0xff,0xe6,0x01,0x26,0xff,0xe6,0x01,0x38,0xff,0xe7,0x01,0x3a,0xff,0xe7,0x01,0x69,0xff,0xe7,0x01,0x7f,0xff,0xe7,0x01,0x81,0xff,0xf2,0x01,0x85,0xff,0xe7,0x01,0xae,0xff,0xe6,0x01,0xb7,0xff,0xe6,0x01,0xba,0xff,0xee,0x01,0xc2,0xff,0xf2,0x01,0xce,0xff,0xe6,0x01,0xcf,0xff,0xee,0x01,0xd1,0xff,0xf2,0x01,0xd3,0xff,0xe8,0x01,0xe2, +0xff,0xf1,0x01,0xf1,0xff,0xf1,0x02,0x20,0xff,0xe7,0x02,0x22,0xff,0xe7,0x02,0x41,0xff,0xf2,0x02,0x42,0xff,0xf1,0x02,0x4b,0xff,0xe6,0x02,0x57,0xff,0xe6,0x02,0x59,0xff,0xe7,0x02,0x5b,0xff,0xe7,0x02,0x5d,0xff,0xf2,0x02,0x5e,0xff,0xf1,0x02,0x5f,0xff,0xe6,0x02,0x61,0xff,0xe8,0x02,0x6c,0xff,0xf2,0x02,0x6d,0xff,0xf1,0x02,0x76, +0xff,0xe8,0x02,0x87,0xff,0xf2,0x02,0x88,0xff,0xf1,0x02,0x99,0xff,0xee,0x02,0x9b,0xff,0xee,0x02,0x9d,0xff,0xee,0x02,0x9f,0xff,0xe8,0x02,0xa7,0xff,0xf2,0x02,0xa8,0xff,0xf1,0x03,0x1b,0xff,0xe7,0x03,0x1d,0xff,0xe7,0x03,0x1f,0xff,0xe7,0x03,0x21,0xff,0xe7,0x00,0x83,0x00,0x24,0x00,0x10,0x00,0x26,0xff,0xe8,0x00,0x2a,0xff,0xe8, +0x00,0x32,0xff,0xe8,0x00,0x34,0xff,0xe8,0x00,0x37,0xff,0xe0,0x00,0x39,0xff,0xe0,0x00,0x3c,0xff,0xdf,0x00,0x82,0x00,0x10,0x00,0x83,0x00,0x10,0x00,0x84,0x00,0x10,0x00,0x85,0x00,0x10,0x00,0x86,0x00,0x10,0x00,0x87,0x00,0x10,0x00,0x89,0xff,0xe8,0x00,0x94,0xff,0xe8,0x00,0x95,0xff,0xe8,0x00,0x96,0xff,0xe8,0x00,0x97,0xff,0xe8, +0x00,0x98,0xff,0xe8,0x00,0x9a,0xff,0xe8,0x00,0x9f,0xff,0xdf,0x00,0xc2,0x00,0x10,0x00,0xc4,0x00,0x10,0x00,0xc6,0x00,0x10,0x00,0xc8,0xff,0xe8,0x00,0xca,0xff,0xe8,0x00,0xcc,0xff,0xe8,0x00,0xce,0xff,0xe8,0x00,0xde,0xff,0xe8,0x00,0xe0,0xff,0xe8,0x00,0xe2,0xff,0xe8,0x00,0xe4,0xff,0xe8,0x01,0x0e,0xff,0xe8,0x01,0x10,0xff,0xe8, +0x01,0x12,0xff,0xe8,0x01,0x14,0xff,0xe8,0x01,0x24,0xff,0xe0,0x01,0x26,0xff,0xe0,0x01,0x38,0xff,0xdf,0x01,0x3a,0xff,0xdf,0x01,0x43,0xff,0xe8,0x01,0x48,0x00,0x10,0x01,0x4c,0xff,0xe8,0x01,0x63,0x00,0x10,0x01,0x68,0xff,0xe8,0x01,0x69,0xff,0xdf,0x01,0x6c,0x00,0x10,0x01,0x6f,0x00,0x10,0x01,0x73,0xff,0xe8,0x01,0x76,0x00,0x10, +0x01,0x7a,0xff,0xe8,0x01,0x7f,0xff,0xdf,0x01,0x85,0xff,0xdf,0x01,0xae,0xff,0xe0,0x01,0xb0,0xff,0xe8,0x01,0xb5,0x00,0x10,0x01,0xb7,0xff,0xe0,0x01,0xbc,0x00,0x10,0x01,0xc7,0x00,0x10,0x01,0xca,0xff,0xe8,0x01,0xcd,0xff,0xe8,0x01,0xce,0xff,0xe0,0x01,0xd3,0xff,0xe1,0x01,0xe7,0x00,0x10,0x01,0xf3,0xff,0xe0,0x02,0x05,0x00,0x10, +0x02,0x0c,0xff,0xe8,0x02,0x12,0x00,0x10,0x02,0x1e,0xff,0xe8,0x02,0x20,0xff,0xe0,0x02,0x22,0xff,0xe0,0x02,0x24,0xff,0xe8,0x02,0x26,0xff,0xe8,0x02,0x28,0xff,0xe8,0x02,0x2a,0xff,0xe8,0x02,0x2c,0xff,0xe8,0x02,0x4b,0xff,0xe0,0x02,0x53,0xff,0xe8,0x02,0x55,0xff,0xe8,0x02,0x57,0xff,0xe0,0x02,0x59,0xff,0xdf,0x02,0x5b,0xff,0xdf, +0x02,0x5f,0xff,0xe0,0x02,0x61,0xff,0xe1,0x02,0x62,0xff,0xe0,0x02,0x70,0x00,0x10,0x02,0x71,0x00,0x10,0x02,0x76,0xff,0xe1,0x02,0x77,0xff,0xe0,0x02,0x7b,0x00,0x10,0x02,0x7d,0x00,0x10,0x02,0x91,0xff,0xe8,0x02,0x93,0xff,0xe8,0x02,0x95,0xff,0xe8,0x02,0x9f,0xff,0xe1,0x02,0xa0,0xff,0xe0,0x02,0xb3,0x00,0x10,0x02,0xb7,0xff,0xe8, +0x02,0xbd,0x00,0x10,0x02,0xbe,0x00,0x10,0x02,0xbf,0x00,0x10,0x02,0xc9,0x00,0x10,0x02,0xcb,0x00,0x10,0x02,0xcd,0x00,0x10,0x02,0xcf,0x00,0x10,0x02,0xd1,0x00,0x10,0x02,0xd3,0x00,0x10,0x02,0xd5,0x00,0x10,0x02,0xd7,0x00,0x10,0x02,0xd9,0x00,0x10,0x02,0xdb,0x00,0x10,0x02,0xdd,0x00,0x10,0x02,0xdf,0x00,0x10,0x02,0xf5,0xff,0xe8, +0x02,0xf7,0xff,0xe8,0x02,0xf9,0xff,0xe8,0x02,0xfb,0xff,0xe8,0x02,0xfd,0xff,0xe8,0x02,0xff,0xff,0xe8,0x03,0x01,0xff,0xe8,0x03,0x03,0xff,0xe8,0x03,0x05,0xff,0xe8,0x03,0x07,0xff,0xe8,0x03,0x09,0xff,0xe8,0x03,0x0b,0xff,0xe8,0x03,0x1b,0xff,0xdf,0x03,0x1d,0xff,0xdf,0x03,0x1f,0xff,0xdf,0x03,0x21,0xff,0xdf,0x03,0x23,0xff,0xe8, +0x00,0x2c,0x00,0x37,0xff,0xf1,0x00,0x39,0xff,0xf4,0x00,0x3b,0xff,0xf4,0x00,0x3c,0xff,0xf0,0x00,0x9f,0xff,0xf0,0x01,0x24,0xff,0xf1,0x01,0x26,0xff,0xf1,0x01,0x38,0xff,0xf0,0x01,0x3a,0xff,0xf0,0x01,0x69,0xff,0xf0,0x01,0x7f,0xff,0xf0,0x01,0x81,0xff,0xf4,0x01,0x85,0xff,0xf0,0x01,0xae,0xff,0xf1,0x01,0xb5,0xff,0xf5,0x01,0xb7, +0xff,0xf1,0x01,0xba,0xff,0xf3,0x01,0xc2,0xff,0xf4,0x01,0xc7,0xff,0xf5,0x01,0xce,0xff,0xf1,0x01,0xcf,0xff,0xf3,0x01,0xd1,0xff,0xf4,0x02,0x20,0xff,0xf4,0x02,0x22,0xff,0xf4,0x02,0x41,0xff,0xf4,0x02,0x4b,0xff,0xf1,0x02,0x57,0xff,0xf1,0x02,0x59,0xff,0xf0,0x02,0x5b,0xff,0xf0,0x02,0x5d,0xff,0xf4,0x02,0x5f,0xff,0xf1,0x02,0x6c, +0xff,0xf4,0x02,0x70,0xff,0xf5,0x02,0x87,0xff,0xf4,0x02,0x99,0xff,0xf3,0x02,0x9b,0xff,0xf3,0x02,0x9d,0xff,0xf3,0x02,0xa7,0xff,0xf4,0x02,0xb3,0xff,0xf5,0x02,0xbd,0xff,0xf5,0x03,0x1b,0xff,0xf0,0x03,0x1d,0xff,0xf0,0x03,0x1f,0xff,0xf0,0x03,0x21,0xff,0xf0,0x00,0x58,0x00,0x24,0x00,0x0f,0x00,0x37,0xff,0xe6,0x00,0x39,0xff,0xe6, +0x00,0x3b,0x00,0x0e,0x00,0x3c,0xff,0xe6,0x00,0x82,0x00,0x0f,0x00,0x83,0x00,0x0f,0x00,0x84,0x00,0x0f,0x00,0x85,0x00,0x0f,0x00,0x86,0x00,0x0f,0x00,0x87,0x00,0x0f,0x00,0x9f,0xff,0xe6,0x00,0xc2,0x00,0x0f,0x00,0xc4,0x00,0x0f,0x00,0xc6,0x00,0x0f,0x01,0x24,0xff,0xe6,0x01,0x26,0xff,0xe6,0x01,0x38,0xff,0xe6,0x01,0x3a,0xff,0xe6, +0x01,0x48,0x00,0x0f,0x01,0x63,0x00,0x0f,0x01,0x69,0xff,0xe6,0x01,0x6c,0x00,0x0f,0x01,0x6f,0x00,0x0f,0x01,0x76,0x00,0x0f,0x01,0x7f,0xff,0xe6,0x01,0x81,0x00,0x0e,0x01,0x85,0xff,0xe6,0x01,0xae,0xff,0xe6,0x01,0xb5,0x00,0x0e,0x01,0xb7,0xff,0xe6,0x01,0xba,0x00,0x0b,0x01,0xbc,0x00,0x0f,0x01,0xc2,0x00,0x0e,0x01,0xc7,0x00,0x0e, +0x01,0xce,0xff,0xe6,0x01,0xcf,0x00,0x0b,0x01,0xd1,0x00,0x0e,0x01,0xd3,0xff,0xe5,0x01,0xe7,0x00,0x0f,0x01,0xf3,0xff,0xe8,0x02,0x05,0x00,0x0f,0x02,0x12,0x00,0x0f,0x02,0x20,0xff,0xe6,0x02,0x22,0xff,0xe6,0x02,0x41,0x00,0x0e,0x02,0x4b,0xff,0xe6,0x02,0x57,0xff,0xe6,0x02,0x59,0xff,0xe6,0x02,0x5b,0xff,0xe6,0x02,0x5d,0x00,0x0e, +0x02,0x5f,0xff,0xe6,0x02,0x61,0xff,0xe5,0x02,0x62,0xff,0xe8,0x02,0x6c,0x00,0x0e,0x02,0x70,0x00,0x0e,0x02,0x71,0x00,0x0f,0x02,0x76,0xff,0xe5,0x02,0x77,0xff,0xe8,0x02,0x7b,0x00,0x0f,0x02,0x7d,0x00,0x0f,0x02,0x87,0x00,0x0e,0x02,0x99,0x00,0x0b,0x02,0x9b,0x00,0x0b,0x02,0x9d,0x00,0x0b,0x02,0x9f,0xff,0xe5,0x02,0xa0,0xff,0xe8, +0x02,0xa7,0x00,0x0e,0x02,0xb3,0x00,0x0e,0x02,0xbd,0x00,0x0e,0x02,0xbe,0x00,0x0f,0x02,0xbf,0x00,0x0f,0x02,0xc9,0x00,0x0f,0x02,0xcb,0x00,0x0f,0x02,0xcd,0x00,0x0f,0x02,0xcf,0x00,0x0f,0x02,0xd1,0x00,0x0f,0x02,0xd3,0x00,0x0f,0x02,0xd5,0x00,0x0f,0x02,0xd7,0x00,0x0f,0x02,0xd9,0x00,0x0f,0x02,0xdb,0x00,0x0f,0x02,0xdd,0x00,0x0f, +0x02,0xdf,0x00,0x0f,0x03,0x1b,0xff,0xe6,0x03,0x1d,0xff,0xe6,0x03,0x1f,0xff,0xe6,0x03,0x21,0xff,0xe6,0x00,0x2d,0x00,0x37,0xff,0xe3,0x00,0x3b,0xff,0xe5,0x00,0x3c,0xff,0xe4,0x00,0x9f,0xff,0xe4,0x01,0x24,0xff,0xe3,0x01,0x26,0xff,0xe3,0x01,0x38,0xff,0xe4,0x01,0x3a,0xff,0xe4,0x01,0x69,0xff,0xe4,0x01,0x7f,0xff,0xe4,0x01,0x81, +0xff,0xe5,0x01,0x85,0xff,0xe4,0x01,0xae,0xff,0xe3,0x01,0xb5,0xff,0xe5,0x01,0xb7,0xff,0xe3,0x01,0xba,0xff,0xe9,0x01,0xc2,0xff,0xe5,0x01,0xc7,0xff,0xe5,0x01,0xce,0xff,0xe3,0x01,0xcf,0xff,0xe9,0x01,0xd1,0xff,0xe5,0x01,0xe7,0xff,0xea,0x02,0x05,0xff,0xea,0x02,0x41,0xff,0xe5,0x02,0x4b,0xff,0xe3,0x02,0x57,0xff,0xe3,0x02,0x59, +0xff,0xe4,0x02,0x5b,0xff,0xe4,0x02,0x5d,0xff,0xe5,0x02,0x5f,0xff,0xe3,0x02,0x6c,0xff,0xe5,0x02,0x70,0xff,0xe5,0x02,0x71,0xff,0xea,0x02,0x87,0xff,0xe5,0x02,0x99,0xff,0xe9,0x02,0x9b,0xff,0xe9,0x02,0x9d,0xff,0xe9,0x02,0xa7,0xff,0xe5,0x02,0xb3,0xff,0xe5,0x02,0xbd,0xff,0xe5,0x02,0xbe,0xff,0xea,0x03,0x1b,0xff,0xe4,0x03,0x1d, +0xff,0xe4,0x03,0x1f,0xff,0xe4,0x03,0x21,0xff,0xe4,0x00,0x20,0x00,0x37,0xff,0xe2,0x00,0x3b,0xff,0xe4,0x01,0x24,0xff,0xe2,0x01,0x26,0xff,0xe2,0x01,0x81,0xff,0xe4,0x01,0xae,0xff,0xe2,0x01,0xb5,0xff,0xe4,0x01,0xb7,0xff,0xe2,0x01,0xba,0xff,0xe9,0x01,0xc2,0xff,0xe4,0x01,0xc7,0xff,0xe4,0x01,0xce,0xff,0xe2,0x01,0xcf,0xff,0xe9, +0x01,0xd1,0xff,0xe4,0x01,0xe7,0xff,0xeb,0x02,0x05,0xff,0xeb,0x02,0x41,0xff,0xe4,0x02,0x4b,0xff,0xe2,0x02,0x57,0xff,0xe2,0x02,0x5d,0xff,0xe4,0x02,0x5f,0xff,0xe2,0x02,0x6c,0xff,0xe4,0x02,0x70,0xff,0xe4,0x02,0x71,0xff,0xeb,0x02,0x87,0xff,0xe4,0x02,0x99,0xff,0xe9,0x02,0x9b,0xff,0xe9,0x02,0x9d,0xff,0xe9,0x02,0xa7,0xff,0xe4, +0x02,0xb3,0xff,0xe4,0x02,0xbd,0xff,0xe4,0x02,0xbe,0xff,0xeb,0x00,0x16,0x00,0x37,0xff,0xeb,0x00,0x3c,0xff,0xf3,0x00,0x9f,0xff,0xf3,0x01,0x24,0xff,0xeb,0x01,0x26,0xff,0xeb,0x01,0x38,0xff,0xf3,0x01,0x3a,0xff,0xf3,0x01,0x69,0xff,0xf3,0x01,0x7f,0xff,0xf3,0x01,0x85,0xff,0xf3,0x01,0xae,0xff,0xeb,0x01,0xb7,0xff,0xeb,0x01,0xce, +0xff,0xeb,0x02,0x4b,0xff,0xeb,0x02,0x57,0xff,0xeb,0x02,0x59,0xff,0xf3,0x02,0x5b,0xff,0xf3,0x02,0x5f,0xff,0xeb,0x03,0x1b,0xff,0xf3,0x03,0x1d,0xff,0xf3,0x03,0x1f,0xff,0xf3,0x03,0x21,0xff,0xf3,0x00,0x30,0x00,0x50,0xff,0xef,0x00,0x51,0xff,0xef,0x00,0x53,0xff,0xef,0x00,0x5b,0xff,0xf0,0x00,0xb3,0xff,0xef,0x01,0x06,0xff,0xef, +0x01,0x08,0xff,0xef,0x01,0x0a,0xff,0xef,0x01,0x0b,0xff,0xef,0x01,0x88,0xff,0xef,0x01,0x91,0xff,0xef,0x01,0xdf,0xff,0xef,0x01,0xe2,0xff,0xf0,0x01,0xe4,0xff,0xef,0x01,0xe5,0xff,0xef,0x01,0xe6,0xff,0xef,0x01,0xe8,0xff,0xef,0x01,0xe9,0xff,0xef,0x01,0xeb,0xff,0xef,0x01,0xec,0xff,0xef,0x01,0xf1,0xff,0xf0,0x01,0xf2,0xff,0xef, +0x01,0xf4,0xff,0xef,0x01,0xf5,0xff,0xef,0x01,0xf8,0xff,0xef,0x01,0xfa,0xff,0xef,0x01,0xff,0xff,0xef,0x02,0x06,0xff,0xef,0x02,0x08,0xff,0xef,0x02,0x09,0xff,0xef,0x02,0x36,0xff,0xef,0x02,0x42,0xff,0xf0,0x02,0x46,0xff,0xef,0x02,0x4e,0xff,0xef,0x02,0x50,0xff,0xef,0x02,0x5e,0xff,0xf0,0x02,0x6d,0xff,0xf0,0x02,0x73,0xff,0xef, +0x02,0x75,0xff,0xef,0x02,0x79,0xff,0xef,0x02,0x88,0xff,0xf0,0x02,0x8e,0xff,0xef,0x02,0x90,0xff,0xef,0x02,0xa2,0xff,0xef,0x02,0xa4,0xff,0xef,0x02,0xa6,0xff,0xef,0x02,0xa8,0xff,0xf0,0x02,0xc2,0xff,0xef,0x00,0x1d,0x00,0x05,0xff,0xf2,0x00,0x0a,0xff,0xf2,0x00,0x59,0xff,0xf5,0x00,0x5c,0xff,0xf5,0x00,0xbf,0xff,0xf5,0x00,0xc1, +0xff,0xf5,0x01,0x39,0xff,0xf5,0x01,0x51,0xff,0xf2,0x01,0x8d,0xff,0xf5,0x01,0x97,0xff,0xf5,0x01,0xef,0xff,0xf5,0x02,0x0a,0xff,0xf5,0x02,0x21,0xff,0xf5,0x02,0x23,0xff,0xf5,0x02,0x5a,0xff,0xf5,0x02,0x9a,0xff,0xf5,0x02,0x9c,0xff,0xf5,0x02,0x9e,0xff,0xf5,0x03,0x1c,0xff,0xf5,0x03,0x1e,0xff,0xf5,0x03,0x20,0xff,0xf5,0x03,0x22, +0xff,0xf5,0x03,0x34,0xff,0xf2,0x03,0x35,0xff,0xf2,0x03,0x37,0xff,0xf2,0x03,0x38,0xff,0xf2,0x03,0x39,0xff,0xf2,0x03,0x41,0xff,0xf2,0x03,0x42,0xff,0xf2,0x00,0x04,0x01,0xf3,0xff,0xed,0x02,0x62,0xff,0xed,0x02,0x77,0xff,0xed,0x02,0xa0,0xff,0xed,0x00,0x0a,0x00,0x05,0xff,0xf5,0x00,0x0a,0xff,0xf5,0x01,0x51,0xff,0xf5,0x03,0x34, +0xff,0xf5,0x03,0x35,0xff,0xf5,0x03,0x37,0xff,0xf5,0x03,0x38,0xff,0xf5,0x03,0x39,0xff,0xf5,0x03,0x41,0xff,0xf5,0x03,0x42,0xff,0xf5,0x00,0x54,0x00,0x46,0xff,0xf0,0x00,0x47,0xff,0xf0,0x00,0x48,0xff,0xf0,0x00,0x4a,0xff,0xf0,0x00,0x52,0xff,0xeb,0x00,0x54,0xff,0xf0,0x00,0xa9,0xff,0xf0,0x00,0xaa,0xff,0xf0,0x00,0xab,0xff,0xf0, +0x00,0xac,0xff,0xf0,0x00,0xad,0xff,0xf0,0x00,0xb4,0xff,0xeb,0x00,0xb5,0xff,0xeb,0x00,0xb6,0xff,0xeb,0x00,0xb7,0xff,0xeb,0x00,0xb8,0xff,0xeb,0x00,0xc9,0xff,0xf0,0x00,0xcb,0xff,0xf0,0x00,0xcd,0xff,0xf0,0x00,0xcf,0xff,0xf0,0x00,0xd1,0xff,0xf0,0x00,0xd5,0xff,0xf0,0x00,0xd7,0xff,0xf0,0x00,0xd9,0xff,0xf0,0x00,0xdb,0xff,0xf0, +0x00,0xdd,0xff,0xf0,0x00,0xdf,0xff,0xf0,0x00,0xe1,0xff,0xf0,0x00,0xe3,0xff,0xf0,0x00,0xe5,0xff,0xf0,0x01,0x0f,0xff,0xeb,0x01,0x11,0xff,0xeb,0x01,0x13,0xff,0xeb,0x01,0x15,0xff,0xf0,0x01,0x44,0xff,0xf0,0x01,0x86,0xff,0xf0,0x01,0x8b,0xff,0xf0,0x01,0x99,0xff,0xeb,0x01,0x9c,0xff,0xf0,0x01,0x9d,0xff,0xf0,0x01,0xa6,0xff,0xeb, +0x01,0xe1,0xff,0xf0,0x01,0xea,0xff,0xeb,0x01,0xed,0xff,0xf0,0x01,0xf0,0xff,0xf0,0x01,0xfc,0xff,0xf0,0x01,0xfd,0xff,0xf0,0x02,0x00,0xff,0xf0,0x02,0x1f,0xff,0xeb,0x02,0x25,0xff,0xf0,0x02,0x29,0xff,0xf0,0x02,0x2d,0xff,0xf0,0x02,0x54,0xff,0xf0,0x02,0x56,0xff,0xf0,0x02,0x82,0xff,0xf0,0x02,0x84,0xff,0xf0,0x02,0x86,0xff,0xf0, +0x02,0x92,0xff,0xeb,0x02,0x94,0xff,0xf0,0x02,0x96,0xff,0xeb,0x02,0xac,0xff,0xf0,0x02,0xad,0xff,0xf0,0x02,0xae,0xff,0xf0,0x02,0xb8,0xff,0xf0,0x02,0xe2,0xff,0xf0,0x02,0xe4,0xff,0xf0,0x02,0xe6,0xff,0xf0,0x02,0xe8,0xff,0xf0,0x02,0xea,0xff,0xf0,0x02,0xec,0xff,0xf0,0x02,0xee,0xff,0xf0,0x02,0xf0,0xff,0xf0,0x02,0xf6,0xff,0xeb, +0x02,0xf8,0xff,0xeb,0x02,0xfa,0xff,0xeb,0x02,0xfc,0xff,0xeb,0x02,0xfe,0xff,0xeb,0x03,0x00,0xff,0xeb,0x03,0x02,0xff,0xeb,0x03,0x04,0xff,0xf0,0x03,0x06,0xff,0xf0,0x03,0x08,0xff,0xf0,0x03,0x0a,0xff,0xeb,0x03,0x0c,0xff,0xf0,0x00,0x90,0x00,0x05,0x00,0x0d,0x00,0x0a,0x00,0x0d,0x00,0x44,0xff,0xf0,0x00,0x46,0xff,0xee,0x00,0x47, +0xff,0xee,0x00,0x48,0xff,0xee,0x00,0x4a,0xff,0xee,0x00,0x52,0xff,0xea,0x00,0x54,0xff,0xee,0x00,0x59,0x00,0x0b,0x00,0x5c,0x00,0x0b,0x00,0xa2,0xff,0xf0,0x00,0xa3,0xff,0xf0,0x00,0xa4,0xff,0xf0,0x00,0xa5,0xff,0xf0,0x00,0xa6,0xff,0xf0,0x00,0xa7,0xff,0xf0,0x00,0xa9,0xff,0xee,0x00,0xaa,0xff,0xee,0x00,0xab,0xff,0xee,0x00,0xac, +0xff,0xee,0x00,0xad,0xff,0xee,0x00,0xb4,0xff,0xea,0x00,0xb5,0xff,0xea,0x00,0xb6,0xff,0xea,0x00,0xb7,0xff,0xea,0x00,0xb8,0xff,0xea,0x00,0xbf,0x00,0x0b,0x00,0xc1,0x00,0x0b,0x00,0xc3,0xff,0xf0,0x00,0xc5,0xff,0xf0,0x00,0xc7,0xff,0xf0,0x00,0xc9,0xff,0xee,0x00,0xcb,0xff,0xee,0x00,0xcd,0xff,0xee,0x00,0xcf,0xff,0xee,0x00,0xd1, +0xff,0xee,0x00,0xd5,0xff,0xee,0x00,0xd7,0xff,0xee,0x00,0xd9,0xff,0xee,0x00,0xdb,0xff,0xee,0x00,0xdd,0xff,0xee,0x00,0xdf,0xff,0xee,0x00,0xe1,0xff,0xee,0x00,0xe3,0xff,0xee,0x00,0xe5,0xff,0xee,0x01,0x0f,0xff,0xea,0x01,0x11,0xff,0xea,0x01,0x13,0xff,0xea,0x01,0x15,0xff,0xee,0x01,0x39,0x00,0x0b,0x01,0x44,0xff,0xee,0x01,0x49, +0xff,0xf0,0x01,0x51,0x00,0x0d,0x01,0x86,0xff,0xee,0x01,0x8b,0xff,0xee,0x01,0x8d,0x00,0x0b,0x01,0x97,0x00,0x0b,0x01,0x99,0xff,0xea,0x01,0x9c,0xff,0xee,0x01,0x9d,0xff,0xee,0x01,0xa6,0xff,0xea,0x01,0xdc,0xff,0xf0,0x01,0xe1,0xff,0xee,0x01,0xe7,0xff,0xd7,0x01,0xea,0xff,0xea,0x01,0xed,0xff,0xee,0x01,0xef,0x00,0x0b,0x01,0xf0, +0xff,0xee,0x01,0xfc,0xff,0xee,0x01,0xfd,0xff,0xee,0x02,0x00,0xff,0xee,0x02,0x05,0xff,0xd7,0x02,0x0a,0x00,0x0b,0x02,0x1f,0xff,0xea,0x02,0x21,0x00,0x0b,0x02,0x23,0x00,0x0b,0x02,0x25,0xff,0xee,0x02,0x29,0xff,0xee,0x02,0x2d,0xff,0xee,0x02,0x54,0xff,0xee,0x02,0x56,0xff,0xee,0x02,0x5a,0x00,0x0b,0x02,0x71,0xff,0xd7,0x02,0x7c, +0xff,0xf0,0x02,0x7e,0xff,0xf0,0x02,0x82,0xff,0xee,0x02,0x84,0xff,0xee,0x02,0x86,0xff,0xee,0x02,0x92,0xff,0xea,0x02,0x94,0xff,0xee,0x02,0x96,0xff,0xea,0x02,0x9a,0x00,0x0b,0x02,0x9c,0x00,0x0b,0x02,0x9e,0x00,0x0b,0x02,0xac,0xff,0xee,0x02,0xad,0xff,0xee,0x02,0xae,0xff,0xee,0x02,0xb8,0xff,0xee,0x02,0xbe,0xff,0xd7,0x02,0xc0, +0xff,0xf0,0x02,0xca,0xff,0xf0,0x02,0xcc,0xff,0xf0,0x02,0xce,0xff,0xf0,0x02,0xd0,0xff,0xf0,0x02,0xd2,0xff,0xf0,0x02,0xd4,0xff,0xf0,0x02,0xd6,0xff,0xf0,0x02,0xd8,0xff,0xf0,0x02,0xda,0xff,0xf0,0x02,0xdc,0xff,0xf0,0x02,0xde,0xff,0xf0,0x02,0xe0,0xff,0xf0,0x02,0xe2,0xff,0xee,0x02,0xe4,0xff,0xee,0x02,0xe6,0xff,0xee,0x02,0xe8, +0xff,0xee,0x02,0xea,0xff,0xee,0x02,0xec,0xff,0xee,0x02,0xee,0xff,0xee,0x02,0xf0,0xff,0xee,0x02,0xf6,0xff,0xea,0x02,0xf8,0xff,0xea,0x02,0xfa,0xff,0xea,0x02,0xfc,0xff,0xea,0x02,0xfe,0xff,0xea,0x03,0x00,0xff,0xea,0x03,0x02,0xff,0xea,0x03,0x04,0xff,0xee,0x03,0x06,0xff,0xee,0x03,0x08,0xff,0xee,0x03,0x0a,0xff,0xea,0x03,0x0c, +0xff,0xee,0x03,0x1c,0x00,0x0b,0x03,0x1e,0x00,0x0b,0x03,0x20,0x00,0x0b,0x03,0x22,0x00,0x0b,0x03,0x34,0x00,0x0d,0x03,0x35,0x00,0x0d,0x03,0x37,0x00,0x0d,0x03,0x38,0x00,0x0d,0x03,0x39,0x00,0x0d,0x03,0x41,0x00,0x0d,0x03,0x42,0x00,0x0d,0x00,0x08,0x01,0xe7,0x00,0x10,0x01,0xf3,0xff,0xf0,0x02,0x05,0x00,0x10,0x02,0x62,0xff,0xf0, +0x02,0x71,0x00,0x10,0x02,0x77,0xff,0xf0,0x02,0xa0,0xff,0xf0,0x02,0xbe,0x00,0x10,0x00,0x45,0x00,0x46,0xff,0xee,0x00,0x47,0xff,0xee,0x00,0x48,0xff,0xee,0x00,0x4a,0xff,0xee,0x00,0x54,0xff,0xee,0x00,0xa9,0xff,0xee,0x00,0xaa,0xff,0xee,0x00,0xab,0xff,0xee,0x00,0xac,0xff,0xee,0x00,0xad,0xff,0xee,0x00,0xc9,0xff,0xee,0x00,0xcb, +0xff,0xee,0x00,0xcd,0xff,0xee,0x00,0xcf,0xff,0xee,0x00,0xd1,0xff,0xee,0x00,0xd5,0xff,0xee,0x00,0xd7,0xff,0xee,0x00,0xd9,0xff,0xee,0x00,0xdb,0xff,0xee,0x00,0xdd,0xff,0xee,0x00,0xdf,0xff,0xee,0x00,0xe1,0xff,0xee,0x00,0xe3,0xff,0xee,0x00,0xe5,0xff,0xee,0x01,0x15,0xff,0xee,0x01,0x44,0xff,0xee,0x01,0x86,0xff,0xee,0x01,0x8b, +0xff,0xee,0x01,0x9c,0xff,0xee,0x01,0x9d,0xff,0xee,0x01,0xe1,0xff,0xee,0x01,0xe7,0x00,0x0e,0x01,0xed,0xff,0xee,0x01,0xf0,0xff,0xee,0x01,0xf3,0xff,0xe3,0x01,0xfc,0xff,0xee,0x01,0xfd,0xff,0xee,0x02,0x00,0xff,0xee,0x02,0x05,0x00,0x0e,0x02,0x25,0xff,0xee,0x02,0x29,0xff,0xee,0x02,0x2d,0xff,0xee,0x02,0x54,0xff,0xee,0x02,0x56, +0xff,0xee,0x02,0x62,0xff,0xe3,0x02,0x71,0x00,0x0e,0x02,0x77,0xff,0xe3,0x02,0x82,0xff,0xee,0x02,0x84,0xff,0xee,0x02,0x86,0xff,0xee,0x02,0x94,0xff,0xee,0x02,0xa0,0xff,0xe3,0x02,0xac,0xff,0xee,0x02,0xad,0xff,0xee,0x02,0xae,0xff,0xee,0x02,0xb8,0xff,0xee,0x02,0xbe,0x00,0x0e,0x02,0xe2,0xff,0xee,0x02,0xe4,0xff,0xee,0x02,0xe6, +0xff,0xee,0x02,0xe8,0xff,0xee,0x02,0xea,0xff,0xee,0x02,0xec,0xff,0xee,0x02,0xee,0xff,0xee,0x02,0xf0,0xff,0xee,0x03,0x04,0xff,0xee,0x03,0x06,0xff,0xee,0x03,0x08,0xff,0xee,0x03,0x0c,0xff,0xee,0x00,0x1f,0x00,0x59,0xff,0xf4,0x00,0x5b,0xff,0xf0,0x00,0x5c,0xff,0xf4,0x00,0xbf,0xff,0xf4,0x00,0xc1,0xff,0xf4,0x01,0x39,0xff,0xf4, +0x01,0x8d,0xff,0xf4,0x01,0x97,0xff,0xf4,0x01,0xe2,0xff,0xf0,0x01,0xe7,0xff,0xf3,0x01,0xef,0xff,0xf4,0x01,0xf1,0xff,0xf0,0x02,0x05,0xff,0xf3,0x02,0x0a,0xff,0xf4,0x02,0x21,0xff,0xf4,0x02,0x23,0xff,0xf4,0x02,0x42,0xff,0xf0,0x02,0x5a,0xff,0xf4,0x02,0x5e,0xff,0xf0,0x02,0x6d,0xff,0xf0,0x02,0x71,0xff,0xf3,0x02,0x88,0xff,0xf0, +0x02,0x9a,0xff,0xf4,0x02,0x9c,0xff,0xf4,0x02,0x9e,0xff,0xf4,0x02,0xa8,0xff,0xf0,0x02,0xbe,0xff,0xf3,0x03,0x1c,0xff,0xf4,0x03,0x1e,0xff,0xf4,0x03,0x20,0xff,0xf4,0x03,0x22,0xff,0xf4,0x00,0x0a,0x00,0x05,0xff,0xd6,0x00,0x0a,0xff,0xd6,0x01,0x51,0xff,0xd6,0x03,0x34,0xff,0xd6,0x03,0x35,0xff,0xd6,0x03,0x37,0xff,0xd6,0x03,0x38, +0xff,0xd6,0x03,0x39,0xff,0xd6,0x03,0x41,0xff,0xd6,0x03,0x42,0xff,0xd6,0x00,0x0a,0x00,0x05,0xff,0xf5,0x00,0x0a,0xff,0xf5,0x01,0x51,0xff,0xf5,0x03,0x34,0xff,0xf5,0x03,0x35,0xff,0xf5,0x03,0x37,0xff,0xf5,0x03,0x38,0xff,0xf5,0x03,0x39,0xff,0xf5,0x03,0x41,0xff,0xf5,0x03,0x42,0xff,0xf5,0x00,0x02,0x0a,0xe2,0x00,0x04,0x00,0x00, +0x0d,0xe8,0x14,0x6a,0x00,0x20,0x00,0x1d,0x00,0x00,0x00,0x11,0xff,0xce,0xff,0x8f,0x00,0x12,0xff,0xf5,0xff,0xef,0xff,0xb1,0xff,0xf4,0xff,0xbb,0xff,0x7f,0xff,0xf5,0x00,0x0c,0xff,0xa9,0xff,0xa2,0xff,0xc9,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,0xff,0xe5,0x00,0x00,0x00,0x00,0xff,0xe8,0xff,0xc9,0x00,0x00,0xff,0xf3,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,0x11, +0x00,0x00,0xff,0xe5,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe4,0xff,0xe4,0x00,0x00,0x00,0x12,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe1,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe5,0x00,0x00,0x00,0x00,0xff,0xea,0xff,0xd5,0x00,0x00,0x00,0x00,0xff,0xeb,0xff,0xea,0xff,0x9a,0xff,0xe9,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,0xff,0xe3,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,0xff,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xed,0x00,0x00,0x00,0x00, +0xff,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xed,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xcb,0xff,0xb8,0xff,0x7c,0xff,0x7e,0xff,0xe4,0x00,0x00,0x00,0x00,0xff,0x9d,0x00,0x0f,0x00,0x10,0xff,0xa1,0xff,0xc4,0x00,0x10, +0x00,0x10,0x00,0x00,0x00,0x00,0xff,0xb1,0x00,0x00,0xff,0x26,0x00,0x00,0xff,0x9d,0xff,0xb3,0xff,0x18,0xff,0x93,0xff,0xf0,0xff,0x8f,0xff,0x8c,0x00,0x00,0x00,0x00,0xff,0x92,0xff,0x72,0xff,0x0c,0xff,0x0f,0xff,0xbd,0x00,0x00,0x00,0x00,0xff,0x44,0x00,0x05,0x00,0x07,0xff,0x4b,0xff,0x86,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00, +0xff,0x3e,0x00,0x00,0xfe,0x7a,0x00,0x00,0xff,0x44,0xff,0x6a,0xfe,0x62,0xff,0x33,0xff,0xd1,0xff,0x2c,0xff,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xec,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xff,0xec,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xd8,0xff,0xa3,0x00,0x00,0xff,0xe1,0x00,0x00,0x00,0x00,0xff,0xe5,0x00,0x00,0x00,0x00,0xff,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe6,0x00,0x00, +0xff,0xc0,0xff,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x7b,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xca,0xff,0x76,0x00,0x00,0xff,0x71,0xfe,0xed,0xff,0xd4,0x00,0x00,0xff,0x51,0xff,0x11,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc9,0x00,0x0f,0x00,0x00,0xff,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x76,0xff,0xe1,0xfe,0xbc,0xff,0xe6,0xff,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf5,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,0xff,0xea,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,0xff,0xf5, +0x00,0x00,0x00,0x00,0xff,0xf3,0x00,0x00,0x00,0x00,0xff,0xd2,0x00,0x00,0x00,0x00,0xff,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xb5,0x00,0x00,0xff,0x1f,0x00,0x00,0xff,0xd4,0x00,0x00,0xff,0xdb,0x00,0x00,0x00,0x00,0xff,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0xff,0xe1,0xff,0xd1,0x00,0x11,0xff,0xe7, +0x00,0x00,0x00,0x00,0xff,0xeb,0x00,0x00,0x00,0x00,0xff,0xeb,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe6,0x00,0x00,0xff,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xec,0x00,0x00,0x00,0x00,0xff,0xe3,0xff,0xa0,0x00,0x00,0xff,0xbf, +0x00,0x11,0x00,0x11,0xff,0xd9,0xff,0xe2,0x00,0x12,0x00,0x12,0x00,0x00,0x00,0x00,0xff,0xae,0x00,0x0d,0xff,0x2d,0x00,0x00,0xff,0xbf,0xff,0xe9,0xff,0xcc,0xff,0xd8,0xff,0xf0,0xff,0xb7,0xff,0xc6,0xff,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe1,0x00,0x00,0x00,0x0e,0xff,0xed, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xd5,0x00,0x00,0xff,0x85,0x00,0x00,0xff,0xe1,0x00,0x00,0xff,0xc4,0x00,0x00,0x00,0x00,0xff,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe5,0x00,0x00,0x00,0x00,0xff,0xe6,0x00,0x00,0x00,0x00,0xff,0xeb,0x00,0x00,0x00,0x00,0xff,0xed,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xca,0x00,0x00,0xff,0xe9,0xff,0xbb,0xff,0xe9,0x00,0x00,0x00,0x00,0xff,0xbd,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0xff,0xa5, +0x00,0x00,0xfe,0x6d,0x00,0x00,0xff,0xbd,0x00,0x00,0xff,0x89,0xff,0x9a,0x00,0x00,0xff,0x91,0xff,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xbd,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf5,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,0xff,0xf5,0x00,0x00,0xff,0xf2,0x00,0x00,0x00,0x00,0xff,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf2,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf0,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,0xff,0xf1,0x00,0x00, +0xff,0xf0,0x00,0x00,0x00,0x00,0xff,0xec,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xd7,0x00,0x00,0x00,0x00, +0x00,0x0f,0xff,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x95,0x00,0x00,0xff,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xff,0xec,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x85,0x00,0x00,0xff,0xed,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,0xff,0xec,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xec,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,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf0,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,0xff,0x95,0xff,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x96,0x00,0x00, +0x00,0x00,0x00,0x00,0xff,0xc5,0x00,0x00,0x00,0x00,0xff,0xec,0x00,0x00,0xff,0xce,0xff,0xd6,0x00,0x00,0x00,0x00,0xff,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc0,0x00,0x00,0x00,0x00,0xfe,0xf5,0x00,0x00,0x00,0x00,0xff,0xc8,0xff,0xad,0xff,0xe7,0xff,0xeb,0x00,0x00,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00, +0xff,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xdd,0xff,0xed,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x79,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,0xff,0xf5,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x99,0x00,0x05,0x00,0x0a,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a,0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x44, +0x00,0x45,0x00,0x48,0x00,0x49,0x00,0x52,0x00,0x53,0x00,0x55,0x00,0x59,0x00,0x5b,0x00,0x5c,0x00,0x82,0x00,0x83,0x00,0x84,0x00,0x85,0x00,0x86,0x00,0x87,0x00,0x89,0x00,0x8a,0x00,0x8b,0x00,0x8c,0x00,0x8d,0x00,0x8e,0x00,0x8f,0x00,0x90,0x00,0x91,0x00,0x92,0x00,0x93,0x00,0x94,0x00,0x95,0x00,0x96,0x00,0x97,0x00,0x98,0x00,0x9b, +0x00,0x9c,0x00,0x9d,0x00,0x9e,0x00,0x9f,0x00,0xa2,0x00,0xa3,0x00,0xa4,0x00,0xa5,0x00,0xa6,0x00,0xa7,0x00,0xaa,0x00,0xab,0x00,0xac,0x00,0xad,0x00,0xb4,0x00,0xb5,0x00,0xb6,0x00,0xb7,0x00,0xb8,0x00,0xbf,0x00,0xc0,0x00,0xc1,0x00,0xc2,0x00,0xc3,0x00,0xc4,0x00,0xc5,0x00,0xc6,0x00,0xc7,0x00,0xc8,0x00,0xca,0x00,0xcc,0x00,0xce, +0x00,0xd0,0x00,0xd2,0x00,0xd4,0x00,0xd5,0x00,0xd6,0x00,0xd7,0x00,0xd8,0x00,0xd9,0x00,0xda,0x00,0xdb,0x00,0xdc,0x00,0xdd,0x00,0xe6,0x00,0xea,0x00,0xec,0x00,0xee,0x00,0xf0,0x00,0xf2,0x00,0xf6,0x00,0xf8,0x00,0xfb,0x00,0xfd,0x00,0xff,0x01,0x01,0x01,0x05,0x01,0x07,0x01,0x09,0x01,0x0e,0x01,0x0f,0x01,0x10,0x01,0x11,0x01,0x12, +0x01,0x13,0x01,0x17,0x01,0x19,0x01,0x1b,0x01,0x24,0x01,0x26,0x01,0x28,0x01,0x2a,0x01,0x2c,0x01,0x2e,0x01,0x30,0x01,0x32,0x01,0x34,0x01,0x36,0x01,0x38,0x01,0x39,0x01,0x3a,0x01,0x3b,0x01,0x3d,0x01,0x3f,0x01,0x48,0x01,0x49,0x01,0x51,0x01,0x63,0x01,0x65,0x01,0x66,0x01,0x67,0x01,0x68,0x01,0x69,0x01,0x6c,0x01,0x6d,0x01,0x6e, +0x01,0x6f,0x01,0x70,0x01,0x71,0x01,0x72,0x01,0x73,0x01,0x74,0x01,0x75,0x01,0x76,0x01,0x77,0x01,0x78,0x01,0x79,0x01,0x7a,0x01,0x7c,0x01,0x7d,0x01,0x7e,0x01,0x7f,0x01,0x80,0x01,0x81,0x01,0x82,0x01,0x84,0x01,0x85,0x01,0x8b,0x01,0x8d,0x01,0x8e,0x01,0x90,0x01,0x93,0x01,0x95,0x01,0x97,0x01,0x98,0x01,0x99,0x01,0x9b,0x01,0x9d, +0x01,0x9e,0x01,0xa0,0x01,0xa1,0x01,0xa6,0x01,0xac,0x01,0xad,0x01,0xae,0x01,0xaf,0x01,0xb2,0x01,0xb3,0x01,0xb4,0x01,0xb5,0x01,0xb6,0x01,0xb7,0x01,0xb8,0x01,0xba,0x01,0xbb,0x01,0xbc,0x01,0xbd,0x01,0xbe,0x01,0xbf,0x01,0xc0,0x01,0xc1,0x01,0xc2,0x01,0xc3,0x01,0xc4,0x01,0xc6,0x01,0xc7,0x01,0xc8,0x01,0xc9,0x01,0xca,0x01,0xcc, +0x01,0xcd,0x01,0xce,0x01,0xcf,0x01,0xd1,0x01,0xd2,0x01,0xd4,0x01,0xd5,0x01,0xd6,0x01,0xd8,0x01,0xd9,0x01,0xda,0x01,0xdc,0x01,0xdd,0x01,0xde,0x01,0xdf,0x01,0xe0,0x01,0xe1,0x01,0xe2,0x01,0xe6,0x01,0xea,0x01,0xec,0x01,0xee,0x01,0xef,0x01,0xf0,0x01,0xf1,0x01,0xf2,0x01,0xf5,0x01,0xf6,0x01,0xf8,0x01,0xf9,0x01,0xfa,0x01,0xfc, +0x01,0xfd,0x01,0xff,0x02,0x05,0x02,0x06,0x02,0x0a,0x02,0x0e,0x02,0x0f,0x02,0x12,0x02,0x1f,0x02,0x20,0x02,0x21,0x02,0x22,0x02,0x23,0x02,0x3a,0x02,0x3b,0x02,0x3c,0x02,0x3d,0x02,0x41,0x02,0x42,0x02,0x45,0x02,0x47,0x02,0x49,0x02,0x4b,0x02,0x4d,0x02,0x55,0x02,0x57,0x02,0x59,0x02,0x5a,0x02,0x5b,0x02,0x5d,0x02,0x5e,0x02,0x6b, +0x02,0x6c,0x02,0x6d,0x02,0x74,0x02,0x78,0x02,0x7a,0x02,0x7b,0x02,0x7c,0x02,0x7d,0x02,0x7e,0x02,0x81,0x02,0x82,0x02,0x84,0x02,0x86,0x02,0x87,0x02,0x88,0x02,0x91,0x02,0x92,0x02,0x96,0x02,0x98,0x02,0x99,0x02,0x9a,0x02,0x9b,0x02,0x9c,0x02,0x9d,0x02,0x9e,0x02,0xa1,0x02,0xa2,0x02,0xa6,0x02,0xa7,0x02,0xa8,0x02,0xbf,0x02,0xc0, +0x02,0xc1,0x02,0xc3,0x02,0xc5,0x02,0xc7,0x02,0xc9,0x02,0xca,0x02,0xcb,0x02,0xcc,0x02,0xcd,0x02,0xce,0x02,0xcf,0x02,0xd0,0x02,0xd1,0x02,0xd2,0x02,0xd3,0x02,0xd4,0x02,0xd5,0x02,0xd6,0x02,0xd7,0x02,0xd8,0x02,0xd9,0x02,0xda,0x02,0xdb,0x02,0xdc,0x02,0xdd,0x02,0xde,0x02,0xdf,0x02,0xe0,0x02,0xe1,0x02,0xe2,0x02,0xe3,0x02,0xe4, +0x02,0xe5,0x02,0xe6,0x02,0xe7,0x02,0xe8,0x02,0xe9,0x02,0xea,0x02,0xeb,0x02,0xec,0x02,0xed,0x02,0xee,0x02,0xef,0x02,0xf0,0x02,0xf1,0x02,0xf3,0x02,0xf5,0x02,0xf6,0x02,0xf7,0x02,0xf8,0x02,0xf9,0x02,0xfa,0x02,0xfb,0x02,0xfc,0x02,0xfd,0x02,0xfe,0x02,0xff,0x03,0x00,0x03,0x01,0x03,0x02,0x03,0x0a,0x03,0x0d,0x03,0x0f,0x03,0x1b, +0x03,0x1c,0x03,0x1d,0x03,0x1e,0x03,0x1f,0x03,0x20,0x03,0x21,0x03,0x22,0x03,0x23,0x03,0x34,0x03,0x35,0x03,0x37,0x03,0x38,0x03,0x39,0x03,0x41,0x03,0x42,0x03,0x71,0x03,0x76,0x03,0x78,0x03,0x7d,0x03,0x7e,0x03,0x82,0x03,0xdb,0x03,0xdc,0x03,0xec,0x03,0xed,0x03,0xee,0x03,0xef,0x03,0xf0,0x03,0xf1,0x03,0xf2,0x04,0x0a,0x00,0x01, +0x00,0x0b,0x00,0x0b,0x00,0x29,0x00,0x34,0x00,0x35,0x00,0x3e,0x00,0x49,0x00,0x4e,0x00,0x5a,0x00,0x5e,0x01,0x79,0x01,0x7d,0x00,0x01,0x00,0x1f,0x01,0x80,0x01,0x82,0x01,0x90,0x01,0x93,0x01,0x95,0x01,0x98,0x01,0x9e,0x01,0xa0,0x01,0xa1,0x01,0xa2,0x01,0xa3,0x01,0xae,0x01,0xb7,0x01,0xbd,0x01,0xc0,0x01,0xc3,0x01,0xd5,0x01,0xd9, +0x01,0xda,0x01,0xdb,0x01,0xdd,0x01,0xde,0x01,0xe0,0x01,0xe3,0x01,0xe6,0x01,0xee,0x01,0xf2,0x01,0xf5,0x01,0xfa,0x02,0x00,0x02,0x2d,0x00,0x01,0x01,0x81,0x00,0x05,0x00,0x0a,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x37, +0x00,0x38,0x00,0x39,0x00,0x3a,0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x48,0x00,0x4b,0x00,0x50,0x00,0x51,0x00,0x52,0x00,0x53,0x00,0x55,0x00,0x59,0x00,0x5b,0x00,0x5c,0x00,0x5d,0x00,0x82,0x00,0x83,0x00,0x84,0x00,0x85,0x00,0x86,0x00,0x87,0x00,0x89,0x00,0x8a,0x00,0x8b,0x00,0x8c,0x00,0x8d,0x00,0x8e, +0x00,0x8f,0x00,0x90,0x00,0x91,0x00,0x92,0x00,0x93,0x00,0x94,0x00,0x95,0x00,0x96,0x00,0x97,0x00,0x98,0x00,0x9b,0x00,0x9c,0x00,0x9d,0x00,0x9e,0x00,0x9f,0x00,0xa2,0x00,0xa3,0x00,0xa4,0x00,0xa5,0x00,0xa6,0x00,0xa7,0x00,0xa9,0x00,0xaa,0x00,0xab,0x00,0xac,0x00,0xad,0x00,0xb3,0x00,0xb4,0x00,0xb5,0x00,0xb6,0x00,0xb7,0x00,0xb8, +0x00,0xbf,0x00,0xc0,0x00,0xc1,0x00,0xc2,0x00,0xc3,0x00,0xc4,0x00,0xc5,0x00,0xc6,0x00,0xc7,0x00,0xc8,0x00,0xc9,0x00,0xca,0x00,0xcb,0x00,0xcc,0x00,0xcd,0x00,0xce,0x00,0xcf,0x00,0xd0,0x00,0xd2,0x00,0xd4,0x00,0xd5,0x00,0xd6,0x00,0xd7,0x00,0xd8,0x00,0xd9,0x00,0xda,0x00,0xdb,0x00,0xdc,0x00,0xdd,0x00,0xe6,0x00,0xe7,0x00,0xea, +0x00,0xec,0x00,0xee,0x00,0xf0,0x00,0xf2,0x00,0xf6,0x00,0xf8,0x00,0xfb,0x00,0xfd,0x00,0xff,0x01,0x01,0x01,0x05,0x01,0x06,0x01,0x07,0x01,0x08,0x01,0x09,0x01,0x0a,0x01,0x0b,0x01,0x0e,0x01,0x0f,0x01,0x10,0x01,0x11,0x01,0x12,0x01,0x13,0x01,0x17,0x01,0x19,0x01,0x1b,0x01,0x24,0x01,0x26,0x01,0x28,0x01,0x2a,0x01,0x2c,0x01,0x2e, +0x01,0x30,0x01,0x32,0x01,0x34,0x01,0x36,0x01,0x38,0x01,0x39,0x01,0x3a,0x01,0x3b,0x01,0x3c,0x01,0x3d,0x01,0x3e,0x01,0x3f,0x01,0x40,0x01,0x48,0x01,0x49,0x01,0x51,0x01,0x63,0x01,0x65,0x01,0x66,0x01,0x67,0x01,0x68,0x01,0x69,0x01,0x6c,0x01,0x6d,0x01,0x6e,0x01,0x6f,0x01,0x70,0x01,0x71,0x01,0x72,0x01,0x73,0x01,0x74,0x01,0x75, +0x01,0x76,0x01,0x77,0x01,0x78,0x01,0x7a,0x01,0x7c,0x01,0x7e,0x01,0x7f,0x01,0x81,0x01,0x84,0x01,0x85,0x01,0x88,0x01,0x8d,0x01,0x91,0x01,0x97,0x01,0x99,0x01,0x9b,0x01,0xa6,0x01,0xac,0x01,0xad,0x01,0xaf,0x01,0xb2,0x01,0xb3,0x01,0xb4,0x01,0xb5,0x01,0xb6,0x01,0xb8,0x01,0xba,0x01,0xbb,0x01,0xbc,0x01,0xbe,0x01,0xbf,0x01,0xc1, +0x01,0xc2,0x01,0xc4,0x01,0xc6,0x01,0xc7,0x01,0xc8,0x01,0xc9,0x01,0xca,0x01,0xcc,0x01,0xcd,0x01,0xce,0x01,0xcf,0x01,0xd1,0x01,0xd2,0x01,0xd4,0x01,0xd6,0x01,0xd8,0x01,0xdc,0x01,0xdf,0x01,0xe1,0x01,0xe2,0x01,0xea,0x01,0xec,0x01,0xed,0x01,0xef,0x01,0xf0,0x01,0xf1,0x01,0xf6,0x01,0xf8,0x01,0xf9,0x01,0xfc,0x01,0xfd,0x01,0xff, +0x02,0x05,0x02,0x06,0x02,0x0a,0x02,0x0e,0x02,0x0f,0x02,0x12,0x02,0x1f,0x02,0x20,0x02,0x21,0x02,0x22,0x02,0x23,0x02,0x3a,0x02,0x3b,0x02,0x3c,0x02,0x3d,0x02,0x41,0x02,0x42,0x02,0x45,0x02,0x47,0x02,0x49,0x02,0x4b,0x02,0x4d,0x02,0x55,0x02,0x56,0x02,0x57,0x02,0x59,0x02,0x5a,0x02,0x5b,0x02,0x5d,0x02,0x5e,0x02,0x66,0x02,0x6b, +0x02,0x6c,0x02,0x6d,0x02,0x74,0x02,0x78,0x02,0x7a,0x02,0x7b,0x02,0x7c,0x02,0x7d,0x02,0x7e,0x02,0x81,0x02,0x82,0x02,0x84,0x02,0x86,0x02,0x87,0x02,0x88,0x02,0x91,0x02,0x92,0x02,0x96,0x02,0x98,0x02,0x99,0x02,0x9a,0x02,0x9b,0x02,0x9c,0x02,0x9d,0x02,0x9e,0x02,0xa1,0x02,0xa2,0x02,0xa6,0x02,0xa7,0x02,0xa8,0x02,0xbf,0x02,0xc0, +0x02,0xc1,0x02,0xc2,0x02,0xc3,0x02,0xc5,0x02,0xc7,0x02,0xc9,0x02,0xca,0x02,0xcb,0x02,0xcc,0x02,0xcd,0x02,0xce,0x02,0xcf,0x02,0xd0,0x02,0xd1,0x02,0xd2,0x02,0xd3,0x02,0xd4,0x02,0xd5,0x02,0xd6,0x02,0xd7,0x02,0xd8,0x02,0xd9,0x02,0xda,0x02,0xdb,0x02,0xdc,0x02,0xdd,0x02,0xde,0x02,0xdf,0x02,0xe0,0x02,0xe1,0x02,0xe2,0x02,0xe3, +0x02,0xe4,0x02,0xe5,0x02,0xe6,0x02,0xe7,0x02,0xe8,0x02,0xe9,0x02,0xea,0x02,0xeb,0x02,0xec,0x02,0xed,0x02,0xee,0x02,0xef,0x02,0xf0,0x02,0xf1,0x02,0xf3,0x02,0xf5,0x02,0xf6,0x02,0xf7,0x02,0xf8,0x02,0xf9,0x02,0xfa,0x02,0xfb,0x02,0xfc,0x02,0xfd,0x02,0xfe,0x02,0xff,0x03,0x00,0x03,0x01,0x03,0x02,0x03,0x0a,0x03,0x0d,0x03,0x0f, +0x03,0x1b,0x03,0x1c,0x03,0x1d,0x03,0x1e,0x03,0x1f,0x03,0x20,0x03,0x21,0x03,0x22,0x03,0x23,0x03,0x34,0x03,0x35,0x03,0x37,0x03,0x38,0x03,0x39,0x03,0x41,0x03,0x42,0x00,0x01,0x00,0x05,0x03,0x3e,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x03,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x0c,0x00,0x09,0x00,0x0a,0x00,0x02,0x00,0x02, +0x00,0x03,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0c,0x00,0x0d,0x00,0x10,0x00,0x0e,0x00,0x0f,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x15,0x00,0x14,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x17, +0x00,0x18,0x00,0x15,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x1b,0x00,0x19,0x00,0x1c,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,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,0x04,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02, +0x00,0x03,0x00,0x02,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x00,0x00,0x14,0x00,0x16,0x00,0x16,0x00,0x16,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x17,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x15,0x00,0x19,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x04,0x00,0x14,0x00,0x04,0x00,0x14,0x00,0x04,0x00,0x14,0x00,0x04,0x00,0x14,0x00,0x03,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00, +0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x17,0x00,0x02,0x00,0x17,0x00,0x02,0x00,0x17,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x18,0x00,0x03,0x00,0x18, +0x00,0x03,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00, +0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x0f,0x00,0x19,0x00,0x0f,0x00,0x11,0x00,0x1c,0x00,0x11,0x00,0x1c,0x00,0x11,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d, +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,0x05,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x05,0x00,0x11, +0x00,0x02,0x00,0x03,0x00,0x02,0x00,0x09,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x06,0x00,0x0f,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x02,0x00,0x02,0x00,0x0c,0x00,0x1e,0x00,0x1e,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x12,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x05,0x00,0x0e,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x09,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x04,0x00,0x06,0x00,0x12,0x00,0x00,0x00,0x0e, +0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x16,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x15,0x00,0x14,0x00,0x00,0x00,0x19,0x00,0x15,0x00,0x1b, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1f,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x16,0x00,0x16,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x00,0x1f,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,0x18,0x00,0x0d,0x00,0x19,0x00,0x0d,0x00,0x19,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,0x15,0x00,0x07,0x00,0x08,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x14,0x00,0x06,0x00,0x00,0x00,0x0f,0x00,0x19,0x00,0x0f,0x00,0x00,0x00,0x0e,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x0e,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x16,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x16,0x00,0x0e,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, +0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x15,0x00,0x12,0x00,0x19,0x00,0x12,0x00,0x19,0x00,0x12,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x00,0x1b,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,0x00,0x13,0x00,0x02,0x00,0x17,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00, +0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x05,0x00,0x16,0x00,0x02, +0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x18,0x00,0x03,0x00,0x18,0x00,0x03,0x00,0x18,0x00,0x03,0x00,0x18,0x00,0x03,0x00,0x18,0x00,0x03,0x00,0x18,0x00,0x03,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x19,0x00,0x0f,0x00,0x19,0x00,0x0f,0x00,0x19,0x00,0x0f,0x00,0x19,0x00,0x03,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,0x1d,0x00,0x1d,0x00,0x00,0x00,0x1d,0x00,0x1d,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0x00,0x1d,0x00,0x01,0x00,0x05,0x03,0x3e,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x17, +0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x19,0x00,0x0a,0x00,0x06,0x00,0x0d,0x00,0x09,0x00,0x12,0x00,0x0e,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18, +0x00,0x18,0x00,0x08,0x00,0x18,0x00,0x15,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x0b,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x02,0x00,0x0c,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,0x17,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,0x11,0x00,0x11,0x00,0x11,0x00,0x11,0x00,0x11,0x00,0x11,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x1a,0x00,0x1a,0x00,0x1a,0x00,0x1a,0x00,0x1a,0x00,0x00,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x0b,0x00,0x0b,0x00,0x0b,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x00, +0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,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,0x1c,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,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x08,0x00,0x05, +0x00,0x08,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00,0x1b,0x00,0x19,0x00,0x1b,0x00,0x19,0x00,0x1b,0x00,0x19,0x00,0x1b,0x00,0x0a,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0b,0x00,0x06,0x00,0x0b,0x00,0x06,0x00,0x0b,0x00,0x06, +0x00,0x0b,0x00,0x06,0x00,0x0b,0x00,0x06,0x00,0x0b,0x00,0x09,0x00,0x00,0x00,0x0e,0x00,0x02,0x00,0x0e,0x00,0x14,0x00,0x0c,0x00,0x14,0x00,0x0c,0x00,0x14,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x11,0x00,0x1a,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x19,0x00,0x1b,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00, +0x00,0x14,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x15,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x0b,0x00,0x15,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x15,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x08,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x05, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x01,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x0a,0x00,0x10,0x00,0x00, +0x00,0x12,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x15,0x00,0x16,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x04,0x00,0x18,0x00,0x18,0x00,0x08,0x00,0x18,0x00,0x18,0x00,0x15,0x00,0x00,0x00,0x02,0x00,0x15, +0x00,0x16,0x00,0x18,0x00,0x03,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x15,0x00,0x15,0x00,0x00,0x00,0x18,0x00,0x15,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x02,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x08,0x00,0x0d,0x00,0x02,0x00,0x0d,0x00,0x02,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x00,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x00,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18, +0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x0a,0x00,0x00,0x00,0x0e,0x00,0x02,0x00,0x0e,0x00,0x00,0x00,0x12,0x00,0x16,0x00,0x0a,0x00,0x00,0x00,0x0f,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x01, +0x00,0x04,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x0f,0x00,0x03,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x12,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18, +0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x02,0x00,0x10,0x00,0x02,0x00,0x10,0x00,0x02,0x00,0x0f,0x00,0x03,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x12,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x11,0x00,0x1a,0x00,0x00,0x00,0x18,0x00,0x09,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a, +0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x11,0x00,0x1a,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x15,0x00,0x05,0x00,0x08,0x00,0x05,0x00,0x15,0x00,0x06,0x00,0x0b,0x00,0x06,0x00,0x0b, +0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x0b,0x00,0x0e,0x00,0x02,0x00,0x0e,0x00,0x02,0x00,0x0e,0x00,0x02,0x00,0x0e,0x00,0x02,0x00,0x05,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,0x17, +0x00,0x17,0x00,0x17,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x13,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x13,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x01,0x00,0x00,0x00,0x0a,0x00,0x20,0x00,0x3a,0x00,0x01,0x44,0x46,0x4c,0x54,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x02, +0x00,0x00,0x00,0x01,0x00,0x02,0x6c,0x69,0x67,0x61,0x00,0x0e,0x73,0x6d,0x63,0x70,0x00,0x14,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x06,0x00,0x0e,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x04,0x00,0x00,0x00,0x01,0x01,0xc6,0x00,0x02,0x01,0xd0,0x00,0xdc,0x03,0x71,0x03,0x74,0x03,0x75, +0x03,0x76,0x03,0x77,0x03,0x78,0x03,0x79,0x03,0x7a,0x03,0x7b,0x03,0x7c,0x03,0x7d,0x03,0x7e,0x03,0x7f,0x03,0x81,0x03,0x82,0x04,0x0a,0x03,0xdb,0x03,0xdc,0x03,0xeb,0x03,0xec,0x03,0xed,0x03,0xee,0x03,0xef,0x03,0xf0,0x03,0xf1,0x03,0xf2,0x03,0x71,0x03,0x74,0x03,0x75,0x03,0x76,0x03,0x77,0x03,0x78,0x03,0x79,0x03,0x7a,0x03,0x7b, +0x03,0x7c,0x03,0x7d,0x03,0x7e,0x03,0x7f,0x03,0x81,0x03,0x82,0x04,0x0a,0x03,0xdb,0x03,0xdc,0x03,0xeb,0x03,0xec,0x03,0xed,0x03,0xee,0x03,0xef,0x03,0xf0,0x03,0xf1,0x03,0xf2,0x03,0xd7,0x03,0xd6,0x03,0xd5,0x03,0xd4,0x03,0xd3,0x03,0xd2,0x03,0xd0,0x03,0xcf,0x03,0xce,0x03,0xcd,0x03,0xcc,0x03,0xcb,0x03,0xca,0x03,0xc9,0x03,0xc8, +0x03,0xd9,0x03,0xc7,0x03,0xc6,0x03,0xc5,0x03,0xc4,0x03,0xc3,0x03,0xc2,0x03,0xc1,0x03,0xc0,0x03,0x6c,0x03,0xbe,0x03,0xbd,0x03,0x84,0x03,0xd7,0x03,0xd6,0x03,0xd5,0x03,0xd4,0x03,0xd3,0x03,0xd2,0x03,0xd0,0x03,0xcf,0x03,0xce,0x03,0xcd,0x03,0xcc,0x03,0xcb,0x03,0xca,0x03,0xc9,0x03,0xc8,0x03,0xd9,0x03,0xc7,0x03,0xc6,0x03,0xc5, +0x03,0xc4,0x03,0xc3,0x03,0xc2,0x03,0xc1,0x03,0xc0,0x03,0x6c,0x03,0xbe,0x03,0xbd,0x03,0x88,0x03,0xbc,0x03,0xbc,0x03,0xbb,0x03,0xbb,0x03,0xba,0x03,0xba,0x03,0xb9,0x03,0xb9,0x03,0xb8,0x03,0xb8,0x03,0xb6,0x03,0xb6,0x03,0xb5,0x03,0xb5,0x03,0xda,0x03,0xda,0x03,0xb4,0x03,0xb4,0x03,0xb3,0x03,0xb3,0x03,0xb2,0x03,0xb2,0x03,0xb1, +0x03,0xb1,0x03,0xb0,0x03,0xb0,0x03,0xaf,0x03,0xaf,0x03,0xae,0x03,0xae,0x03,0xac,0x03,0xac,0x03,0xab,0x03,0xab,0x03,0xaa,0x03,0xaa,0x03,0xa9,0x03,0xa9,0x03,0xa8,0x03,0xa8,0x03,0xa7,0x03,0xa7,0x03,0xa6,0x03,0xa5,0x03,0xa5,0x03,0xa4,0x03,0xa4,0x03,0xa3,0x03,0xa3,0x03,0xa2,0x03,0xa2,0x03,0xa1,0x03,0xa1,0x03,0xa0,0x03,0xa0, +0x03,0x9f,0x03,0x9f,0x03,0x9e,0x03,0x9e,0x03,0x9d,0x03,0x9d,0x03,0x9c,0x03,0x9c,0x03,0x9b,0x03,0x9b,0x03,0x9a,0x03,0x9a,0x03,0x99,0x03,0x99,0x03,0x98,0x03,0x98,0x03,0x97,0x03,0x97,0x03,0x96,0x03,0x96,0x03,0x95,0x03,0x95,0x03,0x6b,0x03,0x6b,0x03,0x93,0x03,0x93,0x03,0x92,0x03,0x92,0x03,0x91,0x03,0x91,0x03,0xd8,0x03,0xd8, +0x03,0x90,0x03,0x90,0x03,0x8f,0x03,0x8f,0x03,0x8e,0x03,0x8e,0x03,0x8d,0x03,0x8d,0x03,0x8c,0x03,0x8c,0x03,0x8b,0x03,0x8b,0x03,0x8a,0x03,0x8a,0x03,0x89,0x03,0x89,0x03,0x88,0x03,0x87,0x03,0x87,0x03,0x86,0x03,0x86,0x03,0x85,0x03,0x85,0x03,0xd1,0x03,0xd1,0x00,0x01,0x00,0x82,0x00,0x01,0x00,0x08,0x00,0x01,0x00,0x04,0x03,0x64, +0x00,0x02,0x00,0x4c,0x00,0x02,0x00,0x12,0x00,0x24,0x00,0x3d,0x00,0x00,0x00,0x44,0x00,0x5d,0x00,0x1a,0x00,0x82,0x00,0x87,0x00,0x34,0x00,0x89,0x00,0x98,0x00,0x3a,0x00,0x9b,0x00,0x9f,0x00,0x4a,0x00,0xa1,0x00,0xa7,0x00,0x4f,0x00,0xa9,0x00,0xb8,0x00,0x56,0x00,0xbb,0x00,0xbf,0x00,0x66,0x00,0xc1,0x00,0xcb,0x00,0x6b,0x00,0xce, +0x00,0xe1,0x00,0x76,0x00,0xe4,0x00,0xe7,0x00,0x8a,0x00,0xea,0x00,0xf2,0x00,0x8e,0x00,0xf6,0x00,0xf9,0x00,0x97,0x00,0xfb,0x01,0x02,0x00,0x9b,0x01,0x05,0x01,0x0a,0x00,0xa3,0x01,0x0e,0x01,0x13,0x00,0xa9,0x01,0x16,0x01,0x40,0x00,0xaf,0x01,0x48,0x01,0x49,0x00,0xda,0x00,0x01,0x00,0x01,0x00,0x49,0x00,0x00,0x00,0x03,0x04,0x99, +0x01,0x90,0x00,0x05,0x00,0x04,0x05,0x9a,0x05,0x33,0x00,0x00,0x01,0x1f,0x05,0x9a,0x05,0x33,0x00,0x00,0x03,0xd1,0x00,0x66,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x02,0xef,0x50,0x00,0x20,0x5b,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x70,0x79,0x72,0x73,0x00,0x40,0x00,0x00,0xff,0xfd, +0x06,0x00,0xfe,0x00,0x00,0x66,0x07,0x9a,0x02,0x00,0x20,0x00,0x01,0x9f,0x4f,0x01,0x00,0x00,0x04,0x3a,0x05,0xb0,0x00,0x00,0x00,0x20,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x04,0x7e,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x03,0x00,0x01,0x00,0x00,0x02,0x26,0x00,0x06,0x02,0x0a,0x00,0x00,0x00,0x00, +0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00, +0x00,0x00,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,0x00,0x09,0x00,0x0a,0x00,0x0b,0x00,0x0c,0x00,0x0d,0x00,0x0e,0x00,0x0f,0x00,0x10,0x00,0x11,0x00,0x12,0x00,0x13,0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x18,0x00,0x19,0x00,0x1a,0x00,0x1b,0x00,0x1c,0x00,0x1d,0x00,0x1e,0x00,0x1f,0x00,0x20,0x00,0x21, +0x00,0x22,0x00,0x23,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2a,0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a,0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x3e,0x00,0x3f,0x00,0x40,0x00,0x41, +0x00,0x42,0x00,0x43,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x47,0x00,0x48,0x00,0x49,0x00,0x4a,0x00,0x4b,0x00,0x4c,0x00,0x4d,0x00,0x4e,0x00,0x4f,0x00,0x50,0x00,0x51,0x00,0x52,0x00,0x53,0x00,0x54,0x00,0x55,0x00,0x56,0x00,0x57,0x00,0x58,0x00,0x59,0x00,0x5a,0x00,0x5b,0x00,0x5c,0x00,0x5d,0x00,0x5e,0x00,0x5f,0x00,0x60,0x00,0x61, +0x00,0x00,0x00,0x86,0x00,0x87,0x00,0x89,0x00,0x8b,0x00,0x93,0x00,0x98,0x00,0x9e,0x00,0xa3,0x00,0xa2,0x00,0xa4,0x00,0xa6,0x00,0xa5,0x00,0xa7,0x00,0xa9,0x00,0xab,0x00,0xaa,0x00,0xac,0x00,0xad,0x00,0xaf,0x00,0xae,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xb5,0x00,0xb4,0x00,0xb6,0x00,0xb8,0x00,0xb7,0x00,0xbc,0x00,0xbb,0x00,0xbd, +0x00,0xbe,0x03,0x3b,0x00,0x72,0x00,0x64,0x00,0x65,0x00,0x69,0x03,0x3d,0x00,0x78,0x00,0xa1,0x00,0x70,0x00,0x6b,0x03,0x51,0x00,0x76,0x00,0x6a,0x03,0x5f,0x00,0x88,0x00,0x9a,0x03,0x5c,0x00,0x73,0x03,0x60,0x03,0x61,0x00,0x67,0x00,0x77,0x03,0x57,0x03,0x59,0x03,0x58,0x01,0x9a,0x03,0x5d,0x00,0x6c,0x00,0x7c,0x01,0x83,0x00,0xa8, +0x00,0xba,0x00,0x81,0x00,0x63,0x00,0x6e,0x03,0x5b,0x01,0x42,0x03,0x5e,0x01,0x6f,0x00,0x6d,0x00,0x7d,0x03,0x3f,0x00,0x03,0x00,0x82,0x00,0x85,0x00,0x97,0x01,0x14,0x01,0x15,0x03,0x30,0x03,0x31,0x03,0x38,0x03,0x39,0x03,0x34,0x03,0x35,0x00,0xb9,0x03,0x62,0x00,0xc1,0x01,0x3a,0x03,0x46,0x03,0x4d,0x03,0x43,0x03,0x44,0x03,0x64, +0x03,0x65,0x03,0x3c,0x00,0x79,0x03,0x36,0x03,0x3a,0x03,0x40,0x00,0x84,0x00,0x8c,0x00,0x83,0x00,0x8d,0x00,0x8a,0x00,0x8f,0x00,0x90,0x00,0x91,0x00,0x8e,0x00,0x95,0x00,0x96,0x00,0x00,0x00,0x94,0x00,0x9c,0x00,0x9d,0x00,0x9b,0x00,0xf3,0x01,0x52,0x01,0x58,0x00,0x71,0x01,0x54,0x01,0x55,0x01,0x56,0x00,0x7a,0x01,0x59,0x01,0x57, +0x01,0x53,0x00,0x04,0x02,0x58,0x00,0x00,0x00,0x92,0x00,0x80,0x00,0x06,0x00,0x12,0x00,0x00,0x00,0x09,0x00,0x0d,0x00,0x7e,0x01,0x7f,0x01,0x92,0x01,0xa1,0x01,0xb0,0x01,0xf0,0x01,0xff,0x02,0x19,0x02,0x37,0x02,0xbc,0x02,0xc7,0x02,0xc9,0x02,0xdd,0x02,0xf3,0x03,0x01,0x03,0x03,0x03,0x09,0x03,0x0f,0x03,0x23,0x03,0x8a,0x03,0x8c, +0x03,0xa1,0x03,0xce,0x03,0xd2,0x03,0xd6,0x04,0x86,0x05,0x13,0x1e,0x01,0x1e,0x3f,0x1e,0x85,0x1e,0xf9,0x1f,0x4d,0x20,0x0b,0x20,0x15,0x20,0x1e,0x20,0x22,0x20,0x26,0x20,0x30,0x20,0x33,0x20,0x3a,0x20,0x3c,0x20,0x44,0x20,0x74,0x20,0x7f,0x20,0xa4,0x20,0xa7,0x20,0xac,0x21,0x05,0x21,0x13,0x21,0x16,0x21,0x22,0x21,0x26,0x21,0x2e, +0x21,0x5e,0x22,0x02,0x22,0x06,0x22,0x0f,0x22,0x12,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60,0x22,0x65,0x25,0xca,0xf6,0xc3,0xfb,0x04,0xfe,0xff,0xff,0xfd,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x0d,0x00,0x20,0x00,0xa0,0x01,0x92,0x01,0xa0,0x01,0xaf,0x01,0xf0,0x01,0xfa,0x02,0x18,0x02,0x37,0x02,0xbc,0x02,0xc6, +0x02,0xc9,0x02,0xd8,0x02,0xf3,0x03,0x00,0x03,0x03,0x03,0x09,0x03,0x0f,0x03,0x23,0x03,0x84,0x03,0x8c,0x03,0x8e,0x03,0xa3,0x03,0xd1,0x03,0xd6,0x04,0x00,0x04,0x88,0x1e,0x00,0x1e,0x3e,0x1e,0x80,0x1e,0xa0,0x1f,0x4d,0x20,0x00,0x20,0x13,0x20,0x17,0x20,0x20,0x20,0x25,0x20,0x30,0x20,0x32,0x20,0x39,0x20,0x3c,0x20,0x44,0x20,0x74, +0x20,0x7f,0x20,0xa3,0x20,0xa7,0x20,0xab,0x21,0x05,0x21,0x13,0x21,0x16,0x21,0x22,0x21,0x26,0x21,0x2e,0x21,0x5b,0x22,0x02,0x22,0x06,0x22,0x0f,0x22,0x11,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60,0x22,0x64,0x25,0xca,0xf6,0xc3,0xfb,0x01,0xfe,0xff,0xff,0xfc,0xff,0xff,0x00,0x01,0x04,0x03,0xff,0xf5,0xff,0xe3,0xff,0xc2, +0xff,0xb0,0xff,0xa3,0xff,0x96,0xff,0x57,0xff,0x4e,0xff,0x36,0xff,0x19,0xfe,0x95,0xfe,0x8c,0xfd,0xa8,0xfe,0x7c,0xfe,0x67,0xfe,0x5b,0xfe,0x5a,0xfe,0x55,0xfe,0x50,0xfe,0x3d,0xfd,0xdd,0xfd,0xdc,0xfd,0xdb,0xfd,0xda,0xfd,0xd8,0xfd,0xd5,0xfd,0xac,0xfd,0xab,0xe4,0xbf,0xe4,0x83,0xe4,0x43,0xe4,0x29,0xe3,0xd6,0xe3,0x24,0xe3,0x1d, +0xe3,0x1c,0xe3,0x1b,0xe3,0x19,0xe3,0x10,0xe3,0x0f,0xe3,0x0a,0xe3,0x09,0xe3,0x02,0xe2,0xd3,0xe2,0xc9,0xe2,0xa6,0xe2,0xa4,0xe2,0xa1,0xe2,0x49,0xe2,0x3c,0xe2,0x3a,0xe2,0x2f,0xe0,0x5d,0xe2,0x24,0xe1,0xf8,0xe1,0x55,0xdf,0x69,0xe1,0x49,0xe1,0x48,0xe1,0x41,0xe1,0x3e,0xe1,0x32,0xe1,0x16,0xe0,0xff,0xe0,0xfc,0xdd,0x98,0x0c,0xa0, +0x08,0x63,0x04,0x69,0x03,0x6d,0x00,0x01,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x02,0x58,0x00,0x00,0x00,0x92,0x00,0x80,0x00,0x06,0x00,0x12,0x00,0x00,0x00,0x09,0x00,0x0d,0x00,0x7e,0x01,0x7f,0x01,0x92,0x01,0xa1,0x01,0xb0,0x01,0xf0,0x01,0xff,0x02,0x19,0x02,0x37, +0x02,0xbc,0x02,0xc7,0x02,0xc9,0x02,0xdd,0x02,0xf3,0x03,0x01,0x03,0x03,0x03,0x09,0x03,0x0f,0x03,0x23,0x03,0x8a,0x03,0x8c,0x03,0xa1,0x03,0xce,0x03,0xd2,0x03,0xd6,0x04,0x86,0x05,0x13,0x1e,0x01,0x1e,0x3f,0x1e,0x85,0x1e,0xf9,0x1f,0x4d,0x20,0x0b,0x20,0x15,0x20,0x1e,0x20,0x22,0x20,0x26,0x20,0x30,0x20,0x33,0x20,0x3a,0x20,0x3c, +0x20,0x44,0x20,0x74,0x20,0x7f,0x20,0xa4,0x20,0xa7,0x20,0xac,0x21,0x05,0x21,0x13,0x21,0x16,0x21,0x22,0x21,0x26,0x21,0x2e,0x21,0x5e,0x22,0x02,0x22,0x06,0x22,0x0f,0x22,0x12,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60,0x22,0x65,0x25,0xca,0xf6,0xc3,0xfb,0x04,0xfe,0xff,0xff,0xfd,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x09, +0x00,0x0d,0x00,0x20,0x00,0xa0,0x01,0x92,0x01,0xa0,0x01,0xaf,0x01,0xf0,0x01,0xfa,0x02,0x18,0x02,0x37,0x02,0xbc,0x02,0xc6,0x02,0xc9,0x02,0xd8,0x02,0xf3,0x03,0x00,0x03,0x03,0x03,0x09,0x03,0x0f,0x03,0x23,0x03,0x84,0x03,0x8c,0x03,0x8e,0x03,0xa3,0x03,0xd1,0x03,0xd6,0x04,0x00,0x04,0x88,0x1e,0x00,0x1e,0x3e,0x1e,0x80,0x1e,0xa0, +0x1f,0x4d,0x20,0x00,0x20,0x13,0x20,0x17,0x20,0x20,0x20,0x25,0x20,0x30,0x20,0x32,0x20,0x39,0x20,0x3c,0x20,0x44,0x20,0x74,0x20,0x7f,0x20,0xa3,0x20,0xa7,0x20,0xab,0x21,0x05,0x21,0x13,0x21,0x16,0x21,0x22,0x21,0x26,0x21,0x2e,0x21,0x5b,0x22,0x02,0x22,0x06,0x22,0x0f,0x22,0x11,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60, +0x22,0x64,0x25,0xca,0xf6,0xc3,0xfb,0x01,0xfe,0xff,0xff,0xfc,0xff,0xff,0x00,0x01,0x04,0x03,0xff,0xf5,0xff,0xe3,0xff,0xc2,0xff,0xb0,0xff,0xa3,0xff,0x96,0xff,0x57,0xff,0x4e,0xff,0x36,0xff,0x19,0xfe,0x95,0xfe,0x8c,0xfd,0xa8,0xfe,0x7c,0xfe,0x67,0xfe,0x5b,0xfe,0x5a,0xfe,0x55,0xfe,0x50,0xfe,0x3d,0xfd,0xdd,0xfd,0xdc,0xfd,0xdb, +0xfd,0xda,0xfd,0xd8,0xfd,0xd5,0xfd,0xac,0xfd,0xab,0xe4,0xbf,0xe4,0x83,0xe4,0x43,0xe4,0x29,0xe3,0xd6,0xe3,0x24,0xe3,0x1d,0xe3,0x1c,0xe3,0x1b,0xe3,0x19,0xe3,0x10,0xe3,0x0f,0xe3,0x0a,0xe3,0x09,0xe3,0x02,0xe2,0xd3,0xe2,0xc9,0xe2,0xa6,0xe2,0xa4,0xe2,0xa1,0xe2,0x49,0xe2,0x3c,0xe2,0x3a,0xe2,0x2f,0xe0,0x5d,0xe2,0x24,0xe1,0xf8, +0xe1,0x55,0xdf,0x69,0xe1,0x49,0xe1,0x48,0xe1,0x41,0xe1,0x3e,0xe1,0x32,0xe1,0x16,0xe0,0xff,0xe0,0xfc,0xdd,0x98,0x0c,0xa0,0x08,0x63,0x04,0x69,0x03,0x6d,0x00,0x01,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xab,0x00,0x00,0x01,0x71,0x05,0xb0,0x00,0x03, +0x00,0x07,0x00,0x31,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x00,0x03,0x03,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x33,0x13,0x23,0x35,0x33,0x01,0x70,0xc5, +0xc5,0x01,0xc6,0xc6,0x01,0xde,0x03,0xd2,0xfa,0x50,0xcc,0x00,0x00,0x02,0x00,0x7e,0x03,0xa8,0x02,0x79,0x05,0xb0,0x00,0x04,0x00,0x0a,0x00,0x2e,0x40,0x0a,0x0a,0x09,0x07,0x06,0x04,0x03,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x05,0x00,0x02,0x00,0x01,0x01,0x15,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x03, +0x01,0x01,0x01,0x07,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x07,0x23,0x11,0x33,0x01,0x07,0x23,0x37,0x11,0x33,0x02,0x79,0x65,0x61,0xc6,0xfe,0xcb,0x65,0x61,0x01,0xc5,0x04,0xa2,0xfa,0x02,0x08,0xfe,0xf2,0xfa,0xf0,0x01,0x18,0x00,0x00,0x02,0x00,0x46,0x00,0x00,0x04,0xa2,0x05,0xb0,0x00,0x1b,0x00,0x1f,0x00,0x8d,0x40,0x22,0x1f,0x1e, +0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x10,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x2c,0x0e,0x0b,0x02,0x03,0x0c,0x02,0x02,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x08,0x01,0x06,0x06,0x07,0x16, +0x0f,0x0a,0x02,0x04,0x04,0x05,0x00,0x00,0x1b,0x09,0x07,0x02,0x05,0x05,0x0a,0x16,0x0d,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0x1b,0x40,0x2a,0x09,0x07,0x02,0x05,0x0f,0x0a,0x02,0x04,0x03,0x05,0x04,0x00,0x02,0x1d,0x0e,0x0b,0x02,0x03,0x0c,0x02,0x02,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x08,0x01,0x06,0x06,0x07,0x16,0x0d,0x01,0x01, +0x01,0x08,0x01,0x17,0x04,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x03,0x23,0x13,0x23,0x35,0x21,0x13,0x21,0x35,0x21,0x13,0x33,0x03,0x33,0x13,0x33,0x03,0x33,0x15,0x23,0x03,0x33,0x15,0x23,0x03,0x23,0x03,0x33,0x13,0x23,0x02,0xc8,0xff,0x50,0x97,0x50,0xec,0x01,0x08,0x44,0xff,0x00,0x01,0x1c,0x52,0x97,0x52,0xff,0x52,0x97,0x52,0xc7,0xe2, +0x44,0xdb,0xf7,0x50,0x98,0x93,0xff,0x44,0xff,0x01,0x9a,0xfe,0x66,0x01,0x9a,0x8c,0x01,0x5c,0x8e,0x01,0xa0,0xfe,0x60,0x01,0xa0,0xfe,0x60,0x8e,0xfe,0xa4,0x8c,0xfe,0x66,0x02,0x26,0x01,0x5c,0x00,0x00,0x00,0x00,0x01,0x00,0x7f,0xff,0x30,0x04,0x26,0x06,0x9d,0x00,0x2c,0x00,0x5b,0x40,0x0e,0x2b,0x29,0x27,0x26,0x21,0x20,0x14,0x12, +0x10,0x0f,0x0b,0x0a,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x40,0x0c,0x09,0x02,0x02,0x00,0x25,0x01,0x05,0x04,0x22,0x1f,0x02,0x03,0x05,0x03,0x15,0x00,0x01,0x02,0x04,0x02,0x01,0x04,0x29,0x00,0x04,0x05,0x02,0x04,0x05,0x27,0x00,0x00,0x00,0x02,0x01,0x00,0x02,0x01,0x00,0x1d,0x00,0x05,0x03,0x03,0x05,0x01,0x00,0x1a,0x00, +0x05,0x05,0x03,0x00,0x00,0x1b,0x00,0x03,0x05,0x03,0x00,0x00,0x18,0x07,0xb0,0x2f,0x2b,0x01,0x34,0x26,0x27,0x2e,0x01,0x35,0x34,0x36,0x37,0x35,0x33,0x15,0x1e,0x01,0x15,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x17,0x1e,0x01,0x15,0x14,0x06,0x07,0x15,0x23,0x35,0x2e,0x01,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x03,0x61, +0x7f,0x93,0xca,0xce,0xbe,0xa6,0x9e,0xa7,0xb9,0xc4,0x7e,0x6f,0x76,0x76,0x7a,0x9e,0xcc,0xc6,0xce,0xb4,0x9d,0xac,0xdc,0x04,0x02,0xbe,0x9c,0x70,0x81,0x91,0x01,0x78,0x5a,0x7f,0x32,0x3d,0xcc,0xaa,0xa5,0xd0,0x15,0xdd,0xde,0x16,0xe6,0xc1,0x7f,0x9e,0x7b,0x6b,0x61,0x78,0x36,0x42,0xc5,0xa9,0xac,0xcb,0x13,0xc0,0xbf,0x12,0xd7,0xd0, +0x05,0x9a,0x83,0x7b,0x00,0x05,0x00,0x68,0xff,0xeb,0x05,0x83,0x05,0xc5,0x00,0x0d,0x00,0x1b,0x00,0x29,0x00,0x37,0x00,0x3b,0x00,0x59,0x40,0x12,0x35,0x33,0x2e,0x2c,0x27,0x25,0x20,0x1e,0x19,0x17,0x12,0x10,0x0b,0x09,0x04,0x02,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3a,0x3b,0x3a,0x02,0x02,0x03,0x39,0x38,0x02,0x06,0x07, +0x02,0x15,0x00,0x02,0x00,0x01,0x04,0x02,0x01,0x01,0x00,0x1d,0x00,0x04,0x00,0x07,0x06,0x04,0x07,0x01,0x00,0x1d,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x06,0x06,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x07,0xb0,0x2f,0x2b,0x13,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26, +0x35,0x33,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26,0x35,0x33,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x05,0x27,0x01,0x17,0x68,0xa4,0x89,0x89,0xa4,0xa3,0x88,0x8a,0xa5,0x92,0x51,0x4c,0x49,0x50,0x51,0x4a,0x4b, +0x50,0x02,0x2f,0xa4,0x89,0x88,0xa5,0xa4,0x87,0x8a,0xa5,0x92,0x51,0x4c,0x49,0x50,0x52,0x49,0x4a,0x51,0xfe,0x0f,0x6d,0x02,0xc7,0x6d,0x04,0x98,0x7f,0xae,0xad,0x80,0x4d,0x7f,0xac,0xac,0x7f,0x4a,0x67,0x66,0x4b,0x4d,0x4a,0x69,0x69,0x4a,0xfc,0xcd,0x7f,0xad,0xad,0x7f,0x4e,0x80,0xac,0xac,0x80,0x4b,0x67,0x67,0x4b,0x4e,0x4a,0x68, +0x68,0x4a,0xf7,0x43,0x04,0x72,0x43,0x00,0x00,0x03,0x00,0x40,0xff,0xeb,0x04,0xd0,0x05,0xc5,0x00,0x21,0x00,0x2c,0x00,0x39,0x00,0x9d,0x40,0x12,0x23,0x22,0x38,0x36,0x22,0x2c,0x23,0x2c,0x20,0x1e,0x1b,0x1a,0x15,0x14,0x0a,0x08,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x3c,0x30,0x10,0x03,0x03,0x01,0x05, +0x26,0x25,0x18,0x11,0x04,0x04,0x01,0x1c,0x01,0x02,0x04,0x03,0x15,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x08,0x16,0x06,0x01,0x04,0x04,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x08,0x02,0x17,0x07,0x1b,0x40,0x3a,0x30,0x10,0x03,0x03,0x01,0x05,0x26, +0x25,0x18,0x11,0x04,0x04,0x01,0x1c,0x01,0x02,0x04,0x03,0x15,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x01,0x01,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x08,0x16,0x06,0x01,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x13,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x36, +0x33,0x32,0x16,0x15,0x14,0x06,0x0f,0x01,0x01,0x3e,0x01,0x35,0x33,0x14,0x06,0x07,0x17,0x07,0x23,0x27,0x0e,0x01,0x23,0x22,0x24,0x05,0x32,0x36,0x37,0x01,0x07,0x0e,0x01,0x15,0x14,0x16,0x03,0x14,0x16,0x17,0x37,0x3e,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x40,0x8d,0x8c,0x4e,0x4c,0xc3,0xab,0x9e,0xc6,0x69,0x67,0x6d,0x01,0x54,0x29, +0x2e,0xb0,0x4e,0x4a,0xb9,0x02,0xe5,0x55,0x50,0xc2,0x68,0xd9,0xfe,0xff,0x01,0xda,0x48,0x8c,0x3e,0xfe,0x97,0x28,0x5b,0x3b,0x8e,0x0f,0x36,0x36,0x8a,0x39,0x29,0x61,0x4e,0x51,0x58,0x01,0x88,0x7a,0xb7,0x5c,0x63,0x9b,0x52,0xa9,0xb7,0xb6,0x80,0x62,0x8f,0x4b,0x50,0xfe,0x67,0x41,0x9e,0x58,0x84,0xe0,0x59,0xdf,0x05,0x66,0x3c,0x3f, +0xe6,0x4c,0x31,0x2e,0x01,0xb3,0x1d,0x44,0x7c,0x32,0x71,0x92,0x03,0xe2,0x35,0x73,0x44,0x5f,0x26,0x59,0x36,0x3d,0x5e,0x71,0x00,0x01,0x00,0x7e,0x03,0xb7,0x01,0x44,0x05,0xb0,0x00,0x05,0x00,0x27,0x40,0x06,0x05,0x04,0x02,0x01,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x00,0x01,0x00,0x01,0x01,0x15,0x00,0x00,0x00,0x01, +0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x03,0x23,0x13,0x35,0x33,0x01,0x44,0x65,0x61,0x01,0xc5,0x04,0xd1,0xfe,0xe6,0x01,0x09,0xf0,0x00,0x01,0x00,0x84,0xfe,0x31,0x02,0x9d,0x06,0x64,0x00,0x11,0x00,0x2f,0x40,0x04,0x0e,0x0d,0x01,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x0c, +0x0c,0x05,0x02,0x00,0x13,0x00,0x00,0x00,0x0c,0x00,0x17,0x02,0x1b,0x40,0x0a,0x0c,0x05,0x02,0x00,0x13,0x00,0x00,0x00,0x22,0x02,0x59,0xb0,0x2f,0x2b,0x13,0x10,0x00,0x37,0x1f,0x01,0x06,0x02,0x11,0x15,0x10,0x12,0x17,0x07,0x23,0x26,0x00,0x11,0x84,0x01,0x3e,0xaf,0x06,0x26,0x89,0xcb,0xca,0x8a,0x26,0x06,0xaf,0xfe,0xc2,0x02,0x4f, +0x01,0x8a,0x02,0x2e,0x5d,0x01,0x74,0x6b,0xfe,0x28,0xfe,0xa5,0x0d,0xfe,0xa5,0xfe,0x28,0x74,0x6c,0x5d,0x02,0x2d,0x01,0x8b,0x00,0x01,0x00,0x06,0xfe,0x31,0x02,0x1f,0x06,0x64,0x00,0x11,0x00,0x3f,0x40,0x06,0x0e,0x0d,0x04,0x03,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x13,0x0c,0x05,0x02,0x00,0x01,0x01, +0x15,0x00,0x01,0x00,0x01,0x2b,0x00,0x00,0x00,0x0c,0x00,0x17,0x03,0x1b,0x40,0x11,0x0c,0x05,0x02,0x00,0x01,0x01,0x15,0x00,0x01,0x00,0x01,0x2b,0x00,0x00,0x00,0x22,0x03,0x59,0xb0,0x2f,0x2b,0x01,0x10,0x00,0x07,0x23,0x27,0x36,0x12,0x11,0x35,0x10,0x02,0x27,0x37,0x33,0x16,0x00,0x11,0x02,0x1f,0xfe,0xc1,0xae,0x06,0x26,0x87,0xcd, +0xd3,0x81,0x26,0x06,0xae,0x01,0x3f,0x02,0x46,0xfe,0x75,0xfd,0xd3,0x5d,0x6c,0x69,0x01,0xe1,0x01,0x5d,0x0d,0x01,0x56,0x01,0xe3,0x6e,0x6c,0x5d,0xfd,0xd2,0xfe,0x76,0x00,0x01,0x00,0x58,0x01,0x86,0x03,0x1b,0x04,0x39,0x00,0x0e,0x00,0x28,0x40,0x04,0x05,0x04,0x01,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x0e,0x0d,0x0c,0x0b, +0x0a,0x09,0x08,0x07,0x06,0x03,0x02,0x01,0x00,0x0d,0x00,0x12,0x00,0x00,0x00,0x0a,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x01,0x27,0x37,0x17,0x27,0x33,0x03,0x37,0x17,0x07,0x17,0x07,0x27,0x07,0x27,0x01,0x44,0xec,0x31,0xec,0x0a,0xa1,0x0a,0xe9,0x30,0xf2,0x99,0x84,0x8c,0x87,0x85,0x02,0xb8,0x43,0x9a,0x5a,0xfe,0xfe,0xfc,0x59,0x9c,0x44, +0xc8,0x60,0xda,0xd2,0x5c,0x00,0x00,0x00,0x00,0x01,0x00,0x4e,0x00,0x92,0x04,0x34,0x04,0xb6,0x00,0x0b,0x00,0x3e,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23,0x00,0x05,0x00,0x02,0x05,0x00,0x00,0x1a,0x04,0x01,0x00,0x03,0x01,0x01,0x02,0x00,0x01,0x00, +0x00,0x1d,0x00,0x05,0x05,0x02,0x00,0x00,0x1b,0x00,0x02,0x05,0x02,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x33,0x02,0xa5,0x01,0x8f,0xfe,0x71,0xc5,0xfe,0x6e,0x01,0x92,0xc5,0x03,0x0f,0xb2,0xfe,0x35,0x01,0xcb,0xb2,0x01,0xa7,0x00,0x00,0x00,0x01,0x00,0x30,0xfe,0xfe,0x01,0x3b, +0x00,0xdd,0x00,0x05,0x00,0x31,0x40,0x06,0x05,0x04,0x02,0x01,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x03,0x00,0x02,0x00,0x01,0x01,0x15,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b,0x25,0x03,0x23,0x13,0x35,0x33,0x01,0x3b,0x96, +0x75,0x46,0xc5,0x30,0xfe,0xce,0x01,0x3c,0xa3,0x00,0x00,0x00,0x00,0x01,0x00,0xa7,0x02,0x1a,0x02,0xf5,0x02,0xb4,0x00,0x03,0x00,0x2a,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x01,0x00,0x00,0x00,0x18, +0x03,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x02,0xf5,0xfd,0xb2,0x02,0x4e,0x02,0x1a,0x9a,0x00,0x00,0x00,0x00,0x01,0x00,0xa1,0x00,0x00,0x01,0x66,0x00,0xca,0x00,0x03,0x00,0x21,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0e,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x08,0x00,0x17,0x02, +0xb0,0x2f,0x2b,0x21,0x23,0x35,0x33,0x01,0x66,0xc5,0xc5,0xca,0x00,0x01,0x00,0x10,0xff,0x83,0x03,0x17,0x05,0xb0,0x00,0x03,0x00,0x1f,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0c,0x00,0x00,0x01,0x00,0x2c,0x00,0x01,0x01,0x07,0x01,0x17,0x02,0xb0,0x2f,0x2b,0x17,0x23,0x01,0x33,0xb8,0xa8,0x02, +0x60,0xa7,0x7d,0x06,0x2d,0x00,0x00,0x00,0x00,0x02,0x00,0x71,0xff,0xeb,0x04,0x10,0x05,0xc5,0x00,0x0d,0x00,0x1b,0x00,0x31,0x40,0x0a,0x19,0x17,0x12,0x10,0x0b,0x09,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00, +0x00,0x00,0x0e,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x14,0x02,0x23,0x22,0x02,0x35,0x11,0x34,0x12,0x33,0x32,0x12,0x15,0x27,0x34,0x26,0x23,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x04,0x10,0xfb,0xd4,0xd3,0xfd,0xfb,0xd3,0xd4,0xfd,0xc5,0x8c,0x80,0x7f,0x8a,0x8d,0x7e,0x80,0x8a,0x02,0x02,0xf7,0xfe,0xe0,0x01,0x20,0xf7, +0x01,0xac,0xf5,0x01,0x22,0xfe,0xde,0xf5,0x29,0x9d,0xb6,0xb6,0x9d,0xfe,0x03,0x9d,0xb8,0xb7,0x9e,0x00,0x00,0x01,0x00,0xc3,0x00,0x00,0x02,0xc6,0x05,0xc5,0x00,0x05,0x00,0x24,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x11,0x05,0x04,0x02,0x01,0x13,0x00,0x01,0x00,0x01,0x2b,0x00,0x00,0x00,0x08, +0x00,0x17,0x03,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x05,0x35,0x25,0x02,0xc6,0xc6,0xfe,0xc3,0x02,0x03,0x04,0xfa,0x03,0x98,0x36,0x00,0x01,0x00,0x85,0x00,0x00,0x04,0x1e,0x05,0xc5,0x00,0x1a,0x00,0x45,0x40,0x0c,0x1a,0x19,0x12,0x10,0x0d,0x0c,0x0a,0x08,0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2c,0x0e,0x01,0x02,0x01, +0x02,0x01,0x00,0x04,0x02,0x15,0x00,0x02,0x01,0x04,0x01,0x02,0x04,0x29,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x16,0x00,0x04,0x04,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x08,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x29,0x01,0x35,0x01,0x3e,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15, +0x14,0x06,0x07,0x01,0x17,0x21,0x04,0x1e,0xfc,0x78,0x01,0xc9,0x7a,0x57,0x76,0x68,0x81,0x87,0xbe,0x02,0x05,0xf8,0xd5,0xc3,0xe0,0x7f,0x82,0xfe,0x91,0x02,0x02,0x97,0x87,0x02,0x21,0x94,0xaf,0x59,0x65,0x81,0x9e,0x76,0x06,0xb2,0xf7,0xd8,0xab,0x73,0xdc,0xa6,0xfe,0x52,0x05,0x00,0x00,0x00,0x00,0x01,0x00,0x73,0xff,0xeb,0x04,0x0f, +0x05,0xc5,0x00,0x2a,0x00,0x66,0x40,0x16,0x01,0x00,0x29,0x27,0x23,0x21,0x1f,0x1e,0x1b,0x19,0x0f,0x0d,0x0a,0x09,0x07,0x05,0x00,0x2a,0x01,0x2a,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x43,0x0b,0x01,0x02,0x01,0x14,0x01,0x07,0x00,0x1d,0x01,0x06,0x05,0x03,0x15,0x00,0x02,0x01,0x00,0x01,0x02,0x00,0x29,0x00,0x05,0x07,0x06, +0x07,0x05,0x06,0x29,0x08,0x01,0x00,0x00,0x07,0x05,0x00,0x07,0x01,0x00,0x1d,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x16,0x00,0x06,0x06,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x0e,0x04,0x17,0x08,0xb0,0x2f,0x2b,0x01,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x24,0x33,0x32,0x16,0x15,0x14,0x06, +0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x24,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x02,0x43,0x84,0x6d,0x77,0x75,0x72,0x95,0xbc,0x03,0x05,0x01,0x02,0xc9,0xcb,0xe6,0x6b,0x60,0x6e,0x73,0xfd,0xca,0xba,0xfe,0xe5,0x05,0x02,0xbc,0x99,0x79,0x78,0x8a,0x7f,0x88,0xa2,0x03,0x3c,0x83,0x76,0x6e,0x87, +0x8d,0x6a,0x06,0xa4,0xe8,0xcd,0xc7,0x66,0xa8,0x2f,0x2c,0xb3,0x7f,0xc8,0xe3,0xdb,0xb4,0x06,0x6a,0x91,0x95,0x78,0x89,0x88,0x99,0x00,0x00,0x00,0x00,0x02,0x00,0x48,0x00,0x00,0x04,0x46,0x05,0xb0,0x00,0x0a,0x00,0x0f,0x00,0x3d,0x40,0x0e,0x0c,0x0b,0x0a,0x09,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x22,0x0d,0x01,0x00,0x04,0x08,0x01,0x01,0x00,0x02,0x15,0x05,0x01,0x00,0x03,0x01,0x01,0x02,0x00,0x01,0x00,0x00,0x1d,0x00,0x04,0x04,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x33,0x15,0x23,0x11,0x23,0x11,0x21,0x35,0x01,0x33,0x01,0x21,0x11,0x27,0x07,0x03,0x7d,0xc9,0xc9,0xc4,0xfd,0x8f, +0x02,0x65,0xd0,0xfd,0x9e,0x01,0x9e,0x06,0x13,0x01,0xea,0x9a,0xfe,0xb0,0x01,0x50,0x6f,0x03,0xf1,0xfc,0x3a,0x02,0xab,0x01,0x32,0x00,0x00,0x00,0x00,0x01,0x00,0x98,0xff,0xeb,0x04,0x13,0x05,0xb0,0x00,0x1f,0x00,0x58,0x40,0x10,0x1d,0x1b,0x17,0x15,0x13,0x12,0x0f,0x0d,0x09,0x07,0x04,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x3b,0x05,0x01,0x06,0x02,0x1f,0x00,0x02,0x04,0x06,0x11,0x01,0x05,0x04,0x03,0x15,0x00,0x04,0x06,0x05,0x06,0x04,0x05,0x29,0x00,0x02,0x00,0x06,0x04,0x02,0x06,0x01,0x00,0x1d,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x07,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x07,0xb0, +0x2f,0x2b,0x1b,0x01,0x21,0x15,0x21,0x03,0x3e,0x01,0x37,0x36,0x12,0x15,0x14,0x02,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0xaf,0x54,0x02,0xd9,0xfd,0xcd,0x2f,0x2f,0x72,0x49,0xca,0xe5,0xeb,0xe1,0xb9,0xf6,0x05,0x02,0xb2,0x89,0x6d,0x7d,0x8a,0x8b,0x7c,0x74,0x68,0x19,0x02,0x87, +0x03,0x29,0xaf,0xfe,0x5d,0x23,0x2d,0x01,0x02,0xfe,0xff,0xe0,0xdb,0xfe,0xf6,0xca,0xc4,0x06,0x77,0x83,0xb0,0x99,0x8b,0xac,0x46,0x49,0x00,0x00,0x00,0x02,0x00,0x89,0xff,0xeb,0x04,0x28,0x05,0xc5,0x00,0x1a,0x00,0x27,0x00,0x5b,0x40,0x16,0x1c,0x1b,0x01,0x00,0x23,0x21,0x1b,0x27,0x1c,0x27,0x15,0x13,0x0f,0x0d,0x08,0x06,0x00,0x1a, +0x01,0x1a,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x38,0x03,0x01,0x01,0x00,0x04,0x01,0x02,0x01,0x0b,0x01,0x04,0x02,0x1e,0x01,0x05,0x04,0x04,0x15,0x00,0x02,0x07,0x01,0x04,0x05,0x02,0x04,0x01,0x00,0x1d,0x00,0x01,0x01,0x00,0x01,0x00,0x1b,0x06,0x01,0x00,0x00,0x0d,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03, +0x0e,0x03,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x3e,0x01,0x33,0x32,0x16,0x15,0x14,0x02,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x13,0x22,0x06,0x07,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x02,0x81,0x56,0xa8,0x37,0x2a,0x39,0x7e,0x54,0x89,0xab,0x3d,0xa7,0x60,0xbc,0xdb,0xf5, +0xd0,0xca,0xfe,0xf0,0x01,0x23,0xa6,0x5d,0x85,0x23,0xa1,0x75,0x7b,0x85,0x8f,0x05,0xc5,0x22,0x1a,0x97,0x19,0x1f,0xea,0xb3,0x71,0x3d,0x46,0xfc,0xcd,0xe0,0xfe,0xf5,0x01,0x33,0x01,0x0a,0x01,0x4f,0x01,0x00,0x01,0x4e,0xfd,0x47,0x4f,0x43,0x65,0xb9,0xd7,0xbb,0x96,0x8e,0xa8,0x00,0x00,0x00,0x00,0x01,0x00,0x61,0x00,0x00,0x04,0x27, +0x05,0xb0,0x00,0x0c,0x00,0x2d,0x40,0x08,0x0c,0x0b,0x0a,0x09,0x05,0x04,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x18,0x00,0x01,0x01,0x01,0x14,0x00,0x01,0x01,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x00,0x02,0x11,0x15,0x23,0x35,0x10,0x12,0x13,0x21,0x35,0x21, +0x04,0x27,0xfe,0xec,0xc2,0xc5,0xf3,0xe6,0xfc,0xfc,0x03,0xc6,0x05,0x15,0xfe,0xb8,0xfe,0x0a,0xfe,0xc8,0x9f,0x9f,0x01,0x4a,0x02,0x11,0x01,0x1b,0x9b,0x00,0x00,0x00,0x00,0x03,0x00,0x66,0xff,0xeb,0x04,0x1a,0x05,0xc5,0x00,0x17,0x00,0x23,0x00,0x2f,0x00,0x46,0x40,0x0e,0x2e,0x2c,0x28,0x26,0x22,0x20,0x1c,0x1a,0x16,0x14,0x0a,0x08, +0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2b,0x0f,0x03,0x02,0x02,0x05,0x01,0x15,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x01,0x00,0x1d,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x14,0x06,0x07,0x1e,0x01,0x15,0x14, +0x04,0x23,0x22,0x24,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x36,0x33,0x32,0x16,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x03,0xf2,0x80,0x6a,0x7c,0x96,0xfe,0xfb,0xca,0xd6,0xfe,0xf1,0x99,0x82,0x70,0x82,0xf5,0xc5,0xba,0xef,0x9c,0x9b,0x72,0x7c, +0xa2,0xa1,0x7f,0x72,0x99,0x29,0x83,0x61,0x6b,0x8a,0x8c,0x6b,0x61,0x81,0x04,0x3c,0x72,0xad,0x2b,0x2b,0xbc,0x7b,0xc9,0xdc,0xdc,0xc9,0x7b,0xbc,0x2c,0x2a,0xad,0x72,0xbf,0xca,0xcb,0xfc,0x9a,0x77,0x9a,0x9a,0x77,0x7b,0x94,0x95,0x03,0x1f,0x69,0x88,0x83,0x6e,0x6f,0x8a,0x8a,0x00,0x00,0x00,0x00,0x02,0x00,0x5d,0xff,0xeb,0x03,0xf8, +0x05,0xc5,0x00,0x1a,0x00,0x27,0x00,0x5b,0x40,0x16,0x1c,0x1b,0x01,0x00,0x23,0x21,0x1b,0x27,0x1c,0x27,0x15,0x13,0x0e,0x0c,0x08,0x06,0x00,0x1a,0x01,0x1a,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x38,0x1e,0x01,0x04,0x05,0x04,0x01,0x01,0x04,0x18,0x01,0x00,0x01,0x17,0x01,0x03,0x00,0x04,0x15,0x07,0x01,0x04,0x00,0x01,0x00, +0x04,0x01,0x01,0x00,0x1d,0x00,0x05,0x05,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x06,0x01,0x00,0x00,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x06,0xb0,0x2f,0x2b,0x25,0x32,0x36,0x3d,0x01,0x0e,0x01,0x23,0x22,0x02,0x35,0x34,0x12,0x33,0x32,0x00,0x15,0x11,0x14,0x00,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x13,0x32, +0x36,0x37,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x01,0xf5,0x8e,0xaf,0x30,0x8f,0x55,0xd2,0xef,0xfe,0xbb,0xda,0x01,0x08,0xfe,0xe0,0xe3,0x4d,0xa1,0x46,0x1e,0x42,0x7f,0x7e,0x67,0x8d,0x20,0x92,0x84,0x6b,0x8f,0x84,0x85,0xc4,0xb4,0x7c,0x47,0x49,0x01,0x03,0xe6,0xdc,0x01,0x17,0xfe,0xee,0xfa,0xfe,0x46,0xfb,0xfe,0xe7,0x20, +0x1f,0x96,0x20,0x1b,0x01,0xfe,0x5e,0x49,0xac,0xa3,0xb1,0xbf,0x99,0x96,0xb9,0x00,0xff,0xff,0x00,0xa1,0x00,0x00,0x01,0x66,0x04,0x36,0x00,0x26,0x00,0x11,0x00,0x00,0x01,0x07,0x00,0x11,0x00,0x00,0x03,0x6c,0x00,0x09,0xb1,0x01,0x01,0xb8,0x03,0x6c,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x63,0xfe,0xfe,0x01,0x6e,0x04,0x36,0x00,0x27, +0x00,0x11,0x00,0x01,0x03,0x6c,0x01,0x06,0x00,0x0f,0x33,0x00,0x00,0x09,0xb1,0x00,0x01,0xb8,0x03,0x6c,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x47,0x00,0x6b,0x03,0x77,0x03,0xf5,0x00,0x09,0x00,0x07,0x40,0x02,0x00,0x07,0x2b,0x00,0x00,0x01,0x07,0x15,0x17,0x05,0x15,0x01,0x35,0x01,0x15,0x01,0x48,0x55,0x55,0x02,0x2f,0xfc,0xd0,0x03, +0x30,0x02,0x43,0x12,0x06,0x13,0xe4,0xc9,0x01,0x7b,0x95,0x01,0x7a,0xc9,0x00,0x00,0x00,0x02,0x00,0x98,0x01,0x97,0x03,0xda,0x03,0xdb,0x00,0x03,0x00,0x07,0x00,0x38,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x00,0x00,0x1d,0x00,0x03, +0x02,0x02,0x03,0x00,0x00,0x1a,0x00,0x03,0x03,0x02,0x00,0x00,0x1b,0x00,0x02,0x03,0x02,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x11,0x21,0x35,0x21,0x03,0xda,0xfc,0xbe,0x03,0x42,0xfc,0xbe,0x03,0x42,0x03,0x37,0xa4,0xfd,0xbc,0xa4,0x00,0x01,0x00,0x88,0x00,0x57,0x03,0xe0,0x03,0xe1,0x00,0x09,0x00,0x07,0x40,0x02, +0x00,0x07,0x2b,0x00,0x00,0x13,0x35,0x01,0x15,0x01,0x35,0x25,0x37,0x35,0x27,0x88,0x03,0x58,0xfc,0xa8,0x02,0x56,0x55,0x55,0x03,0x1e,0xc3,0xfe,0x86,0x95,0xfe,0x85,0xc4,0xee,0x11,0x06,0x14,0x00,0x00,0x00,0x00,0x02,0x00,0x3a,0x00,0x00,0x03,0x76,0x05,0xc5,0x00,0x1a,0x00,0x1e,0x00,0x4f,0x40,0x12,0x00,0x00,0x1e,0x1d,0x1c,0x1b, +0x00,0x1a,0x00,0x1a,0x12,0x10,0x0d,0x0c,0x0a,0x08,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x30,0x0e,0x01,0x01,0x00,0x01,0x15,0x00,0x01,0x00,0x03,0x00,0x01,0x03,0x29,0x06,0x01,0x03,0x05,0x00,0x03,0x05,0x27,0x00,0x00,0x00,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x00,0x05,0x05,0x04,0x00,0x00,0x1b,0x00,0x04,0x04, +0x08,0x04,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x3e,0x01,0x37,0x3e,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x07,0x0e,0x01,0x15,0x13,0x23,0x35,0x33,0x01,0x63,0x01,0x30,0x66,0x63,0x54,0x71,0x69,0x5b,0x80,0xbc,0x03,0x03,0xe9,0xb4,0xc5,0xda,0x8d,0x74,0x36,0x17,0x07,0xce,0xce,0x01, +0x9a,0x91,0x70,0x5c,0x75,0x7e,0x59,0x6a,0x72,0x63,0x60,0x06,0xa1,0xc2,0xc9,0xb4,0x81,0xd6,0x70,0x36,0x56,0x5b,0xfe,0x66,0xd0,0x00,0x00,0x00,0x00,0x02,0x00,0x60,0xfe,0x3b,0x06,0xd5,0x05,0x97,0x00,0x33,0x00,0x43,0x01,0x32,0x40,0x18,0x42,0x40,0x38,0x36,0x32,0x30,0x2c,0x2a,0x25,0x23,0x1f,0x1d,0x19,0x17,0x14,0x13,0x10,0x0e, +0x0a,0x08,0x04,0x02,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x14,0x58,0x40,0x4d,0x12,0x01,0x03,0x02,0x3e,0x06,0x02,0x04,0x0a,0x27,0x01,0x06,0x00,0x28,0x01,0x07,0x06,0x04,0x15,0x00,0x03,0x02,0x0a,0x02,0x03,0x0a,0x29,0x00,0x02,0x00,0x0a,0x04,0x02,0x0a,0x01,0x00,0x1d,0x00,0x05,0x05,0x08,0x01,0x00,0x1b,0x00,0x08, +0x08,0x07,0x16,0x09,0x01,0x04,0x04,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x0e,0x16,0x00,0x06,0x06,0x07,0x01,0x00,0x1b,0x00,0x07,0x07,0x12,0x07,0x17,0x09,0x1b,0x4b,0xb0,0x28,0x58,0x40,0x59,0x12,0x01,0x03,0x02,0x3e,0x06,0x02,0x09,0x0a,0x27,0x01,0x06,0x00,0x28,0x01,0x07,0x06,0x04,0x15,0x00,0x03,0x02,0x0a,0x02,0x03,0x0a, +0x29,0x00,0x02,0x00,0x0a,0x09,0x02,0x0a,0x01,0x00,0x1d,0x00,0x05,0x05,0x08,0x01,0x00,0x1b,0x00,0x08,0x08,0x07,0x16,0x00,0x09,0x09,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x0e,0x16,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x0e,0x16,0x00,0x06,0x06,0x07,0x01,0x00,0x1b,0x00,0x07,0x07,0x12,0x07,0x17,0x0b,0x1b, +0x40,0x57,0x12,0x01,0x03,0x02,0x3e,0x06,0x02,0x09,0x0a,0x27,0x01,0x06,0x00,0x28,0x01,0x07,0x06,0x04,0x15,0x00,0x03,0x02,0x0a,0x02,0x03,0x0a,0x29,0x00,0x08,0x00,0x05,0x02,0x08,0x05,0x01,0x00,0x1d,0x00,0x02,0x00,0x0a,0x09,0x02,0x0a,0x01,0x00,0x1d,0x00,0x09,0x09,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x0e,0x16,0x00,0x04, +0x04,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x0e,0x16,0x00,0x06,0x06,0x07,0x01,0x00,0x1b,0x00,0x07,0x07,0x12,0x07,0x17,0x0a,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x06,0x02,0x23,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x26,0x37,0x1a,0x01,0x33,0x32,0x16,0x17,0x07,0x33,0x03,0x06,0x16,0x33,0x32,0x36,0x37,0x12,0x00,0x21,0x20,0x00,0x03, +0x02,0x00,0x21,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x20,0x00,0x13,0x12,0x00,0x21,0x20,0x00,0x01,0x06,0x16,0x33,0x32,0x36,0x37,0x26,0x36,0x37,0x13,0x2e,0x01,0x23,0x22,0x06,0x06,0xc4,0x09,0xde,0xdd,0x49,0x6a,0x17,0x32,0x90,0x60,0x7d,0x8a,0x12,0x17,0xe5,0xa5,0x69,0x80,0x4b,0x04,0x06,0x33,0x09,0x3d,0x33,0x7b,0x94,0x08,0x10, +0xfe,0xc0,0xfe,0xb0,0xfe,0xcc,0xfe,0x89,0x0f,0x12,0x01,0x50,0x01,0x3a,0x58,0xb5,0x3e,0x26,0x43,0xcf,0x63,0xfe,0x84,0xfe,0x61,0x12,0x13,0x01,0xcc,0x01,0x74,0x01,0x7b,0x01,0x95,0xfb,0xfb,0x0b,0x41,0x4a,0x40,0x6a,0x2c,0x01,0x01,0x02,0x2f,0x1a,0x39,0x1f,0x7d,0x84,0x01,0xf6,0xd6,0xfe,0xcb,0x53,0x4c,0x50,0x4f,0xf1,0xc4,0x01, +0x03,0x01,0x39,0x34,0x36,0x04,0xfd,0xb7,0x6e,0x53,0xe3,0xaf,0x01,0x7e,0x01,0xab,0xfe,0x32,0xfe,0x8d,0xfe,0x88,0xfe,0x4b,0x2b,0x23,0x6b,0x2a,0x2f,0x01,0xf3,0x01,0xb0,0x01,0xa7,0x02,0x12,0xfe,0x0c,0xfd,0xfd,0x8e,0x94,0x31,0x3f,0x0c,0x1b,0x10,0x02,0x1a,0x0c,0x0e,0xdb,0x00,0x00,0x00,0x00,0x02,0x00,0x2b,0x00,0x00,0x04,0xe3, +0x05,0xb0,0x00,0x07,0x00,0x0b,0x00,0x3a,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x00,0x05,0x02,0x04,0x02,0x05,0x04,0x29,0x00,0x04,0x00,0x00,0x01,0x04,0x00,0x00,0x02,0x1d,0x00,0x02,0x02,0x07,0x16,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0, +0x2f,0x2b,0x01,0x21,0x03,0x23,0x01,0x33,0x01,0x23,0x01,0x21,0x03,0x23,0x03,0x9a,0xfd,0xdc,0x82,0xc9,0x02,0x0d,0xa9,0x02,0x02,0xc9,0xfd,0x95,0x01,0xb3,0xd4,0x06,0x01,0x77,0xfe,0x89,0x05,0xb0,0xfa,0x50,0x02,0x1c,0x02,0x71,0x00,0x03,0x00,0xaa,0x00,0x00,0x04,0xcd,0x05,0xb0,0x00,0x0e,0x00,0x18,0x00,0x21,0x00,0x4f,0x40,0x16, +0x0f,0x0f,0x00,0x00,0x21,0x1f,0x1b,0x19,0x0f,0x18,0x0f,0x16,0x12,0x10,0x00,0x0e,0x00,0x0d,0x03,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2c,0x08,0x01,0x03,0x04,0x01,0x15,0x00,0x04,0x07,0x01,0x03,0x02,0x04,0x03,0x01,0x00,0x1d,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x07,0x16,0x00,0x02,0x02,0x01,0x01, +0x00,0x1b,0x06,0x01,0x01,0x01,0x08,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x33,0x11,0x21,0x32,0x04,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x04,0x23,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x27,0x23,0x25,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0xaa,0x01,0xdb,0xe4,0x01,0x02,0x74,0x60,0x8f,0xa7,0xfe,0xfc,0xde,0xfe,0x84,0x01,0x7c, +0x87,0x95,0x98,0x81,0x0d,0xfe,0x8e,0x01,0x3f,0x6e,0x8a,0x95,0x8c,0xfe,0xea,0x05,0xb0,0xc5,0xc5,0x5e,0x95,0x27,0x14,0xd0,0x8d,0xc8,0xd3,0x02,0xab,0xfd,0xef,0x85,0x7a,0x79,0x94,0x05,0x9a,0x79,0x6c,0x76,0x75,0x00,0x00,0x00,0x00,0x01,0x00,0x76,0xff,0xeb,0x04,0xbf,0x05,0xc5,0x00,0x1d,0x00,0x53,0x40,0x12,0x00,0x00,0x00,0x1d, +0x00,0x1d,0x1b,0x19,0x14,0x12,0x10,0x0f,0x0c,0x0a,0x05,0x03,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x34,0x0e,0x01,0x02,0x03,0x01,0x01,0x04,0x05,0x02,0x15,0x00,0x02,0x03,0x05,0x03,0x02,0x05,0x29,0x06,0x01,0x05,0x04,0x03,0x05,0x04,0x27,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x04,0x04,0x00, +0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x17,0x16,0x00,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x00,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32,0x36,0x35,0x04,0xb9,0x02,0x04,0xfe,0xd8,0xf3,0xf7,0xfe,0xc9,0x01,0x37,0xf7,0xf7,0x01,0x24,0x04,0x02,0xbd,0xb4,0xa4, +0xa5,0xc4,0xc4,0xa5,0xa4,0xb4,0x01,0xd2,0x06,0xcd,0xfe,0xec,0x01,0x5e,0x01,0x0d,0x01,0x03,0x01,0x0d,0x01,0x5f,0xfe,0xf9,0xd9,0x06,0x99,0xb2,0xfe,0xf6,0xc5,0xfe,0xfb,0xc7,0xfe,0xf6,0xb1,0x9c,0x00,0x00,0x00,0x02,0x00,0xaa,0x00,0x00,0x04,0xec,0x05,0xb0,0x00,0x09,0x00,0x13,0x00,0x3b,0x40,0x12,0x0a,0x0a,0x00,0x00,0x0a,0x13, +0x0a,0x12,0x0d,0x0b,0x00,0x09,0x00,0x08,0x03,0x01,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1c,0x05,0x01,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x07,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x04,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x33,0x11,0x21,0x20,0x00,0x11,0x15,0x10,0x00,0x21,0x01,0x11,0x21, +0x32,0x12,0x3d,0x01,0x34,0x02,0x23,0xaa,0x01,0xca,0x01,0x1d,0x01,0x5b,0xfe,0xa5,0xfe,0xe3,0xfe,0xfb,0x01,0x05,0xca,0xe9,0xe9,0xca,0x05,0xb0,0xfe,0xa1,0xfe,0xea,0xc7,0xfe,0xe9,0xfe,0xa3,0x05,0x15,0xfb,0x85,0x01,0x0a,0xd0,0xc9,0xce,0x01,0x0a,0x00,0x01,0x00,0xaa,0x00,0x00,0x04,0x2b,0x05,0xb0,0x00,0x0b,0x00,0x3f,0x40,0x0e, +0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x00,0x05,0x00,0x00,0x01,0x05,0x00,0x00,0x00,0x1d,0x00,0x04,0x04,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x01,0x01,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x11, +0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x03,0xc5,0xfd,0xaa,0x02,0xbc,0xfc,0x7f,0x03,0x76,0xfd,0x4f,0x02,0x56,0x02,0xa3,0xfd,0xf7,0x9a,0x05,0xb0,0x9b,0xfe,0x29,0x00,0x00,0x00,0x00,0x01,0x00,0xaa,0x00,0x00,0x04,0x3b,0x05,0xb0,0x00,0x09,0x00,0x36,0x40,0x0c,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x05,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1d,0x00,0x04,0x00,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x03,0x03,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x15,0x21,0x11,0x21,0x03,0xd5,0xfd,0x9a,0xc5,0x03,0x91,0xfd,0x34,0x02,0x66,0x02,0x84,0xfd, +0x7c,0x05,0xb0,0x9b,0xfe,0x0a,0x00,0x00,0x00,0x01,0x00,0x79,0xff,0xeb,0x04,0xc1,0x05,0xc5,0x00,0x20,0x00,0x54,0x40,0x10,0x20,0x1f,0x1e,0x1d,0x1a,0x18,0x13,0x11,0x0f,0x0e,0x0b,0x09,0x04,0x02,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x37,0x0d,0x01,0x02,0x03,0x1c,0x00,0x02,0x04,0x05,0x02,0x15,0x00,0x02,0x03,0x06,0x03, +0x02,0x06,0x29,0x00,0x06,0x00,0x05,0x04,0x06,0x05,0x00,0x00,0x1d,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x07,0xb0,0x2f,0x2b,0x25,0x06,0x04,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x00,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15, +0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x21,0x35,0x21,0x04,0xc1,0x34,0xfe,0xff,0xcd,0xfc,0xfe,0xb6,0x01,0x3e,0xfb,0xf3,0x01,0x1a,0x04,0x02,0xbd,0xac,0x9e,0xa7,0xcc,0xd8,0xa8,0x81,0x97,0x25,0xfe,0xb6,0x02,0x0f,0xc4,0x51,0x88,0x01,0x4e,0x01,0x09,0x01,0x2c,0x01,0x09,0x01,0x4e,0xfe,0xfd,0xc8,0x06,0x85,0xb1,0xfa,0xc0,0xfe, +0xd2,0xc2,0xfb,0x43,0x2e,0x01,0x48,0x9a,0x00,0x01,0x00,0xaa,0x00,0x00,0x04,0xf7,0x05,0xb0,0x00,0x0b,0x00,0x33,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x18,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x00,0x00,0x1d,0x05,0x01,0x03,0x03,0x07,0x16,0x02,0x01, +0x00,0x00,0x08,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x33,0x04,0xf7,0xc5,0xfd,0x3d,0xc5,0xc5,0x02,0xc3,0xc5,0x02,0x83,0xfd,0x7d,0x05,0xb0,0xfd,0x6e,0x02,0x92,0x00,0x00,0x00,0x00,0x01,0x00,0xbe,0x00,0x00,0x01,0x84,0x05,0xb0,0x00,0x03,0x00,0x1f,0x40,0x06,0x03,0x02,0x01,0x00, +0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0c,0x00,0x01,0x01,0x07,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x33,0x01,0x84,0xc6,0xc6,0x05,0xb0,0x00,0x00,0x01,0x00,0x4a,0xff,0xeb,0x03,0xbc,0x05,0xb0,0x00,0x10,0x00,0x38,0x40,0x0a,0x0e,0x0c,0x0a,0x09,0x06,0x04,0x01,0x00,0x04,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x21,0x08,0x01,0x03,0x02,0x01,0x15,0x00,0x02,0x00,0x03,0x00,0x02,0x03,0x29,0x00,0x00,0x00,0x07,0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x33,0x11,0x14,0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x02,0xf7,0xc5,0xf7,0xc5, +0xc9,0xed,0x05,0x02,0xbd,0x7e,0x74,0x6d,0x8a,0x05,0xb0,0xfb,0xf6,0xcb,0xf0,0xd5,0xcb,0x06,0x88,0x84,0x9e,0x83,0x00,0x00,0x00,0x01,0x00,0xaa,0x00,0x00,0x05,0x01,0x05,0xb0,0x00,0x0e,0x00,0x39,0x40,0x0e,0x0e,0x0d,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x0b,0x01, +0x00,0x03,0x01,0x15,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x04,0x01,0x02,0x02,0x07,0x16,0x05,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x01,0x33,0x17,0x09,0x01,0x07,0x23,0x01,0xef,0x80,0xc5,0xc5,0x6c,0x02,0x1c,0xde,0x02,0xfd,0xb2,0x02,0x78,0x02,0xef,0x02,0x92, +0xfd,0x6e,0x05,0xb0,0xfd,0x7c,0x02,0x84,0x05,0xfd,0x4f,0xfd,0x0b,0x05,0x00,0x00,0x00,0x01,0x00,0xaa,0x00,0x00,0x04,0x35,0x05,0xb0,0x00,0x05,0x00,0x28,0x40,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x13,0x00,0x02,0x02,0x07,0x16,0x00,0x00,0x00,0x01,0x00,0x02,0x1b,0x00,0x01,0x01,0x08, +0x01,0x17,0x03,0xb0,0x2f,0x2b,0x25,0x21,0x15,0x21,0x11,0x33,0x01,0x6f,0x02,0xc6,0xfc,0x75,0xc5,0x9a,0x9a,0x05,0xb0,0x00,0x00,0x01,0x00,0xaa,0x00,0x00,0x06,0x48,0x05,0xb0,0x00,0x0f,0x00,0x39,0x40,0x0e,0x0f,0x0e,0x0d,0x0c,0x09,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x0b,0x06, +0x02,0x00,0x01,0x01,0x15,0x00,0x00,0x01,0x02,0x01,0x00,0x02,0x29,0x05,0x01,0x01,0x01,0x07,0x16,0x04,0x03,0x02,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x33,0x01,0x33,0x11,0x23,0x11,0x27,0x01,0x23,0x01,0x07,0x11,0x23,0x11,0x21,0x03,0x7c,0x06,0x01,0xd1,0xf5,0xc5,0x06,0xfe,0x47,0x89,0xfe,0x3a,0x06,0xc5,0x01,0x03, +0x01,0x11,0x04,0x9f,0xfa,0x50,0x04,0x43,0x01,0xfb,0xbc,0x04,0x68,0x01,0xfb,0x99,0x05,0xb0,0x00,0x00,0x00,0x01,0x00,0xaa,0x00,0x00,0x04,0xf7,0x05,0xb0,0x00,0x0b,0x00,0x2c,0x40,0x0a,0x0b,0x0a,0x07,0x06,0x05,0x04,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x09,0x03,0x02,0x00,0x02,0x01,0x15,0x03,0x01,0x02, +0x02,0x07,0x16,0x01,0x01,0x00,0x00,0x08,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x21,0x23,0x01,0x07,0x11,0x23,0x11,0x33,0x01,0x37,0x11,0x33,0x04,0xf7,0xc5,0xfd,0x43,0x06,0xc5,0xc5,0x02,0xbd,0x06,0xc5,0x04,0x58,0x02,0xfb,0xaa,0x05,0xb0,0xfb,0xa9,0x02,0x04,0x55,0x00,0x00,0x00,0x02,0x00,0x71,0xff,0xeb,0x05,0x02,0x05,0xc5,0x00,0x0d, +0x00,0x1b,0x00,0x31,0x40,0x0a,0x19,0x17,0x12,0x10,0x0b,0x09,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x10,0x00,0x21,0x22,0x00,0x19,0x01,0x10,0x00,0x33, +0x20,0x00,0x11,0x27,0x34,0x02,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32,0x36,0x35,0x05,0x02,0xfe,0xb5,0xfe,0xf8,0xff,0xfe,0xc1,0x01,0x3f,0xff,0x01,0x08,0x01,0x4b,0xc5,0xd8,0xb6,0xac,0xcd,0xcd,0xac,0xb7,0xd7,0x02,0x56,0xfe,0xf5,0xfe,0xa0,0x01,0x60,0x01,0x0b,0x01,0x03,0x01,0x0a,0x01,0x62,0xfe,0x9f,0xfe,0xf5,0x02,0xc8, +0x01,0x00,0xff,0x00,0xc8,0xfe,0xfb,0xca,0xff,0x00,0xff,0xcb,0x00,0x02,0x00,0xaa,0x00,0x00,0x04,0xc3,0x05,0xb0,0x00,0x0a,0x00,0x13,0x00,0x3b,0x40,0x10,0x00,0x00,0x13,0x11,0x0d,0x0b,0x00,0x0a,0x00,0x09,0x05,0x03,0x02,0x01,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x00,0x03,0x05,0x01,0x02,0x00,0x03,0x02,0x01,0x00, +0x1d,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x23,0x11,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x25,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x01,0x6f,0xc5,0x02,0x2d,0xe9,0x01,0x03,0xfe,0xfd,0xe9,0xfe,0x98,0x01,0x68,0x94,0x92,0x93,0x93,0xfe,0x98, +0x02,0x48,0xfd,0xb8,0x05,0xb0,0xf0,0xc4,0xc6,0xee,0x9a,0x9f,0x79,0x79,0xa2,0x00,0x00,0x02,0x00,0x71,0xff,0x71,0x05,0x5a,0x05,0xc5,0x00,0x13,0x00,0x21,0x00,0x40,0x40,0x0a,0x1f,0x1d,0x18,0x16,0x11,0x0f,0x0a,0x08,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x29,0x03,0x01,0x03,0x02,0x06,0x04,0x02,0x00,0x03,0x02,0x15,0x05, +0x01,0x00,0x12,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x14,0x06,0x07,0x17,0x07,0x27,0x0e,0x01,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x20,0x00,0x11,0x27,0x34,0x02,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32, +0x36,0x35,0x05,0x02,0x43,0x3e,0xd9,0x87,0xde,0x46,0xa4,0x5c,0xff,0xfe,0xc1,0x01,0x3f,0xff,0x01,0x08,0x01,0x4b,0xc5,0xd8,0xb6,0xac,0xcd,0xcd,0xac,0xb7,0xd7,0x02,0x56,0x73,0xcd,0x51,0xd3,0x81,0xd5,0x2d,0x2e,0x01,0x60,0x01,0x0b,0x01,0x03,0x01,0x0a,0x01,0x62,0xfe,0x9f,0xfe,0xf5,0x02,0xc8,0x01,0x00,0xff,0x00,0xc8,0xfe,0xfb, +0xca,0xff,0x00,0xff,0xcb,0x00,0x00,0x00,0x00,0x02,0x00,0xaa,0x00,0x00,0x04,0xc6,0x05,0xaf,0x00,0x1a,0x00,0x23,0x00,0x48,0x40,0x12,0x00,0x00,0x23,0x21,0x1d,0x1b,0x00,0x1a,0x00,0x19,0x13,0x12,0x05,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x29,0x0a,0x01,0x03,0x04,0x11,0x01,0x00,0x03,0x02,0x15,0x00,0x04, +0x06,0x01,0x03,0x00,0x04,0x03,0x01,0x00,0x1d,0x00,0x05,0x05,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x11,0x23,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x14,0x16,0x17,0x15,0x23,0x2e,0x01,0x3d,0x01,0x34,0x26,0x23,0x25,0x21,0x32,0x36,0x35, +0x34,0x26,0x23,0x21,0x01,0x6f,0xc5,0x01,0xf2,0xef,0xfc,0x75,0x70,0x78,0x69,0x1e,0x25,0xcb,0x27,0x16,0x8a,0x74,0xfe,0xaf,0x01,0x19,0xa7,0x93,0x8f,0x97,0xfe,0xd3,0x02,0x77,0xfd,0x89,0x05,0xaf,0xd4,0xca,0x70,0xa6,0x31,0x27,0xaf,0x81,0x89,0x44,0x6c,0x22,0x18,0x22,0x84,0x46,0x85,0x76,0x90,0x9b,0x7f,0x82,0x7b,0x87,0x00,0x00, +0x00,0x01,0x00,0x6d,0xff,0xeb,0x04,0x77,0x05,0xc5,0x00,0x27,0x00,0x4e,0x40,0x0e,0x26,0x24,0x22,0x21,0x1e,0x1c,0x12,0x10,0x0e,0x0d,0x0a,0x08,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x33,0x0c,0x01,0x01,0x02,0x20,0x01,0x05,0x04,0x02,0x15,0x00,0x01,0x02,0x04,0x02,0x01,0x04,0x29,0x00,0x04,0x05,0x02,0x04,0x05,0x27,0x00, +0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x34,0x26,0x27,0x2e,0x01,0x35,0x34,0x24,0x33,0x32,0x00,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x17,0x1e,0x01,0x15,0x14,0x04,0x23,0x22,0x24,0x3f,0x01,0x33,0x14, +0x16,0x33,0x32,0x36,0x03,0xb2,0x8e,0xb3,0xde,0xf9,0x01,0x0c,0xd6,0xe6,0x01,0x11,0x04,0x03,0xbc,0xad,0x87,0x8a,0x93,0xa1,0xb5,0xdc,0xe6,0xfe,0xeb,0xdf,0xd3,0xfe,0xbd,0x05,0x02,0xbc,0xd0,0x83,0x8c,0xa3,0x01,0x6f,0x63,0x86,0x2f,0x37,0xd6,0xa2,0xab,0xe4,0xfe,0xfb,0xae,0x06,0x7c,0xa2,0x86,0x6b,0x5f,0x7f,0x30,0x39,0xde,0xa3, +0xb0,0xd6,0xec,0xc6,0x06,0x89,0x95,0x7e,0x00,0x01,0x00,0x25,0x00,0x00,0x04,0xa4,0x05,0xb0,0x00,0x07,0x00,0x2b,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x02,0x01,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f, +0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x35,0x21,0x04,0xa4,0xfe,0x20,0xc5,0xfe,0x26,0x04,0x7f,0x05,0x15,0xfa,0xeb,0x05,0x15,0x9b,0x00,0x00,0x00,0x00,0x01,0x00,0x93,0xff,0xeb,0x04,0xdc,0x05,0xb0,0x00,0x11,0x00,0x30,0x40,0x0e,0x00,0x00,0x00,0x11,0x00,0x11,0x0e,0x0c,0x09,0x08,0x05,0x03,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x15,0x04,0x03,0x02,0x01,0x01,0x07,0x16,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x11,0x14,0x00,0x23,0x22,0x00,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x11,0x04,0xdc,0xfe,0xc8,0xf6,0xed,0xfe,0xd2,0xc5,0xbf,0x97,0xa0,0xc9,0x05,0xb0,0xfc,0x39,0xf0,0xfe,0xf2, +0x01,0x0f,0xef,0x03,0xc7,0xfc,0x39,0xa7,0xbd,0xbd,0xa7,0x03,0xc7,0x00,0x00,0x00,0x00,0x01,0x00,0x16,0x00,0x00,0x04,0xf9,0x05,0xb0,0x00,0x09,0x00,0x2c,0x40,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x00,0x00,0x01,0x02,0x01,0x00,0x02,0x29,0x03,0x01,0x01,0x01,0x07,0x16, +0x00,0x02,0x02,0x08,0x02,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x37,0x01,0x33,0x01,0x23,0x01,0x33,0x02,0x64,0x21,0x06,0x21,0x01,0x78,0xd5,0xfd,0xe3,0xa9,0xfd,0xe3,0xd6,0x01,0x7e,0x79,0x79,0x04,0x32,0xfa,0x50,0x05,0xb0,0x00,0x01,0x00,0x25,0x00,0x00,0x06,0xbf,0x05,0xb0,0x00,0x15,0x00,0x3b,0x40,0x10,0x15,0x14,0x13,0x12, +0x10,0x0f,0x0d,0x0c,0x0b,0x0a,0x08,0x07,0x05,0x04,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x29,0x00,0x01,0x03,0x00,0x01,0x03,0x27,0x06,0x02,0x02,0x00,0x00,0x07,0x16,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x1f,0x01,0x37,0x01,0x33,0x01,0x17,0x33,0x37,0x13, +0x33,0x01,0x23,0x01,0x27,0x23,0x07,0x01,0x23,0x01,0x33,0x01,0xce,0x19,0x06,0x22,0x01,0x02,0xc1,0x01,0x04,0x22,0x06,0x1b,0xd0,0xd6,0xfe,0xa0,0xb0,0xfe,0xdd,0x16,0x06,0x15,0xfe,0xd9,0xb0,0xfe,0xa1,0xd5,0x01,0xf9,0xbf,0x01,0xc0,0x03,0xb7,0xfc,0x49,0xc3,0xc3,0x03,0xb7,0xfa,0x50,0x03,0xf2,0x83,0x83,0xfc,0x0e,0x05,0xb0,0x00, +0x00,0x01,0x00,0x42,0x00,0x00,0x04,0xd6,0x05,0xb0,0x00,0x0b,0x00,0x2e,0x40,0x0a,0x0b,0x0a,0x08,0x07,0x05,0x04,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x09,0x06,0x03,0x00,0x04,0x01,0x00,0x01,0x15,0x03,0x01,0x00,0x00,0x07,0x16,0x02,0x01,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x09,0x01,0x33,0x09, +0x01,0x23,0x09,0x01,0x23,0x09,0x01,0x33,0x02,0x8a,0x01,0x54,0xee,0xfe,0x32,0x01,0xd8,0xeb,0xfe,0xa3,0xfe,0xa2,0xee,0x01,0xd8,0xfe,0x32,0xec,0x03,0x78,0x02,0x38,0xfd,0x2e,0xfd,0x22,0x02,0x42,0xfd,0xbe,0x02,0xde,0x02,0xd2,0x00,0x01,0x00,0x28,0x00,0x00,0x04,0xe2,0x05,0xb0,0x00,0x08,0x00,0x2a,0x40,0x08,0x08,0x07,0x05,0x04, +0x02,0x01,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x06,0x03,0x00,0x03,0x01,0x00,0x01,0x15,0x02,0x01,0x00,0x00,0x07,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x09,0x01,0x33,0x01,0x11,0x23,0x11,0x01,0x33,0x02,0x85,0x01,0x7c,0xe1,0xfe,0x01,0xc4,0xfe,0x09,0xe1,0x02,0xcc,0x02,0xe4,0xfc,0x50,0xfe,0x00, +0x02,0x0f,0x03,0xa1,0x00,0x01,0x00,0x61,0x00,0x00,0x04,0x6d,0x05,0xb0,0x00,0x09,0x00,0x3b,0x40,0x0a,0x08,0x07,0x06,0x05,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x09,0x01,0x02,0x03,0x04,0x01,0x01,0x00,0x02,0x15,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x00,0x00,0x01, +0x00,0x00,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x25,0x21,0x15,0x21,0x35,0x01,0x21,0x35,0x21,0x15,0x01,0x3f,0x03,0x2e,0xfb,0xf4,0x03,0x0a,0xfd,0x01,0x03,0xe0,0x9a,0x9a,0x92,0x04,0x83,0x9b,0x8d,0x00,0x00,0x00,0x01,0x00,0x8f,0xfe,0xc8,0x02,0x10,0x06,0x80,0x00,0x07,0x00,0x38,0x40,0x0a,0x07,0x06,0x05,0x04, +0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x00,0x01,0x02,0x02,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x02,0x00,0x00,0x1b,0x00,0x02,0x01,0x02,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x33,0x15,0x21,0x11,0x21,0x02,0x10,0xbc,0xbc,0xfe,0x7f, +0x01,0x81,0x05,0xe5,0xf9,0x7e,0x9b,0x07,0xb8,0x00,0x00,0x00,0x00,0x01,0x00,0x27,0xff,0x83,0x03,0x41,0x05,0xb0,0x00,0x03,0x00,0x1f,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0c,0x00,0x01,0x00,0x01,0x2c,0x00,0x00,0x00,0x07,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x13,0x33,0x01,0x23,0x27,0xba,0x02, +0x60,0xba,0x05,0xb0,0xf9,0xd3,0x00,0x00,0x00,0x01,0x00,0x0b,0xfe,0xc8,0x01,0x8d,0x06,0x80,0x00,0x07,0x00,0x38,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x00,0x00,0x00,0x03,0x02,0x00,0x03,0x00,0x00,0x1d,0x00,0x02,0x01,0x01,0x02,0x00,0x00,0x1a,0x00,0x02,0x02,0x01, +0x00,0x00,0x1b,0x00,0x01,0x02,0x01,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b,0x13,0x21,0x11,0x21,0x35,0x33,0x11,0x23,0x0b,0x01,0x82,0xfe,0x7e,0xbd,0xbd,0x06,0x80,0xf8,0x48,0x9b,0x06,0x82,0x00,0x01,0x00,0x3d,0x02,0xd9,0x03,0x18,0x05,0xb0,0x00,0x09,0x00,0x2b,0x40,0x0a,0x08,0x07,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x14,0x00,0x03,0x01,0x00,0x01,0x03,0x00,0x29,0x02,0x01,0x00,0x00,0x2a,0x00,0x01,0x01,0x07,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x13,0x23,0x01,0x33,0x01,0x23,0x03,0x27,0x23,0x07,0xf4,0xb7,0x01,0x2b,0x86,0x01,0x2a,0xb5,0xa6,0x10,0x06,0x10,0x02,0xd9,0x02,0xd7,0xfd,0x29,0x01,0xa3,0x46,0x46,0x00,0x00,0x00, +0x00,0x01,0x00,0x04,0xff,0x66,0x03,0x9f,0x00,0x00,0x00,0x03,0x00,0x2a,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x03,0xb0,0x2f,0x2b,0x05,0x21,0x35,0x21,0x03,0x9f,0xfc,0x65, +0x03,0x9b,0x9a,0x9a,0x00,0x01,0x00,0x52,0x04,0xe4,0x01,0xea,0x05,0xee,0x00,0x04,0x00,0x31,0x40,0x06,0x04,0x03,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x0c,0x00,0x00,0x01,0x00,0x2c,0x00,0x01,0x01,0x09,0x01,0x17,0x02,0x1b,0x40,0x0a,0x00,0x01,0x00,0x01,0x2b,0x00,0x00,0x00,0x22,0x02,0x59, +0xb0,0x2f,0x2b,0x01,0x23,0x03,0x37,0x33,0x01,0xea,0x9e,0xfa,0x03,0xe6,0x04,0xe4,0x01,0x04,0x06,0x00,0x00,0x02,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x04,0x4e,0x00,0x20,0x00,0x2b,0x00,0xa7,0x40,0x1a,0x22,0x21,0x00,0x00,0x27,0x25,0x21,0x2b,0x22,0x2b,0x00,0x20,0x00,0x20,0x1a,0x18,0x15,0x14,0x12,0x10,0x0d,0x0b,0x07,0x05,0x0a,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x3a,0x16,0x01,0x03,0x02,0x24,0x03,0x02,0x06,0x07,0x02,0x15,0x00,0x03,0x02,0x01,0x02,0x03,0x01,0x29,0x00,0x01,0x00,0x07,0x06,0x01,0x07,0x01,0x00,0x1d,0x00,0x02,0x02,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x09,0x01,0x06,0x06,0x00,0x01,0x00,0x1b,0x08,0x05,0x02, +0x00,0x00,0x0e,0x00,0x17,0x07,0x1b,0x40,0x3e,0x16,0x01,0x03,0x02,0x24,0x03,0x02,0x06,0x07,0x02,0x15,0x00,0x03,0x02,0x01,0x02,0x03,0x01,0x29,0x00,0x01,0x00,0x07,0x06,0x01,0x07,0x01,0x00,0x1d,0x00,0x02,0x02,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x08,0x01,0x05,0x05,0x08,0x16,0x09,0x01,0x06,0x06,0x00,0x01,0x00,0x1b, +0x00,0x00,0x00,0x0e,0x00,0x17,0x08,0x59,0xb0,0x2f,0x2b,0x21,0x2e,0x01,0x27,0x0e,0x01,0x23,0x22,0x26,0x35,0x34,0x36,0x3b,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x07,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x11,0x14,0x16,0x17,0x25,0x32,0x36,0x37,0x35,0x23,0x22,0x06,0x15,0x14,0x16,0x03,0x28,0x0a,0x0b,0x01,0x37,0xb1,0x66,0xa9, +0xb1,0xfb,0xd7,0xd6,0x74,0x6a,0x60,0x76,0xbb,0x02,0x07,0xeb,0xba,0xb8,0xe0,0x0c,0x10,0xfd,0xee,0x6b,0xac,0x1a,0xdd,0x77,0x8f,0x5a,0x31,0x4b,0x26,0x4e,0x69,0xad,0x98,0x9b,0xaf,0x6b,0x5f,0x6f,0x60,0x43,0x02,0x06,0x76,0xc4,0xbb,0xb0,0xfd,0xf7,0x3a,0x6c,0x34,0x90,0x6e,0x47,0xb0,0x78,0x51,0x48,0x54,0x00,0x00,0x02,0x00,0x8f, +0xff,0xeb,0x04,0x2b,0x06,0x18,0x00,0x11,0x00,0x1f,0x00,0x7f,0x40,0x0e,0x1d,0x1b,0x16,0x14,0x0f,0x0d,0x0a,0x09,0x08,0x07,0x04,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x2c,0x0b,0x01,0x04,0x03,0x19,0x18,0x06,0x03,0x05,0x04,0x02,0x15,0x00,0x02,0x02,0x09,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b, +0x00,0x03,0x03,0x10,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x0e,0x00,0x17,0x06,0x1b,0x40,0x30,0x0b,0x01,0x04,0x03,0x19,0x18,0x06,0x03,0x05,0x04,0x02,0x15,0x00,0x02,0x02,0x09,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x01,0x01,0x08,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b, +0x00,0x00,0x00,0x0e,0x00,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x01,0x14,0x02,0x23,0x22,0x26,0x27,0x07,0x23,0x11,0x33,0x11,0x3e,0x01,0x33,0x32,0x12,0x11,0x23,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x1e,0x01,0x33,0x32,0x36,0x35,0x04,0x2b,0xe1,0xc5,0x6c,0x9f,0x34,0x20,0x97,0xc5,0x33,0x97,0x65,0xc8,0xe0,0xc5,0x89,0x8c,0x5b,0x7d,0x25, +0x26,0x7b,0x5e,0x8b,0x88,0x01,0xf4,0xea,0xfe,0xe1,0x55,0x53,0x93,0x06,0x18,0xfd,0xa2,0x48,0x4c,0xfe,0xc0,0xfe,0xfb,0xba,0xeb,0x59,0x4b,0xfe,0x2b,0x50,0x5a,0xc6,0xa3,0x00,0x00,0x00,0x00,0x01,0x00,0x61,0xff,0xeb,0x03,0xd9,0x04,0x4e,0x00,0x1d,0x00,0x53,0x40,0x12,0x01,0x00,0x18,0x16,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03, +0x00,0x1d,0x01,0x1d,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x34,0x12,0x01,0x04,0x05,0x05,0x01,0x00,0x01,0x02,0x15,0x00,0x04,0x05,0x01,0x05,0x04,0x01,0x29,0x00,0x01,0x00,0x05,0x01,0x00,0x27,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x06,0x01,0x00,0x00,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02, +0x17,0x07,0xb0,0x2f,0x2b,0x25,0x32,0x36,0x35,0x33,0x17,0x16,0x06,0x23,0x22,0x02,0x3d,0x01,0x34,0x12,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x02,0x3d,0x5b,0x88,0xb2,0x03,0x04,0xf8,0xa4,0xe4,0xf8,0xf9,0xe3,0xb5,0xe7,0x04,0x02,0xb3,0x81,0x62,0x91,0x85,0x83,0x85,0x79,0x58,0x06,0x8c,0xd9, +0x01,0x36,0xe7,0x2a,0xe5,0x01,0x37,0xe0,0xa3,0x06,0x63,0x8b,0xe1,0xa0,0x2a,0xa3,0xe0,0x00,0x00,0x00,0x00,0x02,0x00,0x62,0xff,0xeb,0x03,0xf5,0x06,0x18,0x00,0x11,0x00,0x1f,0x00,0x85,0x40,0x0e,0x1d,0x1b,0x16,0x14,0x0f,0x0d,0x0a,0x09,0x08,0x07,0x04,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x2f, +0x06,0x01,0x05,0x00,0x19,0x18,0x02,0x04,0x05,0x0b,0x01,0x02,0x04,0x03,0x15,0x00,0x01,0x01,0x09,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x08,0x02,0x17,0x06,0x1b,0x40,0x33,0x06,0x01,0x05,0x00,0x19,0x18,0x02,0x04,0x05,0x0b,0x01,0x02,0x04,0x03, +0x15,0x00,0x01,0x01,0x09,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x02,0x02,0x08,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x13,0x10,0x12,0x33,0x32,0x16,0x17,0x11,0x33,0x11,0x23,0x27,0x0e,0x01,0x23,0x22,0x02,0x35,0x33,0x14,0x16,0x33,0x32, +0x36,0x37,0x11,0x2e,0x01,0x23,0x22,0x06,0x15,0x62,0xdf,0xc9,0x5f,0x93,0x34,0xc5,0x97,0x1e,0x35,0x9c,0x67,0xc6,0xe0,0xc5,0x86,0x8d,0x58,0x78,0x26,0x26,0x79,0x55,0x8e,0x87,0x02,0x09,0x01,0x05,0x01,0x40,0x46,0x43,0x02,0x53,0xf9,0xe8,0x89,0x4e,0x50,0x01,0x1f,0xea,0xa4,0xc5,0x50,0x48,0x01,0xf9,0x43,0x4f,0xea,0xbb,0x00,0x00, +0x00,0x02,0x00,0x61,0xff,0xeb,0x03,0xe2,0x04,0x4e,0x00,0x16,0x00,0x1f,0x00,0x54,0x40,0x16,0x18,0x17,0x01,0x00,0x1c,0x1b,0x17,0x1f,0x18,0x1f,0x11,0x0f,0x0c,0x0b,0x08,0x06,0x00,0x16,0x01,0x16,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x31,0x13,0x0d,0x02,0x03,0x02,0x14,0x01,0x00,0x03,0x02,0x15,0x00,0x05,0x00,0x02,0x03, +0x05,0x02,0x00,0x00,0x1d,0x07,0x01,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x06,0x01,0x00,0x00,0x0e,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x05,0x22,0x00,0x3d,0x01,0x34,0x00,0x33,0x32,0x12,0x1d,0x01,0x21,0x07,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x03,0x22,0x06,0x07,0x17, +0x21,0x35,0x34,0x26,0x02,0x4f,0xe9,0xfe,0xfb,0x01,0x0d,0xc2,0xd9,0xd9,0xfd,0x4c,0x03,0x90,0x94,0x64,0x97,0x36,0x4d,0x3a,0xbe,0xa5,0x67,0x87,0x0f,0x02,0x01,0xe8,0x74,0x15,0x01,0x2a,0xf3,0x2c,0xe9,0x01,0x31,0xfe,0xf2,0xe0,0x68,0x05,0xa3,0xcb,0x39,0x32,0x80,0x38,0x4d,0x03,0xc8,0x9f,0x7c,0x05,0x10,0x76,0x9a,0x00,0x00,0x00, +0x00,0x01,0x00,0x38,0x00,0x00,0x02,0xc9,0x06,0x2d,0x00,0x17,0x00,0x49,0x40,0x14,0x00,0x00,0x00,0x17,0x00,0x17,0x16,0x15,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03,0x02,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x28,0x0b,0x01,0x03,0x02,0x01,0x15,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0f,0x16,0x05,0x01, +0x00,0x00,0x01,0x00,0x00,0x1b,0x04,0x01,0x01,0x01,0x0a,0x16,0x07,0x01,0x06,0x06,0x08,0x06,0x17,0x06,0xb0,0x2f,0x2b,0x33,0x11,0x23,0x35,0x33,0x35,0x34,0x36,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x33,0x15,0x23,0x11,0xe1,0xa9,0xa9,0xb5,0xa2,0x22,0x45,0x2a,0x18,0x12,0x33,0x1c,0x56,0x54,0xc4,0xc4,0x03, +0xa8,0x92,0x89,0xad,0xbd,0x0b,0x0a,0x96,0x04,0x06,0x67,0x62,0x89,0x92,0xfc,0x58,0x00,0x02,0x00,0x6c,0xfe,0x4b,0x04,0x00,0x04,0x4e,0x00,0x1d,0x00,0x2b,0x00,0x9f,0x40,0x10,0x29,0x27,0x22,0x20,0x1b,0x19,0x14,0x12,0x0d,0x0b,0x08,0x07,0x04,0x02,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x3b,0x25,0x24, +0x06,0x03,0x05,0x06,0x17,0x01,0x04,0x05,0x10,0x01,0x03,0x04,0x0f,0x01,0x02,0x03,0x04,0x15,0x00,0x06,0x06,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x10,0x16,0x00,0x05,0x05,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x0e,0x16,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x12,0x02,0x17,0x07,0x1b,0x40,0x3f,0x25,0x24,0x06,0x03, +0x05,0x06,0x17,0x01,0x04,0x05,0x10,0x01,0x03,0x04,0x0f,0x01,0x02,0x03,0x04,0x15,0x00,0x01,0x01,0x0a,0x16,0x00,0x06,0x06,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x05,0x05,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x0e,0x16,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x12,0x02,0x17,0x08,0x59,0xb0,0x2f,0x2b,0x13, +0x10,0x12,0x33,0x32,0x16,0x17,0x37,0x33,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x3d,0x01,0x0e,0x01,0x23,0x22,0x02,0x35,0x33,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x2e,0x01,0x23,0x22,0x06,0x15,0x6c,0xdf,0xc8,0x67,0x9c,0x35,0x18,0x9d,0xf2,0xe4,0x4e,0xb5,0x45,0x1e,0x39,0xa1,0x4e,0x90,0x83,0x35,0x94, +0x61,0xc6,0xdf,0xc5,0x86,0x8c,0x59,0x78,0x27,0x26,0x7a,0x56,0x8d,0x87,0x02,0x09,0x01,0x05,0x01,0x40,0x53,0x4e,0x8d,0xfb,0xc0,0xd0,0xdf,0x2b,0x25,0x99,0x1e,0x25,0x83,0x86,0x7b,0x44,0x46,0x01,0x1f,0xea,0xa3,0xc6,0x51,0x4a,0x01,0xf2,0x45,0x51,0xea,0xbb,0x00,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x04,0x00,0x06,0x18,0x00,0x13, +0x00,0x39,0x40,0x0c,0x13,0x12,0x11,0x10,0x0d,0x0b,0x08,0x07,0x04,0x02,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x20,0x0f,0x00,0x02,0x01,0x02,0x01,0x15,0x00,0x04,0x04,0x09,0x16,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x3e,0x01,0x33,0x32, +0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x33,0x01,0x54,0x38,0xa3,0x63,0xad,0xc1,0xc5,0x73,0x72,0x58,0x82,0x28,0xc5,0xc5,0x03,0xa9,0x4e,0x57,0xd0,0xd8,0xfd,0x5a,0x02,0xa8,0x86,0x80,0x45,0x3e,0xfc,0xd5,0x06,0x18,0x00,0x02,0x00,0x9f,0x00,0x00,0x01,0x64,0x06,0x18,0x00,0x03,0x00,0x07,0x00,0x2f, +0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x18,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x09,0x16,0x00,0x01,0x01,0x0a,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x33,0x11,0x23,0x35,0x33,0x01,0x64,0xc5,0xc5,0xc5,0xc5,0x04,0x3a,0x01, +0x15,0xc9,0x00,0x00,0x00,0x02,0xff,0xbe,0xfe,0x4b,0x01,0x72,0x06,0x18,0x00,0x0f,0x00,0x13,0x00,0x43,0x40,0x10,0x00,0x00,0x13,0x12,0x11,0x10,0x00,0x0f,0x00,0x0f,0x0c,0x0a,0x05,0x03,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x26,0x07,0x01,0x00,0x01,0x01,0x15,0x00,0x03,0x03,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x09,0x16, +0x05,0x01,0x02,0x02,0x0a,0x16,0x00,0x01,0x01,0x00,0x01,0x02,0x1b,0x00,0x00,0x00,0x12,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x13,0x23,0x35,0x33,0x01,0x72,0xac,0x99,0x1f,0x33,0x1d,0x0e,0x0e,0x34,0x11,0x41,0x4d,0xbf,0xc5,0xc5,0x04,0x3a,0xfb,0x6d,0xa7, +0xb5,0x09,0x09,0x9b,0x05,0x07,0x58,0x63,0x04,0x93,0x01,0x19,0xc5,0x00,0x00,0x00,0x00,0x01,0x00,0x90,0x00,0x00,0x04,0x0b,0x06,0x18,0x00,0x0c,0x00,0x3d,0x40,0x0e,0x0c,0x0b,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x22,0x0a,0x01,0x00,0x03,0x01,0x15,0x00,0x03,0x00,0x00, +0x01,0x03,0x00,0x00,0x00,0x1d,0x00,0x02,0x02,0x09,0x16,0x00,0x04,0x04,0x0a,0x16,0x05,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x01,0x33,0x09,0x01,0x23,0x01,0xba,0x65,0xc5,0xc5,0x63,0x01,0x45,0xec,0xfe,0x77,0x01,0xab,0xe9,0x01,0xf3,0xfe,0x0d,0x06,0x18,0xfc,0x78,0x01,0xaa, +0xfe,0x0d,0xfd,0xb9,0x00,0x01,0x00,0x9f,0x00,0x00,0x01,0x64,0x06,0x18,0x00,0x03,0x00,0x1f,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0c,0x00,0x01,0x01,0x09,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x33,0x01,0x64,0xc5,0xc5,0x06,0x18,0x00,0x00,0x01,0x00,0x8f, +0x00,0x00,0x06,0x6f,0x04,0x4e,0x00,0x23,0x00,0x73,0x40,0x16,0x00,0x00,0x00,0x23,0x00,0x23,0x22,0x21,0x1e,0x1c,0x19,0x18,0x14,0x12,0x0f,0x0e,0x0b,0x09,0x05,0x03,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x22,0x20,0x16,0x07,0x01,0x04,0x02,0x03,0x01,0x15,0x05,0x01,0x03,0x03,0x00,0x01,0x00,0x1b,0x08, +0x07,0x01,0x03,0x00,0x00,0x10,0x16,0x06,0x04,0x02,0x02,0x02,0x08,0x02,0x17,0x04,0x1b,0x40,0x26,0x20,0x16,0x07,0x01,0x04,0x02,0x03,0x01,0x15,0x08,0x01,0x07,0x07,0x0a,0x16,0x05,0x01,0x03,0x03,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x10,0x16,0x06,0x04,0x02,0x02,0x02,0x08,0x02,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x3e, +0x01,0x33,0x32,0x16,0x17,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x01,0x3f,0x0e,0x35,0xa3,0x6c,0x6c,0x9b,0x27,0x34,0xa7,0x70,0xa5,0xc0,0xc5,0x6e,0x6d,0x65,0x7d,0x0b,0xc6,0x71,0x6a,0x5a,0x74,0x1f,0xc5,0x04,0x3a,0x8e,0x4d, +0x55,0x64,0x64,0x5d,0x6b,0xe3,0xe4,0xfd,0x79,0x02,0x89,0xa0,0x85,0x8c,0x6b,0x08,0xfd,0x51,0x02,0x89,0x98,0x8d,0x4a,0x43,0xfc,0xdf,0x04,0x3a,0x00,0x01,0x00,0x8f,0x00,0x00,0x03,0xfd,0x04,0x4e,0x00,0x13,0x00,0x63,0x40,0x10,0x00,0x00,0x00,0x13,0x00,0x13,0x12,0x11,0x0e,0x0c,0x09,0x08,0x05,0x03,0x06,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x1d,0x10,0x01,0x02,0x01,0x02,0x01,0x15,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x05,0x04,0x02,0x00,0x00,0x10,0x16,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0x1b,0x40,0x21,0x10,0x01,0x02,0x01,0x02,0x01,0x15,0x05,0x01,0x04,0x04,0x0a,0x16,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10, +0x16,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x01,0x3f,0x0e,0x36,0xa3,0x68,0xaf,0xc0,0xc5,0x71,0x74,0x5b,0x7f,0x25,0xc5,0x04,0x3a,0xa1,0x56,0x5f,0xcd,0xd6,0xfd,0x55,0x02,0xa7,0x8f,0x78,0x49,0x42,0xfc, +0xdd,0x04,0x3a,0x00,0x00,0x02,0x00,0x61,0xff,0xeb,0x04,0x2a,0x04,0x4e,0x00,0x0d,0x00,0x1b,0x00,0x31,0x40,0x0a,0x19,0x17,0x12,0x10,0x0b,0x09,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01, +0x17,0x04,0xb0,0x2f,0x2b,0x13,0x34,0x00,0x33,0x32,0x00,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x35,0x33,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x61,0x01,0x04,0xdf,0xe1,0x01,0x05,0xfe,0xfc,0xe0,0xe0,0xfe,0xfb,0xc5,0x91,0x8f,0x8d,0x92,0x93,0x8e,0x8d,0x91,0x02,0x27,0xf0,0x01,0x37,0xfe,0xca,0xf1,0x16, +0xf2,0xfe,0xcc,0x01,0x35,0xf1,0xac,0xe0,0xe0,0xac,0x16,0xaa,0xe2,0xe2,0xaa,0x00,0x00,0x02,0x00,0x8f,0xfe,0x60,0x04,0x29,0x04,0x4e,0x00,0x11,0x00,0x1f,0x00,0x87,0x40,0x0e,0x1d,0x1b,0x16,0x14,0x0f,0x0d,0x0a,0x09,0x08,0x07,0x04,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x30,0x19,0x18,0x02,0x05, +0x04,0x06,0x01,0x00,0x05,0x02,0x15,0x0b,0x01,0x04,0x01,0x14,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x0a,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x07,0x1b,0x40,0x34,0x19,0x18,0x02,0x05,0x04,0x06,0x01,0x00,0x05,0x02,0x15,0x0b,0x01,0x04,0x01,0x14,0x00, +0x02,0x02,0x0a,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x08,0x59,0xb0,0x2f,0x2b,0x01,0x14,0x02,0x23,0x22,0x26,0x27,0x11,0x23,0x11,0x33,0x17,0x3e,0x01,0x33,0x32,0x12,0x11,0x23,0x34,0x26,0x23,0x22,0x06,0x07, +0x11,0x1e,0x01,0x33,0x32,0x36,0x35,0x04,0x29,0xe0,0xc5,0x64,0x97,0x35,0xc5,0x97,0x1f,0x35,0x9e,0x69,0xc9,0xdf,0xc5,0x91,0x8d,0x55,0x78,0x25,0x25,0x78,0x57,0x8c,0x90,0x01,0xf4,0xea,0xfe,0xe1,0x43,0x43,0xfd,0xef,0x05,0xda,0x8c,0x4e,0x52,0xfe,0xc1,0xfe,0xfa,0xb8,0xed,0x4d,0x43,0xfd,0xf5,0x43,0x4b,0xcd,0xa2,0x00,0x00,0x00, +0x00,0x02,0x00,0x62,0xfe,0x60,0x03,0xea,0x04,0x4e,0x00,0x11,0x00,0x1f,0x00,0x85,0x40,0x0e,0x1d,0x1b,0x16,0x14,0x0f,0x0d,0x0a,0x09,0x08,0x07,0x04,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x2f,0x06,0x01,0x05,0x00,0x19,0x18,0x02,0x04,0x05,0x0b,0x01,0x03,0x04,0x03,0x15,0x00,0x05,0x05,0x00,0x01, +0x00,0x1b,0x01,0x01,0x00,0x00,0x10,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x16,0x00,0x02,0x02,0x0c,0x02,0x17,0x06,0x1b,0x40,0x33,0x06,0x01,0x05,0x01,0x19,0x18,0x02,0x04,0x05,0x0b,0x01,0x03,0x04,0x03,0x15,0x00,0x01,0x01,0x0a,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x04, +0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x16,0x00,0x02,0x02,0x0c,0x02,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x13,0x10,0x12,0x33,0x32,0x16,0x17,0x37,0x33,0x11,0x23,0x11,0x0e,0x01,0x23,0x22,0x02,0x35,0x33,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x2e,0x01,0x23,0x22,0x06,0x15,0x62,0xdf,0xc9,0x62,0x96,0x35,0x1c,0x97,0xc5,0x34,0x8e, +0x5b,0xc6,0xe0,0xc5,0x87,0x8c,0x51,0x73,0x27,0x27,0x73,0x4f,0x8d,0x88,0x02,0x09,0x01,0x05,0x01,0x40,0x4b,0x47,0x7e,0xfa,0x26,0x02,0x06,0x3d,0x3e,0x01,0x1f,0xea,0xa4,0xcb,0x48,0x41,0x02,0x22,0x3d,0x46,0xef,0xbb,0x00,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x02,0xaa,0x04,0x4e,0x00,0x0f,0x00,0x67,0x40,0x0a,0x0d,0x0b,0x08,0x07, +0x06,0x05,0x02,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x22,0x09,0x01,0x00,0x02,0x04,0x01,0x01,0x00,0x02,0x15,0x0f,0x01,0x02,0x13,0x00,0x00,0x00,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x0a,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x05,0x1b,0x40,0x26,0x0f,0x01,0x02,0x03,0x09,0x01,0x00,0x02,0x04, +0x01,0x01,0x00,0x03,0x15,0x00,0x02,0x02,0x0a,0x16,0x00,0x00,0x00,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x27,0x22,0x06,0x07,0x11,0x23,0x11,0x33,0x17,0x3e,0x01,0x33,0x32,0x16,0x17,0x02,0x8f,0x65,0x4e,0x6b,0x1d,0xc5,0xb0,0x13,0x2e,0x87,0x58,0x16,0x28,0x0d, +0x03,0x8c,0x06,0x4a,0x43,0xfc,0xfb,0x04,0x3a,0x9e,0x54,0x5e,0x07,0x04,0x00,0x00,0x00,0x01,0x00,0x67,0xff,0xeb,0x03,0xc9,0x04,0x4e,0x00,0x27,0x00,0x4e,0x40,0x0e,0x26,0x24,0x22,0x21,0x1e,0x1c,0x12,0x10,0x0e,0x0d,0x0a,0x08,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x33,0x0c,0x01,0x01,0x02,0x20,0x01,0x05,0x04,0x02,0x15, +0x00,0x01,0x02,0x04,0x02,0x01,0x04,0x29,0x00,0x04,0x05,0x02,0x04,0x05,0x27,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x34,0x26,0x27,0x2e,0x01,0x35,0x34,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06, +0x15,0x14,0x16,0x17,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x1e,0x01,0x33,0x32,0x36,0x03,0x04,0x63,0x8a,0xbf,0xcd,0xe1,0xb3,0xb8,0xe4,0x05,0x02,0xbc,0x7b,0x5e,0x68,0x67,0x59,0x8b,0xc7,0xce,0xe9,0xbc,0xcf,0xee,0x06,0x02,0xbc,0x05,0x92,0x62,0x69,0x77,0x01,0x23,0x41,0x52,0x1f,0x29,0x94,0x7c,0x84,0xbc,0xc8, +0x85,0x06,0x46,0x72,0x5e,0x41,0x40,0x46,0x1d,0x2a,0x9a,0x7c,0x90,0xb6,0xd2,0x8c,0x06,0x69,0x61,0x59,0x00,0x01,0x00,0x30,0xff,0xeb,0x02,0x78,0x05,0x3f,0x00,0x17,0x00,0x4d,0x40,0x14,0x00,0x00,0x00,0x17,0x00,0x17,0x16,0x15,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03,0x02,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2c, +0x0b,0x01,0x02,0x01,0x0c,0x01,0x03,0x02,0x02,0x15,0x07,0x01,0x06,0x00,0x06,0x2b,0x04,0x01,0x01,0x01,0x00,0x00,0x00,0x1b,0x05,0x01,0x00,0x00,0x0a,0x16,0x00,0x02,0x02,0x03,0x01,0x02,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x11,0x33,0x15,0x23,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22, +0x26,0x35,0x11,0x23,0x35,0x33,0x11,0x01,0xa1,0xcd,0xcd,0x3f,0x34,0x11,0x2a,0x0e,0x1b,0x16,0x56,0x2a,0x78,0x8e,0xac,0xac,0x05,0x3f,0xfe,0xfb,0x92,0xfd,0x6f,0x4c,0x3e,0x09,0x05,0x87,0x12,0x17,0x91,0x9b,0x02,0x91,0x92,0x01,0x05,0x00,0x00,0x00,0x00,0x01,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x04,0x3a,0x00,0x13,0x00,0x5d,0x40,0x0c, +0x13,0x12,0x11,0x10,0x0d,0x0b,0x08,0x07,0x04,0x02,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x1c,0x0f,0x00,0x02,0x02,0x01,0x01,0x15,0x03,0x01,0x01,0x01,0x0a,0x16,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x0e,0x00,0x17,0x04,0x1b,0x40,0x20,0x0f,0x00,0x02,0x02,0x01,0x01,0x15,0x03,0x01, +0x01,0x01,0x0a,0x16,0x00,0x04,0x04,0x08,0x16,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x25,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x33,0x11,0x23,0x03,0x3e,0x33,0xa0,0x69,0xb1,0xc6,0xc5,0x66,0x6c,0x69,0x89,0x23,0xc5,0xb1,0xa0,0x57, +0x5e,0xe2,0xef,0x02,0x7e,0xfd,0x80,0xad,0x82,0x55,0x4e,0x03,0x0c,0xfb,0xc6,0x00,0x00,0x01,0x00,0x2e,0x00,0x00,0x03,0xe4,0x04,0x3a,0x00,0x09,0x00,0x2c,0x40,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x00,0x00,0x01,0x02,0x01,0x00,0x02,0x29,0x03,0x01,0x01,0x01,0x0a,0x16, +0x00,0x02,0x02,0x08,0x02,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x37,0x13,0x33,0x01,0x23,0x01,0x33,0x01,0xf8,0x11,0x06,0x13,0xf9,0xc9,0xfe,0x72,0x95,0xfe,0x6d,0xca,0x01,0x3f,0x4c,0x4c,0x02,0xfb,0xfb,0xc6,0x04,0x3a,0x00,0x00,0x01,0x00,0x2d,0x00,0x00,0x05,0xdc,0x04,0x3a,0x00,0x15,0x00,0x6b,0x40,0x12,0x15,0x14,0x13,0x12, +0x10,0x0f,0x0d,0x0c,0x0b,0x0a,0x08,0x07,0x05,0x04,0x02,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1f,0x58,0x40,0x1f,0x00,0x05,0x01,0x00,0x01,0x05,0x00,0x29,0x02,0x01,0x00,0x04,0x01,0x00,0x04,0x27,0x07,0x03,0x02,0x01,0x01,0x0a,0x16,0x06,0x01,0x04,0x04,0x08,0x04,0x17,0x04,0x1b,0x40,0x25,0x00,0x05,0x01,0x00, +0x01,0x05,0x00,0x29,0x00,0x00,0x02,0x01,0x00,0x02,0x27,0x00,0x02,0x04,0x01,0x02,0x04,0x27,0x07,0x03,0x02,0x01,0x01,0x0a,0x16,0x06,0x01,0x04,0x04,0x08,0x04,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x37,0x13,0x33,0x13,0x17,0x33,0x37,0x13,0x33,0x01,0x23,0x03,0x27,0x23,0x07,0x03,0x23,0x01,0x33,0x01,0xa4,0x19,0x06,0x1a, +0xd8,0x9e,0xd9,0x1c,0x06,0x20,0xa0,0xce,0xfe,0xc6,0x9f,0xd6,0x29,0x06,0x26,0xd2,0x9f,0xfe,0xc6,0xcd,0x01,0x8a,0x8b,0x8b,0x02,0xb0,0xfd,0x50,0x9b,0x9b,0x02,0xb0,0xfb,0xc6,0x02,0x93,0xac,0xac,0xfd,0x6d,0x04,0x3a,0x00,0x00,0x00,0x01,0x00,0x2e,0x00,0x00,0x03,0xd4,0x04,0x3a,0x00,0x0b,0x00,0x2e,0x40,0x0a,0x0b,0x0a,0x08,0x07, +0x05,0x04,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x09,0x06,0x03,0x00,0x04,0x01,0x00,0x01,0x15,0x03,0x01,0x00,0x00,0x0a,0x16,0x02,0x01,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x13,0x33,0x09,0x01,0x23,0x0b,0x01,0x23,0x09,0x01,0x33,0x01,0xfe,0xe6,0xe6,0xfe,0xa1,0x01,0x69,0xe2,0xf0,0xf0,0xe4, +0x01,0x69,0xfe,0xa1,0xe3,0x02,0xab,0x01,0x8f,0xfd,0xe9,0xfd,0xdd,0x01,0x99,0xfe,0x67,0x02,0x23,0x02,0x17,0x00,0x00,0x00,0x00,0x01,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x04,0x3a,0x00,0x15,0x00,0x3f,0x40,0x0c,0x15,0x14,0x10,0x0e,0x09,0x07,0x04,0x03,0x02,0x01,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x26,0x0c,0x01,0x03,0x00, +0x0b,0x01,0x02,0x03,0x02,0x15,0x00,0x00,0x01,0x03,0x01,0x00,0x03,0x29,0x04,0x01,0x01,0x01,0x0a,0x16,0x00,0x03,0x03,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x12,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x01,0x33,0x01,0x0e,0x01,0x23,0x22,0x26,0x27,0x37,0x26,0x16,0x33,0x32,0x36,0x3f,0x01,0x01,0x33,0x01,0xda,0x23,0x06,0x01, +0x0a,0xdb,0xfe,0x39,0x29,0x99,0x82,0x18,0x4a,0x14,0x14,0x06,0x53,0x0b,0x3f,0x50,0x1b,0x2f,0xfe,0x6e,0xdc,0x01,0x91,0x88,0x03,0x31,0xfb,0x20,0x6d,0xa2,0x0b,0x05,0x9b,0x01,0x06,0x70,0x44,0x71,0x04,0x24,0x00,0x01,0x00,0x5e,0x00,0x00,0x03,0xba,0x04,0x3a,0x00,0x09,0x00,0x3b,0x40,0x0a,0x08,0x07,0x06,0x05,0x03,0x02,0x01,0x00, +0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x09,0x01,0x02,0x03,0x04,0x01,0x01,0x00,0x02,0x15,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x0a,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x25,0x21,0x15,0x21,0x35,0x01,0x21,0x35,0x21,0x15,0x01,0x49,0x02,0x71,0xfc, +0xa4,0x02,0x49,0xfd,0xbe,0x03,0x33,0x9a,0x9a,0x8a,0x03,0x14,0x9c,0x86,0x00,0x00,0x00,0x01,0x00,0x3f,0xfe,0x94,0x02,0x9f,0x06,0x3d,0x00,0x1e,0x00,0x3a,0x40,0x06,0x09,0x08,0x07,0x06,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x27,0x17,0x01,0x00,0x01,0x01,0x15,0x10,0x0f,0x02,0x01,0x13,0x1e,0x00,0x02,0x00,0x12,0x00,0x01, +0x00,0x00,0x01,0x01,0x00,0x1a,0x00,0x01,0x01,0x00,0x01,0x00,0x1b,0x00,0x00,0x01,0x00,0x01,0x00,0x18,0x06,0xb0,0x2f,0x2b,0x01,0x2e,0x01,0x3d,0x01,0x34,0x26,0x23,0x35,0x32,0x36,0x3d,0x01,0x34,0x36,0x37,0x17,0x0e,0x01,0x1d,0x01,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x14,0x16,0x17,0x02,0x77,0xc3,0xa4,0x67,0x6a,0x6a,0x67,0xa4, +0xc3,0x28,0x6e,0x5c,0x55,0x55,0x55,0x55,0x5c,0x6e,0xfe,0x94,0x37,0xf0,0xaa,0xcd,0x70,0x7d,0x93,0x7b,0x71,0xce,0xab,0xef,0x37,0x75,0x23,0xb5,0x84,0xce,0x69,0xa0,0x2d,0x2e,0xa1,0x67,0xcd,0x84,0xb3,0x24,0x00,0x01,0x00,0x91,0xfe,0xf2,0x01,0x56,0x05,0xb0,0x00,0x03,0x00,0x21,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x0e,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x33,0x01,0x56,0xc5,0xc5,0xfe,0xf2,0x06,0xbe,0x00,0x00,0x01,0x00,0x15,0xfe,0x94,0x02,0x76,0x06,0x3d,0x00,0x1e,0x00,0x3a,0x40,0x06,0x18,0x17,0x16,0x15,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x27,0x07,0x01,0x01,0x00,0x01,0x15,0x0f,0x0e,0x02,0x00,0x13,0x1e,0x00,0x02,0x01,0x12,0x00,0x00,0x01,0x01,0x00,0x01,0x00,0x1a,0x00,0x00,0x00,0x01,0x01,0x00,0x1b,0x00,0x01,0x00,0x01,0x01,0x00,0x18,0x06,0xb0,0x2f,0x2b,0x17,0x3e,0x01,0x3d,0x01,0x34,0x36,0x37,0x2e,0x01,0x3d,0x01,0x34,0x26,0x27,0x37,0x1e,0x01,0x1d,0x01, +0x14,0x16,0x33,0x15,0x22,0x06,0x1d,0x01,0x14,0x06,0x07,0x15,0x6d,0x5e,0x5a,0x5e,0x5e,0x5a,0x5e,0x6d,0x29,0xc2,0xa5,0x65,0x6c,0x6c,0x65,0xa5,0xc2,0xf6,0x24,0xb3,0x84,0xcd,0x6b,0xa0,0x2b,0x29,0xa0,0x6d,0xce,0x84,0xb5,0x23,0x75,0x37,0xef,0xab,0xce,0x71,0x7b,0x93,0x7d,0x70,0xcd,0xaa,0xf0,0x37,0x00,0x00,0x00,0x01,0x00,0x80, +0x01,0x91,0x04,0xf0,0x03,0x23,0x00,0x19,0x00,0x44,0x40,0x0a,0x17,0x15,0x11,0x0f,0x0a,0x08,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2d,0x19,0x00,0x02,0x01,0x02,0x0d,0x0c,0x02,0x00,0x03,0x02,0x15,0x00,0x02,0x00,0x01,0x03,0x02,0x01,0x01,0x00,0x1d,0x00,0x03,0x00,0x00,0x03,0x01,0x00,0x1a,0x00,0x03,0x03,0x00, +0x01,0x00,0x1b,0x00,0x00,0x03,0x00,0x01,0x00,0x18,0x05,0xb0,0x2f,0x2b,0x01,0x14,0x06,0x23,0x22,0x26,0x27,0x2e,0x01,0x23,0x22,0x06,0x15,0x27,0x34,0x36,0x33,0x32,0x16,0x17,0x1e,0x01,0x33,0x32,0x36,0x35,0x04,0xf0,0xae,0x82,0x5a,0x93,0x55,0x3b,0x62,0x32,0x43,0x5f,0x8d,0xab,0x84,0x58,0x96,0x55,0x3a,0x60,0x34,0x42,0x61,0x02, +0xe4,0x89,0xca,0x42,0x4a,0x30,0x30,0x6a,0x4b,0x12,0x88,0xc1,0x45,0x46,0x33,0x2e,0x72,0x4d,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x90,0xfe,0x8a,0x01,0x55,0x04,0x3a,0x00,0x03,0x00,0x07,0x00,0x50,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x1a,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x0a,0x16,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x0c,0x00,0x17,0x04,0x1b,0x40,0x17,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x0a,0x02,0x17,0x03, +0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x33,0x11,0x23,0x35,0x33,0x01,0x55,0xc5,0xc5,0xc5,0xc5,0xfe,0x8a,0x03,0xd2,0x01,0x10,0xce,0x00,0x00,0x00,0x00,0x01,0x00,0x61,0xff,0x0b,0x03,0xda,0x05,0x26,0x00,0x23,0x00,0x65,0x40,0x12,0x01,0x00,0x1e,0x1c,0x1a,0x19,0x14,0x13,0x0a,0x09,0x04,0x03,0x00,0x23,0x01,0x23,0x07,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x46,0x15,0x12,0x02,0x05,0x03,0x18,0x01,0x04,0x05,0x05,0x01,0x00,0x01,0x0b,0x08,0x02,0x02,0x00,0x04,0x15,0x00,0x04,0x05,0x01,0x05,0x04,0x01,0x29,0x00,0x01,0x00,0x05,0x01,0x00,0x27,0x00,0x03,0x00,0x05,0x04,0x03,0x05,0x01,0x00,0x1d,0x06,0x01,0x00,0x02,0x02,0x00,0x01,0x00,0x1a,0x06,0x01,0x00,0x00, +0x02,0x00,0x00,0x1b,0x00,0x02,0x00,0x02,0x00,0x00,0x18,0x07,0xb0,0x2f,0x2b,0x25,0x32,0x36,0x35,0x33,0x17,0x16,0x06,0x07,0x15,0x23,0x35,0x26,0x02,0x3d,0x01,0x34,0x12,0x37,0x35,0x33,0x15,0x1e,0x01,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x02,0x3d,0x5b,0x88,0xb4,0x02,0x03,0xb2,0x83,0xc6,0xb8,0xc5,0xc6, +0xb7,0xc6,0x8c,0xaa,0x03,0x03,0xb4,0x81,0x62,0x91,0x85,0x83,0x85,0x79,0x58,0x05,0x74,0xc6,0x1f,0xed,0xe9,0x1f,0x01,0x28,0xcd,0x2a,0xca,0x01,0x28,0x21,0xe1,0xe3,0x1e,0xd1,0x8a,0x05,0x63,0x8b,0xe1,0xa0,0x2a,0xa3,0xe0,0x00,0x00,0x01,0x00,0x46,0x00,0x00,0x04,0x57,0x05,0xc5,0x00,0x22,0x00,0x5d,0x40,0x1a,0x00,0x00,0x00,0x22, +0x00,0x22,0x21,0x20,0x1d,0x1b,0x19,0x18,0x15,0x13,0x10,0x0f,0x0e,0x0d,0x09,0x08,0x07,0x06,0x05,0x04,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x36,0x17,0x01,0x06,0x07,0x01,0x15,0x00,0x06,0x07,0x04,0x07,0x06,0x04,0x29,0x08,0x01,0x04,0x0a,0x09,0x02,0x03,0x00,0x04,0x03,0x00,0x00,0x1d,0x00,0x07,0x07,0x05,0x01,0x00,0x1b, +0x00,0x05,0x05,0x0d,0x16,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x17,0x14,0x06,0x07,0x21,0x07,0x21,0x35,0x33,0x3e,0x01,0x35,0x27,0x23,0x35,0x33,0x03,0x34,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x13,0x21,0x15,0x01,0xae,0x06,0x1f,0x1d,0x02, +0xdf,0x01,0xfc,0x30,0x0a,0x30,0x30,0x06,0xa4,0x9e,0x0a,0xe0,0xbc,0xc8,0xdc,0x04,0x02,0xbe,0x7e,0x62,0x63,0x74,0x0a,0x01,0xa2,0x02,0x67,0x95,0x5a,0xa3,0x3b,0x9a,0x9a,0x0d,0xc4,0x67,0x95,0x9b,0x01,0x0e,0xcc,0xe9,0xd1,0xac,0x06,0x76,0x72,0x95,0x85,0xfe,0xf2,0x9b,0x00,0x02,0x00,0x68,0xff,0xe5,0x05,0x5a,0x04,0xf1,0x00,0x23, +0x00,0x2f,0x00,0x50,0x40,0x0a,0x2e,0x2c,0x28,0x26,0x16,0x14,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x39,0x1a,0x18,0x12,0x10,0x04,0x03,0x01,0x21,0x1b,0x0f,0x09,0x04,0x02,0x03,0x22,0x08,0x06,0x00,0x04,0x00,0x02,0x03,0x15,0x19,0x11,0x02,0x01,0x13,0x23,0x07,0x02,0x00,0x12,0x00,0x01,0x00,0x03,0x02,0x01,0x03, +0x01,0x00,0x1d,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x25,0x0e,0x01,0x23,0x22,0x26,0x27,0x07,0x27,0x37,0x2e,0x01,0x35,0x34,0x36,0x37,0x27,0x37,0x17,0x3e,0x01,0x33,0x32,0x16,0x17,0x37,0x17,0x07,0x1e,0x01,0x15,0x14,0x06,0x07,0x17,0x07,0x01,0x14,0x12,0x33,0x32,0x12,0x35,0x34, +0x02,0x23,0x22,0x02,0x04,0x49,0x4d,0xb9,0x65,0x65,0xb9,0x4b,0x82,0x8b,0x8a,0x32,0x35,0x39,0x36,0x92,0x8b,0x8f,0x4a,0xb2,0x60,0x61,0xb2,0x4b,0x92,0x8c,0x96,0x34,0x39,0x35,0x30,0x8e,0x8c,0xfc,0x73,0xf1,0xac,0xaa,0xf1,0xf1,0xaa,0xac,0xf1,0x6c,0x3e,0x42,0x41,0x3d,0x84,0x8a,0x8c,0x4c,0xb5,0x63,0x66,0xbc,0x4e,0x95,0x8b,0x92, +0x37,0x3d,0x3e,0x38,0x95,0x8c,0x99,0x4e,0xb9,0x65,0x62,0xb3,0x4c,0x8f,0x8b,0x02,0x7b,0xbc,0xfe,0xf7,0x01,0x09,0xbc,0xba,0x01,0x08,0xfe,0xf8,0x00,0x01,0x00,0x1e,0x00,0x00,0x04,0xaf,0x05,0xb0,0x00,0x16,0x00,0x50,0x40,0x18,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03, +0x02,0x01,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2b,0x00,0x01,0x01,0x00,0x01,0x15,0x09,0x01,0x01,0x08,0x01,0x02,0x03,0x01,0x02,0x00,0x02,0x1d,0x07,0x01,0x03,0x06,0x01,0x04,0x05,0x03,0x04,0x00,0x00,0x1d,0x0a,0x01,0x00,0x00,0x07,0x16,0x00,0x05,0x05,0x08,0x05,0x17,0x05,0xb0,0x2f,0x2b,0x09,0x01,0x33,0x01,0x21,0x15, +0x21,0x15,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x35,0x21,0x35,0x21,0x35,0x21,0x01,0x33,0x02,0x67,0x01,0x68,0xe0,0xfe,0x5e,0x01,0x38,0xfe,0x81,0x01,0x7f,0xfe,0x81,0xc5,0xfe,0x89,0x01,0x77,0xfe,0x89,0x01,0x37,0xfe,0x5d,0xe2,0x03,0x19,0x02,0x97,0xfd,0x32,0x7b,0xa7,0x7a,0xfe,0xba,0x01,0x46,0x7a,0xa7,0x7b,0x02,0xce,0x00,0x00, +0x00,0x02,0x00,0x91,0xfe,0xf2,0x01,0x56,0x05,0xb0,0x00,0x03,0x00,0x07,0x00,0x33,0x40,0x0e,0x00,0x00,0x07,0x06,0x05,0x04,0x00,0x03,0x00,0x03,0x02,0x01,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x18,0x00,0x00,0x04,0x01,0x01,0x00,0x01,0x00,0x00,0x1c,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x02,0x17,0x03, +0xb0,0x2f,0x2b,0x13,0x11,0x33,0x19,0x01,0x23,0x11,0x33,0x91,0xc5,0xc5,0xc5,0xfe,0xf2,0x03,0x18,0xfc,0xe8,0x03,0xc8,0x02,0xf6,0x00,0x00,0x00,0x00,0x02,0x00,0x5a,0xfe,0x11,0x04,0x7c,0x05,0xc5,0x00,0x33,0x00,0x45,0x00,0x52,0x40,0x0e,0x2c,0x2a,0x28,0x27,0x24,0x22,0x12,0x10,0x0e,0x0d,0x0a,0x08,0x06,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x37,0x26,0x01,0x04,0x05,0x40,0x37,0x1d,0x03,0x04,0x01,0x04,0x0c,0x01,0x02,0x01,0x03,0x15,0x00,0x04,0x05,0x01,0x05,0x04,0x01,0x29,0x00,0x01,0x02,0x05,0x01,0x02,0x27,0x00,0x02,0x00,0x00,0x02,0x00,0x01,0x00,0x1c,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x05,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x14, +0x06,0x07,0x1e,0x01,0x15,0x14,0x04,0x23,0x22,0x24,0x3f,0x02,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x27,0x2e,0x01,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x24,0x33,0x32,0x04,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x17,0x1e,0x01,0x25,0x2e,0x01,0x27,0x0e,0x01,0x15,0x14,0x16,0x17,0x1e,0x01,0x17,0x3e,0x01, +0x35,0x34,0x26,0x04,0x7c,0x60,0x57,0x45,0x46,0xfe,0xf6,0xe1,0xdd,0xfe,0xd2,0x05,0x02,0xbc,0xc1,0x87,0x89,0x9d,0x90,0xcc,0xef,0xe2,0x5e,0x57,0x44,0x44,0x01,0x0c,0xe0,0xe9,0x01,0x04,0x04,0x03,0xbc,0x9e,0x8c,0x91,0x96,0x86,0xd3,0xf4,0xdf,0xfd,0xdf,0x2f,0x53,0x24,0x49,0x49,0x88,0xd2,0x38,0x4a,0x21,0x48,0x50,0x93,0x01,0xaf, +0x5e,0x8c,0x28,0x33,0x88,0x62,0xac,0xc3,0xcd,0xdc,0x06,0x02,0x8f,0x87,0x77,0x5b,0x5b,0x65,0x3f,0x3f,0xba,0xb1,0x5b,0x8d,0x29,0x32,0x8b,0x61,0xa6,0xc9,0xdf,0xca,0x06,0x76,0x9e,0x77,0x5b,0x63,0x63,0x3a,0x45,0xb5,0x53,0x0c,0x19,0x0f,0x13,0x64,0x45,0x64,0x67,0x3b,0x11,0x16,0x0c,0x14,0x63,0x45,0x5b,0x6b,0x00,0x02,0x00,0xaa, +0x04,0xe8,0x03,0x5b,0x05,0xb0,0x00,0x03,0x00,0x07,0x00,0x27,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x10,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x03,0x01,0x01,0x01,0x07,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x01,0x23,0x35,0x33,0x05,0x23,0x35,0x33,0x03,0x5b,0xdb,0xdb,0xfe, +0x2a,0xdb,0xdb,0x04,0xe8,0xc8,0xc8,0xc8,0x00,0x03,0x00,0x58,0xff,0xeb,0x05,0xe3,0x05,0xc4,0x00,0x1d,0x00,0x29,0x00,0x35,0x00,0x6f,0x40,0x1a,0x00,0x00,0x34,0x32,0x2e,0x2c,0x28,0x26,0x22,0x20,0x00,0x1d,0x00,0x1d,0x1b,0x19,0x14,0x12,0x10,0x0f,0x0c,0x0a,0x05,0x03,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x48,0x0e,0x01, +0x02,0x03,0x01,0x01,0x04,0x05,0x02,0x15,0x00,0x02,0x03,0x05,0x03,0x02,0x05,0x29,0x0a,0x01,0x05,0x04,0x03,0x05,0x04,0x27,0x00,0x01,0x00,0x03,0x02,0x01,0x03,0x01,0x00,0x1d,0x00,0x04,0x00,0x00,0x06,0x04,0x00,0x01,0x00,0x1d,0x00,0x07,0x07,0x08,0x01,0x00,0x1b,0x00,0x08,0x08,0x0d,0x16,0x00,0x06,0x06,0x09,0x01,0x02,0x1b,0x00, +0x09,0x09,0x0e,0x09,0x17,0x09,0xb0,0x2f,0x2b,0x01,0x17,0x16,0x06,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x35,0x25,0x10,0x00,0x33,0x32,0x00,0x11,0x10,0x00,0x23,0x22,0x00,0x03,0x10,0x00,0x21,0x20,0x00,0x11,0x10,0x00,0x21,0x20,0x00,0x04, +0x57,0x02,0x04,0xb0,0x9d,0xa0,0xbc,0xbc,0xa0,0x9d,0xb1,0x04,0x02,0x92,0x5b,0x5b,0x5e,0x66,0x66,0x5e,0x5b,0x5a,0xfd,0x0c,0x01,0x57,0xf6,0xf5,0x01,0x58,0xfe,0xa8,0xf5,0xf6,0xfe,0xa9,0x79,0x01,0x9e,0x01,0x28,0x01,0x27,0x01,0x9e,0xfe,0x61,0xfe,0xda,0xfe,0xd8,0xfe,0x62,0x02,0x54,0x06,0x97,0x9d,0xd5,0xae,0x77,0xad,0xd6,0x9e, +0x95,0x06,0x5f,0x57,0x8d,0x72,0x78,0x75,0x8c,0x56,0x62,0x85,0xfe,0xf7,0xfe,0x94,0x01,0x6c,0x01,0x09,0x01,0x07,0x01,0x6a,0xfe,0x96,0xfe,0xf9,0x01,0x3b,0x01,0xb0,0xfe,0x50,0xfe,0xc5,0xfe,0xc4,0xfe,0x4e,0x01,0xb2,0x00,0x00,0x00,0x02,0x00,0x78,0x02,0xb4,0x03,0x13,0x05,0xc5,0x00,0x20,0x00,0x2b,0x00,0xd7,0x40,0x18,0x22,0x21, +0x00,0x00,0x27,0x25,0x21,0x2b,0x22,0x2b,0x00,0x20,0x00,0x20,0x1a,0x18,0x12,0x10,0x0d,0x0b,0x07,0x05,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x35,0x16,0x14,0x02,0x01,0x02,0x24,0x01,0x05,0x06,0x03,0x01,0x00,0x05,0x03,0x15,0x08,0x01,0x05,0x07,0x04,0x02,0x00,0x05,0x00,0x01,0x00,0x1c,0x00,0x02,0x02, +0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x16,0x00,0x06,0x06,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x06,0x17,0x06,0x1b,0x4b,0xb0,0x23,0x58,0x40,0x33,0x16,0x14,0x02,0x01,0x02,0x24,0x01,0x05,0x06,0x03,0x01,0x00,0x05,0x03,0x15,0x00,0x01,0x00,0x06,0x05,0x01,0x06,0x01,0x00,0x1d,0x08,0x01,0x05,0x07,0x04,0x02,0x00,0x05,0x00, +0x01,0x00,0x1c,0x00,0x02,0x02,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x02,0x17,0x05,0x1b,0x40,0x3a,0x16,0x14,0x02,0x01,0x02,0x24,0x01,0x05,0x06,0x03,0x01,0x04,0x05,0x03,0x15,0x07,0x01,0x04,0x05,0x00,0x05,0x04,0x00,0x29,0x00,0x01,0x00,0x06,0x05,0x01,0x06,0x01,0x00,0x1d,0x08,0x01,0x05,0x00,0x00,0x05,0x00,0x01,0x00,0x1c, +0x00,0x02,0x02,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x02,0x17,0x06,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x2e,0x01,0x27,0x0e,0x01,0x23,0x22,0x26,0x35,0x34,0x36,0x3b,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x2f,0x01,0x26,0x36,0x33,0x32,0x16,0x15,0x11,0x14,0x16,0x17,0x25,0x32,0x36,0x37,0x35,0x23,0x22,0x06,0x15,0x14,0x16,0x02, +0x65,0x08,0x0a,0x03,0x21,0x71,0x4d,0x77,0x82,0xa9,0xa1,0x8b,0x3c,0x3a,0x43,0x49,0xa2,0x01,0x06,0xa9,0x8c,0x86,0x9c,0x0c,0x0e,0xfe,0x88,0x33,0x6d,0x12,0x8a,0x4b,0x53,0x3a,0x02,0xc2,0x15,0x30,0x1a,0x2f,0x3e,0x7a,0x6a,0x6e,0x78,0x34,0x3f,0x44,0x36,0x31,0x0d,0x06,0x62,0x82,0x8e,0x86,0xfe,0xc6,0x32,0x58,0x2b,0x7d,0x3c,0x23, +0x6e,0x42,0x2e,0x2d,0x30,0x00,0x00,0x00,0xff,0xff,0x00,0x61,0x00,0x75,0x03,0x6b,0x03,0x92,0x00,0x26,0x03,0x43,0xf5,0xdd,0x01,0x07,0x03,0x43,0x01,0x44,0xff,0xdd,0x00,0x12,0xb1,0x00,0x01,0xb8,0xff,0xdd,0xb0,0x0d,0x2b,0xb1,0x01,0x01,0xb8,0xff,0xdd,0xb0,0x0d,0x2b,0x00,0x01,0x00,0x7f,0x01,0x77,0x03,0xc2,0x03,0x22,0x00,0x05, +0x00,0x56,0x40,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x0a,0x58,0x40,0x1d,0x00,0x00,0x01,0x01,0x00,0x20,0x00,0x02,0x01,0x01,0x02,0x00,0x00,0x1a,0x00,0x02,0x02,0x01,0x00,0x00,0x1b,0x00,0x01,0x02,0x01,0x00,0x00,0x18,0x04,0x1b,0x40,0x1c,0x00,0x00,0x01,0x00,0x2c,0x00,0x02,0x01, +0x01,0x02,0x00,0x00,0x1a,0x00,0x02,0x02,0x01,0x00,0x00,0x1b,0x00,0x01,0x02,0x01,0x00,0x00,0x18,0x04,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x21,0x35,0x21,0x03,0xc2,0xc6,0xfd,0x83,0x03,0x43,0x01,0x77,0x01,0x06,0xa5,0x00,0x00,0xff,0xff,0x00,0xa7,0x02,0x1a,0x02,0xf5,0x02,0xb4,0x02,0x06,0x00,0x10,0x00,0x00,0x00,0x04,0x00,0x58, +0xff,0xeb,0x05,0xe3,0x05,0xc4,0x00,0x0b,0x00,0x17,0x00,0x32,0x00,0x3b,0x00,0x69,0x40,0x1a,0x18,0x18,0x3b,0x39,0x35,0x33,0x18,0x32,0x18,0x31,0x2b,0x2a,0x1d,0x1b,0x1a,0x19,0x16,0x14,0x10,0x0e,0x0a,0x08,0x04,0x02,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x42,0x22,0x01,0x07,0x08,0x29,0x01,0x04,0x07,0x02,0x15,0x06,0x01, +0x04,0x07,0x02,0x07,0x04,0x02,0x29,0x00,0x05,0x00,0x09,0x08,0x05,0x09,0x01,0x00,0x1d,0x00,0x08,0x0a,0x01,0x07,0x04,0x08,0x07,0x01,0x00,0x1d,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x08,0xb0,0x2f,0x2b,0x13,0x10,0x00,0x21,0x20,0x00,0x11, +0x10,0x00,0x21,0x20,0x00,0x13,0x10,0x00,0x33,0x32,0x00,0x11,0x10,0x00,0x23,0x22,0x00,0x01,0x11,0x23,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x14,0x16,0x17,0x15,0x23,0x2e,0x01,0x3d,0x01,0x34,0x26,0x23,0x27,0x33,0x3e,0x01,0x35,0x34,0x26,0x2b,0x01,0x58,0x01,0x9e,0x01,0x28,0x01,0x27,0x01,0x9e,0xfe,0x61, +0xfe,0xda,0xfe,0xd8,0xfe,0x62,0x79,0x01,0x57,0xf6,0xf4,0x01,0x58,0xfe,0xa9,0xf5,0xf6,0xfe,0xa9,0x01,0xbc,0x95,0x01,0x18,0x98,0xad,0x42,0x3f,0x42,0x3b,0x07,0x0a,0x99,0x09,0x04,0x43,0x4d,0x9f,0x98,0x41,0x5b,0x4f,0x62,0x83,0x02,0xd9,0x01,0x3b,0x01,0xb0,0xfe,0x50,0xfe,0xc5,0xfe,0xc4,0xfe,0x4e,0x01,0xb2,0x01,0x3c,0xfe,0xf6, +0xfe,0x95,0x01,0x6c,0x01,0x09,0x01,0x08,0x01,0x69,0xfe,0x97,0xfe,0xad,0xfe,0xae,0x03,0x52,0x83,0x7e,0x3e,0x5e,0x1f,0x1a,0x6a,0x4b,0x38,0x29,0x41,0x15,0x10,0x15,0x51,0x2a,0x36,0x48,0x44,0x82,0x01,0x3f,0x38,0x49,0x3b,0x00,0x00,0x01,0x00,0x7b,0x05,0x1e,0x03,0x4c,0x05,0xb0,0x00,0x03,0x00,0x21,0x40,0x06,0x03,0x02,0x01,0x00, +0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0e,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x03,0x4c,0xfd,0x2f,0x02,0xd1,0x05,0x1e,0x92,0x00,0x02,0x00,0x80,0x03,0xbf,0x02,0x7d,0x05,0xc5,0x00,0x0b,0x00,0x17,0x00,0x31,0x40,0x0a,0x16,0x14,0x10,0x0e,0x0a,0x08, +0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0a,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x13,0x34,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x37,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22, +0x06,0x80,0x98,0x69,0x67,0x95,0x94,0x68,0x6a,0x97,0x83,0x49,0x35,0x34,0x47,0x48,0x33,0x35,0x49,0x04,0xc0,0x6a,0x9b,0x9b,0x6a,0x6c,0x95,0x95,0x6c,0x37,0x48,0x48,0x37,0x37,0x4b,0x4b,0x00,0x02,0x00,0x63,0x00,0x04,0x03,0xf7,0x04,0xf3,0x00,0x0b,0x00,0x0f,0x00,0x43,0x40,0x12,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06, +0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x04,0x01,0x00,0x03,0x01,0x01,0x02,0x00,0x01,0x00,0x00,0x1d,0x00,0x05,0x00,0x02,0x07,0x05,0x02,0x00,0x00,0x1d,0x00,0x07,0x07,0x06,0x00,0x00,0x1b,0x00,0x06,0x06,0x08,0x06,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x35, +0x21,0x11,0x33,0x01,0x21,0x35,0x21,0x02,0x91,0x01,0x66,0xfe,0x9a,0xb1,0xfe,0x83,0x01,0x7d,0xb1,0x01,0x3a,0xfc,0xbd,0x03,0x43,0x03,0x58,0x9a,0xfe,0x63,0x01,0x9d,0x9a,0x01,0x9b,0xfb,0x11,0x9b,0x00,0x00,0x00,0x01,0x00,0x71,0x02,0x9b,0x02,0xca,0x05,0xc7,0x00,0x1a,0x00,0x43,0x40,0x0c,0x1a,0x19,0x12,0x10,0x0d,0x0c,0x0a,0x08, +0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2a,0x0e,0x01,0x02,0x01,0x01,0x15,0x02,0x01,0x04,0x01,0x14,0x00,0x02,0x01,0x04,0x01,0x02,0x04,0x29,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x00,0x1c,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x01,0x3e,0x01,0x35, +0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x0f,0x01,0x17,0x21,0x02,0xca,0xfd,0xb0,0x01,0x2e,0x45,0x2c,0x39,0x3a,0x43,0x49,0xa1,0x02,0x06,0xa8,0x8d,0x87,0x98,0x59,0x74,0x99,0x02,0x01,0x69,0x02,0x9b,0x82,0x01,0x06,0x3c,0x4b,0x2a,0x32,0x3e,0x40,0x32,0x06,0x63,0x8c,0x80,0x74,0x50,0x70, +0x69,0x87,0x06,0x00,0x00,0x01,0x00,0x6a,0x02,0x8f,0x02,0xe4,0x05,0xc6,0x00,0x2a,0x00,0xad,0x40,0x16,0x01,0x00,0x29,0x27,0x23,0x21,0x1f,0x1e,0x1b,0x19,0x0f,0x0d,0x0a,0x09,0x07,0x05,0x00,0x2a,0x01,0x2a,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1d,0x58,0x40,0x42,0x0b,0x01,0x02,0x01,0x14,0x01,0x07,0x00,0x1d,0x01, +0x06,0x05,0x03,0x15,0x00,0x02,0x01,0x00,0x01,0x02,0x00,0x29,0x00,0x05,0x07,0x06,0x07,0x05,0x06,0x29,0x00,0x06,0x00,0x04,0x06,0x04,0x01,0x00,0x1c,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x16,0x00,0x07,0x07,0x00,0x01,0x00,0x1b,0x08,0x01,0x00,0x00,0x10,0x07,0x17,0x08,0x1b,0x40,0x40,0x0b,0x01,0x02,0x01,0x14, +0x01,0x07,0x00,0x1d,0x01,0x06,0x05,0x03,0x15,0x00,0x02,0x01,0x00,0x01,0x02,0x00,0x29,0x00,0x05,0x07,0x06,0x07,0x05,0x06,0x29,0x08,0x01,0x00,0x00,0x07,0x05,0x00,0x07,0x01,0x00,0x1d,0x00,0x06,0x00,0x04,0x06,0x04,0x01,0x00,0x1c,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x01,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x01, +0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x01,0xa8,0x43,0x41,0x49,0x45,0x38,0x45,0xa2,0x02,0x06,0xa9,0x7e,0x91,0xa8,0x47,0x3e,0x46,0x4c,0xb4,0x92,0x7f, +0xb5,0x06,0x01,0xa3,0x4b,0x3f,0x48,0x54,0x49,0x49,0x84,0x04,0x71,0x39,0x34,0x2b,0x3a,0x30,0x28,0x06,0x5e,0x77,0x77,0x6e,0x37,0x5b,0x1a,0x17,0x60,0x44,0x6f,0x7c,0x74,0x6f,0x06,0x2e,0x39,0x3b,0x30,0x3e,0x39,0x7e,0x00,0x00,0x00,0x01,0x00,0x83,0x04,0xe4,0x02,0x24,0x05,0xee,0x00,0x04,0x00,0x31,0x40,0x06,0x04,0x03,0x01,0x00, +0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x0c,0x00,0x01,0x00,0x01,0x2c,0x00,0x00,0x00,0x09,0x00,0x17,0x02,0x1b,0x40,0x0a,0x00,0x00,0x01,0x00,0x2b,0x00,0x01,0x01,0x22,0x02,0x59,0xb0,0x2f,0x2b,0x01,0x33,0x17,0x01,0x23,0x01,0x3c,0xe6,0x02,0xfe,0xf3,0x94,0x05,0xee,0x06,0xfe,0xfc,0x00,0x01,0x00,0x99, +0xfe,0x60,0x03,0xf2,0x04,0x3a,0x00,0x15,0x00,0x77,0x40,0x12,0x00,0x00,0x00,0x15,0x00,0x15,0x14,0x13,0x10,0x0e,0x0b,0x0a,0x09,0x08,0x05,0x03,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x26,0x07,0x01,0x00,0x01,0x12,0x0c,0x02,0x02,0x00,0x02,0x15,0x06,0x05,0x02,0x01,0x01,0x0a,0x16,0x00,0x00,0x00,0x02, +0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x08,0x16,0x00,0x04,0x04,0x0c,0x04,0x17,0x05,0x1b,0x40,0x2a,0x07,0x01,0x00,0x01,0x12,0x0c,0x02,0x02,0x00,0x02,0x15,0x06,0x05,0x02,0x01,0x01,0x0a,0x16,0x00,0x02,0x02,0x08,0x16,0x00,0x00,0x00,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x16,0x00,0x04,0x04,0x0c,0x04,0x17,0x06,0x59,0xb0,0x2f, +0x2b,0x01,0x11,0x1e,0x01,0x33,0x32,0x36,0x37,0x11,0x33,0x11,0x23,0x27,0x0e,0x01,0x23,0x22,0x26,0x27,0x11,0x23,0x11,0x01,0x5d,0x02,0x6f,0x64,0x62,0x79,0x20,0xc5,0xb1,0x09,0x2c,0x7f,0x53,0x48,0x6d,0x28,0xc4,0x04,0x3a,0xfd,0x7e,0xb2,0x81,0x48,0x46,0x03,0x27,0xfb,0xc6,0x6c,0x3f,0x42,0x21,0x23,0xfe,0x31,0x05,0xda,0x00,0x00, +0x00,0x01,0x00,0x3f,0x00,0x00,0x03,0x44,0x05,0xb0,0x00,0x0a,0x00,0x2d,0x40,0x0c,0x00,0x00,0x00,0x0a,0x00,0x0a,0x09,0x07,0x03,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x00,0x00,0x00,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x03,0x01,0x02,0x02,0x08,0x02,0x17,0x03,0xb0,0x2f,0x2b,0x21,0x11,0x23,0x22,0x00, +0x35,0x34,0x00,0x33,0x21,0x11,0x02,0x7f,0x54,0xe9,0xfe,0xfd,0x01,0x03,0xe9,0x01,0x19,0x02,0x08,0x01,0x03,0xd1,0xcf,0x01,0x05,0xfa,0x50,0x00,0x00,0x01,0x00,0xa1,0x02,0x70,0x01,0x67,0x03,0x44,0x00,0x03,0x00,0x2a,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x00,0x01,0x00,0x00,0x01,0x00, +0x00,0x1a,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x03,0xb0,0x2f,0x2b,0x01,0x23,0x35,0x33,0x01,0x67,0xc6,0xc6,0x02,0x70,0xd4,0x00,0x00,0x01,0x00,0x77,0xfe,0x4d,0x01,0xaf,0x00,0x00,0x00,0x0f,0x00,0x58,0x40,0x0c,0x00,0x00,0x00,0x0f,0x00,0x0f,0x09,0x08,0x07,0x06,0x04,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x4b,0xb0,0x09,0x58,0x40,0x1c,0x0e,0x01,0x02,0x01,0x02,0x01,0x15,0x03,0x01,0x02,0x01,0x01,0x02,0x1f,0x00,0x01,0x01,0x00,0x01,0x02,0x1b,0x00,0x00,0x00,0x12,0x00,0x17,0x04,0x1b,0x40,0x1b,0x0e,0x01,0x02,0x01,0x02,0x01,0x15,0x03,0x01,0x02,0x01,0x02,0x2b,0x00,0x01,0x01,0x00,0x01,0x02,0x1b,0x00,0x00,0x00,0x12,0x00, +0x17,0x04,0x59,0xb0,0x2f,0x2b,0x21,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x27,0x32,0x36,0x35,0x34,0x26,0x27,0x37,0x01,0x24,0x0c,0x41,0x56,0x9e,0x93,0x07,0x48,0x58,0x48,0x57,0x20,0x34,0x0b,0x52,0x50,0x60,0x72,0x6d,0x31,0x31,0x30,0x26,0x07,0x87,0x00,0x01,0x00,0x5f,0x02,0x99,0x01,0x8c,0x05,0xc5,0x00,0x05,0x00,0x22,0x40,0x06, +0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0f,0x05,0x04,0x02,0x01,0x13,0x00,0x01,0x00,0x01,0x2b,0x00,0x00,0x00,0x22,0x03,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x35,0x25,0x01,0x8c,0xae,0x7f,0x01,0x2d,0x02,0x99,0x02,0x8f,0x86,0x17,0x00,0x00,0x00,0x02,0x00,0x78,0x02,0xb3,0x03,0x2b,0x05,0xc5,0x00,0x0d, +0x00,0x1b,0x00,0x2e,0x40,0x0a,0x19,0x17,0x12,0x10,0x0b,0x09,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x00,0x02,0x00,0x01,0x02,0x01,0x01,0x00,0x1c,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x03,0x17,0x03,0xb0,0x2f,0x2b,0x13,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26,0x35, +0x33,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x78,0xbc,0x9d,0x9e,0xbc,0xbb,0x9d,0x9e,0xbd,0xad,0x58,0x56,0x53,0x59,0x5a,0x54,0x54,0x58,0x04,0x76,0x94,0xbb,0xbb,0x94,0x75,0x95,0xb9,0xb9,0x95,0x58,0x69,0x6a,0x57,0x75,0x54,0x6b,0x6b,0x54,0xff,0xff,0x00,0x74,0x00,0xaa,0x03,0x83,0x03,0xa2,0x00,0x26, +0x03,0x44,0x16,0x00,0x00,0x07,0x03,0x44,0x01,0x70,0x00,0x00,0xff,0xff,0x00,0xb8,0x00,0x00,0x05,0xe2,0x05,0xc4,0x00,0x27,0x04,0x03,0x00,0x59,0x02,0x98,0x00,0x27,0x03,0x46,0x01,0x18,0x00,0x08,0x01,0x07,0x03,0xff,0x02,0xba,0x00,0x00,0x00,0x11,0xb1,0x00,0x01,0xb8,0x02,0x98,0xb0,0x0d,0x2b,0xb1,0x01,0x01,0xb0,0x08,0xb0,0x0d, +0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0xb8,0x00,0x00,0x05,0xf5,0x05,0xc4,0x00,0x27,0x03,0x46,0x01,0x25,0x00,0x08,0x00,0x27,0x04,0x03,0x00,0x59,0x02,0x98,0x01,0x07,0x04,0x01,0x03,0x2b,0x00,0x00,0x00,0x11,0xb1,0x00,0x01,0xb0,0x08,0xb0,0x0d,0x2b,0xb1,0x01,0x01,0xb8,0x02,0x98,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x7a, +0x00,0x00,0x06,0x9f,0x05,0xc7,0x00,0x27,0x03,0x46,0x01,0xcf,0x00,0x08,0x00,0x27,0x03,0xff,0x03,0x77,0x00,0x00,0x01,0x07,0x04,0x00,0x00,0x10,0x02,0x9b,0x00,0x11,0xb1,0x00,0x01,0xb0,0x08,0xb0,0x0d,0x2b,0xb1,0x03,0x01,0xb8,0x02,0x9b,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x00,0x02,0x00,0x72,0xfe,0x76,0x03,0xad,0x04,0x3b,0x00,0x1a, +0x00,0x1e,0x00,0x84,0x40,0x12,0x00,0x00,0x1e,0x1d,0x1c,0x1b,0x00,0x1a,0x00,0x1a,0x12,0x10,0x0d,0x0c,0x0a,0x08,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x2e,0x58,0x40,0x30,0x0e,0x01,0x00,0x01,0x01,0x15,0x06,0x01,0x03,0x05,0x01,0x05,0x03,0x01,0x29,0x00,0x01,0x00,0x05,0x01,0x00,0x27,0x00,0x05,0x05,0x04,0x00,0x00, +0x1b,0x00,0x04,0x04,0x0a,0x16,0x00,0x00,0x00,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x0c,0x02,0x17,0x07,0x1b,0x40,0x2d,0x0e,0x01,0x00,0x01,0x01,0x15,0x06,0x01,0x03,0x05,0x01,0x05,0x03,0x01,0x29,0x00,0x01,0x00,0x05,0x01,0x00,0x27,0x00,0x00,0x00,0x02,0x00,0x02,0x01,0x02,0x1c,0x00,0x05,0x05,0x04,0x00,0x00,0x1b,0x00,0x04,0x04, +0x0a,0x05,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x01,0x0e,0x01,0x07,0x0e,0x01,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x33,0x17,0x16,0x06,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x3e,0x01,0x35,0x03,0x33,0x15,0x23,0x02,0x85,0x02,0x30,0x65,0x64,0x53,0x70,0x6a,0x5a,0x81,0xbc,0x03,0x02,0xe9,0xb3,0xc6,0xd9,0x8c,0x75,0x35,0x18,0x07,0xce,0xce, +0x02,0xa0,0x92,0x70,0x5b,0x76,0x7e,0x57,0x6a,0x72,0x63,0x60,0x06,0xa1,0xc2,0xc9,0xb4,0x7f,0xd5,0x72,0x35,0x56,0x5c,0x01,0x9b,0xd1,0x00,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x4b,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xf1,0x01,0x5d,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x47,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xab,0x01,0x59,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x48,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0xab,0x01,0x5d,0x00,0x09,0xb1,0x02, +0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x54,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0xa6,0x01,0x61,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x61,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x0d,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x00,0x6a, +0x00,0x86,0x01,0x5d,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x6f,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x01,0x56,0x01,0x32,0x01,0xaa,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0xaa,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0x0e,0x00,0x00,0x07,0x84,0x05,0xb0,0x00,0x0f, +0x00,0x13,0x00,0x56,0x40,0x14,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x35,0x12,0x01,0x05,0x04,0x01,0x15,0x00,0x05,0x00,0x06,0x08,0x05,0x06,0x00,0x00,0x1d,0x00,0x08,0x00,0x01,0x07,0x08,0x01,0x00,0x00,0x1d,0x00,0x04,0x04,0x03, +0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x07,0x07,0x00,0x00,0x00,0x1b,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x07,0xb0,0x2f,0x2b,0x29,0x01,0x03,0x21,0x03,0x23,0x01,0x21,0x15,0x21,0x13,0x21,0x15,0x21,0x13,0x21,0x01,0x21,0x03,0x27,0x07,0x84,0xfc,0x81,0x0f,0xfd,0xd3,0xc9,0xf2,0x03,0x71,0x03,0xc7,0xfd,0x4d,0x14,0x02,0x4e, +0xfd,0xb8,0x16,0x02,0xc1,0xfa,0xac,0x01,0xbf,0x1f,0x05,0x01,0x5e,0xfe,0xa2,0x05,0xb0,0x9b,0xfe,0x2e,0x9b,0xfd,0xf2,0x01,0x77,0x02,0xc6,0x02,0xff,0xff,0x00,0x76,0xfe,0x44,0x04,0xbf,0x05,0xc5,0x02,0x26,0x00,0x26,0x00,0x00,0x01,0x07,0x00,0x7a,0x01,0xce,0xff,0xf7,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x4b,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xd4,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x47,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x8e,0x01,0x59,0x00,0x09,0xb1,0x01, +0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x48,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0x8e,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x0d,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x00,0x6a, +0x00,0x69,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xdd,0x00,0x00,0x01,0x84,0x07,0x4b,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x00,0x43,0xff,0x8b,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xbe,0x00,0x00,0x02,0x68,0x07,0x47,0x02,0x26, +0x00,0x2c,0x00,0x00,0x01,0x07,0x00,0x76,0x00,0x44,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xf0,0x00,0x00,0x02,0x56,0x07,0x48,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x01,0x52,0xff,0x45,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xca, +0x00,0x00,0x02,0x7b,0x07,0x0d,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x00,0x6a,0xff,0x20,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x04,0xec,0x05,0xb0,0x00,0x0d,0x00,0x1b,0x00,0x4a,0x40,0x16,0x00,0x00,0x1b,0x1a,0x19,0x17,0x12,0x10,0x0f,0x0e,0x00,0x0d,0x00,0x0c, +0x07,0x05,0x04,0x03,0x02,0x01,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x27,0x07,0x01,0x01,0x04,0x01,0x00,0x05,0x01,0x00,0x00,0x00,0x1d,0x00,0x06,0x06,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x08,0x01,0x03,0x03,0x08,0x03,0x17,0x05,0xb0,0x2f,0x2b,0x33,0x11,0x23,0x35,0x33,0x11, +0x21,0x20,0x00,0x11,0x15,0x10,0x00,0x21,0x13,0x21,0x11,0x21,0x32,0x12,0x3d,0x01,0x34,0x02,0x23,0x21,0x11,0x21,0xaa,0xa8,0xa8,0x01,0xca,0x01,0x1d,0x01,0x5b,0xfe,0xa5,0xfe,0xe3,0x0f,0xfe,0xec,0x01,0x05,0xca,0xe9,0xe9,0xca,0xfe,0xfb,0x01,0x14,0x02,0x97,0x9b,0x02,0x7e,0xfe,0xa1,0xfe,0xea,0xc7,0xfe,0xe9,0xfe,0xa3,0x02,0x97, +0xfe,0x03,0x01,0x0a,0xd0,0xc9,0xce,0x01,0x0a,0xfe,0x1d,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xf7,0x07,0x54,0x02,0x26,0x00,0x31,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0xed,0x01,0x61,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x61,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x60,0x02,0x26,0x00,0x32,0x00,0x00, +0x01,0x07,0x00,0x43,0x01,0x23,0x01,0x72,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x5c,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xdd,0x01,0x6e,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x6e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02, +0x07,0x5d,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0xdd,0x01,0x72,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x69,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0xd8,0x01,0x76,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x76,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x22,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xb8,0x01,0x72,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x58,0x00,0xe1,0x03,0xe1,0x04,0x79,0x00,0x0b,0x00,0x07,0x40,0x02,0x00,0x07,0x2b,0x00,0x00,0x13,0x09,0x01,0x37,0x09,0x01,0x17, +0x09,0x01,0x07,0x09,0x01,0x58,0x01,0x47,0xfe,0xb9,0x7e,0x01,0x46,0x01,0x47,0x7e,0xfe,0xb8,0x01,0x48,0x7e,0xfe,0xb9,0xfe,0xba,0x01,0x5f,0x01,0x4e,0x01,0x4e,0x7e,0xfe,0xb3,0x01,0x4d,0x7e,0xfe,0xb2,0xfe,0xb2,0x7e,0x01,0x4c,0xfe,0xb4,0x00,0x00,0x00,0x03,0x00,0x71,0xff,0xa2,0x05,0x02,0x05,0xed,0x00,0x19,0x00,0x25,0x00,0x31, +0x00,0x93,0x40,0x0e,0x2f,0x2d,0x23,0x21,0x15,0x14,0x11,0x0f,0x08,0x07,0x04,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x38,0x13,0x01,0x04,0x02,0x1f,0x16,0x02,0x05,0x04,0x06,0x01,0x00,0x05,0x03,0x15,0x09,0x01,0x05,0x01,0x14,0x00,0x01,0x00,0x01,0x2c,0x00,0x03,0x03,0x09,0x16,0x00,0x04,0x04,0x02, +0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x08,0x1b,0x40,0x38,0x13,0x01,0x04,0x02,0x1f,0x16,0x02,0x05,0x04,0x06,0x01,0x00,0x05,0x03,0x15,0x09,0x01,0x05,0x01,0x14,0x00,0x03,0x02,0x03,0x2b,0x00,0x01,0x00,0x01,0x2c,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x00,0x02, +0x02,0x0d,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x08,0x59,0xb0,0x2f,0x2b,0x01,0x10,0x00,0x21,0x22,0x26,0x27,0x07,0x23,0x37,0x2e,0x01,0x35,0x11,0x10,0x00,0x33,0x32,0x16,0x17,0x37,0x33,0x07,0x1e,0x01,0x15,0x01,0x14,0x16,0x1f,0x01,0x01,0x2e,0x01,0x23,0x22,0x02,0x15,0x21,0x34,0x26,0x2f,0x01, +0x01,0x1e,0x01,0x33,0x32,0x36,0x35,0x05,0x02,0xfe,0xb5,0xfe,0xf8,0x55,0x97,0x40,0x5b,0x95,0x8b,0x54,0x59,0x01,0x3f,0xff,0x5e,0xa9,0x48,0x51,0x95,0x84,0x4d,0x55,0xfc,0x34,0x26,0x23,0x06,0x02,0x20,0x32,0x7c,0x48,0xac,0xcd,0x03,0x07,0x21,0x1e,0x06,0xfd,0xe3,0x2c,0x6a,0x3e,0xb7,0xd7,0x02,0x56,0xfe,0xf5,0xfe,0xa0,0x29,0x28, +0x9a,0xea,0x54,0xec,0x8a,0x01,0x03,0x01,0x0a,0x01,0x62,0x33,0x2e,0x89,0xdd,0x54,0xe2,0x81,0xfe,0xfd,0x55,0x92,0x34,0x01,0x03,0x94,0x29,0x2c,0xff,0x00,0xc8,0x4b,0x86,0x32,0x01,0xfc,0x71,0x22,0x22,0xff,0xcb,0x00,0x00,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0x4b,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x00,0x43, +0x01,0x22,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0x47,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xdc,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0x48,0x02,0x26, +0x00,0x38,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0xdc,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0x0d,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xb7,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x28, +0x00,0x00,0x04,0xe2,0x07,0x46,0x02,0x26,0x00,0x3c,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xa9,0x01,0x58,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x58,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0xa3,0x00,0x00,0x04,0x61,0x05,0xb0,0x00,0x0c,0x00,0x15,0x00,0x45,0x40,0x16,0x0d,0x0d,0x00,0x00,0x0d,0x15,0x0d,0x14,0x10,0x0e,0x00,0x0c,0x00,0x0c, +0x0b,0x0a,0x09,0x07,0x03,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x22,0x00,0x00,0x07,0x01,0x05,0x04,0x00,0x05,0x01,0x00,0x1d,0x00,0x04,0x00,0x01,0x02,0x04,0x01,0x01,0x00,0x1d,0x06,0x01,0x03,0x03,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11, +0x23,0x11,0x13,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x01,0x68,0x01,0x0d,0xe8,0x01,0x04,0xfe,0xfc,0xe8,0xfe,0xf3,0xc5,0xc5,0x01,0x0d,0x93,0x93,0x93,0x93,0x05,0xb0,0xfe,0xdb,0xec,0xbd,0xbe,0xeb,0xfe,0xc7,0x05,0xb0,0xfe,0x41,0xfd,0xe2,0x9c,0x71,0x72,0x9f,0x00,0x00,0x01,0x00,0x89,0xff,0xeb,0x04,0x70,0x06,0x13,0x00,0x27, +0x00,0x6f,0x40,0x0c,0x25,0x23,0x19,0x17,0x12,0x10,0x06,0x04,0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x25,0x15,0x01,0x03,0x04,0x14,0x01,0x00,0x03,0x02,0x15,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x09,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x02,0x01,0x00,0x00,0x08,0x00,0x17, +0x05,0x1b,0x40,0x29,0x15,0x01,0x03,0x04,0x14,0x01,0x00,0x03,0x02,0x15,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x09,0x16,0x00,0x00,0x00,0x08,0x16,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x34,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x15,0x14,0x00,0x15, +0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x34,0x00,0x35,0x34,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x4d,0xc4,0xeb,0xb7,0xa1,0xca,0x81,0x01,0x5b,0xd1,0xb2,0x54,0xb1,0x25,0x2c,0x2b,0x82,0x3d,0x6c,0x66,0xfe,0xa5,0x8d,0x66,0x42,0x68,0x80,0x04,0x3a,0xdf,0xfa,0xac,0xa7,0x76,0xdc,0x39,0x52,0xfe, +0xe4,0x8b,0xa7,0xaa,0x29,0x1e,0x9f,0x1c,0x30,0x5f,0x4e,0x54,0x01,0x1f,0x92,0x50,0xdd,0x4c,0x5d,0x6c,0xa7,0x98,0x00,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x09,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0x94,0x00,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x6a, +0xff,0xeb,0x03,0xf3,0x06,0x05,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x4e,0x00,0x17,0x00,0x08,0xb1,0x02,0x01,0xb0,0x17,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x06,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x01,0x52,0x4e,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b, +0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x12,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x01,0x58,0x49,0x1f,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1f,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x05,0xcb,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x00,0x6a,0x29,0x1b,0x00,0x08,0xb1,0x02,0x02,0xb0,0x1b,0xb0,0x0d,0x2b, +0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x2d,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x07,0x01,0x56,0x00,0xd5,0x00,0x68,0x00,0x08,0xb1,0x02,0x02,0xb0,0x68,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x03,0x00,0x58,0xff,0xeb,0x06,0x9a,0x04,0x4e,0x00,0x2e,0x00,0x39,0x00,0x42,0x00,0x73,0x40,0x26,0x3b,0x3a,0x30,0x2f,0x01,0x00,0x3f,0x3e, +0x3a,0x42,0x3b,0x42,0x35,0x33,0x2f,0x39,0x30,0x39,0x29,0x27,0x24,0x23,0x20,0x1e,0x1a,0x18,0x12,0x10,0x0d,0x0b,0x07,0x05,0x00,0x2e,0x01,0x2e,0x0f,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x40,0x1c,0x16,0x14,0x03,0x02,0x03,0x32,0x2b,0x25,0x03,0x04,0x07,0x06,0x2c,0x01,0x00,0x07,0x03,0x15,0x0b,0x01,0x02,0x09,0x01,0x06,0x07, +0x02,0x06,0x01,0x00,0x1d,0x0e,0x0a,0x02,0x03,0x03,0x04,0x01,0x00,0x1b,0x05,0x01,0x04,0x04,0x10,0x16,0x0d,0x08,0x02,0x07,0x07,0x00,0x01,0x00,0x1b,0x01,0x0c,0x02,0x00,0x00,0x0e,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x05,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x26,0x35,0x34,0x36,0x3b,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x2f,0x01, +0x26,0x36,0x33,0x32,0x16,0x17,0x3e,0x01,0x33,0x32,0x12,0x1d,0x01,0x21,0x07,0x1e,0x01,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x25,0x32,0x36,0x37,0x35,0x23,0x22,0x06,0x15,0x14,0x16,0x01,0x22,0x06,0x07,0x17,0x21,0x35,0x34,0x26,0x05,0x0c,0x88,0xd0,0x42,0x38,0xdf,0xa0,0xaa,0xb9,0xe6,0xdc,0xe5,0x68,0x61,0x67,0x7a,0xbc,0x02,0x05, +0xe6,0xbe,0x72,0xaf,0x32,0x40,0xaf,0x65,0xd6,0xe7,0xfd,0x3b,0x02,0x01,0x9d,0x9b,0x67,0x85,0x4e,0x43,0x35,0xbc,0xfc,0x4a,0x4c,0xa6,0x2b,0xe3,0x78,0x87,0x64,0x03,0x5c,0x71,0x8a,0x0b,0x02,0x01,0xfc,0x78,0x15,0x61,0x5a,0x4f,0x6c,0xae,0x97,0x9d,0xac,0x57,0x6a,0x79,0x6e,0x4e,0x12,0x06,0x8a,0xb5,0x51,0x4d,0x4b,0x53,0xfe,0xfc, +0xe4,0x77,0x05,0x9f,0xc6,0x37,0x33,0x8a,0x2c,0x4e,0x9a,0x57,0x39,0xd6,0x6f,0x50,0x4a,0x5d,0x03,0x2e,0xa9,0x85,0x05,0x1f,0x7a,0x9a,0x00,0x00,0xff,0xff,0x00,0x61,0xfe,0x44,0x03,0xd9,0x04,0x4e,0x02,0x26,0x00,0x46,0x00,0x00,0x01,0x07,0x00,0x7a,0x01,0x4b,0xff,0xf7,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x0a,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0x84,0x00,0x1c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x06,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x3e,0x00,0x18,0x00,0x08,0xb1,0x02, +0x01,0xb0,0x18,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x07,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x01,0x52,0x3e,0x1c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x05,0xcc,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x00,0x6a,0x19,0x1c,0x00,0x08, +0xb1,0x02,0x02,0xb0,0x1c,0xb0,0x0d,0x2b,0xff,0xff,0xff,0xb8,0x00,0x00,0x01,0x5e,0x05,0xf4,0x02,0x26,0x00,0xf3,0x00,0x00,0x01,0x07,0x00,0x43,0xff,0x66,0x00,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x02,0x43,0x05,0xf0,0x02,0x26,0x00,0xf3,0x00,0x00,0x01,0x06,0x00,0x76, +0x1f,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0xff,0xff,0xff,0xcb,0x00,0x00,0x02,0x31,0x05,0xf1,0x02,0x26,0x00,0xf3,0x00,0x00,0x01,0x07,0x01,0x52,0xff,0x20,0x00,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0xff,0xa5,0x00,0x00,0x02,0x56,0x05,0xb6,0x02,0x26,0x00,0xf3,0x00,0x00, +0x01,0x07,0x00,0x6a,0xfe,0xfb,0x00,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x02,0x00,0x48,0xff,0xeb,0x04,0x30,0x05,0xed,0x00,0x20,0x00,0x2d,0x00,0x4c,0x40,0x0e,0x22,0x21,0x29,0x27,0x21,0x2d,0x22,0x2d,0x0e,0x0c,0x08,0x06,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x31,0x11,0x10,0x02,0x03, +0x01,0x25,0x01,0x02,0x03,0x02,0x15,0x20,0x1f,0x1e,0x1b,0x1a,0x17,0x16,0x15,0x14,0x00,0x0a,0x01,0x13,0x00,0x01,0x00,0x03,0x02,0x01,0x03,0x01,0x00,0x1d,0x04,0x01,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x16,0x12,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x35,0x34,0x00,0x33,0x32,0x16, +0x17,0x37,0x2e,0x01,0x27,0x05,0x27,0x25,0x2e,0x01,0x27,0x37,0x1e,0x01,0x17,0x37,0x17,0x01,0x32,0x36,0x3d,0x01,0x2e,0x01,0x23,0x22,0x06,0x15,0x14,0x16,0x03,0x69,0x5f,0x68,0xfe,0xe0,0xd7,0xda,0xfe,0xe9,0x01,0x14,0xd5,0x5a,0x9f,0x34,0x04,0x09,0x55,0x44,0xfe,0xde,0x4d,0x01,0x00,0x27,0x53,0x2c,0x3c,0x4f,0x90,0x3f,0xda,0x4d, +0xfe,0x11,0x85,0xa9,0x23,0xa1,0x76,0x83,0xa1,0xa4,0x05,0x11,0x68,0xfe,0xed,0xa3,0xdc,0xf5,0xfe,0xc9,0x01,0x18,0xcf,0xe4,0x01,0x1c,0x4a,0x3c,0x05,0x6d,0xb0,0x42,0xa5,0x66,0x92,0x16,0x22,0x0e,0xa4,0x13,0x42,0x2e,0x7d,0x66,0xfb,0x04,0xe4,0xae,0x94,0x3b,0x51,0xd0,0x95,0x84,0xc9,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x03,0xfd, +0x06,0x12,0x02,0x26,0x00,0x51,0x00,0x00,0x01,0x06,0x01,0x58,0x60,0x1f,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1f,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0x09,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xaf,0x00,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61, +0xff,0xeb,0x04,0x2a,0x06,0x05,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x69,0x00,0x17,0x00,0x08,0xb1,0x02,0x01,0xb0,0x17,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0x06,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x01,0x52,0x69,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b, +0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0x12,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x01,0x58,0x64,0x1f,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1f,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x05,0xcb,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x00,0x6a,0x44,0x1b,0x00,0x08,0xb1,0x02,0x02,0xb0,0x1b,0xb0,0x0d,0x2b, +0x00,0x03,0x00,0x47,0x00,0xb4,0x04,0x2d,0x04,0xb2,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x46,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2b,0x00,0x03,0x00,0x02,0x01,0x03,0x02,0x00,0x00,0x1d,0x00,0x01,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x1d,0x00,0x05, +0x04,0x04,0x05,0x00,0x00,0x1a,0x00,0x05,0x05,0x04,0x00,0x00,0x1b,0x00,0x04,0x05,0x04,0x00,0x00,0x18,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x25,0x23,0x35,0x33,0x11,0x23,0x35,0x33,0x04,0x2d,0xfc,0x1a,0x03,0xe6,0xfe,0x71,0xc6,0xc6,0xc6,0xc6,0x02,0x55,0xbc,0xd6,0xcb,0xfc,0x02,0xcb,0x00,0x03,0x00,0x61,0xff,0x79,0x04,0x2a, +0x04,0xb9,0x00,0x19,0x00,0x25,0x00,0x31,0x00,0x5e,0x40,0x12,0x2f,0x2d,0x2a,0x29,0x23,0x21,0x1e,0x1d,0x15,0x14,0x11,0x0f,0x08,0x07,0x04,0x02,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3f,0x09,0x06,0x02,0x05,0x00,0x16,0x13,0x02,0x02,0x07,0x02,0x15,0x00,0x01,0x00,0x01,0x2b,0x00,0x06,0x05,0x04,0x05,0x06,0x04,0x29,0x00, +0x04,0x07,0x05,0x04,0x07,0x27,0x00,0x03,0x02,0x03,0x2c,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x07,0x07,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x09,0xb0,0x2f,0x2b,0x13,0x34,0x00,0x33,0x32,0x16,0x17,0x37,0x33,0x07,0x1e,0x01,0x1d,0x01,0x14,0x00,0x23,0x22,0x26,0x27,0x07,0x23,0x37,0x2e, +0x01,0x35,0x33,0x14,0x16,0x17,0x33,0x01,0x2e,0x01,0x23,0x22,0x06,0x15,0x21,0x34,0x26,0x27,0x23,0x01,0x1e,0x01,0x33,0x32,0x36,0x35,0x61,0x01,0x04,0xdf,0x38,0x67,0x2e,0x4a,0x81,0x68,0x58,0x5e,0xfe,0xfc,0xe0,0x33,0x5c,0x2a,0x48,0x81,0x64,0x60,0x67,0xc5,0x28,0x29,0x06,0x01,0x4c,0x1d,0x43,0x25,0x8d,0x91,0x02,0x3f,0x23,0x20, +0x06,0xfe,0xb9,0x18,0x38,0x21,0x8d,0x92,0x02,0x27,0xf0,0x01,0x37,0x16,0x14,0x95,0xd3,0x4a,0xe8,0x8d,0x16,0xf2,0xfe,0xcc,0x11,0x10,0x93,0xcc,0x47,0xf0,0x95,0x5b,0x97,0x30,0x02,0xa2,0x10,0x12,0xe2,0xaa,0x50,0x8d,0x2f,0xfd,0x69,0x0c,0x0b,0xe0,0xac,0x00,0x00,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x05,0xf4,0x02,0x26, +0x00,0x58,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xad,0x00,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x05,0xf0,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x67,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x8b, +0xff,0xeb,0x03,0xfc,0x05,0xf1,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x06,0x01,0x52,0x67,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x05,0xb6,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x06,0x00,0x6a,0x42,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x1a, +0xfe,0x4b,0x03,0xe8,0x05,0xf0,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x25,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x02,0x00,0x99,0xfe,0x60,0x04,0x33,0x06,0x18,0x00,0x11,0x00,0x1f,0x00,0x4e,0x40,0x0e,0x1d,0x1b,0x16,0x14,0x0f,0x0d,0x0a,0x09,0x08,0x07,0x04,0x02,0x06,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x33,0x0b,0x01,0x04,0x03,0x19,0x18,0x02,0x05,0x04,0x06,0x01,0x00,0x05,0x03,0x15,0x00,0x02,0x02,0x09,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x14, +0x02,0x23,0x22,0x26,0x27,0x11,0x23,0x11,0x33,0x11,0x3e,0x01,0x33,0x32,0x12,0x11,0x23,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x1e,0x01,0x33,0x32,0x36,0x35,0x04,0x33,0xe0,0xc5,0x64,0x97,0x35,0xc5,0xc5,0x35,0x96,0x62,0xc9,0xdf,0xc5,0x91,0x8d,0x55,0x78,0x25,0x25,0x78,0x57,0x8c,0x90,0x01,0xf4,0xea,0xfe,0xe1,0x43,0x43,0xfd,0xef, +0x07,0xb8,0xfd,0xaa,0x44,0x48,0xfe,0xc1,0xfe,0xfa,0xb8,0xed,0x4d,0x43,0xfd,0xf5,0x43,0x4b,0xcd,0xa2,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x05,0xb6,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x06,0x00,0x6a,0x00,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x06,0xfa,0x02,0x26, +0x00,0x24,0x00,0x00,0x01,0x07,0x00,0x71,0x00,0xaa,0x01,0x4a,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x4a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x05,0xb8,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x00,0x71,0x4d,0x08,0x00,0x08,0xb1,0x02,0x01,0xb0,0x08,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3, +0x07,0x4e,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0xdc,0x01,0x9e,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x0c,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x01,0x54,0x7f,0x5c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b, +0xfe,0x50,0x05,0x1a,0x05,0xb0,0x02,0x26,0x00,0x24,0x00,0x00,0x00,0x07,0x01,0x57,0x03,0x47,0x00,0x00,0xff,0xff,0x00,0x6a,0xfe,0x50,0x04,0x2a,0x04,0x4e,0x02,0x26,0x00,0x44,0x00,0x00,0x00,0x07,0x01,0x57,0x02,0x57,0x00,0x00,0xff,0xff,0x00,0x76,0xff,0xeb,0x04,0xbf,0x07,0x5c,0x02,0x26,0x00,0x26,0x00,0x00,0x01,0x07,0x00,0x76, +0x01,0xc9,0x01,0x6e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x6e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xd9,0x06,0x05,0x02,0x26,0x00,0x46,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x46,0x00,0x17,0x00,0x08,0xb1,0x01,0x01,0xb0,0x17,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x76,0xff,0xeb,0x04,0xbf,0x07,0x5d,0x02,0x26, +0x00,0x26,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0xc9,0x01,0x72,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xd9,0x06,0x06,0x02,0x26,0x00,0x46,0x00,0x00,0x01,0x06,0x01,0x52,0x46,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x76,0xff,0xeb,0x04,0xbf, +0x07,0x22,0x02,0x26,0x00,0x26,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x99,0x01,0x72,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xd9,0x05,0xcb,0x02,0x26,0x00,0x46,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x16,0x00,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00, +0xff,0xff,0x00,0x76,0xff,0xeb,0x04,0xbf,0x07,0x5e,0x02,0x26,0x00,0x26,0x00,0x00,0x01,0x07,0x01,0x53,0x00,0xe0,0x01,0x73,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x73,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xd9,0x06,0x07,0x02,0x26,0x00,0x46,0x00,0x00,0x01,0x06,0x01,0x53,0x5d,0x1c,0x00,0x08,0xb1,0x01,0x01,0xb0, +0x1c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xec,0x07,0x49,0x02,0x26,0x00,0x27,0x00,0x00,0x01,0x07,0x01,0x53,0x00,0x9d,0x01,0x5e,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x5e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x62,0xff,0xeb,0x05,0x1d,0x06,0x18,0x02,0x26,0x00,0x47,0x00,0x00,0x01,0x07,0x03,0x63,0x03,0xdd,0x05,0x25, +0x00,0x09,0xb1,0x02,0x01,0xb8,0x05,0x25,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x04,0xec,0x05,0xb0,0x00,0x0d,0x00,0x1b,0x00,0x4a,0x40,0x16,0x00,0x00,0x1b,0x1a,0x19,0x17,0x12,0x10,0x0f,0x0e,0x00,0x0d,0x00,0x0c,0x07,0x05,0x04,0x03,0x02,0x01,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x27,0x07,0x01,0x01,0x04, +0x01,0x00,0x05,0x01,0x00,0x00,0x00,0x1d,0x00,0x06,0x06,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x08,0x01,0x03,0x03,0x08,0x03,0x17,0x05,0xb0,0x2f,0x2b,0x33,0x11,0x23,0x35,0x33,0x11,0x21,0x20,0x00,0x11,0x15,0x10,0x00,0x21,0x13,0x21,0x11,0x21,0x32,0x12,0x3d,0x01,0x34,0x02,0x23,0x21, +0x11,0x21,0xaa,0xa8,0xa8,0x01,0xca,0x01,0x1d,0x01,0x5b,0xfe,0xa5,0xfe,0xe3,0x0f,0xfe,0xec,0x01,0x05,0xca,0xe9,0xe9,0xca,0xfe,0xfb,0x01,0x14,0x02,0x97,0x9b,0x02,0x7e,0xfe,0xa1,0xfe,0xea,0xc7,0xfe,0xe9,0xfe,0xa3,0x02,0x97,0xfe,0x03,0x01,0x0a,0xd0,0xc9,0xce,0x01,0x0a,0xfe,0x1d,0x00,0x00,0x02,0x00,0x62,0xff,0xeb,0x04,0xba, +0x06,0x18,0x00,0x19,0x00,0x27,0x00,0xa5,0x40,0x16,0x25,0x23,0x1e,0x1c,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x0f,0x0d,0x08,0x06,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x3b,0x11,0x01,0x09,0x03,0x21,0x20,0x02,0x08,0x09,0x04,0x01,0x01,0x08,0x03,0x15,0x07,0x01,0x05,0x04,0x01, +0x00,0x03,0x05,0x00,0x00,0x00,0x1d,0x00,0x06,0x06,0x09,0x16,0x00,0x09,0x09,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x08,0x08,0x01,0x01,0x00,0x1b,0x02,0x01,0x01,0x01,0x08,0x01,0x17,0x07,0x1b,0x40,0x3f,0x11,0x01,0x09,0x03,0x21,0x20,0x02,0x08,0x09,0x04,0x01,0x01,0x08,0x03,0x15,0x07,0x01,0x05,0x04,0x01,0x00,0x03, +0x05,0x00,0x00,0x00,0x1d,0x00,0x06,0x06,0x09,0x16,0x00,0x09,0x09,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x01,0x01,0x08,0x16,0x00,0x08,0x08,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x08,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x27,0x0e,0x01,0x23,0x22,0x02,0x3d,0x01,0x10,0x12,0x33,0x32,0x16,0x17,0x11, +0x23,0x35,0x33,0x35,0x33,0x15,0x33,0x01,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x2e,0x01,0x23,0x22,0x06,0x15,0x04,0xba,0xc5,0x97,0x1e,0x35,0x9c,0x67,0xc6,0xe0,0xdf,0xc9,0x5f,0x93,0x34,0xf7,0xf7,0xc5,0xc5,0xfc,0x6d,0x86,0x8d,0x58,0x78,0x26,0x26,0x79,0x55,0x8e,0x87,0x04,0xcf,0xfb,0x31,0x89,0x4e,0x50,0x01,0x1f,0xea,0x15,0x01, +0x05,0x01,0x40,0x46,0x43,0x01,0x0a,0x9b,0xae,0xae,0xfc,0x8a,0xa4,0xc5,0x50,0x48,0x01,0xf9,0x43,0x4f,0xea,0xbb,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x06,0xfa,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x00,0x71,0x00,0x8d,0x01,0x4a,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x4a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61, +0xff,0xeb,0x03,0xe2,0x05,0xb9,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x00,0x71,0x3d,0x09,0x00,0x08,0xb1,0x02,0x01,0xb0,0x09,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x4e,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0xbf,0x01,0x9e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x0d,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x01,0x54,0x6f,0x5d,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5d,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x0d,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x5e,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x05,0xcc,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x0e,0x00,0x1c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xaa,0xfe,0x50,0x04,0x2b,0x05,0xb0,0x02,0x26,0x00,0x28,0x00,0x00,0x00,0x07,0x01,0x57,0x01,0x29,0x00,0x00, +0xff,0xff,0x00,0x61,0xfe,0x8c,0x03,0xe2,0x04,0x4e,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x07,0x01,0x57,0x01,0xf0,0x00,0x3c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x3c,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x49,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x53,0x00,0xa5,0x01,0x5e,0x00,0x09,0xb1,0x01, +0x01,0xb8,0x01,0x5e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x08,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x01,0x53,0x55,0x1d,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1d,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x79,0xff,0xeb,0x04,0xc1,0x07,0x5d,0x02,0x26,0x00,0x2a,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0xc0,0x01,0x72, +0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6c,0xfe,0x4b,0x04,0x00,0x06,0x06,0x02,0x26,0x00,0x4a,0x00,0x00,0x01,0x06,0x01,0x52,0x5a,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x79,0xff,0xeb,0x04,0xc1,0x07,0x63,0x02,0x26,0x00,0x2a,0x00,0x00,0x01,0x07,0x01,0x54, +0x00,0xf1,0x01,0xb3,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0xb3,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6c,0xfe,0x4b,0x04,0x00,0x06,0x0c,0x02,0x26,0x00,0x4a,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0x8b,0x00,0x5c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5c,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x79,0xff,0xeb,0x04,0xc1,0x07,0x22,0x02,0x26, +0x00,0x2a,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x90,0x01,0x72,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6c,0xfe,0x4b,0x04,0x00,0x05,0xcb,0x02,0x26,0x00,0x4a,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x2a,0x00,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x79, +0xfe,0x11,0x04,0xc1,0x05,0xc5,0x02,0x26,0x00,0x2a,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0xa5,0xfe,0x97,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0x97,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6c,0xfe,0x4b,0x04,0x00,0x06,0x70,0x02,0x26,0x00,0x4a,0x00,0x00,0x01,0x07,0x03,0x73,0x01,0x2e,0x00,0x59,0x00,0x08,0xb1,0x02,0x01,0xb0,0x59,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xf7,0x07,0x48,0x02,0x26,0x00,0x2b,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0xeb,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x00,0x07,0x47,0x02,0x26,0x00,0x4b,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0x20,0x01,0x5c, +0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5c,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0x1f,0x00,0x00,0x05,0x8f,0x05,0xb0,0x00,0x13,0x00,0x17,0x00,0x4d,0x40,0x1a,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x26, +0x08,0x06,0x02,0x00,0x0b,0x05,0x02,0x01,0x0a,0x00,0x01,0x00,0x00,0x1d,0x00,0x0a,0x00,0x03,0x02,0x0a,0x03,0x00,0x00,0x1d,0x09,0x01,0x07,0x07,0x07,0x16,0x04,0x01,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x33,0x15,0x23,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x23,0x35,0x33,0x11,0x33,0x11,0x21,0x11,0x33,0x01,0x21,0x35, +0x21,0x04,0xff,0x90,0x90,0xc5,0xfd,0x3d,0xc5,0x93,0x93,0xc5,0x02,0xc3,0xc5,0xfc,0x78,0x02,0xc3,0xfd,0x3d,0x04,0x91,0x91,0xfc,0x00,0x02,0x83,0xfd,0x7d,0x04,0x00,0x91,0x01,0x1f,0xfe,0xe1,0x01,0x1f,0xfd,0x6e,0xe2,0x00,0x00,0x00,0x01,0xff,0xe4,0x00,0x00,0x04,0x00,0x06,0x18,0x00,0x1b,0x00,0x4d,0x40,0x14,0x1b,0x1a,0x19,0x18, +0x17,0x16,0x15,0x14,0x13,0x12,0x0f,0x0d,0x0a,0x09,0x06,0x04,0x01,0x00,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2c,0x11,0x02,0x02,0x02,0x03,0x01,0x15,0x08,0x01,0x06,0x05,0x01,0x00,0x01,0x06,0x00,0x00,0x00,0x1d,0x00,0x07,0x07,0x09,0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x16,0x04,0x01,0x02,0x02, +0x08,0x02,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x23,0x35,0x33,0x35,0x33,0x15,0x21,0x02,0x65,0xfe,0xef,0x38,0xa3,0x63,0xad,0xc1,0xc5,0x73,0x72,0x58,0x82,0x28,0xc5,0xab,0xab,0xc5,0x01,0x11,0x04,0xcf,0xfe,0xda,0x4e,0x57,0xd0,0xd8, +0xfd,0x5a,0x02,0xa8,0x86,0x80,0x45,0x3e,0xfc,0xd5,0x04,0xcf,0x9b,0xae,0xae,0x00,0xff,0xff,0xff,0xc7,0x00,0x00,0x02,0x7d,0x07,0x54,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x01,0x58,0xff,0x40,0x01,0x61,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x61,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xa2,0x00,0x00,0x02,0x58,0x05,0xfd,0x02,0x26, +0x00,0xf3,0x00,0x00,0x01,0x07,0x01,0x58,0xff,0x1b,0x00,0x0a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0xff,0xbf,0x00,0x00,0x02,0x90,0x06,0xfa,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x00,0x71,0xff,0x44,0x01,0x4a,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x4a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0x9a, +0x00,0x00,0x02,0x6b,0x05,0xa4,0x02,0x26,0x00,0xf3,0x00,0x00,0x01,0x07,0x00,0x71,0xff,0x1f,0xff,0xf4,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf4,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xf7,0x00,0x00,0x02,0x4e,0x07,0x4e,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x01,0x54,0xff,0x76,0x01,0x9e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x9e, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xd2,0x00,0x00,0x02,0x29,0x05,0xf7,0x02,0x26,0x00,0xf3,0x00,0x00,0x01,0x07,0x01,0x54,0xff,0x51,0x00,0x47,0x00,0x08,0xb1,0x01,0x01,0xb0,0x47,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x2d,0xfe,0x50,0x01,0xbc,0x05,0xb0,0x02,0x26,0x00,0x2c,0x00,0x00,0x00,0x06,0x01,0x57,0xe9,0x00,0x00,0x00, +0xff,0xff,0x00,0x0d,0xfe,0x50,0x01,0x9c,0x06,0x18,0x02,0x26,0x00,0x4c,0x00,0x00,0x00,0x06,0x01,0x57,0xc9,0x00,0x00,0x00,0xff,0xff,0x00,0xb4,0x00,0x00,0x01,0x8e,0x07,0x0d,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x01,0x55,0x00,0x14,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x99, +0x00,0x00,0x01,0x5e,0x04,0x3a,0x00,0x03,0x00,0x1f,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0c,0x00,0x01,0x01,0x0a,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x33,0x01,0x5e,0xc5,0xc5,0x04,0x3a,0x00,0xff,0xff,0x00,0xbe,0xff,0xeb,0x05,0xff,0x05,0xb0,0x00,0x26, +0x00,0x2c,0x00,0x00,0x00,0x07,0x00,0x2d,0x02,0x43,0x00,0x00,0xff,0xff,0x00,0x9f,0xfe,0x4b,0x03,0x76,0x06,0x18,0x00,0x26,0x00,0x4c,0x00,0x00,0x00,0x07,0x00,0x4d,0x02,0x04,0x00,0x00,0xff,0xff,0x00,0x4a,0xff,0xeb,0x04,0x85,0x07,0x3c,0x02,0x26,0x00,0x2d,0x00,0x00,0x01,0x07,0x01,0x52,0x01,0x74,0x01,0x51,0x00,0x09,0xb1,0x01, +0x01,0xb8,0x01,0x51,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xbc,0xfe,0x4b,0x02,0x43,0x05,0xde,0x02,0x26,0x01,0x50,0x00,0x00,0x01,0x07,0x01,0x52,0xff,0x32,0xff,0xf3,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf3,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0xfe,0x22,0x05,0x01,0x05,0xb0,0x02,0x26,0x00,0x2e,0x00,0x00,0x01,0x07,0x03,0x63, +0x01,0x78,0xfe,0xa8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xa8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x90,0xfe,0x24,0x04,0x0b,0x06,0x18,0x02,0x26,0x00,0x4e,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x1f,0xfe,0xaa,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xaa,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x04,0x40,0x04,0x3a,0x00,0x0e, +0x00,0x39,0x40,0x0e,0x0e,0x0d,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x0b,0x01,0x00,0x03,0x01,0x15,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x04,0x01,0x02,0x02,0x0a,0x16,0x05,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11, +0x33,0x11,0x33,0x01,0x33,0x17,0x09,0x01,0x07,0x23,0x01,0xc3,0x65,0xc5,0xc5,0x54,0x01,0x84,0xe7,0x02,0xfe,0x3e,0x01,0xe3,0x02,0xf1,0x01,0xcb,0xfe,0x35,0x04,0x3a,0xfe,0x37,0x01,0xc9,0x05,0xfd,0xfe,0xfd,0xd2,0x05,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x35,0x07,0x08,0x02,0x26,0x00,0x2f,0x00,0x00,0x01,0x07,0x00,0x76, +0x00,0x2d,0x01,0x1a,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x1a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x9f,0x00,0x00,0x02,0x49,0x07,0x53,0x02,0x26,0x00,0x4f,0x00,0x00,0x01,0x07,0x00,0x76,0x00,0x25,0x01,0x65,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x65,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0xfe,0x24,0x04,0x35,0x05,0xb0,0x02,0x26, +0x00,0x2f,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x72,0xfe,0xaa,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xaa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6e,0xfe,0x24,0x01,0x64,0x06,0x18,0x02,0x26,0x00,0x4f,0x00,0x00,0x01,0x07,0x03,0x63,0x00,0x09,0xfe,0xaa,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xaa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa, +0x00,0x00,0x04,0x35,0x05,0xb1,0x02,0x26,0x00,0x2f,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0xd8,0x04,0xbe,0x00,0x09,0xb1,0x01,0x01,0xb8,0x04,0xbe,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x9f,0x00,0x00,0x02,0xad,0x06,0x18,0x02,0x26,0x00,0x4f,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x6d,0x05,0x25,0x00,0x09,0xb1,0x01,0x01,0xb8,0x05,0x25, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x35,0x05,0xb0,0x02,0x26,0x00,0x2f,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0xbc,0xfd,0xc8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfd,0xc8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x9f,0x00,0x00,0x02,0x69,0x06,0x18,0x02,0x26,0x00,0x4f,0x00,0x00,0x01,0x07,0x01,0x55,0x00,0xef,0xfd,0xb7, +0x00,0x09,0xb1,0x01,0x01,0xb8,0xfd,0xb7,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x28,0x00,0x00,0x04,0x2e,0x05,0xb0,0x00,0x0d,0x00,0x35,0x40,0x08,0x0d,0x0c,0x07,0x06,0x05,0x04,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x20,0x0b,0x0a,0x09,0x08,0x03,0x02,0x01,0x00,0x08,0x00,0x02,0x01,0x15,0x00,0x02,0x02,0x07,0x16,0x00,0x00, +0x00,0x01,0x00,0x02,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x25,0x15,0x05,0x11,0x21,0x15,0x21,0x11,0x07,0x35,0x37,0x11,0x33,0x01,0x68,0x01,0x0d,0xfe,0xf3,0x02,0xc6,0xfc,0x75,0x7b,0x7b,0xc5,0x03,0x4b,0x56,0xa6,0x56,0xfd,0xf5,0x9a,0x02,0x67,0x27,0xa6,0x27,0x02,0xa3,0x00,0x00,0x00,0x00,0x01,0x00,0x25, +0x00,0x00,0x02,0x0e,0x06,0x18,0x00,0x0b,0x00,0x2c,0x40,0x06,0x0b,0x0a,0x05,0x04,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x19,0x09,0x08,0x07,0x06,0x03,0x02,0x01,0x00,0x08,0x00,0x01,0x01,0x15,0x00,0x01,0x01,0x09,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x37,0x15,0x07,0x11,0x23,0x11,0x07,0x35,0x37, +0x11,0x33,0x01,0x78,0x96,0x96,0xc5,0x8e,0x8e,0xc5,0x03,0x68,0x3a,0xa5,0x3a,0xfd,0x3d,0x02,0x78,0x36,0xa5,0x36,0x02,0xfb,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xf7,0x07,0x47,0x02,0x26,0x00,0x31,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xf2,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f, +0x00,0x00,0x03,0xfd,0x06,0x05,0x02,0x26,0x00,0x51,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x65,0x00,0x17,0x00,0x08,0xb1,0x01,0x01,0xb0,0x17,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xaa,0xfe,0x24,0x04,0xf7,0x05,0xb0,0x02,0x26,0x00,0x31,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0xd6,0xfe,0xaa,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xaa, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f,0xfe,0x24,0x03,0xfd,0x04,0x4e,0x02,0x26,0x00,0x51,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x49,0xfe,0xaa,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xaa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xf7,0x07,0x49,0x02,0x26,0x00,0x31,0x00,0x00,0x01,0x07,0x01,0x53,0x01,0x09,0x01,0x5e, +0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x03,0xfd,0x06,0x07,0x02,0x26,0x00,0x51,0x00,0x00,0x01,0x06,0x01,0x53,0x7c,0x1c,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0xff,0xff,0xff,0xdf,0x00,0x00,0x03,0xfd,0x06,0x18,0x02,0x26,0x00,0x51,0x00,0x00,0x01,0x07,0x03,0x63, +0xff,0x7a,0x05,0x25,0x00,0x09,0xb1,0x01,0x01,0xb8,0x05,0x25,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0xa1,0xfe,0x4b,0x04,0xee,0x05,0xb0,0x00,0x18,0x00,0x4b,0x40,0x10,0x00,0x00,0x00,0x18,0x00,0x18,0x15,0x14,0x13,0x12,0x0c,0x0a,0x05,0x03,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2e,0x17,0x11,0x02,0x02,0x03,0x08,0x01,0x01, +0x02,0x07,0x01,0x00,0x01,0x03,0x15,0x0f,0x01,0x02,0x01,0x14,0x05,0x04,0x02,0x03,0x03,0x07,0x16,0x00,0x02,0x02,0x08,0x16,0x00,0x01,0x01,0x00,0x01,0x02,0x1b,0x00,0x00,0x00,0x12,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x3d,0x01,0x01,0x07,0x11,0x23,0x11,0x33,0x01, +0x37,0x11,0x04,0xee,0xac,0x9a,0x1f,0x34,0x1d,0x0e,0x0d,0x44,0x11,0x3c,0x45,0xfd,0x43,0x06,0xc5,0xc5,0x02,0xbd,0x06,0x05,0xb0,0xf9,0xf7,0xa7,0xb5,0x09,0x09,0x96,0x05,0x08,0x67,0x5a,0x59,0x04,0x58,0x02,0xfb,0xaa,0x05,0xb0,0xfb,0xa8,0x02,0x04,0x56,0x00,0x00,0x00,0x00,0x01,0x00,0x8f,0xfe,0x4b,0x03,0xf5,0x04,0x4e,0x00,0x1f, +0x00,0x83,0x40,0x12,0x00,0x00,0x00,0x1f,0x00,0x1f,0x1e,0x1d,0x1a,0x18,0x13,0x11,0x0c,0x0a,0x05,0x03,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x2c,0x1c,0x01,0x02,0x04,0x03,0x0e,0x01,0x01,0x02,0x02,0x15,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x06,0x05,0x02,0x00,0x00,0x10,0x16,0x00,0x04,0x04,0x08,0x16, +0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x12,0x01,0x17,0x06,0x1b,0x40,0x30,0x1c,0x01,0x02,0x04,0x03,0x0e,0x01,0x01,0x02,0x02,0x15,0x06,0x01,0x05,0x05,0x0a,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x04,0x04,0x08,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x12,0x01,0x17, +0x07,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x01,0x3f,0x0d,0x36,0xa0,0x65,0xae,0xc0,0xac,0x9a,0x1f,0x35,0x1c,0x0e,0x0d,0x43,0x12,0x3d,0x44,0x72,0x74,0x55,0x7b,0x26,0xc5,0x04,0x3a, +0x96,0x51,0x59,0xcd,0xd6,0xfc,0xfc,0xa7,0xb5,0x09,0x09,0xa0,0x05,0x07,0x5e,0x58,0x03,0x00,0x8f,0x78,0x42,0x3b,0xfc,0xcf,0x04,0x3a,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x0f,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x00,0x71,0x00,0xdc,0x01,0x5f,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x5f,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x05,0xb8,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x00,0x71,0x68,0x08,0x00,0x08,0xb1,0x02,0x01,0xb0,0x08,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x63,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x01,0x54,0x01,0x0e,0x01,0xb3,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0xb3, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0x0c,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0x9a,0x00,0x5c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5c,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x60,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x01,0x59,0x01,0x6a,0x01,0x72, +0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x40,0x06,0x09,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x07,0x01,0x59,0x00,0xf6,0x00,0x1b,0x00,0x08,0xb1,0x02,0x02,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x02,0x00,0x68,0xff,0xeb,0x07,0x0a,0x05,0xc5,0x00,0x17,0x00,0x25,0x00,0xfb, +0x40,0x1a,0x19,0x18,0x20,0x1e,0x18,0x25,0x19,0x25,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0c,0x0a,0x05,0x03,0x01,0x00,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x33,0x1c,0x01,0x04,0x02,0x1b,0x01,0x00,0x07,0x02,0x15,0x00,0x05,0x00,0x06,0x07,0x05,0x06,0x00,0x00,0x1d,0x09,0x01,0x04,0x04, +0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x0d,0x16,0x0a,0x08,0x02,0x07,0x07,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x08,0x00,0x17,0x06,0x1b,0x4b,0xb0,0x19,0x58,0x40,0x4a,0x1c,0x01,0x04,0x09,0x1b,0x01,0x00,0x07,0x02,0x15,0x00,0x05,0x00,0x06,0x07,0x05,0x06,0x00,0x00,0x1d,0x00,0x09,0x09,0x02,0x01,0x00,0x1b,0x00,0x02,0x02, +0x0d,0x16,0x00,0x04,0x04,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x0a,0x08,0x02,0x07,0x07,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x08,0x16,0x0a,0x08,0x02,0x07,0x07,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x0a,0x1b,0x40,0x47,0x1c,0x01,0x04,0x09,0x1b,0x01,0x08,0x07,0x02,0x15,0x00,0x05,0x00,0x06,0x07,0x05,0x06, +0x00,0x00,0x1d,0x00,0x09,0x09,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x00,0x04,0x04,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x07,0x07,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x08,0x16,0x0a,0x01,0x08,0x08,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x0a,0x59,0x59,0xb0,0x2f,0x2b,0x29,0x01,0x0e,0x01,0x23, +0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x16,0x17,0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x05,0x32,0x36,0x37,0x11,0x2e,0x01,0x23,0x22,0x06,0x15,0x11,0x14,0x16,0x07,0x0a,0xfc,0xaf,0x5c,0x82,0x43,0xf9,0xfe,0xc9,0x01,0x35,0xf9,0x45,0x8f,0x4f,0x03,0x46,0xfd,0x4f,0x02,0x56,0xfd,0xaa,0x02,0xbc,0xfb,0x8e,0x3d,0x7a,0x3a, +0x3d,0x7a,0x3c,0xa9,0xc0,0xc2,0x0a,0x0b,0x01,0x4c,0x01,0x09,0x01,0x30,0x01,0x09,0x01,0x4c,0x0c,0x09,0x9b,0xfe,0x29,0x9b,0xfd,0xf7,0x14,0x09,0x09,0x04,0x7f,0x08,0x0b,0xe3,0xd5,0xfe,0xce,0xd6,0xe4,0x00,0x00,0x03,0x00,0x61,0xff,0xeb,0x06,0xee,0x04,0x4e,0x00,0x22,0x00,0x30,0x00,0x39,0x00,0x65,0x40,0x1e,0x32,0x31,0x01,0x00, +0x36,0x35,0x31,0x39,0x32,0x39,0x2e,0x2c,0x27,0x25,0x1d,0x1b,0x18,0x17,0x14,0x12,0x0e,0x0c,0x07,0x05,0x00,0x22,0x01,0x22,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3a,0x10,0x01,0x09,0x07,0x1f,0x19,0x03,0x03,0x05,0x04,0x20,0x01,0x00,0x05,0x03,0x15,0x00,0x09,0x00,0x04,0x05,0x09,0x04,0x00,0x00,0x1d,0x0b,0x08,0x02,0x07, +0x07,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x10,0x16,0x06,0x01,0x05,0x05,0x00,0x01,0x00,0x1b,0x01,0x0a,0x02,0x00,0x00,0x0e,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x05,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x00,0x3d,0x01,0x34,0x00,0x33,0x32,0x16,0x17,0x3e,0x01,0x33,0x32,0x12,0x1d,0x01,0x21,0x07,0x14,0x16,0x33,0x32,0x36,0x37,0x17, +0x0e,0x01,0x01,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x22,0x06,0x07,0x17,0x21,0x35,0x34,0x26,0x05,0x5b,0x87,0xcc,0x3f,0x40,0xc5,0x7e,0xe0,0xfe,0xfb,0x01,0x04,0xdf,0x80,0xc8,0x40,0x40,0xc0,0x70,0xd9,0xd9,0xfd,0x4c,0x03,0x90,0x94,0x64,0x97,0x36,0x4d,0x3a,0xbe,0xfb,0x45,0x91,0x8f,0x8d,0x92, +0x93,0x8e,0x8d,0x91,0x04,0x16,0x67,0x87,0x0f,0x02,0x01,0xe8,0x74,0x15,0x67,0x5f,0x5e,0x68,0x01,0x35,0xf1,0x16,0xf0,0x01,0x37,0x6c,0x60,0x60,0x6c,0xfe,0xf2,0xe0,0x68,0x05,0xa3,0xcb,0x39,0x32,0x80,0x38,0x4d,0x02,0x26,0xac,0xe0,0xe0,0xac,0x16,0xaa,0xe2,0xe2,0xaa,0x01,0x8c,0x9f,0x7c,0x05,0x10,0x76,0x9a,0xff,0xff,0x00,0xaa, +0x00,0x00,0x04,0xc6,0x07,0x47,0x02,0x26,0x00,0x35,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x85,0x01,0x59,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x02,0xe4,0x06,0x05,0x02,0x26,0x00,0x55,0x00,0x00,0x01,0x07,0x00,0x76,0x00,0xc0,0x00,0x17,0x00,0x08,0xb1,0x01,0x01,0xb0,0x17,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xaa,0xfe,0x24,0x04,0xc6,0x05,0xaf,0x02,0x26,0x00,0x35,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x69,0xfe,0xaa,0x00,0x09,0xb1,0x02,0x01,0xb8,0xfe,0xaa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6b,0xfe,0x24,0x02,0xaa,0x04,0x4e,0x02,0x26,0x00,0x55,0x00,0x00,0x01,0x07,0x03,0x63,0x00,0x06,0xfe,0xaa, +0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xaa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xc6,0x07,0x49,0x02,0x26,0x00,0x35,0x00,0x00,0x01,0x07,0x01,0x53,0x00,0x9c,0x01,0x5e,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x5e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x64,0x00,0x00,0x02,0xda,0x06,0x07,0x02,0x26,0x00,0x55,0x00,0x00, +0x01,0x06,0x01,0x53,0xd8,0x1c,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x6d,0xff,0xeb,0x04,0x77,0x07,0x5c,0x02,0x26,0x00,0x36,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x94,0x01,0x6e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x6e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x67,0xff,0xeb,0x03,0xc9,0x06,0x05,0x02,0x26, +0x00,0x56,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x3a,0x00,0x17,0x00,0x08,0xb1,0x01,0x01,0xb0,0x17,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x6d,0xff,0xeb,0x04,0x77,0x07,0x5d,0x02,0x26,0x00,0x36,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0x94,0x01,0x72,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x67, +0xff,0xeb,0x03,0xc9,0x06,0x06,0x02,0x26,0x00,0x56,0x00,0x00,0x01,0x06,0x01,0x52,0x3a,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x6d,0xfe,0x44,0x04,0x77,0x05,0xc5,0x02,0x26,0x00,0x36,0x00,0x00,0x01,0x07,0x00,0x7a,0x01,0x99,0xff,0xf7,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x67,0xfe,0x45,0x03,0xc9,0x04,0x4e,0x02,0x26,0x00,0x56,0x00,0x00,0x01,0x07,0x00,0x7a,0x01,0x3f,0xff,0xf8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6d,0xff,0xeb,0x04,0x77,0x07,0x5e,0x02,0x26,0x00,0x36,0x00,0x00,0x01,0x07,0x01,0x53,0x00,0xab,0x01,0x73,0x00,0x09,0xb1,0x01, +0x01,0xb8,0x01,0x73,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x67,0xff,0xeb,0x03,0xc9,0x06,0x07,0x02,0x26,0x00,0x56,0x00,0x00,0x01,0x06,0x01,0x53,0x51,0x1c,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x25,0xfe,0x24,0x04,0xa4,0x05,0xb0,0x02,0x26,0x00,0x37,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x6c,0xfe,0xaa, +0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xaa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x30,0xfe,0x1a,0x02,0x78,0x05,0x3f,0x02,0x26,0x00,0x57,0x00,0x00,0x01,0x07,0x03,0x63,0x00,0xdd,0xfe,0xa0,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xa0,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x25,0x00,0x00,0x04,0xa4,0x07,0x48,0x02,0x26,0x00,0x37,0x00,0x00, +0x01,0x07,0x01,0x53,0x00,0x9f,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x30,0xff,0xeb,0x03,0x09,0x06,0x33,0x02,0x26,0x00,0x57,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0xc9,0x05,0x40,0x00,0x09,0xb1,0x01,0x01,0xb8,0x05,0x40,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x25,0x00,0x00,0x04,0xa4, +0x05,0xb0,0x00,0x0f,0x00,0x3f,0x40,0x12,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x20,0x07,0x01,0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x06,0x01,0x04,0x04,0x05,0x00,0x00,0x1b,0x00,0x05,0x05,0x07,0x16,0x00,0x01,0x01,0x08,0x01, +0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x23,0x35,0x33,0x11,0x21,0x35,0x21,0x15,0x21,0x11,0x33,0x03,0xa0,0xdc,0xc5,0xe0,0xe0,0xfe,0x26,0x04,0x7f,0xfe,0x20,0xdc,0x03,0x34,0xfc,0xcc,0x03,0x34,0x9b,0x01,0x46,0x9b,0x9b,0xfe,0xba,0x00,0x00,0x01,0x00,0x06,0xff,0xeb,0x02,0x87,0x05,0x3f,0x00,0x1f,0x00,0x61,0x40,0x1c, +0x00,0x00,0x00,0x1f,0x00,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x14,0x12,0x0d,0x0b,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x38,0x0f,0x01,0x04,0x03,0x10,0x01,0x05,0x04,0x02,0x15,0x0b,0x01,0x0a,0x00,0x0a,0x2b,0x07,0x01,0x02,0x06,0x01,0x03,0x04,0x02,0x03,0x00,0x00,0x1d, +0x08,0x01,0x01,0x01,0x00,0x00,0x00,0x1b,0x09,0x01,0x00,0x00,0x0a,0x16,0x00,0x04,0x04,0x05,0x01,0x02,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x11,0x33,0x15,0x23,0x15,0x33,0x15,0x23,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x23,0x35,0x33,0x35,0x23,0x35,0x33,0x11,0x01, +0xa1,0xcd,0xcd,0xe6,0xe6,0x3f,0x34,0x11,0x2a,0x0e,0x1b,0x16,0x56,0x2a,0x78,0x8e,0xd6,0xd6,0xac,0xac,0x05,0x3f,0xfe,0xfb,0x92,0xb5,0x9b,0xfe,0xbf,0x4c,0x3e,0x09,0x05,0x87,0x12,0x17,0x91,0x9b,0x01,0x41,0x9b,0xb5,0x92,0x01,0x05,0x00,0x00,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0x54,0x02,0x26,0x00,0x38,0x00,0x00, +0x01,0x07,0x01,0x58,0x00,0xd7,0x01,0x61,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x61,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x05,0xfd,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x06,0x01,0x58,0x62,0x0a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x06,0xfa,0x02,0x26, +0x00,0x38,0x00,0x00,0x01,0x07,0x00,0x71,0x00,0xdb,0x01,0x4a,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x4a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x05,0xa4,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x06,0x00,0x71,0x66,0xf4,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf4,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x93, +0xff,0xeb,0x04,0xdc,0x07,0x4e,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x01,0x54,0x01,0x0d,0x01,0x9e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x05,0xf7,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0x98,0x00,0x47,0x00,0x08,0xb1,0x01,0x01,0xb0,0x47,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0x6f,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x01,0x56,0x01,0x63,0x01,0xaa,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0xaa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc,0x06,0x18,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x07,0x01,0x56,0x00,0xee,0x00,0x53, +0x00,0x08,0xb1,0x01,0x02,0xb0,0x53,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0x4b,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x01,0x59,0x01,0x69,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x04,0x3e,0x05,0xf4,0x02,0x26,0x00,0x58,0x00,0x00, +0x01,0x07,0x01,0x59,0x00,0xf4,0x00,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x93,0xfe,0x50,0x04,0xdc,0x05,0xb0,0x02,0x26,0x00,0x38,0x00,0x00,0x00,0x07,0x01,0x57,0x01,0xa9,0x00,0x00,0xff,0xff,0x00,0x8b,0xfe,0x50,0x04,0x32,0x04,0x3a,0x02,0x26,0x00,0x58,0x00,0x00,0x00,0x07,0x01,0x57, +0x02,0x5f,0x00,0x00,0xff,0xff,0x00,0x25,0x00,0x00,0x06,0xbf,0x07,0x48,0x02,0x26,0x00,0x3a,0x00,0x00,0x01,0x07,0x01,0x52,0x01,0x94,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2d,0x00,0x00,0x05,0xdc,0x05,0xf1,0x02,0x26,0x00,0x5a,0x00,0x00,0x01,0x07,0x01,0x52,0x01,0x28,0x00,0x06, +0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x28,0x00,0x00,0x04,0xe2,0x07,0x47,0x02,0x26,0x00,0x3c,0x00,0x00,0x01,0x07,0x01,0x52,0x00,0xa9,0x01,0x5c,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5c,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x05,0xf1,0x02,0x26,0x00,0x5c,0x00,0x00, +0x01,0x06,0x01,0x52,0x25,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x28,0x00,0x00,0x04,0xe2,0x07,0x0c,0x02,0x26,0x00,0x3c,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0x84,0x01,0x5c,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5c,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0x00,0x00,0x04,0x6d,0x07,0x47,0x02,0x26, +0x00,0x3d,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x84,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x5e,0x00,0x00,0x03,0xba,0x05,0xf0,0x02,0x26,0x00,0x5d,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x2f,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61, +0x00,0x00,0x04,0x6d,0x07,0x0d,0x02,0x26,0x00,0x3d,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x54,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x5e,0x00,0x00,0x03,0xba,0x05,0xb6,0x02,0x26,0x00,0x5d,0x00,0x00,0x01,0x07,0x01,0x55,0x00,0xff,0x00,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61,0x00,0x00,0x04,0x6d,0x07,0x49,0x02,0x26,0x00,0x3d,0x00,0x00,0x01,0x07,0x01,0x53,0x00,0x9b,0x01,0x5e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x5e,0x00,0x00,0x03,0xba,0x05,0xf2,0x02,0x26,0x00,0x5d,0x00,0x00,0x01,0x06,0x01,0x53,0x46,0x07,0x00,0x08, +0xb1,0x01,0x01,0xb0,0x07,0xb0,0x0d,0x2b,0x00,0x01,0x00,0x9f,0x00,0x00,0x02,0x87,0x06,0x2d,0x00,0x0f,0x00,0x33,0x40,0x0c,0x00,0x00,0x00,0x0f,0x00,0x0f,0x0c,0x0a,0x05,0x03,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x07,0x01,0x01,0x00,0x01,0x15,0x00,0x01,0x01,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0f,0x16,0x03,0x01, +0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x33,0x11,0x34,0x36,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x15,0x11,0x9f,0xb6,0xa2,0x21,0x45,0x2a,0x18,0x14,0x2c,0x19,0x57,0x5b,0x04,0xc3,0xad,0xbd,0x0b,0x0a,0x91,0x05,0x06,0x6d,0x62,0xfb,0x3d,0x00,0x00,0x00,0x01,0xff,0xe9,0xfe,0x4b,0x02,0xc0,0x06,0x2d,0x00,0x23, +0x00,0x55,0x40,0x12,0x23,0x22,0x1f,0x1d,0x18,0x16,0x13,0x12,0x11,0x10,0x0d,0x0b,0x06,0x04,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x36,0x1a,0x01,0x06,0x05,0x09,0x01,0x02,0x00,0x08,0x01,0x01,0x02,0x03,0x15,0x00,0x06,0x06,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0f,0x16,0x03,0x01,0x00,0x00,0x04,0x00,0x00,0x1b, +0x07,0x01,0x04,0x04,0x0a,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x12,0x01,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x23,0x35,0x33,0x35,0x34,0x36,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x33,0x02,0x61,0xc4,0xab,0x9a, +0x20,0x34,0x1b,0x0e,0x0c,0x43,0x12,0x3c,0x44,0xa9,0xa9,0xb5,0xa2,0x22,0x45,0x2a,0x18,0x12,0x33,0x1b,0x57,0x54,0xc4,0x03,0xa8,0xfb,0xff,0xa7,0xb5,0x09,0x09,0x96,0x05,0x08,0x67,0x5a,0x04,0x01,0x92,0x89,0xad,0xbd,0x0b,0x0a,0x96,0x04,0x06,0x67,0x62,0x89,0x00,0x00,0x00,0x02,0x00,0x6c,0xff,0xeb,0x05,0xff,0x06,0x75,0x00,0x17, +0x00,0x25,0x00,0x42,0x40,0x0c,0x23,0x21,0x1c,0x1a,0x11,0x10,0x0b,0x09,0x04,0x02,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x29,0x0d,0x01,0x03,0x01,0x14,0x01,0x04,0x03,0x02,0x15,0x00,0x02,0x01,0x02,0x2b,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e, +0x00,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x10,0x00,0x21,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x16,0x17,0x3e,0x01,0x35,0x33,0x14,0x06,0x07,0x1e,0x01,0x15,0x27,0x34,0x02,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32,0x36,0x35,0x04,0xfd,0xfe,0xb5,0xfe,0xf8,0xff,0xfe,0xc1,0x01,0x3f,0xff,0x78,0xce,0x4f,0x7b,0x80,0xc5,0xb0,0xa2, +0x26,0x2a,0xc5,0xd8,0xb6,0xac,0xcd,0xcd,0xac,0xb7,0xd7,0x02,0x56,0xfe,0xf5,0xfe,0xa0,0x01,0x60,0x01,0x0b,0x01,0x03,0x01,0x0a,0x01,0x62,0x50,0x49,0x0b,0xab,0x93,0xc0,0xf3,0x24,0x47,0xa6,0x58,0x02,0xc8,0x01,0x00,0xff,0x00,0xc8,0xfe,0xfb,0xca,0xff,0x00,0xff,0xcb,0x00,0x02,0x00,0x61,0xff,0xeb,0x04,0xe8,0x04,0xc7,0x00,0x17, +0x00,0x25,0x00,0x42,0x40,0x0c,0x23,0x21,0x1c,0x1a,0x15,0x13,0x0a,0x09,0x04,0x02,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x29,0x06,0x01,0x04,0x00,0x0d,0x01,0x03,0x04,0x02,0x15,0x00,0x01,0x00,0x01,0x2b,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e, +0x02,0x17,0x06,0xb0,0x2f,0x2b,0x13,0x34,0x00,0x33,0x32,0x16,0x17,0x3e,0x01,0x35,0x33,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x35,0x33,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x61,0x01,0x04,0xdf,0x66,0xaa,0x40,0x52,0x50,0xb2,0x85,0x81,0x23,0x25,0xfe,0xfc,0xe0,0xe0,0xfe,0xfb, +0xc5,0x91,0x8f,0x8d,0x92,0x93,0x8e,0x8d,0x91,0x02,0x27,0xf0,0x01,0x37,0x46,0x3f,0x12,0x84,0x68,0x8f,0xbc,0x20,0x42,0x9d,0x56,0x16,0xf2,0xfe,0xcc,0x01,0x35,0xf1,0xac,0xe0,0xe0,0xac,0x16,0xaa,0xe2,0xe2,0xaa,0x00,0x00,0x00,0x00,0x01,0x00,0x93,0xff,0xeb,0x06,0x57,0x06,0x37,0x00,0x1b,0x00,0x6f,0x40,0x10,0x00,0x00,0x00,0x1b, +0x00,0x1b,0x18,0x16,0x13,0x12,0x0f,0x0d,0x06,0x05,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x21,0x58,0x40,0x25,0x07,0x01,0x02,0x00,0x0a,0x01,0x02,0x03,0x02,0x02,0x15,0x00,0x00,0x00,0x09,0x16,0x05,0x04,0x02,0x02,0x02,0x07,0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x05,0x1b,0x40,0x25, +0x07,0x01,0x02,0x00,0x0a,0x01,0x02,0x03,0x02,0x02,0x15,0x00,0x00,0x02,0x00,0x2b,0x05,0x04,0x02,0x02,0x02,0x07,0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x15,0x17,0x3e,0x01,0x35,0x33,0x17,0x16,0x06,0x07,0x11,0x14,0x00,0x23,0x22,0x00,0x35,0x11,0x33,0x11,0x14,0x16, +0x33,0x32,0x36,0x35,0x11,0x04,0xdc,0x06,0x56,0x5c,0xbe,0x03,0x02,0xc4,0xb7,0xfe,0xc8,0xf6,0xed,0xfe,0xd2,0xc5,0xbf,0x97,0xa0,0xc9,0x05,0xb0,0xb2,0x02,0x1b,0xa3,0x7d,0x05,0xc1,0xf3,0x22,0xfd,0x8d,0xf0,0xfe,0xf2,0x01,0x0f,0xef,0x03,0xc7,0xfc,0x39,0xa7,0xbd,0xbd,0xa7,0x03,0xc7,0x00,0x00,0x01,0x00,0x8b,0xff,0xeb,0x05,0x6a, +0x04,0xcb,0x00,0x1d,0x00,0x8d,0x40,0x14,0x00,0x00,0x00,0x1d,0x00,0x1d,0x1b,0x1a,0x18,0x17,0x14,0x12,0x0f,0x0e,0x0b,0x09,0x06,0x05,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x30,0x01,0x01,0x02,0x06,0x19,0x16,0x07,0x04,0x04,0x03,0x05,0x02,0x15,0x07,0x01,0x06,0x02,0x06,0x2b,0x00,0x05,0x02,0x03,0x02, +0x05,0x03,0x29,0x04,0x01,0x02,0x02,0x0a,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x01,0x01,0x00,0x00,0x08,0x00,0x17,0x06,0x1b,0x40,0x34,0x01,0x01,0x02,0x06,0x19,0x16,0x07,0x04,0x04,0x03,0x05,0x02,0x15,0x07,0x01,0x06,0x02,0x06,0x2b,0x00,0x05,0x02,0x03,0x02,0x05,0x03,0x29,0x04,0x01,0x02,0x02,0x0a,0x16,0x00,0x00,0x00,0x08, +0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x16,0x06,0x07,0x11,0x23,0x27,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x33,0x15,0x17,0x3e,0x01,0x35,0x05,0x64,0x03,0x03,0xb1,0xbd,0xb1,0x0d,0x33,0xa0,0x69,0xb1,0xc6,0xc5,0x66, +0x6c,0x69,0x89,0x23,0xc5,0x06,0x64,0x55,0x04,0xcb,0x06,0xb1,0xc0,0x0e,0xfc,0xba,0xa0,0x57,0x5e,0xe2,0xef,0x02,0x7e,0xfd,0x80,0xad,0x82,0x55,0x4e,0x03,0x0c,0x72,0x02,0x07,0x80,0x7e,0xff,0xff,0xff,0xbc,0xfe,0x4b,0x02,0x4b,0x05,0xdf,0x02,0x26,0x01,0x50,0x00,0x00,0x01,0x07,0x01,0x53,0xff,0x49,0xff,0xf4,0x00,0x09,0xb1,0x01, +0x01,0xb8,0xff,0xf4,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x08,0x25,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x04,0x02,0x01,0x41,0x01,0xb3,0x00,0x09,0xb1,0x02,0x03,0xb8,0x01,0xb3,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0xe3,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x07,0x04,0x02, +0x00,0xe4,0x00,0x71,0x00,0x08,0xb1,0x02,0x03,0xb0,0x71,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x0e,0x00,0x00,0x07,0x84,0x07,0x47,0x02,0x26,0x00,0x88,0x00,0x00,0x01,0x07,0x00,0x76,0x02,0xee,0x01,0x59,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x58,0xff,0xeb,0x06,0x9a,0x06,0x06,0x02,0x26, +0x00,0xa8,0x00,0x00,0x01,0x07,0x00,0x76,0x02,0x9c,0x00,0x18,0x00,0x08,0xb1,0x03,0x01,0xb0,0x18,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xa2,0x05,0x02,0x07,0x85,0x02,0x26,0x00,0x9a,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xdd,0x01,0x97,0x00,0x09,0xb1,0x03,0x01,0xb8,0x01,0x97,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61, +0xff,0x79,0x04,0x2a,0x06,0x04,0x02,0x26,0x00,0xba,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x3e,0x00,0x16,0x00,0x08,0xb1,0x03,0x01,0xb0,0x16,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x6d,0xfe,0x10,0x04,0x77,0x05,0xc5,0x02,0x26,0x00,0x36,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x78,0xfe,0x96,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0x96, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x67,0xfe,0x11,0x03,0xc9,0x04,0x4e,0x02,0x26,0x00,0x56,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x1e,0xfe,0x97,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0x97,0xb0,0x0d,0x2b,0x00,0x00,0x01,0xff,0xbc,0xfe,0x4b,0x01,0x70,0x04,0x3a,0x00,0x0f,0x00,0x37,0x40,0x0c,0x00,0x00,0x00,0x0f,0x00,0x0f,0x0c,0x0a, +0x05,0x03,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x08,0x01,0x01,0x02,0x07,0x01,0x00,0x01,0x02,0x15,0x03,0x01,0x02,0x02,0x0a,0x16,0x00,0x01,0x01,0x00,0x01,0x02,0x1b,0x00,0x00,0x00,0x12,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x01,0x70,0xac, +0x99,0x1f,0x33,0x1d,0x0e,0x0e,0x41,0x12,0x3b,0x45,0x04,0x3a,0xfb,0x6d,0xa7,0xb5,0x09,0x09,0x96,0x05,0x08,0x67,0x5a,0x04,0x93,0x00,0x00,0x00,0xff,0xff,0x00,0xa0,0x03,0x95,0x01,0x66,0x05,0xb0,0x02,0x06,0x03,0x35,0x00,0x00,0x00,0x01,0x00,0xab,0x04,0xe4,0x03,0x11,0x05,0xeb,0x00,0x08,0x00,0x45,0x40,0x08,0x08,0x07,0x05,0x04, +0x02,0x01,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x15,0x06,0x03,0x00,0x03,0x00,0x02,0x01,0x15,0x01,0x01,0x00,0x02,0x00,0x2c,0x00,0x02,0x02,0x09,0x02,0x17,0x03,0x1b,0x40,0x13,0x06,0x03,0x00,0x03,0x00,0x02,0x01,0x15,0x00,0x02,0x00,0x02,0x2b,0x01,0x01,0x00,0x00,0x22,0x03,0x59,0xb0,0x2f,0x2b,0x01, +0x15,0x23,0x27,0x07,0x23,0x35,0x37,0x33,0x03,0x11,0xa1,0x93,0x92,0xa0,0xf6,0x78,0x04,0xfd,0x19,0x94,0x94,0x1a,0xed,0x00,0x00,0x01,0x00,0x8c,0x04,0xe4,0x03,0x02,0x05,0xeb,0x00,0x08,0x00,0x45,0x40,0x08,0x08,0x07,0x05,0x04,0x02,0x01,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x15,0x06,0x03,0x00,0x03, +0x01,0x00,0x01,0x15,0x00,0x01,0x00,0x01,0x2c,0x02,0x01,0x00,0x00,0x09,0x00,0x17,0x03,0x1b,0x40,0x13,0x06,0x03,0x00,0x03,0x01,0x00,0x01,0x15,0x02,0x01,0x00,0x01,0x00,0x2b,0x00,0x01,0x01,0x22,0x03,0x59,0xb0,0x2f,0x2b,0x01,0x37,0x33,0x15,0x05,0x23,0x27,0x35,0x33,0x01,0xc5,0x93,0xaa,0xfe,0xff,0x77,0xfe,0xa6,0x05,0x57,0x94, +0x12,0xf5,0xf3,0x14,0x00,0x01,0x00,0x81,0x04,0xa4,0x02,0xd8,0x05,0xb0,0x00,0x0f,0x00,0x34,0x40,0x0e,0x00,0x00,0x00,0x0f,0x00,0x0f,0x0d,0x0b,0x09,0x08,0x05,0x03,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x19,0x07,0x01,0x02,0x02,0x01,0x01,0x15,0x00,0x02,0x00,0x00,0x02,0x00,0x01,0x00,0x1c,0x04,0x03,0x02,0x01,0x01,0x07, +0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x17,0x16,0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x02,0xd2,0x02,0x04,0xa2,0x89,0x8a,0xa2,0x05,0x02,0x97,0x44,0x4a,0x48,0x46,0x05,0xb0,0x06,0x74,0x92,0x92,0x74,0x06,0x42,0x52,0x53,0x41,0x00,0x00,0x00,0x00,0x01,0x00,0xa0,0x04,0xe7,0x01,0x7a,0x05,0xb0,0x00,0x03, +0x00,0x21,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0e,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x00,0x17,0x02,0xb0,0x2f,0x2b,0x01,0x23,0x35,0x33,0x01,0x7a,0xda,0xda,0x04,0xe7,0xc9,0x00,0x00,0x00,0x02,0x00,0xa5,0x04,0x78,0x02,0x02,0x05,0xc5,0x00,0x0b,0x00,0x17,0x00,0x2e, +0x40,0x0a,0x16,0x14,0x10,0x0e,0x0a,0x08,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x00,0x02,0x00,0x01,0x02,0x01,0x01,0x00,0x1c,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x03,0x17,0x03,0xb0,0x2f,0x2b,0x13,0x34,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x37,0x14,0x16,0x33,0x32,0x36, +0x35,0x34,0x26,0x23,0x22,0x06,0xa5,0x67,0x49,0x48,0x65,0x65,0x48,0x4a,0x66,0x64,0x2d,0x1f,0x1e,0x2b,0x2b,0x1e,0x20,0x2c,0x05,0x1c,0x48,0x61,0x61,0x48,0x49,0x5b,0x5c,0x48,0x1f,0x2b,0x2a,0x20,0x20,0x2d,0x2d,0x00,0x00,0x00,0x00,0x01,0x00,0x44,0xfe,0x50,0x01,0xd3,0x00,0x39,0x00,0x13,0x00,0x2d,0x40,0x06,0x0e,0x0c,0x07,0x05, +0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x0a,0x01,0x01,0x00,0x01,0x15,0x13,0x09,0x00,0x03,0x00,0x13,0x00,0x00,0x00,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x12,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x21,0x0e,0x01,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x01,0x84,0x46,0x4f,0x2d, +0x33,0x1b,0x2e,0x1a,0x21,0x24,0x57,0x3c,0x5f,0x79,0x79,0x7f,0x34,0x5f,0x36,0x2a,0x30,0x0f,0x0b,0x7b,0x13,0x19,0x6e,0x63,0x50,0x90,0x38,0x00,0x00,0x01,0x00,0x87,0x04,0xe1,0x03,0x3d,0x05,0xf3,0x00,0x13,0x00,0xaf,0x40,0x0a,0x11,0x0f,0x0e,0x0c,0x07,0x05,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58, +0x40,0x2c,0x00,0x01,0x03,0x02,0x0a,0x01,0x00,0x01,0x02,0x15,0x13,0x01,0x02,0x13,0x09,0x01,0x00,0x12,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x00,0x00,0x00,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x07,0x00,0x17,0x07,0x1b,0x4b,0xb0,0x24,0x58,0x40,0x29,0x00,0x01,0x03,0x02,0x0a,0x01,0x00,0x01,0x02,0x15,0x13, +0x01,0x02,0x13,0x09,0x01,0x00,0x12,0x00,0x03,0x00,0x00,0x03,0x00,0x01,0x00,0x1c,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x01,0x17,0x06,0x1b,0x40,0x33,0x00,0x01,0x03,0x02,0x0a,0x01,0x00,0x01,0x02,0x15,0x13,0x01,0x02,0x13,0x09,0x01,0x00,0x12,0x00,0x03,0x01,0x00,0x03,0x01,0x00,0x1a,0x00,0x02,0x00,0x01,0x00, +0x02,0x01,0x01,0x00,0x1d,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x03,0x00,0x01,0x00,0x18,0x07,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x14,0x06,0x23,0x22,0x26,0x23,0x22,0x06,0x15,0x27,0x34,0x36,0x33,0x32,0x16,0x33,0x32,0x36,0x35,0x03,0x3d,0x77,0x5a,0x47,0x9a,0x33,0x2b,0x3a,0x6c,0x76,0x5b,0x38,0xa8,0x34,0x29,0x3c,0x05,0xd3, +0x5e,0x82,0x5d,0x41,0x2e,0x1a,0x5d,0x89,0x5e,0x41,0x2f,0x00,0x00,0x02,0x00,0x64,0x04,0xe4,0x03,0x4a,0x05,0xee,0x00,0x05,0x00,0x0a,0x00,0x49,0x40,0x0a,0x0a,0x09,0x07,0x06,0x04,0x03,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x10,0x03,0x01,0x01,0x01,0x00,0x00,0x00,0x1b,0x02,0x01,0x00,0x00, +0x09,0x01,0x17,0x02,0x1b,0x40,0x1a,0x02,0x01,0x00,0x01,0x01,0x00,0x00,0x00,0x1a,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x03,0x01,0x01,0x00,0x01,0x00,0x00,0x18,0x03,0x59,0xb0,0x2f,0x2b,0x01,0x33,0x17,0x01,0x23,0x27,0x03,0x33,0x17,0x03,0x23,0x02,0x62,0xe5,0x03,0xfe,0xd4,0xab,0x02,0x55,0xd3,0x02,0xf0,0x9d,0x05,0xee,0x06, +0xfe,0xfc,0x05,0x01,0x05,0x05,0xfe,0xfb,0x00,0x02,0x00,0xb6,0xfe,0x85,0x01,0xec,0xff,0xac,0x00,0x0b,0x00,0x17,0x00,0x58,0x40,0x0a,0x16,0x14,0x10,0x0e,0x0a,0x08,0x04,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1b,0x58,0x40,0x18,0x00,0x00,0x00,0x03,0x02,0x00,0x03,0x01,0x00,0x1d,0x00,0x02,0x02,0x01,0x01,0x00, +0x1b,0x00,0x01,0x01,0x0c,0x01,0x17,0x03,0x1b,0x40,0x21,0x00,0x00,0x00,0x03,0x02,0x00,0x03,0x01,0x00,0x1d,0x00,0x02,0x01,0x01,0x02,0x01,0x00,0x1a,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x02,0x01,0x01,0x00,0x18,0x04,0x59,0xb0,0x2f,0x2b,0x17,0x34,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x37,0x14,0x16,0x33, +0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0xb6,0x5b,0x42,0x3f,0x5a,0x59,0x40,0x42,0x5b,0x59,0x28,0x1c,0x1a,0x26,0x26,0x1a,0x1c,0x28,0xea,0x41,0x55,0x55,0x41,0x3f,0x52,0x52,0x3f,0x1a,0x26,0x25,0x1b,0x1e,0x27,0x28,0x00,0x00,0xff,0xff,0xfc,0xe6,0x04,0xf0,0xfe,0x02,0x06,0x4f,0x01,0x47,0x00,0x43,0xfc,0xad,0xfe,0x7b,0x2c,0x9c, +0x54,0x80,0x00,0x09,0xb1,0x00,0x01,0xb8,0xfe,0x7b,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0xfd,0x81,0x04,0xef,0xfe,0x9e,0x06,0x50,0x01,0x47,0x00,0x76,0xfd,0x28,0xfe,0x76,0x2b,0xb1,0x54,0xc0,0x00,0x09,0xb1,0x00,0x01,0xb8,0xfe,0x76,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0xfc,0x8c,0x04,0xe1,0xff,0x42,0x05,0xf3,0x00,0x07, +0x01,0x58,0xfc,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0xfd,0x5b,0x04,0xda,0xfe,0x93,0x06,0x76,0x00,0x0f,0x00,0x43,0x40,0x0e,0x00,0x00,0x00,0x0f,0x00,0x0f,0x09,0x08,0x07,0x06,0x02,0x01,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x28,0x0e,0x01,0x03,0x00,0x01,0x15,0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x01,0x00,0x1d,0x00,0x00, +0x03,0x03,0x00,0x01,0x00,0x1a,0x00,0x00,0x00,0x03,0x00,0x00,0x1b,0x04,0x01,0x03,0x00,0x03,0x00,0x00,0x18,0x05,0xb0,0x2f,0x2b,0x01,0x27,0x3e,0x01,0x35,0x34,0x26,0x23,0x37,0x32,0x16,0x15,0x14,0x06,0x0f,0x01,0xfd,0x6f,0x01,0x4c,0x41,0x57,0x49,0x07,0x93,0x9e,0x56,0x41,0x01,0x04,0xda,0x9a,0x04,0x20,0x25,0x27,0x26,0x6c,0x67, +0x56,0x46,0x49,0x09,0x47,0x00,0x00,0x00,0x00,0x02,0xfc,0x2c,0x04,0xe4,0xff,0x12,0x05,0xee,0x00,0x05,0x00,0x0a,0x00,0x49,0x40,0x0a,0x0a,0x09,0x07,0x06,0x05,0x04,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x10,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x03,0x01,0x01,0x01,0x09,0x00,0x17,0x02, +0x1b,0x40,0x1a,0x03,0x01,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x03,0x01,0x01,0x01,0x00,0x00,0x00,0x1b,0x02,0x01,0x00,0x01,0x00,0x00,0x00,0x18,0x03,0x59,0xb0,0x2f,0x2b,0x01,0x07,0x23,0x01,0x37,0x33,0x01,0x23,0x03,0x37,0x33,0xfe,0x05,0x02,0xab,0xfe,0xd4,0x03,0xe5,0x01,0xfe,0x9d,0xf1,0x02,0xd4,0x04,0xe9,0x05,0x01,0x04,0x06, +0xfe,0xf6,0x01,0x05,0x05,0x00,0x00,0x00,0x00,0x01,0xfd,0x3c,0xfe,0xaf,0xfe,0x16,0xff,0x77,0x00,0x03,0x00,0x2a,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x03,0xb0,0x2f,0x2b, +0x01,0x23,0x35,0x33,0xfe,0x16,0xda,0xda,0xfe,0xaf,0xc8,0x00,0x00,0x01,0x00,0xce,0x04,0xf8,0x01,0xbc,0x06,0x07,0x00,0x03,0x00,0x21,0x40,0x06,0x03,0x02,0x01,0x00,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x0e,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x09,0x01,0x17,0x02,0xb0,0x2f,0x2b,0x13,0x33,0x03,0x23,0xec, +0xd0,0x9b,0x53,0x06,0x07,0xfe,0xf1,0x00,0x00,0x03,0x00,0xa1,0x04,0xe8,0x03,0x65,0x06,0xc2,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x35,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x04,0x00,0x05,0x01,0x04,0x05,0x00,0x00,0x1d,0x02,0x01,0x00,0x00, +0x01,0x00,0x00,0x1b,0x03,0x01,0x01,0x01,0x07,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x23,0x35,0x33,0x05,0x23,0x35,0x33,0x13,0x33,0x03,0x23,0x03,0x65,0xc7,0xc7,0xfe,0x02,0xc6,0xc6,0x8a,0xda,0x7f,0x8e,0x04,0xe8,0xc8,0xc8,0xc8,0x01,0x12,0xfe,0xfa,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x06,0x07,0x02,0x26,0x00,0x24,0x00,0x00, +0x00,0x06,0x01,0x61,0xf9,0x00,0x00,0x00,0xff,0xff,0x00,0xa1,0x02,0x70,0x01,0x67,0x03,0x44,0x00,0x06,0x00,0x79,0x00,0x00,0xff,0xff,0xff,0x80,0x00,0x00,0x04,0x2b,0x06,0x09,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x61,0xfe,0xb2,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0xff,0xb1, +0x00,0x00,0x04,0xf7,0x06,0x09,0x02,0x26,0x00,0x2b,0x00,0x00,0x01,0x07,0x01,0x61,0xfe,0xe3,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0xff,0xbf,0x00,0x00,0x01,0x84,0x06,0x08,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x01,0x61,0xfe,0xf1,0x00,0x01,0x00,0x08,0xb1,0x01,0x01,0xb0,0x01,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x3c,0xff,0xeb,0x05,0x02,0x06,0x07,0x02,0x26,0x00,0x32,0x00,0x00,0x00,0x07,0x01,0x61,0xff,0x6e,0x00,0x00,0xff,0xff,0xff,0x3c,0x00,0x00,0x04,0xe2,0x06,0x07,0x02,0x26,0x00,0x3c,0x00,0x00,0x00,0x07,0x01,0x61,0xfe,0x6e,0x00,0x00,0xff,0xff,0x00,0x33,0x00,0x00,0x04,0xd0,0x06,0x07,0x02,0x26, +0x01,0x83,0x00,0x00,0x00,0x07,0x01,0x61,0xff,0x65,0x00,0x00,0xff,0xff,0xff,0xcc,0xff,0xeb,0x02,0x90,0x06,0x79,0x02,0x26,0x01,0x93,0x00,0x00,0x01,0x07,0x01,0x62,0xff,0x2b,0xff,0xb7,0x00,0x09,0xb1,0x01,0x03,0xb8,0xff,0xb7,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x05,0xb0,0x02,0x06,0x00,0x24,0x00,0x00, +0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xcd,0x05,0xb0,0x02,0x06,0x00,0x25,0x00,0x00,0x00,0x01,0x00,0xa3,0x00,0x00,0x04,0x20,0x05,0xb0,0x00,0x05,0x00,0x28,0x40,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x13,0x00,0x00,0x00,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x01,0x01,0x08, +0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x04,0x20,0xfd,0x48,0xc5,0x03,0x7d,0x05,0x15,0xfa,0xeb,0x05,0xb0,0x00,0x00,0x00,0x00,0x02,0x00,0x1e,0x00,0x00,0x05,0x70,0x05,0xb0,0x00,0x03,0x00,0x07,0x00,0x32,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1b, +0x00,0x03,0x00,0x02,0x00,0x03,0x02,0x29,0x00,0x00,0x00,0x07,0x16,0x00,0x02,0x02,0x01,0x00,0x02,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x33,0x01,0x21,0x25,0x21,0x01,0x23,0x02,0x87,0xa9,0x02,0x40,0xfa,0xae,0x01,0x08,0x03,0x46,0xfe,0x70,0x06,0x05,0xb0,0xfa,0x50,0x9a,0x04,0x1a,0x00,0xff,0xff,0x00,0xaa, +0x00,0x00,0x04,0x2b,0x05,0xb0,0x02,0x06,0x00,0x28,0x00,0x00,0xff,0xff,0x00,0x61,0x00,0x00,0x04,0x6d,0x05,0xb0,0x02,0x06,0x00,0x3d,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xf7,0x05,0xb0,0x02,0x06,0x00,0x2b,0x00,0x00,0x00,0x03,0x00,0x71,0xff,0xeb,0x05,0x02,0x05,0xc5,0x00,0x03,0x00,0x11,0x00,0x1f,0x00,0x3f,0x40,0x0e, +0x1d,0x1b,0x16,0x14,0x0f,0x0d,0x08,0x06,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x00,0x01,0x00,0x00,0x05,0x01,0x00,0x00,0x00,0x1d,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x16,0x00,0x05,0x05,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x35, +0x21,0x05,0x10,0x00,0x21,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x20,0x00,0x11,0x27,0x34,0x02,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32,0x36,0x35,0x03,0xbf,0xfe,0x03,0x01,0xfd,0x01,0x43,0xfe,0xb5,0xfe,0xf8,0xff,0xfe,0xc1,0x01,0x3f,0xff,0x01,0x08,0x01,0x4b,0xc5,0xd8,0xb6,0xac,0xcd,0xcd,0xac,0xb7,0xd7,0x02,0x93,0x9a,0xd7, +0xfe,0xf5,0xfe,0xa0,0x01,0x60,0x01,0x0b,0x01,0x03,0x01,0x0a,0x01,0x62,0xfe,0x9f,0xfe,0xf5,0x02,0xc8,0x01,0x00,0xff,0x00,0xc8,0xfe,0xfb,0xca,0xff,0x00,0xff,0xcb,0xff,0xff,0x00,0xbe,0x00,0x00,0x01,0x84,0x05,0xb0,0x02,0x06,0x00,0x2c,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x05,0x01,0x05,0xb0,0x02,0x06,0x00,0x2e,0x00,0x00, +0x00,0x01,0x00,0x31,0x00,0x00,0x05,0x07,0x05,0xb0,0x00,0x07,0x00,0x2c,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x00,0x00,0x02,0x01,0x02,0x00,0x01,0x29,0x00,0x02,0x02,0x07,0x16,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x23,0x01,0x23,0x01,0x33, +0x01,0x23,0x02,0x9f,0x06,0xfe,0x61,0xc9,0x02,0x16,0xaa,0x02,0x16,0xc9,0x04,0x93,0xfb,0x6d,0x05,0xb0,0xfa,0x50,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x06,0x48,0x05,0xb0,0x02,0x06,0x00,0x30,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xf7,0x05,0xb0,0x02,0x06,0x00,0x31,0x00,0x00,0x00,0x03,0x00,0x7b,0x00,0x00,0x04,0x24, +0x05,0xb0,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x3f,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x00,0x02,0x00,0x03,0x00,0x02,0x03,0x00,0x00,0x1d,0x00,0x05,0x05,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x07,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00, +0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x37,0x21,0x15,0x21,0x13,0x21,0x15,0x21,0x03,0x21,0x15,0x21,0x7b,0x03,0xa9,0xfc,0x57,0x53,0x02,0xf9,0xfd,0x07,0x52,0x03,0x9c,0xfc,0x64,0x9a,0x9a,0x03,0x41,0x9b,0x03,0x0a,0x9b,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x05,0xc5,0x02,0x06,0x00,0x32,0x00,0x00,0x00,0x01,0x00,0xa8, +0x00,0x00,0x04,0xf7,0x05,0xb0,0x00,0x07,0x00,0x2b,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x00,0x01,0x01,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x21,0x11,0x23,0x11,0x21,0x04,0xf7,0xc5, +0xfd,0x3b,0xc5,0x04,0x4f,0x05,0x15,0xfa,0xeb,0x05,0xb0,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xc3,0x05,0xb0,0x02,0x06,0x00,0x33,0x00,0x00,0x00,0x01,0x00,0x46,0x00,0x00,0x04,0x48,0x05,0xb0,0x00,0x0e,0x00,0x41,0x40,0x0a,0x0c,0x0b,0x0a,0x09,0x05,0x04,0x03,0x02,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2a,0x08,0x01, +0x03,0x02,0x0e,0x07,0x00,0x03,0x00,0x03,0x06,0x01,0x01,0x00,0x03,0x15,0x00,0x03,0x03,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x09,0x01,0x17,0x21,0x15,0x21,0x35,0x09,0x01,0x35,0x21,0x15,0x21,0x07,0x01,0x02,0xf6,0xfe,0x43,0x03,0x03, +0x0c,0xfb,0xfe,0x01,0xe0,0xfe,0x20,0x03,0xd0,0xfd,0x26,0x03,0x01,0xbd,0x02,0xcb,0xfd,0xd5,0x05,0x9b,0x93,0x02,0x45,0x02,0x45,0x93,0x9b,0x05,0xfd,0xd3,0x00,0x00,0xff,0xff,0x00,0x25,0x00,0x00,0x04,0xa4,0x05,0xb0,0x02,0x06,0x00,0x37,0x00,0x00,0xff,0xff,0x00,0x28,0x00,0x00,0x04,0xe2,0x05,0xb0,0x02,0x06,0x00,0x3c,0x00,0x00, +0x00,0x03,0x00,0x54,0x00,0x00,0x05,0x4d,0x05,0xb0,0x00,0x11,0x00,0x1a,0x00,0x23,0x00,0x50,0x40,0x16,0x22,0x21,0x1e,0x1d,0x19,0x18,0x15,0x14,0x11,0x10,0x0f,0x0e,0x0a,0x09,0x08,0x07,0x06,0x05,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2d,0x20,0x1f,0x17,0x16,0x04,0x06,0x07,0x01,0x15,0x04,0x01,0x00,0x08,0x01, +0x07,0x06,0x00,0x07,0x01,0x00,0x1d,0x09,0x01,0x06,0x03,0x01,0x01,0x02,0x06,0x01,0x01,0x00,0x1d,0x00,0x05,0x05,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x16,0x00,0x15,0x14,0x00,0x07,0x15,0x23,0x35,0x26,0x00,0x35,0x34,0x00,0x37,0x35,0x33,0x01,0x14,0x16,0x3f,0x01,0x11,0x27,0x26,0x06,0x05,0x34,0x26, +0x23,0x07,0x11,0x17,0x16,0x36,0x03,0x34,0xe6,0x01,0x33,0xfe,0xcd,0xe6,0xc5,0xe8,0xfe,0xcd,0x01,0x33,0xe8,0xc5,0xfd,0xe3,0xb1,0xa1,0x06,0x06,0xa0,0xb2,0x03,0x72,0xb2,0x9d,0x06,0x06,0x9d,0xb2,0x04,0xcd,0x05,0xfe,0xe5,0xda,0xdd,0xfe,0xe3,0x04,0xd5,0xd5,0x03,0x01,0x1c,0xdd,0xdb,0x01,0x1e,0x04,0xe2,0xfd,0x21,0xa1,0xbb,0x01, +0x02,0x02,0xb3,0x02,0x01,0xbd,0x9e,0x9f,0xbb,0x02,0xfd,0x4d,0x02,0x01,0xbd,0x00,0xff,0xff,0x00,0x42,0x00,0x00,0x04,0xd6,0x05,0xb0,0x02,0x06,0x00,0x3b,0x00,0x00,0x00,0x01,0x00,0x57,0x00,0x00,0x05,0x1b,0x05,0xb0,0x00,0x19,0x00,0x2e,0x40,0x0a,0x19,0x18,0x12,0x11,0x0c,0x0b,0x06,0x05,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x17,0x17,0x0d,0x0a,0x00,0x04,0x01,0x00,0x01,0x15,0x03,0x02,0x02,0x00,0x00,0x07,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x17,0x3e,0x01,0x35,0x11,0x33,0x11,0x14,0x00,0x07,0x11,0x23,0x11,0x26,0x00,0x35,0x11,0x33,0x11,0x14,0x16,0x17,0x37,0x11,0x33,0x03,0x13,0x06,0x90,0xad,0xc5,0xfe,0xe2,0xea,0xc6, +0xe3,0xfe,0xed,0xc4,0xa4,0x88,0x06,0xc6,0x01,0xe5,0x02,0x13,0xd3,0xac,0x02,0x3b,0xfd,0xc5,0xf5,0xfe,0xd7,0x18,0xfe,0xc1,0x01,0x40,0x18,0x01,0x28,0xf5,0x02,0x3b,0xfd,0xc5,0xaa,0xd2,0x14,0x01,0x03,0xca,0x00,0x01,0x00,0x70,0x00,0x00,0x04,0xd0,0x05,0xc5,0x00,0x23,0x00,0x3e,0x40,0x0e,0x23,0x22,0x21,0x20,0x1a,0x18,0x12,0x11, +0x10,0x0f,0x08,0x06,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23,0x0e,0x00,0x02,0x02,0x00,0x01,0x15,0x00,0x00,0x00,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x16,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x1b,0x05,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x25,0x36,0x12,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x1d,0x01, +0x14,0x12,0x17,0x15,0x21,0x35,0x33,0x26,0x02,0x3d,0x01,0x10,0x00,0x33,0x32,0x00,0x11,0x15,0x14,0x02,0x07,0x21,0x15,0x21,0x02,0xdf,0x8d,0x9d,0xc1,0xaa,0xa9,0xc0,0xa1,0x8f,0xfe,0x11,0xfd,0x78,0x8b,0x01,0x35,0xf9,0xf9,0x01,0x37,0x8b,0x76,0x01,0x03,0xfe,0x0f,0x9f,0x19,0x01,0x1f,0xfb,0x76,0xe9,0xf9,0xf9,0xe9,0x76,0xfb,0xfe, +0xe0,0x18,0x9f,0x9a,0x5c,0x01,0x35,0xa7,0x74,0x01,0x1c,0x01,0x63,0xfe,0x9d,0xfe,0xe4,0x74,0xa7,0xfe,0xcc,0x5d,0x9a,0x00,0xff,0xff,0xff,0xca,0x00,0x00,0x02,0x7b,0x07,0x0d,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x00,0x6a,0xff,0x20,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x28, +0x00,0x00,0x04,0xe2,0x07,0x0c,0x02,0x26,0x00,0x3c,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0x84,0x01,0x5c,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5c,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x62,0xff,0xeb,0x04,0x80,0x06,0x0e,0x02,0x26,0x01,0x8b,0x00,0x00,0x01,0x07,0x01,0x61,0x01,0x75,0x00,0x07,0x00,0x08,0xb1,0x02,0x01,0xb0,0x07,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x62,0xff,0xed,0x03,0xe9,0x06,0x0d,0x02,0x26,0x01,0x8f,0x00,0x00,0x01,0x07,0x01,0x61,0x01,0x2b,0x00,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x8f,0xfe,0x61,0x03,0xf5,0x06,0x0e,0x02,0x26,0x01,0x91,0x00,0x00,0x01,0x07,0x01,0x61,0x01,0x46,0x00,0x07, +0x00,0x08,0xb1,0x01,0x01,0xb0,0x07,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xc5,0xff,0xeb,0x02,0x73,0x05,0xfa,0x02,0x26,0x01,0x93,0x00,0x00,0x01,0x06,0x01,0x61,0x32,0xf3,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf3,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x8d,0xff,0xeb,0x04,0x26,0x06,0x79,0x02,0x26,0x01,0x9f,0x00,0x00, +0x01,0x06,0x01,0x62,0x54,0xb7,0x00,0x09,0xb1,0x01,0x03,0xb8,0xff,0xb7,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x00,0x02,0x00,0x62,0xff,0xeb,0x04,0x80,0x04,0x4e,0x00,0x1c,0x00,0x2b,0x00,0xcf,0x40,0x14,0x00,0x00,0x29,0x27,0x21,0x1f,0x00,0x1c,0x00,0x1c,0x19,0x17,0x12,0x10,0x0c,0x0a,0x05,0x03,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x4b,0xb0,0x17,0x58,0x40,0x2e,0x1b,0x01,0x06,0x03,0x25,0x23,0x02,0x00,0x06,0x0e,0x08,0x02,0x01,0x00,0x03,0x15,0x00,0x06,0x06,0x03,0x01,0x00,0x1b,0x07,0x04,0x02,0x03,0x03,0x10,0x16,0x05,0x01,0x00,0x00,0x01,0x01,0x02,0x1b,0x02,0x01,0x01,0x01,0x0e,0x01,0x17,0x05,0x1b,0x4b,0xb0,0x21,0x58,0x40,0x32,0x1b,0x01,0x06,0x04,0x25, +0x23,0x02,0x00,0x06,0x0e,0x08,0x02,0x01,0x00,0x03,0x15,0x07,0x01,0x04,0x04,0x0a,0x16,0x00,0x06,0x06,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x05,0x01,0x00,0x00,0x01,0x01,0x02,0x1b,0x02,0x01,0x01,0x01,0x0e,0x01,0x17,0x06,0x1b,0x40,0x3e,0x1b,0x01,0x06,0x04,0x25,0x23,0x02,0x00,0x06,0x0e,0x08,0x02,0x01,0x05,0x03,0x15, +0x07,0x01,0x04,0x04,0x0a,0x16,0x00,0x06,0x06,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x00,0x00,0x01,0x01,0x02,0x1b,0x02,0x01,0x01,0x01,0x0e,0x16,0x00,0x05,0x05,0x01,0x01,0x00,0x1b,0x02,0x01,0x01,0x01,0x0e,0x01,0x17,0x08,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22, +0x26,0x27,0x0e,0x01,0x23,0x22,0x02,0x3d,0x01,0x10,0x12,0x33,0x32,0x16,0x17,0x37,0x01,0x14,0x16,0x33,0x32,0x36,0x37,0x35,0x11,0x2e,0x01,0x23,0x22,0x06,0x15,0x03,0xe9,0x29,0x23,0x0f,0x1a,0x0b,0x17,0x1d,0x3c,0x25,0x4b,0x64,0x18,0x37,0x99,0x63,0xc6,0xe0,0xdf,0xc9,0x65,0x9b,0x37,0x33,0xfd,0xb3,0x87,0x8c,0x51,0x72,0x27,0x27, +0x73,0x4e,0x8d,0x88,0x04,0x39,0xfc,0xdb,0x48,0x38,0x03,0x04,0x8e,0x14,0x0e,0x40,0x45,0x42,0x43,0x01,0x1f,0xea,0x15,0x01,0x05,0x01,0x40,0x48,0x44,0x77,0xfd,0xbb,0xa4,0xcb,0x47,0x40,0x08,0x02,0x1d,0x3c,0x46,0xef,0xbb,0x00,0x00,0x02,0x00,0x9d,0xfe,0x81,0x04,0x4f,0x05,0xc5,0x00,0x14,0x00,0x2a,0x00,0x9f,0x40,0x18,0x16,0x15, +0x01,0x00,0x29,0x27,0x23,0x21,0x1c,0x1a,0x15,0x2a,0x16,0x2a,0x11,0x10,0x0d,0x0b,0x00,0x14,0x01,0x14,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1f,0x58,0x40,0x39,0x06,0x01,0x06,0x03,0x1f,0x01,0x05,0x06,0x0f,0x01,0x01,0x05,0x03,0x15,0x08,0x01,0x03,0x00,0x06,0x05,0x03,0x06,0x01,0x00,0x1d,0x00,0x04,0x04,0x00,0x01, +0x00,0x1b,0x07,0x01,0x00,0x00,0x0d,0x16,0x00,0x05,0x05,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x16,0x00,0x02,0x02,0x0c,0x02,0x17,0x07,0x1b,0x40,0x39,0x06,0x01,0x06,0x03,0x1f,0x01,0x05,0x06,0x0f,0x01,0x01,0x05,0x03,0x15,0x00,0x02,0x01,0x02,0x2c,0x08,0x01,0x03,0x00,0x06,0x05,0x03,0x06,0x01,0x00,0x1d,0x00,0x04,0x04,0x00, +0x01,0x00,0x1b,0x07,0x01,0x00,0x00,0x0d,0x16,0x00,0x05,0x05,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x01,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x26,0x27,0x11,0x23,0x11,0x34,0x24,0x13,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x11,0x1e,0x01,0x33,0x32,0x36, +0x35,0x34,0x26,0x2b,0x01,0x35,0x02,0x5f,0xc3,0xec,0x64,0x57,0x77,0x85,0xfd,0xca,0x52,0x99,0x3b,0xc5,0x01,0x0a,0xb4,0x7a,0x74,0x7d,0x6d,0x6b,0x92,0x2c,0x8d,0x59,0x81,0x95,0x83,0x6f,0x8f,0x05,0xc5,0xdc,0xae,0x5b,0x99,0x2d,0x2c,0xc4,0x81,0xd1,0xed,0x2d,0x2e,0xfe,0x3b,0x05,0xb0,0xa5,0xef,0xfd,0x97,0x79,0x6a,0x5f,0x8c,0x8f, +0x6a,0xfc,0xc2,0x34,0x3a,0xa0,0x80,0x70,0xac,0x9b,0x00,0x00,0x00,0x01,0x00,0x2e,0xfe,0x5f,0x03,0xe4,0x04,0x3a,0x00,0x0b,0x00,0x33,0x40,0x0a,0x0a,0x09,0x07,0x06,0x04,0x03,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1c,0x05,0x02,0x02,0x01,0x03,0x01,0x15,0x00,0x03,0x00,0x01,0x00,0x03,0x01,0x29,0x02,0x01,0x00, +0x00,0x0a,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x33,0x01,0x11,0x23,0x11,0x01,0x33,0x01,0x17,0x33,0x37,0x03,0x1b,0xc9,0xfe,0x89,0xc5,0xfe,0x86,0xca,0x01,0x00,0x11,0x06,0x13,0x04,0x3a,0xfc,0x04,0xfe,0x21,0x01,0xe4,0x03,0xf7,0xfd,0x05,0x4c,0x4c,0x00,0x00,0x00,0x00,0x02,0x00,0x61,0xff,0xeb,0x04,0x2a, +0x05,0xb0,0x00,0x16,0x00,0x24,0x00,0x4b,0x40,0x14,0x18,0x17,0x00,0x00,0x1f,0x1d,0x17,0x24,0x18,0x24,0x00,0x16,0x00,0x16,0x0c,0x0a,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2a,0x15,0x01,0x00,0x02,0x01,0x15,0x06,0x01,0x03,0x00,0x04,0x00,0x03,0x04,0x29,0x00,0x00,0x00,0x02,0x00,0x00,0x1b,0x05,0x01,0x02,0x02, +0x07,0x16,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x15,0x21,0x07,0x01,0x1e,0x01,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x3d,0x01,0x34,0x12,0x3f,0x02,0x25,0x35,0x01,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x03,0xaa,0xfe,0x3a,0x02,0x01,0x73,0x65,0x70, +0xfe,0xfc,0xe0,0xe0,0xfe,0xfb,0xd3,0xb9,0x07,0x02,0xfe,0xd7,0x01,0x77,0x8d,0x91,0x91,0x8f,0x8d,0x92,0x93,0x05,0xb0,0x97,0x06,0xfe,0xeb,0x4b,0xf6,0x96,0x16,0xf2,0xfe,0xcc,0x01,0x35,0xf1,0x16,0xd7,0x01,0x2b,0x1e,0x01,0x06,0xec,0x76,0xfe,0x03,0xe2,0xaa,0x16,0xac,0xe0,0xe0,0xac,0x16,0xaa,0xe2,0x00,0x00,0x00,0x01,0x00,0x62, +0xff,0xed,0x03,0xe9,0x04,0x4c,0x00,0x2a,0x00,0x66,0x40,0x16,0x01,0x00,0x29,0x27,0x23,0x21,0x1f,0x1e,0x1b,0x19,0x0f,0x0d,0x0a,0x09,0x07,0x05,0x00,0x2a,0x01,0x2a,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x43,0x1d,0x01,0x05,0x06,0x14,0x01,0x00,0x07,0x0b,0x01,0x01,0x02,0x03,0x15,0x00,0x05,0x06,0x07,0x06,0x05,0x07,0x29, +0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x29,0x00,0x07,0x08,0x01,0x00,0x02,0x07,0x00,0x01,0x00,0x1d,0x00,0x06,0x06,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x08,0xb0,0x2f,0x2b,0x01,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x33,0x17,0x16,0x04,0x23,0x22, +0x26,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x3b,0x01,0x15,0x02,0x1a,0x79,0x79,0x89,0x76,0x70,0x91,0xba,0x02,0x05,0xfe,0xf6,0xb8,0xca,0xfb,0x67,0x63,0x57,0x60,0xe9,0xc9,0xb7,0xf9,0x05,0x02,0xba,0x8b,0x64,0x74,0x79,0x6d,0x73,0xd1,0x01,0xdd,0x55, +0x57,0x49,0x64,0x70,0x4c,0x06,0xa2,0xab,0xad,0x97,0x5b,0x80,0x20,0x23,0x7a,0x49,0x96,0xa4,0xaf,0x8b,0x06,0x46,0x62,0x5f,0x43,0x4a,0x55,0x96,0x00,0x01,0x00,0x73,0xfe,0x58,0x03,0xca,0x05,0xb0,0x00,0x21,0x00,0x41,0x40,0x0e,0x00,0x00,0x00,0x21,0x00,0x21,0x20,0x1f,0x18,0x15,0x0a,0x07,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x26,0x01,0x01,0x02,0x03,0x01,0x15,0x10,0x0f,0x02,0x01,0x12,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x04,0x01,0x03,0x03,0x07,0x16,0x00,0x00,0x00,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x15,0x01,0x0e,0x01,0x15,0x14,0x16,0x3b,0x01,0x32,0x16,0x15,0x0e,0x01,0x07,0x27,0x3e,0x01,0x35,0x34, +0x26,0x2b,0x01,0x22,0x26,0x35,0x34,0x12,0x37,0x01,0x27,0x21,0x35,0x03,0xca,0xfe,0xaa,0x81,0x71,0x69,0x66,0x20,0x9f,0xb4,0x02,0x9b,0x6d,0x51,0x42,0x5e,0x52,0x5a,0x34,0xb3,0xb9,0x8b,0x90,0x01,0x0c,0x02,0xfd,0x91,0x05,0xb0,0x70,0xfe,0x50,0x99,0xe3,0x91,0x74,0x75,0x7f,0x80,0x6f,0xa5,0x2f,0x7f,0x1f,0x56,0x46,0x34,0x3a,0xd6, +0xa8,0x78,0x01,0x41,0xa9,0x01,0x30,0x05,0x9b,0x00,0x00,0x00,0x00,0x01,0x00,0x8f,0xfe,0x61,0x03,0xf5,0x04,0x4e,0x00,0x13,0x00,0x6b,0x40,0x10,0x00,0x00,0x00,0x13,0x00,0x13,0x12,0x11,0x0e,0x0c,0x09,0x08,0x05,0x03,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x21,0x10,0x01,0x02,0x03,0x02,0x01,0x15,0x00, +0x02,0x02,0x00,0x01,0x00,0x1b,0x05,0x04,0x02,0x00,0x00,0x10,0x16,0x00,0x03,0x03,0x08,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x05,0x1b,0x40,0x25,0x10,0x01,0x02,0x03,0x02,0x01,0x15,0x05,0x01,0x04,0x04,0x0a,0x16,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x03,0x03,0x08,0x16,0x00,0x01,0x01,0x0c,0x01,0x17, +0x06,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x01,0x3f,0x0d,0x36,0xa0,0x65,0xb1,0xbd,0xc5,0x72,0x74,0x55,0x7b,0x26,0xc5,0x04,0x3a,0x96,0x51,0x59,0xc3,0xe0,0xfb,0xb6,0x04,0x46,0x8f,0x7d,0x43,0x3c,0xfc,0xcc,0x04,0x3a,0x00,0x00,0x03,0x00,0x77, +0xff,0xeb,0x04,0x16,0x05,0xc5,0x00,0x0d,0x00,0x16,0x00,0x1f,0x00,0x3f,0x40,0x0e,0x1d,0x1b,0x18,0x17,0x14,0x12,0x0f,0x0e,0x0b,0x09,0x04,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x00,0x02,0x00,0x04,0x05,0x02,0x04,0x00,0x00,0x1d,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x05,0x05,0x00, +0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x14,0x02,0x23,0x22,0x02,0x35,0x11,0x34,0x12,0x33,0x32,0x12,0x15,0x05,0x21,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x21,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x04,0x16,0xfb,0xd4,0xd3,0xfd,0xfb,0xd3,0xd4,0xfd,0xfd,0x26,0x02,0x15,0x8c,0x80,0x7f,0x8a,0x02, +0x15,0xfd,0xeb,0x8d,0x7e,0x80,0x8a,0x02,0x02,0xf7,0xfe,0xe0,0x01,0x20,0xf7,0x01,0xac,0xf5,0x01,0x22,0xfe,0xde,0xf5,0x8b,0xb4,0x9d,0xb6,0xb6,0x9d,0xfe,0xb1,0xae,0x9d,0xb8,0xb7,0x9e,0x00,0x01,0x00,0xc5,0xff,0xeb,0x02,0x73,0x04,0x39,0x00,0x0f,0x00,0x37,0x40,0x0c,0x00,0x00,0x00,0x0f,0x00,0x0f,0x0c,0x0a,0x05,0x03,0x04,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x07,0x01,0x00,0x02,0x08,0x01,0x01,0x00,0x02,0x15,0x03,0x01,0x02,0x02,0x0a,0x16,0x00,0x00,0x00,0x01,0x01,0x02,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x01,0x8a,0x35,0x2d,0x19,0x30,0x12, +0x2c,0x2d,0x59,0x35,0x77,0x7c,0x04,0x39,0xfc,0xd3,0x49,0x38,0x0f,0x0b,0x85,0x1f,0x16,0x8e,0x9e,0x03,0x22,0x00,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x40,0x04,0x3a,0x02,0x06,0x00,0xfa,0x00,0x00,0x00,0x01,0x00,0x38,0xff,0xef,0x04,0x5e,0x05,0xee,0x00,0x21,0x00,0xac,0x40,0x0e,0x1c,0x1a,0x15,0x13,0x0e,0x0c,0x09,0x08, +0x07,0x05,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x2b,0x0a,0x01,0x01,0x03,0x17,0x02,0x02,0x04,0x01,0x02,0x15,0x18,0x01,0x00,0x12,0x02,0x01,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0d,0x16,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x05,0x01,0x00,0x00,0x08,0x00,0x17,0x06,0x1b,0x4b,0xb0, +0x1d,0x58,0x40,0x29,0x0a,0x01,0x01,0x03,0x17,0x02,0x02,0x04,0x01,0x02,0x15,0x18,0x01,0x00,0x12,0x00,0x03,0x02,0x01,0x01,0x04,0x03,0x01,0x01,0x00,0x1d,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x05,0x01,0x00,0x00,0x08,0x00,0x17,0x05,0x1b,0x40,0x2d,0x0a,0x01,0x01,0x03,0x17,0x02,0x02,0x04,0x01,0x18,0x01,0x05,0x00,0x03,0x15,0x00, +0x03,0x02,0x01,0x01,0x04,0x03,0x01,0x01,0x00,0x1d,0x00,0x00,0x00,0x08,0x16,0x00,0x04,0x04,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x05,0x59,0x59,0xb0,0x2f,0x2b,0x21,0x23,0x01,0x27,0x2e,0x01,0x23,0x22,0x06,0x23,0x35,0x3e,0x01,0x33,0x32,0x16,0x17,0x01,0x1e,0x01,0x33,0x32,0x36,0x37,0x07,0x0e,0x01,0x23,0x22,0x26, +0x27,0x03,0x0f,0x01,0x01,0x13,0xdb,0x01,0x87,0x37,0x20,0x57,0x3c,0x0a,0x36,0x04,0x14,0x3f,0x18,0x81,0x99,0x28,0x01,0x68,0x16,0x47,0x2c,0x0e,0x09,0x18,0x03,0x0b,0x25,0x0b,0x76,0x8f,0x35,0xca,0x06,0x1d,0x04,0x04,0x91,0x54,0x6a,0x05,0x91,0x05,0x0a,0xa2,0x6c,0xfc,0x4e,0x47,0x54,0x01,0x04,0x9a,0x05,0x0a,0x82,0x8c,0x02,0x13, +0x01,0x71,0x00,0x00,0xff,0xff,0x00,0x99,0xfe,0x60,0x03,0xf2,0x04,0x3a,0x02,0x06,0x00,0x77,0x00,0x00,0xff,0xff,0x00,0x2e,0x00,0x00,0x03,0xe4,0x04,0x3a,0x02,0x06,0x00,0x59,0x00,0x00,0x00,0x01,0x00,0x56,0xfe,0x44,0x03,0xe3,0x05,0xb0,0x00,0x2e,0x00,0x52,0x40,0x14,0x00,0x00,0x00,0x2e,0x00,0x2e,0x2d,0x2c,0x21,0x1e,0x13,0x10, +0x0c,0x0a,0x09,0x07,0x03,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x31,0x26,0x01,0x02,0x01,0x01,0x15,0x19,0x18,0x02,0x04,0x12,0x00,0x01,0x00,0x02,0x03,0x01,0x02,0x01,0x00,0x1d,0x05,0x01,0x00,0x00,0x06,0x00,0x00,0x1b,0x07,0x01,0x06,0x06,0x07,0x16,0x00,0x03,0x03,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x0e,0x04,0x17, +0x07,0xb0,0x2f,0x2b,0x01,0x15,0x21,0x0e,0x01,0x15,0x14,0x16,0x3b,0x01,0x15,0x23,0x22,0x06,0x15,0x14,0x16,0x3b,0x01,0x32,0x16,0x15,0x0e,0x01,0x07,0x27,0x3e,0x01,0x35,0x34,0x26,0x2b,0x01,0x22,0x24,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x36,0x37,0x23,0x35,0x03,0x9a,0xfe,0xd8,0x7b,0x7d,0x91,0x9a,0x8f,0x8f,0xbb,0xc3,0xa0, +0x8d,0x3c,0xa1,0xb2,0x02,0x9b,0x6d,0x4f,0x41,0x5e,0x46,0x4b,0x44,0xde,0xfe,0xec,0x9f,0x98,0x6c,0x78,0x3d,0x3b,0xd7,0x05,0xb0,0x9b,0x08,0x82,0x60,0x5e,0x69,0x9b,0x9c,0x99,0x78,0x96,0x7f,0x81,0x6f,0xa4,0x2f,0x7f,0x1f,0x55,0x46,0x34,0x3c,0xe3,0xc8,0x91,0xc5,0x2c,0x28,0x8d,0x58,0x4d,0x79,0x28,0x9b,0x00,0xff,0xff,0x00,0x61, +0xff,0xeb,0x04,0x2a,0x04,0x4e,0x02,0x06,0x00,0x52,0x00,0x00,0x00,0x01,0x00,0x4f,0xff,0xeb,0x04,0xcc,0x04,0x3a,0x00,0x17,0x00,0x77,0x40,0x10,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0d,0x0b,0x06,0x04,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x27,0x08,0x01,0x01,0x00,0x09,0x01,0x02,0x01, +0x02,0x15,0x05,0x03,0x02,0x00,0x00,0x06,0x00,0x00,0x1b,0x00,0x06,0x06,0x0a,0x16,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x04,0x01,0x02,0x02,0x0e,0x02,0x17,0x05,0x1b,0x40,0x2b,0x08,0x01,0x01,0x00,0x09,0x01,0x04,0x01,0x02,0x15,0x05,0x03,0x02,0x00,0x00,0x06,0x00,0x00,0x1b,0x00,0x06,0x06,0x0a,0x16,0x00,0x04,0x04,0x08,0x16,0x00, +0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x21,0x11,0x23,0x11,0x23,0x35,0x21,0x04,0x5e,0x7b,0x35,0x2d,0x19,0x30,0x12,0x2c,0x2d,0x59,0x35,0x77,0x7c,0xfe,0x91,0xc5,0x9b,0x04,0x0f,0x03,0x9e,0xfd, +0x6e,0x49,0x38,0x0f,0x0b,0x85,0x1f,0x16,0x8e,0x9e,0x02,0x87,0xfc,0x62,0x03,0x9e,0x9c,0x00,0x00,0x00,0x00,0x02,0x00,0x8f,0xfe,0x60,0x04,0x24,0x04,0x4e,0x00,0x10,0x00,0x1e,0x00,0x42,0x40,0x0c,0x1c,0x1a,0x15,0x13,0x0e,0x0c,0x08,0x07,0x04,0x02,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x29,0x18,0x01,0x04,0x03,0x06,0x01, +0x00,0x04,0x02,0x15,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x10,0x16,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x14,0x02,0x23,0x22,0x26,0x27,0x11,0x23,0x11,0x35,0x34,0x00,0x33,0x32,0x12,0x11,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x11,0x1e, +0x01,0x33,0x32,0x36,0x35,0x04,0x24,0xdb,0xc5,0x61,0x98,0x37,0xc5,0x01,0x01,0xc0,0xe3,0xf1,0xc5,0x84,0x8b,0x7b,0x81,0x25,0x78,0x57,0x8b,0x8c,0x01,0xf4,0xeb,0xfe,0xe2,0x3c,0x3a,0xfd,0xff,0x03,0xe0,0x01,0xf7,0x01,0x16,0xfe,0xc3,0xfe,0xf8,0xbd,0xed,0xe7,0x8c,0xfe,0xd3,0x43,0x4b,0xcc,0xa3,0x00,0x00,0x00,0x00,0x01,0x00,0x62, +0xfe,0x57,0x03,0xe1,0x04,0x4e,0x00,0x22,0x00,0x38,0x40,0x0c,0x01,0x00,0x09,0x07,0x05,0x04,0x00,0x22,0x01,0x22,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x03,0x01,0x01,0x02,0x01,0x15,0x16,0x15,0x02,0x01,0x12,0x00,0x01,0x02,0x01,0x2c,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x03,0x01,0x00,0x00,0x10,0x02,0x17,0x05,0xb0, +0x2f,0x2b,0x01,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x17,0x1e,0x01,0x15,0x0e,0x01,0x07,0x27,0x3e,0x01,0x35,0x34,0x26,0x27,0x26,0x02,0x3d,0x01,0x34,0x12,0x02,0x3d,0xbb,0xe9,0x04,0x02,0xb2,0x7a,0x72,0x8a,0x8c,0xa4,0xa6,0xb4,0xa8,0x02,0x9b,0x6d,0x51,0x42,0x5e,0x58,0x5f,0xfb,0xfe,0xff,0x04, +0x4e,0xd1,0xb2,0x06,0x67,0x87,0xe6,0x9b,0x2a,0x8f,0xc9,0x18,0x1a,0x6a,0x7b,0x6f,0xa4,0x2f,0x7f,0x1f,0x55,0x46,0x30,0x33,0x0d,0x23,0x01,0x0e,0xd7,0x2a,0xe3,0x01,0x39,0x00,0x00,0x00,0x00,0x02,0x00,0x61,0xff,0xeb,0x04,0x7c,0x04,0x3a,0x00,0x10,0x00,0x1e,0x00,0x34,0x40,0x0c,0x1c,0x1a,0x15,0x13,0x10,0x0e,0x09,0x07,0x01,0x00, +0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1b,0x04,0x01,0x00,0x00,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0a,0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x1e,0x01,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x3d,0x01,0x34,0x00,0x37,0x21,0x01,0x14,0x16,0x33,0x32,0x36,0x3d, +0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x04,0x7c,0xfe,0xeb,0x5e,0x65,0xfe,0xf8,0xdc,0xe0,0xfe,0xfb,0x01,0x03,0xdf,0x02,0x39,0xfc,0xaa,0x91,0x8f,0x8d,0x92,0x93,0x8e,0x8d,0x91,0x03,0x9e,0x48,0xd4,0x82,0x16,0xd2,0xfe,0xd3,0x01,0x35,0xf1,0x16,0xe7,0x01,0x2b,0x01,0xfd,0xd7,0xac,0xe0,0xe0,0xac,0x16,0xa1,0xd6,0xd6,0xa1,0x00,0x00, +0x00,0x01,0x00,0x51,0x00,0x00,0x03,0xdc,0x04,0x3a,0x00,0x07,0x00,0x2b,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x02,0x01,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x0a,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x35, +0x21,0x03,0xdc,0xfe,0x9a,0xc5,0xfe,0xa0,0x03,0x8b,0x03,0xa1,0xfc,0x5f,0x03,0xa1,0x99,0x00,0x00,0x00,0x00,0x01,0x00,0x8d,0xff,0xeb,0x04,0x26,0x04,0x3a,0x00,0x15,0x00,0x30,0x40,0x0e,0x00,0x00,0x00,0x15,0x00,0x15,0x12,0x10,0x0b,0x0a,0x05,0x03,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x04,0x03,0x02,0x01,0x01,0x0a, +0x16,0x00,0x00,0x00,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x26,0x02,0x27,0x33,0x16,0x12,0x15,0x14,0x02,0x23,0x22,0x26,0x35,0x11,0x01,0x52,0x8a,0x75,0x89,0x87,0x03,0x42,0x37,0xce,0x33,0x40,0xde,0xed,0xdd,0xf1,0x04,0x3a,0xfd,0x9c,0xaf,0xa2,0xfd,0xb0, +0x7e,0x01,0x02,0x88,0x6b,0xfe,0xfd,0x9a,0xff,0xfe,0xb8,0xf2,0xfb,0x02,0x62,0x00,0x00,0x02,0x00,0x53,0xfe,0x22,0x05,0x57,0x04,0x3a,0x00,0x18,0x00,0x21,0x00,0x3a,0x40,0x0e,0x01,0x00,0x1c,0x1b,0x10,0x0f,0x08,0x07,0x00,0x18,0x01,0x18,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x1e,0x1d,0x17,0x09,0x06,0x05,0x01,0x03, +0x01,0x15,0x00,0x01,0x03,0x01,0x2c,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x02,0x04,0x02,0x00,0x00,0x0a,0x03,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x32,0x00,0x15,0x14,0x00,0x05,0x11,0x23,0x11,0x24,0x00,0x35,0x34,0x12,0x37,0x33,0x06,0x02,0x07,0x14,0x16,0x17,0x37,0x11,0x01,0x2e,0x01,0x0f,0x01,0x11,0x17,0x3e,0x01,0x03,0x2e,0xe4,0x01, +0x45,0xfe,0xf1,0xfe,0xe6,0xc5,0xfe,0xee,0xfe,0xfc,0x40,0x34,0xce,0x39,0x42,0x02,0xa3,0xa8,0x06,0x02,0x29,0x04,0xba,0xa0,0x06,0x06,0xb1,0xad,0x04,0x3a,0xfe,0xbf,0xed,0xda,0xfe,0xd5,0x17,0xfe,0x32,0x01,0xce,0x19,0x01,0x41,0xea,0x99,0x01,0x01,0x6c,0x86,0xfe,0xfe,0x7e,0x9b,0xee,0x17,0x02,0x03,0xa4,0xfd,0xd2,0xa3,0xed,0x04, +0x02,0xfc,0xfd,0x02,0x15,0xd9,0x00,0x00,0x00,0x01,0x00,0x5f,0xfe,0x4b,0x04,0x4b,0x04,0x49,0x00,0x25,0x01,0x02,0x40,0x18,0x01,0x00,0x22,0x21,0x20,0x1e,0x1a,0x19,0x18,0x17,0x14,0x12,0x0d,0x0b,0x07,0x06,0x05,0x04,0x00,0x25,0x01,0x25,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x40,0x23,0x01,0x07,0x00, +0x1b,0x08,0x02,0x05,0x01,0x0f,0x01,0x03,0x05,0x10,0x01,0x04,0x03,0x04,0x15,0x00,0x01,0x07,0x05,0x07,0x01,0x05,0x29,0x00,0x05,0x03,0x07,0x05,0x03,0x27,0x08,0x01,0x07,0x07,0x00,0x01,0x00,0x1b,0x02,0x09,0x02,0x00,0x00,0x10,0x16,0x00,0x03,0x03,0x04,0x01,0x02,0x1b,0x06,0x01,0x04,0x04,0x12,0x04,0x17,0x07,0x1b,0x4b,0xb0,0x21, +0x58,0x40,0x44,0x23,0x01,0x07,0x00,0x1b,0x08,0x02,0x05,0x01,0x0f,0x01,0x03,0x05,0x10,0x01,0x04,0x06,0x04,0x15,0x00,0x01,0x07,0x05,0x07,0x01,0x05,0x29,0x00,0x05,0x03,0x07,0x05,0x03,0x27,0x08,0x01,0x07,0x07,0x00,0x01,0x00,0x1b,0x02,0x09,0x02,0x00,0x00,0x10,0x16,0x00,0x06,0x06,0x0c,0x16,0x00,0x03,0x03,0x04,0x01,0x02,0x1b, +0x00,0x04,0x04,0x12,0x04,0x17,0x08,0x1b,0x40,0x49,0x1b,0x08,0x02,0x05,0x01,0x0f,0x01,0x03,0x05,0x10,0x01,0x04,0x06,0x03,0x15,0x23,0x01,0x02,0x01,0x14,0x00,0x01,0x07,0x05,0x07,0x01,0x05,0x29,0x00,0x05,0x03,0x07,0x05,0x03,0x27,0x00,0x02,0x02,0x0a,0x16,0x08,0x01,0x07,0x07,0x00,0x01,0x00,0x1b,0x09,0x01,0x00,0x00,0x10,0x16, +0x00,0x06,0x06,0x0c,0x16,0x00,0x03,0x03,0x04,0x01,0x02,0x1b,0x00,0x04,0x04,0x12,0x04,0x17,0x0a,0x59,0x59,0xb0,0x2f,0x2b,0x13,0x32,0x16,0x1f,0x01,0x33,0x13,0x33,0x01,0x13,0x1e,0x01,0x33,0x32,0x36,0x37,0x07,0x0e,0x01,0x23,0x22,0x26,0x27,0x03,0x23,0x01,0x23,0x01,0x03,0x2e,0x01,0x23,0x22,0x06,0x23,0x35,0x3e,0x01,0xca,0x81, +0x97,0x2a,0x5c,0x06,0xe9,0xc6,0xfe,0xab,0xcc,0x21,0x3e,0x2a,0x0e,0x0a,0x16,0x03,0x0a,0x24,0x0d,0x74,0x8b,0x35,0x7f,0x06,0xfe,0xf7,0xd1,0x01,0x7f,0xa3,0x21,0x56,0x3c,0x0a,0x36,0x04,0x14,0x3f,0x04,0x49,0xa0,0x6c,0xde,0x01,0xdb,0xfd,0x3d,0xfe,0x14,0x4b,0x4f,0x02,0x03,0x9c,0x06,0x09,0x82,0x8e,0x01,0x2c,0xfd,0xda,0x03,0x0e, +0x01,0x82,0x53,0x6a,0x05,0x91,0x05,0x0a,0x00,0x01,0x00,0x5b,0xfe,0x26,0x05,0x4d,0x04,0x3a,0x00,0x1d,0x00,0x35,0x40,0x0e,0x00,0x00,0x00,0x1d,0x00,0x1d,0x17,0x16,0x11,0x10,0x09,0x08,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x1c,0x12,0x0f,0x01,0x04,0x01,0x00,0x01,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x04,0x03, +0x02,0x03,0x00,0x00,0x0a,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x11,0x17,0x3e,0x01,0x35,0x26,0x02,0x27,0x33,0x16,0x12,0x15,0x14,0x00,0x05,0x11,0x23,0x11,0x26,0x00,0x19,0x01,0x33,0x11,0x14,0x16,0x17,0x37,0x11,0x03,0x25,0x06,0xb1,0xac,0x03,0x42,0x38,0xcf,0x33,0x40,0xfe,0xf6,0xfe,0xe2,0xc6,0xf7,0xfe,0xf3,0xc5,0xa9,0x90,0x06, +0x04,0x39,0xfc,0x5c,0x02,0x17,0xf1,0x9c,0x7d,0x01,0x01,0x85,0x6a,0xff,0x00,0x99,0xf0,0xfe,0xbe,0x16,0xfe,0x37,0x01,0xcb,0x19,0x01,0x2e,0x01,0x1c,0x01,0xe6,0xfe,0x18,0xcf,0xdb,0x13,0x02,0x03,0xa2,0x00,0x00,0x01,0x00,0x6c,0xff,0xeb,0x06,0x60,0x04,0x3a,0x00,0x28,0x00,0x46,0x40,0x14,0x00,0x00,0x00,0x28,0x00,0x28,0x23,0x21, +0x1d,0x1b,0x16,0x15,0x10,0x0e,0x0b,0x0a,0x07,0x05,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x1f,0x01,0x00,0x01,0x01,0x15,0x00,0x01,0x03,0x00,0x03,0x01,0x00,0x29,0x07,0x06,0x02,0x03,0x03,0x0a,0x16,0x02,0x01,0x00,0x00,0x04,0x01,0x02,0x1b,0x05,0x01,0x04,0x04,0x0e,0x04,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x06,0x02,0x07, +0x14,0x16,0x33,0x32,0x36,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x26,0x02,0x27,0x33,0x16,0x12,0x15,0x14,0x02,0x23,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x02,0x35,0x34,0x12,0x37,0x01,0xd5,0x4a,0x56,0x04,0x70,0x78,0x6b,0x7f,0xc6,0x7e,0x6c,0x78,0x70,0x05,0x56,0x49,0xcf,0x44,0x56,0xca,0xd8,0x7f,0xaf,0x2a,0x2b,0xaf, +0x7d,0xd9,0xca,0x55,0x46,0x04,0x3a,0x86,0xfe,0xfd,0x7f,0xbe,0xef,0xa2,0xaf,0x01,0x2c,0xfe,0xd4,0xaf,0xa2,0xed,0xc0,0x7f,0x01,0x03,0x86,0x6a,0xfe,0xfc,0x9a,0xff,0xfe,0xb8,0x7a,0x77,0x77,0x7a,0x01,0x48,0xff,0x9b,0x01,0x04,0x69,0x00,0x00,0x00,0xff,0xff,0xff,0xd7,0xff,0xeb,0x02,0x88,0x05,0xb6,0x02,0x26,0x01,0x93,0x00,0x00, +0x01,0x07,0x00,0x6a,0xff,0x2d,0x00,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x8d,0xff,0xeb,0x04,0x26,0x05,0xb6,0x02,0x26,0x01,0x9f,0x00,0x00,0x01,0x06,0x00,0x6a,0x56,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0x0e,0x02,0x26, +0x00,0x52,0x00,0x00,0x01,0x07,0x01,0x61,0x01,0x4a,0x00,0x07,0x00,0x08,0xb1,0x02,0x01,0xb0,0x07,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x8d,0xff,0xeb,0x04,0x26,0x05,0xfa,0x02,0x26,0x01,0x9f,0x00,0x00,0x01,0x07,0x01,0x61,0x01,0x5c,0xff,0xf3,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf3,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6c, +0xff,0xeb,0x06,0x60,0x05,0xfa,0x02,0x26,0x01,0xa3,0x00,0x00,0x01,0x07,0x01,0x61,0x02,0x6a,0xff,0xf3,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf3,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0x71,0xff,0xeb,0x04,0xb0,0x05,0xc5,0x00,0x1a,0x00,0x26,0x00,0x55,0x40,0x10,0x25,0x24,0x1f,0x1d,0x18,0x17,0x15,0x13,0x10,0x0f,0x0c,0x0a,0x05,0x03, +0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x38,0x1a,0x00,0x02,0x06,0x02,0x01,0x15,0x26,0x01,0x06,0x01,0x14,0x00,0x02,0x05,0x06,0x05,0x02,0x06,0x29,0x00,0x06,0x00,0x04,0x03,0x06,0x04,0x01,0x00,0x1d,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01, +0x17,0x08,0xb0,0x2f,0x2b,0x01,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x11,0x10,0x00,0x23,0x22,0x00,0x19,0x01,0x37,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x26,0x24,0x35,0x25,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x17,0x37,0x02,0x09,0xbd,0x97,0x9d,0xb6,0xfe,0xcf,0xf8,0xee,0xfe,0xd8,0xc5,0xb6,0x9b,0xa5,0xbe,0x02,0xda,0xfe, +0xf7,0x01,0xe3,0x49,0x46,0x42,0x4d,0x96,0x82,0x06,0x04,0x0c,0x3e,0xac,0xcf,0xca,0xb1,0xfe,0x06,0xfe,0xea,0xfe,0xb1,0x01,0x5c,0x01,0x09,0x02,0x94,0x02,0xfd,0x6a,0xc8,0xfc,0xed,0xd0,0x08,0xfb,0xc0,0x3e,0x6c,0x6d,0x6d,0x6c,0x40,0x78,0x9e,0x04,0x02,0x00,0x00,0x00,0x00,0x01,0xff,0xea,0x00,0x00,0x04,0x53,0x05,0xbb,0x00,0x23, +0x01,0xcc,0x40,0x0e,0x22,0x21,0x1d,0x1b,0x16,0x14,0x10,0x0f,0x0b,0x09,0x04,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x09,0x58,0x40,0x29,0x19,0x06,0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05,0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x0d,0x16, +0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x0a,0x58,0x40,0x29,0x19,0x06,0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05,0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x0c,0x58,0x40,0x29,0x19,0x06, +0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05,0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x0d,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x10,0x58,0x40,0x29,0x19,0x06,0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05, +0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x12,0x58,0x40,0x29,0x19,0x06,0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05,0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x0d,0x16, +0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x14,0x58,0x40,0x29,0x19,0x06,0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05,0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x17,0x58,0x40,0x29,0x19,0x06, +0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05,0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x0d,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x19,0x58,0x40,0x29,0x19,0x06,0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05, +0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0x1b,0x40,0x29,0x19,0x06,0x02,0x01,0x00,0x11,0x0e,0x02,0x02,0x05,0x02,0x15,0x00,0x05,0x01,0x02,0x01,0x05,0x02,0x29,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x04,0x01,0x00,0x00,0x0d,0x16,0x00,0x02,0x02,0x08, +0x02,0x17,0x05,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x3e,0x01,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x07,0x01,0x11,0x23,0x11,0x01,0x2e,0x01,0x23,0x22,0x06,0x07,0x27,0x3e,0x01,0x33,0x32,0x16,0x17,0x13,0x17,0x33,0x37,0x02,0xe6,0x33,0x7b,0x51,0x22,0x32,0x1a,0x17,0x05,0x16,0x0d,0x21,0x37, +0x10,0xfe,0xd4,0xc4,0xfe,0xd4,0x11,0x37,0x20,0x0e,0x15,0x05,0x16,0x18,0x32,0x23,0x50,0x7b,0x34,0xb2,0x13,0x06,0x13,0x04,0xd7,0x7c,0x68,0x0a,0x0e,0x98,0x03,0x05,0x23,0x27,0xfd,0x79,0xfd,0xbe,0x02,0x42,0x02,0x87,0x27,0x23,0x05,0x03,0x98,0x0e,0x0a,0x68,0x7c,0xfe,0x6a,0x46,0x46,0x00,0x00,0x02,0x00,0x4e,0xff,0xeb,0x06,0x19, +0x04,0x3a,0x00,0x16,0x00,0x2c,0x00,0x4d,0x40,0x14,0x2b,0x29,0x26,0x25,0x22,0x20,0x1b,0x1a,0x16,0x15,0x14,0x13,0x0e,0x0c,0x08,0x06,0x01,0x00,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2c,0x0a,0x01,0x06,0x07,0x01,0x15,0x00,0x07,0x00,0x06,0x00,0x07,0x06,0x29,0x05,0x03,0x02,0x00,0x00,0x04,0x00,0x00,0x1b,0x00,0x04,0x04, +0x0a,0x16,0x08,0x01,0x06,0x06,0x01,0x01,0x00,0x1b,0x02,0x01,0x01,0x01,0x0e,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x23,0x1e,0x01,0x15,0x14,0x02,0x23,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x02,0x35,0x34,0x36,0x37,0x23,0x35,0x21,0x01,0x2e,0x01,0x27,0x21,0x0e,0x01,0x07,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x33,0x15,0x14,0x16,0x33, +0x32,0x36,0x06,0x19,0x85,0x1d,0x21,0xae,0xb8,0x77,0xa5,0x28,0x29,0xa4,0x76,0xb9,0xad,0x20,0x1e,0x6f,0x05,0xcb,0xfe,0xf4,0x03,0x28,0x22,0xfc,0xd1,0x23,0x28,0x02,0x53,0x59,0x62,0x74,0xc6,0x73,0x63,0x57,0x54,0x03,0x9e,0x51,0xb6,0x65,0xfe,0xfe,0xb7,0x79,0x74,0x75,0x78,0x01,0x49,0xfe,0x65,0xb6,0x51,0x9c,0xfd,0xf8,0x59,0xb6, +0x5d,0x5e,0xb6,0x58,0xbe,0xef,0xa2,0xaf,0xfa,0xfa,0xaf,0xa2,0xee,0x00,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x4b,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xd4,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x0d,0x02,0x26, +0x00,0x28,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0x69,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x39,0xff,0xce,0x05,0xa0,0x05,0xb0,0x00,0x17,0x00,0x43,0x40,0x0e,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x0f,0x04,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x28,0x0a,0x01, +0x03,0x02,0x01,0x15,0x09,0x01,0x03,0x12,0x00,0x01,0x00,0x02,0x03,0x01,0x02,0x01,0x00,0x1d,0x04,0x01,0x00,0x00,0x05,0x00,0x00,0x1b,0x00,0x05,0x05,0x07,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x33,0x32,0x00,0x15,0x06,0x02,0x07,0x27,0x3e,0x01,0x35,0x2e,0x01,0x2b,0x01,0x11,0x23,0x11,0x21,0x35, +0x21,0x04,0xb8,0xfe,0x20,0xb5,0xeb,0x01,0x28,0x02,0xc3,0xbe,0x33,0x80,0x70,0x01,0xb6,0x96,0xb5,0xc5,0xfe,0x26,0x04,0x7f,0x05,0x15,0xfe,0x5b,0xff,0x00,0xdc,0x8a,0xfe,0xe6,0x22,0x94,0x22,0x9d,0x73,0x93,0xa4,0xfd,0x35,0x05,0x15,0x9b,0x00,0x00,0xff,0xff,0x00,0xa3,0x00,0x00,0x04,0x20,0x07,0x47,0x02,0x26,0x01,0x6e,0x00,0x00, +0x01,0x07,0x00,0x76,0x01,0x85,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x87,0xff,0xec,0x04,0xd0,0x05,0xc6,0x00,0x21,0x00,0x62,0x40,0x16,0x00,0x00,0x00,0x21,0x00,0x21,0x1f,0x1d,0x1a,0x19,0x18,0x17,0x14,0x12,0x10,0x0f,0x0c,0x0a,0x05,0x03,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x3f,0x0e,0x01,0x02,0x03,0x01,0x01,0x06,0x07,0x02,0x15,0x00,0x02,0x03,0x04,0x03,0x02,0x04,0x29,0x08,0x01,0x07,0x05,0x06,0x05,0x07,0x06,0x29,0x00,0x04,0x00,0x05,0x07,0x04,0x05,0x00,0x00,0x1d,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x06,0x06,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17, +0x08,0xb0,0x2f,0x2b,0x01,0x17,0x16,0x00,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x00,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x02,0x1d,0x01,0x21,0x15,0x21,0x15,0x14,0x12,0x33,0x32,0x36,0x35,0x04,0xca,0x02,0x04,0xfe,0xd8,0xf3,0xf7,0xfe,0xc9,0x01,0x37,0xf7,0xf7,0x01,0x24,0x04,0x02,0xbd,0xb4,0xa4,0xa5,0xc4,0x02,0x32,0xfd, +0xce,0xc4,0xa5,0xa4,0xb4,0x01,0xd3,0x06,0xcd,0xfe,0xec,0x01,0x5e,0x01,0x0d,0x01,0x03,0x01,0x0d,0x01,0x5f,0xfe,0xf9,0xd9,0x06,0x99,0xb2,0xfe,0xf6,0xc5,0x2f,0x9a,0x3c,0xc7,0xfe,0xf6,0xb1,0x9c,0x00,0x00,0x00,0x01,0x00,0x6d,0xff,0xeb,0x04,0x77,0x05,0xc5,0x00,0x27,0x00,0x4e,0x40,0x0e,0x26,0x24,0x22,0x21,0x1e,0x1c,0x12,0x10, +0x0e,0x0d,0x0a,0x08,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x33,0x0c,0x01,0x01,0x02,0x20,0x01,0x05,0x04,0x02,0x15,0x00,0x01,0x02,0x04,0x02,0x01,0x04,0x29,0x00,0x04,0x05,0x02,0x04,0x05,0x27,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17, +0x07,0xb0,0x2f,0x2b,0x01,0x34,0x26,0x27,0x2e,0x01,0x35,0x34,0x24,0x33,0x32,0x00,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x17,0x1e,0x01,0x15,0x14,0x04,0x23,0x22,0x24,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x03,0xb2,0x8e,0xb3,0xde,0xf9,0x01,0x0c,0xd6,0xe6,0x01,0x11,0x04,0x03,0xbc,0xad,0x87,0x8a,0x93,0xa1, +0xb5,0xdc,0xe6,0xfe,0xeb,0xdf,0xd3,0xfe,0xbd,0x05,0x02,0xbc,0xd0,0x83,0x8c,0xa3,0x01,0x6f,0x63,0x86,0x2f,0x37,0xd6,0xa2,0xab,0xe4,0xfe,0xfb,0xae,0x06,0x7c,0xa2,0x86,0x6b,0x5f,0x7f,0x30,0x39,0xde,0xa3,0xb0,0xd6,0xec,0xc6,0x06,0x89,0x95,0x7e,0xff,0xff,0x00,0xbe,0x00,0x00,0x01,0x84,0x05,0xb0,0x02,0x06,0x00,0x2c,0x00,0x00, +0xff,0xff,0xff,0xca,0x00,0x00,0x02,0x7b,0x07,0x0d,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x00,0x6a,0xff,0x20,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x4a,0xff,0xeb,0x03,0xbc,0x05,0xb0,0x02,0x06,0x00,0x2d,0x00,0x00,0x00,0x02,0x00,0x32,0x00,0x00,0x08,0x49,0x05,0xb0,0x00,0x16, +0x00,0x1f,0x00,0x4f,0x40,0x1a,0x17,0x17,0x00,0x00,0x17,0x1f,0x17,0x1e,0x1a,0x18,0x00,0x16,0x00,0x16,0x13,0x11,0x10,0x0e,0x0b,0x0a,0x09,0x07,0x03,0x01,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x28,0x00,0x00,0x09,0x01,0x07,0x04,0x00,0x07,0x01,0x00,0x1d,0x00,0x02,0x02,0x05,0x00,0x00,0x1b,0x08,0x01,0x05,0x05,0x07,0x16, +0x06,0x01,0x04,0x04,0x01,0x01,0x00,0x1b,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11,0x21,0x03,0x0a,0x01,0x2b,0x01,0x35,0x33,0x32,0x12,0x13,0x11,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x04,0xf7,0x01,0x67,0xe8,0x01,0x03,0xfe,0xfd,0xe8,0xfd,0xd4,0xfe, +0x08,0x01,0x01,0xd7,0xfb,0x34,0x28,0x96,0x84,0x01,0x03,0x82,0x01,0x67,0x93,0x93,0x93,0x93,0x05,0xb0,0xfd,0xc9,0xf7,0xc6,0xc6,0xf6,0x05,0x15,0xfd,0xed,0xfe,0x6f,0xfe,0x8f,0x9a,0x01,0x1d,0x01,0x4b,0x02,0xae,0xfd,0x2f,0xfd,0xbb,0xa9,0x7b,0x79,0xa8,0x00,0x00,0x00,0x00,0x02,0x00,0xa8,0x00,0x00,0x08,0x49,0x05,0xb0,0x00,0x12, +0x00,0x1b,0x00,0xaa,0x40,0x18,0x13,0x13,0x13,0x1b,0x13,0x1a,0x16,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0a,0x06,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x26,0x58,0x40,0x22,0x02,0x01,0x00,0x09,0x08,0x02,0x04,0x07,0x00,0x04,0x01,0x00,0x1d,0x06,0x01,0x01,0x01,0x07,0x16,0x00,0x07,0x07, +0x03,0x01,0x02,0x1b,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x04,0x1b,0x4b,0xb0,0x2a,0x58,0x40,0x29,0x00,0x02,0x00,0x04,0x02,0x01,0x00,0x1a,0x00,0x00,0x09,0x08,0x02,0x04,0x07,0x00,0x04,0x01,0x00,0x1d,0x06,0x01,0x01,0x01,0x07,0x16,0x00,0x07,0x07,0x03,0x01,0x02,0x1b,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x05,0x1b,0x40,0x2a,0x00, +0x02,0x09,0x01,0x08,0x04,0x02,0x08,0x01,0x00,0x1d,0x00,0x00,0x00,0x04,0x07,0x00,0x04,0x00,0x00,0x1d,0x06,0x01,0x01,0x01,0x07,0x16,0x00,0x07,0x07,0x03,0x01,0x02,0x1b,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x05,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x33,0x11,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11,0x21,0x11,0x23,0x11, +0x33,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x01,0x6d,0x02,0xc5,0xc5,0x01,0x67,0xe9,0x01,0x02,0xfe,0xfd,0xe8,0xfd,0xd4,0xfd,0x3b,0xc5,0xc5,0x03,0x8a,0x01,0x67,0x94,0x92,0x92,0x94,0x03,0x3b,0x02,0x75,0xfd,0x98,0xe4,0xbc,0xbd,0xeb,0x02,0xa1,0xfd,0x5f,0x05,0xb0,0xfc,0xfd,0xfd,0xf8,0x94,0x71,0x70,0x93,0x00,0x00,0x00, +0x00,0x01,0x00,0x49,0x00,0x00,0x05,0xf7,0x05,0xb0,0x00,0x13,0x00,0x3c,0x40,0x10,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0b,0x08,0x07,0x04,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x00,0x01,0x00,0x03,0x02,0x01,0x03,0x01,0x00,0x1d,0x05,0x01,0x00,0x00,0x06,0x00,0x00,0x1b,0x00,0x06,0x06,0x07,0x16,0x04, +0x01,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x21,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x21,0x11,0x23,0x11,0x21,0x35,0x21,0x04,0xc8,0xfe,0x20,0x01,0x26,0xee,0xfb,0xc5,0x8c,0x98,0xfe,0xda,0xc5,0xfe,0x26,0x04,0x7f,0x05,0x15,0xfe,0xac,0xdd,0xef,0xfe,0x0b,0x01,0xf5,0xa8,0x89,0xfc,0xda,0x05,0x15, +0x9b,0x00,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x05,0x01,0x06,0xef,0x02,0x26,0x00,0x2e,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x7f,0x01,0x01,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x01,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xad,0x00,0x00,0x04,0xfa,0x07,0x4b,0x02,0x26,0x01,0xc4,0x00,0x00,0x01,0x07,0x00,0x43,0x01,0x3f,0x01,0x5d, +0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x42,0xff,0xeb,0x04,0xc8,0x07,0x4e,0x02,0x26,0x01,0xcf,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0xda,0x01,0x9e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0xa8,0xfe,0x99,0x04,0xf7,0x05,0xb0,0x00,0x0b,0x00,0x35,0x40,0x0e, +0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x04,0x03,0x04,0x2c,0x02,0x01,0x00,0x00,0x07,0x16,0x00,0x01,0x01,0x03,0x00,0x02,0x1b,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x04,0xb0,0x2f,0x2b,0x13,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x23,0x11,0x21,0xa8, +0xc5,0x02,0xc5,0xc5,0xfe,0x42,0xc5,0xfe,0x34,0x05,0xb0,0xfa,0xea,0x05,0x16,0xfa,0x50,0xfe,0x99,0x01,0x67,0x00,0x00,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x05,0xb0,0x02,0x06,0x00,0x24,0x00,0x00,0x00,0x02,0x00,0xa3,0x00,0x00,0x04,0xbb,0x05,0xb0,0x00,0x0c,0x00,0x15,0x00,0x44,0x40,0x12,0x0d,0x0d,0x0d,0x15,0x0d,0x14, +0x10,0x0e,0x0c,0x0b,0x0a,0x08,0x04,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x00,0x01,0x06,0x01,0x05,0x04,0x01,0x05,0x01,0x00,0x1d,0x00,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x21, +0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11,0x21,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x04,0x20,0xfd,0x48,0x01,0x67,0xe9,0x01,0x03,0xfe,0xfc,0xe8,0xfd,0xd4,0x03,0x7d,0xfd,0x48,0x01,0x67,0x93,0x94,0x93,0x94,0x05,0x15,0xfe,0x5b,0xef,0xc5,0xc6,0xf6,0x05,0xb0,0xfd,0x25,0xfd,0xc5,0xa9,0x7b,0x77,0xa0,0xff,0xff,0x00,0xaa, +0x00,0x00,0x04,0xcd,0x05,0xb0,0x02,0x06,0x00,0x25,0x00,0x00,0xff,0xff,0x00,0xa3,0x00,0x00,0x04,0x20,0x05,0xb0,0x02,0x06,0x01,0x6e,0x00,0x00,0x00,0x02,0x00,0x36,0xfe,0x99,0x05,0xee,0x05,0xb0,0x00,0x0e,0x00,0x15,0x00,0x43,0x40,0x12,0x15,0x14,0x13,0x12,0x0e,0x0d,0x0c,0x0b,0x08,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x02,0x01,0x00,0x03,0x00,0x00,0x00,0x19,0x00,0x07,0x07,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x07,0x16,0x06,0x05,0x02,0x03,0x03,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x21,0x11,0x23,0x11,0x33,0x32,0x12,0x1b,0x01,0x21,0x11,0x33,0x01,0x06, +0x02,0x07,0x21,0x11,0x21,0x05,0xee,0xc5,0xfb,0xd2,0xc5,0x68,0x84,0x83,0x12,0x21,0x03,0x4f,0xc7,0xfc,0x90,0x0d,0x51,0x4d,0x02,0x8f,0xfe,0x33,0xfe,0x9b,0x01,0x65,0xfe,0x99,0x02,0x01,0x01,0x6b,0x01,0x5e,0x02,0x4d,0xfa,0xea,0x02,0xc9,0xf9,0xfe,0x9b,0x6b,0x04,0x7b,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x05,0xb0,0x02,0x06, +0x00,0x28,0x00,0x00,0x00,0x01,0x00,0x1a,0x00,0x00,0x06,0x7c,0x05,0xb0,0x00,0x15,0x00,0x46,0x40,0x16,0x15,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23,0x13,0x08,0x02,0x00,0x05,0x01,0x15,0x07,0x01,0x05,0x02,0x01,0x00,0x01, +0x05,0x00,0x00,0x00,0x1d,0x08,0x06,0x02,0x04,0x04,0x07,0x16,0x09,0x03,0x02,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x23,0x01,0x23,0x09,0x01,0x33,0x01,0x33,0x11,0x33,0x11,0x33,0x01,0x33,0x09,0x01,0x23,0x03,0xe7,0x36,0xc4,0x3f,0xfe,0x61,0xf5,0x01,0xef,0xfe,0x39,0xe6,0x01,0x84,0x41,0xc4,0x39, +0x01,0x84,0xe6,0xfe,0x39,0x01,0xef,0xf5,0x02,0x9c,0xfd,0x64,0x02,0x9c,0xfd,0x64,0x03,0x02,0x02,0xae,0xfd,0x87,0x02,0x79,0xfd,0x87,0x02,0x79,0xfd,0x53,0xfc,0xfd,0x00,0x01,0x00,0x78,0xff,0xeb,0x04,0xdf,0x05,0xc5,0x00,0x2a,0x00,0x61,0x40,0x12,0x29,0x27,0x24,0x23,0x21,0x1f,0x1b,0x19,0x18,0x16,0x12,0x10,0x0e,0x0d,0x0a,0x08, +0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x42,0x25,0x01,0x06,0x05,0x03,0x01,0x03,0x04,0x0c,0x01,0x02,0x01,0x03,0x15,0x00,0x06,0x05,0x04,0x05,0x06,0x04,0x29,0x00,0x01,0x03,0x02,0x03,0x01,0x02,0x29,0x00,0x04,0x00,0x03,0x01,0x04,0x03,0x01,0x00,0x1d,0x00,0x05,0x05,0x07,0x01,0x00,0x1b,0x00,0x07,0x07,0x0d,0x16,0x00,0x02, +0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x08,0xb0,0x2f,0x2b,0x01,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x04,0x21,0x22,0x24,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x24,0x33,0x20,0x04,0x04,0xc9,0x88,0x78,0x87,0x8f, +0xfe,0xc1,0xfe,0xfe,0xe2,0xfe,0xbc,0x05,0x02,0xbc,0xc6,0x9d,0xb2,0xca,0xb8,0xb4,0xb7,0xb7,0xae,0xa8,0xb5,0xb1,0x8d,0xc1,0xbc,0x01,0x06,0x01,0x31,0xe0,0x01,0x01,0x01,0x2a,0x04,0x26,0x65,0xa7,0x2f,0x2a,0xae,0x7d,0xc9,0xe2,0xd6,0xcd,0x06,0x72,0x9d,0x95,0x78,0x85,0x81,0x9c,0x84,0x72,0x70,0x90,0x8e,0x69,0x06,0xb0,0xdc,0xd8, +0x00,0x01,0x00,0xad,0x00,0x00,0x04,0xfa,0x05,0xb0,0x00,0x0b,0x00,0x2c,0x40,0x0a,0x09,0x08,0x07,0x06,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x0a,0x04,0x02,0x01,0x00,0x01,0x15,0x03,0x01,0x00,0x00,0x07,0x16,0x02,0x01,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x33,0x11,0x23,0x11,0x27, +0x01,0x23,0x11,0x33,0x11,0x17,0x04,0x35,0xc5,0xc5,0x06,0xfd,0x43,0xc5,0xc5,0x06,0x05,0xb0,0xfa,0x50,0x04,0x56,0x02,0xfb,0xa8,0x05,0xb0,0xfb,0xab,0x02,0x00,0x00,0xff,0xff,0x00,0xad,0x00,0x00,0x04,0xfa,0x07,0x4e,0x02,0x26,0x01,0xc4,0x00,0x00,0x01,0x07,0x01,0x54,0x01,0x2a,0x01,0x9e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x9e, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x05,0x01,0x05,0xb0,0x02,0x06,0x00,0x2e,0x00,0x00,0x00,0x01,0x00,0x31,0x00,0x00,0x04,0xf7,0x05,0xb0,0x00,0x0f,0x00,0x39,0x40,0x10,0x00,0x00,0x00,0x0f,0x00,0x0f,0x0c,0x0a,0x09,0x07,0x04,0x03,0x02,0x01,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1c,0x00,0x01,0x01,0x04, +0x00,0x00,0x1b,0x05,0x01,0x04,0x04,0x07,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x23,0x11,0x21,0x03,0x10,0x02,0x2b,0x01,0x35,0x33,0x32,0x12,0x1b,0x01,0x04,0xf7,0xc5,0xfd,0xf2,0x01,0xce,0xef,0x35,0x29,0x8a,0x7a,0x01,0x01,0x05,0xb0,0xfa,0x50,0x05,0x15,0xfd, +0xed,0xfe,0x70,0xfe,0x8e,0x9a,0x01,0x1d,0x01,0x4b,0x02,0xae,0xff,0xff,0x00,0xaa,0x00,0x00,0x06,0x48,0x05,0xb0,0x02,0x06,0x00,0x30,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xf7,0x05,0xb0,0x02,0x06,0x00,0x2b,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x05,0xc5,0x02,0x06,0x00,0x32,0x00,0x00,0xff,0xff,0x00,0xa8, +0x00,0x00,0x04,0xf7,0x05,0xb0,0x02,0x06,0x01,0x7b,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xc3,0x05,0xb0,0x02,0x06,0x00,0x33,0x00,0x00,0xff,0xff,0x00,0x76,0xff,0xeb,0x04,0xbf,0x05,0xc5,0x02,0x06,0x00,0x26,0x00,0x00,0xff,0xff,0x00,0x25,0x00,0x00,0x04,0xa4,0x05,0xb0,0x02,0x06,0x00,0x37,0x00,0x00,0x00,0x01,0x00,0x42, +0xff,0xeb,0x04,0xc8,0x05,0xb0,0x00,0x15,0x00,0x3f,0x40,0x0c,0x15,0x14,0x10,0x0e,0x09,0x07,0x04,0x03,0x02,0x01,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x26,0x0c,0x01,0x03,0x00,0x0b,0x01,0x02,0x03,0x02,0x15,0x00,0x00,0x01,0x03,0x01,0x00,0x03,0x29,0x04,0x01,0x01,0x01,0x07,0x16,0x00,0x03,0x03,0x02,0x01,0x02,0x1b,0x00, +0x02,0x02,0x0e,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x01,0x33,0x01,0x0e,0x01,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x3f,0x01,0x01,0x33,0x02,0x38,0x4a,0x06,0x01,0x5c,0xe4,0xfd,0xef,0x38,0xa0,0x9a,0x41,0x71,0x21,0x19,0x21,0x60,0x24,0x52,0x62,0x1e,0x27,0xfe,0x19,0xdd,0x03,0x07,0xbf,0x03,0x68,0xfb,0x3f, +0x7c,0x88,0x16,0x0f,0x90,0x0a,0x11,0x55,0x43,0x53,0x04,0x40,0xff,0xff,0x00,0x54,0x00,0x00,0x05,0x4d,0x05,0xb0,0x02,0x06,0x01,0x80,0x00,0x00,0xff,0xff,0x00,0x42,0x00,0x00,0x04,0xd6,0x05,0xb0,0x02,0x06,0x00,0x3b,0x00,0x00,0x00,0x01,0x00,0xa1,0xfe,0x99,0x05,0xad,0x05,0xb0,0x00,0x0b,0x00,0x37,0x40,0x0e,0x0b,0x0a,0x09,0x08, +0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1c,0x00,0x04,0x01,0x04,0x00,0x02,0x19,0x02,0x01,0x00,0x00,0x07,0x16,0x03,0x01,0x01,0x01,0x05,0x00,0x02,0x1b,0x00,0x05,0x05,0x08,0x05,0x17,0x04,0xb0,0x2f,0x2b,0x13,0x33,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x23,0x11,0x21,0xa1,0xc5,0x02, +0xc5,0xc5,0xbd,0xc5,0xfb,0xb9,0x05,0xb0,0xfa,0xeb,0x05,0x15,0xfa,0xf0,0xfd,0xf9,0x01,0x67,0x00,0x00,0x00,0x01,0x00,0x93,0x00,0x00,0x04,0xcc,0x05,0xb0,0x00,0x13,0x00,0x3f,0x40,0x10,0x00,0x00,0x00,0x13,0x00,0x13,0x10,0x0e,0x0b,0x0a,0x07,0x05,0x02,0x01,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x22,0x12,0x01,0x03,0x02, +0x03,0x01,0x01,0x03,0x02,0x15,0x00,0x03,0x00,0x01,0x00,0x03,0x01,0x01,0x00,0x1d,0x05,0x04,0x02,0x02,0x02,0x07,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x23,0x11,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x04,0xcc,0xc5,0x5f,0xb2,0x7a,0xf1,0xf8,0xc6,0x8a,0x99, +0x68,0xc0,0x63,0x05,0xb0,0xfa,0x50,0x02,0x5b,0x1d,0x1a,0xd3,0xed,0x01,0xcc,0xfe,0x34,0xa5,0x7f,0x1c,0x1b,0x02,0xb9,0x00,0x00,0x01,0x00,0xa4,0x00,0x00,0x07,0x8f,0x05,0xb0,0x00,0x0b,0x00,0x36,0x40,0x12,0x00,0x00,0x00,0x0b,0x00,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x17,0x06,0x05,0x03,0x03,0x01,0x01,0x07,0x16,0x02,0x01,0x00,0x00,0x04,0x00,0x02,0x1b,0x00,0x04,0x04,0x08,0x04,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x01,0x69,0x02,0x50,0xc4,0x02,0x4d,0xc5,0xf9,0x15,0x05,0xb0,0xfa,0xea,0x05,0x16,0xfa,0xea,0x05,0x16,0xfa,0x50,0x05,0xb0, +0x00,0x01,0x00,0xa4,0xfe,0x98,0x08,0x39,0x05,0xb0,0x00,0x0f,0x00,0x42,0x40,0x16,0x00,0x00,0x00,0x0f,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x00,0x05,0x00,0x05,0x00,0x02,0x19,0x08,0x07,0x03,0x03,0x01,0x01,0x07,0x16,0x04,0x02,0x02, +0x00,0x00,0x06,0x00,0x02,0x1b,0x00,0x06,0x06,0x08,0x06,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x23,0x11,0x21,0x11,0x01,0x69,0x02,0x50,0xc4,0x02,0x4d,0xc5,0xaa,0xc5,0xf9,0x30,0x05,0xb0,0xfa,0xea,0x05,0x16,0xfa,0xea,0x05,0x16,0xfa,0xed,0xfd,0xfb,0x01,0x68,0x05,0xb0,0x00,0x00, +0x00,0x02,0x00,0x00,0x00,0x00,0x05,0x5e,0x05,0xb0,0x00,0x0c,0x00,0x15,0x00,0x44,0x40,0x12,0x0d,0x0d,0x0d,0x15,0x0d,0x14,0x10,0x0e,0x0c,0x0b,0x0a,0x08,0x04,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x00,0x01,0x06,0x01,0x05,0x04,0x01,0x05,0x01,0x00,0x1d,0x00,0x03,0x03,0x00,0x00,0x00,0x1b,0x00,0x00, +0x00,0x07,0x16,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x11,0x21,0x11,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11,0x21,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x02,0x0b,0x01,0x67,0xe9,0x01,0x03,0xfe,0xfc,0xe8,0xfd,0xd4,0xfe,0xba,0x02,0x0b,0x01,0x67,0x93,0x94,0x93,0x94, +0x05,0xb0,0xfd,0xc0,0xef,0xc5,0xc6,0xf6,0x05,0x15,0xfd,0xc0,0xfd,0xc5,0xa9,0x7b,0x77,0xa0,0x00,0x00,0x00,0x03,0x00,0xa3,0x00,0x00,0x06,0x32,0x05,0xb0,0x00,0x0a,0x00,0x13,0x00,0x17,0x00,0x41,0x40,0x14,0x0b,0x0b,0x17,0x16,0x15,0x14,0x0b,0x13,0x0b,0x12,0x0e,0x0c,0x0a,0x09,0x08,0x06,0x02,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x20,0x00,0x00,0x07,0x01,0x04,0x03,0x00,0x04,0x01,0x00,0x1d,0x06,0x01,0x02,0x02,0x07,0x16,0x00,0x03,0x03,0x01,0x01,0x02,0x1b,0x05,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11,0x33,0x19,0x01,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x01,0x23,0x11,0x33,0x01, +0x68,0x01,0x67,0xe9,0x01,0x03,0xfe,0xfc,0xe8,0xfd,0xd4,0xc5,0x01,0x67,0x93,0x94,0x93,0x94,0x03,0x63,0xc6,0xc6,0x03,0x70,0xef,0xc5,0xc6,0xf6,0x05,0xb0,0xfd,0x25,0xfd,0xc5,0xa9,0x7b,0x77,0xa0,0xfd,0x2b,0x05,0xb0,0x00,0x00,0x00,0x02,0x00,0xa3,0x00,0x00,0x04,0xbb,0x05,0xb0,0x00,0x0a,0x00,0x13,0x00,0x3b,0x40,0x10,0x0b,0x0b, +0x0b,0x13,0x0b,0x12,0x0e,0x0c,0x0a,0x09,0x08,0x06,0x02,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x00,0x00,0x05,0x01,0x04,0x03,0x00,0x04,0x01,0x00,0x1d,0x00,0x02,0x02,0x07,0x16,0x00,0x03,0x03,0x01,0x01,0x02,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21, +0x11,0x33,0x19,0x01,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x01,0x68,0x01,0x67,0xe9,0x01,0x03,0xfe,0xfc,0xe8,0xfd,0xd4,0xc5,0x01,0x67,0x93,0x94,0x93,0x94,0x03,0x70,0xef,0xc5,0xc6,0xf6,0x05,0xb0,0xfd,0x25,0xfd,0xc5,0xa9,0x7b,0x77,0xa0,0x00,0x00,0x00,0x01,0x00,0xb5,0xff,0xec,0x04,0xff,0x05,0xc6,0x00,0x21,0x00,0x62,0x40,0x16, +0x00,0x00,0x00,0x21,0x00,0x21,0x1f,0x1d,0x1a,0x19,0x18,0x17,0x14,0x12,0x10,0x0f,0x0c,0x0a,0x05,0x03,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3f,0x01,0x01,0x07,0x06,0x0e,0x01,0x03,0x02,0x02,0x15,0x08,0x01,0x07,0x06,0x05,0x06,0x07,0x05,0x29,0x00,0x02,0x04,0x03,0x04,0x02,0x03,0x29,0x00,0x05,0x00,0x04,0x02,0x05,0x04, +0x00,0x00,0x1d,0x00,0x06,0x06,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0d,0x16,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x08,0xb0,0x2f,0x2b,0x13,0x27,0x26,0x00,0x33,0x32,0x00,0x19,0x01,0x10,0x00,0x23,0x22,0x00,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x12,0x3d,0x01,0x21,0x35,0x21,0x35,0x34,0x02,0x23,0x22, +0x06,0x15,0xbc,0x02,0x05,0x01,0x29,0xf2,0xf7,0x01,0x38,0xfe,0xc8,0xf7,0xf7,0xfe,0xdc,0x05,0x02,0xbd,0xb2,0xa5,0xa4,0xc5,0xfd,0xc2,0x02,0x3e,0xc5,0xa4,0xa5,0xb2,0x03,0xde,0x06,0xcb,0x01,0x17,0xfe,0xa1,0xfe,0xf3,0xfe,0xfd,0xfe,0xf2,0xfe,0xa3,0x01,0x05,0xda,0x06,0x9a,0xb1,0x01,0x09,0xc6,0x51,0x9b,0x19,0xc6,0x01,0x0b,0xb2, +0x9b,0x00,0x00,0x00,0x00,0x02,0x00,0xbe,0xff,0xeb,0x06,0xe2,0x05,0xc5,0x00,0x15,0x00,0x23,0x00,0x7b,0x40,0x12,0x21,0x1f,0x1a,0x18,0x13,0x11,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x04,0x02,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x26,0x00,0x04,0x00,0x01,0x07,0x04,0x01,0x00,0x00,0x1d,0x00,0x06, +0x06,0x03,0x01,0x00,0x1b,0x05,0x01,0x03,0x03,0x07,0x16,0x00,0x07,0x07,0x00,0x01,0x00,0x1b,0x02,0x01,0x00,0x00,0x0e,0x00,0x17,0x05,0x1b,0x40,0x2e,0x00,0x04,0x00,0x01,0x07,0x04,0x01,0x00,0x00,0x1d,0x00,0x03,0x03,0x07,0x16,0x00,0x06,0x06,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0d,0x16,0x00,0x02,0x02,0x08,0x16,0x00,0x07,0x07, +0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x01,0x10,0x00,0x21,0x22,0x00,0x11,0x35,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x35,0x10,0x00,0x33,0x20,0x00,0x11,0x27,0x34,0x02,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32,0x36,0x35,0x06,0xe2,0xfe,0xb5,0xfe,0xf8,0xff,0xfe,0xc1,0xcd,0xc6,0xc6,0xcd, +0x01,0x3f,0xff,0x01,0x08,0x01,0x4b,0xc5,0xd8,0xb6,0xac,0xcd,0xcd,0xac,0xb7,0xd7,0x02,0x56,0xfe,0xf5,0xfe,0xa0,0x01,0x60,0x01,0x0b,0x22,0xfd,0x88,0x05,0xb0,0xfd,0x62,0x47,0x01,0x0a,0x01,0x62,0xfe,0x9f,0xfe,0xf5,0x02,0xc8,0x01,0x00,0xff,0x00,0xc8,0xfe,0xfb,0xca,0xff,0x00,0xff,0xcb,0x00,0x02,0x00,0x2c,0x00,0x00,0x04,0x36, +0x05,0xb0,0x00,0x0d,0x00,0x16,0x00,0x3f,0x40,0x0e,0x16,0x14,0x10,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x07,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x02,0x01,0x03,0x05,0x01,0x15,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x00,0x00,0x1d,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x02,0x01,0x00,0x00, +0x08,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x33,0x23,0x01,0x2e,0x01,0x35,0x34,0x24,0x33,0x21,0x11,0x23,0x11,0x21,0x01,0x21,0x22,0x06,0x15,0x14,0x16,0x33,0x21,0xfd,0xd1,0x01,0x56,0x8e,0x93,0x01,0x12,0xf1,0x01,0xd2,0xc5,0xfe,0xbd,0x01,0x43,0xfe,0xf3,0x9c,0xa2,0xa3,0x99,0x01,0x0f,0x02,0x95,0x33,0xbe,0x88,0xc7,0xdb,0xfa,0x50,0x02, +0x61,0x02,0xb4,0x8b,0x7a,0x7b,0x98,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x04,0x4e,0x02,0x06,0x00,0x44,0x00,0x00,0x00,0x02,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0x11,0x00,0x20,0x00,0x2e,0x00,0x9d,0x40,0x18,0x22,0x21,0x01,0x00,0x29,0x27,0x21,0x2e,0x22,0x2e,0x1b,0x19,0x16,0x15,0x13,0x11,0x08,0x06,0x00,0x20,0x01,0x20, +0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1d,0x58,0x40,0x39,0x17,0x01,0x02,0x03,0x1e,0x1d,0x0e,0x03,0x06,0x05,0x02,0x15,0x00,0x03,0x03,0x09,0x16,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x08,0x01,0x05,0x05,0x00,0x01,0x00,0x1b,0x07,0x01,0x00,0x00,0x10,0x16,0x00,0x06,0x06,0x01,0x01,0x00,0x1b, +0x00,0x01,0x01,0x0e,0x01,0x17,0x08,0x1b,0x40,0x37,0x17,0x01,0x02,0x03,0x1e,0x1d,0x0e,0x03,0x06,0x05,0x02,0x15,0x00,0x02,0x00,0x04,0x00,0x02,0x04,0x01,0x00,0x1d,0x00,0x03,0x03,0x09,0x16,0x08,0x01,0x05,0x05,0x00,0x01,0x00,0x1b,0x07,0x01,0x00,0x00,0x10,0x16,0x00,0x06,0x06,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17, +0x07,0x59,0xb0,0x2f,0x2b,0x01,0x32,0x12,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x3d,0x01,0x3c,0x01,0x37,0x35,0x10,0x12,0x37,0x3e,0x01,0x35,0x33,0x17,0x16,0x06,0x07,0x0e,0x01,0x1f,0x01,0x3e,0x01,0x17,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x02,0x6b,0xcf,0xf0,0xfe,0xfc,0xe0,0xe0,0xfe,0xfb,0x01,0xf7, +0xf0,0x8a,0x96,0x97,0x02,0x05,0xdc,0xd1,0x98,0xb8,0x03,0x03,0x3b,0xb8,0x41,0x8d,0x90,0x90,0x8f,0x8d,0x92,0x93,0x04,0x4e,0xfe,0xca,0xf1,0x16,0xf2,0xfe,0xcc,0x01,0x35,0xf1,0x16,0x08,0x0b,0x07,0xeb,0x01,0x34,0x01,0x23,0x0d,0x07,0x37,0x43,0x06,0x9e,0x7f,0x04,0x04,0xa0,0x9d,0x05,0x4b,0x5f,0x9b,0xe2,0xaa,0x16,0xac,0xe0,0xe0, +0xac,0x16,0xaa,0xe2,0x00,0x03,0x00,0x90,0x00,0x00,0x04,0x23,0x04,0x3a,0x00,0x0e,0x00,0x17,0x00,0x20,0x00,0x4f,0x40,0x16,0x0f,0x0f,0x00,0x00,0x20,0x1e,0x1a,0x18,0x0f,0x17,0x0f,0x16,0x12,0x10,0x00,0x0e,0x00,0x0d,0x03,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2c,0x08,0x01,0x03,0x04,0x01,0x15,0x00,0x04,0x07,0x01, +0x03,0x02,0x04,0x03,0x01,0x00,0x1d,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0a,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x06,0x01,0x01,0x01,0x08,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x33,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x25,0x33,0x32, +0x36,0x35,0x34,0x26,0x2b,0x01,0x90,0x01,0xab,0xd6,0xec,0x5c,0x54,0x65,0x71,0xdd,0xc6,0xfe,0xd5,0x01,0x2b,0x6d,0x70,0x70,0x6d,0xfe,0xd5,0xe7,0x7d,0x7f,0x80,0x7d,0xe6,0x04,0x3a,0x95,0x95,0x4c,0x77,0x1f,0x19,0x89,0x58,0x98,0x9c,0x01,0xda,0xfe,0xbe,0x53,0x4e,0x4d,0x54,0x97,0x4a,0x4b,0x4d,0x4e,0x00,0x00,0x00,0x01,0x00,0x8f, +0x00,0x00,0x03,0x3f,0x04,0x3a,0x00,0x05,0x00,0x28,0x40,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x03,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x13,0x00,0x00,0x00,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x0a,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x03,0x3f,0xfe,0x15,0xc5,0x02,0xb0,0x03, +0x9e,0xfc,0x62,0x04,0x3a,0x00,0x00,0x00,0x00,0x02,0x00,0x45,0xfe,0x9a,0x04,0xcb,0x04,0x3a,0x00,0x0e,0x00,0x15,0x00,0x48,0x40,0x16,0x01,0x00,0x15,0x14,0x13,0x12,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x00,0x0e,0x01,0x0e,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x05,0x01,0x03,0x00,0x03,0x00,0x00,0x19, +0x00,0x07,0x07,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x0a,0x16,0x06,0x02,0x08,0x03,0x00,0x00,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x08,0x04,0x17,0x05,0xb0,0x2f,0x2b,0x37,0x32,0x12,0x1b,0x01,0x21,0x11,0x33,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x01,0x0e,0x01,0x07,0x21,0x11,0x21,0xaf,0x4e,0x47,0x10,0x1a,0x02,0xce,0x8f,0xc5,0xfd, +0x04,0xc5,0x01,0xd5,0x0c,0x29,0x29,0x01,0xbb,0xfe,0xb1,0x9a,0x01,0x01,0x01,0x08,0x01,0x97,0xfc,0x60,0xfe,0x00,0x01,0x66,0xfe,0x9a,0x02,0x00,0x02,0x09,0xbf,0xf9,0x51,0x02,0xf1,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x04,0x4e,0x02,0x06,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x1a,0x00,0x00,0x05,0xa6,0x04,0x3a,0x00,0x15, +0x00,0x46,0x40,0x16,0x15,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23,0x13,0x08,0x02,0x00,0x05,0x01,0x15,0x07,0x01,0x05,0x02,0x01,0x00,0x01,0x05,0x00,0x00,0x00,0x1d,0x08,0x06,0x02,0x04,0x04,0x0a,0x16,0x09,0x03,0x02,0x01, +0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x23,0x01,0x23,0x09,0x01,0x33,0x01,0x33,0x11,0x33,0x11,0x33,0x01,0x33,0x09,0x01,0x23,0x03,0x7c,0x3a,0xc5,0x3a,0xfe,0xcf,0xf8,0x01,0x94,0xfe,0x8e,0xee,0x01,0x1e,0x35,0xc5,0x36,0x01,0x1f,0xed,0xfe,0x8e,0x01,0x94,0xf8,0x01,0xd5,0xfe,0x2b,0x01,0xd5,0xfe,0x2b, +0x02,0x3c,0x01,0xfe,0xfe,0x42,0x01,0xbe,0xfe,0x42,0x01,0xbe,0xfe,0x02,0xfd,0xc4,0x00,0x01,0x00,0x64,0xff,0xed,0x03,0xec,0x04,0x4c,0x00,0x2a,0x00,0x66,0x40,0x16,0x01,0x00,0x29,0x27,0x23,0x21,0x1f,0x1e,0x1b,0x19,0x0f,0x0d,0x0a,0x09,0x07,0x05,0x00,0x2a,0x01,0x2a,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x43,0x0b,0x01, +0x02,0x01,0x14,0x01,0x07,0x00,0x1d,0x01,0x06,0x05,0x03,0x15,0x00,0x02,0x01,0x00,0x01,0x02,0x00,0x29,0x00,0x05,0x07,0x06,0x07,0x05,0x06,0x29,0x08,0x01,0x00,0x00,0x07,0x05,0x00,0x07,0x01,0x00,0x1d,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x06,0x06,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x0e,0x04,0x17, +0x08,0xb0,0x2f,0x2b,0x01,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x24,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x02,0x33,0x73,0x6d,0x79,0x73,0x66,0x8a,0xba,0x02,0x06,0xfa,0xb8,0xc8,0xe9,0x61,0x56, +0x62,0x69,0xfc,0xc9,0xb9,0xfe,0xf6,0x06,0x02,0xba,0x90,0x71,0x75,0x8a,0x7a,0x79,0xd0,0x02,0x78,0x50,0x4a,0x43,0x5f,0x62,0x46,0x06,0x8b,0xaf,0xa3,0x97,0x49,0x7a,0x23,0x20,0x80,0x5b,0x97,0xad,0xab,0xa2,0x06,0x4c,0x70,0x64,0x49,0x56,0x51,0xa0,0x00,0x01,0x00,0x8f,0x00,0x00,0x03,0xfc,0x04,0x3a,0x00,0x0b,0x00,0x2c,0x40,0x0a, +0x09,0x08,0x07,0x06,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x15,0x0a,0x04,0x02,0x01,0x00,0x01,0x15,0x03,0x01,0x00,0x00,0x0a,0x16,0x02,0x01,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x33,0x11,0x23,0x11,0x27,0x01,0x23,0x11,0x33,0x11,0x17,0x03,0x37,0xc5,0xc5,0x06,0xfe,0x22,0xc4,0xc4,0x06, +0x04,0x3a,0xfb,0xc6,0x03,0x00,0x02,0xfc,0xfe,0x04,0x3a,0xfd,0x00,0x02,0x00,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x03,0xfc,0x05,0xf7,0x02,0x26,0x01,0xe4,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0x99,0x00,0x47,0x00,0x08,0xb1,0x01,0x01,0xb0,0x47,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x04,0x40,0x04,0x3a,0x00,0x0e, +0x00,0x39,0x40,0x0e,0x0e,0x0d,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x0b,0x01,0x00,0x03,0x01,0x15,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x04,0x01,0x02,0x02,0x0a,0x16,0x05,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11, +0x33,0x11,0x33,0x01,0x33,0x17,0x09,0x01,0x07,0x23,0x01,0xc3,0x65,0xc5,0xc5,0x54,0x01,0x83,0xe7,0x02,0xfe,0x3f,0x01,0xe3,0x02,0xf2,0x01,0xcb,0xfe,0x35,0x04,0x3a,0xfe,0x37,0x01,0xc9,0x05,0xfd,0xfe,0xfd,0xd2,0x05,0x00,0x00,0x00,0x01,0x00,0x1a,0x00,0x00,0x03,0xfc,0x04,0x3a,0x00,0x0f,0x00,0x39,0x40,0x10,0x00,0x00,0x00,0x0f, +0x00,0x0f,0x0c,0x0a,0x09,0x07,0x04,0x03,0x02,0x01,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1c,0x00,0x01,0x01,0x04,0x00,0x00,0x1b,0x05,0x01,0x04,0x04,0x0a,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x23,0x11,0x21,0x11,0x10,0x02,0x2b,0x01,0x3f,0x01,0x32, +0x36,0x35,0x11,0x03,0xfc,0xc5,0xfe,0x92,0xaa,0xcd,0x38,0x04,0x29,0x69,0x53,0x04,0x3a,0xfb,0xc6,0x03,0x9e,0xfe,0xce,0xfe,0xc0,0xfe,0xd4,0xa8,0x01,0xcd,0xf6,0x01,0xce,0x00,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x05,0x55,0x04,0x3a,0x00,0x0f,0x00,0x39,0x40,0x0e,0x0f,0x0e,0x0d,0x0c,0x09,0x08,0x05,0x04,0x03,0x02,0x01,0x00, +0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x0b,0x06,0x02,0x00,0x01,0x01,0x15,0x00,0x00,0x01,0x02,0x01,0x00,0x02,0x29,0x05,0x01,0x01,0x01,0x0a,0x16,0x04,0x03,0x02,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x33,0x01,0x33,0x11,0x23,0x11,0x27,0x01,0x23,0x01,0x07,0x11,0x23,0x11,0x33,0x02,0xf7,0x06,0x01,0x62, +0xf6,0xc5,0x06,0xfe,0xb4,0x88,0xfe,0xae,0x06,0xc5,0xfe,0x01,0x02,0x03,0x38,0xfb,0xc6,0x02,0xef,0x02,0xfd,0x0f,0x03,0x02,0x02,0xfd,0x00,0x04,0x3a,0x00,0x00,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x03,0xfb,0x04,0x3a,0x00,0x0b,0x00,0x33,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x18,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x00,0x00,0x1d,0x05,0x01,0x03,0x03,0x0a,0x16,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x33,0x03,0xfb,0xc5,0xfe,0x1e,0xc5,0xc5,0x01,0xe2,0xc5,0x01,0xcc,0xfe,0x34,0x04,0x3a,0xfe,0x2c,0x01, +0xd4,0x00,0x00,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x04,0x4e,0x02,0x06,0x00,0x52,0x00,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x03,0xfc,0x04,0x3a,0x00,0x07,0x00,0x2b,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x00,0x01,0x01,0x03,0x00,0x00,0x1b,0x00,0x03,0x03, +0x0a,0x16,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x21,0x11,0x23,0x11,0x21,0x03,0xfc,0xc5,0xfe,0x1d,0xc5,0x03,0x6d,0x03,0x9e,0xfc,0x62,0x04,0x3a,0x00,0xff,0xff,0x00,0x8f,0xfe,0x60,0x04,0x29,0x04,0x4e,0x02,0x06,0x00,0x53,0x00,0x00,0x00,0x01,0x00,0x61,0xff,0xeb,0x03,0xd9,0x04,0x4e,0x00,0x1d, +0x00,0x53,0x40,0x12,0x01,0x00,0x18,0x16,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03,0x00,0x1d,0x01,0x1d,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x34,0x12,0x01,0x04,0x05,0x05,0x01,0x00,0x01,0x02,0x15,0x00,0x04,0x05,0x01,0x05,0x04,0x01,0x29,0x00,0x01,0x00,0x05,0x01,0x00,0x27,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03, +0x03,0x10,0x16,0x06,0x01,0x00,0x00,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x07,0xb0,0x2f,0x2b,0x25,0x32,0x36,0x35,0x33,0x17,0x16,0x06,0x23,0x22,0x02,0x3d,0x01,0x34,0x12,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x02,0x3d,0x5b,0x88,0xb2,0x03,0x04,0xf8,0xa4,0xe4,0xf8,0xf9,0xe3, +0xb5,0xe7,0x04,0x02,0xb3,0x81,0x62,0x91,0x85,0x83,0x85,0x79,0x58,0x06,0x8c,0xd9,0x01,0x36,0xe7,0x2a,0xe5,0x01,0x37,0xe0,0xa3,0x06,0x63,0x8b,0xe1,0xa0,0x2a,0xa3,0xe0,0x00,0x00,0x00,0x00,0x01,0x00,0x47,0x00,0x00,0x03,0xd1,0x04,0x3a,0x00,0x07,0x00,0x2b,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x14,0x02,0x01,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x0a,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x35,0x21,0x03,0xd1,0xfe,0x9b,0xc5,0xfe,0xa0,0x03,0x8a,0x03,0xa1,0xfc,0x5f,0x03,0xa1,0x99,0x00,0x00,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8, +0x04,0x3a,0x02,0x06,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x62,0xfe,0x60,0x06,0xbf,0x06,0x18,0x00,0x1f,0x00,0x2d,0x00,0x3b,0x00,0x5e,0x40,0x16,0x39,0x37,0x32,0x30,0x2b,0x29,0x24,0x22,0x1d,0x1b,0x18,0x17,0x14,0x12,0x0d,0x0b,0x08,0x07,0x04,0x02,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3b,0x09,0x06,0x02,0x06,0x00,0x35, +0x34,0x27,0x26,0x04,0x07,0x06,0x19,0x16,0x02,0x03,0x07,0x03,0x15,0x00,0x01,0x01,0x09,0x16,0x09,0x01,0x06,0x06,0x00,0x01,0x00,0x1b,0x02,0x01,0x00,0x00,0x10,0x16,0x08,0x01,0x07,0x07,0x03,0x01,0x00,0x1b,0x05,0x01,0x03,0x03,0x0e,0x16,0x00,0x04,0x04,0x0c,0x04,0x17,0x07,0xb0,0x2f,0x2b,0x13,0x10,0x12,0x33,0x32,0x16,0x17,0x11, +0x33,0x11,0x3e,0x01,0x33,0x32,0x12,0x11,0x15,0x14,0x02,0x23,0x22,0x26,0x27,0x11,0x23,0x11,0x0e,0x01,0x23,0x22,0x02,0x35,0x25,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x1e,0x01,0x33,0x32,0x36,0x35,0x21,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x2e,0x01,0x23,0x22,0x06,0x15,0x62,0xdf,0xc9,0x58,0x8e,0x35,0xc5,0x37,0x97,0x60,0xc8,0xdf, +0xe0,0xc5,0x61,0x98,0x37,0xc5,0x36,0x8d,0x5a,0xc6,0xe0,0x05,0x98,0x91,0x8d,0x55,0x78,0x25,0x25,0x78,0x57,0x8c,0x90,0xfb,0x2d,0x87,0x8c,0x51,0x73,0x27,0x27,0x73,0x4f,0x8d,0x88,0x02,0x09,0x01,0x05,0x01,0x40,0x37,0x35,0x02,0x36,0xfd,0xba,0x3d,0x3f,0xfe,0xc1,0xfe,0xfa,0x15,0xea,0xfe,0xe1,0x3c,0x3a,0xfd,0xff,0x01,0xf7,0x36, +0x36,0x01,0x1f,0xea,0x15,0xb9,0xf1,0x4f,0x44,0xfd,0xf3,0x43,0x4b,0xcc,0xa3,0xa4,0xcb,0x48,0x41,0x02,0x22,0x3d,0x46,0xef,0xbb,0x00,0x00,0x00,0xff,0xff,0x00,0x2e,0x00,0x00,0x03,0xd4,0x04,0x3a,0x02,0x06,0x00,0x5b,0x00,0x00,0x00,0x01,0x00,0x8f,0xfe,0x9e,0x04,0x80,0x04,0x3a,0x00,0x0b,0x00,0x37,0x40,0x0e,0x0b,0x0a,0x09,0x08, +0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1c,0x00,0x04,0x01,0x04,0x00,0x02,0x19,0x02,0x01,0x00,0x00,0x0a,0x16,0x03,0x01,0x01,0x01,0x05,0x00,0x02,0x1b,0x00,0x05,0x05,0x08,0x05,0x17,0x04,0xb0,0x2f,0x2b,0x13,0x33,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x23,0x11,0x21,0x8f,0xc5,0x01, +0xe3,0xc5,0x84,0xc5,0xfc,0xd4,0x04,0x3a,0xfc,0x60,0x03,0xa0,0xfc,0x60,0xfe,0x04,0x01,0x62,0x00,0x00,0x00,0x01,0x00,0x7f,0x00,0x00,0x03,0xdc,0x04,0x3b,0x00,0x13,0x00,0x3a,0x40,0x0c,0x13,0x12,0x0f,0x0d,0x0a,0x09,0x06,0x04,0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x11,0x01,0x03,0x02,0x02,0x01,0x01,0x03, +0x02,0x15,0x00,0x03,0x00,0x01,0x00,0x03,0x01,0x01,0x00,0x1d,0x04,0x01,0x02,0x02,0x0a,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x04,0xb0,0x2f,0x2b,0x21,0x23,0x11,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x33,0x03,0xdc,0xc5,0x39,0x78,0x44,0xc4,0xdf,0xc5,0x70,0x6e,0x42,0x78,0x3b,0xc5,0x01, +0x83,0x0f,0x0f,0xce,0xca,0x01,0x3e,0xfe,0xc2,0x82,0x7a,0x0f,0x0f,0x02,0x1b,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x05,0xd8,0x04,0x3a,0x00,0x0b,0x00,0x36,0x40,0x12,0x00,0x00,0x00,0x0b,0x00,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x06,0x05,0x03,0x03,0x01,0x01, +0x0a,0x16,0x02,0x01,0x00,0x00,0x04,0x00,0x02,0x1b,0x00,0x04,0x04,0x08,0x04,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x01,0x54,0x01,0x7d,0xc5,0x01,0x7d,0xc5,0xfa,0xb7,0x04,0x3a,0xfc,0x60,0x03,0xa0,0xfc,0x60,0x03,0xa0,0xfb,0xc6,0x04,0x3a,0x00,0x01,0x00,0x8f,0xfe,0xae,0x06,0x88, +0x04,0x3a,0x00,0x0f,0x00,0x42,0x40,0x16,0x00,0x00,0x00,0x0f,0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x00,0x05,0x00,0x05,0x00,0x02,0x19,0x08,0x07,0x03,0x03,0x01,0x01,0x0a,0x16,0x04,0x02,0x02,0x00,0x00,0x06,0x00,0x02,0x1b,0x00,0x06, +0x06,0x08,0x06,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x23,0x11,0x21,0x11,0x01,0x54,0x01,0x7d,0xc5,0x01,0x7d,0xc5,0xb0,0xc3,0xfa,0xca,0x04,0x3a,0xfc,0x60,0x03,0xa0,0xfc,0x60,0x03,0xa0,0xfc,0x57,0xfe,0x1d,0x01,0x52,0x04,0x3a,0x00,0x00,0x00,0x02,0x00,0x2d,0x00,0x00,0x04,0xc6, +0x04,0x3a,0x00,0x0c,0x00,0x15,0x00,0x44,0x40,0x12,0x0d,0x0d,0x0d,0x15,0x0d,0x14,0x10,0x0e,0x0c,0x0b,0x0a,0x08,0x04,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x00,0x01,0x06,0x01,0x05,0x04,0x01,0x05,0x01,0x00,0x1d,0x00,0x03,0x03,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x0a,0x16,0x00,0x04,0x04,0x02,0x01, +0x00,0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x13,0x21,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x23,0x21,0x11,0x21,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x2d,0x01,0xf7,0x01,0x0d,0xc0,0xd5,0xd7,0xbe,0xfe,0x2e,0xfe,0xce,0x01,0xf7,0x01,0x0d,0x6a,0x65,0x66,0x69,0x04,0x3a,0xfe,0x64,0xb8,0x93,0x94,0xbf,0x03, +0x9f,0xfe,0x65,0xfe,0x96,0x66,0x4c,0x4a,0x6e,0x00,0x00,0x00,0x00,0x03,0x00,0xad,0x00,0x00,0x05,0x98,0x04,0x3a,0x00,0x0a,0x00,0x0e,0x00,0x17,0x00,0x41,0x40,0x14,0x0f,0x0f,0x0f,0x17,0x0f,0x16,0x12,0x10,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x06,0x02,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x20,0x00,0x00,0x07,0x01, +0x06,0x05,0x00,0x06,0x01,0x00,0x1d,0x04,0x01,0x02,0x02,0x0a,0x16,0x00,0x05,0x05,0x01,0x01,0x02,0x1b,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x32,0x16,0x15,0x14,0x06,0x23,0x21,0x11,0x33,0x01,0x23,0x11,0x33,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x01,0x72,0x01,0x0d,0xc0,0xd5,0xd7,0xbe,0xfe, +0x2e,0xc5,0x04,0x26,0xc5,0xc5,0xfb,0xda,0x01,0x0d,0x6a,0x65,0x66,0x69,0x02,0x9e,0xb8,0x93,0x94,0xbf,0x04,0x3a,0xfb,0xc6,0x04,0x3a,0xfd,0xca,0xfe,0x96,0x66,0x4c,0x4a,0x6e,0x00,0x00,0x00,0x02,0x00,0x99,0x00,0x00,0x04,0x00,0x04,0x3a,0x00,0x0a,0x00,0x13,0x00,0x3b,0x40,0x10,0x0b,0x0b,0x0b,0x13,0x0b,0x12,0x0e,0x0c,0x0a,0x09, +0x08,0x06,0x02,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1e,0x00,0x00,0x05,0x01,0x04,0x03,0x00,0x04,0x01,0x00,0x1d,0x00,0x02,0x02,0x0a,0x16,0x00,0x03,0x03,0x01,0x01,0x02,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x32,0x16,0x15,0x14,0x06,0x23,0x21,0x11,0x33,0x19,0x01,0x21,0x32,0x36,0x35, +0x34,0x26,0x23,0x01,0x5e,0x01,0x0d,0xc0,0xd5,0xd7,0xbe,0xfe,0x2e,0xc5,0x01,0x0d,0x6a,0x65,0x66,0x69,0x02,0x9e,0xb8,0x93,0x94,0xbf,0x04,0x3a,0xfd,0xca,0xfe,0x96,0x66,0x4c,0x4a,0x6e,0x00,0x01,0x00,0x63,0xff,0xeb,0x03,0xe3,0x04,0x4e,0x00,0x21,0x00,0x66,0x40,0x16,0x01,0x00,0x1e,0x1d,0x1c,0x1b,0x18,0x16,0x14,0x13,0x10,0x0e, +0x09,0x07,0x04,0x03,0x00,0x21,0x01,0x21,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x43,0x05,0x01,0x01,0x00,0x1a,0x01,0x04,0x06,0x12,0x01,0x05,0x04,0x03,0x15,0x00,0x01,0x00,0x07,0x00,0x01,0x07,0x29,0x00,0x04,0x06,0x05,0x06,0x04,0x05,0x29,0x00,0x07,0x00,0x06,0x04,0x07,0x06,0x00,0x00,0x1d,0x08,0x01,0x00,0x00,0x02,0x01, +0x00,0x1b,0x00,0x02,0x02,0x10,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x08,0xb0,0x2f,0x2b,0x01,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x12,0x1d,0x01,0x14,0x00,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x37,0x27,0x21,0x35,0x21,0x37,0x2e,0x01,0x02,0x08,0x5c,0x8f,0xb2,0x02, +0x06,0xff,0xa6,0xdc,0xff,0xff,0x00,0xdb,0xb7,0xee,0x05,0x02,0xb3,0x87,0x64,0x7e,0x8a,0x08,0x03,0xfe,0x7f,0x01,0x7f,0x02,0x0a,0x89,0x03,0xb3,0x7a,0x57,0x06,0x8b,0xdb,0xfe,0xc7,0xe3,0x2a,0xe4,0xfe,0xc7,0xdf,0xa3,0x06,0x63,0x8b,0xc4,0x8c,0x05,0x9a,0x05,0x83,0xb7,0x00,0x02,0x00,0x99,0xff,0xeb,0x06,0x24,0x04,0x4e,0x00,0x13, +0x00,0x21,0x00,0xad,0x40,0x12,0x1f,0x1d,0x18,0x16,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0c,0x0a,0x05,0x03,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x26,0x00,0x00,0x00,0x03,0x06,0x00,0x03,0x00,0x00,0x1d,0x00,0x07,0x07,0x01,0x01,0x00,0x1b,0x05,0x01,0x01,0x01,0x10,0x16,0x00,0x06,0x06,0x02,0x01, +0x00,0x1b,0x04,0x01,0x02,0x02,0x0e,0x02,0x17,0x05,0x1b,0x4b,0xb0,0x19,0x58,0x40,0x2a,0x00,0x00,0x00,0x03,0x06,0x00,0x03,0x00,0x00,0x1d,0x00,0x07,0x07,0x01,0x01,0x00,0x1b,0x05,0x01,0x01,0x01,0x10,0x16,0x00,0x04,0x04,0x08,0x16,0x00,0x06,0x06,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x06,0x1b,0x40,0x2e,0x00,0x00, +0x00,0x03,0x06,0x00,0x03,0x00,0x00,0x1d,0x00,0x05,0x05,0x0a,0x16,0x00,0x07,0x07,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x16,0x00,0x04,0x04,0x08,0x16,0x00,0x06,0x06,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x07,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x36,0x12,0x33,0x32,0x00,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x27, +0x23,0x11,0x23,0x11,0x33,0x01,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x5e,0x01,0x00,0x14,0xff,0xcd,0xe1,0x01,0x05,0xfe,0xfc,0xe0,0xd2,0xfe,0xff,0x10,0xff,0xc5,0xc5,0x01,0xc2,0x91,0x8f,0x8d,0x92,0x93,0x8e,0x8d,0x91,0x02,0x71,0xd4,0x01,0x09,0xfe,0xca,0xf1,0x16,0xf2,0xfe,0xcc,0x01,0x11,0xdb, +0xfe,0x29,0x04,0x3a,0xfd,0xd7,0xac,0xe0,0xe0,0xac,0x16,0xaa,0xe2,0xe2,0xaa,0x00,0x00,0x02,0x00,0x4e,0x00,0x00,0x03,0xf2,0x04,0x3a,0x00,0x0d,0x00,0x16,0x00,0x44,0x40,0x12,0x00,0x00,0x15,0x13,0x12,0x10,0x00,0x0d,0x00,0x0c,0x06,0x05,0x04,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x07,0x01,0x01,0x04, +0x01,0x15,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x00,0x00,0x1d,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x06,0x01,0x03,0x03,0x0a,0x16,0x02,0x01,0x00,0x00,0x08,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x11,0x23,0x11,0x21,0x01,0x23,0x01,0x2e,0x01,0x35,0x34,0x36,0x33,0x03,0x14,0x16,0x33,0x21,0x11,0x21,0x22,0x06,0x03,0xf2,0xc5,0xfe,0xf5, +0xff,0x00,0xd4,0x01,0x12,0x67,0x6f,0xdd,0xc2,0xd9,0x62,0x62,0x01,0x19,0xfe,0xfc,0x6b,0x6e,0x04,0x3a,0xfb,0xc6,0x01,0xa4,0xfe,0x5c,0x01,0xc1,0x25,0xa0,0x69,0x92,0xb9,0xfe,0xb3,0x48,0x66,0x01,0x62,0x6b,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x0a,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0x84,0x00,0x1c, +0x00,0x08,0xb1,0x02,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x05,0xcc,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x00,0x6a,0x19,0x1c,0x00,0x08,0xb1,0x02,0x02,0xb0,0x1c,0xb0,0x0d,0x2b,0x00,0x01,0xff,0xf2,0xfe,0x4b,0x04,0x01,0x06,0x18,0x00,0x29,0x00,0x6c,0x40,0x18,0x29,0x28,0x27,0x26, +0x25,0x24,0x23,0x22,0x21,0x20,0x1d,0x1b,0x16,0x14,0x0f,0x0d,0x0a,0x09,0x06,0x04,0x01,0x00,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x47,0x1f,0x02,0x02,0x02,0x05,0x12,0x01,0x04,0x06,0x11,0x01,0x03,0x04,0x03,0x15,0x00,0x02,0x05,0x06,0x05,0x02,0x06,0x29,0x0a,0x01,0x08,0x07,0x01,0x00,0x01,0x08,0x00,0x00,0x00,0x1d,0x00, +0x09,0x09,0x09,0x16,0x00,0x05,0x05,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x16,0x00,0x06,0x06,0x08,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x12,0x03,0x17,0x09,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x3e,0x01,0x33,0x32,0x16,0x1d,0x01,0x33,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11, +0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x23,0x35,0x33,0x35,0x33,0x15,0x33,0x02,0x40,0xec,0x38,0xa3,0x63,0xad,0xc1,0x01,0xac,0x9a,0x21,0x34,0x1c,0x0f,0x0d,0x44,0x11,0x3c,0x44,0x73,0x72,0x58,0x82,0x28,0xc5,0x9d,0x9d,0xc5,0xec,0x04,0xcc,0xfe,0xdd,0x4e,0x57,0xd0,0xd8,0xde,0xfd,0xdf,0xa7,0xb5,0x08,0x09,0x97,0x05,0x08, +0x67,0x5a,0x03,0x01,0x86,0x80,0x45,0x3e,0xfc,0xd5,0x04,0xcc,0x7c,0xd0,0xd0,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x03,0x3f,0x05,0xf0,0x02,0x26,0x01,0xdf,0x00,0x00,0x01,0x07,0x00,0x76,0x00,0xc9,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x01,0x00,0x61,0xff,0xeb,0x03,0xd9,0x04,0x4e,0x00,0x21, +0x00,0x6a,0x40,0x16,0x01,0x00,0x1e,0x1d,0x1c,0x1b,0x18,0x16,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03,0x00,0x21,0x01,0x21,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x47,0x12,0x01,0x04,0x05,0x1a,0x01,0x06,0x04,0x1f,0x01,0x01,0x07,0x05,0x01,0x00,0x01,0x04,0x15,0x00,0x04,0x05,0x06,0x05,0x04,0x06,0x29,0x00,0x01,0x07,0x00, +0x07,0x01,0x00,0x29,0x00,0x06,0x00,0x07,0x01,0x06,0x07,0x00,0x00,0x1d,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x08,0x01,0x00,0x00,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x08,0xb0,0x2f,0x2b,0x25,0x32,0x36,0x35,0x33,0x17,0x16,0x06,0x23,0x22,0x02,0x3d,0x01,0x34,0x12,0x33,0x32,0x16,0x0f,0x01, +0x23,0x34,0x26,0x23,0x22,0x06,0x07,0x17,0x21,0x15,0x21,0x07,0x1e,0x01,0x02,0x3d,0x5b,0x88,0xb2,0x03,0x04,0xf8,0xa4,0xe4,0xf8,0xf9,0xe3,0xb5,0xe7,0x04,0x02,0xb3,0x81,0x62,0x84,0x85,0x06,0x02,0x01,0x82,0xfe,0x7e,0x02,0x05,0x84,0x85,0x79,0x58,0x06,0x8c,0xd9,0x01,0x36,0xe7,0x2a,0xe5,0x01,0x37,0xe0,0xa3,0x06,0x63,0x8b,0xbc, +0x89,0x05,0x9a,0x05,0x8b,0xba,0x00,0x00,0xff,0xff,0x00,0x67,0xff,0xeb,0x03,0xc9,0x04,0x4e,0x02,0x06,0x00,0x56,0x00,0x00,0xff,0xff,0x00,0x9f,0x00,0x00,0x01,0x64,0x06,0x18,0x02,0x06,0x00,0x4c,0x00,0x00,0xff,0xff,0xff,0xa5,0x00,0x00,0x02,0x56,0x05,0xb6,0x02,0x26,0x00,0xf3,0x00,0x00,0x01,0x07,0x00,0x6a,0xfe,0xfb,0x00,0x06, +0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0xff,0xbe,0xfe,0x4b,0x01,0x72,0x06,0x18,0x02,0x06,0x00,0x4d,0x00,0x00,0x00,0x02,0x00,0x41,0x00,0x00,0x06,0x9e,0x04,0x3a,0x00,0x16,0x00,0x1f,0x00,0x4f,0x40,0x1a,0x17,0x17,0x00,0x00,0x17,0x1f,0x17,0x1e,0x1a,0x18,0x00,0x16,0x00,0x16,0x13,0x11,0x10,0x0e, +0x0b,0x0a,0x09,0x07,0x03,0x01,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x28,0x00,0x00,0x09,0x01,0x07,0x04,0x00,0x07,0x01,0x00,0x1d,0x00,0x02,0x02,0x05,0x00,0x00,0x1b,0x08,0x01,0x05,0x05,0x0a,0x16,0x06,0x01,0x04,0x04,0x01,0x01,0x00,0x1b,0x03,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x32,0x16, +0x15,0x14,0x06,0x23,0x21,0x11,0x21,0x11,0x10,0x02,0x2b,0x01,0x3f,0x01,0x32,0x36,0x35,0x11,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x03,0xfc,0x01,0x0d,0xbf,0xd6,0xd7,0xbe,0xfe,0x2e,0xfe,0xc2,0xb2,0xce,0x38,0x04,0x29,0x6a,0x5c,0x02,0xc8,0x01,0x0d,0x69,0x66,0x65,0x6a,0x04,0x3a,0xfe,0x65,0xb9,0x93,0x94,0xbf,0x03,0x9e, +0xfe,0xce,0xfe,0xc2,0xfe,0xd2,0x9e,0x01,0xda,0xf3,0x01,0xce,0xfd,0xcb,0xfe,0x93,0x70,0x4d,0x49,0x67,0x00,0x02,0x00,0x8f,0x00,0x00,0x06,0x9d,0x04,0x3a,0x00,0x12,0x00,0x1b,0x00,0x47,0x40,0x18,0x13,0x13,0x13,0x1b,0x13,0x1a,0x16,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0a,0x06,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x22,0x02,0x01,0x00,0x09,0x08,0x02,0x04,0x07,0x00,0x04,0x01,0x00,0x1d,0x06,0x01,0x01,0x01,0x0a,0x16,0x00,0x07,0x07,0x03,0x01,0x02,0x1b,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x33,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x23,0x21,0x11,0x21,0x11,0x23,0x11,0x33,0x01,0x11, +0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x01,0x54,0x01,0xe2,0xc5,0x01,0x0d,0xc0,0xd5,0xd7,0xbe,0xfe,0x2e,0xfe,0x1e,0xc5,0xc5,0x02,0xa7,0x01,0x0d,0x69,0x66,0x65,0x6a,0x02,0xa2,0x01,0x98,0xfe,0x64,0xb8,0x93,0x94,0xbf,0x02,0x09,0xfd,0xf7,0x04,0x3a,0xfd,0xcb,0xfe,0x93,0x70,0x4d,0x49,0x67,0x00,0x01,0x00,0x13,0x00,0x00,0x04,0x00, +0x06,0x18,0x00,0x1b,0x00,0x4d,0x40,0x14,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x0f,0x0d,0x0a,0x09,0x06,0x04,0x01,0x00,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2c,0x11,0x02,0x02,0x02,0x03,0x01,0x15,0x08,0x01,0x06,0x05,0x01,0x00,0x01,0x06,0x00,0x00,0x00,0x1d,0x00,0x07,0x07,0x09,0x16,0x00,0x03,0x03,0x01, +0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x16,0x04,0x01,0x02,0x02,0x08,0x02,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x23,0x35,0x33,0x35,0x33,0x15,0x21,0x02,0x94,0xfe,0xc0,0x38,0xa3,0x63,0xad,0xc1,0xc5,0x73,0x72,0x58,0x82,0x28,0xc5,0x7c, +0x7c,0xc5,0x01,0x40,0x04,0xbb,0xfe,0xee,0x4e,0x57,0xd0,0xd8,0xfd,0x5a,0x02,0xa8,0x86,0x80,0x45,0x3e,0xfc,0xd5,0x04,0xbb,0x9b,0xc2,0xc2,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x40,0x05,0xef,0x02,0x26,0x01,0xe6,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x3e,0x00,0x01,0x00,0x08,0xb1,0x01,0x01,0xb0,0x01,0xb0,0x0d,0x2b,0x00,0x00, +0xff,0xff,0x00,0x8f,0x00,0x00,0x03,0xfc,0x05,0xf4,0x02,0x26,0x01,0xe4,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xae,0x00,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x05,0xf7,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x06,0x01,0x54,0x56,0x47,0x00,0x08,0xb1,0x01,0x01,0xb0, +0x47,0xb0,0x0d,0x2b,0x00,0x01,0x00,0x8f,0xfe,0x9c,0x03,0xfc,0x04,0x3a,0x00,0x0b,0x00,0x3a,0x40,0x12,0x00,0x00,0x00,0x0b,0x00,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1b,0x00,0x03,0x02,0x03,0x2c,0x06,0x05,0x02,0x01,0x01,0x0a,0x16,0x00,0x00,0x00,0x02,0x00,0x02, +0x1b,0x04,0x01,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x23,0x11,0x21,0x11,0x01,0x54,0x01,0xe3,0xc5,0xfe,0xaf,0xc5,0xfe,0xa9,0x04,0x3a,0xfc,0x60,0x03,0xa0,0xfb,0xc6,0xfe,0x9c,0x01,0x64,0x04,0x3a,0x00,0x01,0x00,0x78,0xff,0xeb,0x07,0x28,0x05,0xc5,0x00,0x3c,0x00,0x63,0x40,0x18, +0x3a,0x38,0x33,0x31,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x26,0x24,0x1f,0x1d,0x18,0x16,0x11,0x0f,0x0b,0x09,0x04,0x02,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3e,0x1a,0x00,0x02,0x04,0x00,0x3c,0x1b,0x02,0x07,0x04,0x2f,0x28,0x02,0x05,0x06,0x0d,0x01,0x01,0x05,0x04,0x15,0x00,0x07,0x08,0x01,0x06,0x05,0x07,0x06,0x00,0x00,0x1d, +0x0a,0x01,0x04,0x04,0x00,0x01,0x00,0x1b,0x03,0x01,0x00,0x00,0x0d,0x16,0x09,0x01,0x05,0x05,0x01,0x01,0x00,0x1b,0x02,0x01,0x01,0x01,0x0e,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x3e,0x01,0x33,0x32,0x00,0x19,0x01,0x10,0x00,0x23,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23, +0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x23,0x35,0x21,0x15,0x23,0x11,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x04,0x4d,0x35,0x7a,0x43,0xd7,0x01,0x12,0xfe,0xe4,0xda,0x73,0xb1,0x3e,0x3f,0xb1,0x72,0xdb,0xfe,0xe5,0x01,0x11,0xd8,0x42,0x7a,0x36,0x3a,0x25,0x5d,0x36,0x83,0xa1,0xac,0x85, +0x67,0x79,0x1f,0xc6,0x02,0x52,0xc6,0x1c,0x7a,0x69,0x83,0xae,0xa2,0x82,0x37,0x5c,0x25,0x05,0x9a,0x14,0x17,0xfe,0xb1,0xfe,0xf8,0xfe,0xd4,0xfe,0xf7,0xfe,0xb2,0x3a,0x30,0x30,0x3a,0x01,0x4e,0x01,0x09,0x01,0x2c,0x01,0x08,0x01,0x4f,0x17,0x14,0x9c,0x15,0x17,0xfa,0xc0,0xfe,0xd2,0xc1,0xfc,0x40,0x2d,0x01,0x4c,0x9a,0x9a,0xfe,0xb4, +0x2c,0x41,0xfc,0xc1,0x01,0x2e,0xc0,0xfa,0x17,0x15,0x00,0x00,0x00,0x01,0x00,0x2e,0x00,0x00,0x05,0x4c,0x04,0x3a,0x00,0x18,0x00,0x41,0x40,0x10,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x0e,0x0d,0x06,0x05,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x04,0x01,0x04,0x01,0x01,0x15,0x00,0x04,0x01,0x00,0x01,0x04, +0x00,0x29,0x00,0x00,0x03,0x01,0x00,0x03,0x27,0x06,0x02,0x02,0x01,0x01,0x0a,0x16,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x37,0x13,0x03,0x33,0x13,0x1f,0x01,0x37,0x36,0x12,0x27,0x33,0x12,0x02,0x07,0x23,0x03,0x23,0x03,0x23,0x01,0x33,0x01,0xf8,0x11,0x06,0x13,0x85,0x74,0xc9,0xc4,0x1a,0x06,0x0b, +0x5a,0x46,0x0b,0xc9,0x03,0x9a,0x94,0x95,0x8f,0x06,0x9e,0x95,0xfe,0x6d,0xca,0x01,0x3f,0x4c,0x4c,0x01,0x89,0x01,0x72,0xfd,0x05,0x71,0x01,0x22,0x8c,0x01,0xd0,0xef,0xfe,0xca,0xfd,0xe6,0xea,0x01,0xc3,0xfe,0x3d,0x04,0x3a,0x00,0x00,0x02,0xff,0xcd,0x00,0x00,0x04,0xbb,0x05,0xb0,0x00,0x12,0x00,0x1b,0x00,0x4f,0x40,0x18,0x13,0x13, +0x13,0x1b,0x13,0x1a,0x16,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x08,0x04,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2a,0x06,0x01,0x04,0x03,0x01,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x01,0x09,0x01,0x08,0x07,0x01,0x08,0x01,0x00,0x1d,0x00,0x05,0x05,0x07,0x16,0x00,0x07,0x07,0x02,0x01,0x02, +0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x23,0x15,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11,0x23,0x35,0x33,0x35,0x33,0x15,0x33,0x03,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x02,0x4e,0xe6,0x01,0x67,0xe9,0x01,0x03,0xfe,0xfc,0xe8,0xfd,0xd4,0xd6,0xd6,0xc5,0xe6,0xe6,0x01,0x67,0x93,0x94,0x93,0x94,0x04, +0x4d,0xdd,0xef,0xc5,0xc6,0xf6,0x04,0x4d,0x9b,0xc8,0xc8,0xfd,0xed,0xfd,0xc5,0xa9,0x7b,0x77,0xa0,0x00,0x00,0x02,0xff,0xdb,0x00,0x00,0x04,0x00,0x06,0x1a,0x00,0x12,0x00,0x1b,0x00,0x4f,0x40,0x18,0x13,0x13,0x13,0x1b,0x13,0x1a,0x16,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x08,0x04,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x2a,0x06,0x01,0x04,0x03,0x01,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x01,0x09,0x01,0x08,0x07,0x01,0x08,0x01,0x00,0x1d,0x00,0x05,0x05,0x09,0x16,0x00,0x07,0x07,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x23,0x21,0x11,0x23, +0x35,0x33,0x11,0x33,0x11,0x21,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x02,0x9f,0xfe,0xbf,0x01,0x0d,0xc0,0xd5,0xd7,0xbe,0xfe,0x2e,0xbe,0xbe,0xc5,0x01,0x41,0xfe,0xbf,0x01,0x0d,0x6a,0x65,0x66,0x69,0x04,0x36,0xfe,0x68,0xb8,0x93,0x94,0xbf,0x04,0x36,0x9b,0x01,0x49,0xfe,0xb7,0xfd,0x33,0xfe,0x96,0x66,0x4c,0x4a,0x6e,0x00, +0x00,0x01,0x00,0xbf,0xff,0xec,0x06,0x92,0x05,0xc6,0x00,0x29,0x01,0x09,0x40,0x1a,0x29,0x28,0x25,0x23,0x21,0x20,0x1d,0x1b,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x0e,0x0c,0x09,0x08,0x06,0x04,0x01,0x00,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x42,0x1f,0x01,0x09,0x0a,0x0a,0x01,0x01,0x02,0x02,0x15, +0x00,0x09,0x0a,0x07,0x0a,0x09,0x07,0x29,0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x29,0x0b,0x01,0x07,0x04,0x01,0x00,0x02,0x07,0x00,0x00,0x00,0x1d,0x00,0x0a,0x0a,0x06,0x01,0x00,0x1b,0x08,0x01,0x06,0x06,0x07,0x16,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x05,0x01,0x03,0x03,0x0e,0x03,0x17,0x08,0x1b,0x4b,0xb0,0x19,0x58,0x40,0x46,0x1f, +0x01,0x09,0x0a,0x0a,0x01,0x01,0x02,0x02,0x15,0x00,0x09,0x0a,0x07,0x0a,0x09,0x07,0x29,0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x29,0x0b,0x01,0x07,0x04,0x01,0x00,0x02,0x07,0x00,0x00,0x00,0x1d,0x00,0x06,0x06,0x07,0x16,0x00,0x0a,0x0a,0x08,0x01,0x00,0x1b,0x00,0x08,0x08,0x0d,0x16,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x05,0x01,0x03, +0x03,0x0e,0x03,0x17,0x09,0x1b,0x40,0x4a,0x1f,0x01,0x09,0x0a,0x0a,0x01,0x01,0x02,0x02,0x15,0x00,0x09,0x0a,0x07,0x0a,0x09,0x07,0x29,0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x29,0x0b,0x01,0x07,0x04,0x01,0x00,0x02,0x07,0x00,0x00,0x00,0x1d,0x00,0x06,0x06,0x07,0x16,0x00,0x0a,0x0a,0x08,0x01,0x00,0x1b,0x00,0x08,0x08,0x0d,0x16,0x00, +0x05,0x05,0x08,0x16,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x0a,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x15,0x14,0x12,0x33,0x32,0x36,0x35,0x33,0x17,0x16,0x00,0x23,0x22,0x00,0x11,0x35,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x35,0x10,0x00,0x33,0x32,0x00,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x02,0x1d,0x01, +0x21,0x04,0xed,0xfe,0x21,0xc4,0xa5,0xa4,0xb4,0xbd,0x02,0x04,0xfe,0xd8,0xf3,0xf7,0xfe,0xc9,0xc4,0xc6,0xc6,0xc4,0x01,0x37,0xf7,0xf7,0x01,0x24,0x04,0x02,0xbd,0xb4,0xa4,0xa5,0xc4,0x01,0xdf,0x02,0x7f,0x28,0xc7,0xfe,0xf6,0xb1,0x9c,0x06,0xcd,0xfe,0xec,0x01,0x5e,0x01,0x0d,0x28,0xfd,0x81,0x05,0xb0,0xfd,0x69,0x41,0x01,0x0d,0x01, +0x5f,0xfe,0xf9,0xd9,0x06,0x99,0xb2,0xfe,0xf6,0xc5,0x43,0x00,0x00,0x01,0x00,0x97,0xff,0xeb,0x05,0x83,0x04,0x4e,0x00,0x27,0x01,0x21,0x40,0x1a,0x27,0x26,0x23,0x21,0x1f,0x1e,0x1b,0x19,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0e,0x0c,0x09,0x08,0x06,0x04,0x01,0x00,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58, +0x40,0x4a,0x1d,0x01,0x09,0x0a,0x25,0x01,0x07,0x09,0x02,0x01,0x02,0x00,0x0a,0x01,0x01,0x02,0x04,0x15,0x00,0x09,0x0a,0x07,0x0a,0x09,0x07,0x29,0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x29,0x0b,0x01,0x07,0x04,0x01,0x00,0x02,0x07,0x00,0x00,0x00,0x1d,0x00,0x0a,0x0a,0x06,0x01,0x00,0x1b,0x08,0x01,0x06,0x06,0x0a,0x16,0x00,0x01,0x01, +0x03,0x01,0x00,0x1b,0x05,0x01,0x03,0x03,0x0e,0x03,0x17,0x08,0x1b,0x4b,0xb0,0x19,0x58,0x40,0x4e,0x1d,0x01,0x09,0x0a,0x25,0x01,0x07,0x09,0x02,0x01,0x02,0x00,0x0a,0x01,0x01,0x02,0x04,0x15,0x00,0x09,0x0a,0x07,0x0a,0x09,0x07,0x29,0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x29,0x0b,0x01,0x07,0x04,0x01,0x00,0x02,0x07,0x00,0x00,0x00, +0x1d,0x00,0x0a,0x0a,0x06,0x01,0x00,0x1b,0x08,0x01,0x06,0x06,0x0a,0x16,0x00,0x05,0x05,0x08,0x16,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x09,0x1b,0x40,0x52,0x1d,0x01,0x09,0x0a,0x25,0x01,0x07,0x09,0x02,0x01,0x02,0x00,0x0a,0x01,0x01,0x02,0x04,0x15,0x00,0x09,0x0a,0x07,0x0a,0x09,0x07,0x29,0x00,0x02, +0x00,0x01,0x00,0x02,0x01,0x29,0x0b,0x01,0x07,0x04,0x01,0x00,0x02,0x07,0x00,0x00,0x00,0x1d,0x00,0x06,0x06,0x0a,0x16,0x00,0x0a,0x0a,0x08,0x01,0x00,0x1b,0x00,0x08,0x08,0x10,0x16,0x00,0x05,0x05,0x08,0x16,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x0a,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x07,0x1e,0x01, +0x33,0x32,0x36,0x35,0x33,0x17,0x16,0x06,0x23,0x22,0x02,0x27,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x36,0x12,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x07,0x17,0x21,0x04,0x19,0xfe,0xc1,0x02,0x06,0x84,0x85,0x5b,0x88,0xb2,0x03,0x04,0xf8,0xa4,0xd5,0xf6,0x0f,0xb1,0xc5,0xc5,0xb1,0x0f,0xf6,0xd5,0xb5,0xe7,0x04,0x02, +0xb3,0x81,0x62,0x85,0x85,0x05,0x02,0x01,0x3f,0x01,0xcd,0x05,0x8b,0xb8,0x79,0x58,0x06,0x8c,0xd9,0x01,0x10,0xd2,0xfe,0x33,0x04,0x3a,0xfe,0x2e,0xd2,0x01,0x14,0xe0,0xa3,0x06,0x63,0x8b,0xbd,0x89,0x05,0x00,0x00,0x02,0x00,0x2b,0x00,0x00,0x04,0xe3,0x05,0xb0,0x00,0x0b,0x00,0x0f,0x00,0x40,0x40,0x12,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a, +0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x00,0x07,0x04,0x06,0x04,0x07,0x06,0x29,0x00,0x06,0x02,0x01,0x00,0x01,0x06,0x00,0x00,0x00,0x1d,0x00,0x04,0x04,0x07,0x16,0x05,0x03,0x02,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x23,0x03,0x23, +0x01,0x33,0x01,0x23,0x01,0x21,0x03,0x23,0x03,0x85,0xa1,0xc4,0x94,0x98,0xc9,0x02,0x0d,0xa9,0x02,0x02,0xc9,0xfd,0xab,0x01,0x88,0xbf,0x06,0x01,0xb6,0xfe,0x4a,0x01,0xb6,0xfe,0x4a,0x05,0xb0,0xfa,0x50,0x02,0x5a,0x02,0x33,0x00,0x00,0x02,0x00,0x0d,0x00,0x00,0x04,0x29,0x04,0x3a,0x00,0x0b,0x00,0x11,0x00,0x40,0x40,0x12,0x10,0x0f, +0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x00,0x07,0x04,0x06,0x04,0x07,0x06,0x29,0x00,0x06,0x02,0x01,0x00,0x01,0x06,0x00,0x00,0x00,0x1d,0x00,0x04,0x04,0x0a,0x16,0x05,0x03,0x02,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23, +0x11,0x23,0x03,0x23,0x01,0x33,0x01,0x23,0x01,0x21,0x03,0x27,0x23,0x07,0x02,0xe9,0x6a,0xc4,0x71,0x74,0xc9,0x01,0xb8,0xa9,0x01,0xbb,0xc9,0xfe,0x27,0x01,0x24,0x7e,0x12,0x06,0x12,0x01,0x26,0xfe,0xda,0x01,0x26,0xfe,0xda,0x04,0x3a,0xfb,0xc6,0x01,0xc1,0x01,0x38,0x44,0x44,0x00,0x00,0x00,0x00,0x02,0x00,0xd1,0x00,0x00,0x06,0xf4, +0x05,0xb0,0x00,0x13,0x00,0x17,0x00,0x4c,0x40,0x1a,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x00,0x0b,0x01,0x00,0x01,0x0b,0x00,0x29,0x0a,0x01,0x00,0x07,0x05,0x02,0x03,0x02,0x00,0x03,0x00,0x02, +0x1d,0x09,0x01,0x01,0x01,0x07,0x16,0x08,0x06,0x04,0x03,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x01,0x33,0x01,0x23,0x03,0x23,0x11,0x23,0x11,0x23,0x03,0x23,0x13,0x21,0x11,0x23,0x11,0x33,0x01,0x21,0x03,0x23,0x01,0x97,0x01,0x7e,0x01,0x34,0xa9,0x02,0x02,0xc9,0x95,0xa1,0xc4,0x94,0x98,0xc9,0x9e,0xfe,0xbd,0xc6, +0xc6,0x02,0x3f,0x01,0x88,0xbf,0x06,0x02,0x5b,0x03,0x55,0xfa,0x50,0x01,0xb6,0xfe,0x4a,0x01,0xb6,0xfe,0x4a,0x01,0xb7,0xfe,0x49,0x05,0xb0,0xfc,0xaa,0x02,0x33,0x00,0x00,0x02,0x00,0xba,0x00,0x00,0x05,0xe8,0x04,0x3a,0x00,0x13,0x00,0x19,0x00,0x4c,0x40,0x1a,0x18,0x17,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a, +0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x00,0x0b,0x01,0x00,0x01,0x0b,0x00,0x29,0x0a,0x01,0x00,0x07,0x05,0x02,0x03,0x02,0x00,0x03,0x00,0x02,0x1d,0x09,0x01,0x01,0x01,0x0a,0x16,0x08,0x06,0x04,0x03,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x01,0x33, +0x01,0x23,0x03,0x23,0x11,0x23,0x11,0x23,0x03,0x23,0x13,0x23,0x11,0x23,0x11,0x33,0x01,0x21,0x03,0x27,0x23,0x07,0x01,0x7f,0x01,0x03,0x01,0x02,0xa9,0x01,0xbb,0xc9,0x77,0x6a,0xc4,0x71,0x74,0xc9,0x77,0xc4,0xc5,0xc5,0x01,0xc7,0x01,0x24,0x7e,0x12,0x06,0x12,0x01,0xc1,0x02,0x79,0xfb,0xc6,0x01,0x26,0xfe,0xda,0x01,0x26,0xfe,0xda, +0x01,0x25,0xfe,0xdb,0x04,0x3a,0xfd,0x87,0x01,0x38,0x44,0x44,0x00,0x02,0x00,0x95,0x00,0x00,0x06,0x4b,0x05,0xb0,0x00,0x21,0x00,0x25,0x00,0x59,0x40,0x18,0x25,0x24,0x23,0x22,0x21,0x20,0x1d,0x1c,0x1b,0x19,0x16,0x15,0x12,0x10,0x0e,0x0d,0x0b,0x09,0x06,0x05,0x02,0x00,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x34,0x1f,0x1e, +0x02,0x0a,0x07,0x0f,0x0c,0x02,0x01,0x02,0x02,0x15,0x04,0x01,0x02,0x01,0x00,0x02,0x01,0x02,0x1a,0x00,0x0a,0x0a,0x07,0x00,0x00,0x1b,0x08,0x01,0x07,0x07,0x07,0x16,0x09,0x06,0x02,0x00,0x00,0x01,0x00,0x02,0x1b,0x05,0x03,0x02,0x01,0x01,0x08,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x2b, +0x01,0x07,0x11,0x23,0x11,0x27,0x23,0x22,0x06,0x15,0x11,0x23,0x11,0x34,0x36,0x3b,0x01,0x01,0x33,0x17,0x37,0x35,0x21,0x01,0x33,0x01,0x21,0x04,0x4c,0x16,0xef,0xfa,0xc5,0x8b,0x99,0x74,0x19,0xc5,0x11,0x83,0x99,0x89,0xc5,0xf7,0xf0,0x25,0xfe,0x79,0xe2,0x05,0x06,0x03,0xcc,0xfd,0x9f,0x0a,0x01,0x1c,0xfd,0xbe,0x03,0x2e,0xd1,0xea, +0xfe,0x8d,0x01,0x73,0xa2,0x7e,0x2a,0xfd,0x97,0x02,0x78,0x1b,0x7e,0xa2,0xfe,0x8d,0x01,0x73,0xea,0xd1,0x02,0x82,0x09,0x02,0x07,0xfd,0x7e,0x01,0xe7,0x00,0x00,0x00,0x00,0x02,0x00,0x95,0x00,0x00,0x05,0x57,0x04,0x3b,0x00,0x1f,0x00,0x22,0x00,0x53,0x40,0x18,0x22,0x21,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x17,0x16,0x13,0x11,0x0f,0x0e, +0x0c,0x0a,0x07,0x06,0x03,0x02,0x01,0x00,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2e,0x20,0x01,0x01,0x0a,0x10,0x0d,0x02,0x02,0x03,0x02,0x15,0x07,0x01,0x01,0x05,0x01,0x03,0x02,0x01,0x03,0x01,0x00,0x1d,0x00,0x0a,0x0a,0x00,0x00,0x00,0x1b,0x09,0x08,0x02,0x00,0x00,0x0a,0x16,0x06,0x04,0x02,0x02,0x02,0x08,0x02,0x17,0x05, +0xb0,0x2f,0x2b,0x01,0x33,0x01,0x1e,0x01,0x1d,0x01,0x23,0x35,0x34,0x26,0x2b,0x01,0x07,0x11,0x23,0x11,0x27,0x23,0x22,0x06,0x1d,0x01,0x23,0x35,0x34,0x36,0x37,0x01,0x33,0x35,0x21,0x01,0x13,0x21,0x04,0x63,0x7b,0xfe,0xe3,0xc6,0xd0,0xc6,0x77,0x84,0x2f,0x0b,0xc5,0x06,0x3c,0x85,0x76,0xc5,0xd4,0xcd,0xfe,0xe4,0x9e,0x02,0xab,0xfe, +0x99,0xb0,0xfe,0xa0,0x04,0x3a,0xfe,0x21,0x0a,0xd2,0xdd,0xa2,0xa2,0xa3,0x7d,0x13,0xfe,0x51,0x01,0xb8,0x0a,0x7d,0xa3,0xa2,0xa2,0xe2,0xd0,0x07,0x01,0xdf,0x01,0xfe,0x24,0x01,0x40,0x00,0x00,0x04,0x00,0xbe,0x00,0x00,0x08,0x82,0x05,0xb0,0x00,0x03,0x00,0x07,0x00,0x29,0x00,0x2d,0x00,0x65,0x40,0x20,0x2d,0x2c,0x2b,0x2a,0x29,0x28, +0x25,0x24,0x23,0x21,0x1e,0x1d,0x1a,0x18,0x16,0x15,0x13,0x11,0x0e,0x0d,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x38,0x27,0x26,0x02,0x0e,0x03,0x17,0x14,0x02,0x02,0x00,0x02,0x15,0x08,0x06,0x02,0x00,0x02,0x01,0x00,0x01,0x02,0x1a,0x00,0x0e,0x0e,0x03,0x00,0x00,0x1b,0x0c, +0x0b,0x02,0x03,0x03,0x07,0x16,0x0d,0x0a,0x04,0x03,0x01,0x01,0x02,0x00,0x02,0x1b,0x09,0x07,0x05,0x03,0x02,0x02,0x08,0x02,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x01,0x23,0x11,0x33,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x2b,0x01,0x07,0x11,0x23,0x11,0x27,0x23,0x22,0x06,0x15,0x11,0x23,0x11,0x34,0x36,0x3b, +0x01,0x01,0x33,0x17,0x37,0x35,0x21,0x01,0x33,0x01,0x21,0x04,0xfc,0xfc,0x6d,0x03,0x93,0xfc,0x88,0xc6,0xc6,0x04,0xff,0x16,0xef,0xfa,0xc5,0x8b,0x99,0x74,0x19,0xc5,0x11,0x83,0x99,0x89,0xc5,0xf7,0xf0,0x25,0xfe,0x79,0xe2,0x05,0x06,0x03,0xcc,0xfd,0x9f,0x0a,0x01,0x1c,0xfd,0xbe,0x02,0x94,0x9a,0xfc,0xd2,0x05,0xb0,0xfd,0x7e,0xd1, +0xea,0xfe,0x8d,0x01,0x73,0xa2,0x7e,0x2a,0xfd,0x97,0x02,0x78,0x1b,0x7e,0xa2,0xfe,0x8d,0x01,0x73,0xea,0xd1,0x02,0x82,0x09,0x02,0x07,0xfd,0x7e,0x01,0xe7,0x00,0x00,0x00,0x04,0x00,0x99,0x00,0x00,0x07,0x51,0x04,0x3b,0x00,0x03,0x00,0x07,0x00,0x27,0x00,0x2a,0x00,0x5f,0x40,0x20,0x2a,0x29,0x27,0x26,0x25,0x24,0x23,0x22,0x1f,0x1e, +0x1b,0x19,0x17,0x16,0x14,0x12,0x0f,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0f,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x32,0x28,0x01,0x01,0x0e,0x18,0x15,0x02,0x02,0x00,0x02,0x15,0x0b,0x05,0x02,0x01,0x09,0x07,0x02,0x00,0x02,0x01,0x00,0x01,0x02,0x1d,0x00,0x0e,0x0e,0x03,0x00,0x00,0x1b,0x0d,0x0c, +0x04,0x03,0x03,0x03,0x0a,0x16,0x0a,0x08,0x06,0x03,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x01,0x23,0x11,0x33,0x21,0x33,0x01,0x1e,0x01,0x1d,0x01,0x23,0x35,0x34,0x26,0x2b,0x01,0x07,0x11,0x23,0x11,0x27,0x23,0x22,0x06,0x1d,0x01,0x23,0x35,0x34,0x36,0x37,0x01,0x33,0x35,0x21,0x01,0x13,0x21,0x04,0xf8, +0xfc,0x0b,0x03,0xf5,0xfc,0x66,0xc5,0xc5,0x04,0xff,0x7b,0xfe,0xe3,0xc6,0xd0,0xc6,0x77,0x84,0x2f,0x0b,0xc5,0x06,0x3c,0x85,0x76,0xc5,0xd4,0xcd,0xfe,0xe4,0x9e,0x02,0xab,0xfe,0x99,0xb0,0xfe,0xa0,0x01,0xc2,0x9b,0xfd,0xa3,0x04,0x3a,0xfe,0x21,0x0a,0xd2,0xdd,0xa2,0xa2,0xa3,0x7d,0x13,0xfe,0x51,0x01,0xb8,0x0a,0x7d,0xa3,0xa2,0xa2, +0xe2,0xd0,0x07,0x01,0xdf,0x01,0xfe,0x24,0x01,0x40,0x00,0x00,0x00,0x02,0x00,0x4a,0xfe,0x44,0x03,0xa4,0x07,0x72,0x00,0x2c,0x00,0x35,0x00,0x66,0x40,0x18,0x01,0x00,0x35,0x34,0x32,0x31,0x2f,0x2e,0x2b,0x29,0x25,0x22,0x17,0x14,0x0a,0x08,0x07,0x05,0x00,0x2c,0x01,0x2c,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x41,0x33,0x30, +0x2d,0x03,0x07,0x06,0x0f,0x01,0x05,0x00,0x02,0x15,0x1d,0x1c,0x02,0x03,0x12,0x08,0x01,0x06,0x07,0x06,0x2b,0x00,0x07,0x02,0x07,0x2b,0x09,0x01,0x00,0x00,0x05,0x04,0x00,0x05,0x01,0x00,0x1d,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x09,0xb0, +0x2f,0x2b,0x01,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x35,0x21,0x32,0x04,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x04,0x2b,0x01,0x22,0x06,0x15,0x14,0x16,0x17,0x07,0x2e,0x01,0x27,0x34,0x36,0x3b,0x01,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x01,0x37,0x33,0x15,0x05,0x23,0x27,0x35,0x33,0x01,0x9c,0x9a,0x92,0x8f,0x89,0xfe,0xd0, +0x01,0x30,0xd3,0x01,0x0b,0x82,0x73,0x81,0x8a,0xfe,0xf7,0xd3,0x32,0x4c,0x45,0x5d,0x42,0x4f,0x6f,0x9b,0x01,0xb3,0xa1,0x2a,0x81,0x95,0xa4,0x9e,0x8f,0x01,0x0a,0x93,0xaa,0xfe,0xff,0x77,0xfe,0xa6,0x03,0x39,0x7f,0x72,0x66,0x85,0x9b,0xd5,0xb5,0x67,0xa4,0x2c,0x29,0xb0,0x7f,0xc8,0xe3,0x3b,0x35,0x46,0x55,0x1e,0x7f,0x2f,0xa4,0x6f, +0x81,0x80,0x95,0x77,0x85,0x86,0x9b,0x03,0xa5,0x94,0x12,0xf5,0xf3,0x14,0x00,0x00,0x00,0x02,0x00,0x49,0xfe,0x44,0x03,0x79,0x06,0x1a,0x00,0x2c,0x00,0x35,0x00,0x69,0x40,0x18,0x01,0x00,0x35,0x34,0x32,0x31,0x2f,0x2e,0x2b,0x29,0x25,0x22,0x17,0x14,0x0a,0x08,0x07,0x05,0x00,0x2c,0x01,0x2c,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x44,0x33,0x30,0x2d,0x03,0x07,0x06,0x0f,0x01,0x05,0x00,0x02,0x15,0x1d,0x1c,0x02,0x03,0x12,0x00,0x07,0x06,0x02,0x06,0x07,0x02,0x29,0x09,0x01,0x00,0x00,0x05,0x04,0x00,0x05,0x01,0x00,0x1d,0x08,0x01,0x06,0x06,0x09,0x16,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0a,0x16,0x00,0x04,0x04,0x03,0x01,0x02,0x1b,0x00, +0x03,0x03,0x0e,0x03,0x17,0x09,0xb0,0x2f,0x2b,0x01,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x35,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x06,0x15,0x14,0x16,0x17,0x07,0x2e,0x01,0x27,0x34,0x36,0x3b,0x01,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x13,0x37,0x33,0x15,0x05,0x23,0x27,0x35,0x33,0x01, +0x9a,0x85,0x7e,0x7b,0x74,0xfe,0xd1,0x01,0x2f,0xc0,0xf5,0x67,0x5b,0x69,0x6f,0xf3,0xc0,0x31,0x4c,0x45,0x5e,0x42,0x50,0x6f,0x9b,0x01,0xb3,0xa1,0x29,0x6e,0x7f,0x8f,0x8a,0x8f,0xc4,0x93,0xaa,0xfe,0xff,0x77,0xfe,0xa6,0x02,0x6a,0x53,0x4b,0x41,0x55,0x9c,0xa8,0x8e,0x49,0x77,0x23,0x21,0x7a,0x56,0x97,0xad,0x3b,0x35,0x46,0x56,0x1d, +0x7f,0x2f,0xa4,0x6f,0x81,0x80,0x5b,0x4a,0x52,0x51,0x9b,0x03,0x1c,0x94,0x12,0xf5,0xf3,0x14,0x00,0x00,0xff,0xff,0x00,0x57,0x00,0x00,0x05,0x1b,0x05,0xb0,0x02,0x06,0x01,0x82,0x00,0x00,0xff,0xff,0x00,0x5b,0xfe,0x26,0x05,0x4d,0x04,0x3a,0x02,0x06,0x01,0xa2,0x00,0x00,0x00,0x03,0x00,0x71,0xff,0xeb,0x05,0x02,0x05,0xc5,0x00,0x0d, +0x00,0x1e,0x00,0x2f,0x00,0x5e,0x40,0x16,0x0f,0x0e,0x2d,0x2b,0x26,0x24,0x23,0x21,0x1d,0x1b,0x16,0x14,0x0e,0x1e,0x0f,0x1e,0x0b,0x09,0x04,0x02,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3b,0x19,0x11,0x02,0x02,0x04,0x28,0x1f,0x02,0x05,0x06,0x02,0x15,0x00,0x04,0x00,0x06,0x05,0x04,0x06,0x01,0x00,0x1d,0x08,0x01,0x02,0x00, +0x05,0x07,0x02,0x05,0x01,0x00,0x1d,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x07,0x07,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x00,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x10,0x00,0x21,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x20,0x00,0x11,0x05,0x32,0x36,0x37,0x35,0x34,0x02,0x23,0x22,0x02,0x1d,0x01,0x3e,0x01, +0x33,0x32,0x04,0x05,0x0e,0x01,0x23,0x22,0x26,0x23,0x22,0x06,0x07,0x15,0x14,0x12,0x33,0x32,0x36,0x35,0x05,0x02,0xfe,0xb5,0xfe,0xf8,0xff,0xfe,0xc1,0x01,0x3f,0xff,0x01,0x08,0x01,0x4b,0xfe,0x8a,0x37,0x5f,0x1b,0xd8,0xb6,0xac,0xcd,0x24,0x57,0x31,0x57,0x01,0x02,0x01,0x02,0x25,0x5a,0x32,0x6d,0xed,0x50,0x37,0x5c,0x19,0xcd,0xac, +0xb7,0xd7,0x02,0x56,0xfe,0xf5,0xfe,0xa0,0x01,0x60,0x01,0x0b,0x01,0x03,0x01,0x0a,0x01,0x62,0xfe,0x9f,0xfe,0xf5,0x8c,0x29,0x21,0x44,0xc8,0x01,0x00,0xff,0x00,0xc8,0x44,0x1c,0x20,0x86,0x63,0x1b,0x1d,0x85,0x2f,0x23,0x0f,0xca,0xff,0x00,0xff,0xcb,0x00,0x03,0x00,0x61,0xff,0xeb,0x04,0x2a,0x04,0x4e,0x00,0x0d,0x00,0x1d,0x00,0x2d, +0x00,0x65,0x40,0x1a,0x1f,0x1e,0x0f,0x0e,0x2c,0x2a,0x25,0x23,0x1e,0x2d,0x1f,0x2d,0x1c,0x1a,0x15,0x13,0x0e,0x1d,0x0f,0x1d,0x0b,0x09,0x04,0x02,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3e,0x18,0x17,0x11,0x03,0x02,0x04,0x28,0x27,0x21,0x03,0x07,0x05,0x02,0x15,0x00,0x04,0x09,0x01,0x05,0x07,0x04,0x05,0x01,0x00,0x1d,0x08, +0x01,0x02,0x00,0x07,0x06,0x02,0x07,0x01,0x00,0x1d,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00,0x06,0x06,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x07,0xb0,0x2f,0x2b,0x13,0x34,0x00,0x33,0x32,0x00,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x35,0x25,0x32,0x36,0x37,0x2e,0x01,0x23,0x22,0x06,0x07,0x17, +0x3e,0x01,0x33,0x32,0x16,0x05,0x22,0x06,0x07,0x1e,0x01,0x33,0x32,0x36,0x37,0x27,0x0e,0x01,0x23,0x22,0x26,0x61,0x01,0x04,0xdf,0xe1,0x01,0x05,0xfe,0xfc,0xe0,0xe0,0xfe,0xfb,0x02,0x80,0x2b,0x4a,0x09,0x13,0x8f,0x79,0x86,0x8e,0x02,0x04,0x14,0x46,0x29,0x3e,0xb6,0xfe,0xf9,0x26,0x43,0x0e,0x10,0x8f,0x7c,0x83,0x8e,0x04,0x03,0x15, +0x4b,0x2b,0x4c,0xa7,0x02,0x27,0xf0,0x01,0x37,0xfe,0xca,0xf1,0x16,0xf2,0xfe,0xcc,0x01,0x35,0xf1,0x1b,0x32,0x26,0x87,0xa8,0xc9,0x95,0x05,0x17,0x1f,0x5a,0x2c,0x28,0x1e,0x8b,0xaa,0xc1,0x94,0x04,0x1a,0x1f,0x5b,0x00,0x00,0x00,0x00,0x01,0x00,0x16,0x00,0x00,0x05,0x17,0x05,0xc4,0x00,0x15,0x00,0x69,0x40,0x0c,0x15,0x14,0x13,0x12, +0x0f,0x0d,0x08,0x06,0x02,0x01,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x22,0x0a,0x01,0x02,0x01,0x01,0x15,0x00,0x00,0x02,0x03,0x02,0x00,0x03,0x29,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x04,0x01,0x01,0x01,0x0d,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x05,0x1b,0x40,0x26,0x0a,0x01,0x02,0x04,0x01,0x15,0x00, +0x00,0x02,0x03,0x02,0x00,0x03,0x29,0x00,0x04,0x04,0x07,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x37,0x13,0x3e,0x01,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x07,0x01,0x23,0x01,0x33,0x02,0x59,0x20,0x06,0x21,0xe0,0x2f, +0x9c,0x5f,0x21,0x33,0x19,0x16,0x06,0x15,0x0d,0x34,0x46,0x1a,0xfe,0x8b,0xa8,0xfd,0xee,0xd6,0x01,0x7e,0x78,0x78,0x03,0x25,0x94,0x8d,0x0b,0x0f,0x97,0x02,0x05,0x41,0x4e,0xfb,0x75,0x05,0xb0,0x00,0x00,0x00,0x00,0x01,0x00,0x2e,0x00,0x00,0x04,0x0e,0x04,0x4d,0x00,0x15,0x00,0x69,0x40,0x0c,0x15,0x14,0x13,0x12,0x0f,0x0d,0x08,0x06, +0x02,0x01,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1b,0x58,0x40,0x22,0x0a,0x01,0x02,0x01,0x01,0x15,0x00,0x00,0x02,0x03,0x02,0x00,0x03,0x29,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x04,0x01,0x01,0x01,0x10,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x05,0x1b,0x40,0x26,0x0a,0x01,0x02,0x04,0x01,0x15,0x00,0x00,0x02,0x03,0x02, +0x00,0x03,0x29,0x00,0x04,0x04,0x0a,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x33,0x37,0x13,0x3e,0x01,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x07,0x01,0x23,0x01,0x33,0x01,0xe3,0x11,0x06,0x13,0x95,0x29,0x84,0x52,0x22,0x33, +0x18,0x16,0x05,0x16,0x0d,0x20,0x3b,0x0d,0xfe,0xd8,0x95,0xfe,0x83,0xca,0x01,0x3f,0x4c,0x4c,0x02,0x17,0x7f,0x78,0x0a,0x0f,0x97,0x03,0x05,0x34,0x2a,0xfc,0xb9,0x04,0x3a,0x00,0x00,0x00,0xff,0xff,0x00,0x16,0x00,0x00,0x05,0x17,0x07,0x48,0x02,0x26,0x02,0x20,0x00,0x00,0x01,0x07,0x01,0x5f,0x04,0x38,0x01,0x5a,0x00,0x09,0xb1,0x01, +0x02,0xb8,0x01,0x5a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xfe,0x00,0x00,0x04,0x0e,0x06,0x20,0x02,0x26,0x02,0x21,0x00,0x00,0x01,0x07,0x01,0x5f,0x03,0xd2,0x00,0x32,0x00,0x08,0xb1,0x01,0x02,0xb0,0x32,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x71,0xfe,0x4b,0x09,0x5c,0x05,0xc5,0x00,0x26,0x00,0x32,0x00,0x00,0x00,0x07,0x00,0x5c, +0x05,0x74,0x00,0x00,0xff,0xff,0x00,0x61,0xfe,0x4b,0x08,0x74,0x04,0x4e,0x00,0x26,0x00,0x52,0x00,0x00,0x00,0x07,0x00,0x5c,0x04,0x8c,0x00,0x00,0x00,0x04,0x00,0x71,0xff,0x73,0x05,0x02,0x06,0x35,0x00,0x03,0x00,0x07,0x00,0x15,0x00,0x23,0x00,0xc7,0x40,0x12,0x21,0x1f,0x1a,0x18,0x13,0x11,0x0c,0x0a,0x07,0x06,0x05,0x04,0x03,0x02, +0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x32,0x00,0x00,0x06,0x03,0x06,0x00,0x21,0x00,0x03,0x07,0x07,0x03,0x1f,0x00,0x02,0x04,0x04,0x02,0x20,0x00,0x01,0x01,0x09,0x16,0x00,0x06,0x06,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0d,0x16,0x00,0x07,0x07,0x04,0x01,0x02,0x1b,0x00,0x04,0x04,0x0e,0x04, +0x17,0x08,0x1b,0x4b,0xb0,0x23,0x58,0x40,0x33,0x00,0x00,0x06,0x03,0x06,0x00,0x03,0x29,0x00,0x03,0x07,0x06,0x03,0x07,0x27,0x00,0x02,0x04,0x02,0x2c,0x00,0x01,0x01,0x09,0x16,0x00,0x06,0x06,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0d,0x16,0x00,0x07,0x07,0x04,0x01,0x02,0x1b,0x00,0x04,0x04,0x0e,0x04,0x17,0x08,0x1b,0x40,0x33,0x00, +0x01,0x05,0x01,0x2b,0x00,0x00,0x06,0x03,0x06,0x00,0x03,0x29,0x00,0x03,0x07,0x06,0x03,0x07,0x27,0x00,0x02,0x04,0x02,0x2c,0x00,0x06,0x06,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0d,0x16,0x00,0x07,0x07,0x04,0x01,0x02,0x1b,0x00,0x04,0x04,0x0e,0x04,0x17,0x08,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x33,0x11,0x23,0x11,0x33,0x01, +0x10,0x00,0x21,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x20,0x00,0x11,0x27,0x34,0x02,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32,0x36,0x35,0x03,0x1d,0xc5,0xc5,0xc5,0xc5,0x01,0xe5,0xfe,0xb5,0xfe,0xf8,0xff,0xfe,0xc1,0x01,0x3f,0xff,0x01,0x08,0x01,0x4b,0xc5,0xd8,0xb6,0xac,0xcd,0xcd,0xac,0xb7,0xd7,0x04,0xb0,0x01,0x85,0xf9,0x3e, +0x01,0x8e,0x01,0x55,0xfe,0xf5,0xfe,0xa0,0x01,0x60,0x01,0x0b,0x01,0x03,0x01,0x0a,0x01,0x62,0xfe,0x9f,0xfe,0xf5,0x02,0xc8,0x01,0x00,0xff,0x00,0xc8,0xfe,0xfb,0xca,0xff,0x00,0xff,0xcb,0x00,0x04,0x00,0x61,0xff,0x8a,0x04,0x2a,0x04,0xb6,0x00,0x03,0x00,0x07,0x00,0x15,0x00,0x23,0x01,0x42,0x40,0x12,0x21,0x1f,0x1a,0x18,0x13,0x11, +0x0c,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x33,0x00,0x01,0x04,0x04,0x01,0x1f,0x00,0x00,0x07,0x03,0x07,0x00,0x21,0x00,0x03,0x06,0x06,0x03,0x1f,0x00,0x02,0x05,0x05,0x02,0x20,0x00,0x07,0x07,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x00,0x06,0x06, +0x05,0x01,0x02,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x08,0x1b,0x4b,0xb0,0x17,0x58,0x40,0x34,0x00,0x01,0x04,0x04,0x01,0x1f,0x00,0x00,0x07,0x03,0x07,0x00,0x21,0x00,0x03,0x06,0x07,0x03,0x06,0x27,0x00,0x02,0x05,0x05,0x02,0x20,0x00,0x07,0x07,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x00,0x06,0x06,0x05,0x01,0x02,0x1b,0x00, +0x05,0x05,0x0e,0x05,0x17,0x08,0x1b,0x4b,0xb0,0x19,0x58,0x40,0x35,0x00,0x01,0x04,0x04,0x01,0x1f,0x00,0x00,0x07,0x03,0x07,0x00,0x03,0x29,0x00,0x03,0x06,0x07,0x03,0x06,0x27,0x00,0x02,0x05,0x05,0x02,0x20,0x00,0x07,0x07,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x00,0x06,0x06,0x05,0x01,0x02,0x1b,0x00,0x05,0x05,0x0e,0x05, +0x17,0x08,0x1b,0x4b,0xb0,0x1b,0x58,0x40,0x34,0x00,0x01,0x04,0x01,0x2b,0x00,0x00,0x07,0x03,0x07,0x00,0x03,0x29,0x00,0x03,0x06,0x07,0x03,0x06,0x27,0x00,0x02,0x05,0x05,0x02,0x20,0x00,0x07,0x07,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x00,0x06,0x06,0x05,0x01,0x02,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x08,0x1b,0x40,0x33, +0x00,0x01,0x04,0x01,0x2b,0x00,0x00,0x07,0x03,0x07,0x00,0x03,0x29,0x00,0x03,0x06,0x07,0x03,0x06,0x27,0x00,0x02,0x05,0x02,0x2c,0x00,0x07,0x07,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x10,0x16,0x00,0x06,0x06,0x05,0x01,0x02,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x08,0x59,0x59,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x33,0x11,0x23, +0x11,0x33,0x01,0x34,0x00,0x33,0x32,0x00,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x35,0x33,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x02,0xa9,0xc5,0xc5,0xc5,0xc5,0xfd,0xb8,0x01,0x04,0xdf,0xe1,0x01,0x05,0xfe,0xfc,0xe0,0xe0,0xfe,0xfb,0xc5,0x91,0x8f,0x8d,0x92,0x93,0x8e,0x8d,0x91,0x03,0x44,0x01,0x72,0xfa, +0xd4,0x01,0x71,0x01,0x2c,0xf0,0x01,0x37,0xfe,0xca,0xf1,0x16,0xf2,0xfe,0xcc,0x01,0x35,0xf1,0xac,0xe0,0xe0,0xac,0x16,0xaa,0xe2,0xe2,0xaa,0x00,0x00,0x03,0x00,0x78,0xff,0xeb,0x07,0x29,0x07,0xed,0x00,0x38,0x00,0x4a,0x00,0x50,0x00,0x91,0x40,0x24,0x39,0x39,0x4f,0x4e,0x39,0x4a,0x39,0x49,0x48,0x46,0x43,0x42,0x3f,0x3d,0x3c,0x3a, +0x36,0x34,0x2f,0x2d,0x2a,0x29,0x26,0x24,0x1f,0x1d,0x18,0x16,0x11,0x0f,0x0b,0x09,0x04,0x02,0x10,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x60,0x50,0x4d,0x4c,0x03,0x00,0x09,0x4b,0x1a,0x00,0x03,0x04,0x00,0x38,0x1b,0x02,0x06,0x04,0x2b,0x28,0x02,0x05,0x06,0x0d,0x01,0x01,0x05,0x05,0x15,0x00,0x0e,0x0a,0x09,0x0a,0x0e,0x09,0x29, +0x00,0x06,0x04,0x05,0x04,0x06,0x05,0x29,0x00,0x0c,0x00,0x0a,0x0e,0x0c,0x0a,0x01,0x00,0x1d,0x0f,0x01,0x0d,0x0b,0x01,0x09,0x00,0x0d,0x09,0x01,0x00,0x1d,0x08,0x01,0x04,0x04,0x00,0x01,0x00,0x1b,0x03,0x01,0x00,0x00,0x0d,0x16,0x07,0x01,0x05,0x05,0x01,0x01,0x00,0x1b,0x02,0x01,0x01,0x01,0x0e,0x01,0x17,0x09,0xb0,0x2f,0x2b,0x01, +0x3e,0x01,0x33,0x32,0x00,0x19,0x01,0x10,0x00,0x23,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x35,0x33,0x15,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x01,0x15,0x23,0x22,0x24,0x23,0x22,0x06, +0x1d,0x01,0x23,0x35,0x34,0x36,0x33,0x32,0x04,0x33,0x01,0x27,0x37,0x27,0x33,0x15,0x04,0x4f,0x35,0x79,0x43,0xd7,0x01,0x12,0xfe,0xe4,0xda,0x73,0xb1,0x3f,0x40,0xb0,0x72,0xdb,0xfe,0xe5,0x01,0x11,0xd8,0x42,0x79,0x36,0x3a,0x25,0x5d,0x35,0x83,0xa1,0xac,0x85,0x69,0x79,0x1e,0xc5,0x1d,0x79,0x6a,0x83,0xae,0xa2,0x82,0x36,0x5d,0x24, +0x01,0x32,0x2e,0x83,0xfe,0xd5,0x2a,0x33,0x39,0x86,0x7c,0x72,0x48,0x01,0x24,0x72,0xfe,0x47,0x50,0x3a,0x01,0xbc,0x05,0x9a,0x14,0x17,0xfe,0xb1,0xfe,0xf8,0xfe,0xd4,0xfe,0xf7,0xfe,0xb2,0x3a,0x30,0x30,0x3a,0x01,0x4e,0x01,0x09,0x01,0x2c,0x01,0x08,0x01,0x4f,0x17,0x14,0x9c,0x15,0x17,0xfa,0xc0,0xfe,0xd2,0xc1,0xfc,0x42,0x2d,0x21, +0x21,0x2d,0x42,0xfc,0xc1,0x01,0x2e,0xc0,0xfa,0x17,0x15,0x02,0x74,0x82,0x7c,0x36,0x35,0x12,0x25,0x6c,0x6d,0x7b,0xfe,0x49,0x42,0x74,0x8c,0x7b,0x00,0x03,0x00,0x78,0xff,0xeb,0x06,0x10,0x06,0x90,0x00,0x38,0x00,0x4a,0x00,0x50,0x00,0x90,0x40,0x24,0x39,0x39,0x4f,0x4e,0x39,0x4a,0x39,0x49,0x48,0x46,0x43,0x42,0x3f,0x3d,0x3c,0x3a, +0x36,0x34,0x2f,0x2d,0x2a,0x29,0x26,0x24,0x1f,0x1d,0x18,0x16,0x11,0x0f,0x0b,0x09,0x04,0x02,0x10,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x5f,0x50,0x4d,0x4c,0x4b,0x04,0x00,0x09,0x1a,0x00,0x02,0x04,0x00,0x38,0x1b,0x02,0x06,0x04,0x2b,0x28,0x02,0x05,0x06,0x0d,0x01,0x01,0x05,0x05,0x15,0x00,0x06,0x04,0x05,0x04,0x06,0x05,0x29, +0x00,0x0c,0x00,0x0a,0x0e,0x0c,0x0a,0x01,0x00,0x1d,0x00,0x0e,0x0e,0x07,0x16,0x0b,0x01,0x09,0x09,0x0d,0x01,0x00,0x1b,0x0f,0x01,0x0d,0x0d,0x09,0x16,0x08,0x01,0x04,0x04,0x00,0x01,0x00,0x1b,0x03,0x01,0x00,0x00,0x10,0x16,0x07,0x01,0x05,0x05,0x01,0x01,0x00,0x1b,0x02,0x01,0x01,0x01,0x0e,0x01,0x17,0x0a,0xb0,0x2f,0x2b,0x01,0x3e, +0x01,0x33,0x32,0x12,0x1d,0x01,0x14,0x02,0x23,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x02,0x3d,0x01,0x34,0x12,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x37,0x35,0x33,0x15,0x1e,0x01,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x07,0x01,0x15,0x23,0x22,0x24,0x23,0x22,0x06,0x1d, +0x01,0x23,0x35,0x34,0x36,0x33,0x32,0x04,0x33,0x01,0x27,0x37,0x27,0x33,0x15,0x03,0xae,0x2b,0x66,0x39,0xb2,0xe6,0xef,0xb7,0x5e,0x93,0x35,0x36,0x93,0x5d,0xb8,0xee,0xe5,0xb4,0x38,0x65,0x2c,0x3a,0x1e,0x48,0x29,0x60,0x74,0x7f,0x62,0x51,0x59,0x1a,0xc5,0x17,0x5b,0x51,0x61,0x80,0x75,0x5e,0x2a,0x48,0x1e,0x01,0x47,0x2e,0x83,0xfe, +0xd5,0x2a,0x32,0x3a,0x86,0x7c,0x72,0x48,0x01,0x24,0x72,0xfe,0x47,0x50,0x3a,0x01,0xbc,0x04,0x1f,0x14,0x16,0xfe,0xd3,0xec,0x3f,0xe5,0xfe,0xdf,0x3d,0x33,0x33,0x3d,0x01,0x21,0xe5,0x3f,0xec,0x01,0x2d,0x16,0x14,0x9c,0x14,0x17,0xd5,0xa7,0x41,0x9d,0xcf,0x40,0x2f,0x21,0x21,0x2e,0x41,0xcf,0x9d,0x41,0xa7,0xd5,0x17,0x14,0x02,0x91, +0x81,0x7b,0x36,0x34,0x12,0x24,0x6c,0x6e,0x7c,0xfe,0x4a,0x42,0x73,0x8c,0x7b,0x00,0x00,0x02,0x00,0x78,0xff,0xeb,0x07,0x28,0x07,0x05,0x00,0x0b,0x00,0x48,0x00,0x86,0x40,0x28,0x00,0x00,0x46,0x44,0x3f,0x3d,0x39,0x37,0x32,0x30,0x2b,0x29,0x24,0x22,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x17,0x15,0x10,0x0e,0x00,0x0b,0x00,0x0b,0x0a,0x09, +0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x12,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x51,0x48,0x2e,0x02,0x06,0x0d,0x2d,0x0c,0x02,0x09,0x06,0x20,0x19,0x02,0x07,0x08,0x3b,0x01,0x0e,0x07,0x04,0x15,0x00,0x01,0x03,0x01,0x2b,0x11,0x05,0x02,0x03,0x00,0x03,0x2b,0x00,0x09,0x0a,0x01,0x08,0x07,0x09,0x08,0x00,0x02,0x1d,0x04,0x02, +0x02,0x00,0x00,0x09,0x16,0x0c,0x01,0x06,0x06,0x0d,0x01,0x00,0x1b,0x10,0x01,0x0d,0x0d,0x0d,0x16,0x0b,0x01,0x07,0x07,0x0e,0x01,0x00,0x1b,0x0f,0x01,0x0e,0x0e,0x0e,0x0e,0x17,0x09,0xb0,0x2f,0x2b,0x01,0x15,0x27,0x37,0x21,0x15,0x23,0x35,0x23,0x15,0x23,0x35,0x01,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x14,0x06,0x23,0x22,0x26,0x27, +0x11,0x33,0x35,0x21,0x15,0x33,0x11,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x32,0x16,0x17,0x37,0x2e,0x01,0x23,0x22,0x00,0x19,0x01,0x10,0x00,0x33,0x32,0x36,0x37,0x1e,0x01,0x33,0x32,0x00,0x19,0x01,0x10,0x00,0x23,0x22,0x06,0x07,0x02,0xcf,0xaf,0x01,0x03,0x35,0xb0,0x9a,0xb2,0x01,0x2d,0x25,0x5c,0x37,0x82,0xa2,0xae, +0x83,0x69,0x7a,0x1c,0xc6,0xfd,0xae,0xc6,0x1f,0x79,0x67,0x85,0xac,0xa1,0x83,0x36,0x5d,0x25,0x3a,0x36,0x7a,0x42,0xd8,0xfe,0xef,0x01,0x1b,0xdb,0x72,0xb1,0x3f,0x3e,0xb1,0x73,0xda,0x01,0x1c,0xfe,0xee,0xd7,0x43,0x7a,0x35,0x06,0x98,0x7e,0x01,0xea,0xeb,0x7e,0x7e,0x7e,0xfe,0x66,0x15,0x17,0xfa,0xc0,0xfe,0xd2,0xc1,0xfc,0x41,0x2c, +0x01,0x4c,0x9a,0x9a,0xfe,0xb4,0x2d,0x40,0xfc,0xc1,0x01,0x2e,0xc0,0xfa,0x17,0x15,0x9c,0x14,0x17,0xfe,0xb1,0xfe,0xf8,0xfe,0xd4,0xfe,0xf7,0xfe,0xb2,0x3a,0x30,0x30,0x3a,0x01,0x4e,0x01,0x09,0x01,0x2c,0x01,0x08,0x01,0x4f,0x17,0x14,0x00,0x00,0x00,0x00,0x02,0x00,0x2e,0x00,0x00,0x05,0x4c,0x05,0xb5,0x00,0x0b,0x00,0x24,0x00,0xb4, +0x40,0x20,0x00,0x00,0x23,0x22,0x1f,0x1e,0x17,0x16,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x00,0x0b,0x00,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x0e,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x14,0x58,0x40,0x40,0x20,0x01,0x08,0x06,0x01,0x15,0x00,0x01,0x03,0x01,0x2b,0x0d,0x05,0x02,0x03,0x00,0x00,0x03, +0x1f,0x00,0x08,0x06,0x0c,0x06,0x08,0x0c,0x29,0x00,0x0c,0x07,0x06,0x0c,0x07,0x27,0x04,0x02,0x02,0x00,0x00,0x07,0x00,0x02,0x1b,0x09,0x01,0x07,0x07,0x08,0x16,0x0b,0x0a,0x02,0x06,0x06,0x0a,0x16,0x09,0x01,0x07,0x07,0x08,0x07,0x17,0x09,0x1b,0x40,0x3f,0x20,0x01,0x08,0x06,0x01,0x15,0x00,0x01,0x03,0x01,0x2b,0x0d,0x05,0x02,0x03, +0x00,0x03,0x2b,0x00,0x08,0x06,0x0c,0x06,0x08,0x0c,0x29,0x00,0x0c,0x07,0x06,0x0c,0x07,0x27,0x04,0x02,0x02,0x00,0x00,0x07,0x00,0x02,0x1b,0x09,0x01,0x07,0x07,0x08,0x16,0x0b,0x0a,0x02,0x06,0x06,0x0a,0x16,0x09,0x01,0x07,0x07,0x08,0x07,0x17,0x09,0x59,0xb0,0x2f,0x2b,0x01,0x15,0x27,0x37,0x21,0x15,0x23,0x35,0x23,0x15,0x23,0x35, +0x01,0x23,0x01,0x33,0x13,0x33,0x13,0x33,0x36,0x12,0x03,0x23,0x16,0x02,0x0f,0x01,0x2f,0x01,0x03,0x23,0x13,0x03,0x07,0x23,0x27,0x01,0xe4,0xb0,0x01,0x03,0x36,0xb1,0x99,0xb3,0xfe,0x8a,0xca,0x01,0x93,0x95,0x9e,0x06,0x8f,0x95,0x94,0x9a,0x03,0xc9,0x0b,0x46,0x5a,0x0b,0x06,0x1a,0xc4,0xc9,0x74,0x85,0x13,0x06,0x11,0x05,0x48,0x7f, +0x01,0xeb,0xec,0x7f,0x7f,0x7f,0xfe,0xf2,0xfb,0xc6,0x01,0xc3,0xfe,0x3d,0xea,0x02,0x1a,0x01,0x36,0xef,0xfe,0x30,0x8c,0x22,0x01,0x71,0x02,0xfb,0xfe,0x8e,0xfe,0x77,0x4c,0x4c,0x00,0x00,0x00,0x01,0x00,0x76,0xfe,0x81,0x04,0xbf,0x05,0xc5,0x00,0x19,0x00,0x76,0x40,0x0c,0x19,0x17,0x12,0x10,0x0e,0x0d,0x0a,0x08,0x01,0x00,0x05,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1f,0x58,0x40,0x2c,0x0c,0x01,0x02,0x03,0x02,0x01,0x00,0x04,0x02,0x15,0x00,0x02,0x03,0x04,0x03,0x02,0x04,0x29,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x16,0x00,0x04,0x04,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x0c,0x00,0x17,0x06,0x1b,0x40,0x29,0x0c,0x01,0x02,0x03,0x02, +0x01,0x00,0x04,0x02,0x15,0x00,0x02,0x03,0x04,0x03,0x02,0x04,0x29,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x00,0x1c,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0d,0x03,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x26,0x00,0x35,0x11,0x10,0x00,0x33,0x32,0x00,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x02,0x15,0x11,0x14,0x12, +0x3b,0x01,0x03,0x17,0xc4,0xd7,0xfe,0xfa,0x01,0x37,0xf7,0xf7,0x01,0x24,0x04,0x02,0xbd,0xb4,0xa4,0xa5,0xc4,0xc4,0xa5,0x73,0xfe,0x81,0x01,0x70,0x1d,0x01,0x52,0xf6,0x01,0x03,0x01,0x0d,0x01,0x5f,0xfe,0xf9,0xd9,0x06,0x99,0xb2,0xfe,0xf6,0xc5,0xfe,0xfb,0xc7,0xfe,0xf6,0x00,0x01,0x00,0x62,0xfe,0x81,0x03,0xe1,0x04,0x4e,0x00,0x19, +0x00,0x76,0x40,0x0c,0x19,0x17,0x12,0x10,0x0e,0x0d,0x0a,0x08,0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1f,0x58,0x40,0x2c,0x0c,0x01,0x02,0x03,0x02,0x01,0x00,0x04,0x02,0x15,0x00,0x02,0x03,0x04,0x03,0x02,0x04,0x29,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x16,0x00,0x04,0x04,0x00,0x00,0x00, +0x1b,0x00,0x00,0x00,0x0c,0x00,0x17,0x06,0x1b,0x40,0x29,0x0c,0x01,0x02,0x03,0x02,0x01,0x00,0x04,0x02,0x15,0x00,0x02,0x03,0x04,0x03,0x02,0x04,0x29,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x00,0x1c,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x10,0x03,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x26,0x02,0x3d,0x01,0x34, +0x12,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x3b,0x01,0x02,0xa7,0xc5,0xb5,0xcb,0xff,0xdc,0xb6,0xee,0x04,0x02,0xb2,0x89,0x63,0x8a,0x8c,0x8b,0x8b,0x6a,0xfe,0x81,0x01,0x72,0x20,0x01,0x2a,0xcb,0x2a,0xe3,0x01,0x39,0xe0,0xa3,0x06,0x62,0x8c,0xe6,0x9b,0x2a,0x9f,0xe4,0x00,0x00,0x01,0x00,0x70, +0x00,0x00,0x04,0x94,0x05,0x3e,0x00,0x13,0x00,0x34,0x40,0x06,0x0f,0x0e,0x05,0x04,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x13,0x12,0x11,0x10,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x03,0x02,0x01,0x00,0x10,0x00,0x01,0x01,0x15,0x00,0x01,0x00,0x01,0x2b,0x00,0x00,0x00,0x08,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x05, +0x07,0x25,0x03,0x23,0x13,0x25,0x37,0x05,0x13,0x25,0x37,0x05,0x13,0x33,0x03,0x05,0x07,0x25,0x02,0x5c,0x01,0x21,0x47,0xfe,0xdd,0xb5,0xae,0xe1,0xfe,0xdf,0x47,0x01,0x25,0xca,0xfe,0xde,0x49,0x01,0x23,0xb9,0xab,0xe5,0x01,0x25,0x4b,0xfe,0xe0,0x01,0xbf,0xac,0x7d,0xaa,0xfe,0xc0,0x01,0x8e,0xab,0x7c,0xab,0x01,0x6c,0xab,0x7e,0xab, +0x01,0x4a,0xfe,0x69,0xab,0x7c,0xaa,0x00,0x00,0x01,0x00,0xd4,0x04,0xa4,0x03,0xa3,0x05,0xfc,0x00,0x07,0x00,0x9f,0x40,0x0e,0x00,0x00,0x00,0x07,0x00,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x14,0x58,0x40,0x1a,0x00,0x00,0x03,0x03,0x00,0x20,0x00,0x02,0x02,0x09,0x16,0x04,0x01,0x03, +0x03,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x03,0x17,0x04,0x1b,0x4b,0xb0,0x1f,0x58,0x40,0x19,0x00,0x00,0x03,0x00,0x2c,0x00,0x02,0x02,0x09,0x16,0x04,0x01,0x03,0x03,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x03,0x17,0x04,0x1b,0x4b,0xb0,0x23,0x58,0x40,0x17,0x00,0x00,0x03,0x00,0x2c,0x00,0x01,0x04,0x01,0x03,0x00,0x01,0x03, +0x00,0x02,0x1d,0x00,0x02,0x02,0x09,0x02,0x17,0x03,0x1b,0x40,0x22,0x00,0x02,0x01,0x02,0x2b,0x00,0x00,0x03,0x00,0x2c,0x00,0x01,0x03,0x03,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x03,0x00,0x02,0x1b,0x04,0x01,0x03,0x01,0x03,0x00,0x02,0x18,0x05,0x59,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x15,0x27,0x37,0x21,0x27,0x17,0x15,0x01,0x83,0xaf, +0x01,0x02,0x20,0x01,0xaf,0x05,0x22,0x7e,0x01,0xeb,0x6c,0x01,0xd9,0x00,0x00,0x00,0x00,0x01,0x00,0xfb,0x05,0x17,0x03,0xf3,0x06,0x15,0x00,0x11,0x00,0x5a,0x40,0x10,0x01,0x00,0x10,0x0e,0x0d,0x0b,0x08,0x07,0x04,0x02,0x00,0x11,0x01,0x11,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x2c,0x58,0x40,0x1c,0x00,0x03,0x03,0x01, +0x01,0x00,0x1b,0x00,0x01,0x01,0x09,0x16,0x04,0x01,0x02,0x02,0x00,0x01,0x00,0x1b,0x05,0x01,0x00,0x00,0x07,0x02,0x17,0x04,0x1b,0x40,0x19,0x05,0x01,0x00,0x04,0x01,0x02,0x00,0x02,0x01,0x00,0x1c,0x00,0x03,0x03,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x09,0x03,0x17,0x03,0x59,0xb0,0x2f,0x2b,0x01,0x32,0x24,0x33,0x32,0x16,0x1d,0x01, +0x23,0x35,0x34,0x26,0x23,0x22,0x04,0x2b,0x01,0x35,0x01,0x27,0x71,0x01,0x24,0x49,0x71,0x7d,0x86,0x3b,0x31,0x2b,0xfe,0xd5,0x82,0x2e,0x05,0x99,0x7c,0x6e,0x6c,0x24,0x12,0x34,0x36,0x7c,0x82,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x05,0x15,0x01,0xf5,0x06,0x57,0x00,0x05,0x00,0x1d,0x40,0x04,0x02,0x01,0x01,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x0c,0x05,0x04,0x03,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x22,0x02,0xb0,0x2f,0x2b,0x01,0x35,0x33,0x07,0x17,0x07,0x01,0x00,0xbb,0x01,0x3b,0x51,0x05,0xdc,0x7b,0x8c,0x74,0x42,0x00,0x00,0x00,0x00,0x01,0x01,0x2c,0x05,0x15,0x02,0x21,0x06,0x57,0x00,0x05,0x00,0x1d,0x40,0x04,0x04,0x03,0x01,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x0c,0x05,0x02,0x01,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x22,0x02,0xb0,0x2f,0x2b,0x01,0x27,0x37,0x27,0x33,0x15,0x01,0x7c,0x50,0x3a,0x01,0xbc,0x05,0x15,0x42,0x74,0x8c,0x7b,0x00,0x00,0x00,0x00,0x08,0x00,0x3b,0xfe,0xc4,0x07,0xd4,0x05,0xaf,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x4f,0x00,0x5f,0x00,0x6f, +0x00,0x7f,0x01,0x9e,0x40,0x62,0x70,0x70,0x60,0x60,0x50,0x50,0x40,0x40,0x30,0x30,0x20,0x20,0x10,0x10,0x00,0x00,0x70,0x7f,0x70,0x7f,0x7d,0x7b,0x79,0x78,0x75,0x73,0x60,0x6f,0x60,0x6f,0x6d,0x6b,0x69,0x68,0x65,0x63,0x50,0x5f,0x50,0x5f,0x5d,0x5b,0x59,0x58,0x55,0x53,0x40,0x4f,0x40,0x4f,0x4d,0x4b,0x49,0x48,0x45,0x43,0x30,0x3f, +0x30,0x3f,0x3d,0x3b,0x39,0x38,0x35,0x33,0x20,0x2f,0x20,0x2f,0x2d,0x2b,0x29,0x28,0x25,0x23,0x10,0x1f,0x10,0x1f,0x1d,0x1b,0x19,0x18,0x15,0x13,0x00,0x0f,0x00,0x0f,0x0d,0x0b,0x09,0x08,0x05,0x03,0x28,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x1f,0x58,0x40,0x92,0x07,0x01,0x02,0x01,0x02,0x57,0x51,0x17,0x11,0x04,0x05,0x06, +0x67,0x61,0x27,0x21,0x04,0x09,0x0a,0x77,0x71,0x37,0x31,0x04,0x0d,0x0e,0x47,0x41,0x02,0x11,0x12,0x05,0x15,0x20,0x03,0x02,0x01,0x02,0x04,0x02,0x01,0x04,0x29,0x25,0x17,0x15,0x21,0x07,0x05,0x05,0x06,0x08,0x06,0x05,0x08,0x29,0x26,0x1b,0x19,0x22,0x0b,0x05,0x09,0x0a,0x0c,0x0a,0x09,0x0c,0x29,0x24,0x13,0x02,0x11,0x12,0x11,0x2c, +0x14,0x01,0x04,0x16,0x01,0x06,0x05,0x04,0x06,0x01,0x00,0x1d,0x18,0x01,0x08,0x1a,0x01,0x0a,0x09,0x08,0x0a,0x01,0x00,0x1d,0x1c,0x01,0x0c,0x1e,0x01,0x0e,0x0d,0x0c,0x0e,0x01,0x00,0x1d,0x00,0x10,0x00,0x12,0x11,0x10,0x12,0x01,0x00,0x1d,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x07,0x16,0x27,0x1f,0x1d,0x23,0x0f,0x05, +0x0d,0x0d,0x08,0x0d,0x17,0x0c,0x1b,0x40,0x95,0x07,0x01,0x02,0x01,0x02,0x57,0x51,0x17,0x11,0x04,0x05,0x06,0x67,0x61,0x27,0x21,0x04,0x09,0x0a,0x77,0x71,0x37,0x31,0x04,0x0d,0x0e,0x47,0x41,0x02,0x11,0x12,0x05,0x15,0x20,0x03,0x02,0x01,0x02,0x04,0x02,0x01,0x04,0x29,0x25,0x17,0x15,0x21,0x07,0x05,0x05,0x06,0x08,0x06,0x05,0x08, +0x29,0x26,0x1b,0x19,0x22,0x0b,0x05,0x09,0x0a,0x0c,0x0a,0x09,0x0c,0x29,0x27,0x1f,0x1d,0x23,0x0f,0x05,0x0d,0x0e,0x10,0x0e,0x0d,0x10,0x29,0x24,0x13,0x02,0x11,0x12,0x11,0x2c,0x14,0x01,0x04,0x16,0x01,0x06,0x05,0x04,0x06,0x01,0x00,0x1d,0x18,0x01,0x08,0x1a,0x01,0x0a,0x09,0x08,0x0a,0x01,0x00,0x1d,0x1c,0x01,0x0c,0x1e,0x01,0x0e, +0x0d,0x0c,0x0e,0x01,0x00,0x1d,0x00,0x10,0x00,0x12,0x11,0x10,0x12,0x01,0x00,0x1d,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x07,0x02,0x17,0x0c,0x59,0xb0,0x2f,0x2b,0x01,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22, +0x06,0x15,0x13,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22, +0x06,0x15,0x01,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x13,0x27,0x26,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x03,0x2f,0x02,0x05,0x70,0x61,0x60,0x71,0x04,0x02,0x68,0x31,0x32,0x32,0x2f,0x01,0xe6,0x02,0x05,0x71,0x60,0x60,0x72,0x04,0x02,0x69,0x30,0x33,0x32,0x2e, +0x51,0x02,0x05,0x71,0x60,0x60,0x71,0x04,0x02,0x68,0x30,0x33,0x32,0x2f,0xfe,0xd2,0x02,0x05,0x71,0x60,0x60,0x71,0x04,0x02,0x68,0x30,0x33,0x32,0x2f,0xfd,0x57,0x02,0x05,0x70,0x61,0x60,0x71,0x04,0x02,0x68,0x31,0x32,0x32,0x2f,0xfd,0x55,0x02,0x05,0x71,0x61,0x60,0x71,0x04,0x02,0x68,0x31,0x32,0x32,0x2f,0xfe,0xe6,0x02,0x05,0x71, +0x60,0x60,0x71,0x04,0x02,0x68,0x30,0x33,0x32,0x2f,0x3d,0x02,0x05,0x71,0x60,0x60,0x72,0x04,0x02,0x69,0x30,0x33,0x32,0x2e,0x04,0xf3,0x06,0x4f,0x67,0x67,0x4f,0x06,0x2b,0x3a,0x3a,0x2b,0xfe,0xeb,0x06,0x4e,0x68,0x67,0x4f,0x06,0x2c,0x39,0x3a,0x2b,0xfe,0x09,0x06,0x4e,0x68,0x67,0x4f,0x06,0x2c,0x39,0x3a,0x2b,0xfd,0xf9,0x06,0x4e, +0x68,0x67,0x4f,0x06,0x2c,0x39,0x3a,0x2b,0xfe,0xe4,0x06,0x50,0x66,0x66,0x50,0x06,0x2c,0x39,0x39,0x2c,0x05,0x1a,0x06,0x4f,0x67,0x67,0x4f,0x06,0x2b,0x3a,0x3a,0x2b,0xfe,0x09,0x06,0x4e,0x68,0x67,0x4f,0x06,0x2c,0x39,0x3a,0x2b,0xfd,0xf9,0x06,0x4e,0x68,0x67,0x4f,0x06,0x2c,0x39,0x3a,0x2b,0x00,0x08,0x00,0x4d,0xfe,0x63,0x07,0x8d, +0x05,0xc6,0x00,0x04,0x00,0x09,0x00,0x0e,0x00,0x13,0x00,0x19,0x00,0x1e,0x00,0x23,0x00,0x28,0x00,0x9b,0x40,0x12,0x05,0x05,0x00,0x00,0x05,0x09,0x05,0x09,0x08,0x07,0x00,0x04,0x00,0x04,0x03,0x02,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x2e,0x58,0x40,0x3b,0x22,0x21,0x16,0x03,0x03,0x02,0x28,0x23,0x1e,0x19,0x17,0x13, +0x12,0x11,0x0f,0x0e,0x0d,0x0c,0x0a,0x0d,0x01,0x03,0x27,0x26,0x1d,0x1c,0x04,0x00,0x01,0x03,0x15,0x05,0x01,0x03,0x03,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x04,0x01,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x0c,0x00,0x17,0x05,0x1b,0x40,0x39,0x22,0x21,0x16,0x03,0x03,0x02,0x28,0x23,0x1e,0x19,0x17,0x13,0x12,0x11, +0x0f,0x0e,0x0d,0x0c,0x0a,0x0d,0x01,0x03,0x27,0x26,0x1d,0x1c,0x04,0x00,0x01,0x03,0x15,0x00,0x02,0x05,0x01,0x03,0x01,0x02,0x03,0x00,0x00,0x1d,0x04,0x01,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x0c,0x00,0x17,0x04,0x59,0xb0,0x2f,0x2b,0x05,0x17,0x03,0x23,0x13,0x03,0x27,0x13,0x33,0x03,0x01,0x37,0x05,0x15,0x25,0x05,0x07, +0x25,0x35,0x05,0x01,0x37,0x25,0x17,0x06,0x05,0x01,0x07,0x05,0x27,0x25,0x03,0x27,0x03,0x37,0x13,0x01,0x17,0x13,0x07,0x03,0x04,0x50,0x0b,0x7a,0x60,0x46,0x3a,0x0c,0x7a,0x60,0x46,0x02,0x1e,0x0d,0x01,0x4d,0xfe,0xa6,0xfb,0x74,0x0d,0xfe,0xb3,0x01,0x5a,0x03,0x9c,0x02,0x01,0x41,0x44,0x25,0xfe,0xff,0xfc,0xf3,0x02,0xfe,0xc0,0x45, +0x01,0x26,0x2b,0x11,0x94,0x41,0xc6,0x03,0x60,0x11,0x95,0x42,0xc5,0x3c,0x0e,0xfe,0xad,0x01,0x61,0x04,0xa2,0x0e,0x01,0x52,0xfe,0xa0,0xfe,0x11,0x0c,0x7c,0x62,0x47,0x3b,0x0c,0x7c,0x62,0x47,0x01,0xae,0x10,0x99,0x44,0x17,0xb1,0xfc,0x8e,0x11,0x99,0x45,0xc8,0x02,0xe4,0x02,0x01,0x46,0x45,0xfe,0xd5,0xfc,0xe3,0x02,0xfe,0xbb,0x47, +0x01,0x2b,0x00,0x00,0xff,0xff,0x00,0xad,0xfe,0xd7,0x05,0x9e,0x07,0x4e,0x02,0x26,0x01,0xc4,0x00,0x00,0x00,0x27,0x01,0x54,0x01,0x2a,0x01,0x9e,0x01,0x07,0x00,0x0f,0x04,0x63,0xff,0xd9,0x00,0x12,0xb1,0x01,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0xb1,0x02,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x8f,0xfe,0xd7,0x04,0xa0, +0x05,0xf7,0x02,0x26,0x01,0xe4,0x00,0x00,0x00,0x27,0x01,0x54,0x00,0x99,0x00,0x47,0x01,0x07,0x00,0x0f,0x03,0x65,0xff,0xd9,0x00,0x11,0xb1,0x01,0x01,0xb0,0x47,0xb0,0x0d,0x2b,0xb1,0x02,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0x00,0x00,0x02,0xff,0xcd,0x00,0x00,0x04,0xbb,0x05,0xb0,0x00,0x12,0x00,0x1b,0x00,0x4f,0x40,0x18,0x13,0x13, +0x13,0x1b,0x13,0x1a,0x16,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x08,0x04,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2a,0x06,0x01,0x04,0x03,0x01,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x01,0x09,0x01,0x08,0x07,0x01,0x08,0x01,0x00,0x1d,0x00,0x05,0x05,0x07,0x16,0x00,0x07,0x07,0x02,0x01,0x02, +0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x23,0x15,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x21,0x11,0x23,0x35,0x33,0x35,0x33,0x15,0x33,0x03,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x02,0x4e,0xe6,0x01,0x67,0xe9,0x01,0x03,0xfe,0xfc,0xe8,0xfd,0xd4,0xd6,0xd6,0xc5,0xe6,0xe6,0x01,0x67,0x93,0x94,0x93,0x94,0x04, +0x4d,0xdd,0xef,0xc5,0xc6,0xf6,0x04,0x4d,0x9b,0xc8,0xc8,0xfd,0xed,0xfd,0xc5,0xa9,0x7b,0x77,0xa0,0x00,0x00,0x02,0xff,0xba,0x00,0x00,0x04,0x00,0x04,0x3a,0x00,0x12,0x00,0x1b,0x00,0x4f,0x40,0x18,0x13,0x13,0x13,0x1b,0x13,0x1a,0x16,0x14,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x08,0x04,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x2a,0x06,0x01,0x04,0x03,0x01,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x01,0x09,0x01,0x08,0x07,0x01,0x08,0x01,0x00,0x1d,0x00,0x05,0x05,0x0a,0x16,0x00,0x07,0x07,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x23,0x15,0x21,0x32,0x16,0x15,0x14,0x06,0x23,0x21,0x11,0x23, +0x35,0x33,0x35,0x33,0x15,0x33,0x03,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x02,0x3b,0xdd,0x01,0x0d,0xc0,0xd5,0xd7,0xbe,0xfe,0x2e,0xdf,0xdf,0xc5,0xdd,0xdd,0x01,0x0d,0x6a,0x65,0x66,0x69,0x03,0x1f,0x81,0xb8,0x93,0x94,0xbf,0x03,0x1f,0x9b,0x80,0x80,0xfe,0x4a,0xfe,0x96,0x66,0x4c,0x4a,0x6e,0x00,0x00,0x00,0x00,0x03,0x00,0xa3, +0x00,0x00,0x04,0xbc,0x05,0xb0,0x00,0x03,0x00,0x0e,0x00,0x17,0x00,0x47,0x40,0x10,0x04,0x04,0x17,0x15,0x11,0x0f,0x04,0x0e,0x04,0x0d,0x09,0x07,0x06,0x05,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2a,0x03,0x02,0x02,0x03,0x04,0x01,0x00,0x02,0x00,0x02,0x02,0x15,0x00,0x03,0x05,0x01,0x02,0x00,0x03,0x02,0x01,0x00,0x1d,0x00, +0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x00,0x00,0x00,0x08,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x07,0x03,0x37,0x01,0x11,0x23,0x11,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x25,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x04,0x2a,0x8c,0xfe,0x8c,0xfe,0x3c,0xc5,0x02,0x2d,0xe9,0x01,0x03,0xfe,0xfd,0xe9,0xfe,0x98,0x01, +0x68,0x94,0x92,0x93,0x93,0xfe,0x98,0x01,0xce,0x46,0x01,0xe8,0x47,0xfe,0x91,0xfd,0xb8,0x05,0xb0,0xf0,0xc4,0xc6,0xee,0x9a,0x9f,0x79,0x79,0xa2,0x00,0x03,0x00,0x8f,0xfe,0x60,0x04,0x29,0x04,0x4e,0x00,0x03,0x00,0x15,0x00,0x23,0x00,0x95,0x40,0x0e,0x21,0x1f,0x1a,0x18,0x13,0x11,0x0e,0x0d,0x0c,0x0b,0x08,0x06,0x06,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x4b,0xb0,0x19,0x58,0x40,0x37,0x1d,0x1c,0x03,0x02,0x04,0x05,0x04,0x0a,0x01,0x00,0x05,0x01,0x00,0x02,0x01,0x00,0x03,0x15,0x0f,0x01,0x04,0x01,0x14,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x0a,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x16,0x00,0x01,0x01,0x0c,0x01,0x17, +0x07,0x1b,0x40,0x3b,0x1d,0x1c,0x03,0x02,0x04,0x05,0x04,0x0a,0x01,0x00,0x05,0x01,0x00,0x02,0x01,0x00,0x03,0x15,0x0f,0x01,0x04,0x01,0x14,0x00,0x02,0x02,0x0a,0x16,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x10,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x0e,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x08,0x59, +0xb0,0x2f,0x2b,0x05,0x07,0x03,0x37,0x25,0x14,0x02,0x23,0x22,0x26,0x27,0x11,0x23,0x11,0x33,0x17,0x3e,0x01,0x33,0x32,0x12,0x11,0x23,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x1e,0x01,0x33,0x32,0x36,0x35,0x03,0x7d,0x93,0xaf,0x94,0x01,0x5a,0xe0,0xc5,0x64,0x97,0x35,0xc5,0x97,0x1f,0x35,0x9e,0x69,0xc9,0xdf,0xc5,0x91,0x8d,0x55,0x78, +0x25,0x25,0x78,0x57,0x8c,0x90,0x88,0x37,0x01,0xd9,0x37,0xa3,0xea,0xfe,0xe1,0x43,0x43,0xfd,0xef,0x05,0xda,0x8c,0x4e,0x52,0xfe,0xc1,0xfe,0xfa,0xb8,0xed,0x4d,0x43,0xfd,0xf5,0x43,0x4b,0xcd,0xa2,0x00,0x00,0x00,0x01,0x00,0xa3,0x00,0x00,0x04,0x24,0x06,0xfe,0x00,0x09,0x00,0x35,0x40,0x0c,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02, +0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1c,0x00,0x04,0x03,0x00,0x04,0x00,0x00,0x1a,0x01,0x01,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x35,0x21,0x11,0x23,0x11,0x21,0x11,0x33,0x04,0x24,0xc5,0xfe,0x09,0xc5,0x02,0xbc,0xc5,0x05,0x14, +0x01,0xfa,0xeb,0x05,0xb0,0x01,0x4e,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x03,0x44,0x05,0x75,0x00,0x07,0x00,0x50,0x40,0x0a,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x09,0x58,0x40,0x19,0x00,0x03,0x02,0x02,0x03,0x1f,0x00,0x00,0x00,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x0a,0x16, +0x00,0x01,0x01,0x08,0x01,0x17,0x04,0x1b,0x40,0x18,0x00,0x03,0x02,0x03,0x2b,0x00,0x00,0x00,0x02,0x00,0x00,0x1b,0x00,0x02,0x02,0x0a,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x11,0x33,0x03,0x44,0xfe,0x10,0xc5,0x01,0xf0,0xc5,0x03,0x9e,0xfc,0x62,0x04,0x3a,0x01,0x3b,0x00,0x00, +0x00,0x01,0xff,0xeb,0x00,0x00,0x04,0x20,0x05,0xb0,0x00,0x0d,0x00,0x3c,0x40,0x10,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x06,0x01,0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x00,0x05,0x05,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x07,0x16, +0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x23,0x35,0x33,0x11,0x21,0x15,0x21,0x11,0x21,0x02,0x6c,0xfe,0xfc,0xc5,0xb8,0xb8,0x03,0x7d,0xfd,0x48,0x01,0x04,0x02,0xa9,0xfd,0x57,0x02,0xa9,0x9b,0x02,0x6c,0x9b,0xfe,0x2f,0x00,0x00,0x00,0x00,0x01,0xff,0xf3,0x00,0x00,0x03,0x3f,0x04,0x3a,0x00,0x0d, +0x00,0x3c,0x40,0x10,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x06,0x01,0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x00,0x00,0x1d,0x00,0x05,0x05,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x0a,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21, +0x11,0x23,0x11,0x23,0x35,0x33,0x11,0x21,0x15,0x21,0x11,0x21,0x02,0x74,0xfe,0xe0,0xc5,0x9c,0x9c,0x02,0xb0,0xfe,0x15,0x01,0x20,0x01,0xdc,0xfe,0x24,0x01,0xdc,0x9b,0x01,0xc3,0x9c,0xfe,0xd9,0x00,0x00,0x00,0x00,0x01,0x00,0xa3,0xff,0xc9,0x04,0x74,0x05,0xb0,0x00,0x15,0x00,0x40,0x40,0x0c,0x15,0x14,0x13,0x12,0x11,0x0f,0x04,0x02, +0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x27,0x0a,0x01,0x03,0x02,0x01,0x15,0x09,0x01,0x03,0x12,0x00,0x01,0x00,0x02,0x03,0x01,0x02,0x01,0x00,0x1d,0x00,0x00,0x00,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x07,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x33,0x32,0x00,0x15,0x06,0x02,0x07, +0x27,0x3e,0x01,0x35,0x2e,0x01,0x2b,0x01,0x11,0x23,0x11,0x21,0x04,0x20,0xfd,0x48,0xf9,0xeb,0x01,0x28,0x02,0xc3,0xbe,0x33,0x80,0x70,0x01,0xb6,0x96,0xf9,0xc5,0x03,0x7d,0x05,0x15,0xfe,0x56,0xff,0x00,0xdc,0x8a,0xfe,0xe6,0x22,0x94,0x22,0x9d,0x73,0x93,0xa4,0xfd,0x3a,0x05,0xb0,0x00,0x00,0x00,0x01,0x00,0x8f,0xfe,0xff,0x03,0xc4, +0x04,0x3a,0x00,0x15,0x00,0x3b,0x40,0x0c,0x15,0x14,0x13,0x12,0x11,0x0f,0x04,0x02,0x01,0x00,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x22,0x0a,0x09,0x02,0x03,0x12,0x00,0x01,0x00,0x02,0x03,0x01,0x02,0x01,0x00,0x1d,0x00,0x00,0x00,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x0a,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x05,0xb0,0x2f, +0x2b,0x01,0x21,0x15,0x33,0x32,0x00,0x15,0x06,0x02,0x07,0x27,0x3e,0x01,0x35,0x2e,0x01,0x2b,0x01,0x11,0x23,0x11,0x21,0x03,0x3f,0xfe,0x15,0x5d,0xeb,0x01,0x28,0x02,0xc3,0xbe,0x33,0x80,0x70,0x01,0xb6,0x96,0x5d,0xc5,0x02,0xb0,0x03,0x9e,0xfd,0xff,0x00,0xdc,0x8a,0xfe,0xe6,0x22,0x94,0x23,0x9c,0x73,0x93,0xa4,0xfe,0x04,0x04,0x3a, +0xff,0xff,0x00,0x1a,0xfe,0x99,0x06,0xc3,0x05,0xb0,0x02,0x26,0x01,0xc2,0x00,0x00,0x00,0x07,0x03,0xe0,0x05,0x9e,0x00,0x00,0xff,0xff,0x00,0x1a,0xfe,0x99,0x05,0xca,0x04,0x3a,0x02,0x26,0x01,0xe2,0x00,0x00,0x00,0x07,0x03,0xe0,0x04,0xa5,0x00,0x00,0xff,0xff,0x00,0x78,0xfe,0x5a,0x04,0xdf,0x05,0xc5,0x02,0x26,0x01,0xc3,0x00,0x00, +0x01,0x07,0x03,0xe1,0x01,0xae,0xff,0xf7,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x64,0xfe,0x5b,0x03,0xec,0x04,0x4c,0x02,0x26,0x01,0xe3,0x00,0x00,0x01,0x07,0x03,0xe1,0x01,0x2a,0xff,0xf8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xaa,0xfe,0x99,0x05,0x41, +0x05,0xb0,0x02,0x26,0x00,0x2e,0x00,0x00,0x00,0x07,0x03,0xe0,0x04,0x1c,0x00,0x00,0xff,0xff,0x00,0x99,0xfe,0x99,0x04,0x72,0x04,0x3a,0x02,0x26,0x01,0xe6,0x00,0x00,0x00,0x07,0x03,0xe0,0x03,0x4d,0x00,0x00,0x00,0x01,0x00,0xa3,0x00,0x00,0x04,0xff,0x05,0xb0,0x00,0x14,0x00,0x54,0x40,0x1a,0x00,0x00,0x00,0x14,0x00,0x14,0x13,0x12, +0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2d,0x01,0x01,0x01,0x06,0x01,0x15,0x08,0x01,0x06,0x03,0x01,0x01,0x02,0x06,0x01,0x00,0x00,0x1d,0x0a,0x09,0x02,0x05,0x05,0x07,0x16,0x00,0x02,0x02,0x07,0x00,0x00,0x1b,0x00,0x07,0x07,0x0a,0x16,0x04, +0x01,0x00,0x00,0x08,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x09,0x02,0x23,0x01,0x23,0x15,0x23,0x35,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x35,0x33,0x15,0x33,0x01,0x04,0xd5,0xfe,0x72,0x01,0xb8,0xf6,0xfe,0xac,0x4e,0x9d,0x62,0xc5,0xc5,0x62,0x9d,0x4c,0x01,0x3d,0x05,0xb0,0xfd,0x4f,0xfd,0x01,0x02,0x92,0xf3,0xf3,0xfd,0x6e,0x05,0xb0,0xfd, +0x7c,0xff,0xff,0x02,0x84,0x00,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x04,0x63,0x04,0x3a,0x00,0x14,0x00,0x52,0x40,0x1a,0x00,0x00,0x00,0x14,0x00,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x0b,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2b,0x01,0x01,0x01,0x06,0x01,0x15, +0x08,0x01,0x06,0x03,0x01,0x01,0x02,0x06,0x01,0x00,0x00,0x1d,0x00,0x07,0x00,0x02,0x00,0x07,0x02,0x00,0x00,0x1d,0x0a,0x09,0x02,0x05,0x05,0x0a,0x16,0x04,0x01,0x00,0x00,0x08,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x09,0x02,0x23,0x01,0x23,0x15,0x23,0x35,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x35,0x33,0x15,0x33,0x13,0x04,0x40,0xfe,0xad, +0x01,0x76,0xf9,0xfe,0xf3,0x17,0x9d,0x4b,0xc5,0xc5,0x4b,0x9d,0x0f,0xff,0x04,0x3a,0xfe,0x00,0xfd,0xc6,0x01,0xcb,0xbf,0xbf,0xfe,0x35,0x04,0x3a,0xfe,0x37,0xd3,0xd3,0x01,0xc9,0x00,0x00,0x00,0x01,0xff,0xd7,0x00,0x00,0x05,0x01,0x05,0xb0,0x00,0x16,0x00,0x4d,0x40,0x16,0x16,0x15,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08, +0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2a,0x13,0x01,0x00,0x07,0x01,0x15,0x05,0x01,0x03,0x06,0x01,0x02,0x07,0x03,0x02,0x00,0x00,0x1d,0x00,0x07,0x00,0x00,0x01,0x07,0x00,0x00,0x00,0x1d,0x08,0x01,0x04,0x04,0x07,0x16,0x09,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01, +0x23,0x11,0x23,0x11,0x23,0x35,0x33,0x35,0x33,0x15,0x33,0x15,0x23,0x11,0x33,0x01,0x33,0x17,0x09,0x01,0x07,0x23,0x01,0xef,0x80,0xc5,0xd3,0xd3,0xc5,0xe9,0xe9,0x6c,0x02,0x1c,0xde,0x02,0xfd,0xb2,0x02,0x78,0x02,0xef,0x02,0x92,0xfd,0x6e,0x04,0x82,0x9b,0x93,0x93,0x9b,0xfe,0xaa,0x02,0x84,0x05,0xfd,0x4f,0xfd,0x0b,0x05,0x00,0x00, +0x00,0x01,0xff,0xbb,0x00,0x00,0x04,0x0b,0x06,0x18,0x00,0x14,0x00,0x51,0x40,0x16,0x14,0x13,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2e,0x12,0x01,0x00,0x07,0x01,0x15,0x05,0x01,0x03,0x06,0x01,0x02,0x08,0x03,0x02,0x00,0x00,0x1d, +0x00,0x07,0x00,0x00,0x01,0x07,0x00,0x00,0x00,0x1d,0x00,0x04,0x04,0x09,0x16,0x00,0x08,0x08,0x0a,0x16,0x09,0x01,0x01,0x01,0x08,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x23,0x35,0x33,0x35,0x33,0x15,0x33,0x15,0x23,0x11,0x33,0x01,0x33,0x09,0x01,0x23,0x01,0xba,0x65,0xc5,0xd5,0xd5,0xc5,0xe7,0xe7,0x63,0x01,0x45, +0xec,0xfe,0x77,0x01,0xab,0xe9,0x01,0xf3,0xfe,0x0d,0x04,0xbe,0x9b,0xbf,0xbf,0x9b,0xfd,0xd2,0x01,0xaa,0xfe,0x0d,0xfd,0xb9,0x00,0x01,0x00,0x4a,0x00,0x00,0x06,0xb8,0x05,0xb0,0x00,0x10,0x00,0x42,0x40,0x10,0x10,0x0f,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25, +0x0d,0x01,0x00,0x04,0x01,0x15,0x00,0x04,0x00,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x05,0x01,0x03,0x03,0x07,0x16,0x06,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x33,0x01,0x33,0x17,0x09,0x01,0x07,0x23,0x03,0xa6,0x80,0xc5,0xfd,0xe9,0x02, +0xdc,0x6c,0x02,0x1c,0xde,0x02,0xfd,0xb2,0x02,0x78,0x02,0xef,0x02,0x92,0xfd,0x6e,0x05,0x15,0x9b,0xfd,0x7c,0x02,0x84,0x05,0xfd,0x4f,0xfd,0x0b,0x05,0x00,0x00,0x00,0x00,0x01,0x00,0x32,0x00,0x00,0x05,0xbc,0x04,0x3a,0x00,0x10,0x00,0x42,0x40,0x10,0x10,0x0f,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x07,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x25,0x0d,0x01,0x00,0x04,0x01,0x15,0x00,0x04,0x00,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x02,0x02,0x03,0x00,0x00,0x1b,0x05,0x01,0x03,0x03,0x0a,0x16,0x06,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x33,0x01,0x33,0x17,0x09,0x01,0x07, +0x23,0x03,0x3f,0x65,0xc5,0xfe,0x1d,0x02,0xa8,0x54,0x01,0x83,0xe7,0x02,0xfe,0x3f,0x01,0xe3,0x02,0xf2,0x01,0xcb,0xfe,0x35,0x03,0x9e,0x9c,0xfe,0x37,0x01,0xc9,0x05,0xfd,0xfe,0xfd,0xd2,0x05,0x00,0x00,0x00,0xff,0xff,0x00,0xaa,0xfe,0x99,0x05,0x88,0x05,0xb0,0x02,0x26,0x00,0x2b,0x00,0x00,0x00,0x07,0x03,0xe0,0x04,0x63,0x00,0x00, +0xff,0xff,0x00,0x8f,0xfe,0x99,0x04,0x8c,0x04,0x3a,0x02,0x26,0x01,0xe9,0x00,0x00,0x00,0x07,0x03,0xe0,0x03,0x67,0x00,0x00,0x00,0x01,0x00,0xa9,0x00,0x00,0x07,0x6f,0x05,0xb0,0x00,0x0d,0x00,0x3c,0x40,0x10,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f, +0x00,0x00,0x00,0x04,0x03,0x00,0x04,0x00,0x00,0x1d,0x00,0x02,0x02,0x01,0x00,0x00,0x1b,0x06,0x01,0x01,0x01,0x07,0x16,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x33,0x01,0x6e,0x02,0xc3,0x03,0x3e,0xfd,0x87,0xc5,0xfd,0x3d,0xc5,0xc5,0x03,0x1e,0x02, +0x92,0x9b,0xfa,0xeb,0x02,0x83,0xfd,0x7d,0x05,0xb0,0x00,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x05,0x65,0x04,0x3a,0x00,0x0d,0x00,0x3c,0x40,0x10,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x00,0x00,0x00,0x04,0x03,0x00,0x04,0x00,0x00,0x1d,0x00,0x02, +0x02,0x01,0x00,0x00,0x1b,0x06,0x01,0x01,0x01,0x0a,0x16,0x05,0x01,0x03,0x03,0x08,0x03,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x33,0x01,0x54,0x01,0xe2,0x02,0x2f,0xfe,0x96,0xc5,0xfe,0x1e,0xc5,0xc5,0x02,0x66,0x01,0xd4,0x9c,0xfc,0x62,0x01,0xcc,0xfe,0x34,0x04,0x3a,0x00,0x00, +0x00,0x01,0x00,0xa8,0xff,0xce,0x07,0xe3,0x05,0xb0,0x00,0x17,0x00,0x43,0x40,0x0e,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0d,0x02,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x28,0x08,0x01,0x02,0x01,0x01,0x15,0x07,0x01,0x02,0x12,0x00,0x00,0x00,0x01,0x02,0x00,0x01,0x01,0x00,0x1d,0x00,0x03,0x03,0x05,0x00,0x00, +0x1b,0x00,0x05,0x05,0x07,0x16,0x04,0x01,0x02,0x02,0x08,0x02,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x33,0x32,0x00,0x15,0x06,0x02,0x07,0x27,0x3e,0x01,0x35,0x2e,0x01,0x2b,0x01,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x21,0x04,0xf7,0xd9,0xeb,0x01,0x28,0x02,0xc2,0xbf,0x33,0x80,0x71,0x02,0xb6,0x96,0xd9,0xc5,0xfd,0x3b,0xc5,0x04,0x4f,0x03, +0x71,0xfe,0xff,0xdc,0x8a,0xfe,0xe7,0x23,0x95,0x21,0x9e,0x72,0x93,0xa5,0xfd,0x34,0x05,0x15,0xfa,0xeb,0x05,0xb0,0x00,0x00,0x00,0x01,0x00,0x8f,0xff,0x02,0x06,0xb8,0x04,0x3a,0x00,0x17,0x00,0x3e,0x40,0x0e,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0d,0x02,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23,0x08,0x07, +0x02,0x02,0x12,0x00,0x00,0x00,0x01,0x02,0x00,0x01,0x01,0x00,0x1d,0x00,0x03,0x03,0x05,0x00,0x00,0x1b,0x00,0x05,0x05,0x0a,0x16,0x04,0x01,0x02,0x02,0x08,0x02,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x33,0x32,0x00,0x15,0x06,0x02,0x07,0x27,0x3e,0x01,0x35,0x2e,0x01,0x2b,0x01,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x21,0x03,0xfc,0xa9,0xeb, +0x01,0x28,0x02,0xc3,0xbe,0x33,0x80,0x70,0x01,0xb6,0x96,0xa9,0xc5,0xfe,0x1d,0xc5,0x03,0x6d,0x02,0xa4,0xff,0x00,0xdc,0x8a,0xfe,0xe6,0x22,0x94,0x23,0x9c,0x73,0x93,0xa4,0xfe,0x01,0x03,0x9e,0xfc,0x62,0x04,0x3a,0x00,0x00,0x00,0x00,0x02,0x00,0x71,0xff,0xeb,0x05,0x02,0x05,0xc3,0x00,0x21,0x00,0x30,0x00,0x8b,0x40,0x0e,0x27,0x25, +0x1c,0x1a,0x15,0x14,0x12,0x11,0x0c,0x0a,0x05,0x03,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x30,0x58,0x40,0x35,0x13,0x01,0x03,0x02,0x30,0x2d,0x22,0x21,0x1e,0x00,0x06,0x04,0x05,0x02,0x15,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x00,0x05,0x05,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x00, +0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x07,0x1b,0x40,0x33,0x13,0x01,0x03,0x02,0x30,0x2d,0x22,0x21,0x1e,0x00,0x06,0x04,0x05,0x02,0x15,0x00,0x00,0x00,0x05,0x04,0x00,0x05,0x01,0x00,0x1d,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e, +0x01,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x01,0x35,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x10,0x00,0x21,0x22,0x00,0x19,0x01,0x10,0x00,0x1f,0x01,0x15,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x32,0x36,0x37,0x2e,0x01,0x35,0x05,0x35,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x17,0x3e,0x01,0x35,0x02,0x1d,0xce,0xa5,0xa5,0xcd,0xfe,0xb5, +0xfe,0xf8,0xfe,0xfe,0xc0,0x01,0x3e,0xfa,0x06,0xac,0xcd,0xcd,0xac,0x3f,0x6d,0x2d,0xa8,0xc3,0x02,0x20,0x5d,0x50,0x50,0x5e,0x97,0x86,0x1e,0x20,0x02,0x91,0x3b,0xb0,0xe7,0xe5,0xb2,0x50,0xfe,0xe5,0xfe,0x8a,0x01,0x60,0x01,0x0a,0x01,0x06,0x01,0x09,0x01,0x5f,0x04,0x02,0x9a,0xfe,0xff,0xc5,0xfe,0xf8,0xc9,0xff,0x00,0x22,0x22,0x2a, +0xf1,0xa6,0x15,0x53,0x6b,0x88,0x8a,0x69,0x40,0x7a,0xa7,0x0e,0x3b,0x91,0x50,0x00,0x00,0x02,0x00,0x61,0xff,0xeb,0x04,0x2a,0x04,0x4c,0x00,0x21,0x00,0x30,0x00,0x9e,0x40,0x10,0x2d,0x2c,0x27,0x25,0x1c,0x1a,0x15,0x14,0x12,0x11,0x0c,0x0a,0x05,0x03,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x10,0x58,0x40,0x3c,0x13,0x01, +0x03,0x02,0x30,0x22,0x21,0x00,0x04,0x06,0x05,0x1e,0x01,0x04,0x06,0x03,0x15,0x00,0x06,0x05,0x04,0x04,0x06,0x21,0x00,0x00,0x00,0x05,0x06,0x00,0x05,0x01,0x00,0x1d,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x10,0x16,0x00,0x04,0x04,0x01,0x01,0x02,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x07,0x1b,0x40,0x3d,0x13,0x01,0x03, +0x02,0x30,0x22,0x21,0x00,0x04,0x06,0x05,0x1e,0x01,0x04,0x06,0x03,0x15,0x00,0x06,0x05,0x04,0x05,0x06,0x04,0x29,0x00,0x00,0x00,0x05,0x06,0x00,0x05,0x01,0x00,0x1d,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x10,0x16,0x00,0x04,0x04,0x01,0x01,0x02,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x01,0x35, +0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x00,0x23,0x22,0x00,0x3d,0x01,0x34,0x00,0x1f,0x01,0x15,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x37,0x2e,0x01,0x35,0x05,0x35,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x3e,0x01,0x35,0x01,0xd2,0xa9,0x82,0x81,0xac,0xfe,0xf0,0xcb,0xdb,0xfe,0xed,0x01,0x11,0xd7,0x06,0x88, +0xa1,0xa0,0x89,0x1d,0x37,0x19,0x6d,0x7d,0x01,0x93,0x3e,0x2a,0x2c,0x3a,0x5b,0x50,0x10,0x13,0x01,0xe9,0x25,0x84,0xae,0xbb,0x8c,0x21,0xd3,0xfe,0xe6,0x01,0x24,0xde,0x36,0xef,0x01,0x3a,0x04,0x02,0x99,0xdb,0xad,0x38,0x9b,0xc6,0x0c,0x0c,0x23,0xae,0x74,0x11,0x24,0x43,0x60,0x52,0x3d,0x29,0x52,0x65,0x24,0x56,0x2e,0x00,0x00,0x00, +0xff,0xff,0x00,0x76,0xfe,0x5a,0x04,0xbf,0x05,0xc5,0x02,0x26,0x00,0x26,0x00,0x00,0x01,0x07,0x03,0xe1,0x01,0xa9,0xff,0xf7,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xfe,0x5a,0x03,0xd9,0x04,0x4e,0x02,0x26,0x00,0x46,0x00,0x00,0x01,0x07,0x03,0xe1,0x01,0x26,0xff,0xf7,0x00,0x09,0xb1,0x01, +0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x25,0xfe,0x99,0x04,0xa4,0x05,0xb0,0x02,0x26,0x00,0x37,0x00,0x00,0x00,0x07,0x03,0xe0,0x02,0x30,0x00,0x00,0xff,0xff,0x00,0x47,0xfe,0x99,0x03,0xd1,0x04,0x3a,0x02,0x26,0x01,0xee,0x00,0x00,0x00,0x07,0x03,0xe0,0x01,0xd8,0x00,0x00,0xff,0xff,0x00,0x28,0x00,0x00,0x04,0xe2, +0x05,0xb0,0x02,0x06,0x00,0x3c,0x00,0x00,0xff,0xff,0x00,0x2e,0xfe,0x5f,0x03,0xe4,0x04,0x3a,0x02,0x06,0x01,0x8d,0x00,0x00,0x00,0x01,0x00,0x28,0x00,0x00,0x04,0xe2,0x05,0xb0,0x00,0x0f,0x00,0x40,0x40,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x06,0x05,0x04,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23, +0x00,0x01,0x01,0x00,0x07,0x01,0x03,0x02,0x02,0x15,0x05,0x01,0x01,0x04,0x01,0x02,0x03,0x01,0x02,0x00,0x00,0x1d,0x06,0x01,0x00,0x00,0x07,0x16,0x00,0x03,0x03,0x08,0x03,0x17,0x04,0xb0,0x2f,0x2b,0x09,0x01,0x33,0x01,0x33,0x15,0x23,0x07,0x11,0x23,0x11,0x23,0x35,0x33,0x01,0x33,0x02,0x85,0x01,0x7c,0xe1,0xfe,0x5d,0x78,0xcc,0x08, +0xc4,0xe9,0x95,0xfe,0x5d,0xe1,0x02,0xcc,0x02,0xe4,0xfc,0xfa,0x9b,0x0f,0xfe,0x00,0x02,0x0f,0x9b,0x03,0x06,0x00,0x00,0x00,0x00,0x01,0x00,0x2e,0xfe,0x5f,0x03,0xe4,0x04,0x3a,0x00,0x11,0x00,0x42,0x40,0x12,0x11,0x10,0x0f,0x0e,0x0c,0x0b,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x23,0x00,0x05,0x04,0x03,0x04,0x05,0x03,0x29,0x06,0x01,0x04,0x04,0x0a,0x16,0x07,0x01,0x03,0x03,0x00,0x00,0x02,0x1b,0x02,0x01,0x00,0x00,0x08,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x05,0x23,0x11,0x23,0x11,0x23,0x35,0x33,0x01,0x33,0x01,0x17,0x33,0x37,0x13,0x33,0x01,0x33,0x03,0x51,0xe4,0xc5,0xd8,0xbc, +0xfe,0xa2,0xca,0x01,0x00,0x11,0x06,0x13,0xf9,0xc9,0xfe,0xa6,0xc7,0x0d,0xfe,0x6c,0x01,0x94,0x9b,0x03,0xac,0xfd,0x05,0x4c,0x4c,0x02,0xfb,0xfc,0x54,0x00,0x00,0x00,0xff,0xff,0x00,0x42,0xfe,0x99,0x04,0xf0,0x05,0xb0,0x02,0x26,0x00,0x3b,0x00,0x00,0x00,0x07,0x03,0xe0,0x03,0xcb,0x00,0x00,0xff,0xff,0x00,0x2e,0xfe,0x99,0x04,0x0b, +0x04,0x3a,0x02,0x26,0x00,0x5b,0x00,0x00,0x00,0x07,0x03,0xe0,0x02,0xe6,0x00,0x00,0x00,0x01,0x00,0x37,0xfe,0x9d,0x06,0x9c,0x05,0xb0,0x00,0x13,0x00,0x49,0x40,0x16,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x26,0x00,0x08, +0x05,0x08,0x00,0x02,0x19,0x04,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x06,0x03,0x02,0x03,0x01,0x01,0x07,0x16,0x07,0x01,0x05,0x05,0x09,0x00,0x02,0x1b,0x00,0x09,0x09,0x08,0x09,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x35,0x33,0x15,0x21,0x15,0x21,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x23,0x11,0x21,0x01,0xa4,0xfe,0x93,0x01, +0x6d,0xc5,0x01,0x88,0xfe,0x78,0x02,0xc5,0xc5,0xa9,0xc5,0xfb,0xcd,0x05,0x13,0x9b,0x02,0x02,0x9b,0xfb,0x88,0x05,0x15,0xfa,0xf1,0xfd,0xfc,0x01,0x63,0x00,0x00,0x00,0x00,0x01,0x00,0x20,0xfe,0x9e,0x05,0x1d,0x04,0x3b,0x00,0x0f,0x00,0x43,0x40,0x12,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, +0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x00,0x06,0x03,0x06,0x00,0x02,0x19,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x04,0x01,0x01,0x01,0x0a,0x16,0x05,0x01,0x03,0x03,0x07,0x00,0x02,0x1b,0x00,0x07,0x07,0x08,0x07,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x15,0x23,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x23,0x11, +0x21,0x01,0x2c,0xfe,0xf4,0x02,0xc4,0xf3,0x01,0xe3,0xc5,0x84,0xc5,0xfc,0xd4,0x03,0xa0,0x9b,0x9b,0xfc,0xfa,0x03,0xa0,0xfc,0x60,0xfe,0x04,0x01,0x62,0x00,0x00,0x00,0xff,0xff,0x00,0x93,0xfe,0x99,0x05,0x5d,0x05,0xb0,0x02,0x26,0x01,0xd3,0x00,0x00,0x00,0x07,0x03,0xe0,0x04,0x38,0x00,0x00,0xff,0xff,0x00,0x7f,0xfe,0x99,0x04,0x6d, +0x04,0x3b,0x02,0x26,0x01,0xf3,0x00,0x00,0x00,0x07,0x03,0xe0,0x03,0x48,0x00,0x00,0x00,0x02,0x00,0x93,0x00,0x00,0x04,0xcc,0x05,0xb0,0x00,0x03,0x00,0x17,0x00,0xc4,0x40,0x14,0x04,0x04,0x04,0x17,0x04,0x17,0x14,0x12,0x0f,0x0e,0x0b,0x09,0x06,0x05,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x09,0x58, +0x40,0x30,0x16,0x01,0x05,0x01,0x07,0x01,0x03,0x05,0x02,0x15,0x00,0x01,0x04,0x05,0x05,0x01,0x21,0x00,0x00,0x03,0x02,0x03,0x00,0x21,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x01,0x02,0x1d,0x07,0x06,0x02,0x04,0x04,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x06,0x1b,0x4b,0xb0,0x0a,0x58,0x40,0x31,0x16,0x01,0x05,0x01,0x07,0x01,0x03, +0x05,0x02,0x15,0x00,0x01,0x04,0x05,0x04,0x01,0x05,0x29,0x00,0x00,0x03,0x02,0x03,0x00,0x21,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x01,0x02,0x1d,0x07,0x06,0x02,0x04,0x04,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x06,0x1b,0x40,0x32,0x16,0x01,0x05,0x01,0x07,0x01,0x03,0x05,0x02,0x15,0x00,0x01,0x04,0x05,0x04,0x01,0x05,0x29,0x00, +0x00,0x03,0x02,0x03,0x00,0x02,0x29,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x01,0x02,0x1d,0x07,0x06,0x02,0x04,0x04,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x06,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x23,0x11,0x33,0x01,0x11,0x23,0x11,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x03,0x1e,0x9e,0x9e, +0x01,0xae,0xc5,0x5f,0xb2,0x7a,0xf1,0xf8,0xc6,0x8a,0x99,0x68,0xc0,0x63,0x01,0x3c,0x02,0xbd,0x01,0xb7,0xfa,0x50,0x02,0x5b,0x1d,0x1a,0xd3,0xed,0x01,0xcc,0xfe,0x34,0xa5,0x7f,0x1c,0x1b,0x02,0xb9,0x00,0x00,0x00,0x02,0x00,0x7f,0x00,0x00,0x03,0xdc,0x04,0x3b,0x00,0x03,0x00,0x17,0x00,0xbd,0x40,0x10,0x17,0x16,0x13,0x11,0x0e,0x0d, +0x0a,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x09,0x58,0x40,0x2f,0x15,0x01,0x05,0x01,0x06,0x01,0x03,0x05,0x02,0x15,0x00,0x01,0x04,0x05,0x05,0x01,0x21,0x00,0x00,0x03,0x02,0x03,0x00,0x21,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x01,0x02,0x1d,0x06,0x01,0x04,0x04,0x0a,0x16,0x00,0x02, +0x02,0x08,0x02,0x17,0x06,0x1b,0x4b,0xb0,0x14,0x58,0x40,0x30,0x15,0x01,0x05,0x01,0x06,0x01,0x03,0x05,0x02,0x15,0x00,0x01,0x04,0x05,0x04,0x01,0x05,0x29,0x00,0x00,0x03,0x02,0x03,0x00,0x21,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x01,0x02,0x1d,0x06,0x01,0x04,0x04,0x0a,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x06,0x1b,0x40,0x31,0x15, +0x01,0x05,0x01,0x06,0x01,0x03,0x05,0x02,0x15,0x00,0x01,0x04,0x05,0x04,0x01,0x05,0x29,0x00,0x00,0x03,0x02,0x03,0x00,0x02,0x29,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x01,0x02,0x1d,0x06,0x01,0x04,0x04,0x0a,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x06,0x59,0x59,0xb0,0x2f,0x2b,0x25,0x23,0x11,0x33,0x01,0x23,0x11,0x0e,0x01,0x23,0x22, +0x26,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x11,0x33,0x02,0x87,0x9e,0x9e,0x01,0x55,0xc5,0x39,0x78,0x44,0xc4,0xdf,0xc5,0x70,0x6e,0x42,0x78,0x3b,0xc5,0xe5,0x02,0x36,0xfc,0xe5,0x01,0x83,0x0f,0x0f,0xce,0xca,0x01,0x3e,0xfe,0xc2,0x82,0x7a,0x0f,0x0f,0x02,0x1b,0x00,0x00,0x00,0x00,0x01,0x00,0x8a,0x00,0x00,0x04,0xc3, +0x05,0xb0,0x00,0x13,0x00,0x3f,0x40,0x10,0x00,0x00,0x00,0x13,0x00,0x13,0x10,0x0e,0x0b,0x0a,0x07,0x05,0x02,0x01,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x22,0x03,0x01,0x03,0x01,0x12,0x01,0x02,0x03,0x02,0x15,0x00,0x01,0x00,0x03,0x02,0x01,0x03,0x01,0x00,0x1d,0x00,0x00,0x00,0x07,0x16,0x05,0x04,0x02,0x02,0x02,0x08,0x02, +0x17,0x04,0xb0,0x2f,0x2b,0x33,0x11,0x33,0x11,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x8a,0xc5,0x60,0xb1,0x7a,0xf0,0xf9,0xc6,0x8b,0x98,0x69,0xc0,0x62,0x05,0xb0,0xfd,0xa5,0x1b,0x1c,0xd4,0xec,0xfe,0x34,0x01,0xcc,0xa4,0x80,0x1d,0x1b,0xfd,0x48,0xff,0xff,0x00,0x94,0x00,0x01,0x03,0xf1, +0x04,0x3c,0x01,0x0f,0x01,0xf3,0x04,0x70,0x04,0x3c,0xc0,0x01,0x00,0x09,0xb1,0x00,0x01,0xb8,0x04,0x3c,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0x4d,0xff,0xe9,0x06,0x2c,0x05,0xc3,0x00,0x1e,0x00,0x27,0x00,0x64,0x40,0x18,0x20,0x1f,0x01,0x00,0x24,0x23,0x1f,0x27,0x20,0x27,0x19,0x17,0x14,0x13,0x10,0x0e,0x09,0x08,0x00,0x1e,0x01,0x1e, +0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x3f,0x0c,0x07,0x02,0x06,0x01,0x04,0x01,0x03,0x06,0x1b,0x15,0x02,0x04,0x03,0x1c,0x01,0x00,0x04,0x04,0x15,0x00,0x06,0x00,0x03,0x04,0x06,0x03,0x00,0x00,0x1d,0x08,0x01,0x05,0x05,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0d,0x16,0x00,0x01,0x01,0x0a,0x16,0x00,0x04,0x04,0x00,0x01,0x00, +0x1b,0x07,0x01,0x00,0x00,0x0e,0x00,0x17,0x07,0xb0,0x2f,0x2b,0x05,0x20,0x00,0x11,0x35,0x2e,0x01,0x3f,0x01,0x33,0x14,0x16,0x17,0x12,0x00,0x33,0x20,0x00,0x11,0x15,0x21,0x07,0x06,0x12,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x03,0x22,0x02,0x07,0x17,0x21,0x35,0x34,0x26,0x04,0x47,0xfe,0xb6,0xfe,0x91,0x9e,0xa3,0x04,0x02,0x97,0x53, +0x55,0x1b,0x01,0x51,0xe9,0x01,0x1b,0x01,0x2a,0xfc,0x2e,0x02,0x05,0xf7,0xfd,0x6b,0x9a,0x4b,0x30,0x32,0xc0,0xee,0xab,0xd2,0x0f,0x03,0x03,0x09,0xb5,0x17,0x01,0x8d,0x01,0x47,0x06,0x14,0xc4,0x9a,0x05,0x5d,0x7d,0x12,0x01,0x17,0x01,0x5e,0xfe,0x9d,0xfe,0xc9,0x6c,0x05,0xf9,0xfe,0xc4,0x2e,0x26,0x8b,0x24,0x3f,0x05,0x3f,0xfe,0xf2, +0xd1,0x05,0x1f,0xce,0xf7,0x00,0x00,0x00,0x00,0x02,0xff,0xdf,0xff,0xeb,0x04,0x51,0x04,0x4e,0x00,0x1d,0x00,0x26,0x00,0x66,0x40,0x18,0x1f,0x1e,0x01,0x00,0x23,0x22,0x1e,0x26,0x1f,0x26,0x18,0x16,0x13,0x12,0x0f,0x0d,0x08,0x07,0x00,0x1d,0x01,0x1d,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x41,0x0b,0x01,0x06,0x01,0x04,0x01, +0x03,0x06,0x1a,0x14,0x02,0x04,0x03,0x1b,0x01,0x00,0x04,0x04,0x15,0x00,0x01,0x05,0x06,0x05,0x01,0x06,0x29,0x00,0x06,0x00,0x03,0x04,0x06,0x03,0x00,0x00,0x1d,0x08,0x01,0x05,0x05,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x10,0x16,0x00,0x04,0x04,0x00,0x01,0x00,0x1b,0x07,0x01,0x00,0x00,0x0e,0x00,0x17,0x07,0xb0,0x2f,0x2b,0x05,0x22, +0x00,0x3d,0x01,0x2e,0x01,0x35,0x33,0x14,0x16,0x17,0x3e,0x01,0x33,0x32,0x12,0x1d,0x01,0x21,0x07,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x03,0x22,0x06,0x07,0x17,0x21,0x35,0x34,0x26,0x02,0xbe,0xe9,0xfe,0xfb,0x77,0x7a,0x9d,0x2d,0x30,0x1f,0xfe,0xa9,0xd9,0xd9,0xfd,0x4c,0x03,0x90,0x94,0x64,0x97,0x36,0x4d,0x3a,0xbe,0xa5, +0x67,0x87,0x0f,0x02,0x01,0xe8,0x74,0x15,0x01,0x2a,0xf3,0x08,0x1d,0xaf,0x87,0x45,0x62,0x19,0xbe,0xed,0xfe,0xf2,0xe0,0x68,0x05,0xa3,0xcb,0x39,0x32,0x80,0x38,0x4d,0x03,0xc8,0x9f,0x7c,0x05,0x10,0x76,0x9a,0xff,0xff,0x00,0x4d,0xfe,0x50,0x06,0x2c,0x05,0xc3,0x02,0x26,0x02,0x67,0x00,0x00,0x00,0x07,0x01,0x57,0x02,0x5a,0x00,0x00, +0xff,0xff,0xff,0xdf,0xfe,0x50,0x04,0x51,0x04,0x4e,0x02,0x26,0x02,0x68,0x00,0x00,0x00,0x07,0x01,0x57,0x01,0x54,0x00,0x00,0xff,0xff,0x00,0xbe,0x00,0x00,0x01,0x84,0x05,0xb0,0x02,0x06,0x00,0x2c,0x00,0x00,0xff,0xff,0x00,0x1a,0x00,0x00,0x06,0x7c,0x07,0x4e,0x02,0x26,0x01,0xc2,0x00,0x00,0x01,0x07,0x01,0x54,0x01,0xa0,0x01,0x9e, +0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0x00,0x00,0x05,0xa6,0x05,0xf7,0x02,0x26,0x01,0xe2,0x00,0x00,0x01,0x07,0x01,0x54,0x01,0x34,0x00,0x47,0x00,0x08,0xb1,0x01,0x01,0xb0,0x47,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x01,0x00,0xa3,0xff,0x68,0x04,0xd1,0x05,0xb0,0x00,0x17,0x00,0x38,0x40,0x0e, +0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0c,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1d,0x07,0x06,0x02,0x02,0x12,0x04,0x01,0x00,0x00,0x01,0x02,0x00,0x01,0x01,0x00,0x1d,0x05,0x01,0x03,0x03,0x07,0x16,0x00,0x02,0x02,0x08,0x02,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x16,0x04,0x15,0x06,0x02,0x07,0x27,0x3e,0x01, +0x35,0x2e,0x01,0x23,0x21,0x11,0x23,0x11,0x33,0x11,0x33,0x01,0x33,0x17,0x02,0xc3,0xe8,0x01,0x19,0x02,0xe1,0xdd,0x33,0xa0,0x8e,0x02,0xb2,0x9a,0xfe,0xb7,0xc5,0xc5,0x80,0x02,0x08,0xde,0x03,0x03,0x2b,0x05,0xfa,0xe8,0x90,0xfe,0xd9,0x25,0x96,0x22,0xaa,0x7a,0xa5,0x9f,0xfd,0x78,0x05,0xb0,0xfd,0x7c,0x02,0x84,0x05,0x00,0x00,0x00, +0x00,0x01,0x00,0x99,0xfe,0xfe,0x04,0x1e,0x04,0x3a,0x00,0x17,0x00,0x3b,0x40,0x0c,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0c,0x05,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x22,0x00,0x01,0x00,0x03,0x01,0x15,0x07,0x06,0x02,0x01,0x12,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x01,0x00,0x1d,0x04,0x01,0x02,0x02,0x0a,0x16,0x00, +0x01,0x01,0x08,0x01,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x1e,0x01,0x15,0x06,0x02,0x07,0x27,0x3e,0x01,0x35,0x2e,0x01,0x2b,0x01,0x11,0x23,0x11,0x33,0x11,0x33,0x01,0x33,0x17,0x02,0x89,0xb8,0xd7,0x02,0xc2,0xbe,0x33,0x80,0x71,0x02,0xb2,0x9a,0xa8,0xc5,0xc5,0x54,0x01,0x83,0xe7,0x02,0x02,0x65,0x1e,0xde,0xb9,0x85,0xfe,0xf5,0x22,0x96, +0x20,0x91,0x6b,0x90,0x8b,0xfe,0x35,0x04,0x3a,0xfe,0x37,0x01,0xc9,0x05,0x00,0x00,0xff,0xff,0x00,0x31,0xfe,0xd7,0x05,0x9b,0x05,0xb0,0x02,0x26,0x01,0xc7,0x00,0x00,0x01,0x07,0x00,0x0f,0x04,0x60,0xff,0xd9,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0xd7,0x04,0xa0,0x04,0x3a,0x02,0x26, +0x01,0xe7,0x00,0x00,0x01,0x07,0x00,0x0f,0x03,0x65,0xff,0xd9,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0xa9,0xfe,0x4b,0x04,0xf6,0x05,0xb0,0x00,0x17,0x00,0x4f,0x40,0x14,0x00,0x00,0x00,0x17,0x00,0x17,0x16,0x15,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03,0x02,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x2e,0x0c,0x01,0x03,0x05,0x0b,0x01,0x02,0x03,0x02,0x15,0x00,0x00,0x00,0x04,0x05,0x00,0x04,0x00,0x00,0x1d,0x07,0x06,0x02,0x01,0x01,0x07,0x16,0x00,0x05,0x05,0x08,0x16,0x00,0x03,0x03,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x12,0x02,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x11,0x33,0x11,0x14,0x06,0x23,0x22,0x26, +0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x21,0x11,0x23,0x11,0x01,0x6e,0x02,0xc3,0xc5,0xad,0x99,0x1f,0x35,0x1c,0x0e,0x0e,0x43,0x11,0x3c,0x45,0xfd,0x3d,0xc5,0x05,0xb0,0xfd,0x6e,0x02,0x92,0xf9,0xf7,0xa7,0xb5,0x09,0x09,0x96,0x05,0x08,0x67,0x5a,0x02,0xdc,0xfd,0x7d,0x05,0xb0,0x00,0x00,0x01,0x00,0x8f,0xfe,0x4b,0x03,0xfb, +0x04,0x3a,0x00,0x17,0x00,0x4f,0x40,0x14,0x00,0x00,0x00,0x17,0x00,0x17,0x16,0x15,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03,0x02,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2e,0x0c,0x01,0x03,0x05,0x0b,0x01,0x02,0x03,0x02,0x15,0x00,0x00,0x00,0x04,0x05,0x00,0x04,0x00,0x00,0x1d,0x07,0x06,0x02,0x01,0x01,0x0a,0x16,0x00, +0x05,0x05,0x08,0x16,0x00,0x03,0x03,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x12,0x02,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x11,0x21,0x11,0x33,0x11,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x21,0x11,0x23,0x11,0x01,0x54,0x01,0xe2,0xc5,0xad,0x99,0x1f,0x35,0x1c,0x0f,0x0d,0x43,0x11,0x3c,0x45,0xfe,0x1e,0xc5, +0x04,0x3a,0xfe,0x2c,0x01,0xd4,0xfb,0x6d,0xa7,0xb5,0x09,0x09,0x96,0x05,0x08,0x67,0x5a,0x02,0x25,0xfe,0x34,0x04,0x3a,0x00,0xff,0xff,0x00,0xaa,0xfe,0xd7,0x05,0x9b,0x05,0xb0,0x02,0x26,0x00,0x2b,0x00,0x00,0x01,0x07,0x00,0x0f,0x04,0x60,0xff,0xd9,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f, +0xfe,0xd7,0x04,0x9f,0x04,0x3a,0x02,0x26,0x01,0xe9,0x00,0x00,0x01,0x07,0x00,0x0f,0x03,0x64,0xff,0xd9,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x93,0xfe,0x99,0x04,0xcc,0x05,0xb0,0x02,0x26,0x01,0xd3,0x00,0x00,0x00,0x07,0x03,0xe0,0x03,0x15,0x00,0x00,0xff,0xff,0x00,0x7f,0xfe,0x99,0x03,0xdc, +0x04,0x3b,0x02,0x26,0x01,0xf3,0x00,0x00,0x00,0x07,0x03,0xe0,0x02,0x24,0x00,0x00,0xff,0xff,0x00,0xaa,0xfe,0xd7,0x06,0xec,0x05,0xb0,0x02,0x26,0x00,0x30,0x00,0x00,0x01,0x07,0x00,0x0f,0x05,0xb1,0xff,0xd9,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x99,0xfe,0xd7,0x05,0xf9,0x04,0x3a,0x02,0x26, +0x01,0xe8,0x00,0x00,0x01,0x07,0x00,0x0f,0x04,0xbe,0xff,0xd9,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xd9,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xbe,0x00,0x00,0x01,0x84,0x05,0xb0,0x02,0x06,0x00,0x2c,0x00,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x4e,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0xdc,0x01,0x9e, +0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x0c,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x01,0x54,0x7f,0x5c,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0x0d,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x00,0x6a, +0x00,0x86,0x01,0x5d,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x05,0xcb,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x00,0x6a,0x29,0x1b,0x00,0x08,0xb1,0x02,0x02,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x0e,0x00,0x00,0x07,0x84,0x05,0xb0,0x02,0x06,0x00,0x88,0x00,0x00, +0xff,0xff,0x00,0x58,0xff,0xeb,0x06,0x9a,0x04,0x4e,0x02,0x06,0x00,0xa8,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x4e,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0xbf,0x01,0x9e,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x0d,0x02,0x26, +0x00,0x48,0x00,0x00,0x01,0x06,0x01,0x54,0x6f,0x5d,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5d,0xb0,0x0d,0x2b,0x00,0x02,0x00,0x59,0xff,0xeb,0x05,0x21,0x05,0xc5,0x00,0x16,0x00,0x1f,0x00,0x54,0x40,0x16,0x18,0x17,0x01,0x00,0x1c,0x1b,0x17,0x1f,0x18,0x1f,0x11,0x0f,0x0c,0x0b,0x08,0x06,0x00,0x16,0x01,0x16,0x08,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x31,0x14,0x01,0x03,0x00,0x13,0x0d,0x02,0x02,0x03,0x02,0x15,0x00,0x02,0x00,0x05,0x04,0x02,0x05,0x00,0x00,0x1d,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x06,0x01,0x00,0x00,0x0d,0x16,0x07,0x01,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x0e,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x01,0x20,0x00,0x11,0x15,0x10,0x00,0x23, +0x20,0x00,0x11,0x35,0x21,0x37,0x36,0x02,0x23,0x22,0x06,0x07,0x27,0x3e,0x01,0x13,0x32,0x12,0x37,0x27,0x21,0x15,0x14,0x16,0x02,0x66,0x01,0x4a,0x01,0x71,0xfe,0xa2,0xfc,0xfe,0xd0,0xfe,0xc2,0x03,0xfc,0x02,0x04,0xf9,0xfc,0x6c,0x99,0x4a,0x31,0x32,0xbf,0xf0,0xaa,0xd2,0x11,0x03,0xfc,0xcd,0xc7,0x05,0xc5,0xfe,0x71,0xfe,0xba,0x31, +0xfe,0xc4,0xfe,0x68,0x01,0x61,0x01,0x38,0x6c,0x05,0xf8,0x01,0x3d,0x2f,0x25,0x8b,0x23,0x41,0xfa,0xc0,0x01,0x0d,0xd2,0x05,0x1f,0xcf,0xf6,0x00,0xff,0xff,0x00,0x81,0xff,0xec,0x04,0x02,0x04,0x4e,0x01,0x0f,0x00,0x48,0x04,0x63,0x04,0x3a,0xc0,0x01,0x00,0x09,0xb1,0x00,0x02,0xb8,0x04,0x3a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x59, +0xff,0xeb,0x05,0x21,0x06,0xdf,0x02,0x26,0x02,0x83,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0x73,0x01,0x2f,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x2f,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x81,0xff,0xec,0x04,0x02,0x05,0xcb,0x00,0x2f,0x00,0x48,0x04,0x63,0x04,0x3a,0xc0,0x01,0x01,0x06,0x00,0x6a,0x36,0x1b,0x00,0x11,0xb1,0x00,0x02,0xb8, +0x04,0x3a,0xb0,0x0d,0x2b,0xb1,0x02,0x02,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x1a,0x00,0x00,0x06,0x7c,0x07,0x0d,0x02,0x26,0x01,0xc2,0x00,0x00,0x01,0x07,0x00,0x6a,0x01,0x4a,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0x00,0x00,0x05,0xa6,0x05,0xb6,0x02,0x26, +0x01,0xe2,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xde,0x00,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x78,0xff,0xeb,0x04,0xdf,0x07,0x22,0x02,0x26,0x01,0xc3,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xa9,0x01,0x72,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x64, +0xff,0xed,0x03,0xec,0x05,0xca,0x02,0x26,0x01,0xe3,0x00,0x00,0x01,0x06,0x00,0x6a,0x25,0x1a,0x00,0x08,0xb1,0x01,0x02,0xb0,0x1a,0xb0,0x0d,0x2b,0x00,0x01,0x00,0x69,0xff,0xeb,0x04,0x2d,0x05,0xb0,0x00,0x1c,0x00,0x57,0x40,0x10,0x1b,0x19,0x15,0x13,0x11,0x10,0x0d,0x0b,0x07,0x06,0x04,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x40,0x3a,0x05,0x01,0x00,0x01,0x1c,0x01,0x02,0x00,0x0f,0x01,0x05,0x04,0x03,0x15,0x00,0x04,0x06,0x05,0x06,0x04,0x05,0x29,0x00,0x02,0x00,0x06,0x04,0x02,0x06,0x01,0x00,0x1d,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x00,0x05,0x05,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x07,0xb0,0x2f, +0x2b,0x01,0x27,0x21,0x35,0x21,0x17,0x01,0x1e,0x01,0x15,0x14,0x04,0x23,0x22,0x24,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x03,0x0d,0x02,0xfd,0x89,0x03,0x65,0x01,0xfe,0x67,0xdb,0xf1,0xfe,0xee,0xdd,0xc0,0xfe,0xeb,0x05,0x02,0xbd,0x98,0x79,0x8b,0x9f,0xa1,0xa0,0x92,0x05,0x10,0x05,0x9b,0x78,0xfe, +0x15,0x0d,0xe3,0xc7,0xc8,0xe3,0xd6,0xcd,0x06,0x72,0x9d,0x95,0x78,0x99,0x8f,0x9a,0x00,0x01,0x00,0x69,0xfe,0x75,0x04,0x2d,0x04,0x3a,0x00,0x1c,0x00,0x90,0x40,0x0e,0x1b,0x19,0x15,0x13,0x11,0x10,0x0d,0x0b,0x04,0x03,0x02,0x01,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x30,0x58,0x40,0x38,0x05,0x01,0x00,0x01,0x1c,0x06, +0x02,0x05,0x00,0x0f,0x01,0x04,0x03,0x03,0x15,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x29,0x00,0x03,0x04,0x00,0x03,0x04,0x27,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x0a,0x16,0x00,0x04,0x04,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0c,0x02,0x17,0x07,0x1b,0x40,0x35,0x05,0x01,0x00,0x01,0x1c,0x06,0x02,0x05,0x00,0x0f,0x01, +0x04,0x03,0x03,0x15,0x00,0x05,0x00,0x03,0x00,0x05,0x03,0x29,0x00,0x03,0x04,0x00,0x03,0x04,0x27,0x00,0x04,0x00,0x02,0x04,0x02,0x01,0x00,0x1c,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x0a,0x00,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x01,0x27,0x21,0x35,0x21,0x17,0x01,0x1e,0x01,0x15,0x14,0x04,0x23,0x22,0x24,0x3f,0x01,0x33, +0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x02,0xf8,0x03,0xfd,0x9f,0x03,0x65,0x01,0xfe,0x74,0xd6,0xe9,0xfe,0xed,0xdc,0xbf,0xfe,0xea,0x05,0x02,0xbd,0x98,0x79,0x8b,0x9f,0xa2,0xa0,0x93,0x03,0x99,0x05,0x9c,0x78,0xfe,0x13,0x10,0xe2,0xc4,0xc6,0xe4,0xd7,0xcb,0x06,0x70,0x9d,0x95,0x76,0x9a,0x8e,0x9a,0x00,0x00,0x00, +0xff,0xff,0x00,0xad,0x00,0x00,0x04,0xfa,0x06,0xfa,0x02,0x26,0x01,0xc4,0x00,0x00,0x01,0x07,0x00,0x71,0x00,0xf8,0x01,0x4a,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x4a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x03,0xfc,0x05,0xa4,0x02,0x26,0x01,0xe4,0x00,0x00,0x01,0x06,0x00,0x71,0x67,0xf4,0x00,0x09,0xb1,0x01,0x01,0xb8, +0xff,0xf4,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0xad,0x00,0x00,0x04,0xfa,0x07,0x0d,0x02,0x26,0x01,0xc4,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xd4,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x03,0xfc,0x05,0xb6,0x02,0x26,0x01,0xe4,0x00,0x00,0x01,0x06,0x00,0x6a, +0x43,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x22,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xb8,0x01,0x72,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x72,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x05,0xcb,0x02,0x26,0x00,0x52,0x00,0x00, +0x01,0x06,0x00,0x6a,0x44,0x1b,0x00,0x08,0xb1,0x02,0x02,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x05,0xc5,0x02,0x06,0x02,0x1e,0x00,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x04,0x4e,0x02,0x06,0x02,0x1f,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x07,0x08,0x02,0x26,0x02,0x1e,0x00,0x00, +0x01,0x07,0x00,0x6a,0x00,0xce,0x01,0x58,0x00,0x09,0xb1,0x03,0x02,0xb8,0x01,0x58,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x05,0xe7,0x02,0x26,0x02,0x1f,0x00,0x00,0x01,0x06,0x00,0x6a,0x2d,0x37,0x00,0x08,0xb1,0x03,0x02,0xb0,0x37,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xb5,0xff,0xec,0x04,0xff,0x07,0x23,0x02,0x26, +0x01,0xd9,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xb2,0x01,0x73,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x73,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x63,0xff,0xeb,0x03,0xe3,0x05,0xcb,0x02,0x26,0x01,0xf9,0x00,0x00,0x01,0x06,0x00,0x6a,0x21,0x1b,0x00,0x08,0xb1,0x01,0x02,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x42,0xff,0xeb,0x04,0xc8, +0x06,0xfa,0x02,0x26,0x01,0xcf,0x00,0x00,0x01,0x07,0x00,0x71,0x00,0xa8,0x01,0x4a,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x4a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x05,0xa4,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x06,0x00,0x71,0x24,0xf4,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf4,0xb0,0x0d,0x2b,0x00,0x00,0x00, +0xff,0xff,0x00,0x42,0xff,0xeb,0x04,0xc8,0x07,0x0d,0x02,0x26,0x01,0xcf,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0x84,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x05,0xb6,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x06,0x00,0x6a,0x00,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0, +0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x42,0xff,0xeb,0x04,0xc8,0x07,0x4b,0x02,0x26,0x01,0xcf,0x00,0x00,0x01,0x07,0x01,0x59,0x01,0x36,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xfc,0x05,0xf4,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x07,0x01,0x59,0x00,0xb2,0x00,0x06, +0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x93,0x00,0x00,0x04,0xcc,0x07,0x0d,0x02,0x26,0x01,0xd3,0x00,0x00,0x01,0x07,0x00,0x6a,0x00,0xae,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x7f,0x00,0x00,0x03,0xdc,0x05,0xb6,0x02,0x26,0x01,0xf3,0x00,0x00, +0x01,0x06,0x00,0x6a,0x26,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xa3,0xfe,0x99,0x04,0x20,0x05,0xb0,0x02,0x26,0x01,0x6e,0x00,0x00,0x00,0x07,0x03,0xe0,0x00,0xd4,0x00,0x00,0xff,0xff,0x00,0x8f,0xfe,0x99,0x03,0x3f,0x04,0x3a,0x02,0x26,0x01,0xdf,0x00,0x00,0x00,0x07,0x03,0xe0,0x00,0x9f,0x00,0x00, +0xff,0xff,0x00,0xa3,0x00,0x00,0x06,0x32,0x07,0x0d,0x00,0x26,0x01,0xd8,0x00,0x00,0x00,0x27,0x00,0x2c,0x04,0xae,0x00,0x00,0x01,0x07,0x00,0x6a,0x01,0x69,0x01,0x5d,0x00,0x09,0xb1,0x03,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xad,0x00,0x00,0x05,0x98,0x05,0xb6,0x00,0x26,0x01,0xf8,0x14,0x00,0x00,0x27,0x00,0xf3, +0x04,0x3a,0x00,0x00,0x01,0x07,0x00,0x6a,0x01,0x22,0x00,0x06,0x00,0x08,0xb1,0x03,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x40,0xfe,0x4b,0x04,0x7d,0x05,0xb0,0x00,0x26,0x01,0x6e,0x5d,0x00,0x00,0x26,0x03,0x80,0xae,0x3f,0x01,0x07,0x03,0xe2,0x01,0x06,0x00,0x00,0x00,0x08,0xb1,0x01,0x01,0xb0,0x3f,0xb0,0x0d,0x2b, +0xff,0xff,0x00,0x41,0xfe,0x4b,0x03,0xa1,0x04,0x3a,0x00,0x26,0x01,0xdf,0x62,0x00,0x00,0x26,0x03,0x80,0xaf,0x90,0x01,0x07,0x03,0xe2,0x00,0xf6,0x00,0x00,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0x90,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x42,0xfe,0x4b,0x05,0x23,0x05,0xb0,0x02,0x26,0x00,0x3b,0x00,0x00,0x00,0x07,0x03,0xe2, +0x03,0xb1,0x00,0x00,0xff,0xff,0x00,0x2e,0xfe,0x4b,0x04,0x3e,0x04,0x3a,0x02,0x26,0x00,0x5b,0x00,0x00,0x00,0x07,0x03,0xe2,0x02,0xcc,0x00,0x00,0x00,0x01,0x00,0x42,0x00,0x00,0x04,0xd6,0x05,0xb0,0x00,0x11,0x00,0x43,0x40,0x12,0x11,0x10,0x0f,0x0e,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x24,0x0d,0x01,0x04,0x05,0x04,0x01,0x01,0x00,0x02,0x15,0x07,0x01,0x04,0x03,0x01,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x06,0x01,0x05,0x05,0x07,0x16,0x02,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x01,0x23,0x09,0x01,0x23,0x01,0x23,0x35,0x33,0x01,0x33,0x09,0x01,0x33,0x01,0x33,0x03, +0xd5,0xac,0x01,0xad,0xeb,0xfe,0xa3,0xfe,0xa2,0xee,0x01,0xad,0x9b,0x8d,0xfe,0x6b,0xec,0x01,0x52,0x01,0x54,0xee,0xfe,0x6a,0x9f,0x02,0x9b,0xfd,0x65,0x02,0x42,0xfd,0xbe,0x02,0x9b,0x9b,0x02,0x7a,0xfd,0xc8,0x02,0x38,0xfd,0x86,0x00,0x01,0x00,0x2e,0x00,0x00,0x03,0xd4,0x04,0x3a,0x00,0x11,0x00,0x43,0x40,0x12,0x11,0x10,0x0f,0x0e, +0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x24,0x0d,0x01,0x04,0x05,0x04,0x01,0x01,0x00,0x02,0x15,0x07,0x01,0x04,0x03,0x01,0x00,0x01,0x04,0x00,0x00,0x02,0x1d,0x06,0x01,0x05,0x05,0x0a,0x16,0x02,0x01,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x23,0x01, +0x23,0x0b,0x01,0x23,0x01,0x23,0x35,0x33,0x01,0x33,0x1b,0x01,0x33,0x01,0x33,0x03,0x38,0xa0,0x01,0x3c,0xe2,0xf0,0xf0,0xe4,0x01,0x3b,0xb2,0xa7,0xfe,0xda,0xe3,0xe3,0xe6,0xe6,0xfe,0xd9,0x95,0x01,0xde,0xfe,0x22,0x01,0x99,0xfe,0x67,0x01,0xde,0x9b,0x01,0xc1,0xfe,0x71,0x01,0x8f,0xfe,0x3f,0x00,0x02,0x00,0x5b,0x00,0x00,0x04,0x72, +0x05,0xb0,0x00,0x0a,0x00,0x13,0x00,0x40,0x40,0x14,0x0b,0x0b,0x00,0x00,0x0b,0x13,0x0b,0x12,0x0e,0x0c,0x00,0x0a,0x00,0x09,0x05,0x03,0x02,0x01,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x05,0x01,0x02,0x00,0x03,0x04,0x02,0x03,0x01,0x00,0x1d,0x00,0x00,0x00,0x07,0x16,0x06,0x01,0x04,0x04,0x01,0x01,0x02,0x1b,0x00,0x01, +0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x11,0x33,0x11,0x21,0x22,0x24,0x35,0x34,0x24,0x33,0x01,0x11,0x21,0x22,0x06,0x15,0x14,0x16,0x33,0x03,0xad,0xc5,0xfd,0xd4,0xe9,0xfe,0xfe,0x01,0x01,0xea,0x01,0x67,0xfe,0x99,0x94,0x92,0x92,0x94,0x03,0x70,0x02,0x40,0xfa,0x50,0xf6,0xc6,0xc5,0xef,0xfd,0x2a,0x02,0x3b,0xa0,0x77,0x7b, +0xa9,0x00,0x00,0x00,0xff,0xff,0x00,0x62,0xff,0xeb,0x03,0xf5,0x06,0x18,0x02,0x06,0x00,0x47,0x00,0x00,0x00,0x02,0x00,0x5b,0x00,0x00,0x06,0x6e,0x05,0xb0,0x00,0x18,0x00,0x21,0x00,0x4d,0x40,0x18,0x19,0x19,0x01,0x00,0x19,0x21,0x19,0x20,0x1c,0x1a,0x12,0x11,0x0c,0x0a,0x09,0x08,0x07,0x05,0x00,0x18,0x01,0x17,0x09,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x28,0x00,0x04,0x01,0x05,0x01,0x04,0x05,0x29,0x00,0x01,0x00,0x05,0x03,0x01,0x05,0x01,0x00,0x1d,0x00,0x02,0x02,0x07,0x16,0x08,0x06,0x02,0x03,0x03,0x00,0x01,0x02,0x1b,0x07,0x01,0x00,0x00,0x08,0x00,0x17,0x05,0xb0,0x2f,0x2b,0x21,0x22,0x24,0x35,0x34,0x24,0x33,0x21,0x11,0x33,0x11,0x37,0x3e,0x01,0x37, +0x36,0x26,0x27,0x33,0x1e,0x01,0x07,0x0e,0x01,0x23,0x25,0x11,0x21,0x22,0x06,0x15,0x14,0x16,0x33,0x02,0x46,0xe9,0xfe,0xfe,0x01,0x01,0xea,0x01,0x67,0xc5,0x53,0x6a,0x74,0x04,0x01,0x1f,0x1e,0xbe,0x21,0x24,0x02,0x04,0xf3,0xb0,0xfe,0xe8,0xfe,0x99,0x94,0x92,0x92,0x94,0xf6,0xc6,0xc5,0xef,0x02,0x40,0xfa,0xe9,0x01,0x01,0x8d,0x7e, +0x4d,0xa7,0x4f,0x64,0x97,0x48,0xcc,0xda,0x9a,0x02,0x3b,0xa0,0x77,0x7b,0xa9,0x00,0x00,0x02,0x00,0x62,0xff,0xe9,0x06,0x74,0x06,0x18,0x00,0x22,0x00,0x33,0x00,0x53,0x40,0x12,0x2e,0x2c,0x27,0x25,0x20,0x1e,0x1a,0x18,0x13,0x12,0x0d,0x0b,0x08,0x07,0x04,0x02,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x34,0x06,0x01,0x06,0x00, +0x23,0x1c,0x02,0x02,0x03,0x02,0x15,0x00,0x03,0x06,0x02,0x06,0x03,0x02,0x29,0x00,0x01,0x01,0x09,0x16,0x00,0x06,0x06,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x10,0x16,0x07,0x01,0x02,0x02,0x04,0x01,0x00,0x1b,0x05,0x01,0x04,0x04,0x0e,0x04,0x17,0x07,0xb0,0x2f,0x2b,0x13,0x10,0x12,0x33,0x32,0x16,0x17,0x11,0x33,0x11,0x06,0x16,0x33, +0x3e,0x01,0x37,0x36,0x26,0x27,0x37,0x1e,0x01,0x07,0x02,0x00,0x23,0x06,0x26,0x27,0x0e,0x01,0x23,0x22,0x02,0x35,0x01,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x37,0x2e,0x01,0x35,0x62,0xdf,0xc9,0x59,0x8c,0x34,0xc5,0x02,0x5c,0x4d,0x86,0x94,0x04,0x01,0x1f,0x1e,0xbe,0x21,0x24,0x02,0x04,0xfe,0xec,0xcb,0x78, +0xa3,0x29,0x35,0xa1,0x6d,0xc6,0xe0,0x02,0xc1,0x27,0x72,0x4e,0x8e,0x87,0x86,0x8d,0x54,0x74,0x27,0x03,0x03,0x02,0x09,0x01,0x05,0x01,0x40,0x3e,0x3b,0x02,0x43,0xfb,0x41,0x5f,0x75,0x01,0xd2,0xb9,0x61,0xcb,0x66,0x01,0x7a,0xbd,0x5c,0xfe,0xf6,0xfe,0xe4,0x02,0x55,0x5d,0x57,0x59,0x01,0x1f,0xea,0x01,0x3d,0x3a,0x43,0xea,0xbb,0x15, +0xa4,0xc5,0x49,0x42,0x0f,0x22,0x12,0x00,0x00,0x01,0x00,0x36,0xff,0xe8,0x05,0xd3,0x05,0xb0,0x00,0x2c,0x00,0x4f,0x40,0x10,0x2a,0x28,0x23,0x22,0x1d,0x1b,0x10,0x0e,0x0d,0x0b,0x07,0x05,0x04,0x02,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x32,0x15,0x01,0x00,0x01,0x01,0x15,0x00,0x05,0x02,0x01,0x02,0x05,0x01,0x29,0x00,0x01, +0x00,0x00,0x04,0x01,0x00,0x01,0x00,0x1d,0x00,0x02,0x02,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x04,0x04,0x06,0x01,0x00,0x1b,0x00,0x06,0x06,0x0e,0x06,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x34,0x26,0x2b,0x01,0x35,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x35,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x06, +0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x33,0x1e,0x01,0x07,0x0a,0x01,0x23,0x06,0x26,0x27,0x02,0xbf,0x89,0x74,0xbf,0x88,0xa6,0x93,0x8f,0x98,0xfe,0x99,0x01,0x67,0xef,0xfd,0x75,0x6f,0x76,0x69,0x01,0x4f,0x43,0x74,0x80,0x04,0x01,0x1f,0x1e,0xbe,0x22,0x22,0x01,0x04,0xfe,0xbb,0xa0,0xae,0x08,0x01,0x72,0x76,0x91,0x9b,0x7e,0x83, +0x79,0x87,0x9b,0xd4,0xc9,0x71,0xa5,0x31,0x28,0xb0,0x80,0x44,0x4c,0x5f,0x01,0xd4,0xb7,0x61,0xcc,0x66,0x86,0xb3,0x5a,0xfe,0xf7,0xfe,0xe3,0x03,0x9d,0xab,0x00,0x00,0x00,0x01,0x00,0x31,0xff,0xe3,0x04,0xeb,0x04,0x3a,0x00,0x2d,0x00,0x54,0x40,0x10,0x24,0x22,0x21,0x1f,0x1b,0x19,0x18,0x16,0x11,0x0f,0x0a,0x09,0x04,0x02,0x07,0x07, +0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x37,0x29,0x01,0x03,0x04,0x2d,0x00,0x02,0x00,0x03,0x02,0x15,0x00,0x01,0x05,0x04,0x05,0x01,0x04,0x29,0x00,0x04,0x00,0x03,0x00,0x04,0x03,0x01,0x00,0x1d,0x00,0x05,0x05,0x06,0x01,0x00,0x1b,0x00,0x06,0x06,0x0a,0x16,0x00,0x00,0x00,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x07,0xb0, +0x2f,0x2b,0x25,0x06,0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x33,0x1e,0x01,0x07,0x0e,0x01,0x23,0x06,0x26,0x27,0x35,0x34,0x26,0x2b,0x01,0x27,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x27,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x02,0xec,0x01,0x27,0x2f,0x6a,0x75,0x04,0x01,0x20,0x1e,0xbe,0x22,0x24,0x02,0x05, +0xf2,0xb1,0x8a,0x8a,0x06,0x6a,0x62,0xd3,0x02,0xb8,0x77,0x71,0x72,0x77,0xfe,0xfa,0x06,0x01,0x0c,0xce,0xe2,0x60,0x5d,0x63,0x59,0xd5,0x2a,0x2c,0x02,0x99,0x89,0x4c,0xa4,0x4f,0x66,0x92,0x47,0xd7,0xe6,0x03,0x72,0x81,0x4b,0x47,0x4f,0x9a,0x53,0x4d,0x51,0x5f,0x99,0xaa,0x98,0x51,0x72,0x24,0x1c,0x7a,0x59,0x4d,0x00,0x02,0x00,0x50, +0xfe,0xfc,0x03,0xd1,0x05,0xb0,0x00,0x21,0x00,0x27,0x00,0x96,0x40,0x14,0x00,0x00,0x27,0x26,0x24,0x23,0x00,0x21,0x00,0x20,0x1a,0x19,0x0c,0x0a,0x09,0x07,0x03,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x0a,0x58,0x40,0x37,0x11,0x01,0x04,0x00,0x25,0x22,0x18,0x03,0x03,0x06,0x02,0x15,0x00,0x05,0x03,0x03,0x05,0x20, +0x00,0x00,0x07,0x01,0x04,0x06,0x00,0x04,0x01,0x00,0x1d,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x06,0x06,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x08,0x03,0x17,0x07,0x1b,0x40,0x36,0x11,0x01,0x04,0x00,0x25,0x22,0x18,0x03,0x03,0x06,0x02,0x15,0x00,0x05,0x03,0x05,0x2c,0x00,0x00,0x07,0x01,0x04,0x06,0x00, +0x04,0x01,0x00,0x1d,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x07,0x16,0x00,0x06,0x06,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x08,0x03,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x13,0x35,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x35,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x14,0x16,0x17,0x15,0x23,0x2e,0x01,0x3d, +0x01,0x34,0x26,0x23,0x01,0x03,0x23,0x13,0x35,0x33,0xab,0xa2,0xa7,0x95,0x8f,0x98,0xfe,0xee,0x01,0x12,0xef,0xfc,0x75,0x6f,0x77,0x69,0x1f,0x25,0xcb,0x29,0x15,0x89,0x74,0x02,0x4a,0x96,0x75,0x46,0xc5,0x02,0x78,0x9a,0x7f,0x82,0x7a,0x88,0x9b,0xd4,0xcb,0x70,0xa6,0x30,0x28,0xb0,0x80,0x88,0x44,0x6c,0x22,0x19,0x23,0x83,0x47,0x84, +0x76,0x91,0xfd,0xb6,0xfe,0xce,0x01,0x3c,0xa3,0x00,0x00,0x00,0x00,0x02,0x00,0x7b,0xfe,0xe8,0x03,0xc1,0x04,0x3a,0x00,0x21,0x00,0x27,0x00,0x96,0x40,0x14,0x00,0x00,0x27,0x26,0x24,0x23,0x00,0x21,0x00,0x20,0x1a,0x19,0x0c,0x0a,0x09,0x07,0x03,0x01,0x08,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x09,0x58,0x40,0x37,0x11,0x01, +0x04,0x00,0x25,0x22,0x18,0x03,0x03,0x06,0x02,0x15,0x00,0x05,0x03,0x03,0x05,0x20,0x00,0x00,0x07,0x01,0x04,0x06,0x00,0x04,0x01,0x00,0x1d,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0a,0x16,0x00,0x06,0x06,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x08,0x03,0x17,0x07,0x1b,0x40,0x36,0x11,0x01,0x04,0x00,0x25,0x22,0x18,0x03, +0x03,0x06,0x02,0x15,0x00,0x05,0x03,0x05,0x2c,0x00,0x00,0x07,0x01,0x04,0x06,0x00,0x04,0x01,0x00,0x1d,0x00,0x01,0x01,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0a,0x16,0x00,0x06,0x06,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x08,0x03,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x13,0x35,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x35,0x21,0x32,0x16, +0x15,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x14,0x16,0x17,0x15,0x23,0x2e,0x01,0x3d,0x01,0x34,0x26,0x23,0x01,0x03,0x23,0x13,0x35,0x33,0xc1,0xd2,0x78,0x70,0x71,0x77,0xfe,0xe8,0x01,0x18,0xcd,0xe1,0x61,0x5e,0x66,0x59,0x1d,0x22,0xcb,0x25,0x14,0x6a,0x62,0x02,0x11,0x96,0x75,0x46,0xc5,0x01,0xb7,0x9a,0x53,0x4e,0x51,0x5e,0x99,0xa9, +0x99,0x51,0x74,0x24,0x1d,0x84,0x61,0x61,0x2d,0x56,0x16,0x13,0x17,0x63,0x33,0x5f,0x50,0x5b,0xfe,0x63,0xfe,0xce,0x01,0x3c,0xa3,0x00,0x00,0x00,0x00,0x01,0x00,0x45,0xff,0xe8,0x07,0x75,0x05,0xb0,0x00,0x21,0x00,0xaf,0x40,0x10,0x1f,0x1d,0x18,0x17,0x12,0x10,0x0d,0x0c,0x09,0x07,0x06,0x04,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90, +0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x24,0x00,0x05,0x00,0x02,0x00,0x05,0x02,0x29,0x00,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x04,0x01,0x02,0x02,0x01,0x01,0x00,0x1b,0x06,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0x1b,0x4b,0xb0,0x17,0x58,0x40,0x30,0x00,0x05,0x00,0x02,0x00,0x05,0x02,0x29,0x00,0x00,0x00,0x03,0x00, +0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x04,0x01,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x08,0x16,0x04,0x01,0x02,0x02,0x06,0x01,0x00,0x1b,0x00,0x06,0x06,0x0e,0x06,0x17,0x07,0x1b,0x40,0x2e,0x00,0x05,0x00,0x02,0x00,0x05,0x02,0x29,0x00,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x07,0x16,0x00,0x02,0x02,0x01,0x01,0x00, +0x1b,0x00,0x01,0x01,0x08,0x16,0x00,0x04,0x04,0x06,0x01,0x00,0x1b,0x00,0x06,0x06,0x0e,0x06,0x17,0x07,0x59,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x10,0x02,0x2b,0x01,0x35,0x33,0x32,0x12,0x19,0x01,0x21,0x11,0x06,0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x37,0x1e,0x01,0x07,0x02,0x00,0x23,0x06,0x26,0x27,0x04,0x24,0xfe,0x28,0xd8, +0xfa,0x35,0x29,0x95,0x85,0x03,0x61,0x01,0x5b,0x4d,0x87,0x93,0x04,0x01,0x1f,0x1e,0xbe,0x21,0x24,0x02,0x04,0xfe,0xec,0xcb,0xaa,0xba,0x08,0x05,0x15,0xfd,0xeb,0xfe,0x72,0xfe,0x8e,0x9a,0x01,0x20,0x01,0x46,0x02,0xb0,0xfb,0xa9,0x5f,0x75,0x01,0xd2,0xb9,0x61,0xcb,0x66,0x01,0x7a,0xbd,0x5c,0xfe,0xf6,0xfe,0xe4,0x03,0xb1,0xc0,0x00, +0x00,0x01,0x00,0x41,0xff,0xe8,0x06,0x41,0x04,0x3a,0x00,0x21,0x00,0x83,0x40,0x10,0x1f,0x1d,0x18,0x17,0x12,0x10,0x0d,0x0c,0x09,0x07,0x06,0x04,0x01,0x00,0x07,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x30,0x00,0x05,0x00,0x02,0x00,0x05,0x02,0x29,0x00,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x0a,0x16, +0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x06,0x01,0x01,0x01,0x08,0x16,0x00,0x04,0x04,0x01,0x01,0x02,0x1b,0x06,0x01,0x01,0x01,0x08,0x01,0x17,0x07,0x1b,0x40,0x2e,0x00,0x05,0x00,0x02,0x00,0x05,0x02,0x29,0x00,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x03,0x0a,0x16,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x08,0x16,0x00, +0x04,0x04,0x06,0x01,0x02,0x1b,0x00,0x06,0x06,0x0e,0x06,0x17,0x07,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x10,0x02,0x2b,0x01,0x3f,0x01,0x32,0x36,0x35,0x11,0x21,0x11,0x06,0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x33,0x1e,0x01,0x07,0x06,0x02,0x23,0x06,0x26,0x27,0x03,0x2d,0xfe,0xcd,0xb2,0xce,0x39,0x04,0x29,0x6b,0x5c,0x02,0xbd, +0x01,0x5a,0x4c,0x6b,0x74,0x04,0x01,0x20,0x1e,0xbf,0x21,0x24,0x02,0x04,0xf3,0xb1,0xa8,0xba,0x08,0x03,0x9e,0xfe,0xd0,0xfe,0xc3,0xfe,0xcf,0xa8,0x01,0xd4,0xf1,0x01,0xcc,0xfd,0x1f,0x5f,0x75,0x01,0xbb,0xa4,0x5c,0xc0,0x61,0x78,0xaf,0x56,0xf4,0xfe,0xfa,0x03,0xb1,0xc0,0x00,0x01,0x00,0xa9,0xff,0xe8,0x07,0x7e,0x05,0xb0,0x00,0x1d, +0x00,0x7f,0x40,0x16,0x00,0x00,0x00,0x1d,0x00,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x12,0x10,0x0b,0x0a,0x05,0x03,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x28,0x00,0x01,0x05,0x06,0x05,0x01,0x06,0x29,0x00,0x06,0x00,0x03,0x00,0x06,0x03,0x00,0x00,0x1d,0x08,0x07,0x02,0x05,0x05,0x07,0x16,0x00, +0x00,0x00,0x02,0x01,0x00,0x1b,0x04,0x01,0x02,0x02,0x0e,0x02,0x17,0x05,0x1b,0x40,0x2c,0x00,0x01,0x05,0x06,0x05,0x01,0x06,0x29,0x00,0x06,0x00,0x03,0x00,0x06,0x03,0x00,0x00,0x1d,0x08,0x07,0x02,0x05,0x05,0x07,0x16,0x00,0x04,0x04,0x08,0x16,0x00,0x00,0x00,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x06,0x59,0xb0,0x2f, +0x2b,0x01,0x11,0x06,0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x37,0x1e,0x01,0x07,0x02,0x00,0x23,0x06,0x26,0x27,0x11,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x04,0xf2,0x01,0x5a,0x4d,0x87,0x94,0x04,0x01,0x20,0x1e,0xbe,0x22,0x24,0x02,0x05,0xfe,0xec,0xcb,0xa9,0xba,0x08,0xfd,0x41,0xc5,0xc5,0x02,0xbf,0x05,0xb0,0xfb,0xa9,0x5f, +0x75,0x01,0xd2,0xb9,0x61,0xca,0x67,0x01,0x7c,0xbb,0x5c,0xfe,0xf6,0xfe,0xe4,0x03,0xb1,0xc0,0x01,0x2a,0xfd,0x7d,0x05,0xb0,0xfd,0x6e,0x02,0x92,0x00,0x01,0x00,0x8f,0xff,0xe8,0x06,0x55,0x04,0x3a,0x00,0x1d,0x00,0x79,0x40,0x12,0x1b,0x19,0x14,0x13,0x0e,0x0c,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x08,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x4b,0xb0,0x16,0x58,0x40,0x27,0x00,0x06,0x02,0x03,0x02,0x06,0x03,0x29,0x00,0x03,0x00,0x00,0x05,0x03,0x00,0x00,0x00,0x1d,0x04,0x01,0x02,0x02,0x0a,0x16,0x00,0x05,0x05,0x01,0x01,0x02,0x1b,0x07,0x01,0x01,0x01,0x08,0x01,0x17,0x05,0x1b,0x40,0x2b,0x00,0x06,0x02,0x03,0x02,0x06,0x03,0x29,0x00,0x03,0x00,0x00, +0x05,0x03,0x00,0x00,0x00,0x1d,0x04,0x01,0x02,0x02,0x0a,0x16,0x00,0x01,0x01,0x08,0x16,0x00,0x05,0x05,0x07,0x01,0x02,0x1b,0x00,0x07,0x07,0x0e,0x07,0x17,0x06,0x59,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x06,0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x33,0x1e,0x01,0x07,0x06,0x02,0x23,0x06,0x26, +0x27,0x03,0x40,0xfe,0x14,0xc5,0xc5,0x01,0xec,0xc5,0x01,0x5b,0x4c,0x6a,0x75,0x04,0x01,0x1f,0x1e,0xbd,0x22,0x24,0x02,0x04,0xf2,0xb2,0xa9,0xba,0x08,0x01,0xcc,0xfe,0x34,0x04,0x3a,0xfe,0x2b,0x01,0xd5,0xfd,0x1f,0x5f,0x75,0x01,0xbb,0xa4,0x5b,0xc1,0x61,0x7b,0xac,0x56,0xf4,0xfe,0xfa,0x03,0xb1,0xc0,0x00,0x00,0x00,0x01,0x00,0x76, +0xff,0xeb,0x04,0x9f,0x05,0xc5,0x00,0x21,0x00,0x4a,0x40,0x10,0x01,0x00,0x1c,0x1b,0x16,0x14,0x0f,0x0d,0x08,0x06,0x00,0x21,0x01,0x21,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2d,0x0a,0x01,0x02,0x01,0x0b,0x01,0x04,0x02,0x02,0x15,0x00,0x04,0x02,0x03,0x02,0x04,0x03,0x29,0x00,0x02,0x02,0x01,0x01,0x00,0x1b,0x00,0x01,0x01, +0x0d,0x16,0x00,0x03,0x03,0x00,0x01,0x00,0x1b,0x05,0x01,0x00,0x00,0x0e,0x00,0x17,0x06,0xb0,0x2f,0x2b,0x05,0x20,0x00,0x19,0x01,0x10,0x00,0x21,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x02,0x15,0x11,0x14,0x12,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x33,0x1e,0x01,0x07,0x06,0x04,0x02,0xb9,0xff,0x00,0xfe,0xbd,0x01,0x43,0x01,0x00, +0x71,0xb2,0x44,0x3f,0x43,0x90,0x55,0xaf,0xcf,0xcf,0xaf,0x88,0x94,0x04,0x01,0x1b,0x18,0xbe,0x2a,0x10,0x01,0x04,0xfe,0xeb,0x15,0x01,0x5e,0x01,0x0c,0x01,0x06,0x01,0x0b,0x01,0x5f,0x2d,0x2b,0x87,0x21,0x23,0xfe,0xf6,0xc3,0xfe,0xf8,0xc6,0xfe,0xf6,0x01,0x9a,0x89,0x53,0xb5,0x61,0xc5,0x56,0x4e,0xd8,0xe6,0x00,0x00,0x01,0x00,0x62, +0xff,0xeb,0x03,0xc6,0x04,0x4e,0x00,0x21,0x00,0x4a,0x40,0x10,0x01,0x00,0x1c,0x1a,0x15,0x13,0x0e,0x0c,0x07,0x06,0x00,0x21,0x01,0x21,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2d,0x17,0x01,0x04,0x03,0x18,0x01,0x01,0x04,0x02,0x15,0x00,0x01,0x04,0x00,0x04,0x01,0x00,0x29,0x00,0x04,0x04,0x03,0x01,0x00,0x1b,0x00,0x03,0x03, +0x10,0x16,0x05,0x01,0x00,0x00,0x02,0x01,0x02,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x06,0xb0,0x2f,0x2b,0x25,0x3e,0x01,0x37,0x34,0x26,0x27,0x33,0x1e,0x01,0x15,0x0e,0x01,0x23,0x22,0x00,0x3d,0x01,0x34,0x12,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x02,0x51,0x5f,0x4e,0x03,0x0a,0x09,0xbd,0x0d,0x0e, +0x04,0xcc,0xa5,0xe6,0xfe,0xf7,0xff,0xdb,0x5e,0x8e,0x2f,0x2e,0x2f,0x7a,0x44,0x89,0x8c,0x95,0x85,0x01,0x53,0x54,0x3a,0x7a,0x38,0x44,0x73,0x35,0x9e,0xa4,0x01,0x3a,0xe3,0x2a,0xe2,0x01,0x3a,0x23,0x1f,0x93,0x1b,0x1f,0xe7,0x9a,0x2a,0x9e,0xe5,0x00,0x00,0x01,0x00,0x24,0xff,0xe8,0x05,0x4d,0x05,0xb0,0x00,0x19,0x00,0x3e,0x40,0x0e, +0x17,0x15,0x10,0x0f,0x0a,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23,0x00,0x04,0x00,0x03,0x00,0x04,0x03,0x29,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x00,0x03,0x03,0x05,0x01,0x00,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21, +0x15,0x21,0x11,0x06,0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x37,0x1e,0x01,0x07,0x02,0x00,0x23,0x06,0x26,0x27,0x01,0xfc,0xfe,0x28,0x04,0x80,0xfe,0x1d,0x01,0x5b,0x4c,0x87,0x95,0x04,0x01,0x20,0x1f,0xbf,0x22,0x23,0x02,0x04,0xfe,0xec,0xcc,0xa9,0xba,0x08,0x05,0x15,0x9b,0x9b,0xfc,0x44,0x5f,0x75,0x01,0xd2,0xb9,0x60,0xca,0x68, +0x01,0x7c,0xbb,0x5c,0xfe,0xf6,0xfe,0xe4,0x03,0xb1,0xc0,0x00,0x00,0x01,0x00,0x46,0xff,0xe8,0x04,0xbd,0x04,0x3a,0x00,0x19,0x00,0x3e,0x40,0x0e,0x17,0x15,0x10,0x0f,0x0a,0x08,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x23,0x00,0x04,0x00,0x03,0x00,0x04,0x03,0x29,0x02,0x01,0x00,0x00,0x01,0x00, +0x00,0x1b,0x00,0x01,0x01,0x0a,0x16,0x00,0x03,0x03,0x05,0x01,0x02,0x1b,0x00,0x05,0x05,0x0e,0x05,0x17,0x05,0xb0,0x2f,0x2b,0x01,0x21,0x35,0x21,0x15,0x21,0x11,0x06,0x16,0x33,0x3e,0x01,0x37,0x36,0x26,0x27,0x33,0x1e,0x01,0x07,0x0e,0x01,0x23,0x06,0x26,0x27,0x01,0xa8,0xfe,0x9e,0x03,0x8b,0xfe,0x9c,0x01,0x5a,0x4d,0x6a,0x75,0x04, +0x01,0x20,0x1d,0xbd,0x22,0x24,0x02,0x04,0xf3,0xb1,0xa9,0xba,0x08,0x03,0xa1,0x99,0x99,0xfd,0xb8,0x5f,0x75,0x01,0x9b,0x89,0x4c,0xa7,0x50,0x67,0x94,0x48,0xd8,0xe7,0x03,0xb1,0xc0,0x00,0x00,0x01,0x00,0x9c,0xff,0xeb,0x05,0x02,0x05,0xc5,0x00,0x2a,0x00,0x66,0x40,0x16,0x01,0x00,0x29,0x27,0x23,0x21,0x1f,0x1e,0x1b,0x19,0x0f,0x0d, +0x0a,0x09,0x07,0x05,0x00,0x2a,0x01,0x2a,0x09,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x43,0x1d,0x01,0x05,0x06,0x14,0x01,0x00,0x07,0x0b,0x01,0x01,0x02,0x03,0x15,0x00,0x05,0x06,0x07,0x06,0x05,0x07,0x29,0x00,0x02,0x00,0x01,0x00,0x02,0x01,0x29,0x00,0x07,0x08,0x01,0x00,0x02,0x07,0x00,0x01,0x00,0x1d,0x00,0x06,0x06,0x04,0x01, +0x00,0x1b,0x00,0x04,0x04,0x0d,0x16,0x00,0x01,0x01,0x03,0x01,0x00,0x1b,0x00,0x03,0x03,0x0e,0x03,0x17,0x08,0xb0,0x2f,0x2b,0x01,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x33,0x17,0x16,0x04,0x23,0x20,0x24,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x24,0x21,0x32,0x04,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16, +0x3b,0x01,0x15,0x02,0xcd,0xb5,0xb7,0xca,0xb2,0x9c,0xc7,0xbc,0x02,0x04,0xfe,0xbc,0xe1,0xfe,0xfe,0xfe,0xc1,0x8e,0x87,0x78,0x87,0x01,0x2a,0x01,0x01,0xdf,0x01,0x32,0x05,0x01,0xbc,0xc3,0x8c,0xb2,0xb4,0xa7,0xaf,0xb8,0x02,0x98,0x81,0x85,0x78,0x95,0x9d,0x72,0x06,0xcd,0xd6,0xe3,0xc8,0x7e,0xad,0x2a,0x30,0xa6,0x65,0xc7,0xd8,0xdc, +0xb0,0x06,0x69,0x8e,0x90,0x70,0x72,0x84,0x9c,0x00,0x00,0x00,0xff,0xff,0x00,0x62,0xff,0xed,0x03,0xe9,0x04,0x4c,0x02,0x06,0x01,0x8f,0x00,0x00,0xff,0xff,0x00,0x31,0xfe,0x4b,0x05,0xbb,0x05,0xb0,0x02,0x26,0x01,0xc7,0x00,0x00,0x00,0x07,0x03,0xe2,0x04,0x49,0x00,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x04,0xc0,0x04,0x3a,0x02,0x26, +0x01,0xe7,0x00,0x00,0x00,0x07,0x03,0xe2,0x03,0x4e,0x00,0x00,0xff,0xff,0x00,0x2b,0xfe,0x85,0x04,0xe3,0x05,0xb0,0x02,0x26,0x00,0x24,0x00,0x00,0x00,0x07,0x01,0x5a,0x01,0x1f,0x00,0x00,0xff,0xff,0x00,0x6a,0xfe,0x85,0x03,0xf3,0x04,0x4e,0x02,0x26,0x00,0x44,0x00,0x00,0x00,0x07,0x01,0x5a,0x00,0x9c,0x00,0x00,0xff,0xff,0x00,0xaa, +0x00,0x00,0x06,0x48,0x07,0x47,0x02,0x26,0x00,0x30,0x00,0x00,0x01,0x07,0x00,0x76,0x02,0x9d,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x06,0x6f,0x06,0x05,0x02,0x26,0x00,0x50,0x00,0x00,0x01,0x07,0x00,0x76,0x02,0xb7,0x00,0x17,0x00,0x08,0xb1,0x01,0x01,0xb0,0x17,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x25,0x00,0x00,0x06,0xbf,0x07,0x4b,0x02,0x26,0x00,0x3a,0x00,0x00,0x01,0x07,0x00,0x43,0x01,0xda,0x01,0x5d,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2d,0x00,0x00,0x05,0xdc,0x05,0xf4,0x02,0x26,0x00,0x5a,0x00,0x00,0x01,0x07,0x00,0x43,0x01,0x6e,0x00,0x06, +0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x25,0x00,0x00,0x06,0xbf,0x07,0x47,0x02,0x26,0x00,0x3a,0x00,0x00,0x01,0x07,0x00,0x76,0x02,0x94,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2d,0x00,0x00,0x05,0xdc,0x05,0xf0,0x02,0x26,0x00,0x5a,0x00,0x00, +0x01,0x07,0x00,0x76,0x02,0x28,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x25,0x00,0x00,0x06,0xbf,0x07,0x0d,0x02,0x26,0x00,0x3a,0x00,0x00,0x01,0x07,0x00,0x6a,0x01,0x6f,0x01,0x5d,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x2d,0x00,0x00,0x05,0xdc, +0x05,0xb6,0x02,0x26,0x00,0x5a,0x00,0x00,0x01,0x07,0x00,0x6a,0x01,0x03,0x00,0x06,0x00,0x08,0xb1,0x01,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x2b,0xfe,0xaf,0x04,0xe3,0x05,0xb0,0x02,0x26,0x00,0x24,0x00,0x00,0x00,0x07,0x01,0x60,0x04,0xd5,0x00,0x00,0xff,0xff,0x00,0x6a,0xfe,0xaf,0x03,0xf3,0x04,0x4e,0x02,0x26, +0x00,0x44,0x00,0x00,0x00,0x07,0x01,0x60,0x04,0x52,0x00,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0xc8,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0xd7,0x01,0x52,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x52,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x86,0x02,0x26,0x00,0x44,0x00,0x00, +0x01,0x07,0x01,0x5e,0x04,0x7a,0x00,0x10,0x00,0x08,0xb1,0x02,0x01,0xb0,0x10,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x05,0x0b,0x07,0xf1,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0x70,0x00,0x9a,0x01,0x59,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x04,0xae, +0x06,0xaf,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x03,0x70,0x3d,0x17,0x00,0x08,0xb1,0x02,0x02,0xb0,0x17,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xe3,0x07,0xe0,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0x6f,0x00,0xab,0x01,0x48,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x48,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xa3, +0xff,0xeb,0x03,0xf3,0x06,0x9e,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x03,0x6f,0x4e,0x06,0x00,0x08,0xb1,0x02,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x08,0x05,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0x6e,0x00,0xa3,0x01,0x34,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x34,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x6a,0xff,0xeb,0x04,0x77,0x06,0xc4,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x03,0x6e,0x46,0xf3,0x00,0x09,0xb1,0x02,0x02,0xb8,0xff,0xf3,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x08,0x32,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0x6d,0x00,0xa7,0x01,0x36,0x00,0x09,0xb1,0x02, +0x02,0xb8,0x01,0x36,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0xf1,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x03,0x6d,0x4a,0xf5,0x00,0x09,0xb1,0x02,0x02,0xb8,0xff,0xf5,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x2b,0xfe,0xaf,0x04,0xe3,0x07,0x48,0x02,0x26,0x00,0x24,0x00,0x00,0x00,0x27,0x01,0x52, +0x00,0xab,0x01,0x5d,0x01,0x07,0x01,0x60,0x04,0xd5,0x00,0x00,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xfe,0xaf,0x03,0xf3,0x06,0x06,0x02,0x26,0x00,0x44,0x00,0x00,0x00,0x26,0x01,0x52,0x4e,0x1b,0x01,0x07,0x01,0x60,0x04,0x52,0x00,0x00,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b, +0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x07,0xdf,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0xbf,0x00,0xd2,0x01,0x54,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x54,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0x9d,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x03,0xbf,0x75,0x12,0x00,0x08,0xb1,0x02,0x02,0xb0, +0x12,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x08,0x22,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0x72,0x00,0xd6,0x01,0x7a,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x7a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0xe0,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x03,0x72,0x79,0x38,0x00,0x08, +0xb1,0x02,0x02,0xb0,0x38,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x08,0x73,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0xde,0x00,0xd6,0x01,0x49,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x49,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x07,0x31,0x02,0x26,0x00,0x44,0x00,0x00,0x01,0x06,0x03,0xde, +0x79,0x07,0x00,0x08,0xb1,0x02,0x02,0xb0,0x07,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0x00,0x00,0x04,0xe3,0x08,0x25,0x02,0x26,0x00,0x24,0x00,0x00,0x01,0x07,0x03,0xdf,0x00,0xd6,0x01,0x51,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x51,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0xff,0xeb,0x03,0xf3,0x06,0xe3,0x02,0x26,0x00,0x44,0x00,0x00, +0x01,0x06,0x03,0xdf,0x79,0x0f,0x00,0x08,0xb1,0x02,0x02,0xb0,0x0f,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x2b,0xfe,0xaf,0x04,0xe3,0x07,0x4e,0x02,0x26,0x00,0x24,0x00,0x00,0x00,0x27,0x01,0x54,0x00,0xdc,0x01,0x9e,0x01,0x07,0x01,0x60,0x04,0xd5,0x00,0x00,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x9e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a, +0xfe,0xaf,0x03,0xf3,0x06,0x0c,0x02,0x26,0x00,0x44,0x00,0x00,0x00,0x26,0x01,0x54,0x7f,0x5c,0x01,0x07,0x01,0x60,0x04,0x52,0x00,0x00,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xaa,0xfe,0xb9,0x04,0x2b,0x05,0xb0,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x60,0x04,0xc2,0x00,0x0a,0x00,0x08,0xb1,0x01, +0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x61,0xfe,0xaf,0x03,0xe2,0x04,0x4e,0x02,0x26,0x00,0x48,0x00,0x00,0x00,0x07,0x01,0x60,0x04,0x92,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0xc8,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0xba,0x01,0x52,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x52, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x87,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0x6a,0x00,0x11,0x00,0x08,0xb1,0x02,0x01,0xb0,0x11,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0x2b,0x07,0x54,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0x89,0x01,0x61, +0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x61,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0x13,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x01,0x58,0x39,0x20,0x00,0x08,0xb1,0x02,0x01,0xb0,0x20,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xee,0x07,0xf1,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x03,0x70, +0x00,0x7d,0x01,0x59,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x9e,0x06,0xb0,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x03,0x70,0x2d,0x18,0x00,0x08,0xb1,0x02,0x02,0xb0,0x18,0xb0,0x0d,0x2b,0xff,0xff,0xff,0xe3,0x00,0x00,0x04,0x2b,0x07,0xe0,0x02,0x26,0x00,0x28,0x00,0x00, +0x01,0x07,0x03,0x6f,0x00,0x8e,0x01,0x48,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x48,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0x93,0xff,0xeb,0x03,0xe2,0x06,0x9f,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x03,0x6f,0x3e,0x07,0x00,0x08,0xb1,0x02,0x02,0xb0,0x07,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xaa,0x00,0x00,0x04,0xb7,0x08,0x05,0x02,0x26, +0x00,0x28,0x00,0x00,0x01,0x07,0x03,0x6e,0x00,0x86,0x01,0x34,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x34,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x67,0x06,0xc5,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x03,0x6e,0x36,0xf4,0x00,0x09,0xb1,0x02,0x02,0xb8,0xff,0xf4,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0xaa, +0x00,0x00,0x04,0x2b,0x08,0x32,0x02,0x26,0x00,0x28,0x00,0x00,0x01,0x07,0x03,0x6d,0x00,0x8a,0x01,0x36,0x00,0x09,0xb1,0x01,0x02,0xb8,0x01,0x36,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x03,0xe2,0x06,0xf2,0x02,0x26,0x00,0x48,0x00,0x00,0x01,0x06,0x03,0x6d,0x3a,0xf6,0x00,0x09,0xb1,0x02,0x02,0xb8,0xff,0xf6,0xb0,0x0d, +0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0xaa,0xfe,0xb9,0x04,0x2b,0x07,0x48,0x02,0x26,0x00,0x28,0x00,0x00,0x00,0x27,0x01,0x52,0x00,0x8e,0x01,0x5d,0x01,0x07,0x01,0x60,0x04,0xc2,0x00,0x0a,0x00,0x11,0xb1,0x01,0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0xb1,0x02,0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xfe,0xaf,0x03,0xe2, +0x06,0x07,0x02,0x26,0x00,0x48,0x00,0x00,0x00,0x26,0x01,0x52,0x3e,0x1c,0x01,0x07,0x01,0x60,0x04,0x92,0x00,0x00,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1c,0xb0,0x0d,0x2b,0xff,0xff,0x00,0xbe,0x00,0x00,0x02,0x03,0x07,0xc8,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x01,0x5e,0x03,0x70,0x01,0x52,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x52, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x01,0xde,0x06,0x72,0x02,0x26,0x00,0xf3,0x00,0x00,0x01,0x07,0x01,0x5e,0x03,0x4b,0xff,0xfc,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xfc,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0xb4,0xfe,0xb8,0x01,0x8e,0x05,0xb0,0x02,0x26,0x00,0x2c,0x00,0x00,0x01,0x07,0x01,0x60,0x03,0x78,0x00,0x09, +0x00,0x08,0xb1,0x01,0x01,0xb0,0x09,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x95,0xfe,0xb9,0x01,0x6f,0x06,0x18,0x02,0x26,0x00,0x4c,0x00,0x00,0x01,0x07,0x01,0x60,0x03,0x59,0x00,0x0a,0x00,0x08,0xb1,0x02,0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x71,0xfe,0xa7,0x05,0x02,0x05,0xc5,0x02,0x26,0x00,0x32,0x00,0x00, +0x01,0x07,0x01,0x60,0x05,0x11,0xff,0xf8,0x00,0x09,0xb1,0x02,0x01,0xb8,0xff,0xf8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xfe,0xa6,0x04,0x2a,0x04,0x4e,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x07,0x01,0x60,0x04,0x9d,0xff,0xf7,0x00,0x09,0xb1,0x02,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02, +0x07,0xdd,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x01,0x5e,0x05,0x09,0x01,0x67,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x67,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0x86,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0x95,0x00,0x10,0x00,0x08,0xb1,0x02,0x01,0xb0,0x10,0xb0,0x0d,0x2b,0x00,0x00, +0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x3d,0x08,0x06,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x03,0x70,0x00,0xcc,0x01,0x6e,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x6e,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0xc9,0x06,0xaf,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x03,0x70,0x58,0x17,0x00,0x08,0xb1,0x02,0x02,0xb0, +0x17,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x32,0xff,0xeb,0x05,0x02,0x07,0xf5,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x03,0x6f,0x00,0xdd,0x01,0x5d,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xbe,0xff,0xeb,0x04,0x2a,0x06,0x9e,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x03,0x6f,0x69,0x06,0x00,0x08, +0xb1,0x02,0x02,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x06,0x08,0x1a,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x03,0x6e,0x00,0xd5,0x01,0x49,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x49,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x92,0x06,0xc4,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x03,0x6e, +0x61,0xf3,0x00,0x09,0xb1,0x02,0x02,0xb8,0xff,0xf3,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xeb,0x05,0x02,0x08,0x47,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x03,0x6d,0x00,0xd9,0x01,0x4b,0x00,0x09,0xb1,0x02,0x02,0xb8,0x01,0x4b,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0x2a,0x06,0xf1,0x02,0x26, +0x00,0x52,0x00,0x00,0x01,0x06,0x03,0x6d,0x65,0xf5,0x00,0x09,0xb1,0x02,0x02,0xb8,0xff,0xf5,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x71,0xfe,0xa7,0x05,0x02,0x07,0x5d,0x02,0x26,0x00,0x32,0x00,0x00,0x00,0x27,0x01,0x52,0x00,0xdd,0x01,0x72,0x01,0x07,0x01,0x60,0x05,0x11,0xff,0xf8,0x00,0x12,0xb1,0x02,0x01,0xb8,0x01,0x72, +0xb0,0x0d,0x2b,0xb1,0x03,0x01,0xb8,0xff,0xf8,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x61,0xfe,0xa6,0x04,0x2a,0x06,0x06,0x02,0x26,0x00,0x52,0x00,0x00,0x00,0x26,0x01,0x52,0x69,0x1b,0x01,0x07,0x01,0x60,0x04,0x9d,0xff,0xf7,0x00,0x11,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xb1,0x03,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00,0x00,0x00, +0xff,0xff,0x00,0x6c,0xff,0xeb,0x05,0xff,0x07,0x35,0x02,0x26,0x01,0x43,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xe0,0x01,0x47,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x47,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0xe8,0x06,0x05,0x02,0x26,0x01,0x44,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x69,0x00,0x17,0x00,0x08,0xb1,0x02, +0x01,0xb0,0x17,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x6c,0xff,0xeb,0x05,0xff,0x07,0x39,0x02,0x26,0x01,0x43,0x00,0x00,0x01,0x07,0x00,0x43,0x01,0x26,0x01,0x4b,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x4b,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0xe8,0x06,0x09,0x02,0x26,0x01,0x44,0x00,0x00,0x01,0x07,0x00,0x43, +0x00,0xaf,0x00,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x6c,0xff,0xeb,0x05,0xff,0x07,0xb6,0x02,0x26,0x01,0x43,0x00,0x00,0x01,0x07,0x01,0x5e,0x05,0x0c,0x01,0x40,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x40,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61,0xff,0xeb,0x04,0xe8,0x06,0x86,0x02,0x26, +0x01,0x44,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0x95,0x00,0x10,0x00,0x08,0xb1,0x02,0x01,0xb0,0x10,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x6c,0xff,0xeb,0x05,0xff,0x07,0x42,0x02,0x26,0x01,0x43,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0xdb,0x01,0x4f,0x00,0x09,0xb1,0x02,0x01,0xb8,0x01,0x4f,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x61, +0xff,0xeb,0x04,0x2a,0x06,0x12,0x02,0x26,0x00,0x52,0x00,0x00,0x01,0x06,0x01,0x58,0x64,0x1f,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1f,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x6c,0xfe,0xaf,0x05,0xff,0x06,0x75,0x02,0x26,0x01,0x43,0x00,0x00,0x00,0x07,0x01,0x60,0x05,0x0b,0x00,0x00,0xff,0xff,0x00,0x61,0xfe,0xa6,0x04,0xe8,0x04,0xc7,0x02,0x26, +0x01,0x44,0x00,0x00,0x01,0x07,0x01,0x60,0x04,0x9d,0xff,0xf7,0x00,0x09,0xb1,0x02,0x01,0xb8,0xff,0xf7,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x93,0xfe,0xa7,0x04,0xdc,0x05,0xb0,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x01,0x60,0x05,0x0f,0xff,0xf8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b, +0xfe,0xaf,0x03,0xfc,0x04,0x3a,0x02,0x26,0x00,0x58,0x00,0x00,0x00,0x07,0x01,0x60,0x04,0x59,0x00,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x04,0xdc,0x07,0xc8,0x02,0x26,0x00,0x38,0x00,0x00,0x01,0x07,0x01,0x5e,0x05,0x08,0x01,0x52,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x52,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x03,0xfc, +0x06,0x72,0x02,0x26,0x00,0x58,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0x93,0xff,0xfc,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xfc,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x06,0x57,0x07,0x47,0x02,0x26,0x01,0x45,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0xdb,0x01,0x59,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x59,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x8b,0xff,0xeb,0x05,0x6a,0x05,0xf0,0x02,0x26,0x01,0x46,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x67,0x00,0x02,0x00,0x08,0xb1,0x01,0x01,0xb0,0x02,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x06,0x57,0x07,0x4b,0x02,0x26,0x01,0x45,0x00,0x00,0x01,0x07,0x00,0x43,0x01,0x21,0x01,0x5d,0x00,0x09,0xb1,0x01, +0x01,0xb8,0x01,0x5d,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x05,0x6a,0x05,0xf4,0x02,0x26,0x01,0x46,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xad,0x00,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x06,0x57,0x07,0xc8,0x02,0x26,0x01,0x45,0x00,0x00,0x01,0x07,0x01,0x5e, +0x05,0x07,0x01,0x52,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x52,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x05,0x6a,0x06,0x72,0x02,0x26,0x01,0x46,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0x93,0xff,0xfc,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xfc,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x93,0xff,0xeb,0x06,0x57,0x07,0x54,0x02,0x26, +0x01,0x45,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0xd6,0x01,0x61,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x61,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xff,0xeb,0x05,0x6a,0x05,0xfd,0x02,0x26,0x01,0x46,0x00,0x00,0x01,0x06,0x01,0x58,0x62,0x0a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x93,0xfe,0xa7,0x06,0x57, +0x06,0x37,0x02,0x26,0x01,0x45,0x00,0x00,0x01,0x07,0x01,0x60,0x05,0x0f,0xff,0xf8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x8b,0xfe,0xaf,0x05,0x6a,0x04,0xcb,0x02,0x26,0x01,0x46,0x00,0x00,0x00,0x07,0x01,0x60,0x04,0x59,0x00,0x00,0xff,0xff,0x00,0x28,0x00,0x00,0x04,0xe2,0x07,0x4a,0x02,0x26, +0x00,0x3c,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xef,0x01,0x5c,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x5c,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x05,0xf4,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x06,0x00,0x43,0x6b,0x06,0x00,0x08,0xb1,0x01,0x01,0xb0,0x06,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x28,0xfe,0xb9,0x04,0xe2, +0x05,0xb0,0x02,0x26,0x00,0x3c,0x00,0x00,0x01,0x07,0x01,0x60,0x04,0xdd,0x00,0x0a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x1a,0xfe,0x12,0x03,0xe8,0x04,0x3a,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x07,0x01,0x60,0x05,0x24,0xff,0x63,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0x63,0xb0,0x0d,0x2b,0x00, +0xff,0xff,0x00,0x28,0x00,0x00,0x04,0xe2,0x07,0xc7,0x02,0x26,0x00,0x3c,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0xd5,0x01,0x51,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x51,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x06,0x72,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x07,0x01,0x5e,0x04,0x51,0xff,0xfc,0x00,0x09,0xb1,0x01, +0x01,0xb8,0xff,0xfc,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x28,0x00,0x00,0x04,0xe2,0x07,0x53,0x02,0x26,0x00,0x3c,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0xa4,0x01,0x60,0x00,0x09,0xb1,0x01,0x01,0xb8,0x01,0x60,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x1a,0xfe,0x4b,0x03,0xe8,0x05,0xfd,0x02,0x26,0x00,0x5c,0x00,0x00,0x01,0x06,0x01,0x58, +0x20,0x0a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x0a,0xb0,0x0d,0x2b,0xff,0xff,0xff,0x25,0xff,0xeb,0x05,0x02,0x06,0x93,0x02,0x26,0x00,0x32,0x00,0x00,0x01,0x07,0x03,0xfb,0xfe,0xbd,0x00,0xce,0x00,0x08,0xb1,0x02,0x02,0xb0,0xce,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0xb3,0x02,0x88,0x04,0xf0,0x03,0x23,0x00,0x46,0x03,0x5a,0xd9,0x00, +0x53,0x33,0x40,0x00,0xff,0xff,0x00,0xbb,0x02,0x88,0x05,0xf3,0x03,0x23,0x00,0x46,0x03,0x5a,0xaf,0x00,0x66,0x66,0x40,0x00,0xff,0xff,0x00,0xbb,0x02,0x88,0x05,0xf3,0x03,0x23,0x00,0x46,0x03,0x5a,0xaf,0x00,0x66,0x66,0x40,0x00,0xff,0xff,0x00,0x05,0xfe,0x67,0x03,0xa0,0x00,0x00,0x00,0x27,0x00,0x42,0x00,0x01,0xff,0x01,0x01,0x06, +0x00,0x42,0x01,0x00,0x00,0x09,0xb1,0x00,0x01,0xb8,0xff,0x01,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x91,0x03,0x95,0x01,0x57,0x05,0xb0,0x00,0x05,0x00,0x27,0x40,0x06,0x05,0x04,0x02,0x01,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x00,0x01,0x01,0x00,0x01,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x07,0x01, +0x17,0x03,0xb0,0x2f,0x2b,0x1b,0x01,0x33,0x03,0x15,0x23,0x91,0x65,0x61,0x01,0xc5,0x04,0x4d,0x01,0x63,0xfe,0x97,0xb2,0x00,0x00,0x01,0x00,0xa0,0x03,0x95,0x01,0x66,0x05,0xb0,0x00,0x05,0x00,0x27,0x40,0x06,0x05,0x04,0x02,0x01,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x14,0x00,0x01,0x00,0x01,0x01,0x15,0x00,0x00,0x00,0x01, +0x00,0x00,0x1b,0x00,0x01,0x01,0x07,0x00,0x17,0x03,0xb0,0x2f,0x2b,0x01,0x03,0x23,0x13,0x35,0x33,0x01,0x66,0x65,0x61,0x01,0xc5,0x04,0xef,0xfe,0xa6,0x01,0x57,0xc4,0x00,0x01,0x00,0xa8,0xff,0x01,0x01,0x6e,0x00,0xf9,0x00,0x05,0x00,0x30,0x40,0x06,0x05,0x04,0x02,0x01,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1d,0x00,0x01, +0x00,0x01,0x01,0x15,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b,0x25,0x03,0x23,0x13,0x35,0x33,0x01,0x6e,0x65,0x61,0x01,0xc5,0x1a,0xfe,0xe7,0x01,0x07,0xf1,0xff,0xff,0x00,0x55,0x03,0x95,0x01,0x1b,0x05,0xb0,0x00,0x47,0x03,0x35,0x01,0xbb, +0x00,0x00,0xc0,0x01,0x40,0x00,0x00,0x00,0xff,0xff,0x00,0x7b,0x03,0x95,0x02,0x89,0x05,0xb0,0x00,0x26,0x03,0x34,0xea,0x00,0x00,0x07,0x03,0x34,0x01,0x32,0x00,0x00,0xff,0xff,0x00,0x7d,0x03,0x95,0x02,0x93,0x05,0xb0,0x00,0x26,0x03,0x35,0xdd,0x00,0x00,0x07,0x03,0x35,0x01,0x2d,0x00,0x00,0x00,0x02,0x00,0x8a,0xff,0x11,0x02,0x84, +0x01,0x18,0x00,0x05,0x00,0x0b,0x00,0x38,0x40,0x0a,0x0b,0x0a,0x08,0x07,0x05,0x04,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x21,0x06,0x00,0x02,0x00,0x01,0x01,0x15,0x03,0x01,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x03,0x01,0x01,0x01,0x00,0x00,0x00,0x1b,0x02,0x01,0x00,0x01,0x00,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b, +0x25,0x03,0x23,0x13,0x35,0x33,0x05,0x03,0x23,0x13,0x35,0x33,0x01,0x50,0x65,0x61,0x01,0xc5,0x01,0x34,0x65,0x61,0x01,0xc5,0x60,0xfe,0xb1,0x01,0x45,0xc2,0xb8,0xfe,0xb1,0x01,0x4d,0xba,0x00,0x01,0x00,0x46,0x00,0x00,0x04,0x24,0x05,0xb0,0x00,0x0b,0x00,0x35,0x40,0x0e,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00, +0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1a,0x00,0x04,0x04,0x07,0x16,0x02,0x01,0x00,0x00,0x03,0x00,0x00,0x1b,0x05,0x01,0x03,0x03,0x0a,0x16,0x00,0x01,0x01,0x08,0x01,0x17,0x04,0xb0,0x2f,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x33,0x11,0x21,0x04,0x24,0xfe,0x71,0xc5,0xfe,0x76,0x01,0x8a,0xc5,0x01,0x8f,0x03, +0x9e,0xfc,0x62,0x03,0x9e,0x9c,0x01,0x76,0xfe,0x8a,0x00,0x00,0x00,0x01,0x00,0x57,0xfe,0x60,0x04,0x34,0x05,0xb0,0x00,0x13,0x00,0x4b,0x40,0x16,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x28,0x00,0x06,0x06,0x07,0x16,0x08, +0x01,0x04,0x04,0x05,0x00,0x00,0x1b,0x07,0x01,0x05,0x05,0x0a,0x16,0x09,0x01,0x03,0x03,0x00,0x00,0x00,0x1b,0x02,0x01,0x00,0x00,0x08,0x16,0x00,0x01,0x01,0x0c,0x01,0x17,0x06,0xb0,0x2f,0x2b,0x29,0x01,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x21,0x35,0x21,0x11,0x33,0x11,0x21,0x15,0x21,0x11,0x21,0x04,0x34,0xfe,0x71,0xc5,0xfe,0x77, +0x01,0x89,0xfe,0x77,0x01,0x89,0xc5,0x01,0x8f,0xfe,0x71,0x01,0x8f,0xfe,0x60,0x01,0xa0,0x9a,0x03,0x04,0x9c,0x01,0x76,0xfe,0x8a,0x9c,0xfc,0xfc,0x00,0x01,0x00,0x89,0x02,0x17,0x02,0x27,0x03,0xe1,0x00,0x0d,0x00,0x2a,0x40,0x06,0x0b,0x09,0x04,0x02,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x17,0x00,0x00,0x01,0x01,0x00,0x01, +0x00,0x1a,0x00,0x00,0x00,0x01,0x01,0x00,0x1b,0x00,0x01,0x00,0x01,0x01,0x00,0x18,0x03,0xb0,0x2f,0x2b,0x13,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26,0x35,0x89,0x70,0x5e,0x5f,0x71,0x70,0x5f,0x5f,0x70,0x03,0x19,0x58,0x70,0x70,0x58,0x3c,0x59,0x6d,0x6e,0x58,0x00,0x00,0xff,0xff,0x00,0xa1,0x00,0x00,0x03,0x21, +0x00,0xca,0x00,0x26,0x00,0x11,0x00,0x00,0x00,0x07,0x00,0x11,0x01,0xbb,0x00,0x00,0xff,0xff,0x00,0xa1,0x00,0x00,0x04,0xc5,0x00,0xca,0x00,0x26,0x00,0x11,0x00,0x00,0x00,0x27,0x00,0x11,0x01,0xbb,0x00,0x00,0x00,0x07,0x00,0x11,0x03,0x5f,0x00,0x00,0x00,0x06,0x00,0x40,0xff,0xeb,0x07,0x55,0x05,0xc5,0x00,0x19,0x00,0x27,0x00,0x35, +0x00,0x43,0x00,0x51,0x00,0x55,0x00,0x6d,0x40,0x1a,0x4f,0x4d,0x48,0x46,0x41,0x3f,0x3a,0x38,0x33,0x31,0x2c,0x2a,0x25,0x23,0x1e,0x1c,0x17,0x15,0x11,0x0f,0x0a,0x08,0x04,0x02,0x0c,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x46,0x55,0x54,0x02,0x0a,0x0b,0x06,0x01,0x07,0x00,0x53,0x52,0x02,0x06,0x07,0x13,0x01,0x02,0x06,0x04,0x15, +0x00,0x0a,0x00,0x05,0x00,0x0a,0x05,0x01,0x00,0x1d,0x01,0x01,0x00,0x09,0x01,0x07,0x06,0x00,0x07,0x01,0x00,0x1d,0x00,0x0b,0x0b,0x04,0x01,0x00,0x1b,0x00,0x04,0x04,0x0d,0x16,0x08,0x01,0x06,0x06,0x02,0x01,0x00,0x1b,0x03,0x01,0x02,0x02,0x0e,0x02,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x34,0x36,0x33,0x32,0x16,0x17,0x3e,0x01,0x33,0x32, +0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26,0x27,0x0e,0x01,0x23,0x22,0x26,0x35,0x01,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26,0x35,0x01,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x05,0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x01,0x14,0x16,0x33,0x32,0x36,0x3d, +0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x13,0x27,0x01,0x17,0x03,0x33,0xa4,0x88,0x4a,0x75,0x25,0x25,0x75,0x4a,0x89,0xa5,0xa4,0x88,0x4b,0x76,0x25,0x25,0x74,0x49,0x8a,0xa4,0xfd,0x0d,0xa4,0x88,0x8a,0xa4,0xa4,0x88,0x89,0xa5,0x03,0x85,0x51,0x4b,0x4a,0x50,0x52,0x4a,0x4a,0x50,0x01,0xc8,0x51,0x4b,0x49,0x50,0x51,0x4a,0x4a,0x50,0xfb, +0x45,0x51,0x4b,0x49,0x51,0x52,0x4a,0x4a,0x50,0xf8,0x6d,0x02,0xc7,0x6d,0x01,0x65,0x7e,0xae,0x3f,0x36,0x36,0x3f,0xad,0x7f,0x4e,0x80,0xac,0x3d,0x37,0x37,0x3d,0xac,0x80,0x03,0x81,0x7f,0xae,0xad,0x80,0x4d,0x7f,0xac,0xac,0x7f,0xfc,0xcc,0x4b,0x67,0x67,0x4b,0x4e,0x4a,0x68,0x68,0x4a,0x4e,0x4b,0x67,0x67,0x4b,0x4e,0x4a,0x68,0x68, +0x4a,0x02,0xe6,0x4a,0x67,0x66,0x4b,0x4d,0x4a,0x69,0x69,0x4a,0xfb,0xd6,0x43,0x04,0x72,0x43,0x00,0x00,0xff,0xff,0x00,0x7e,0x03,0xb7,0x01,0x44,0x05,0xb0,0x02,0x06,0x00,0x0a,0x00,0x00,0xff,0xff,0x00,0x7e,0x03,0xa8,0x02,0x79,0x05,0xb0,0x02,0x06,0x00,0x05,0x00,0x00,0x00,0x01,0x00,0x6c,0x00,0x98,0x02,0x27,0x03,0xb5,0x00,0x06, +0x00,0x32,0x40,0x06,0x06,0x05,0x02,0x01,0x02,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x1f,0x04,0x03,0x00,0x03,0x00,0x01,0x01,0x15,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x1a,0x00,0x01,0x01,0x00,0x00,0x00,0x1b,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x04,0xb0,0x2f,0x2b,0x01,0x13,0x23,0x01,0x35,0x01,0x33,0x01,0x28,0xff,0x94,0xfe, +0xd9,0x01,0x27,0x94,0x02,0x26,0xfe,0x72,0x01,0x85,0x13,0x01,0x85,0x00,0x00,0x00,0x00,0x01,0x00,0x5e,0x00,0xaa,0x02,0x13,0x03,0xa2,0x00,0x0d,0x00,0x46,0x40,0x0a,0x0d,0x0c,0x0b,0x0a,0x04,0x03,0x02,0x01,0x04,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x2f,0x08,0x07,0x06,0x00,0x04,0x02,0x01,0x01,0x15,0x00,0x01,0x00,0x02,0x00, +0x01,0x02,0x29,0x00,0x02,0x03,0x00,0x02,0x03,0x27,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x03,0x00,0x00,0x1b,0x00,0x03,0x00,0x03,0x00,0x00,0x18,0x06,0xb0,0x2f,0x2b,0x01,0x03,0x33,0x01,0x33,0x1f,0x01,0x07,0x17,0x0f,0x01,0x23,0x01,0x23,0x01,0x45,0xe7,0x94,0x01,0x16,0x05,0x01,0x05,0x02,0x02,0x05,0x01,0x04, +0xfe,0xe9,0x94,0x02,0x26,0x01,0x7c,0xfe,0x9b,0x09,0x05,0x09,0x09,0x06,0x07,0xfe,0x9a,0x00,0x00,0x00,0xff,0xff,0x00,0xab,0x00,0x00,0x03,0x8c,0x05,0xb0,0x00,0x26,0x00,0x04,0x00,0x00,0x00,0x07,0x00,0x04,0x02,0x1b,0x00,0x00,0x00,0x01,0x00,0x3b,0x00,0x6e,0x03,0x6f,0x05,0x23,0x00,0x03,0x00,0x07,0x40,0x02,0x00,0x07,0x2b,0x00, +0x00,0x37,0x27,0x01,0x17,0xa8,0x6d,0x02,0xc7,0x6d,0x6e,0x43,0x04,0x72,0x43,0x00,0x00,0x02,0x00,0x47,0x02,0x30,0x03,0x53,0x05,0xc5,0x00,0x0a,0x00,0x0f,0x00,0x76,0x40,0x0e,0x0c,0x0b,0x0a,0x09,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x30,0x58,0x40,0x25,0x0e,0x0d,0x02,0x00, +0x04,0x08,0x01,0x01,0x00,0x02,0x15,0x05,0x01,0x00,0x03,0x01,0x01,0x02,0x00,0x01,0x00,0x00,0x1d,0x00,0x02,0x02,0x04,0x00,0x00,0x1b,0x00,0x04,0x04,0x07,0x02,0x17,0x04,0x1b,0x40,0x2e,0x0e,0x0d,0x02,0x00,0x04,0x08,0x01,0x01,0x00,0x02,0x15,0x00,0x04,0x00,0x02,0x04,0x00,0x00,0x1a,0x05,0x01,0x00,0x03,0x01,0x01,0x02,0x00,0x01, +0x00,0x00,0x1d,0x00,0x04,0x04,0x02,0x00,0x00,0x1b,0x00,0x02,0x04,0x02,0x00,0x00,0x18,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x33,0x15,0x23,0x15,0x23,0x35,0x21,0x27,0x01,0x33,0x01,0x21,0x11,0x27,0x07,0x02,0xbe,0x95,0x95,0xac,0xfe,0x39,0x04,0x01,0xc6,0xb1,0xfe,0x47,0x01,0x0d,0x06,0x0d,0x03,0x69,0x81,0xb8,0xb8,0x60,0x02,0x7d,0xfd, +0xa4,0x01,0x79,0x01,0x1a,0x00,0x00,0x00,0x00,0x01,0x00,0x7a,0x02,0x8b,0x02,0xfa,0x05,0xba,0x00,0x13,0x00,0x74,0x40,0x10,0x00,0x00,0x00,0x13,0x00,0x13,0x12,0x11,0x0e,0x0c,0x09,0x08,0x05,0x03,0x06,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x21,0x58,0x40,0x29,0x01,0x01,0x02,0x00,0x10,0x01,0x01,0x02,0x02,0x15,0x00,0x02, +0x02,0x00,0x01,0x00,0x1b,0x05,0x04,0x02,0x00,0x00,0x07,0x16,0x03,0x01,0x01,0x01,0x00,0x01,0x00,0x1b,0x05,0x04,0x02,0x00,0x00,0x07,0x01,0x17,0x05,0x1b,0x40,0x26,0x01,0x01,0x02,0x04,0x10,0x01,0x01,0x02,0x02,0x15,0x00,0x02,0x02,0x00,0x01,0x00,0x1b,0x00,0x00,0x00,0x07,0x16,0x03,0x01,0x01,0x01,0x04,0x00,0x00,0x1b,0x05,0x01, +0x04,0x04,0x07,0x01,0x17,0x05,0x59,0xb0,0x2f,0x2b,0x01,0x17,0x3e,0x01,0x33,0x32,0x16,0x15,0x11,0x23,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x01,0x02,0x1f,0x24,0x6e,0x46,0x7a,0x87,0xb4,0x47,0x41,0x35,0x48,0x13,0xb4,0x05,0xab,0x78,0x40,0x47,0x97,0x9c,0xfe,0x04,0x01,0xdb,0x66,0x5b,0x36,0x2f,0xfd,0xc9,0x03,0x20, +0xff,0xff,0x00,0x11,0x00,0x00,0x04,0x3b,0x05,0xb0,0x02,0x26,0x00,0x29,0x00,0x00,0x01,0x07,0x03,0x80,0xff,0x7f,0xfe,0x7f,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0x7f,0xb0,0x0d,0x2b,0x00,0x00,0x01,0x00,0x46,0x00,0x00,0x04,0x57,0x05,0xc5,0x00,0x28,0x00,0x71,0x40,0x22,0x00,0x00,0x00,0x28,0x00,0x28,0x27,0x26,0x25,0x24,0x23,0x22, +0x1f,0x1d,0x1b,0x1a,0x17,0x15,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x08,0x07,0x06,0x05,0x04,0x03,0x0f,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x40,0x42,0x19,0x01,0x08,0x09,0x01,0x15,0x00,0x08,0x09,0x06,0x09,0x08,0x06,0x29,0x0a,0x01,0x06,0x0b,0x01,0x05,0x04,0x06,0x05,0x00,0x00,0x1d,0x0c,0x01,0x04,0x0e,0x0d,0x02,0x03,0x00, +0x04,0x03,0x00,0x00,0x1d,0x00,0x09,0x09,0x07,0x01,0x00,0x1b,0x00,0x07,0x07,0x0d,0x16,0x02,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x00,0x01,0x01,0x08,0x01,0x17,0x08,0xb0,0x2f,0x2b,0x01,0x0e,0x01,0x07,0x21,0x07,0x21,0x35,0x33,0x3e,0x01,0x37,0x23,0x35,0x33,0x27,0x23,0x35,0x33,0x27,0x34,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34, +0x26,0x23,0x22,0x06,0x15,0x17,0x21,0x15,0x21,0x17,0x21,0x15,0x01,0xb3,0x02,0x1e,0x1b,0x02,0xdf,0x01,0xfc,0x30,0x0a,0x2d,0x2f,0x04,0xaa,0xa5,0x06,0x9e,0x98,0x05,0xe0,0xbc,0xc8,0xdc,0x04,0x02,0xbe,0x7e,0x62,0x63,0x74,0x05,0x01,0xa6,0xfe,0x60,0x05,0x01,0x9b,0x01,0xb9,0x53,0x96,0x36,0x9a,0x9a,0x0c,0xad,0x66,0x9b,0x8f,0x9b, +0x92,0xcc,0xe9,0xd1,0xac,0x06,0x76,0x72,0x95,0x85,0x92,0x9b,0x8f,0x9b,0x00,0x00,0x00,0x03,0x00,0xa4,0xff,0xeb,0x06,0x10,0x05,0xb0,0x00,0x0a,0x00,0x13,0x00,0x2b,0x00,0xc9,0x40,0x22,0x14,0x14,0x00,0x00,0x14,0x2b,0x14,0x2b,0x2a,0x29,0x28,0x27,0x24,0x22,0x1d,0x1b,0x18,0x17,0x16,0x15,0x13,0x11,0x0d,0x0b,0x00,0x0a,0x00,0x09, +0x05,0x03,0x02,0x01,0x0e,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58,0x4b,0xb0,0x17,0x58,0x40,0x47,0x1f,0x01,0x07,0x02,0x20,0x01,0x00,0x07,0x02,0x15,0x0d,0x01,0x0b,0x01,0x04,0x01,0x0b,0x04,0x29,0x00,0x03,0x0c,0x01,0x02,0x07,0x03,0x02,0x01,0x00,0x1d,0x00,0x04,0x04,0x01,0x01,0x00,0x1b,0x00,0x01,0x01,0x07,0x16,0x09,0x01,0x06,0x06, +0x05,0x00,0x00,0x1b,0x0a,0x01,0x05,0x05,0x0a,0x16,0x00,0x07,0x07,0x00,0x01,0x02,0x1b,0x08,0x01,0x00,0x00,0x08,0x00,0x17,0x09,0x1b,0x40,0x4b,0x1f,0x01,0x07,0x02,0x20,0x01,0x00,0x07,0x02,0x15,0x0d,0x01,0x0b,0x01,0x04,0x01,0x0b,0x04,0x29,0x00,0x03,0x0c,0x01,0x02,0x07,0x03,0x02,0x01,0x00,0x1d,0x00,0x04,0x04,0x01,0x01,0x00, +0x1b,0x00,0x01,0x01,0x07,0x16,0x09,0x01,0x06,0x06,0x05,0x00,0x00,0x1b,0x0a,0x01,0x05,0x05,0x0a,0x16,0x00,0x00,0x00,0x08,0x16,0x00,0x07,0x07,0x08,0x01,0x02,0x1b,0x00,0x08,0x08,0x0e,0x08,0x17,0x0a,0x59,0xb0,0x2f,0x2b,0x01,0x11,0x23,0x11,0x21,0x32,0x04,0x15,0x14,0x04,0x23,0x27,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x25, +0x11,0x33,0x15,0x23,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x23,0x35,0x33,0x11,0x01,0x69,0xc5,0x01,0x62,0xe8,0x01,0x04,0xfe,0xfc,0xe8,0x9d,0x9d,0x93,0x93,0x93,0x93,0x9d,0x03,0xd0,0xcd,0xcd,0x3f,0x34,0x11,0x2a,0x0e,0x1b,0x16,0x56,0x2a,0x78,0x8e,0xac,0xac,0x02,0x34,0xfd,0xcc,0x05,0xb0, +0xf9,0xc5,0xc7,0xf7,0x9b,0xa7,0x7a,0x7b,0xaa,0x2a,0xfe,0xfb,0x92,0xfd,0x6f,0x4c,0x3e,0x09,0x05,0x87,0x12,0x17,0x91,0x9b,0x02,0x91,0x92,0x01,0x05,0x00,0x00,0x00,0xff,0xff,0x00,0x50,0xfe,0xeb,0x04,0xba,0x06,0x18,0x02,0x26,0x00,0x47,0x00,0x00,0x00,0x27,0x03,0x80,0x01,0xa7,0x02,0x47,0x01,0x06,0x00,0x42,0x4c,0x85,0x00,0x12, +0xb1,0x02,0x01,0xb8,0x02,0x47,0xb0,0x0d,0x2b,0xb1,0x03,0x01,0xb8,0xff,0x85,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x01,0x00,0x4f,0xff,0xeb,0x03,0xd5,0x05,0xc5,0x00,0x2a,0x00,0x6c,0x40,0x1a,0x2a,0x29,0x28,0x27,0x26,0x25,0x22,0x20,0x1b,0x19,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0d,0x0b,0x06,0x04,0x01,0x00,0x0c,0x07,0x2b,0x4b, +0xb0,0x90,0x50,0x58,0x40,0x45,0x1d,0x01,0x08,0x07,0x1e,0x01,0x06,0x08,0x08,0x02,0x02,0x01,0x00,0x09,0x01,0x02,0x01,0x04,0x15,0x09,0x01,0x06,0x0a,0x01,0x05,0x04,0x06,0x05,0x00,0x00,0x1d,0x0b,0x01,0x04,0x03,0x01,0x00,0x01,0x04,0x00,0x00,0x00,0x1d,0x00,0x08,0x08,0x07,0x01,0x00,0x1b,0x00,0x07,0x07,0x0d,0x16,0x00,0x01,0x01, +0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0e,0x02,0x17,0x07,0xb0,0x2f,0x2b,0x01,0x21,0x07,0x06,0x16,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x00,0x35,0x23,0x35,0x33,0x35,0x23,0x35,0x33,0x35,0x34,0x00,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x21,0x15,0x21,0x15,0x21,0x03,0x92,0xfe,0x1b,0x02,0x04,0xab, +0x93,0x39,0x70,0x34,0x13,0x38,0x7b,0x3d,0xe7,0xfe,0xe3,0x92,0x92,0x92,0x92,0x01,0x1b,0xe7,0x3b,0x75,0x42,0x13,0x36,0x71,0x38,0x92,0xab,0x01,0xec,0xfe,0x14,0x01,0xec,0x02,0x00,0x05,0xa9,0xcd,0x11,0x11,0x9d,0x0f,0x10,0x01,0x21,0xf4,0x7c,0xa6,0x7d,0x0f,0xf4,0x01,0x23,0x10,0x0f,0x9f,0x10,0x13,0xce,0xac,0x11,0x7d,0xa6,0x00, +0x00,0x04,0x00,0x7c,0xff,0xeb,0x05,0x83,0x05,0xc5,0x00,0x1d,0x00,0x2b,0x00,0x39,0x00,0x3d,0x00,0x0d,0x40,0x0a,0x3b,0x3d,0x2e,0x35,0x27,0x20,0x0a,0x03,0x04,0x0b,0x2b,0x01,0x17,0x16,0x06,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x35,0x01, +0x14,0x16,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x15,0x33,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26,0x35,0x13,0x27,0x01,0x17,0x02,0xa5,0x02,0x04,0x96,0x7e,0x81,0x9a,0x99,0x80,0x7e,0x98,0x04,0x02,0x8a,0x46,0x40,0x41,0x46,0x47,0x42,0x3f,0x45,0x01,0x0e,0xa5,0x8a,0x87,0xa4,0xa5,0x88,0x89,0xa4, +0x92,0x51,0x4a,0x49,0x52,0x50,0x49,0x4c,0x51,0xcb,0x6d,0xfd,0x39,0x6d,0x04,0x20,0x06,0x69,0x91,0xac,0x7f,0x4d,0x7f,0xae,0x94,0x67,0x06,0x39,0x4e,0x69,0x4a,0x4d,0x4a,0x67,0x50,0x36,0xfc,0xf7,0x80,0xac,0xac,0x80,0x4e,0x7f,0xad,0xad,0x7f,0x4a,0x68,0x68,0x4a,0x4e,0x4b,0x67,0x67,0x4b,0x03,0xc9,0x43,0xfb,0x8e,0x43,0x00,0x00, +0x00,0x02,0x00,0x6a,0xff,0xed,0x03,0x73,0x05,0xc5,0x00,0x1b,0x00,0x28,0x00,0x09,0x40,0x06,0x1f,0x25,0x0f,0x02,0x02,0x0b,0x2b,0x05,0x07,0x06,0x26,0x3d,0x01,0x0e,0x01,0x23,0x35,0x32,0x36,0x37,0x11,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x02,0x07,0x15,0x14,0x16,0x33,0x03,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x11,0x17,0x3e, +0x01,0x35,0x02,0xce,0x06,0xc7,0xcd,0x31,0x65,0x34,0x37,0x65,0x2e,0x9f,0x8b,0x7a,0x9b,0xcb,0xaf,0x60,0x75,0x20,0x2c,0x24,0x33,0x32,0x06,0x55,0x5a,0x0d,0x02,0x04,0xef,0xd3,0x0c,0x0c,0x0c,0xb4,0x0d,0x0d,0x01,0xd9,0xb1,0xca,0xac,0x90,0x2a,0x9e,0xfe,0xae,0x64,0x5c,0x91,0x92,0x03,0xd1,0x2c,0x4c,0x4e,0x6d,0x6c,0xfe,0x9b,0x01, +0x40,0xcc,0x6d,0x00,0xff,0xff,0x00,0xaa,0x00,0x00,0x08,0x4e,0x05,0xc1,0x00,0x22,0x00,0x31,0x00,0x00,0x00,0x23,0x00,0x7c,0x05,0x23,0xff,0xfc,0x01,0x03,0x00,0x10,0x05,0x20,0xff,0x15,0x00,0x12,0xb1,0x01,0x02,0xb8,0xff,0xfc,0xb0,0x0d,0x2b,0xb1,0x03,0x01,0xb8,0xff,0x15,0xb0,0x0d,0x2b,0x00,0x02,0x00,0x67,0x03,0x97,0x04,0x60, +0x05,0xb0,0x00,0x0f,0x00,0x17,0x00,0x09,0x40,0x06,0x16,0x12,0x08,0x02,0x02,0x0b,0x2b,0x01,0x27,0x03,0x23,0x03,0x07,0x11,0x23,0x11,0x33,0x13,0x33,0x13,0x33,0x11,0x23,0x01,0x23,0x11,0x23,0x11,0x23,0x35,0x21,0x04,0x03,0x06,0x96,0x33,0x9c,0x06,0x5d,0x74,0xa1,0x06,0xa2,0x6e,0x5d,0xfd,0xe4,0x91,0x5e,0x91,0x01,0x80,0x04,0xee, +0x02,0xfe,0xa7,0x01,0x67,0x02,0xfe,0x9b,0x02,0x19,0xfe,0x7a,0x01,0x86,0xfd,0xe7,0x01,0xc7,0xfe,0x39,0x01,0xc7,0x52,0x00,0x00,0x02,0x00,0x98,0xff,0xec,0x04,0x93,0x04,0x4e,0x00,0x15,0x00,0x1e,0x00,0x09,0x40,0x06,0x16,0x1a,0x08,0x02,0x02,0x0b,0x2b,0x25,0x0e,0x01,0x23,0x22,0x00,0x35,0x34,0x00,0x33,0x32,0x00,0x1d,0x01,0x21, +0x11,0x1e,0x01,0x33,0x32,0x36,0x37,0x01,0x22,0x06,0x07,0x11,0x21,0x11,0x2e,0x01,0x04,0x16,0x57,0xbc,0x5f,0xda,0xfe,0xce,0x01,0x43,0xc9,0xcf,0x01,0x20,0xfd,0x00,0x37,0x8d,0x4d,0x5f,0xba,0x57,0xfe,0x90,0x4a,0x8d,0x3a,0x02,0x1c,0x36,0x8b,0x5e,0x37,0x3b,0x01,0x49,0xe8,0xe2,0x01,0x4f,0xfe,0xca,0xe7,0x2f,0xfe,0xb8,0x35,0x39, +0x3c,0x3e,0x03,0x2a,0x41,0x39,0xfe,0xeb,0x01,0x1e,0x34,0x3d,0xff,0xff,0x00,0x6b,0xff,0xf5,0x06,0x52,0x05,0xb2,0x00,0x27,0x04,0x03,0x00,0x0c,0x02,0x86,0x00,0x27,0x03,0x46,0x01,0x06,0x00,0x00,0x01,0x07,0x03,0xfa,0x03,0x4b,0x00,0x00,0x00,0x09,0xb1,0x00,0x01,0xb8,0x02,0x86,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x6e, +0xff,0xf5,0x06,0xe9,0x05,0xc0,0x00,0x27,0x04,0x00,0x00,0x04,0x02,0x94,0x00,0x27,0x03,0x46,0x01,0xbf,0x00,0x00,0x01,0x07,0x03,0xfa,0x03,0xe2,0x00,0x00,0x00,0x09,0xb1,0x00,0x01,0xb8,0x02,0x94,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x6f,0xff,0xf5,0x07,0x19,0x05,0xaf,0x00,0x27,0x03,0xfe,0xff,0xfd,0x02,0x8e,0x00,0x27, +0x03,0x46,0x01,0xf7,0x00,0x00,0x01,0x07,0x03,0xfa,0x04,0x12,0x00,0x00,0x00,0x09,0xb1,0x00,0x01,0xb8,0x02,0x8e,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x6b,0xff,0xf5,0x06,0x72,0x05,0xaf,0x00,0x27,0x03,0xfc,0x00,0x0c,0x02,0x8e,0x00,0x27,0x03,0x46,0x01,0x36,0x00,0x00,0x01,0x07,0x03,0xfa,0x03,0x6b,0x00,0x00,0x00,0x09, +0xb1,0x00,0x01,0xb8,0x02,0x8e,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x00,0x02,0x00,0x48,0xff,0xeb,0x04,0x30,0x05,0xed,0x00,0x14,0x00,0x21,0x00,0x09,0x40,0x06,0x1b,0x15,0x00,0x06,0x02,0x0b,0x2b,0x01,0x04,0x00,0x11,0x15,0x14,0x00,0x23,0x22,0x00,0x35,0x34,0x12,0x33,0x32,0x16,0x17,0x37,0x2e,0x01,0x27,0x13,0x32,0x36,0x3d,0x01,0x2e, +0x01,0x23,0x22,0x06,0x15,0x14,0x16,0x01,0xe7,0x01,0x07,0x01,0x42,0xfe,0xe0,0xd7,0xda,0xfe,0xe9,0xfa,0xda,0x5f,0xa8,0x36,0x03,0x16,0xeb,0xb0,0x92,0x85,0xa9,0x24,0xac,0x7f,0x88,0x87,0xa4,0x05,0xed,0x3f,0xfe,0x6c,0xfe,0xd9,0xdc,0xf5,0xfe,0xc9,0x01,0x18,0xcf,0xe9,0x01,0x17,0x3b,0x34,0x05,0xc1,0xec,0x34,0xfb,0x3c,0xe4,0xae, +0x81,0x43,0x5c,0xc9,0x9c,0x84,0xc9,0x00,0x00,0x01,0x00,0xa8,0xff,0x2d,0x04,0xf4,0x05,0xb0,0x00,0x07,0x00,0x07,0x40,0x04,0x06,0x00,0x01,0x0b,0x2b,0x05,0x23,0x11,0x21,0x11,0x23,0x11,0x21,0x04,0xf4,0xc5,0xfd,0x3e,0xc5,0x04,0x4c,0xd3,0x05,0xe8,0xfa,0x18,0x06,0x83,0x00,0x01,0x00,0x46,0xfe,0xf3,0x04,0xae,0x05,0xb0,0x00,0x0e, +0x00,0x07,0x40,0x04,0x09,0x04,0x01,0x0b,0x2b,0x09,0x01,0x17,0x21,0x15,0x21,0x35,0x09,0x01,0x35,0x21,0x15,0x21,0x07,0x01,0x03,0x65,0xfd,0xd2,0x02,0x03,0x75,0xfb,0x98,0x02,0x62,0xfd,0x9e,0x04,0x19,0xfc,0xd8,0x02,0x02,0x30,0x02,0x24,0xfd,0x6f,0x05,0x9b,0x92,0x02,0xc9,0x02,0xcf,0x93,0x9b,0x05,0xfd,0x67,0x00,0x01,0x00,0xa8, +0x02,0x88,0x03,0xeb,0x03,0x23,0x00,0x03,0x00,0x07,0x40,0x04,0x02,0x00,0x01,0x0b,0x2b,0x01,0x21,0x35,0x21,0x03,0xeb,0xfc,0xbd,0x03,0x43,0x02,0x88,0x9b,0x00,0x00,0x00,0x01,0x00,0x3f,0x00,0x00,0x04,0xad,0x05,0xb0,0x00,0x0b,0x00,0x07,0x40,0x04,0x04,0x06,0x01,0x0b,0x2b,0x01,0x17,0x33,0x37,0x01,0x33,0x01,0x23,0x03,0x23,0x35, +0x21,0x02,0x2a,0x12,0x06,0x13,0x01,0x8f,0xc9,0xfd,0xdb,0x95,0xf8,0xbc,0x01,0x48,0x01,0x54,0x53,0x53,0x04,0x5c,0xfa,0x50,0x02,0x74,0x9c,0x00,0x00,0x03,0x00,0x68,0xff,0xeb,0x07,0xbb,0x04,0x4e,0x00,0x19,0x00,0x27,0x00,0x35,0x00,0x0b,0x40,0x08,0x2a,0x31,0x23,0x1c,0x0f,0x02,0x03,0x0b,0x2b,0x01,0x14,0x02,0x23,0x22,0x26,0x27, +0x0e,0x01,0x23,0x22,0x02,0x3d,0x01,0x34,0x12,0x33,0x32,0x16,0x17,0x3e,0x01,0x33,0x32,0x12,0x15,0x05,0x14,0x16,0x33,0x32,0x12,0x37,0x35,0x26,0x02,0x23,0x22,0x06,0x15,0x21,0x34,0x26,0x23,0x22,0x02,0x07,0x15,0x16,0x12,0x33,0x32,0x36,0x35,0x07,0xbb,0xfa,0xcd,0xa5,0xee,0x50,0x50,0xef,0xa3,0xce,0xf9,0xf8,0xcd,0xa4,0xf0,0x51, +0x4f,0xf0,0xa5,0xcb,0xfa,0xf9,0x72,0x83,0x7f,0x89,0xd5,0x1b,0x1c,0xd5,0x8a,0x7e,0x82,0x05,0xc9,0x84,0x7c,0x8a,0xd4,0x1e,0x1d,0xd4,0x89,0x7e,0x84,0x01,0xfb,0xe1,0xfe,0xd1,0xd7,0x9c,0x9b,0xd8,0x01,0x2f,0xe1,0x42,0xe0,0x01,0x31,0xd8,0x9b,0x9a,0xd9,0xfe,0xce,0xdf,0x42,0xaa,0xcc,0x01,0x17,0x6c,0x2a,0x6a,0x01,0x17,0xcf,0xa7, +0xa7,0xcf,0xfe,0xeb,0x6c,0x2a,0x6e,0xfe,0xeb,0xcd,0xa9,0x00,0x00,0x01,0xff,0xbc,0xfe,0x4b,0x02,0x93,0x06,0x2d,0x00,0x1c,0x00,0x07,0x40,0x04,0x10,0x02,0x01,0x0b,0x2b,0x05,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x11,0x34,0x36,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x15,0x11,0x01,0x70, +0xac,0x99,0x1f,0x33,0x1d,0x0e,0x0e,0x41,0x12,0x3b,0x45,0xb6,0xa2,0x21,0x45,0x2a,0x18,0x14,0x2c,0x19,0x57,0x5b,0x59,0xa7,0xb5,0x09,0x09,0x96,0x05,0x08,0x67,0x5a,0x05,0x1c,0xad,0xbd,0x0b,0x0a,0x91,0x05,0x06,0x6d,0x62,0xfa,0xe4,0x00,0x00,0x00,0x00,0x02,0x00,0x65,0x01,0x10,0x04,0x14,0x04,0x00,0x00,0x19,0x00,0x33,0x00,0x09, +0x40,0x06,0x26,0x33,0x0c,0x19,0x02,0x0b,0x2b,0x13,0x3e,0x01,0x33,0x36,0x16,0x17,0x1e,0x01,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x26,0x27,0x2e,0x01,0x07,0x22,0x06,0x0f,0x01,0x3e,0x01,0x33,0x36,0x16,0x17,0x1e,0x01,0x33,0x32,0x36,0x37,0x17,0x0e,0x01,0x23,0x22,0x26,0x27,0x2e,0x01,0x07,0x22,0x06,0x07,0x6f,0x2f,0x7c, +0x41,0x45,0x40,0x65,0x56,0x42,0x42,0x40,0x7c,0x30,0x09,0x30,0x7c,0x40,0x42,0x42,0x56,0x65,0x40,0x45,0x41,0x7c,0x2f,0x13,0x2f,0x7c,0x41,0x45,0x40,0x65,0x59,0x40,0x41,0x40,0x7c,0x30,0x09,0x30,0x7c,0x40,0x42,0x42,0x56,0x69,0x3d,0x44,0x41,0x7c,0x2f,0x03,0x6a,0x44,0x4e,0x01,0x18,0x32,0x2c,0x19,0x4d,0x45,0xae,0x45,0x4d,0x19, +0x2c,0x32,0x18,0x01,0x4e,0x44,0xfd,0x44,0x4e,0x01,0x18,0x32,0x2e,0x18,0x4d,0x46,0xaf,0x45,0x4d,0x19,0x2c,0x34,0x17,0x01,0x4e,0x45,0x00,0x00,0x00,0x01,0x00,0x98,0x00,0xa7,0x03,0xda,0x04,0xe3,0x00,0x13,0x00,0x07,0x40,0x04,0x12,0x08,0x01,0x0b,0x2b,0x01,0x33,0x15,0x21,0x07,0x21,0x15,0x21,0x07,0x27,0x37,0x23,0x35,0x21,0x37, +0x21,0x35,0x21,0x13,0x17,0x03,0x19,0xc1,0xfe,0xe4,0x8c,0x01,0xa8,0xfd,0xfd,0x85,0x57,0x64,0xc7,0x01,0x22,0x8c,0xfe,0x52,0x02,0x09,0x93,0x57,0x03,0xdb,0xa4,0xfc,0xa4,0xf0,0x3c,0xb4,0xa4,0xfc,0xa4,0x01,0x08,0x3c,0x00,0x00,0xff,0xff,0x00,0x9e,0x00,0x06,0x03,0xe6,0x04,0x4b,0x00,0x67,0x00,0x1f,0x00,0x57,0x00,0xbc,0x40,0x00, +0x39,0x9a,0x01,0x07,0x03,0x5a,0xff,0xfb,0xfd,0x7e,0x00,0x11,0xb1,0x00,0x01,0xb0,0xbc,0xb0,0x0d,0x2b,0xb1,0x01,0x01,0xb8,0xfd,0x7e,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x9a,0x00,0x04,0x03,0xf2,0x04,0x4c,0x00,0x67,0x00,0x21,0x00,0x12,0x00,0xcf,0x40,0x00,0x39,0x9a,0x01,0x07,0x03,0x5a,0xff,0xfb,0xfd,0x7c,0x00,0x11, +0xb1,0x00,0x01,0xb0,0xcf,0xb0,0x0d,0x2b,0xb1,0x01,0x01,0xb8,0xfd,0x7c,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x00,0x02,0x00,0x29,0x00,0x00,0x03,0xdf,0x05,0xb0,0x00,0x05,0x00,0x0f,0x00,0x09,0x40,0x06,0x08,0x0d,0x00,0x03,0x02,0x0b,0x2b,0x01,0x33,0x09,0x01,0x23,0x01,0x21,0x01,0x27,0x23,0x07,0x03,0x01,0x17,0x33,0x37,0x01,0xb7,0x96, +0x01,0x92,0xfe,0x71,0x95,0xfe,0x6e,0x02,0xed,0xfe,0xff,0x11,0x06,0x12,0xfa,0x01,0x01,0x11,0x06,0x12,0x05,0xb0,0xfd,0x27,0xfd,0x29,0x02,0xd7,0x02,0x00,0x32,0x32,0xfe,0x00,0xfe,0x01,0x32,0x32,0x00,0x00,0x00,0x01,0x00,0x65,0xff,0x7a,0x01,0x40,0x00,0xf3,0x00,0x05,0x00,0x07,0x40,0x04,0x04,0x01,0x01,0x0b,0x2b,0x25,0x07,0x23, +0x37,0x35,0x33,0x01,0x40,0x7a,0x61,0x3d,0x9e,0x67,0xed,0xf6,0x83,0x00,0x00,0x00,0x00,0x02,0x00,0x1c,0x00,0x00,0x03,0xd5,0x06,0x2d,0x00,0x17,0x00,0x1b,0x00,0x53,0x40,0x18,0x00,0x00,0x1b,0x1a,0x19,0x18,0x00,0x17,0x00,0x17,0x16,0x15,0x14,0x13,0x10,0x0e,0x09,0x07,0x04,0x03,0x02,0x01,0x0a,0x07,0x2b,0x4b,0xb0,0x90,0x50,0x58, +0x40,0x2e,0x0b,0x01,0x03,0x02,0x0c,0x01,0x01,0x03,0x02,0x15,0x00,0x03,0x03,0x02,0x01,0x00,0x1b,0x00,0x02,0x02,0x0f,0x16,0x05,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x08,0x04,0x02,0x01,0x01,0x0a,0x16,0x07,0x09,0x02,0x06,0x06,0x08,0x06,0x17,0x06,0xb0,0x2f,0x2b,0x33,0x11,0x23,0x35,0x33,0x35,0x34,0x36,0x33,0x32,0x16,0x17,0x07, +0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x33,0x15,0x23,0x11,0x21,0x23,0x11,0x33,0xc6,0xaa,0xaa,0xd5,0xbd,0x43,0x82,0x58,0x22,0x35,0x78,0x3f,0x75,0x67,0xd7,0xd7,0x02,0x4a,0xc6,0xc6,0x03,0xa8,0x92,0x75,0xb6,0xc8,0x1f,0x1e,0xa0,0x15,0x1e,0x68,0x6c,0x75,0x92,0xfc,0x58,0x04,0x3a,0x00,0x00,0xff,0xff,0x00,0x38,0x00,0x00,0x04,0x06, +0x06,0x2d,0x00,0x26,0x00,0x49,0x00,0x00,0x00,0x07,0x00,0x4f,0x02,0xa2,0x00,0x00,0xff,0xff,0x00,0x38,0x00,0x00,0x06,0x77,0x06,0x2d,0x00,0x26,0x00,0x49,0x00,0x00,0x00,0x07,0x03,0x64,0x02,0xa2,0x00,0x00,0xff,0xff,0x00,0x38,0x00,0x00,0x06,0xa8,0x06,0x2d,0x00,0x26,0x00,0x49,0x00,0x00,0x00,0x27,0x00,0x49,0x02,0xa2,0x00,0x00, +0x00,0x07,0x00,0x4f,0x05,0x44,0x00,0x00,0x00,0x16,0x00,0x5b,0xfe,0x72,0x07,0xee,0x05,0xae,0x00,0x0d,0x00,0x1c,0x00,0x2a,0x00,0x3b,0x00,0x41,0x00,0x47,0x00,0x4d,0x00,0x53,0x00,0x5d,0x00,0x61,0x00,0x65,0x00,0x69,0x00,0x6d,0x00,0x71,0x00,0x75,0x00,0x7e,0x00,0x82,0x00,0x86,0x00,0x8a,0x00,0x8e,0x00,0x92,0x00,0x96,0x00,0x31, +0x40,0x2e,0x95,0x93,0x91,0x8f,0x8d,0x8b,0x89,0x87,0x85,0x83,0x81,0x7f,0x76,0x7c,0x73,0x72,0x6f,0x6e,0x6b,0x6a,0x67,0x66,0x63,0x62,0x5f,0x5e,0x54,0x5a,0x4f,0x51,0x49,0x48,0x45,0x42,0x3d,0x3c,0x3a,0x35,0x26,0x1f,0x19,0x0e,0x02,0x09,0x16,0x0b,0x2b,0x01,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x35,0x05, +0x32,0x36,0x35,0x34,0x26,0x27,0x3e,0x01,0x35,0x34,0x26,0x2b,0x01,0x11,0x27,0x14,0x06,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x33,0x32,0x16,0x15,0x05,0x14,0x06,0x23,0x22,0x26,0x35,0x23,0x07,0x06,0x16,0x33,0x32,0x36,0x35,0x11,0x23,0x01,0x11,0x33,0x15,0x33,0x15,0x21,0x35,0x33,0x35,0x33,0x11,0x01,0x11,0x21,0x15,0x23,0x15,0x25, +0x35,0x21,0x11,0x23,0x35,0x01,0x33,0x1e,0x01,0x15,0x14,0x06,0x2b,0x01,0x35,0x01,0x35,0x21,0x15,0x21,0x35,0x21,0x15,0x21,0x35,0x21,0x15,0x01,0x35,0x21,0x15,0x21,0x35,0x21,0x15,0x21,0x35,0x21,0x15,0x13,0x33,0x32,0x16,0x15,0x14,0x06,0x2b,0x01,0x05,0x23,0x35,0x33,0x35,0x23,0x35,0x33,0x11,0x23,0x35,0x33,0x25,0x23,0x35,0x33, +0x35,0x23,0x35,0x33,0x11,0x23,0x35,0x33,0x03,0x39,0x81,0x66,0x66,0x80,0x80,0x68,0x65,0x80,0x01,0x20,0x5c,0x69,0x36,0x30,0x28,0x2c,0x6f,0x65,0xbc,0x9f,0x4a,0x3f,0x42,0x4a,0x4a,0x40,0x40,0x4b,0x03,0xba,0x37,0x28,0x32,0x36,0x54,0x02,0x06,0x69,0x5b,0x51,0x6a,0x5c,0xf9,0xc4,0x71,0xc4,0x05,0x28,0xc7,0x6f,0xf8,0x6d,0x01,0x35, +0xc4,0x05,0xec,0x01,0x36,0x6f,0xfc,0xda,0x05,0x2f,0x33,0x35,0x32,0x7e,0x01,0x4e,0x01,0x16,0xfd,0x5b,0x01,0x15,0xfd,0x5c,0x01,0x14,0x02,0x0a,0x01,0x16,0xfd,0x5b,0x01,0x15,0xfd,0x5c,0x01,0x14,0xbc,0x5d,0x3d,0x39,0x3c,0x3a,0x5d,0xfc,0xf1,0x71,0x71,0x71,0x71,0x71,0x71,0x07,0x22,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x02,0x44,0x60, +0x7b,0x7b,0x60,0x70,0x62,0x79,0x79,0x62,0xd8,0x4f,0x4c,0x2d,0x46,0x0d,0x0f,0x3e,0x27,0x4b,0x4b,0xfd,0xdb,0xd8,0x45,0x4e,0x4e,0x45,0x70,0x44,0x4f,0x4f,0x44,0x9b,0x2c,0x36,0x2d,0x2e,0x06,0x4d,0x51,0x5c,0x4f,0x01,0x7a,0xfb,0x4f,0x01,0x3b,0xca,0x71,0x71,0xca,0xfe,0xc5,0x06,0x1f,0x01,0x1d,0x74,0xa9,0xa9,0x74,0xfe,0xe3,0xa9, +0xfc,0xb6,0x02,0x2e,0x26,0x28,0x2b,0xa9,0x03,0x4a,0x74,0x74,0x74,0x74,0x74,0x74,0xf9,0x38,0x71,0x71,0x71,0x71,0x71,0x71,0x04,0x5b,0x20,0x27,0x28,0x28,0x96,0xfc,0x7e,0xfa,0xfc,0x15,0xf9,0x7e,0xfc,0x7e,0xfa,0xfc,0x15,0xf9,0x00,0x05,0x00,0x5c,0xfd,0xd5,0x07,0xd7,0x08,0x62,0x00,0x03,0x00,0x1e,0x00,0x22,0x00,0x26,0x00,0x2a, +0x00,0x0f,0x40,0x0c,0x27,0x29,0x23,0x25,0x1f,0x21,0x0c,0x04,0x00,0x02,0x05,0x0b,0x2b,0x09,0x03,0x05,0x34,0x36,0x37,0x3e,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x1f,0x01,0x33,0x3e,0x01,0x33,0x32,0x16,0x15,0x14,0x06,0x07,0x0e,0x01,0x15,0x17,0x23,0x15,0x33,0x03,0x33,0x15,0x23,0x03,0x33,0x15,0x23,0x04,0x18,0x03,0xbf,0xfc,0x41, +0xfc,0x44,0x04,0x0f,0x1a,0x28,0x48,0x5e,0xa9,0x93,0x88,0xa7,0x03,0x03,0xc2,0x01,0x3b,0x2b,0x36,0x3b,0x33,0x2a,0x4f,0x3b,0xca,0xca,0xca,0x4b,0x04,0x04,0x02,0x04,0x04,0x06,0x52,0xfc,0x31,0xfc,0x31,0x03,0xcf,0xf1,0x35,0x3d,0x1a,0x27,0x83,0x4e,0x80,0x97,0x82,0x82,0x06,0x33,0x34,0x3f,0x35,0x32,0x4d,0x1c,0x37,0x5a,0x58,0x5b, +0xaa,0xfd,0x4c,0x04,0x0a,0x8d,0x04,0x00,0xff,0xff,0x00,0x5d,0xfe,0x47,0x04,0x11,0x04,0x9d,0x02,0x26,0x03,0xeb,0x00,0x00,0x01,0x07,0x00,0x7a,0x01,0x55,0xff,0xfa,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xfa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x06,0x06,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x07,0x01,0x52, +0x00,0x95,0x00,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0x00,0x02,0x00,0x6e,0x04,0xe4,0x03,0x4d,0x06,0xfc,0x00,0x08,0x00,0x1c,0x00,0x09,0x40,0x06,0x1c,0x12,0x07,0x01,0x02,0x0b,0x2b,0x01,0x07,0x23,0x27,0x07,0x23,0x27,0x01,0x33,0x37,0x14,0x06,0x23,0x22,0x26,0x23,0x22,0x06,0x15,0x27,0x34,0x36,0x33, +0x32,0x16,0x33,0x32,0x36,0x35,0x03,0x4d,0x02,0xaa,0xc4,0xc4,0xa9,0x02,0x01,0x21,0x9d,0xb6,0x61,0x42,0x35,0x71,0x26,0x1f,0x33,0x50,0x60,0x42,0x2a,0x7b,0x27,0x1e,0x36,0x04,0xea,0x06,0xb0,0xb0,0x06,0x01,0x01,0xfa,0x45,0x6b,0x47,0x3b,0x22,0x13,0x45,0x6f,0x45,0x38,0x23,0x00,0x00,0x00,0x00,0x02,0x00,0x6e,0x04,0xe4,0x04,0x31, +0x06,0xd1,0x00,0x08,0x00,0x18,0x00,0x09,0x40,0x06,0x11,0x09,0x00,0x03,0x02,0x0b,0x2b,0x01,0x23,0x01,0x17,0x33,0x37,0x17,0x33,0x37,0x2f,0x01,0x3e,0x01,0x35,0x34,0x26,0x23,0x37,0x32,0x16,0x15,0x14,0x06,0x0f,0x01,0x02,0x40,0xc6,0xfe,0xf4,0x02,0xa9,0xc4,0xc4,0xaa,0x02,0x19,0x01,0x42,0x37,0x4b,0x3e,0x06,0x7f,0x89,0x4b,0x39, +0x01,0x05,0xeb,0xfe,0xff,0x06,0xba,0xba,0x06,0x84,0x85,0x04,0x1a,0x20,0x22,0x20,0x5e,0x57,0x4b,0x3d,0x40,0x07,0x3d,0x00,0x00,0x02,0xff,0x55,0x04,0xe4,0x03,0x4d,0x06,0x98,0x00,0x08,0x00,0x0c,0x00,0x09,0x40,0x06,0x0b,0x09,0x07,0x01,0x02,0x0b,0x2b,0x01,0x07,0x23,0x27,0x07,0x23,0x27,0x01,0x33,0x05,0x23,0x03,0x33,0x03,0x4d, +0x02,0xc7,0xa7,0xa7,0xc6,0x02,0x01,0x20,0x9e,0xfe,0x87,0x93,0xcb,0xd2,0x04,0xea,0x06,0x9d,0x9d,0x06,0x01,0x01,0x57,0x01,0x04,0x00,0x00,0x00,0x00,0x02,0x00,0x78,0x04,0xe4,0x04,0x71,0x06,0x98,0x00,0x08,0x00,0x0c,0x00,0x09,0x40,0x06,0x09,0x0b,0x00,0x03,0x02,0x0b,0x2b,0x01,0x33,0x01,0x07,0x23,0x27,0x07,0x23,0x27,0x01,0x33, +0x03,0x23,0x01,0x99,0x9e,0x01,0x20,0x02,0xc6,0xa7,0xa7,0xc7,0x02,0x03,0x26,0xd3,0xcc,0x93,0x05,0xeb,0xfe,0xff,0x06,0x9d,0x9d,0x06,0x01,0xae,0xfe,0xfc,0x00,0x00,0x00,0x02,0x00,0x27,0x00,0x00,0x04,0x8a,0x04,0x8d,0x00,0x07,0x00,0x0b,0x00,0x09,0x40,0x06,0x0a,0x08,0x04,0x02,0x02,0x0b,0x2b,0x01,0x21,0x03,0x23,0x01,0x33,0x01, +0x23,0x01,0x21,0x03,0x23,0x03,0x57,0xfe,0x03,0x67,0xcc,0x01,0xd5,0xba,0x01,0xd4,0xcb,0xfd,0xd6,0x01,0x87,0xc1,0x06,0x01,0x0c,0xfe,0xf4,0x04,0x8d,0xfb,0x73,0x01,0xa6,0x01,0xf2,0x00,0x00,0x02,0x00,0x6d,0x04,0xa5,0x02,0xed,0x06,0xa8,0x00,0x0f,0x00,0x14,0x00,0x09,0x40,0x06,0x13,0x10,0x00,0x03,0x02,0x0b,0x2b,0x01,0x17,0x16, +0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x27,0x23,0x27,0x37,0x33,0x02,0xe6,0x02,0x05,0xae,0x92,0x93,0xad,0x06,0x02,0x95,0x4f,0x54,0x53,0x4f,0x4c,0x9d,0xd0,0x02,0xdc,0x05,0xb0,0x06,0x73,0x92,0x92,0x73,0x06,0x41,0x52,0x52,0x41,0x2b,0xc7,0x06,0x00,0x00,0x00,0x00,0x01,0x00,0xa0,0x04,0x8c,0x01,0x7a, +0x06,0x17,0x00,0x05,0x00,0x07,0x40,0x04,0x01,0x04,0x01,0x0b,0x2b,0x13,0x37,0x33,0x03,0x15,0x23,0xa0,0x79,0x61,0x15,0xc5,0x05,0x20,0xf7,0xfe,0xff,0x8a,0x00,0x00,0x00,0x03,0x00,0x99,0x00,0x00,0x04,0x0d,0x04,0x8d,0x00,0x0e,0x00,0x18,0x00,0x21,0x00,0x0b,0x40,0x08,0x1f,0x19,0x0f,0x10,0x01,0x00,0x03,0x0b,0x2b,0x33,0x11,0x21, +0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x01,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x27,0x23,0x25,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x99,0x01,0x8d,0xd5,0xed,0x5e,0x57,0x66,0x74,0xdd,0xc5,0xfe,0xf3,0x01,0x0d,0x6d,0x6f,0x6a,0x67,0x0b,0xfe,0xf3,0xc8,0x7c,0x81,0x7b,0x82,0xc8,0x04,0x8d,0x9f,0x9f,0x54, +0x82,0x21,0x19,0x96,0x60,0xa2,0xa7,0x02,0x09,0xfe,0x8f,0x5e,0x58,0x54,0x64,0x03,0x8d,0x59,0x55,0x56,0x46,0x00,0x00,0x00,0x00,0x01,0x00,0x70,0xff,0xef,0x04,0x26,0x04,0x9d,0x00,0x1d,0x00,0x07,0x40,0x04,0x0a,0x03,0x01,0x0b,0x2b,0x01,0x17,0x16,0x04,0x23,0x22,0x00,0x3d,0x01,0x34,0x00,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26, +0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x35,0x04,0x1e,0x02,0x05,0xfe,0xfd,0xce,0xcf,0xfe,0xeb,0x01,0x15,0xcf,0xd4,0xfe,0x05,0x02,0xbd,0x8e,0x80,0x7b,0xa4,0xa4,0x7b,0x7f,0x8e,0x01,0x7d,0x06,0xbd,0xcb,0x01,0x0c,0xd2,0xf3,0xd1,0x01,0x0c,0xcb,0xbb,0x06,0x79,0x7a,0xba,0x89,0xf4,0x8b,0xbb,0x7a,0x7c,0x00,0x00,0x00, +0x00,0x02,0x00,0x99,0x00,0x00,0x04,0x31,0x04,0x8d,0x00,0x09,0x00,0x13,0x00,0x09,0x40,0x06,0x0a,0x0b,0x01,0x00,0x02,0x0b,0x2b,0x33,0x11,0x21,0x32,0x00,0x1d,0x01,0x14,0x00,0x23,0x03,0x11,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x99,0x01,0xa5,0xd3,0x01,0x20,0xfe,0xe0,0xd3,0xe0,0xe0,0x7e,0xb0,0xb0,0x7e,0x04,0x8d,0xfe,0xf3, +0xd1,0xd2,0xd2,0xfe,0xf5,0x03,0xf4,0xfc,0xa4,0xba,0x8b,0xd3,0x89,0xbb,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x03,0xc8,0x04,0x8d,0x00,0x0b,0x00,0x07,0x40,0x04,0x06,0x04,0x01,0x0b,0x2b,0x01,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x03,0x71,0xfd,0xed,0x02,0x6a,0xfc,0xd1,0x03,0x2f,0xfd,0x96,0x02,0x13,0x02, +0x12,0xfe,0x86,0x98,0x04,0x8d,0x99,0xfe,0xb8,0x00,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x03,0xca,0x04,0x8d,0x00,0x09,0x00,0x07,0x40,0x04,0x04,0x02,0x01,0x0b,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x15,0x21,0x11,0x21,0x03,0x73,0xfd,0xeb,0xc5,0x03,0x31,0xfd,0x94,0x02,0x15,0x01,0xf5,0xfe,0x0b,0x04,0x8d,0x99,0xfe,0x9b,0x00, +0x00,0x01,0x00,0x70,0xff,0xef,0x04,0x4b,0x04,0x9d,0x00,0x20,0x00,0x07,0x40,0x04,0x09,0x02,0x01,0x0b,0x2b,0x25,0x0e,0x01,0x23,0x22,0x00,0x3d,0x01,0x34,0x00,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x37,0x35,0x21,0x35,0x21,0x04,0x4b,0x2d,0xf2,0xb5,0xe7,0xfe,0xe0,0x01,0x22, +0xe1,0xde,0xf3,0x04,0x02,0xbc,0x91,0x7e,0x8c,0xb2,0xb0,0x92,0x69,0x89,0x1f,0xfe,0xfe,0x01,0xc5,0x9d,0x41,0x6d,0x01,0x09,0xd5,0xf3,0xd3,0x01,0x0a,0xc9,0x9d,0x06,0x65,0x6e,0xb8,0x8b,0xf4,0x8e,0xb8,0x2a,0x1b,0xfa,0x9a,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x04,0x5a,0x04,0x8d,0x00,0x0b,0x00,0x07,0x40,0x04,0x06,0x00,0x01,0x0b, +0x2b,0x21,0x23,0x11,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x33,0x04,0x5a,0xc6,0xfd,0xca,0xc5,0xc5,0x02,0x36,0xc6,0x01,0xeb,0xfe,0x15,0x04,0x8d,0xfd,0xf7,0x02,0x09,0x00,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x01,0x5d,0x04,0x8d,0x00,0x03,0x00,0x07,0x40,0x04,0x02,0x00,0x01,0x0b,0x2b,0x21,0x23,0x11,0x33,0x01,0x5d,0xc4, +0xc4,0x04,0x8d,0x00,0x00,0x01,0x00,0x40,0xff,0xef,0x03,0x77,0x04,0x8d,0x00,0x10,0x00,0x07,0x40,0x04,0x00,0x04,0x01,0x0b,0x2b,0x01,0x33,0x11,0x14,0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x02,0xb3,0xc4,0xe3,0xaf,0xc3,0xe2,0x06,0x02,0xbc,0x76,0x6b,0x58,0x76,0x04,0x8d,0xfc,0xd5,0xaa,0xc9,0xb2,0xaa, +0x06,0x65,0x65,0x79,0x62,0x00,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x04,0x41,0x04,0x8d,0x00,0x0e,0x00,0x07,0x40,0x04,0x04,0x02,0x01,0x0b,0x2b,0x01,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x01,0x33,0x17,0x09,0x01,0x07,0x23,0x01,0xc1,0x63,0xc5,0xc5,0x54,0x01,0x84,0xe7,0x03,0xfe,0x39,0x01,0xe8,0x03,0xf1,0x01,0xf4,0xfe,0x0c, +0x04,0x8d,0xfe,0x04,0x01,0xfc,0x05,0xfd,0xd6,0xfd,0xa7,0x05,0x00,0x01,0x00,0x99,0x00,0x00,0x03,0x6b,0x04,0x8d,0x00,0x05,0x00,0x07,0x40,0x04,0x04,0x02,0x01,0x0b,0x2b,0x25,0x21,0x15,0x21,0x11,0x33,0x01,0x5e,0x02,0x0d,0xfd,0x2e,0xc5,0x98,0x98,0x04,0x8d,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x05,0x55,0x04,0x8d,0x00,0x0f, +0x00,0x07,0x40,0x04,0x02,0x04,0x01,0x0b,0x2b,0x01,0x33,0x01,0x33,0x11,0x23,0x11,0x27,0x01,0x23,0x01,0x07,0x11,0x23,0x11,0x33,0x02,0xf7,0x06,0x01,0x62,0xf6,0xc5,0x06,0xfe,0xb4,0x88,0xfe,0xae,0x06,0xc5,0xfe,0x01,0x03,0x03,0x8a,0xfb,0x73,0x03,0x29,0x02,0xfc,0xd5,0x03,0x3d,0x02,0xfc,0xc5,0x04,0x8d,0x00,0x00,0x01,0x00,0x92, +0x02,0x88,0x03,0x13,0x03,0x23,0x00,0x03,0x00,0x07,0x40,0x04,0x02,0x00,0x01,0x0b,0x2b,0x01,0x21,0x35,0x21,0x03,0x13,0xfd,0x7f,0x02,0x81,0x02,0x88,0x9b,0x00,0x00,0x00,0x01,0x00,0x99,0x00,0x00,0x04,0x76,0x04,0x8d,0x00,0x0b,0x00,0x07,0x40,0x04,0x06,0x00,0x01,0x0b,0x2b,0x21,0x23,0x01,0x07,0x11,0x23,0x11,0x33,0x01,0x37,0x11, +0x33,0x04,0x76,0xc4,0xfd,0xb2,0x06,0xc5,0xc5,0x02,0x4e,0x06,0xc4,0x03,0x5b,0x02,0xfc,0xa7,0x04,0x8d,0xfc,0xa5,0x02,0x03,0x59,0x00,0x00,0x00,0x00,0x02,0x00,0x70,0xff,0xef,0x04,0x5b,0x04,0x9d,0x00,0x0d,0x00,0x1b,0x00,0x09,0x40,0x06,0x10,0x17,0x09,0x02,0x02,0x0b,0x2b,0x01,0x14,0x00,0x23,0x22,0x00,0x3d,0x01,0x34,0x00,0x33, +0x32,0x00,0x15,0x27,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x35,0x04,0x5b,0xfe,0xeb,0xe0,0xdf,0xfe,0xe9,0x01,0x15,0xdf,0xe0,0x01,0x17,0xc5,0xa4,0x8e,0x8d,0xa2,0xa3,0x8e,0x8e,0xa2,0x01,0xcd,0xd6,0xfe,0xf8,0x01,0x09,0xd5,0xf3,0xd4,0x01,0x09,0xfe,0xf7,0xd4,0x01,0x97,0xac,0xac,0x97,0xf4,0x9a,0xac,0xac, +0x9a,0x00,0x00,0x00,0x00,0x02,0x00,0x7b,0xff,0xeb,0x04,0x2f,0x05,0xc5,0x00,0x0d,0x00,0x1b,0x00,0x09,0x40,0x06,0x10,0x17,0x09,0x02,0x02,0x0b,0x2b,0x01,0x14,0x02,0x23,0x22,0x02,0x35,0x11,0x34,0x12,0x33,0x32,0x00,0x15,0x27,0x34,0x26,0x23,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x04,0x2f,0xfe,0xdb,0xdc,0xff,0xfe, +0xdb,0xdb,0x01,0x00,0xc6,0x8e,0x87,0x87,0x8d,0x8f,0x87,0x87,0x8c,0x02,0x02,0xf8,0xfe,0xe1,0x01,0x1f,0xf8,0x01,0xac,0xf6,0x01,0x21,0xfe,0xdf,0xf6,0x02,0xb0,0xca,0xcb,0xaf,0xfe,0x52,0xb1,0xcc,0xcb,0xb2,0xff,0xff,0x00,0x5d,0xff,0xef,0x08,0x82,0x04,0x9d,0x00,0x26,0x03,0xeb,0x00,0x00,0x00,0x07,0x03,0xeb,0x04,0x71,0x00,0x00, +0xff,0xff,0x00,0x4e,0x00,0x00,0x03,0xd8,0x06,0x06,0x02,0x26,0x03,0xf2,0x00,0x00,0x01,0x06,0x01,0x53,0x3a,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x4e,0x00,0x00,0x03,0xd8,0x05,0xca,0x02,0x26,0x03,0xf2,0x00,0x00,0x01,0x07,0x01,0x55,0x00,0xf3,0x00,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x4e,0x00,0x00,0x03,0xd8,0x06,0x04,0x02,0x26,0x03,0xf2,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x23,0x00,0x16,0x00,0x08,0xb1,0x01,0x01,0xb0,0x16,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x1e,0x00,0x00,0x04,0x35,0x05,0xc9,0x02,0x26,0x03,0xf1,0x00,0x00,0x01,0x06,0x00,0x6a,0x21,0x19,0x00,0x08, +0xb1,0x01,0x02,0xb0,0x19,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x1e,0x00,0x00,0x04,0x35,0x06,0x04,0x02,0x26,0x03,0xf1,0x00,0x00,0x01,0x06,0x01,0x52,0x46,0x19,0x00,0x08,0xb1,0x01,0x01,0xb0,0x19,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x3f,0x00,0x00,0x05,0xc0,0x06,0x05,0x02,0x26,0x03,0xef,0x00,0x00,0x01,0x07,0x01,0x52,0x01,0x1b,0x00,0x1a, +0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x89,0xfe,0x50,0x04,0x74,0x04,0x8d,0x02,0x26,0x03,0xed,0x00,0x00,0x00,0x07,0x01,0x57,0x01,0x76,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x06,0x09,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x07,0x01,0x59,0x01,0x22,0x00,0x1b,0x00,0x08,0xb1,0x01, +0x02,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x06,0x2d,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x07,0x01,0x56,0x01,0x1c,0x00,0x68,0x00,0x08,0xb1,0x01,0x02,0xb0,0x68,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x06,0x0c,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x07,0x01,0x54, +0x00,0xc6,0x00,0x5c,0x00,0x08,0xb1,0x01,0x01,0xb0,0x5c,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x05,0xb8,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x07,0x00,0x71,0x00,0x94,0x00,0x08,0x00,0x08,0xb1,0x01,0x01,0xb0,0x08,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x06,0x12,0x02,0x26, +0x03,0xed,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0x90,0x00,0x1f,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1f,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x47,0x00,0x00,0x03,0xd1,0x06,0x05,0x02,0x26,0x03,0xec,0x00,0x00,0x01,0x06,0x01,0x53,0x3d,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x47,0xfe,0x22,0x03,0xd1, +0x04,0x8d,0x02,0x26,0x03,0xec,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x0a,0xfe,0xa8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xa8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x5d,0xff,0xef,0x04,0x11,0x06,0x16,0x02,0x26,0x03,0xeb,0x00,0x00,0x01,0x06,0x01,0x53,0x67,0x2b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x2b,0xb0,0x0d,0x2b,0x00,0x01,0x00,0x5a, +0xff,0xef,0x03,0xa8,0x04,0x8d,0x00,0x1f,0x00,0x07,0x40,0x04,0x01,0x0d,0x01,0x0b,0x2b,0x1b,0x01,0x21,0x15,0x21,0x03,0x3e,0x01,0x37,0x36,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x3f,0x02,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0x87,0x47,0x02,0xa6,0xfe,0x05,0x21,0x25,0x72,0x38,0xb5,0xcc,0xd2,0xdb,0xb2,0xef, +0x05,0x01,0xbd,0x7b,0x63,0x76,0x72,0x6f,0x65,0x66,0x63,0x18,0x01,0xf8,0x02,0x95,0xa4,0xfe,0xca,0x19,0x25,0x02,0x03,0xca,0xb9,0xb2,0xd2,0xa1,0x9d,0x06,0x0e,0x53,0x67,0x7c,0x6e,0x6b,0x7d,0x39,0x35,0x00,0xff,0xff,0x00,0x5d,0xff,0xef,0x04,0x11,0x06,0x15,0x02,0x26,0x03,0xeb,0x00,0x00,0x01,0x06,0x01,0x52,0x50,0x2a,0x00,0x08, +0xb1,0x01,0x01,0xb0,0x2a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x5d,0xff,0xef,0x04,0x11,0x06,0x14,0x02,0x26,0x03,0xeb,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x50,0x00,0x26,0x00,0x08,0xb1,0x01,0x01,0xb0,0x26,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x2c,0x06,0x06,0x02,0x26,0x03,0xdc,0x00,0x00,0x01,0x06,0x01,0x53, +0x3c,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99,0xfe,0x22,0x04,0x2c,0x04,0x8d,0x02,0x26,0x03,0xdc,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x09,0xfe,0xa8,0x00,0x09,0xb1,0x02,0x01,0xb8,0xfe,0xa8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x2c,0x06,0x04,0x02,0x26,0x03,0xdc,0x00,0x00, +0x01,0x07,0x00,0x76,0x01,0x25,0x00,0x16,0x00,0x08,0xb1,0x02,0x01,0xb0,0x16,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b,0x06,0x18,0x02,0x26,0x03,0x82,0x00,0x00,0x01,0x07,0x01,0x59,0x01,0x05,0x00,0x2a,0x00,0x08,0xb1,0x02,0x02,0xb0,0x2a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b, +0x06,0x1b,0x02,0x26,0x03,0x82,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0xa9,0x00,0x6b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x6b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b,0x05,0xc7,0x02,0x26,0x03,0x82,0x00,0x00,0x01,0x06,0x00,0x71,0x77,0x17,0x00,0x08,0xb1,0x02,0x01,0xb0,0x17,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99, +0x00,0x00,0x04,0x76,0x06,0x06,0x02,0x26,0x03,0x81,0x00,0x00,0x01,0x07,0x01,0x53,0x00,0xae,0x00,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0xfe,0x22,0x04,0x76,0x04,0x8d,0x02,0x26,0x03,0x81,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x7b,0xfe,0xa8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xa8, +0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x76,0x06,0x04,0x02,0x26,0x03,0x81,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x97,0x00,0x16,0x00,0x08,0xb1,0x01,0x01,0xb0,0x16,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0x6b,0x04,0x8d,0x02,0x26,0x03,0x7e,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x31,0xfd,0x29, +0x00,0x09,0xb1,0x01,0x01,0xb8,0xfd,0x29,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0x6b,0x04,0x8e,0x02,0x26,0x03,0x7e,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x4b,0x03,0x9b,0x00,0x09,0xb1,0x01,0x01,0xb8,0x03,0x9b,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x99,0xfe,0x22,0x03,0x6b,0x04,0x8d,0x02,0x26,0x03,0x7e,0x00,0x00, +0x01,0x07,0x03,0x63,0x00,0xe3,0xfe,0xa8,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xa8,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x6a,0x00,0x00,0x03,0x6b,0x05,0xd3,0x02,0x26,0x03,0x7e,0x00,0x00,0x01,0x06,0x00,0x76,0xe7,0xe5,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xe5,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0x00,0x99,0xfe,0x20,0x04,0x41, +0x04,0x8d,0x02,0x26,0x03,0x7d,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x06,0xfe,0xa6,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0xa6,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x40,0xff,0xef,0x04,0x42,0x05,0xfc,0x02,0x26,0x03,0x7c,0x00,0x00,0x01,0x07,0x01,0x52,0x01,0x31,0x00,0x11,0x00,0x08,0xb1,0x01,0x01,0xb0,0x11,0xb0,0x0d,0x2b,0x00,0x00, +0xff,0xff,0x00,0x8e,0x00,0x00,0x01,0x68,0x05,0xca,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x06,0x01,0x55,0xee,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x3b,0xfe,0x50,0x01,0xca,0x04,0x8d,0x02,0x26,0x03,0x7b,0x00,0x00,0x00,0x06,0x01,0x57,0xf7,0x00,0x00,0x00,0xff,0xff,0xff,0xd0,0x00,0x00,0x02,0x27, +0x06,0x0b,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x07,0x01,0x54,0xff,0x4f,0x00,0x5b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x5b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0xff,0x98,0x00,0x00,0x02,0x69,0x05,0xb7,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x07,0x00,0x71,0xff,0x1d,0x00,0x07,0x00,0x08,0xb1,0x01,0x01,0xb0,0x07,0xb0,0x0d,0x2b,0x00,0x00, +0xff,0xff,0xff,0xa0,0x00,0x00,0x02,0x56,0x06,0x11,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x07,0x01,0x58,0xff,0x19,0x00,0x1e,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1e,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x5a,0x06,0x05,0x02,0x26,0x03,0x7a,0x00,0x00,0x01,0x06,0x01,0x52,0x7f,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0, +0x1a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x70,0xfe,0x14,0x04,0x4b,0x04,0x9d,0x02,0x26,0x03,0x79,0x00,0x00,0x01,0x07,0x03,0x63,0x01,0x59,0xfe,0x9a,0x00,0x09,0xb1,0x01,0x01,0xb8,0xfe,0x9a,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x4b,0x05,0xda,0x02,0x26,0x03,0x79,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x44,0x00,0x2a, +0x00,0x08,0xb1,0x01,0x01,0xb0,0x2a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x4b,0x06,0x1b,0x02,0x26,0x03,0x79,0x00,0x00,0x01,0x07,0x01,0x54,0x00,0xa5,0x00,0x6b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x6b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x4b,0x06,0x15,0x02,0x26,0x03,0x79,0x00,0x00, +0x01,0x06,0x01,0x52,0x74,0x2a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x2a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x06,0x06,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x06,0x01,0x53,0x5b,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99,0xfe,0x50,0x03,0xc8,0x04,0x8d,0x02,0x26,0x03,0x77,0x00,0x00, +0x00,0x07,0x01,0x57,0x01,0x18,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x05,0xca,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x07,0x01,0x55,0x01,0x14,0x00,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x06,0x0b,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x06,0x01,0x54, +0x75,0x5b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x5b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x05,0xb7,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x06,0x00,0x71,0x43,0x07,0x00,0x08,0xb1,0x01,0x01,0xb0,0x07,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x31,0x06,0x06,0x02,0x26,0x03,0x76,0x00,0x00,0x01,0x06,0x01,0x53, +0x2c,0x1b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x26,0x06,0x16,0x02,0x26,0x03,0x75,0x00,0x00,0x01,0x06,0x01,0x53,0x7f,0x2b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x2b,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x26,0x05,0xda,0x02,0x26,0x03,0x75,0x00,0x00,0x01,0x07,0x01,0x55, +0x01,0x38,0x00,0x2a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x2a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x26,0x06,0x15,0x02,0x26,0x03,0x75,0x00,0x00,0x01,0x06,0x01,0x52,0x68,0x2a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x2a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x26,0x06,0x14,0x02,0x26,0x03,0x75,0x00,0x00, +0x01,0x07,0x00,0x76,0x01,0x68,0x00,0x26,0x00,0x08,0xb1,0x01,0x01,0xb0,0x26,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x27,0xfe,0x50,0x04,0xbd,0x04,0x8d,0x02,0x26,0x03,0x71,0x00,0x00,0x00,0x07,0x01,0x57,0x02,0xea,0x00,0x00,0xff,0xff,0x00,0x27,0x00,0x00,0x04,0x8a,0x06,0x0b,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x07,0x01,0x54, +0x00,0xa9,0x00,0x5b,0x00,0x08,0xb1,0x02,0x01,0xb0,0x5b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x27,0x00,0x00,0x04,0x8a,0x05,0xb7,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x06,0x00,0x71,0x77,0x07,0x00,0x08,0xb1,0x02,0x01,0xb0,0x07,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x1e,0x00,0x00,0x04,0x35,0x06,0x03,0x02,0x26,0x03,0xf1,0x00,0x00, +0x01,0x07,0x00,0x76,0x01,0x46,0x00,0x15,0x00,0x08,0xb1,0x01,0x01,0xb0,0x15,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x05,0xcb,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x06,0x00,0x6a,0x70,0x1b,0x00,0x08,0xb1,0x01,0x02,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x02,0x00,0x81,0x04,0xdf,0x02,0xe0,0x06,0x8b,0x00,0x0f, +0x00,0x14,0x00,0x09,0x40,0x06,0x10,0x13,0x00,0x03,0x02,0x0b,0x2b,0x01,0x17,0x16,0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x27,0x33,0x17,0x07,0x23,0x02,0xd8,0x02,0x06,0xa4,0x8b,0x8c,0xa4,0x07,0x02,0x97,0x45,0x4b,0x49,0x46,0x5d,0x9b,0x02,0x9f,0x6a,0x05,0xb0,0x06,0x59,0x72,0x72,0x59,0x06,0x33,0x3f, +0x3f,0x33,0xdb,0x05,0xc0,0x00,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x06,0x05,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x95,0x00,0x17,0x00,0x08,0xb1,0x01,0x01,0xb0,0x17,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x89,0xff,0xef,0x04,0x74,0x06,0x09,0x02,0x26,0x03,0xed,0x00,0x00,0x01,0x07,0x00,0x43, +0x00,0xdb,0x00,0x1b,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1b,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b,0x05,0xda,0x02,0x26,0x03,0x82,0x00,0x00,0x01,0x06,0x00,0x6a,0x53,0x2a,0x00,0x08,0xb1,0x02,0x02,0xb0,0x2a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b,0x06,0x21,0x02,0x26,0x03,0x82,0x00,0x00, +0x01,0x06,0x01,0x58,0x73,0x2e,0x00,0x08,0xb1,0x02,0x01,0xb0,0x2e,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b,0x06,0x15,0x02,0x26,0x03,0x82,0x00,0x00,0x01,0x06,0x01,0x52,0x78,0x2a,0x00,0x08,0xb1,0x02,0x01,0xb0,0x2a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b,0x06,0x14,0x02,0x26,0x03,0x82,0x00,0x00, +0x01,0x07,0x00,0x76,0x01,0x78,0x00,0x26,0x00,0x08,0xb1,0x02,0x01,0xb0,0x26,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xff,0xef,0x04,0x5b,0x06,0x18,0x02,0x26,0x03,0x82,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xbe,0x00,0x2a,0x00,0x08,0xb1,0x02,0x01,0xb0,0x2a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x04,0x76, +0x06,0x11,0x02,0x26,0x03,0x81,0x00,0x00,0x01,0x07,0x01,0x58,0x00,0x92,0x00,0x1e,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1e,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0xff,0xa3,0x00,0x00,0x02,0x54,0x05,0xca,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x07,0x00,0x6a,0xfe,0xf9,0x00,0x1a,0x00,0x08,0xb1,0x01,0x02,0xb0,0x1a,0xb0,0x0d,0x2b,0x00,0x00, +0xff,0xff,0xff,0xc9,0x00,0x00,0x02,0x2f,0x06,0x05,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x07,0x01,0x52,0xff,0x1e,0x00,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x02,0x41,0x06,0x04,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x06,0x00,0x76,0x1d,0x16,0x00,0x08,0xb1,0x01,0x01,0xb0, +0x16,0xb0,0x0d,0x2b,0xff,0xff,0xff,0xb6,0x00,0x00,0x01,0x5d,0x06,0x08,0x02,0x26,0x03,0x7b,0x00,0x00,0x01,0x07,0x00,0x43,0xff,0x64,0x00,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x05,0xca,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x06,0x00,0x6a,0x1f,0x1a,0x00,0x08, +0xb1,0x01,0x02,0xb0,0x1a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x06,0x05,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x06,0x01,0x52,0x44,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x06,0x04,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x44,0x00,0x16, +0x00,0x08,0xb1,0x01,0x01,0xb0,0x16,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x99,0x00,0x00,0x03,0xc8,0x06,0x08,0x02,0x26,0x03,0x77,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0x8a,0x00,0x1a,0x00,0x08,0xb1,0x01,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x70,0xfe,0x47,0x04,0x26,0x04,0x9d,0x02,0x26,0x03,0x75,0x00,0x00, +0x01,0x07,0x00,0x7a,0x01,0x6d,0xff,0xfa,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xfa,0xb0,0x0d,0x2b,0x00,0xff,0xff,0x00,0x27,0x00,0x00,0x04,0x8a,0x06,0xe2,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x07,0x04,0x02,0x01,0x0e,0x00,0x70,0x00,0x08,0xb1,0x02,0x03,0xb0,0x70,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x27,0x00,0x00,0x04,0x8a, +0x06,0x2c,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x07,0x01,0x56,0x00,0xff,0x00,0x67,0x00,0x08,0xb1,0x02,0x02,0xb0,0x67,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x27,0x00,0x00,0x04,0x8a,0x05,0xca,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x06,0x00,0x6a,0x53,0x1a,0x00,0x08,0xb1,0x02,0x02,0xb0,0x1a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x27, +0x00,0x00,0x04,0x8a,0x06,0x11,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x06,0x01,0x58,0x73,0x1e,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1e,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x27,0x00,0x00,0x04,0x8a,0x06,0x05,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x06,0x01,0x52,0x78,0x1a,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1a,0xb0,0x0d,0x2b,0xff,0xff,0x00,0x27, +0x00,0x00,0x04,0x8a,0x06,0x04,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x07,0x00,0x76,0x01,0x78,0x00,0x16,0x00,0x08,0xb1,0x02,0x01,0xb0,0x16,0xb0,0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x27,0x00,0x00,0x04,0x8a,0x06,0x08,0x02,0x26,0x03,0x71,0x00,0x00,0x01,0x07,0x00,0x43,0x00,0xbe,0x00,0x1a,0x00,0x08,0xb1,0x02,0x01,0xb0,0x1a,0xb0, +0x0d,0x2b,0x00,0x00,0xff,0xff,0x00,0x47,0x00,0x00,0x03,0xd1,0x04,0x8d,0x02,0x26,0x03,0xec,0x00,0x00,0x01,0x06,0x03,0x80,0x2d,0xf9,0x00,0x09,0xb1,0x01,0x01,0xb8,0xff,0xf9,0xb0,0x0d,0x2b,0x00,0x00,0x00,0xff,0xff,0xff,0xf5,0x00,0x00,0x04,0x31,0x04,0x8d,0x02,0x26,0x03,0x76,0x00,0x00,0x01,0x07,0x03,0x80,0xff,0x63,0xff,0x7c, +0x00,0x09,0xb1,0x02,0x01,0xb8,0xff,0x7c,0xb0,0x0d,0x2b,0x00,0xff,0xff,0xff,0xf5,0x00,0x00,0x04,0x31,0x04,0x8d,0x02,0x26,0x03,0x76,0x00,0x00,0x01,0x07,0x03,0x80,0xff,0x63,0xff,0x7c,0x00,0x09,0xb1,0x02,0x01,0xb8,0xff,0x7c,0xb0,0x0d,0x2b,0x00,0x00,0x02,0x00,0x70,0xff,0x8a,0x04,0x9a,0x04,0x9d,0x00,0x13,0x00,0x21,0x00,0x09, +0x40,0x06,0x16,0x1d,0x0f,0x05,0x02,0x0b,0x2b,0x01,0x14,0x06,0x07,0x17,0x07,0x27,0x0e,0x01,0x23,0x22,0x00,0x3d,0x01,0x34,0x00,0x33,0x32,0x00,0x15,0x27,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x35,0x04,0x5b,0x34,0x30,0xa3,0x87,0xa7,0x38,0x85,0x49,0xdf,0xfe,0xe9,0x01,0x15,0xdf,0xe0,0x01,0x17,0xc5,0xa4, +0x8e,0x8d,0xa2,0xa3,0x8e,0x8e,0xa2,0x01,0xcd,0x59,0x9b,0x3c,0x9f,0x74,0xa1,0x1e,0x1e,0x01,0x09,0xd5,0xf3,0xd4,0x01,0x09,0xfe,0xf7,0xd4,0x01,0x97,0xac,0xac,0x97,0xf4,0x9a,0xac,0xac,0x9a,0x00,0x00,0x00,0x00,0x02,0x00,0x99,0x00,0x00,0x04,0x2c,0x04,0x8d,0x00,0x1a,0x00,0x23,0x00,0x09,0x40,0x06,0x21,0x1b,0x03,0x01,0x02,0x0b, +0x2b,0x01,0x11,0x23,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x1d,0x01,0x14,0x16,0x17,0x15,0x23,0x2e,0x01,0x3d,0x01,0x34,0x26,0x23,0x25,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x21,0x01,0x5e,0xc5,0x01,0xcd,0xcd,0xe1,0x63,0x60,0x68,0x5b,0x0b,0x0d,0xcb,0x0c,0x06,0x68,0x62,0xfe,0xd9,0x01,0x08,0x78,0x70,0x71,0x77,0xfe, +0xf8,0x01,0xdf,0xfe,0x21,0x04,0x8d,0xb4,0xa2,0x59,0x7e,0x27,0x1e,0x90,0x69,0x76,0x2d,0x56,0x16,0x13,0x17,0x62,0x34,0x74,0x5a,0x64,0x9a,0x5e,0x58,0x5c,0x69,0x00,0xff,0xff,0x00,0x81,0x04,0xa4,0x02,0xd8,0x05,0xb0,0x02,0x06,0x01,0x54,0x00,0x00,0x00,0x02,0x00,0x81,0x04,0xe0,0x02,0xca,0x07,0x2a,0x00,0x0f,0x00,0x20,0x00,0x09, +0x40,0x06,0x19,0x10,0x00,0x0a,0x02,0x0b,0x2b,0x01,0x14,0x06,0x23,0x22,0x26,0x35,0x23,0x07,0x06,0x16,0x33,0x32,0x36,0x2f,0x01,0x25,0x27,0x3e,0x01,0x27,0x35,0x36,0x26,0x23,0x37,0x32,0x16,0x15,0x14,0x06,0x0f,0x01,0x02,0x31,0x44,0x47,0x48,0x44,0x90,0x02,0x07,0x9e,0x87,0x86,0x9e,0x06,0x02,0xfe,0xb3,0x01,0x49,0x3c,0x05,0x05, +0x51,0x46,0x07,0x8e,0x98,0x53,0x3f,0x01,0x05,0xb0,0x33,0x3f,0x40,0x32,0x06,0x59,0x71,0x71,0x59,0x06,0x38,0x7e,0x03,0x17,0x1a,0x06,0x1c,0x1b,0x53,0x4e,0x42,0x35,0x37,0x07,0x3f,0x00,0x00,0x02,0x00,0x81,0x04,0xdb,0x02,0xd3,0x06,0xd4,0x00,0x0f,0x00,0x23,0x00,0x09,0x40,0x06,0x23,0x19,0x00,0x03,0x02,0x0b,0x2b,0x01,0x17,0x16, +0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x13,0x14,0x06,0x23,0x22,0x26,0x23,0x22,0x06,0x15,0x27,0x34,0x36,0x33,0x32,0x16,0x33,0x32,0x36,0x35,0x02,0xcb,0x02,0x06,0xa0,0x88,0x89,0xa1,0x07,0x02,0x94,0x43,0x4a,0x47,0x45,0x94,0x5f,0x47,0x3a,0x7c,0x29,0x22,0x2d,0x58,0x5e,0x49,0x2d,0x87,0x2b,0x20,0x30, +0x05,0xb0,0x06,0x5b,0x74,0x74,0x5b,0x06,0x34,0x41,0x41,0x34,0x01,0x0c,0x4b,0x6b,0x4c,0x34,0x25,0x15,0x4a,0x6f,0x4c,0x33,0x26,0x00,0x00,0x00,0x00,0x01,0x00,0x60,0xfe,0x99,0x01,0x25,0x00,0x9d,0x00,0x03,0x00,0x07,0x40,0x04,0x02,0x00,0x01,0x0b,0x2b,0x01,0x23,0x11,0x33,0x01,0x25,0xc5,0xc5,0xfe,0x99,0x02,0x04,0x00,0x00,0x00, +0x00,0x01,0x00,0x13,0xfe,0x63,0x01,0xc9,0x00,0x43,0x00,0x13,0x00,0x07,0x40,0x04,0x00,0x05,0x01,0x0b,0x2b,0x37,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x34,0x26,0x27,0xf8,0x69,0x68,0x85,0x66,0x44,0x60,0x27,0x21,0x1e,0x37,0x22,0x3d,0x36,0x46,0x3b,0x43,0x34,0x8f,0x4c,0x63,0x6e,0x19, +0x13,0x7b,0x0b,0x0f,0x30,0x2a,0x31,0x57,0x2e,0x00,0x00,0x00,0x00,0x01,0xff,0xbe,0xfe,0x4b,0x01,0x72,0x00,0x9a,0x00,0x0f,0x00,0x07,0x40,0x04,0x00,0x03,0x01,0x0b,0x2b,0x25,0x15,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x3d,0x01,0x01,0x72,0xac,0x99,0x1f,0x33,0x1d,0x0e,0x0e,0x40,0x13,0x3c,0x44,0x9a,0xf3, +0xa7,0xb5,0x09,0x09,0xa0,0x05,0x07,0x5e,0x58,0xf3,0x00,0x00,0x00,0x01,0xff,0xa0,0xff,0xce,0x02,0xca,0x03,0x70,0x00,0x0f,0x00,0x07,0x40,0x04,0x00,0x07,0x01,0x0b,0x2b,0x03,0x21,0x32,0x00,0x15,0x06,0x02,0x07,0x27,0x3e,0x01,0x35,0x2e,0x01,0x23,0x21,0x60,0x01,0x17,0xeb,0x01,0x28,0x02,0xc3,0xbe,0x33,0x80,0x70,0x01,0xb6,0x96, +0xfe,0xe9,0x03,0x70,0xff,0x00,0xdc,0x8a,0xfe,0xe6,0x22,0x94,0x22,0x9d,0x73,0x93,0xa4,0x00,0x00,0x00,0x00,0x01,0x00,0x71,0x00,0x00,0x02,0x55,0x05,0xc5,0x00,0x05,0x00,0x07,0x40,0x04,0x05,0x00,0x01,0x0b,0x2b,0x21,0x23,0x11,0x05,0x35,0x25,0x02,0x55,0xc5,0xfe,0xe1,0x01,0xe4,0x04,0xfa,0x03,0xa2,0x2c,0x00,0x00,0x01,0x00,0x53, +0x00,0x00,0x03,0xe7,0x05,0xc5,0x00,0x1a,0x00,0x07,0x40,0x04,0x10,0x00,0x01,0x0b,0x2b,0x29,0x01,0x35,0x01,0x3e,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x07,0x01,0x17,0x21,0x03,0xe7,0xfc,0x8f,0x01,0xaf,0x7d,0x5c,0x7a,0x70,0x78,0x85,0xbd,0x02,0x05,0xf5,0xcc,0xc6,0xe9,0x9f, +0x9f,0xfe,0xe0,0x02,0x02,0x80,0x9a,0x01,0xf5,0x8a,0xa9,0x52,0x79,0x9d,0x9f,0x75,0x06,0xb2,0xf7,0xe3,0xd0,0x7d,0xe9,0xb3,0xfe,0xa6,0x05,0x00,0x00,0x01,0x00,0x69,0xff,0xeb,0x04,0x2d,0x05,0xc5,0x00,0x2a,0x00,0x07,0x40,0x04,0x0d,0x19,0x01,0x0b,0x2b,0x01,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x24,0x33, +0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x04,0x23,0x22,0x24,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x02,0x4e,0x84,0x80,0x8c,0x88,0x6b,0x92,0xbd,0x02,0x05,0x01,0x04,0xbd,0xdb,0xfd,0x73,0x64,0x73,0x7b,0xfe,0xee,0xdd,0xc0,0xfe,0xeb,0x05,0x02,0xbd,0x98,0x79,0x8b,0x9f,0x8f,0x8b,0xb6, +0x03,0x33,0x84,0x73,0x70,0x90,0x8e,0x69,0x06,0xb0,0xdc,0xd7,0xc8,0x65,0xa6,0x30,0x2a,0xae,0x7d,0xc8,0xe3,0xd6,0xcd,0x06,0x72,0x9d,0x95,0x78,0x85,0x81,0x9b,0x00,0x00,0x02,0x00,0x49,0x00,0x00,0x04,0x6f,0x05,0xb0,0x00,0x0a,0x00,0x0f,0x00,0x09,0x40,0x06,0x0e,0x0b,0x09,0x04,0x02,0x0b,0x2b,0x01,0x33,0x15,0x23,0x11,0x23,0x11, +0x21,0x35,0x01,0x33,0x01,0x21,0x11,0x27,0x07,0x03,0x9c,0xd3,0xd3,0xc5,0xfd,0x72,0x02,0x83,0xd0,0xfd,0x8d,0x01,0xae,0x06,0x12,0x01,0xd4,0x9a,0xfe,0xc6,0x01,0x3a,0x6f,0x04,0x07,0xfc,0x24,0x02,0xd0,0x01,0x2d,0x00,0x00,0x00,0x00,0x01,0x00,0x84,0xff,0xeb,0x04,0x3d,0x05,0xb0,0x00,0x1f,0x00,0x07,0x40,0x04,0x01,0x0d,0x01,0x0b, +0x2b,0x1b,0x01,0x21,0x15,0x21,0x03,0x3e,0x01,0x37,0x36,0x16,0x15,0x14,0x02,0x23,0x22,0x24,0x3f,0x02,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0xb0,0x54,0x03,0x02,0xfd,0xa4,0x2f,0x31,0x7d,0x50,0xd5,0xef,0xf6,0xea,0xca,0xfe,0xf1,0x05,0x02,0xb4,0xa2,0x7c,0x86,0x95,0x96,0x85,0x7d,0x71,0x1c,0x02,0x7d,0x03, +0x33,0xaf,0xfe,0x54,0x22,0x2d,0x02,0x02,0xf9,0xdf,0xdb,0xfe,0xf6,0xca,0xc5,0x06,0x12,0x78,0x95,0xb0,0x99,0x8a,0xa3,0x46,0x48,0x00,0x00,0x00,0x00,0x02,0x00,0x8e,0xff,0xeb,0x04,0x56,0x05,0xc5,0x00,0x1a,0x00,0x27,0x00,0x09,0x40,0x06,0x1b,0x21,0x00,0x13,0x02,0x0b,0x2b,0x01,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d, +0x01,0x3e,0x01,0x33,0x32,0x16,0x15,0x14,0x00,0x23,0x22,0x00,0x35,0x11,0x34,0x00,0x13,0x22,0x06,0x07,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x02,0xa5,0x56,0xa8,0x36,0x2a,0x41,0x76,0x53,0x94,0xbe,0x3a,0xa4,0x61,0xd3,0xf1,0xff,0x00,0xda,0xd3,0xfe,0xe5,0x01,0x38,0xa5,0x67,0x8d,0x24,0xab,0x7e,0x86,0x8f,0x8f,0x05,0xc5, +0x21,0x1a,0x97,0x1a,0x1d,0xe0,0xaa,0x94,0x43,0x4d,0xf4,0xdc,0xdf,0xfe,0xfe,0x01,0x14,0xef,0x01,0xb0,0xef,0x01,0x38,0xfd,0x30,0x44,0x3e,0x85,0xa8,0xc1,0xb2,0x95,0x97,0x92,0x00,0x00,0x00,0x01,0x00,0x25,0x00,0x00,0x03,0xd5,0x05,0xb0,0x00,0x0c,0x00,0x07,0x40,0x04,0x0b,0x04,0x01,0x0b,0x2b,0x01,0x0a,0x01,0x11,0x15,0x23,0x35, +0x10,0x00,0x37,0x21,0x35,0x21,0x03,0xd5,0xde,0xc4,0xc5,0x01,0x0d,0x99,0xfd,0x11,0x03,0xb0,0x05,0x15,0xfe,0xf4,0xfe,0x4d,0xfe,0x91,0xe7,0xe7,0x01,0x62,0x02,0x29,0xa3,0x9b,0x00,0x00,0x00,0x01,0x00,0x5d,0xff,0xef,0x04,0x11,0x04,0x9d,0x00,0x27,0x00,0x07,0x40,0x04,0x08,0x1c,0x01,0x0b,0x2b,0x01,0x34,0x26,0x27,0x2e,0x01,0x35, +0x34,0x36,0x33,0x32,0x16,0x0f,0x01,0x23,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x17,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x24,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x03,0x4c,0x7c,0xa2,0xdf,0xcb,0xf3,0xce,0xd2,0xeb,0x05,0x02,0xbb,0x84,0x77,0x7d,0x7f,0x73,0xb2,0xd7,0xcc,0xfe,0xda,0xca,0xfe,0xee,0x06,0x01,0xbc,0xa3,0x76, +0x83,0x90,0x01,0x30,0x47,0x58,0x28,0x3a,0x95,0x96,0x93,0xae,0xba,0xa8,0x06,0x5c,0x73,0x5d,0x4a,0x49,0x51,0x2b,0x3a,0x9c,0x91,0x9a,0xa8,0xaa,0xb8,0x06,0x6c,0x64,0x5e,0x00,0x00,0x00,0x00,0x01,0x00,0x47,0x00,0x00,0x03,0xd1,0x04,0x8d,0x00,0x07,0x00,0x07,0x40,0x04,0x06,0x02,0x01,0x0b,0x2b,0x01,0x21,0x11,0x23,0x11,0x21,0x35, +0x21,0x03,0xd1,0xfe,0x9b,0xc5,0xfe,0xa0,0x03,0x8a,0x03,0xf4,0xfc,0x0c,0x03,0xf4,0x99,0x00,0x00,0x00,0x00,0x01,0x00,0x89,0xff,0xef,0x04,0x74,0x04,0x8d,0x00,0x11,0x00,0x07,0x40,0x04,0x00,0x03,0x01,0x0b,0x2b,0x01,0x11,0x14,0x04,0x23,0x22,0x24,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x11,0x04,0x74,0xfe,0xe9,0xdf, +0xdd,0xfe,0xe8,0xc4,0xa9,0x88,0x89,0xa9,0x04,0x8d,0xfd,0x01,0xc3,0xdc,0xdc,0xc3,0x02,0xff,0xfd,0x01,0x7b,0x8c,0x8b,0x7c,0x02,0xff,0x00,0x00,0x00,0x01,0x00,0x27,0x00,0x00,0x04,0x83,0x04,0x8d,0x00,0x09,0x00,0x07,0x40,0x04,0x04,0x06,0x01,0x0b,0x2b,0x01,0x17,0x33,0x37,0x01,0x33,0x01,0x23,0x01,0x33,0x02,0x3b,0x17,0x06,0x17, +0x01,0x41,0xd3,0xfe,0x2e,0xb9,0xfe,0x2f,0xd3,0x01,0x29,0x52,0x50,0x03,0x66,0xfb,0x73,0x04,0x8d,0x00,0x00,0x01,0x00,0x3f,0x00,0x00,0x05,0xc0,0x04,0x8d,0x00,0x11,0x00,0x07,0x40,0x04,0x03,0x0a,0x01,0x0b,0x2b,0x01,0x15,0x37,0x13,0x33,0x13,0x15,0x37,0x13,0x33,0x01,0x23,0x03,0x23,0x03,0x23,0x01,0x33,0x01,0xc7,0x01,0xdd,0xb7, +0xdd,0x01,0xb3,0xd3,0xfe,0xda,0xb6,0xe1,0x06,0xe3,0xb5,0xfe,0xda,0xd3,0x01,0x08,0x03,0x05,0x03,0x83,0xfc,0x7b,0x03,0x05,0x03,0x83,0xfb,0x73,0x03,0x57,0xfc,0xa9,0x04,0x8d,0x00,0x00,0x00,0x01,0x00,0x37,0x00,0x00,0x04,0x42,0x04,0x8d,0x00,0x0b,0x00,0x07,0x40,0x04,0x01,0x04,0x01,0x0b,0x2b,0x09,0x01,0x33,0x09,0x01,0x23,0x09, +0x01,0x23,0x09,0x01,0x33,0x02,0x3a,0x01,0x16,0xe9,0xfe,0x78,0x01,0x91,0xe6,0xfe,0xe1,0xfe,0xe3,0xe9,0x01,0x92,0xfe,0x77,0xe8,0x02,0xdc,0x01,0xb1,0xfd,0xbf,0xfd,0xb4,0x01,0xba,0xfe,0x46,0x02,0x4c,0x02,0x41,0x00,0x00,0x00,0x00,0x01,0x00,0x1e,0x00,0x00,0x04,0x35,0x04,0x8d,0x00,0x08,0x00,0x07,0x40,0x04,0x01,0x04,0x01,0x0b, +0x2b,0x09,0x01,0x33,0x01,0x11,0x23,0x11,0x01,0x33,0x02,0x29,0x01,0x2f,0xdd,0xfe,0x54,0xc5,0xfe,0x5a,0xdd,0x02,0x4d,0x02,0x40,0xfd,0x0d,0xfe,0x66,0x01,0xa3,0x02,0xea,0x00,0x00,0x00,0x00,0x01,0x00,0x4e,0x00,0x00,0x03,0xd8,0x04,0x8d,0x00,0x09,0x00,0x07,0x40,0x04,0x07,0x02,0x01,0x0b,0x2b,0x25,0x21,0x15,0x21,0x35,0x01,0x21, +0x35,0x21,0x15,0x01,0x3d,0x02,0x9b,0xfc,0x76,0x02,0x81,0xfd,0xa1,0x03,0x50,0x98,0x98,0x76,0x03,0x7e,0x99,0x72,0x00,0x00,0x00,0x02,0x00,0x78,0xff,0xef,0x03,0xfa,0x04,0x9d,0x00,0x0d,0x00,0x1b,0x00,0x09,0x40,0x06,0x10,0x17,0x09,0x02,0x02,0x0b,0x2b,0x01,0x14,0x06,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x32,0x16,0x15,0x27, +0x34,0x26,0x23,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x03,0xfa,0xf7,0xc9,0xca,0xf8,0xf7,0xc9,0xca,0xf8,0xc5,0x88,0x75,0x73,0x88,0x89,0x74,0x74,0x87,0x01,0x9b,0xc5,0xe7,0xe8,0xc4,0x01,0x57,0xc3,0xe8,0xe8,0xc3,0x01,0x7c,0x95,0x96,0x7b,0xfe,0xa8,0x7d,0x97,0x96,0x7e,0x00,0x00,0x01,0x00,0x4e,0x00,0x00,0x01,0xc3, +0x04,0x9d,0x00,0x05,0x00,0x07,0x40,0x04,0x05,0x00,0x01,0x0b,0x2b,0x21,0x23,0x11,0x07,0x35,0x25,0x01,0xc3,0xc5,0xb0,0x01,0x75,0x03,0xde,0x02,0xa0,0x21,0x00,0x00,0x00,0x01,0x00,0x59,0x00,0x00,0x03,0x73,0x04,0x9d,0x00,0x1a,0x00,0x07,0x40,0x04,0x10,0x00,0x01,0x0b,0x2b,0x29,0x01,0x35,0x01,0x3e,0x01,0x35,0x34,0x26,0x23,0x22, +0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x0f,0x01,0x17,0x21,0x03,0x73,0xfc,0xf3,0x01,0x96,0x66,0x45,0x5c,0x57,0x65,0x72,0xbc,0x02,0x06,0xe0,0xbb,0xaf,0xc9,0x75,0x9e,0xf8,0x03,0x02,0x0f,0x98,0x01,0x96,0x61,0x72,0x3e,0x54,0x71,0x73,0x53,0x06,0x8f,0xca,0xb8,0xa8,0x6d,0x99,0xa0,0xf9,0x06,0x00,0x00,0x00, +0x00,0x01,0x00,0x5a,0xff,0xef,0x03,0xa3,0x04,0x9d,0x00,0x2a,0x00,0x07,0x40,0x04,0x0d,0x19,0x01,0x0b,0x2b,0x01,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35, +0x02,0x00,0x68,0x63,0x6e,0x6a,0x54,0x72,0xbb,0x02,0x06,0xe2,0xa7,0xc0,0xdd,0x60,0x54,0x60,0x67,0xf0,0xc0,0xa8,0xf1,0x05,0x02,0xba,0x79,0x5f,0x6c,0x7e,0x6f,0x6e,0xa8,0x02,0x9d,0x5f,0x54,0x4c,0x68,0x60,0x47,0x06,0x8c,0xae,0xac,0xa0,0x50,0x85,0x26,0x23,0x8a,0x63,0xa1,0xb6,0xab,0xa2,0x06,0x4d,0x6e,0x6d,0x52,0x62,0x5f,0x96, +0x00,0x02,0x00,0x47,0x00,0x00,0x04,0x15,0x04,0x8d,0x00,0x0a,0x00,0x0e,0x00,0x09,0x40,0x06,0x0d,0x0b,0x09,0x04,0x02,0x0b,0x2b,0x01,0x33,0x15,0x23,0x15,0x23,0x35,0x21,0x27,0x01,0x33,0x03,0x11,0x27,0x01,0x03,0x52,0xc3,0xc3,0xc5,0xfd,0xbe,0x04,0x02,0x3f,0xcc,0xc5,0x06,0xfe,0x99,0x01,0x85,0x9a,0xeb,0xeb,0x7a,0x03,0x28,0xfc, +0xf8,0x01,0xfb,0x02,0xfe,0x03,0x00,0x00,0x00,0x02,0x00,0x78,0xff,0xef,0x03,0xd7,0x04,0x9d,0x00,0x1a,0x00,0x27,0x00,0x09,0x40,0x06,0x1b,0x21,0x00,0x13,0x02,0x0b,0x2b,0x01,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d,0x01,0x3e,0x01,0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x35,0x11,0x34,0x24,0x13,0x22,0x06,0x07, +0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x02,0x4f,0x42,0x93,0x43,0x21,0x3a,0x72,0x49,0x79,0x9b,0x32,0x8f,0x58,0xb9,0xc8,0xef,0xbf,0xba,0xf7,0x01,0x11,0xa1,0x58,0x7a,0x1b,0x86,0x66,0x69,0x80,0x72,0x04,0x9d,0x1c,0x17,0x94,0x18,0x16,0xa3,0x7d,0x6a,0x34,0x3a,0xc6,0xb3,0xab,0xd5,0xf8,0xc4,0x01,0x37,0xc3,0xf8,0xfd,0xb1, +0x40,0x36,0x2d,0x7d,0xa7,0x86,0x62,0x68,0x77,0x00,0x00,0x00,0x00,0x02,0x00,0x68,0xff,0xf5,0x02,0xec,0x03,0x2c,0x00,0x1a,0x00,0x27,0x00,0x09,0x40,0x06,0x21,0x1b,0x0c,0x13,0x02,0x0b,0x2b,0x25,0x32,0x36,0x3d,0x01,0x0e,0x01,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x32,0x16,0x1d,0x01,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x01, +0x13,0x32,0x36,0x37,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x01,0x97,0x48,0x60,0x1f,0x54,0x2f,0x91,0xa4,0xb4,0x8f,0x8a,0xb7,0xc3,0x92,0x33,0x6e,0x32,0x1c,0x2b,0x54,0x48,0x3c,0x4f,0x0d,0x58,0x42,0x42,0x50,0x4b,0x77,0x54,0x43,0x49,0x21,0x22,0x91,0x7a,0x72,0x9b,0xac,0x86,0xeb,0x7d,0x9d,0x12,0x10,0x7f,0x11,0x0e,0x01, +0x17,0x31,0x23,0x18,0x4c,0x63,0x53,0x37,0x42,0x4f,0x00,0x00,0x00,0x03,0x00,0x70,0xff,0xf5,0x03,0x07,0x03,0x2c,0x00,0x17,0x00,0x23,0x00,0x2f,0x00,0x0b,0x40,0x08,0x26,0x2c,0x1a,0x20,0x14,0x08,0x03,0x0b,0x2b,0x01,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x36,0x33,0x32, +0x16,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x02,0xef,0x49,0x3e,0x49,0x56,0xb9,0x8c,0x92,0xc0,0x59,0x4c,0x42,0x4a,0xb1,0x87,0x82,0xac,0x92,0x5c,0x40,0x46,0x60,0x5f,0x48,0x41,0x5a,0x1a,0x4b,0x37,0x3d,0x4f,0x51,0x3c,0x35,0x4c,0x02,0x50,0x3b, +0x5b,0x1b,0x1c,0x63,0x3f,0x70,0x7c,0x7c,0x70,0x3f,0x64,0x1c,0x1b,0x5a,0x3b,0x69,0x73,0x73,0xfe,0x2f,0x33,0x43,0x42,0x34,0x34,0x3d,0x3d,0x01,0x93,0x2d,0x35,0x34,0x2e,0x2e,0x39,0x39,0x00,0x02,0x00,0x68,0x04,0x6f,0x02,0xcc,0x05,0xc5,0x00,0x05,0x00,0x0b,0x00,0x09,0x40,0x06,0x09,0x06,0x01,0x04,0x02,0x0b,0x2b,0x01,0x13,0x33, +0x15,0x03,0x23,0x05,0x33,0x35,0x37,0x23,0x07,0x01,0x95,0x66,0xd1,0xe5,0x52,0xfe,0xd3,0xbc,0x52,0x6c,0xa2,0x04,0x8c,0x01,0x39,0x15,0xfe,0xc1,0x02,0x89,0xcc,0xc6,0x00,0x01,0x00,0x5f,0x00,0x00,0x02,0xac,0x03,0x21,0x00,0x0c,0x00,0x07,0x40,0x04,0x0b,0x04,0x01,0x0b,0x2b,0x01,0x0e,0x01,0x1d,0x01,0x23,0x35,0x34,0x12,0x37,0x21, +0x35,0x21,0x02,0xac,0x86,0x6f,0xac,0x9b,0x59,0xfe,0x60,0x02,0x4d,0x02,0x9e,0x9e,0xcb,0xb6,0x7f,0x7f,0xb5,0x01,0x17,0x53,0x83,0x00,0x00,0x00,0x00,0x02,0x00,0x78,0xff,0xf5,0x03,0x04,0x03,0x2c,0x00,0x1a,0x00,0x27,0x00,0x09,0x40,0x06,0x1b,0x21,0x00,0x13,0x02,0x0b,0x2b,0x01,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x1d, +0x01,0x3e,0x01,0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x13,0x22,0x06,0x07,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x01,0xde,0x35,0x6c,0x2b,0x1e,0x27,0x52,0x33,0x53,0x69,0x24,0x65,0x3f,0x84,0x94,0xb6,0x90,0x8d,0xb9,0xcd,0x80,0x40,0x53,0x0e,0x56,0x44,0x47,0x54,0x4a,0x03,0x2c,0x13,0x10,0x7f, +0x10,0x0f,0x5e,0x4e,0x42,0x22,0x26,0x8c,0x7a,0x76,0x92,0xaa,0x87,0xd6,0x87,0xa9,0xfe,0x56,0x2c,0x26,0x0a,0x4e,0x61,0x4b,0x3b,0x3f,0x46,0x00,0x00,0x01,0x00,0x72,0xff,0xf5,0x02,0xf6,0x03,0x21,0x00,0x1f,0x00,0x07,0x40,0x04,0x01,0x0d,0x01,0x0b,0x2b,0x1b,0x01,0x21,0x15,0x21,0x07,0x3e,0x01,0x37,0x36,0x16,0x15,0x14,0x06,0x23, +0x22,0x26,0x3f,0x02,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0x92,0x34,0x02,0x04,0xfe,0x95,0x1a,0x1e,0x4f,0x2a,0x84,0x96,0x9f,0xa6,0x89,0xb6,0x06,0x01,0xa2,0x52,0x44,0x4e,0x4c,0x4d,0x43,0x41,0x43,0x0f,0x01,0x5a,0x01,0xc7,0x85,0xb9,0x11,0x19,0x01,0x02,0x91,0x80,0x7a,0x90,0x6e,0x6a,0x06,0x0a,0x30,0x36, +0x45,0x42,0x42,0x51,0x22,0x1e,0x00,0x00,0x00,0x02,0x00,0x57,0x00,0x00,0x03,0x28,0x03,0x21,0x00,0x0a,0x00,0x0f,0x00,0x09,0x40,0x06,0x0e,0x0b,0x09,0x04,0x02,0x0b,0x2b,0x01,0x33,0x15,0x23,0x15,0x23,0x35,0x21,0x27,0x01,0x33,0x01,0x33,0x11,0x27,0x07,0x02,0xaa,0x7e,0x7e,0xaa,0xfe,0x5f,0x08,0x01,0xa6,0xad,0xfe,0x63,0xf3,0x06, +0x0d,0x01,0x1a,0x82,0x98,0x98,0x66,0x02,0x23,0xfd,0xf9,0x01,0x36,0x01,0x16,0x00,0x00,0x01,0x00,0x6a,0xff,0xf5,0x02,0xe4,0x03,0x2c,0x00,0x2a,0x00,0x07,0x40,0x04,0x0d,0x19,0x01,0x0b,0x2b,0x01,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x06,0x23, +0x22,0x26,0x3f,0x01,0x33,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x2b,0x01,0x35,0x01,0xa8,0x43,0x41,0x49,0x45,0x38,0x45,0xa2,0x02,0x06,0xa9,0x7e,0x91,0xa8,0x47,0x3e,0x46,0x4c,0xb4,0x92,0x7f,0xb5,0x06,0x01,0xa3,0x4b,0x3f,0x48,0x54,0x49,0x49,0x84,0x01,0xd7,0x39,0x34,0x2b,0x3a,0x30,0x28,0x06,0x5e,0x77,0x77,0x6e,0x37,0x5b, +0x1a,0x17,0x60,0x44,0x6f,0x7c,0x74,0x6f,0x06,0x2e,0x39,0x3b,0x30,0x3e,0x39,0x7e,0x00,0x01,0x00,0x71,0x00,0x00,0x02,0xca,0x03,0x2c,0x00,0x1a,0x00,0x07,0x40,0x04,0x10,0x00,0x01,0x0b,0x2b,0x29,0x01,0x35,0x01,0x3e,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x23,0x27,0x26,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x0f,0x01,0x17,0x21, +0x02,0xca,0xfd,0xb0,0x01,0x2e,0x45,0x2c,0x39,0x3a,0x43,0x49,0xa1,0x02,0x06,0xa8,0x8d,0x87,0x98,0x59,0x74,0x99,0x02,0x01,0x69,0x82,0x01,0x06,0x3c,0x4b,0x2a,0x32,0x3e,0x40,0x32,0x06,0x63,0x8c,0x80,0x74,0x50,0x70,0x69,0x87,0x06,0x00,0x00,0x00,0x00,0x03,0x00,0x9b,0x04,0x3d,0x02,0x74,0x06,0x72,0x00,0x04,0x00,0x10,0x00,0x1c, +0x00,0x0b,0x40,0x08,0x19,0x13,0x07,0x0d,0x00,0x03,0x03,0x0b,0x2b,0x01,0x33,0x17,0x07,0x23,0x07,0x34,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x37,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x01,0xab,0xc7,0x02,0xd8,0x81,0x80,0x66,0x49,0x46,0x64,0x63,0x47,0x49,0x66,0x58,0x33,0x24,0x22,0x31,0x31,0x22, +0x24,0x33,0x06,0x72,0x06,0xb3,0xd8,0x48,0x5f,0x5f,0x48,0x48,0x5c,0x5c,0x48,0x23,0x31,0x30,0x24,0x25,0x33,0x33,0x00,0x00,0x00,0x01,0x00,0x5f,0x00,0x00,0x01,0x8c,0x03,0x2c,0x00,0x05,0x00,0x07,0x40,0x04,0x05,0x00,0x01,0x0b,0x2b,0x21,0x23,0x11,0x23,0x35,0x25,0x01,0x8c,0xae,0x7f,0x01,0x2d,0x02,0x8f,0x86,0x17,0x00,0x00,0x00, +0x00,0x02,0x00,0x78,0xff,0xf5,0x03,0x1e,0x03,0x2c,0x00,0x0d,0x00,0x1b,0x00,0x09,0x40,0x06,0x10,0x17,0x09,0x02,0x02,0x0b,0x2b,0x01,0x14,0x06,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x33,0x32,0x16,0x15,0x27,0x34,0x26,0x23,0x22,0x06,0x1d,0x01,0x14,0x16,0x33,0x32,0x36,0x35,0x03,0x1e,0xbb,0x97,0x99,0xbb,0xba,0x98,0x98,0xbc,0xad, +0x59,0x4e,0x4e,0x58,0x59,0x4f,0x4d,0x58,0x01,0x1b,0x88,0x9e,0x9e,0x88,0xeb,0x86,0xa0,0xa0,0x86,0x01,0x4c,0x56,0x56,0x4c,0xec,0x4e,0x56,0x56,0x4e,0x00,0x00,0x00,0x00,0x02,0x00,0x47,0xff,0xef,0x03,0xa0,0x04,0x9d,0x00,0x1a,0x00,0x27,0x00,0x09,0x40,0x06,0x21,0x1b,0x0c,0x13,0x02,0x0b,0x2b,0x25,0x32,0x36,0x3d,0x01,0x0e,0x01, +0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x11,0x14,0x04,0x23,0x22,0x26,0x27,0x37,0x1e,0x01,0x13,0x32,0x36,0x37,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x01,0xde,0x6c,0x91,0x2d,0x7f,0x48,0xc3,0xdd,0xf0,0xbe,0xb9,0xf2,0xff,0x00,0xc2,0x44,0x94,0x43,0x1f,0x3c,0x75,0x5b,0x58,0x7c,0x19,0x85,0x63,0x66,0x80,0x74, +0x87,0x94,0x6e,0x75,0x32,0x34,0xcf,0xaf,0xa6,0xe1,0xf9,0xc3,0xfe,0xa9,0xb5,0xe6,0x1a,0x18,0x95,0x1a,0x15,0x01,0xa3,0x4a,0x36,0x37,0x7c,0xa7,0x92,0x5c,0x66,0x86,0x00,0x03,0x00,0x58,0xff,0xef,0x03,0xc9,0x04,0x9d,0x00,0x17,0x00,0x23,0x00,0x2f,0x00,0x0b,0x40,0x08,0x26,0x2c,0x1a,0x20,0x14,0x08,0x03,0x0b,0x2b,0x01,0x14,0x06, +0x07,0x1e,0x01,0x15,0x14,0x06,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x36,0x33,0x32,0x16,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x03,0xa6,0x66,0x56,0x66,0x79,0xf7,0xb9,0xc2,0xff,0x7b,0x6a,0x5b,0x68,0xe9,0xb4,0xac,0xe3,0xa3, +0x8b,0x61,0x69,0x91,0x91,0x6b,0x62,0x88,0x23,0x77,0x52,0x5d,0x7b,0x7d,0x5d,0x53,0x74,0x03,0x5c,0x57,0x84,0x25,0x27,0x90,0x5e,0xa2,0xb6,0xb6,0xa2,0x5e,0x91,0x26,0x25,0x84,0x57,0x99,0xa8,0xa8,0xfd,0x56,0x54,0x6f,0x6f,0x54,0x57,0x6d,0x6d,0x02,0x64,0x4a,0x62,0x5e,0x4e,0x4d,0x63,0x63,0x00,0x01,0x00,0x47,0x00,0x00,0x03,0x67, +0x04,0x8d,0x00,0x0c,0x00,0x07,0x40,0x04,0x0b,0x04,0x01,0x0b,0x2b,0x01,0x06,0x02,0x11,0x15,0x23,0x35,0x10,0x12,0x37,0x21,0x35,0x21,0x03,0x67,0xbd,0xa3,0xc5,0xe7,0x8e,0xfd,0x90,0x03,0x20,0x03,0xf4,0xe8,0xfe,0xc0,0xfe,0xed,0xb9,0xb9,0x01,0x0c,0x01,0x96,0x99,0x99,0x00,0x03,0x00,0x82,0xff,0xeb,0x04,0x37,0x05,0xc5,0x00,0x17, +0x00,0x23,0x00,0x2f,0x00,0x0b,0x40,0x08,0x26,0x2c,0x1a,0x20,0x14,0x08,0x03,0x0b,0x2b,0x01,0x14,0x06,0x07,0x1e,0x01,0x15,0x14,0x04,0x23,0x22,0x24,0x35,0x34,0x36,0x37,0x2e,0x01,0x35,0x34,0x36,0x33,0x32,0x16,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32,0x36,0x03,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x33,0x32, +0x36,0x04,0x0e,0x81,0x6d,0x7e,0x99,0xfe,0xfa,0xc9,0xd6,0xfe,0xf0,0x9c,0x85,0x73,0x85,0xf7,0xc4,0xb9,0xef,0x9c,0x9b,0x71,0x7c,0xa3,0xa3,0x7e,0x72,0x98,0x29,0x83,0x60,0x6d,0x89,0x8c,0x6c,0x60,0x81,0x04,0x34,0x72,0xa8,0x28,0x29,0xb5,0x7c,0xca,0xe3,0xe2,0xcb,0x7c,0xb5,0x29,0x27,0xa9,0x72,0xc0,0xd1,0xd1,0xfc,0xa0,0x77,0x9a, +0x9a,0x77,0x7a,0x95,0x95,0x03,0x1f,0x69,0x88,0x83,0x6e,0x6f,0x8a,0x8a,0x00,0x00,0x00,0x02,0x00,0x5c,0xff,0xeb,0x04,0x20,0x05,0xc5,0x00,0x1a,0x00,0x27,0x00,0x09,0x40,0x06,0x21,0x1b,0x0c,0x13,0x02,0x0b,0x2b,0x25,0x32,0x36,0x3d,0x01,0x0e,0x01,0x23,0x22,0x26,0x35,0x34,0x00,0x33,0x32,0x00,0x15,0x11,0x14,0x00,0x23,0x22,0x26, +0x27,0x37,0x1e,0x01,0x13,0x32,0x36,0x37,0x35,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x16,0x02,0x1c,0x8e,0xb0,0x35,0xa3,0x5f,0xdf,0xe8,0x01,0x09,0xcb,0xdc,0x01,0x14,0xfe,0xe0,0xe4,0x52,0xac,0x4a,0x1f,0x45,0x8a,0x61,0x72,0xa2,0x23,0x9f,0x85,0x7d,0x98,0x7d,0x85,0xba,0xa9,0xa9,0x49,0x4c,0xe7,0xef,0xdf,0x01,0x14,0xfe,0xec,0xf8, +0xfe,0x31,0xf2,0xfe,0xf3,0x20,0x1f,0x96,0x20,0x1b,0x02,0x12,0x5c,0x45,0x8a,0xaa,0xbe,0xbb,0x9d,0xa0,0x9b,0x00,0x00,0x00,0x00,0x02,0x00,0x99,0x00,0x00,0x04,0x1f,0x04,0x8d,0x00,0x0a,0x00,0x13,0x00,0x09,0x40,0x06,0x11,0x0b,0x03,0x01,0x02,0x0b,0x2b,0x01,0x11,0x23,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x23,0x25,0x21,0x32,0x36, +0x35,0x34,0x26,0x23,0x21,0x01,0x5e,0xc5,0x01,0xd2,0xcb,0xe9,0xe9,0xcb,0xfe,0xf3,0x01,0x0d,0x75,0x79,0x79,0x75,0xfe,0xf3,0x01,0xa4,0xfe,0x5c,0x04,0x8d,0xd0,0xa5,0xa6,0xce,0x9a,0x7e,0x5a,0x5c,0x82,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x44,0x1b,0xa1,0x2d,0x5f,0x0f,0x3c,0xf5,0x00,0x09,0x08,0x00,0x00,0x00,0x00,0x00, +0xc4,0xf0,0x11,0x2e,0x00,0x00,0x00,0x00,0xca,0xfb,0x6b,0xe6,0xfc,0x2c,0xfd,0xd5,0x09,0x5c,0x08,0x73,0x00,0x00,0x00,0x09,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x07,0x6c,0xfe,0x0c,0x00,0x00,0x09,0x7a,0xfc,0x2c,0xff,0x3f,0x09,0x5c,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x04,0x0d,0x01,0xfd,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xfd,0x00,0x00,0x01,0xfd,0x00,0x00,0x02,0x1b,0x00,0xab,0x02,0xdd,0x00,0x7e,0x04,0xfc,0x00,0x46,0x04,0xa9,0x00,0x7f,0x05,0xda,0x00,0x68,0x04,0xfc,0x00,0x40,0x01,0xbd,0x00,0x7e,0x02,0xa7,0x00,0x84,0x02,0xaf,0x00,0x06,0x03,0x74,0x00,0x58,0x04,0x8a,0x00,0x4e, +0x01,0x94,0x00,0x30,0x03,0x9b,0x00,0xa7,0x02,0x24,0x00,0xa1,0x03,0x52,0x00,0x10,0x04,0x81,0x00,0x71,0x04,0x81,0x00,0xc3,0x04,0x81,0x00,0x85,0x04,0x81,0x00,0x73,0x04,0x81,0x00,0x48,0x04,0x81,0x00,0x98,0x04,0x81,0x00,0x89,0x04,0x81,0x00,0x61,0x04,0x81,0x00,0x66,0x04,0x81,0x00,0x5d,0x02,0x05,0x00,0xa1,0x02,0x0d,0x00,0x63, +0x04,0x10,0x00,0x47,0x04,0x81,0x00,0x98,0x04,0x30,0x00,0x88,0x03,0xce,0x00,0x3a,0x07,0x29,0x00,0x60,0x05,0x0f,0x00,0x2b,0x05,0x16,0x00,0xaa,0x05,0x11,0x00,0x76,0x05,0x6b,0x00,0xaa,0x04,0x6a,0x00,0xaa,0x04,0x6a,0x00,0xaa,0x05,0x6b,0x00,0x79,0x05,0xa1,0x00,0xaa,0x02,0x43,0x00,0xbe,0x04,0x63,0x00,0x4a,0x05,0x16,0x00,0xaa, +0x04,0x66,0x00,0xaa,0x06,0xf3,0x00,0xaa,0x05,0xa2,0x00,0xaa,0x05,0x74,0x00,0x71,0x05,0x16,0x00,0xaa,0x05,0x93,0x00,0x71,0x05,0x17,0x00,0xaa,0x04,0xe4,0x00,0x6d,0x04,0xc9,0x00,0x25,0x05,0x6a,0x00,0x93,0x05,0x0f,0x00,0x16,0x06,0xe3,0x00,0x25,0x05,0x0f,0x00,0x42,0x05,0x0f,0x00,0x28,0x04,0xc9,0x00,0x61,0x02,0x28,0x00,0x8f, +0x03,0x4e,0x00,0x27,0x02,0x28,0x00,0x0b,0x03,0x58,0x00,0x3d,0x03,0xa3,0x00,0x04,0x02,0x81,0x00,0x52,0x04,0x66,0x00,0x6a,0x04,0x8c,0x00,0x8f,0x04,0x30,0x00,0x61,0x04,0x8c,0x00,0x62,0x04,0x30,0x00,0x61,0x02,0xa2,0x00,0x38,0x04,0x8c,0x00,0x6c,0x04,0x8c,0x00,0x8f,0x02,0x04,0x00,0x9f,0x02,0x12,0xff,0xbe,0x04,0x1a,0x00,0x90, +0x02,0x04,0x00,0x9f,0x06,0xfe,0x00,0x8f,0x04,0x8c,0x00,0x8f,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x8f,0x04,0x8c,0x00,0x62,0x02,0xcd,0x00,0x8f,0x04,0x2f,0x00,0x67,0x02,0xb2,0x00,0x30,0x04,0x8c,0x00,0x8b,0x04,0x06,0x00,0x2e,0x06,0x0e,0x00,0x2d,0x04,0x06,0x00,0x2e,0x04,0x06,0x00,0x1a,0x04,0x06,0x00,0x5e,0x02,0xb8,0x00,0x3f, +0x01,0xfb,0x00,0x91,0x02,0xb8,0x00,0x15,0x05,0x6f,0x00,0x80,0x01,0xfd,0x00,0x00,0x01,0xfb,0x00,0x90,0x04,0x62,0x00,0x61,0x04,0xaa,0x00,0x46,0x05,0xb0,0x00,0x68,0x04,0xdb,0x00,0x1e,0x01,0xf3,0x00,0x91,0x04,0xeb,0x00,0x5a,0x03,0xfd,0x00,0xaa,0x06,0x44,0x00,0x58,0x03,0x95,0x00,0x78,0x03,0xc6,0x00,0x61,0x04,0x71,0x00,0x7f, +0x03,0x9b,0x00,0xa7,0x06,0x44,0x00,0x58,0x03,0xb6,0x00,0x7b,0x02,0xfb,0x00,0x80,0x04,0x49,0x00,0x63,0x03,0x64,0x00,0x71,0x03,0x6c,0x00,0x6a,0x02,0x8e,0x00,0x83,0x04,0x8c,0x00,0x99,0x03,0xee,0x00,0x3f,0x02,0x1c,0x00,0xa1,0x01,0xfd,0x00,0x77,0x02,0x2d,0x00,0x5f,0x03,0xa5,0x00,0x78,0x03,0xc6,0x00,0x74,0x06,0x3b,0x00,0xb8, +0x06,0xac,0x00,0xb8,0x06,0xf5,0x00,0x7a,0x03,0xf5,0x00,0x72,0x05,0x0f,0x00,0x2b,0x05,0x0f,0x00,0x2b,0x05,0x0f,0x00,0x2b,0x05,0x0f,0x00,0x2b,0x05,0x0f,0x00,0x2b,0x05,0x0f,0x00,0x2b,0x07,0xcf,0x00,0x0e,0x05,0x11,0x00,0x76,0x04,0x6a,0x00,0xaa,0x04,0x6a,0x00,0xaa,0x04,0x6a,0x00,0xaa,0x04,0x6a,0x00,0xaa,0x02,0x43,0xff,0xdd, +0x02,0x43,0x00,0xbe,0x02,0x43,0xff,0xf0,0x02,0x43,0xff,0xca,0x05,0x6b,0x00,0x02,0x05,0xa2,0x00,0xaa,0x05,0x74,0x00,0x71,0x05,0x74,0x00,0x71,0x05,0x74,0x00,0x71,0x05,0x74,0x00,0x71,0x05,0x74,0x00,0x71,0x04,0x48,0x00,0x58,0x05,0x74,0x00,0x71,0x05,0x6a,0x00,0x93,0x05,0x6a,0x00,0x93,0x05,0x6a,0x00,0x93,0x05,0x6a,0x00,0x93, +0x05,0x0f,0x00,0x28,0x04,0xb9,0x00,0xa3,0x04,0xc5,0x00,0x89,0x04,0x66,0x00,0x6a,0x04,0x66,0x00,0x6a,0x04,0x66,0x00,0x6a,0x04,0x66,0x00,0x6a,0x04,0x66,0x00,0x6a,0x04,0x66,0x00,0x6a,0x06,0xfd,0x00,0x58,0x04,0x30,0x00,0x61,0x04,0x30,0x00,0x61,0x04,0x30,0x00,0x61,0x04,0x30,0x00,0x61,0x04,0x30,0x00,0x61,0x02,0x03,0xff,0xb8, +0x02,0x03,0x00,0x99,0x02,0x03,0xff,0xcb,0x02,0x03,0xff,0xa5,0x04,0xb2,0x00,0x48,0x04,0x8c,0x00,0x8f,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x61,0x04,0x92,0x00,0x47,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x8b,0x04,0x8c,0x00,0x8b,0x04,0x8c,0x00,0x8b,0x04,0x8c,0x00,0x8b, +0x04,0x06,0x00,0x1a,0x04,0xa2,0x00,0x99,0x04,0x06,0x00,0x1a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x11,0x00,0x76,0x04,0x30,0x00,0x61,0x05,0x11,0x00,0x76,0x04,0x30,0x00,0x61,0x05,0x11,0x00,0x76,0x04,0x30,0x00,0x61,0x05,0x11,0x00,0x76, +0x04,0x30,0x00,0x61,0x05,0x6b,0x00,0xaa,0x04,0x8c,0x00,0x62,0x05,0x6b,0x00,0x02,0x04,0x8c,0x00,0x62,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x05,0x6b,0x00,0x79, +0x04,0x8c,0x00,0x6c,0x05,0x6b,0x00,0x79,0x04,0x8c,0x00,0x6c,0x05,0x6b,0x00,0x79,0x04,0x8c,0x00,0x6c,0x05,0x6b,0x00,0x79,0x04,0x8c,0x00,0x6c,0x05,0xa1,0x00,0xaa,0x04,0x8c,0x00,0x8f,0x05,0x9f,0x00,0x1f,0x04,0x8c,0xff,0xe4,0x02,0x43,0xff,0xc7,0x02,0x03,0xff,0xa2,0x02,0x43,0xff,0xbf,0x02,0x03,0xff,0x9a,0x02,0x43,0xff,0xf7, +0x02,0x03,0xff,0xd2,0x02,0x43,0x00,0x2d,0x02,0x04,0x00,0x0d,0x02,0x43,0x00,0xb4,0x02,0x03,0x00,0x99,0x06,0xa6,0x00,0xbe,0x04,0x16,0x00,0x9f,0x04,0x63,0x00,0x4a,0x02,0x0b,0xff,0xbc,0x05,0x16,0x00,0xaa,0x04,0x1a,0x00,0x90,0x04,0x78,0x00,0x99,0x04,0x66,0x00,0xaa,0x02,0x04,0x00,0x9f,0x04,0x66,0x00,0xaa,0x02,0x04,0x00,0x6e, +0x04,0x66,0x00,0xaa,0x02,0x04,0x00,0x9f,0x04,0x66,0x00,0xaa,0x02,0x04,0x00,0x9f,0x04,0x35,0x00,0x28,0x02,0x2e,0x00,0x25,0x05,0xa2,0x00,0xaa,0x04,0x8c,0x00,0x8f,0x05,0xa2,0x00,0xaa,0x04,0x8c,0x00,0x8f,0x05,0xa2,0x00,0xaa,0x04,0x8c,0x00,0x8f,0x04,0x8c,0xff,0xdf,0x05,0x88,0x00,0xa1,0x04,0x8c,0x00,0x8f,0x05,0x74,0x00,0x71, +0x04,0x8c,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x07,0xa8,0x00,0x68,0x07,0x3e,0x00,0x61,0x05,0x17,0x00,0xaa,0x02,0xcd,0x00,0x8f,0x05,0x17,0x00,0xaa,0x02,0xcd,0x00,0x6b,0x05,0x17,0x00,0xaa,0x02,0xcd,0x00,0x64,0x04,0xe4,0x00,0x6d,0x04,0x2f,0x00,0x67,0x04,0xe4,0x00,0x6d, +0x04,0x2f,0x00,0x67,0x04,0xe4,0x00,0x6d,0x04,0x2f,0x00,0x67,0x04,0xe4,0x00,0x6d,0x04,0x2f,0x00,0x67,0x04,0xc9,0x00,0x25,0x02,0xb2,0x00,0x30,0x04,0xc9,0x00,0x25,0x02,0xb2,0x00,0x30,0x04,0xc9,0x00,0x25,0x02,0xb2,0x00,0x06,0x05,0x6a,0x00,0x93,0x04,0x8c,0x00,0x8b,0x05,0x6a,0x00,0x93,0x04,0x8c,0x00,0x8b,0x05,0x6a,0x00,0x93, +0x04,0x8c,0x00,0x8b,0x05,0x6a,0x00,0x93,0x04,0x8c,0x00,0x8b,0x05,0x6a,0x00,0x93,0x04,0x8c,0x00,0x8b,0x05,0x6a,0x00,0x93,0x04,0x8c,0x00,0x8b,0x06,0xe3,0x00,0x25,0x06,0x0e,0x00,0x2d,0x05,0x0f,0x00,0x28,0x04,0x06,0x00,0x1a,0x05,0x0f,0x00,0x28,0x04,0xc9,0x00,0x61,0x04,0x06,0x00,0x5e,0x04,0xc9,0x00,0x61,0x04,0x06,0x00,0x5e, +0x04,0xc9,0x00,0x61,0x04,0x06,0x00,0x5e,0x02,0x04,0x00,0x9f,0x02,0xbe,0xff,0xe9,0x05,0x7b,0x00,0x6c,0x04,0x97,0x00,0x61,0x05,0x96,0x00,0x93,0x04,0xb4,0x00,0x8b,0x02,0x0b,0xff,0xbc,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x07,0xcf,0x00,0x0e,0x06,0xfd,0x00,0x58,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x04,0xe4,0x00,0x6d, +0x04,0x2f,0x00,0x67,0x02,0x0b,0xff,0xbc,0x02,0x04,0x00,0xa0,0x03,0xd3,0x00,0xab,0x03,0x9a,0x00,0x8c,0x03,0x6c,0x00,0x81,0x02,0x2c,0x00,0xa0,0x02,0xb8,0x00,0xa5,0x02,0x32,0x00,0x44,0x03,0xd3,0x00,0x87,0x02,0xfa,0x00,0x64,0x02,0xa0,0x00,0xb6,0x00,0x00,0xfc,0xe6,0x00,0x00,0xfd,0x81,0x00,0x00,0xfc,0x8c,0x00,0x00,0xfd,0x5b, +0x00,0x00,0xfc,0x2c,0x00,0x00,0xfd,0x3c,0x02,0x0e,0x00,0xce,0x04,0x15,0x00,0xa1,0x05,0x0f,0x00,0x2b,0x02,0x1d,0x00,0xa1,0x04,0x6a,0xff,0x80,0x05,0xa1,0xff,0xb1,0x02,0x43,0xff,0xbf,0x05,0x74,0x00,0x3c,0x05,0x0f,0xff,0x3c,0x05,0x56,0x00,0x33,0x02,0xa0,0xff,0xcc,0x05,0x0f,0x00,0x2b,0x05,0x16,0x00,0xaa,0x04,0x63,0x00,0xa3, +0x05,0xa7,0x00,0x1e,0x04,0x6a,0x00,0xaa,0x04,0xc9,0x00,0x61,0x05,0xa1,0x00,0xaa,0x05,0x74,0x00,0x71,0x02,0x43,0x00,0xbe,0x05,0x16,0x00,0xaa,0x05,0x41,0x00,0x31,0x06,0xf3,0x00,0xaa,0x05,0xa2,0x00,0xaa,0x04,0x95,0x00,0x7b,0x05,0x74,0x00,0x71,0x05,0x9f,0x00,0xa8,0x05,0x16,0x00,0xaa,0x04,0x95,0x00,0x46,0x04,0xc9,0x00,0x25, +0x05,0x0f,0x00,0x28,0x05,0x9f,0x00,0x54,0x05,0x0f,0x00,0x42,0x05,0x88,0x00,0x57,0x05,0x56,0x00,0x70,0x02,0x43,0xff,0xca,0x05,0x0f,0x00,0x28,0x04,0x86,0x00,0x62,0x04,0x4f,0x00,0x62,0x04,0x8c,0x00,0x8f,0x02,0xa0,0x00,0xc5,0x04,0x8c,0x00,0x8d,0x04,0x86,0x00,0x62,0x04,0xbd,0x00,0x9d,0x04,0x07,0x00,0x2e,0x04,0x8c,0x00,0x61, +0x04,0x4f,0x00,0x62,0x04,0x2f,0x00,0x73,0x04,0x8c,0x00,0x8f,0x04,0x8d,0x00,0x77,0x02,0xa0,0x00,0xc5,0x04,0x78,0x00,0x99,0x04,0x8c,0x00,0x38,0x04,0x8c,0x00,0x99,0x04,0x06,0x00,0x2e,0x04,0x13,0x00,0x56,0x04,0x8c,0x00,0x61,0x04,0xa5,0x00,0x4f,0x04,0x8c,0x00,0x8f,0x04,0x4e,0x00,0x62,0x04,0x8c,0x00,0x61,0x04,0x30,0x00,0x51, +0x04,0x8c,0x00,0x8d,0x05,0xaa,0x00,0x53,0x04,0x8c,0x00,0x5f,0x05,0xa0,0x00,0x5b,0x06,0xcd,0x00,0x6c,0x02,0xa0,0xff,0xd7,0x04,0x8c,0x00,0x8d,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x8d,0x06,0xcd,0x00,0x6c,0x04,0xf1,0x00,0x71,0x04,0x41,0xff,0xea,0x06,0x48,0x00,0x4e,0x04,0x6a,0x00,0xaa,0x04,0x6a,0x00,0xaa,0x05,0xea,0x00,0x39, +0x04,0x63,0x00,0xa3,0x05,0x6a,0x00,0x87,0x04,0xe4,0x00,0x6d,0x02,0x43,0x00,0xbe,0x02,0x43,0xff,0xca,0x04,0x63,0x00,0x4a,0x08,0x99,0x00,0x32,0x08,0x99,0x00,0xa8,0x06,0x86,0x00,0x49,0x05,0x16,0x00,0xaa,0x05,0xa0,0x00,0xad,0x05,0x11,0x00,0x42,0x05,0x9f,0x00,0xa8,0x05,0x0f,0x00,0x2b,0x05,0x0c,0x00,0xa3,0x05,0x16,0x00,0xaa, +0x04,0x63,0x00,0xa3,0x06,0x27,0x00,0x36,0x04,0x6a,0x00,0xaa,0x06,0x97,0x00,0x1a,0x05,0x69,0x00,0x78,0x05,0xa0,0x00,0xad,0x05,0xa0,0x00,0xad,0x05,0x16,0x00,0xaa,0x05,0x9f,0x00,0x31,0x06,0xf3,0x00,0xaa,0x05,0xa1,0x00,0xaa,0x05,0x74,0x00,0x71,0x05,0x9f,0x00,0xa8,0x05,0x16,0x00,0xaa,0x05,0x11,0x00,0x76,0x04,0xc9,0x00,0x25, +0x05,0x11,0x00,0x42,0x05,0x9f,0x00,0x54,0x05,0x0f,0x00,0x42,0x05,0xfd,0x00,0xa1,0x05,0x75,0x00,0x93,0x08,0x1f,0x00,0xa4,0x08,0x64,0x00,0xa4,0x05,0xb2,0x00,0x00,0x06,0xd5,0x00,0xa3,0x05,0x0a,0x00,0xa3,0x05,0x69,0x00,0xb5,0x07,0x21,0x00,0xbe,0x04,0xbb,0x00,0x2c,0x04,0x66,0x00,0x6a,0x04,0x6d,0x00,0x61,0x04,0x8c,0x00,0x90, +0x03,0x51,0x00,0x8f,0x05,0x11,0x00,0x45,0x04,0x30,0x00,0x61,0x05,0xc1,0x00,0x1a,0x04,0x4f,0x00,0x64,0x04,0x8c,0x00,0x8f,0x04,0x8c,0x00,0x8f,0x04,0x60,0x00,0x99,0x04,0x6d,0x00,0x1a,0x05,0xf8,0x00,0x99,0x04,0x8c,0x00,0x8f,0x04,0x8c,0x00,0x61,0x04,0x8c,0x00,0x8f,0x04,0x8c,0x00,0x8f,0x04,0x30,0x00,0x61,0x04,0x18,0x00,0x47, +0x04,0x06,0x00,0x1a,0x07,0x22,0x00,0x62,0x04,0x06,0x00,0x2e,0x04,0xc2,0x00,0x8f,0x04,0x6b,0x00,0x7f,0x06,0x6d,0x00,0x8f,0x06,0xc4,0x00,0x8f,0x04,0xfa,0x00,0x2d,0x06,0x51,0x00,0xad,0x04,0x59,0x00,0x99,0x04,0x4e,0x00,0x63,0x06,0x87,0x00,0x99,0x04,0x8b,0x00,0x4e,0x04,0x30,0x00,0x61,0x04,0x30,0x00,0x61,0x04,0x8c,0xff,0xf2, +0x03,0x51,0x00,0x8f,0x04,0x4f,0x00,0x61,0x04,0x2f,0x00,0x67,0x02,0x04,0x00,0x9f,0x02,0x03,0xff,0xa5,0x02,0x12,0xff,0xbe,0x06,0xf6,0x00,0x41,0x06,0xf5,0x00,0x8f,0x04,0x8c,0x00,0x13,0x04,0x60,0x00,0x99,0x04,0x8c,0x00,0x8f,0x04,0x06,0x00,0x1a,0x04,0x8c,0x00,0x8f,0x07,0x8e,0x00,0x78,0x05,0x82,0x00,0x2e,0x05,0x0a,0xff,0xcd, +0x04,0x59,0xff,0xdb,0x07,0x2d,0x00,0xbf,0x05,0xfa,0x00,0x97,0x04,0xd3,0x00,0x2b,0x04,0x49,0x00,0x0d,0x07,0x0d,0x00,0xd1,0x06,0x0d,0x00,0xba,0x06,0xdf,0x00,0x95,0x05,0xec,0x00,0x95,0x09,0x16,0x00,0xbe,0x07,0xe3,0x00,0x99,0x04,0x25,0x00,0x4a,0x03,0xda,0x00,0x49,0x05,0x88,0x00,0x57,0x05,0xa0,0x00,0x5b,0x05,0x74,0x00,0x71, +0x04,0x8d,0x00,0x61,0x05,0x0f,0x00,0x16,0x04,0x07,0x00,0x2e,0x05,0x0f,0x00,0x16,0x04,0x07,0xff,0xfe,0x09,0x7a,0x00,0x71,0x08,0x92,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x07,0x8e,0x00,0x78,0x06,0x76,0x00,0x78,0x07,0x8e,0x00,0x78,0x05,0x82,0x00,0x2e,0x05,0x38,0x00,0x76,0x04,0x4b,0x00,0x62,0x05,0x02,0x00,0x70, +0x04,0x8d,0x00,0xd4,0x04,0xb9,0x00,0xfb,0x03,0x13,0x01,0x00,0x03,0x4f,0x01,0x2c,0x08,0x1c,0x00,0x3b,0x07,0xd8,0x00,0x4d,0x05,0xa0,0x00,0xad,0x04,0x8c,0x00,0x8f,0x05,0x0a,0xff,0xcd,0x04,0x59,0xff,0xba,0x05,0x0d,0x00,0xa3,0x04,0x8b,0x00,0x8f,0x04,0x64,0x00,0xa3,0x03,0x93,0x00,0x8f,0x04,0x63,0xff,0xeb,0x03,0x51,0xff,0xf3, +0x04,0xd6,0x00,0xa3,0x04,0x08,0x00,0x8f,0x06,0x97,0x00,0x1a,0x05,0xc1,0x00,0x1a,0x05,0x69,0x00,0x78,0x04,0x4f,0x00,0x64,0x05,0x16,0x00,0xaa,0x04,0x60,0x00,0x99,0x05,0x0f,0x00,0xa3,0x04,0x68,0x00,0x99,0x05,0x16,0xff,0xd7,0x04,0x1a,0xff,0xbb,0x06,0xd3,0x00,0x4a,0x05,0xc6,0x00,0x32,0x05,0xa1,0x00,0xaa,0x04,0x8c,0x00,0x8f, +0x07,0xb9,0x00,0xa9,0x05,0xb0,0x00,0x8f,0x08,0x26,0x00,0xa8,0x06,0xfc,0x00,0x8f,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x11,0x00,0x76,0x04,0x30,0x00,0x61,0x04,0xc9,0x00,0x25,0x04,0x18,0x00,0x47,0x05,0x0f,0x00,0x28,0x04,0x07,0x00,0x2e,0x05,0x0f,0x00,0x28,0x04,0x07,0x00,0x2e,0x05,0x0f,0x00,0x42,0x04,0x06,0x00,0x2e, +0x07,0x37,0x00,0x37,0x05,0x93,0x00,0x20,0x05,0x75,0x00,0x93,0x04,0x6b,0x00,0x7f,0x05,0x76,0x00,0x93,0x04,0x6c,0x00,0x7f,0x05,0x76,0x00,0x8a,0x04,0x6c,0x00,0x94,0x06,0xcb,0x00,0x4d,0x04,0xbf,0xff,0xdf,0x06,0xcb,0x00,0x4d,0x04,0xbf,0xff,0xdf,0x02,0x43,0x00,0xbe,0x06,0x97,0x00,0x1a,0x05,0xc1,0x00,0x1a,0x05,0x0f,0x00,0xa3, +0x04,0x60,0x00,0x99,0x05,0x9f,0x00,0x31,0x04,0x6d,0x00,0x1a,0x05,0x9f,0x00,0xa9,0x04,0x8c,0x00,0x8f,0x05,0xa1,0x00,0xaa,0x04,0x8c,0x00,0x8f,0x05,0x75,0x00,0x93,0x04,0x6b,0x00,0x7f,0x06,0xf3,0x00,0xaa,0x05,0xf8,0x00,0x99,0x02,0x43,0x00,0xbe,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a, +0x07,0xcf,0x00,0x0e,0x06,0xfd,0x00,0x58,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x05,0x91,0x00,0x59,0x04,0x42,0x00,0x81,0x05,0x91,0x00,0x59,0x04,0x42,0x00,0x81,0x06,0x97,0x00,0x1a,0x05,0xc1,0x00,0x1a,0x05,0x69,0x00,0x78,0x04,0x4f,0x00,0x64,0x04,0xaa,0x00,0x69,0x04,0xaa,0x00,0x69,0x05,0xa0,0x00,0xad,0x04,0x8c,0x00,0x8f, +0x05,0xa0,0x00,0xad,0x04,0x8c,0x00,0x8f,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8d,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8d,0x00,0x61,0x05,0x69,0x00,0xb5,0x04,0x4e,0x00,0x63,0x05,0x11,0x00,0x42,0x04,0x06,0x00,0x1a,0x05,0x11,0x00,0x42,0x04,0x06,0x00,0x1a,0x05,0x11,0x00,0x42,0x04,0x06,0x00,0x1a, +0x05,0x75,0x00,0x93,0x04,0x6b,0x00,0x7f,0x04,0x63,0x00,0xa3,0x03,0x51,0x00,0x8f,0x06,0xd5,0x00,0xa3,0x06,0x51,0x00,0xad,0x04,0xbf,0x00,0x40,0x03,0x49,0x00,0x41,0x05,0x0f,0x00,0x42,0x04,0x06,0x00,0x2e,0x05,0x0f,0x00,0x42,0x04,0x06,0x00,0x2e,0x05,0x07,0x00,0x5b,0x04,0x8c,0x00,0x62,0x06,0xa4,0x00,0x5b,0x06,0xe5,0x00,0x62, +0x06,0x57,0x00,0x36,0x05,0x2c,0x00,0x31,0x04,0x4b,0x00,0x50,0x04,0x09,0x00,0x7b,0x07,0xc2,0x00,0x45,0x06,0x76,0x00,0x41,0x08,0x03,0x00,0xa9,0x06,0xa2,0x00,0x8f,0x04,0xf7,0x00,0x76,0x04,0x1e,0x00,0x62,0x05,0xae,0x00,0x24,0x05,0x21,0x00,0x46,0x05,0x69,0x00,0x9c,0x04,0x4f,0x00,0x62,0x05,0x9f,0x00,0x31,0x04,0x6d,0x00,0x1a, +0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x06,0xf3,0x00,0xaa,0x06,0xfe,0x00,0x8f,0x06,0xe3,0x00,0x25,0x06,0x0e,0x00,0x2d,0x06,0xe3,0x00,0x25,0x06,0x0e,0x00,0x2d,0x06,0xe3,0x00,0x25,0x06,0x0e,0x00,0x2d,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a, +0x05,0x0f,0x00,0x00,0x04,0x66,0xff,0xa3,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a, +0x05,0x0f,0x00,0x2b,0x04,0x66,0x00,0x6a,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0xff,0xe3,0x04,0x30,0xff,0x93,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61, +0x04,0x6a,0x00,0xaa,0x04,0x30,0x00,0x61,0x02,0x43,0x00,0xbe,0x02,0x03,0x00,0x99,0x02,0x43,0x00,0xb4,0x02,0x04,0x00,0x95,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x74,0x00,0x32,0x04,0x8c,0xff,0xbe,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61, +0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x74,0x00,0x71,0x04,0x8c,0x00,0x61,0x05,0x7b,0x00,0x6c,0x04,0x97,0x00,0x61,0x05,0x7b,0x00,0x6c,0x04,0x97,0x00,0x61,0x05,0x7b,0x00,0x6c,0x04,0x97,0x00,0x61,0x05,0x7b,0x00,0x6c,0x04,0x8c,0x00,0x61,0x05,0x7b,0x00,0x6c,0x04,0x97,0x00,0x61,0x05,0x6a,0x00,0x93,0x04,0x8c,0x00,0x8b, +0x05,0x6a,0x00,0x93,0x04,0x8c,0x00,0x8b,0x05,0x96,0x00,0x93,0x04,0xb4,0x00,0x8b,0x05,0x96,0x00,0x93,0x04,0xb4,0x00,0x8b,0x05,0x96,0x00,0x93,0x04,0xb4,0x00,0x8b,0x05,0x96,0x00,0x93,0x04,0xb4,0x00,0x8b,0x05,0x96,0x00,0x93,0x04,0xb4,0x00,0x8b,0x05,0x0f,0x00,0x28,0x04,0x06,0x00,0x1a,0x05,0x0f,0x00,0x28,0x04,0x06,0x00,0x1a, +0x05,0x0f,0x00,0x28,0x04,0x06,0x00,0x1a,0x05,0x0f,0x00,0x28,0x04,0x06,0x00,0x1a,0x05,0x74,0xff,0x25,0x04,0x14,0x00,0x00,0x08,0x29,0x00,0x00,0x04,0x14,0x00,0x00,0x08,0x29,0x00,0x00,0x02,0xb9,0x00,0x00,0x02,0x0a,0x00,0x00,0x01,0x5c,0x00,0x00,0x04,0x7f,0x00,0x00,0x02,0x30,0x00,0x00,0x01,0xa2,0x00,0x00,0x00,0xd1,0x00,0x00, +0x00,0x00,0x00,0x00,0x05,0x88,0x00,0xb3,0x06,0x7c,0x00,0xbb,0x06,0x7c,0x00,0xbb,0x03,0xa7,0x00,0x05,0x02,0x0c,0x00,0x91,0x02,0x04,0x00,0xa0,0x02,0x1c,0x00,0xa8,0x01,0xbc,0x00,0x55,0x03,0x14,0x00,0x7b,0x03,0x01,0x00,0x7d,0x02,0xff,0x00,0x8a,0x04,0x69,0x00,0x46,0x04,0x92,0x00,0x57,0x02,0xb7,0x00,0x89,0x03,0xca,0x00,0xa1, +0x05,0x64,0x00,0xa1,0x07,0xa4,0x00,0x40,0x01,0xbd,0x00,0x7e,0x02,0xdd,0x00,0x7e,0x02,0x67,0x00,0x6c,0x02,0x67,0x00,0x5e,0x04,0x36,0x00,0xab,0x03,0xa5,0x00,0x3b,0x03,0xad,0x00,0x47,0x03,0x60,0x00,0x7a,0x04,0x6a,0x00,0x11,0x04,0xaa,0x00,0x46,0x06,0x92,0x00,0xa4,0x04,0x8c,0x00,0x50,0x04,0x40,0x00,0x4f,0x05,0xe9,0x00,0x7c, +0x03,0xd2,0x00,0x6a,0x08,0xcc,0x00,0xaa,0x05,0x04,0x00,0x67,0x05,0x18,0x00,0x98,0x06,0xbf,0x00,0x6b,0x07,0x56,0x00,0x6e,0x07,0x86,0x00,0x6f,0x06,0xdf,0x00,0x6b,0x04,0xa2,0x00,0x48,0x05,0x9c,0x00,0xa8,0x04,0xb2,0x00,0x46,0x04,0x92,0x00,0xa8,0x04,0xd7,0x00,0x3f,0x08,0x2f,0x00,0x68,0x02,0x0d,0xff,0xbc,0x04,0x82,0x00,0x65, +0x04,0x30,0x00,0x98,0x04,0x38,0x00,0x9e,0x04,0x40,0x00,0x9a,0x04,0x08,0x00,0x29,0x02,0x08,0x00,0x65,0x04,0x74,0x00,0x1c,0x04,0xa6,0x00,0x38,0x07,0x16,0x00,0x38,0x07,0x48,0x00,0x38,0x00,0x00,0x00,0x00,0x08,0x34,0x00,0x5b,0x08,0x35,0x00,0x5c,0x04,0x71,0x00,0x5d,0x05,0x04,0x00,0x89,0x04,0x0a,0x00,0x6e,0x04,0x0f,0x00,0x6e, +0x04,0x0a,0xff,0x55,0x04,0x09,0x00,0x78,0x04,0xba,0x00,0x27,0x03,0xa5,0x00,0x6d,0x02,0x07,0x00,0xa0,0x04,0x79,0x00,0x99,0x04,0x92,0x00,0x70,0x04,0xaa,0x00,0x99,0x04,0x47,0x00,0x99,0x04,0x1f,0x00,0x99,0x04,0xd3,0x00,0x70,0x04,0xfb,0x00,0x99,0x02,0x03,0x00,0x99,0x04,0x0f,0x00,0x40,0x04,0x61,0x00,0x99,0x03,0xbd,0x00,0x99, +0x05,0xf8,0x00,0x99,0x03,0xa0,0x00,0x92,0x05,0x1c,0x00,0x99,0x04,0xcb,0x00,0x70,0x04,0xaa,0x00,0x7b,0x08,0xe2,0x00,0x5d,0x04,0x40,0x00,0x4e,0x04,0x40,0x00,0x4e,0x04,0x40,0x00,0x4e,0x04,0x61,0x00,0x1e,0x04,0x61,0x00,0x1e,0x06,0x02,0x00,0x3f,0x05,0x04,0x00,0x89,0x05,0x04,0x00,0x89,0x05,0x04,0x00,0x89,0x05,0x04,0x00,0x89, +0x05,0x04,0x00,0x89,0x05,0x04,0x00,0x89,0x04,0x30,0x00,0x47,0x04,0x30,0x00,0x47,0x04,0x71,0x00,0x5d,0x04,0x1f,0x00,0x5a,0x04,0x71,0x00,0x5d,0x04,0x71,0x00,0x5d,0x04,0xad,0x00,0x99,0x04,0xad,0x00,0x99,0x04,0xad,0x00,0x99,0x04,0xcb,0x00,0x70,0x04,0xcb,0x00,0x70,0x04,0xcb,0x00,0x70,0x05,0x1c,0x00,0x99,0x05,0x1c,0x00,0x99, +0x05,0x1c,0x00,0x99,0x03,0xbd,0x00,0x99,0x03,0xbd,0x00,0x99,0x03,0xbd,0x00,0x99,0x03,0xbd,0x00,0x6a,0x04,0x61,0x00,0x99,0x04,0x0f,0x00,0x40,0x02,0x03,0x00,0x8e,0x02,0x03,0x00,0x3b,0x02,0x03,0xff,0xd0,0x02,0x03,0xff,0x98,0x02,0x03,0xff,0xa0,0x04,0xfb,0x00,0x99,0x04,0xd3,0x00,0x70,0x04,0xd3,0x00,0x70,0x04,0xd3,0x00,0x70, +0x04,0xd3,0x00,0x70,0x04,0x47,0x00,0x99,0x04,0x47,0x00,0x99,0x04,0x47,0x00,0x99,0x04,0x47,0x00,0x99,0x04,0x47,0x00,0x99,0x04,0xaa,0x00,0x99,0x04,0x92,0x00,0x70,0x04,0x92,0x00,0x70,0x04,0x92,0x00,0x70,0x04,0x92,0x00,0x70,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0x61,0x00,0x1e,0x05,0x04,0x00,0x89, +0x03,0xa4,0x00,0x81,0x05,0x04,0x00,0x89,0x05,0x04,0x00,0x89,0x04,0xcb,0x00,0x70,0x04,0xcb,0x00,0x70,0x04,0xcb,0x00,0x70,0x04,0xcb,0x00,0x70,0x04,0xcb,0x00,0x70,0x05,0x1c,0x00,0x99,0x02,0x03,0xff,0xa3,0x02,0x03,0xff,0xc9,0x02,0x03,0x00,0x99,0x02,0x03,0xff,0xb6,0x04,0x47,0x00,0x99,0x04,0x47,0x00,0x99,0x04,0x47,0x00,0x99, +0x04,0x47,0x00,0x99,0x04,0x92,0x00,0x70,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0xba,0x00,0x27,0x04,0x30,0x00,0x47,0x04,0xaa,0xff,0xf5,0x04,0xaa,0xff,0xf5,0x04,0xe3,0x00,0x70,0x04,0xad,0x00,0x99,0x03,0x6c,0x00,0x81,0x03,0xa4,0x00,0x81, +0x03,0xa5,0x00,0x81,0x01,0x91,0x00,0x60,0x02,0x31,0x00,0x13,0x02,0x04,0xff,0xbe,0x03,0x0c,0xff,0xa0,0x03,0x26,0x00,0x71,0x04,0x45,0x00,0x53,0x04,0xaa,0x00,0x69,0x04,0xaa,0x00,0x49,0x04,0xaa,0x00,0x84,0x04,0xaa,0x00,0x8e,0x03,0xfb,0x00,0x25,0x04,0x71,0x00,0x5d,0x04,0x30,0x00,0x47,0x05,0x04,0x00,0x89,0x04,0xbb,0x00,0x27, +0x06,0x02,0x00,0x3f,0x04,0x89,0x00,0x37,0x04,0x61,0x00,0x1e,0x04,0x40,0x00,0x4e,0x04,0x79,0x00,0x78,0x02,0x5e,0x00,0x4e,0x03,0xe5,0x00,0x59,0x04,0x16,0x00,0x5a,0x04,0x68,0x00,0x47,0x04,0x30,0x00,0x78,0x03,0x6c,0x00,0x68,0x03,0x84,0x00,0x70,0x03,0x4c,0x00,0x68,0x03,0x11,0x00,0x5f,0x03,0x7c,0x00,0x78,0x03,0x7c,0x00,0x72, +0x03,0x94,0x00,0x57,0x03,0x6c,0x00,0x6a,0x03,0x5b,0x00,0x71,0x02,0xb8,0x00,0x9b,0x02,0x2d,0x00,0x5f,0x03,0xa5,0x00,0x78,0x04,0x28,0x00,0x47,0x04,0x30,0x00,0x58,0x03,0xbd,0x00,0x47,0x04,0xaa,0x00,0x82,0x04,0xaa,0x00,0x5c,0x04,0x79,0x00,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x30,0x0e, +0x00,0x01,0x08,0x00,0x30,0x00,0x00,0x0b,0x00,0x00,0x00,0x05,0x00,0x05,0xff,0x95,0x00,0x05,0x00,0x0a,0xff,0x95,0x00,0x05,0x00,0x24,0xff,0x96,0x00,0x05,0x00,0x44,0xff,0xce,0x00,0x05,0x00,0x46,0xff,0xc5,0x00,0x05,0x00,0x47,0xff,0xc5,0x00,0x05,0x00,0x48,0xff,0xc5,0x00,0x05,0x00,0x4a,0xff,0xc5,0x00,0x05,0x00,0x50,0xff,0xec, +0x00,0x05,0x00,0x51,0xff,0xec,0x00,0x05,0x00,0x52,0xff,0xc3,0x00,0x05,0x00,0x53,0xff,0xec,0x00,0x05,0x00,0x54,0xff,0xc5,0x00,0x05,0x00,0x56,0xff,0xd6,0x00,0x05,0x00,0x82,0xff,0x96,0x00,0x05,0x00,0x83,0xff,0x96,0x00,0x05,0x00,0x84,0xff,0x96,0x00,0x05,0x00,0x85,0xff,0x96,0x00,0x05,0x00,0x86,0xff,0x96,0x00,0x05,0x00,0x87, +0xff,0x96,0x00,0x05,0x00,0xa2,0xff,0xce,0x00,0x05,0x00,0xa3,0xff,0xce,0x00,0x05,0x00,0xa4,0xff,0xce,0x00,0x05,0x00,0xa5,0xff,0xce,0x00,0x05,0x00,0xa6,0xff,0xce,0x00,0x05,0x00,0xa7,0xff,0xce,0x00,0x05,0x00,0xa9,0xff,0xc5,0x00,0x05,0x00,0xaa,0xff,0xc5,0x00,0x05,0x00,0xab,0xff,0xc5,0x00,0x05,0x00,0xac,0xff,0xc5,0x00,0x05, +0x00,0xad,0xff,0xc5,0x00,0x05,0x00,0xb3,0xff,0xec,0x00,0x05,0x00,0xb4,0xff,0xc3,0x00,0x05,0x00,0xb5,0xff,0xc3,0x00,0x05,0x00,0xb6,0xff,0xc3,0x00,0x05,0x00,0xb7,0xff,0xc3,0x00,0x05,0x00,0xb8,0xff,0xc3,0x00,0x05,0x01,0x15,0xff,0xc5,0x00,0x05,0x01,0x6f,0xff,0x96,0x00,0x05,0x03,0x34,0xff,0x95,0x00,0x05,0x03,0x35,0xff,0x95, +0x00,0x05,0x03,0x38,0xff,0x95,0x00,0x05,0x03,0x39,0xff,0x95,0x00,0x0a,0x00,0x05,0xff,0x95,0x00,0x0a,0x00,0x0a,0xff,0x95,0x00,0x0a,0x00,0x24,0xff,0x96,0x00,0x0a,0x00,0x44,0xff,0xce,0x00,0x0a,0x00,0x46,0xff,0xc5,0x00,0x0a,0x00,0x47,0xff,0xc5,0x00,0x0a,0x00,0x48,0xff,0xc5,0x00,0x0a,0x00,0x4a,0xff,0xc5,0x00,0x0a,0x00,0x50, +0xff,0xec,0x00,0x0a,0x00,0x51,0xff,0xec,0x00,0x0a,0x00,0x52,0xff,0xc3,0x00,0x0a,0x00,0x53,0xff,0xec,0x00,0x0a,0x00,0x54,0xff,0xc5,0x00,0x0a,0x00,0x56,0xff,0xd6,0x00,0x0a,0x00,0x82,0xff,0x96,0x00,0x0a,0x00,0x83,0xff,0x96,0x00,0x0a,0x00,0x84,0xff,0x96,0x00,0x0a,0x00,0x85,0xff,0x96,0x00,0x0a,0x00,0x86,0xff,0x96,0x00,0x0a, +0x00,0x87,0xff,0x96,0x00,0x0a,0x00,0xa2,0xff,0xce,0x00,0x0a,0x00,0xa3,0xff,0xce,0x00,0x0a,0x00,0xa4,0xff,0xce,0x00,0x0a,0x00,0xa5,0xff,0xce,0x00,0x0a,0x00,0xa6,0xff,0xce,0x00,0x0a,0x00,0xa7,0xff,0xce,0x00,0x0a,0x00,0xa9,0xff,0xc5,0x00,0x0a,0x00,0xaa,0xff,0xc5,0x00,0x0a,0x00,0xab,0xff,0xc5,0x00,0x0a,0x00,0xac,0xff,0xc5, +0x00,0x0a,0x00,0xad,0xff,0xc5,0x00,0x0a,0x00,0xb3,0xff,0xec,0x00,0x0a,0x00,0xb4,0xff,0xc3,0x00,0x0a,0x00,0xb5,0xff,0xc3,0x00,0x0a,0x00,0xb6,0xff,0xc3,0x00,0x0a,0x00,0xb7,0xff,0xc3,0x00,0x0a,0x00,0xb8,0xff,0xc3,0x00,0x0a,0x01,0x15,0xff,0xc5,0x00,0x0a,0x01,0x6f,0xff,0x96,0x00,0x0a,0x03,0x34,0xff,0x95,0x00,0x0a,0x03,0x35, +0xff,0x95,0x00,0x0a,0x03,0x38,0xff,0x95,0x00,0x0a,0x03,0x39,0xff,0x95,0x00,0x0b,0x00,0x39,0x00,0x14,0x00,0x0b,0x00,0x3a,0x00,0x12,0x00,0x0b,0x00,0x3c,0x00,0x16,0x00,0x0b,0x01,0x3a,0x00,0x16,0x00,0x24,0x00,0x05,0xff,0xb1,0x00,0x24,0x00,0x0a,0xff,0xb1,0x00,0x24,0x00,0x22,0xff,0xc3,0x00,0x24,0x00,0x37,0xff,0x7f,0x00,0x24, +0x00,0x38,0xff,0xef,0x00,0x24,0x00,0x39,0xff,0xa9,0x00,0x24,0x00,0x3a,0xff,0xbb,0x00,0x24,0x00,0x3c,0xff,0xa2,0x00,0x24,0x00,0x52,0xff,0xf4,0x00,0x24,0x00,0x57,0xff,0xef,0x00,0x24,0x00,0x59,0xff,0xce,0x00,0x24,0x00,0x5a,0xff,0xdf,0x00,0x24,0x00,0x5c,0xff,0xce,0x00,0x24,0x00,0x5d,0x00,0x0c,0x00,0x24,0x00,0x96,0xff,0xf5, +0x00,0x24,0x00,0x97,0xff,0xf5,0x00,0x24,0x00,0x9b,0xff,0xef,0x00,0x24,0x00,0x9c,0xff,0xef,0x00,0x24,0x00,0x9d,0xff,0xef,0x00,0x24,0x00,0x9e,0xff,0xef,0x00,0x24,0x00,0xb4,0xff,0xf4,0x00,0x24,0x00,0xb5,0xff,0xf4,0x00,0x24,0x00,0xb6,0xff,0xf4,0x00,0x24,0x00,0xb7,0xff,0xf4,0x00,0x24,0x00,0xb8,0xff,0xf4,0x00,0x24,0x00,0xc1, +0xff,0xce,0x00,0x24,0x01,0x3a,0xff,0xa2,0x00,0x24,0x03,0x34,0xff,0xb1,0x00,0x24,0x03,0x35,0xff,0xb1,0x00,0x24,0x03,0x38,0xff,0xb1,0x00,0x24,0x03,0x39,0xff,0xb1,0x00,0x25,0x00,0x37,0xff,0xe5,0x00,0x25,0x00,0x39,0xff,0xe8,0x00,0x25,0x00,0x3c,0xff,0xc9,0x00,0x25,0x01,0x3a,0xff,0xc9,0x00,0x26,0x00,0x0c,0xff,0xe6,0x00,0x26, +0x00,0x37,0xff,0xe3,0x00,0x26,0x00,0x40,0xff,0xf4,0x00,0x26,0x00,0x60,0xff,0xef,0x00,0x27,0x00,0x0f,0xff,0x9a,0x00,0x27,0x00,0x11,0xff,0x9a,0x00,0x27,0x00,0x1d,0xff,0x9a,0x00,0x27,0x00,0x24,0xff,0xeb,0x00,0x27,0x00,0x37,0xff,0xe5,0x00,0x27,0x00,0x39,0xff,0xea,0x00,0x27,0x00,0x3b,0xff,0xea,0x00,0x27,0x00,0x3c,0xff,0xd5, +0x00,0x27,0x00,0x3d,0xff,0xe9,0x00,0x27,0x00,0x82,0xff,0xeb,0x00,0x27,0x00,0x83,0xff,0xeb,0x00,0x27,0x00,0x84,0xff,0xeb,0x00,0x27,0x00,0x85,0xff,0xeb,0x00,0x27,0x00,0x86,0xff,0xeb,0x00,0x27,0x00,0x87,0xff,0xeb,0x00,0x27,0x00,0x88,0xff,0xdf,0x00,0x27,0x01,0x3a,0xff,0xd5,0x00,0x27,0x01,0x6f,0xff,0xeb,0x00,0x27,0x03,0x36, +0xff,0x9a,0x00,0x27,0x03,0x3a,0xff,0x9a,0x00,0x27,0x03,0x3f,0xff,0x9a,0x00,0x28,0x00,0x46,0xff,0xed,0x00,0x28,0x00,0x47,0xff,0xed,0x00,0x28,0x00,0x48,0xff,0xed,0x00,0x28,0x00,0x49,0xff,0xee,0x00,0x28,0x00,0x4a,0xff,0xed,0x00,0x28,0x00,0x52,0xff,0xed,0x00,0x28,0x00,0x54,0xff,0xed,0x00,0x28,0x00,0x58,0xff,0xef,0x00,0x28, +0x00,0x59,0xff,0xe6,0x00,0x28,0x00,0x5a,0xff,0xea,0x00,0x28,0x00,0x5c,0xff,0xe6,0x00,0x28,0x00,0xa9,0xff,0xed,0x00,0x28,0x00,0xaa,0xff,0xed,0x00,0x28,0x00,0xab,0xff,0xed,0x00,0x28,0x00,0xac,0xff,0xed,0x00,0x28,0x00,0xad,0xff,0xed,0x00,0x28,0x00,0xb4,0xff,0xed,0x00,0x28,0x00,0xb5,0xff,0xed,0x00,0x28,0x00,0xb6,0xff,0xed, +0x00,0x28,0x00,0xb7,0xff,0xed,0x00,0x28,0x00,0xb8,0xff,0xed,0x00,0x28,0x00,0xbb,0xff,0xef,0x00,0x28,0x00,0xbc,0xff,0xef,0x00,0x28,0x00,0xbd,0xff,0xef,0x00,0x28,0x00,0xbe,0xff,0xef,0x00,0x28,0x00,0xc1,0xff,0xe6,0x00,0x28,0x01,0x15,0xff,0xed,0x00,0x29,0x00,0x0f,0xff,0x16,0x00,0x29,0x00,0x11,0xff,0x16,0x00,0x29,0x00,0x1d, +0xff,0x16,0x00,0x29,0x00,0x24,0xff,0xc5,0x00,0x29,0x00,0x44,0xff,0xde,0x00,0x29,0x00,0x46,0xff,0xeb,0x00,0x29,0x00,0x47,0xff,0xeb,0x00,0x29,0x00,0x48,0xff,0xeb,0x00,0x29,0x00,0x4a,0xff,0xeb,0x00,0x29,0x00,0x52,0xff,0xeb,0x00,0x29,0x00,0x54,0xff,0xeb,0x00,0x29,0x00,0x55,0xff,0xe6,0x00,0x29,0x00,0x58,0xff,0xea,0x00,0x29, +0x00,0x59,0xff,0xe8,0x00,0x29,0x00,0x5c,0xff,0xe8,0x00,0x29,0x00,0x82,0xff,0xc5,0x00,0x29,0x00,0x83,0xff,0xc5,0x00,0x29,0x00,0x84,0xff,0xc5,0x00,0x29,0x00,0x85,0xff,0xc5,0x00,0x29,0x00,0x86,0xff,0xc5,0x00,0x29,0x00,0x87,0xff,0xc5,0x00,0x29,0x00,0xa2,0xff,0xde,0x00,0x29,0x00,0xa3,0xff,0xde,0x00,0x29,0x00,0xa4,0xff,0xde, +0x00,0x29,0x00,0xa5,0xff,0xde,0x00,0x29,0x00,0xa6,0xff,0xde,0x00,0x29,0x00,0xa7,0xff,0xde,0x00,0x29,0x00,0xa9,0xff,0xeb,0x00,0x29,0x00,0xaa,0xff,0xeb,0x00,0x29,0x00,0xab,0xff,0xeb,0x00,0x29,0x00,0xac,0xff,0xeb,0x00,0x29,0x00,0xad,0xff,0xeb,0x00,0x29,0x00,0xb4,0xff,0xeb,0x00,0x29,0x00,0xb5,0xff,0xeb,0x00,0x29,0x00,0xb6, +0xff,0xeb,0x00,0x29,0x00,0xb7,0xff,0xeb,0x00,0x29,0x00,0xb8,0xff,0xeb,0x00,0x29,0x00,0xbb,0xff,0xea,0x00,0x29,0x00,0xbc,0xff,0xea,0x00,0x29,0x00,0xbd,0xff,0xea,0x00,0x29,0x00,0xbe,0xff,0xea,0x00,0x29,0x00,0xc1,0xff,0xe8,0x00,0x29,0x01,0x15,0xff,0xeb,0x00,0x29,0x01,0x6f,0xff,0xc5,0x00,0x29,0x03,0x36,0xff,0x16,0x00,0x29, +0x03,0x3a,0xff,0x16,0x00,0x29,0x03,0x3f,0xff,0x16,0x00,0x2b,0x00,0x24,0x00,0x12,0x00,0x2b,0x00,0x37,0xff,0xe3,0x00,0x2b,0x00,0x3b,0x00,0x11,0x00,0x2b,0x00,0x3c,0xff,0xe4,0x00,0x2b,0x00,0x82,0x00,0x12,0x00,0x2b,0x00,0x83,0x00,0x12,0x00,0x2b,0x00,0x84,0x00,0x12,0x00,0x2b,0x00,0x85,0x00,0x12,0x00,0x2b,0x00,0x86,0x00,0x12, +0x00,0x2b,0x00,0x87,0x00,0x12,0x00,0x2b,0x01,0x3a,0xff,0xe4,0x00,0x2b,0x01,0x6f,0x00,0x12,0x00,0x2c,0x00,0x24,0x00,0x12,0x00,0x2c,0x00,0x37,0xff,0xe3,0x00,0x2c,0x00,0x3b,0x00,0x11,0x00,0x2c,0x00,0x3c,0xff,0xe4,0x00,0x2c,0x00,0x82,0x00,0x12,0x00,0x2c,0x00,0x83,0x00,0x12,0x00,0x2c,0x00,0x84,0x00,0x12,0x00,0x2c,0x00,0x85, +0x00,0x12,0x00,0x2c,0x00,0x86,0x00,0x12,0x00,0x2c,0x00,0x87,0x00,0x12,0x00,0x2c,0x01,0x3a,0xff,0xe4,0x00,0x2c,0x01,0x6f,0x00,0x12,0x00,0x2d,0x00,0x24,0xff,0xea,0x00,0x2d,0x00,0x82,0xff,0xea,0x00,0x2d,0x00,0x83,0xff,0xea,0x00,0x2d,0x00,0x84,0xff,0xea,0x00,0x2d,0x00,0x85,0xff,0xea,0x00,0x2d,0x00,0x86,0xff,0xea,0x00,0x2d, +0x00,0x87,0xff,0xea,0x00,0x2d,0x01,0x6f,0xff,0xea,0x00,0x2e,0x00,0x10,0xff,0xc0,0x00,0x2e,0x00,0x26,0xff,0xe1,0x00,0x2e,0x00,0x2a,0xff,0xe1,0x00,0x2e,0x00,0x32,0xff,0xe1,0x00,0x2e,0x00,0x34,0xff,0xe1,0x00,0x2e,0x00,0x46,0xff,0xe6,0x00,0x2e,0x00,0x47,0xff,0xe6,0x00,0x2e,0x00,0x48,0xff,0xe6,0x00,0x2e,0x00,0x4a,0xff,0xe6, +0x00,0x2e,0x00,0x50,0xff,0xe9,0x00,0x2e,0x00,0x51,0xff,0xe9,0x00,0x2e,0x00,0x52,0xff,0xe5,0x00,0x2e,0x00,0x53,0xff,0xe9,0x00,0x2e,0x00,0x54,0xff,0xe6,0x00,0x2e,0x00,0x58,0xff,0xe9,0x00,0x2e,0x00,0x59,0xff,0xd8,0x00,0x2e,0x00,0x5a,0xff,0xc1,0x00,0x2e,0x00,0x5c,0xff,0xd8,0x00,0x2e,0x00,0x89,0xff,0xe1,0x00,0x2e,0x00,0x94, +0xff,0xe1,0x00,0x2e,0x00,0x95,0xff,0xe1,0x00,0x2e,0x00,0x96,0xff,0xe1,0x00,0x2e,0x00,0x97,0xff,0xe1,0x00,0x2e,0x00,0x98,0xff,0xe1,0x00,0x2e,0x00,0x9a,0xff,0xe1,0x00,0x2e,0x00,0xa9,0xff,0xe6,0x00,0x2e,0x00,0xaa,0xff,0xe6,0x00,0x2e,0x00,0xab,0xff,0xe6,0x00,0x2e,0x00,0xac,0xff,0xe6,0x00,0x2e,0x00,0xad,0xff,0xe6,0x00,0x2e, +0x00,0xb3,0xff,0xe9,0x00,0x2e,0x00,0xb4,0xff,0xe5,0x00,0x2e,0x00,0xb5,0xff,0xe5,0x00,0x2e,0x00,0xb6,0xff,0xe5,0x00,0x2e,0x00,0xb7,0xff,0xe5,0x00,0x2e,0x00,0xb8,0xff,0xe5,0x00,0x2e,0x00,0xbb,0xff,0xe9,0x00,0x2e,0x00,0xbc,0xff,0xe9,0x00,0x2e,0x00,0xbd,0xff,0xe9,0x00,0x2e,0x00,0xbe,0xff,0xe9,0x00,0x2e,0x00,0xc1,0xff,0xd8, +0x00,0x2e,0x01,0x14,0xff,0xe1,0x00,0x2e,0x01,0x15,0xff,0xe6,0x00,0x2e,0x03,0x30,0xff,0xc0,0x00,0x2e,0x03,0x31,0xff,0xc0,0x00,0x2f,0x00,0x05,0xff,0x76,0x00,0x2f,0x00,0x0a,0xff,0x76,0x00,0x2f,0x00,0x24,0x00,0x13,0x00,0x2f,0x00,0x26,0xff,0xbf,0x00,0x2f,0x00,0x2a,0xff,0xbf,0x00,0x2f,0x00,0x32,0xff,0xbf,0x00,0x2f,0x00,0x34, +0xff,0xbf,0x00,0x2f,0x00,0x37,0xfe,0xed,0x00,0x2f,0x00,0x38,0xff,0xca,0x00,0x2f,0x00,0x39,0xff,0x51,0x00,0x2f,0x00,0x3a,0xff,0x71,0x00,0x2f,0x00,0x3c,0xff,0x11,0x00,0x2f,0x00,0x58,0xff,0xd4,0x00,0x2f,0x00,0x59,0xff,0x7b,0x00,0x2f,0x00,0x5a,0xff,0xa4,0x00,0x2f,0x00,0x5c,0xff,0x7b,0x00,0x2f,0x00,0x82,0x00,0x13,0x00,0x2f, +0x00,0x83,0x00,0x13,0x00,0x2f,0x00,0x84,0x00,0x13,0x00,0x2f,0x00,0x85,0x00,0x13,0x00,0x2f,0x00,0x86,0x00,0x13,0x00,0x2f,0x00,0x87,0x00,0x13,0x00,0x2f,0x00,0x89,0xff,0xbf,0x00,0x2f,0x00,0x94,0xff,0xbf,0x00,0x2f,0x00,0x95,0xff,0xbf,0x00,0x2f,0x00,0x96,0xff,0xbf,0x00,0x2f,0x00,0x97,0xff,0xbf,0x00,0x2f,0x00,0x98,0xff,0xbf, +0x00,0x2f,0x00,0x9a,0xff,0xbf,0x00,0x2f,0x00,0x9b,0xff,0xca,0x00,0x2f,0x00,0x9c,0xff,0xca,0x00,0x2f,0x00,0x9d,0xff,0xca,0x00,0x2f,0x00,0x9e,0xff,0xca,0x00,0x2f,0x00,0xbb,0xff,0xd4,0x00,0x2f,0x00,0xbc,0xff,0xd4,0x00,0x2f,0x00,0xbd,0xff,0xd4,0x00,0x2f,0x00,0xbe,0xff,0xd4,0x00,0x2f,0x00,0xc1,0xff,0x7b,0x00,0x2f,0x01,0x14, +0xff,0xbf,0x00,0x2f,0x01,0x3a,0xff,0x11,0x00,0x2f,0x01,0x6f,0x00,0x13,0x00,0x2f,0x03,0x34,0xff,0x76,0x00,0x2f,0x03,0x35,0xff,0x76,0x00,0x2f,0x03,0x38,0xff,0x76,0x00,0x2f,0x03,0x39,0xff,0x76,0x00,0x30,0x00,0x24,0x00,0x12,0x00,0x30,0x00,0x37,0xff,0xe3,0x00,0x30,0x00,0x3b,0x00,0x11,0x00,0x30,0x00,0x3c,0xff,0xe4,0x00,0x30, +0x00,0x82,0x00,0x12,0x00,0x30,0x00,0x83,0x00,0x12,0x00,0x30,0x00,0x84,0x00,0x12,0x00,0x30,0x00,0x85,0x00,0x12,0x00,0x30,0x00,0x86,0x00,0x12,0x00,0x30,0x00,0x87,0x00,0x12,0x00,0x30,0x01,0x3a,0xff,0xe4,0x00,0x30,0x01,0x6f,0x00,0x12,0x00,0x31,0x00,0x24,0x00,0x12,0x00,0x31,0x00,0x37,0xff,0xe3,0x00,0x31,0x00,0x3b,0x00,0x11, +0x00,0x31,0x00,0x3c,0xff,0xe4,0x00,0x31,0x00,0x82,0x00,0x12,0x00,0x31,0x00,0x83,0x00,0x12,0x00,0x31,0x00,0x84,0x00,0x12,0x00,0x31,0x00,0x85,0x00,0x12,0x00,0x31,0x00,0x86,0x00,0x12,0x00,0x31,0x00,0x87,0x00,0x12,0x00,0x31,0x01,0x3a,0xff,0xe4,0x00,0x31,0x01,0x6f,0x00,0x12,0x00,0x32,0x00,0x0f,0xff,0x9a,0x00,0x32,0x00,0x11, +0xff,0x9a,0x00,0x32,0x00,0x1d,0xff,0x9a,0x00,0x32,0x00,0x24,0xff,0xeb,0x00,0x32,0x00,0x37,0xff,0xe5,0x00,0x32,0x00,0x39,0xff,0xea,0x00,0x32,0x00,0x3b,0xff,0xea,0x00,0x32,0x00,0x3c,0xff,0xd5,0x00,0x32,0x00,0x3d,0xff,0xe9,0x00,0x32,0x00,0x82,0xff,0xeb,0x00,0x32,0x00,0x83,0xff,0xeb,0x00,0x32,0x00,0x84,0xff,0xeb,0x00,0x32, +0x00,0x85,0xff,0xeb,0x00,0x32,0x00,0x86,0xff,0xeb,0x00,0x32,0x00,0x87,0xff,0xeb,0x00,0x32,0x00,0x88,0xff,0xdf,0x00,0x32,0x01,0x3a,0xff,0xd5,0x00,0x32,0x01,0x6f,0xff,0xeb,0x00,0x32,0x03,0x36,0xff,0x9a,0x00,0x32,0x03,0x3a,0xff,0x9a,0x00,0x32,0x03,0x3f,0xff,0x9a,0x00,0x33,0x00,0x0f,0xfe,0xbc,0x00,0x33,0x00,0x11,0xfe,0xbc, +0x00,0x33,0x00,0x1d,0xfe,0xbc,0x00,0x33,0x00,0x24,0xff,0x76,0x00,0x33,0x00,0x3b,0xff,0xe1,0x00,0x33,0x00,0x3d,0xff,0xe6,0x00,0x33,0x00,0x46,0xff,0xf3,0x00,0x33,0x00,0x47,0xff,0xf3,0x00,0x33,0x00,0x48,0xff,0xf3,0x00,0x33,0x00,0x4a,0xff,0xf3,0x00,0x33,0x00,0x52,0xff,0xf3,0x00,0x33,0x00,0x54,0xff,0xf3,0x00,0x33,0x00,0x57, +0x00,0x0e,0x00,0x33,0x00,0x59,0x00,0x0f,0x00,0x33,0x00,0x5c,0x00,0x0f,0x00,0x33,0x00,0x82,0xff,0x76,0x00,0x33,0x00,0x83,0xff,0x76,0x00,0x33,0x00,0x84,0xff,0x76,0x00,0x33,0x00,0x85,0xff,0x76,0x00,0x33,0x00,0x86,0xff,0x76,0x00,0x33,0x00,0x87,0xff,0x76,0x00,0x33,0x00,0x88,0xff,0x9f,0x00,0x33,0x00,0xa9,0xff,0xf3,0x00,0x33, +0x00,0xaa,0xff,0xf3,0x00,0x33,0x00,0xab,0xff,0xf3,0x00,0x33,0x00,0xac,0xff,0xf3,0x00,0x33,0x00,0xad,0xff,0xf3,0x00,0x33,0x00,0xb4,0xff,0xf3,0x00,0x33,0x00,0xb5,0xff,0xf3,0x00,0x33,0x00,0xb6,0xff,0xf3,0x00,0x33,0x00,0xb7,0xff,0xf3,0x00,0x33,0x00,0xb8,0xff,0xf3,0x00,0x33,0x00,0xc1,0x00,0x0f,0x00,0x33,0x01,0x15,0xff,0xf3, +0x00,0x33,0x01,0x6f,0xff,0x76,0x00,0x33,0x03,0x36,0xfe,0xbc,0x00,0x33,0x03,0x3a,0xfe,0xbc,0x00,0x33,0x03,0x3f,0xfe,0xbc,0x00,0x34,0x00,0x37,0xff,0xd5,0x00,0x34,0x00,0x39,0xff,0xe4,0x00,0x34,0x00,0x3a,0xff,0xec,0x00,0x34,0x00,0x3c,0xff,0xdd,0x00,0x34,0x01,0x3a,0xff,0xdd,0x00,0x35,0x00,0x37,0xff,0xb0,0x00,0x35,0x00,0x39, +0xff,0xed,0x00,0x35,0x00,0x3c,0xff,0xd0,0x00,0x35,0x01,0x3a,0xff,0xd0,0x00,0x37,0x00,0x0f,0xff,0x26,0x00,0x37,0x00,0x10,0xff,0x18,0x00,0x37,0x00,0x11,0xff,0x26,0x00,0x37,0x00,0x1d,0xff,0x26,0x00,0x37,0x00,0x24,0xff,0xb1,0x00,0x37,0x00,0x26,0xff,0xe4,0x00,0x37,0x00,0x2a,0xff,0xe4,0x00,0x37,0x00,0x32,0xff,0xe4,0x00,0x37, +0x00,0x34,0xff,0xe4,0x00,0x37,0x00,0x36,0xff,0xf0,0x00,0x37,0x00,0x37,0x00,0x10,0x00,0x37,0x00,0x39,0x00,0x10,0x00,0x37,0x00,0x3a,0x00,0x0f,0x00,0x37,0x00,0x3c,0x00,0x10,0x00,0x37,0x00,0x44,0xff,0x8f,0x00,0x37,0x00,0x46,0xff,0x9d,0x00,0x37,0x00,0x47,0xff,0x9d,0x00,0x37,0x00,0x48,0xff,0x9d,0x00,0x37,0x00,0x4a,0xff,0x9d, +0x00,0x37,0x00,0x50,0xff,0x93,0x00,0x37,0x00,0x51,0xff,0x93,0x00,0x37,0x00,0x52,0xff,0x9d,0x00,0x37,0x00,0x53,0xff,0x93,0x00,0x37,0x00,0x54,0xff,0x9d,0x00,0x37,0x00,0x55,0xff,0xb5,0x00,0x37,0x00,0x56,0xff,0x8c,0x00,0x37,0x00,0x58,0xff,0xa1,0x00,0x37,0x00,0x59,0xff,0xb8,0x00,0x37,0x00,0x5a,0xff,0xc7,0x00,0x37,0x00,0x5b, +0xff,0xb3,0x00,0x37,0x00,0x5c,0xff,0xb8,0x00,0x37,0x00,0x5d,0xff,0xc4,0x00,0x37,0x00,0x6d,0xfe,0xb8,0x00,0x37,0x00,0x7d,0xff,0x28,0x00,0x37,0x00,0x82,0xff,0xb1,0x00,0x37,0x00,0x83,0xff,0xb1,0x00,0x37,0x00,0x84,0xff,0xb1,0x00,0x37,0x00,0x85,0xff,0xb1,0x00,0x37,0x00,0x86,0xff,0xb1,0x00,0x37,0x00,0x87,0xff,0xb1,0x00,0x37, +0x00,0x88,0xff,0x4d,0x00,0x37,0x00,0x89,0xff,0xe4,0x00,0x37,0x00,0x94,0xff,0xe4,0x00,0x37,0x00,0x95,0xff,0xe4,0x00,0x37,0x00,0x96,0xff,0xe4,0x00,0x37,0x00,0x97,0xff,0xe4,0x00,0x37,0x00,0x98,0xff,0xe4,0x00,0x37,0x00,0x9a,0xff,0xe4,0x00,0x37,0x00,0xa2,0xff,0x8f,0x00,0x37,0x00,0xa3,0xff,0x8f,0x00,0x37,0x00,0xa4,0xff,0x8f, +0x00,0x37,0x00,0xa5,0xff,0x8f,0x00,0x37,0x00,0xa6,0xff,0x8f,0x00,0x37,0x00,0xa7,0xff,0x8f,0x00,0x37,0x00,0xa8,0xff,0x8e,0x00,0x37,0x00,0xa9,0xff,0x9d,0x00,0x37,0x00,0xaa,0xff,0x9d,0x00,0x37,0x00,0xab,0xff,0x9d,0x00,0x37,0x00,0xac,0xff,0x9d,0x00,0x37,0x00,0xad,0xff,0x9d,0x00,0x37,0x00,0xb3,0xff,0x93,0x00,0x37,0x00,0xb4, +0xff,0x9d,0x00,0x37,0x00,0xb5,0xff,0x9d,0x00,0x37,0x00,0xb6,0xff,0x9d,0x00,0x37,0x00,0xb7,0xff,0x9d,0x00,0x37,0x00,0xb8,0xff,0x9d,0x00,0x37,0x00,0xba,0xff,0xa1,0x00,0x37,0x00,0xbb,0xff,0xa1,0x00,0x37,0x00,0xbc,0xff,0xa1,0x00,0x37,0x00,0xbd,0xff,0xa1,0x00,0x37,0x00,0xbe,0xff,0xa1,0x00,0x37,0x00,0xc1,0xff,0xb8,0x00,0x37, +0x01,0x14,0xff,0xe4,0x00,0x37,0x01,0x15,0xff,0x9d,0x00,0x37,0x01,0x3a,0x00,0x10,0x00,0x37,0x01,0x6f,0xff,0xb1,0x00,0x37,0x01,0x9a,0xff,0x87,0x00,0x37,0x03,0x30,0xff,0x18,0x00,0x37,0x03,0x31,0xff,0x18,0x00,0x37,0x03,0x36,0xff,0x26,0x00,0x37,0x03,0x3a,0xff,0x26,0x00,0x37,0x03,0x3f,0xff,0x26,0x00,0x38,0x00,0x24,0xff,0xea, +0x00,0x38,0x00,0x82,0xff,0xea,0x00,0x38,0x00,0x83,0xff,0xea,0x00,0x38,0x00,0x84,0xff,0xea,0x00,0x38,0x00,0x85,0xff,0xea,0x00,0x38,0x00,0x86,0xff,0xea,0x00,0x38,0x00,0x87,0xff,0xea,0x00,0x38,0x01,0x6f,0xff,0xea,0x00,0x39,0x00,0x0c,0x00,0x14,0x00,0x39,0x00,0x0f,0xff,0x1f,0x00,0x39,0x00,0x10,0xff,0xdb,0x00,0x39,0x00,0x11, +0xff,0x1f,0x00,0x39,0x00,0x1d,0xff,0x1f,0x00,0x39,0x00,0x24,0xff,0xb5,0x00,0x39,0x00,0x26,0xff,0xf3,0x00,0x39,0x00,0x2a,0xff,0xf3,0x00,0x39,0x00,0x32,0xff,0xf3,0x00,0x39,0x00,0x34,0xff,0xf3,0x00,0x39,0x00,0x40,0x00,0x11,0x00,0x39,0x00,0x44,0xff,0xd2,0x00,0x39,0x00,0x46,0xff,0xd4,0x00,0x39,0x00,0x47,0xff,0xd4,0x00,0x39, +0x00,0x48,0xff,0xd4,0x00,0x39,0x00,0x4a,0xff,0xd4,0x00,0x39,0x00,0x52,0xff,0xd2,0x00,0x39,0x00,0x54,0xff,0xd4,0x00,0x39,0x00,0x55,0xff,0xe2,0x00,0x39,0x00,0x58,0xff,0xe4,0x00,0x39,0x00,0x59,0xff,0xf5,0x00,0x39,0x00,0x60,0x00,0x13,0x00,0x39,0x00,0x82,0xff,0xb5,0x00,0x39,0x00,0x83,0xff,0xb5,0x00,0x39,0x00,0x84,0xff,0xb5, +0x00,0x39,0x00,0x85,0xff,0xb5,0x00,0x39,0x00,0x86,0xff,0xb5,0x00,0x39,0x00,0x87,0xff,0xb5,0x00,0x39,0x00,0x89,0xff,0xf3,0x00,0x39,0x00,0x94,0xff,0xf3,0x00,0x39,0x00,0x95,0xff,0xf3,0x00,0x39,0x00,0x96,0xff,0xf3,0x00,0x39,0x00,0x97,0xff,0xf3,0x00,0x39,0x00,0x98,0xff,0xf3,0x00,0x39,0x00,0x9a,0xff,0xf3,0x00,0x39,0x00,0xa2, +0xff,0xd2,0x00,0x39,0x00,0xa3,0xff,0xd2,0x00,0x39,0x00,0xa4,0xff,0xd2,0x00,0x39,0x00,0xa5,0xff,0xd2,0x00,0x39,0x00,0xa6,0xff,0xd2,0x00,0x39,0x00,0xa7,0xff,0xd2,0x00,0x39,0x00,0xa9,0xff,0xd4,0x00,0x39,0x00,0xaa,0xff,0xd4,0x00,0x39,0x00,0xab,0xff,0xd4,0x00,0x39,0x00,0xac,0xff,0xd4,0x00,0x39,0x00,0xad,0xff,0xd4,0x00,0x39, +0x00,0xb4,0xff,0xd2,0x00,0x39,0x00,0xb5,0xff,0xd2,0x00,0x39,0x00,0xb6,0xff,0xd2,0x00,0x39,0x00,0xb7,0xff,0xd2,0x00,0x39,0x00,0xb8,0xff,0xd2,0x00,0x39,0x00,0xbb,0xff,0xe4,0x00,0x39,0x00,0xbc,0xff,0xe4,0x00,0x39,0x00,0xbd,0xff,0xe4,0x00,0x39,0x00,0xbe,0xff,0xe4,0x00,0x39,0x01,0x14,0xff,0xf3,0x00,0x39,0x01,0x15,0xff,0xd4, +0x00,0x39,0x01,0x6f,0xff,0xb5,0x00,0x39,0x03,0x30,0xff,0xdb,0x00,0x39,0x03,0x31,0xff,0xdb,0x00,0x39,0x03,0x36,0xff,0x1f,0x00,0x39,0x03,0x3a,0xff,0x1f,0x00,0x39,0x03,0x3f,0xff,0x1f,0x00,0x3a,0x00,0x0c,0x00,0x0f,0x00,0x3a,0x00,0x0f,0xff,0x85,0x00,0x3a,0x00,0x10,0xff,0xc4,0x00,0x3a,0x00,0x11,0xff,0x85,0x00,0x3a,0x00,0x1d, +0xff,0x85,0x00,0x3a,0x00,0x24,0xff,0xd5,0x00,0x3a,0x00,0x37,0x00,0x0e,0x00,0x3a,0x00,0x40,0x00,0x0c,0x00,0x3a,0x00,0x44,0xff,0xdf,0x00,0x3a,0x00,0x46,0xff,0xe1,0x00,0x3a,0x00,0x47,0xff,0xe1,0x00,0x3a,0x00,0x48,0xff,0xe1,0x00,0x3a,0x00,0x4a,0xff,0xe1,0x00,0x3a,0x00,0x52,0xff,0xe1,0x00,0x3a,0x00,0x54,0xff,0xe1,0x00,0x3a, +0x00,0x55,0xff,0xeb,0x00,0x3a,0x00,0x58,0xff,0xed,0x00,0x3a,0x00,0x60,0x00,0x0e,0x00,0x3a,0x00,0x82,0xff,0xd5,0x00,0x3a,0x00,0x83,0xff,0xd5,0x00,0x3a,0x00,0x84,0xff,0xd5,0x00,0x3a,0x00,0x85,0xff,0xd5,0x00,0x3a,0x00,0x86,0xff,0xd5,0x00,0x3a,0x00,0x87,0xff,0xd5,0x00,0x3a,0x00,0xa2,0xff,0xdf,0x00,0x3a,0x00,0xa3,0xff,0xdf, +0x00,0x3a,0x00,0xa4,0xff,0xdf,0x00,0x3a,0x00,0xa5,0xff,0xdf,0x00,0x3a,0x00,0xa6,0xff,0xdf,0x00,0x3a,0x00,0xa7,0xff,0xdf,0x00,0x3a,0x00,0xa9,0xff,0xe1,0x00,0x3a,0x00,0xaa,0xff,0xe1,0x00,0x3a,0x00,0xab,0xff,0xe1,0x00,0x3a,0x00,0xac,0xff,0xe1,0x00,0x3a,0x00,0xad,0xff,0xe1,0x00,0x3a,0x00,0xb4,0xff,0xe1,0x00,0x3a,0x00,0xb5, +0xff,0xe1,0x00,0x3a,0x00,0xb6,0xff,0xe1,0x00,0x3a,0x00,0xb7,0xff,0xe1,0x00,0x3a,0x00,0xb8,0xff,0xe1,0x00,0x3a,0x00,0xbb,0xff,0xed,0x00,0x3a,0x00,0xbc,0xff,0xed,0x00,0x3a,0x00,0xbd,0xff,0xed,0x00,0x3a,0x00,0xbe,0xff,0xed,0x00,0x3a,0x01,0x15,0xff,0xe1,0x00,0x3a,0x01,0x6f,0xff,0xd5,0x00,0x3a,0x03,0x30,0xff,0xc4,0x00,0x3a, +0x03,0x31,0xff,0xc4,0x00,0x3a,0x03,0x36,0xff,0x85,0x00,0x3a,0x03,0x3a,0xff,0x85,0x00,0x3a,0x03,0x3f,0xff,0x85,0x00,0x3b,0x00,0x10,0xff,0xd2,0x00,0x3b,0x00,0x26,0xff,0xe7,0x00,0x3b,0x00,0x2a,0xff,0xe7,0x00,0x3b,0x00,0x32,0xff,0xe7,0x00,0x3b,0x00,0x34,0xff,0xe7,0x00,0x3b,0x00,0x39,0x00,0x0e,0x00,0x3b,0x00,0x46,0xff,0xe6, +0x00,0x3b,0x00,0x47,0xff,0xe6,0x00,0x3b,0x00,0x48,0xff,0xe6,0x00,0x3b,0x00,0x4a,0xff,0xe6,0x00,0x3b,0x00,0x52,0xff,0xeb,0x00,0x3b,0x00,0x54,0xff,0xe6,0x00,0x3b,0x00,0x58,0xff,0xeb,0x00,0x3b,0x00,0x59,0xff,0xe1,0x00,0x3b,0x00,0x5c,0xff,0xe1,0x00,0x3b,0x00,0x89,0xff,0xe7,0x00,0x3b,0x00,0x94,0xff,0xe7,0x00,0x3b,0x00,0x95, +0xff,0xe7,0x00,0x3b,0x00,0x96,0xff,0xe7,0x00,0x3b,0x00,0x97,0xff,0xe7,0x00,0x3b,0x00,0x98,0xff,0xe7,0x00,0x3b,0x00,0x9a,0xff,0xe7,0x00,0x3b,0x00,0xa9,0xff,0xe6,0x00,0x3b,0x00,0xaa,0xff,0xe6,0x00,0x3b,0x00,0xab,0xff,0xe6,0x00,0x3b,0x00,0xac,0xff,0xe6,0x00,0x3b,0x00,0xad,0xff,0xe6,0x00,0x3b,0x00,0xb4,0xff,0xeb,0x00,0x3b, +0x00,0xb5,0xff,0xeb,0x00,0x3b,0x00,0xb6,0xff,0xeb,0x00,0x3b,0x00,0xb7,0xff,0xeb,0x00,0x3b,0x00,0xb8,0xff,0xeb,0x00,0x3b,0x00,0xbb,0xff,0xeb,0x00,0x3b,0x00,0xbc,0xff,0xeb,0x00,0x3b,0x00,0xbd,0xff,0xeb,0x00,0x3b,0x00,0xbe,0xff,0xeb,0x00,0x3b,0x00,0xc1,0xff,0xe1,0x00,0x3b,0x01,0x14,0xff,0xe7,0x00,0x3b,0x01,0x15,0xff,0xe6, +0x00,0x3b,0x03,0x30,0xff,0xd2,0x00,0x3b,0x03,0x31,0xff,0xd2,0x00,0x3c,0x00,0x09,0xff,0xe2,0x00,0x3c,0x00,0x0c,0x00,0x14,0x00,0x3c,0x00,0x0d,0xff,0xcf,0x00,0x3c,0x00,0x0f,0xff,0x2d,0x00,0x3c,0x00,0x10,0xff,0xcc,0x00,0x3c,0x00,0x11,0xff,0x2d,0x00,0x3c,0x00,0x1d,0xff,0x2d,0x00,0x3c,0x00,0x24,0xff,0xae,0x00,0x3c,0x00,0x26, +0xff,0xe3,0x00,0x3c,0x00,0x2a,0xff,0xe3,0x00,0x3c,0x00,0x2d,0xff,0xa0,0x00,0x3c,0x00,0x32,0xff,0xe3,0x00,0x3c,0x00,0x34,0xff,0xe3,0x00,0x3c,0x00,0x36,0xff,0xf0,0x00,0x3c,0x00,0x37,0x00,0x11,0x00,0x3c,0x00,0x38,0xff,0xa0,0x00,0x3c,0x00,0x39,0x00,0x12,0x00,0x3c,0x00,0x3a,0x00,0x11,0x00,0x3c,0x00,0x3b,0x00,0x0d,0x00,0x3c, +0x00,0x3c,0x00,0x12,0x00,0x3c,0x00,0x40,0x00,0x12,0x00,0x3c,0x00,0x44,0xff,0xb7,0x00,0x3c,0x00,0x46,0xff,0xbf,0x00,0x3c,0x00,0x47,0xff,0xbf,0x00,0x3c,0x00,0x48,0xff,0xbf,0x00,0x3c,0x00,0x49,0xff,0xea,0x00,0x3c,0x00,0x4a,0xff,0xbf,0x00,0x3c,0x00,0x50,0xff,0xd8,0x00,0x3c,0x00,0x51,0xff,0xd8,0x00,0x3c,0x00,0x52,0xff,0xbf, +0x00,0x3c,0x00,0x53,0xff,0xd8,0x00,0x3c,0x00,0x54,0xff,0xbf,0x00,0x3c,0x00,0x55,0xff,0xd8,0x00,0x3c,0x00,0x56,0xff,0xc6,0x00,0x3c,0x00,0x57,0xff,0xea,0x00,0x3c,0x00,0x58,0xff,0xd9,0x00,0x3c,0x00,0x59,0xff,0xec,0x00,0x3c,0x00,0x5b,0xff,0xe9,0x00,0x3c,0x00,0x5c,0xff,0xec,0x00,0x3c,0x00,0x5d,0xff,0xe2,0x00,0x3c,0x00,0x60, +0x00,0x13,0x00,0x3c,0x00,0x6d,0xff,0xae,0x00,0x3c,0x00,0x7d,0xff,0xcd,0x00,0x3c,0x00,0x82,0xff,0xae,0x00,0x3c,0x00,0x83,0xff,0xae,0x00,0x3c,0x00,0x84,0xff,0xae,0x00,0x3c,0x00,0x85,0xff,0xae,0x00,0x3c,0x00,0x86,0xff,0xae,0x00,0x3c,0x00,0x87,0xff,0xae,0x00,0x3c,0x00,0x88,0xff,0xa0,0x00,0x3c,0x00,0x89,0xff,0xe3,0x00,0x3c, +0x00,0x94,0xff,0xe3,0x00,0x3c,0x00,0x95,0xff,0xe3,0x00,0x3c,0x00,0x96,0xff,0xe3,0x00,0x3c,0x00,0x97,0xff,0xe3,0x00,0x3c,0x00,0x98,0xff,0xe3,0x00,0x3c,0x00,0x9a,0xff,0xe3,0x00,0x3c,0x00,0x9b,0xff,0xa0,0x00,0x3c,0x00,0x9c,0xff,0xa0,0x00,0x3c,0x00,0x9d,0xff,0xa0,0x00,0x3c,0x00,0x9e,0xff,0xa0,0x00,0x3c,0x00,0xa2,0xff,0xb7, +0x00,0x3c,0x00,0xa3,0xff,0xb7,0x00,0x3c,0x00,0xa4,0xff,0xb7,0x00,0x3c,0x00,0xa5,0xff,0xb7,0x00,0x3c,0x00,0xa6,0xff,0xb7,0x00,0x3c,0x00,0xa7,0xff,0xb7,0x00,0x3c,0x00,0xa8,0xff,0xc1,0x00,0x3c,0x00,0xa9,0xff,0xbf,0x00,0x3c,0x00,0xaa,0xff,0xbf,0x00,0x3c,0x00,0xab,0xff,0xbf,0x00,0x3c,0x00,0xac,0xff,0xbf,0x00,0x3c,0x00,0xad, +0xff,0xbf,0x00,0x3c,0x00,0xb3,0xff,0xd8,0x00,0x3c,0x00,0xb4,0xff,0xbf,0x00,0x3c,0x00,0xb5,0xff,0xbf,0x00,0x3c,0x00,0xb6,0xff,0xbf,0x00,0x3c,0x00,0xb7,0xff,0xbf,0x00,0x3c,0x00,0xb8,0xff,0xbf,0x00,0x3c,0x00,0xba,0xff,0xc0,0x00,0x3c,0x00,0xbb,0xff,0xd9,0x00,0x3c,0x00,0xbc,0xff,0xd9,0x00,0x3c,0x00,0xbd,0xff,0xd9,0x00,0x3c, +0x00,0xbe,0xff,0xd9,0x00,0x3c,0x00,0xc1,0xff,0xec,0x00,0x3c,0x01,0x14,0xff,0xe3,0x00,0x3c,0x01,0x15,0xff,0xbf,0x00,0x3c,0x01,0x3a,0x00,0x12,0x00,0x3c,0x01,0x6f,0xff,0xae,0x00,0x3c,0x01,0x9a,0xff,0xe8,0x00,0x3c,0x03,0x30,0xff,0xcc,0x00,0x3c,0x03,0x31,0xff,0xcc,0x00,0x3c,0x03,0x36,0xff,0x2d,0x00,0x3c,0x03,0x3a,0xff,0x2d, +0x00,0x3c,0x03,0x3d,0xff,0xd3,0x00,0x3c,0x03,0x3f,0xff,0x2d,0x00,0x3d,0x00,0x24,0x00,0x0d,0x00,0x3d,0x00,0x26,0xff,0xe6,0x00,0x3d,0x00,0x2a,0xff,0xe6,0x00,0x3d,0x00,0x32,0xff,0xe6,0x00,0x3d,0x00,0x34,0xff,0xe6,0x00,0x3d,0x00,0x46,0xff,0xeb,0x00,0x3d,0x00,0x47,0xff,0xeb,0x00,0x3d,0x00,0x48,0xff,0xeb,0x00,0x3d,0x00,0x4a, +0xff,0xeb,0x00,0x3d,0x00,0x52,0xff,0xeb,0x00,0x3d,0x00,0x54,0xff,0xeb,0x00,0x3d,0x00,0x58,0xff,0xed,0x00,0x3d,0x00,0x59,0xff,0xe5,0x00,0x3d,0x00,0x5a,0xff,0xe5,0x00,0x3d,0x00,0x5c,0xff,0xe5,0x00,0x3d,0x00,0x82,0x00,0x0d,0x00,0x3d,0x00,0x83,0x00,0x0d,0x00,0x3d,0x00,0x84,0x00,0x0d,0x00,0x3d,0x00,0x85,0x00,0x0d,0x00,0x3d, +0x00,0x86,0x00,0x0d,0x00,0x3d,0x00,0x87,0x00,0x0d,0x00,0x3d,0x00,0x89,0xff,0xe6,0x00,0x3d,0x00,0x94,0xff,0xe6,0x00,0x3d,0x00,0x95,0xff,0xe6,0x00,0x3d,0x00,0x96,0xff,0xe6,0x00,0x3d,0x00,0x97,0xff,0xe6,0x00,0x3d,0x00,0x98,0xff,0xe6,0x00,0x3d,0x00,0x9a,0xff,0xe6,0x00,0x3d,0x00,0xa9,0xff,0xeb,0x00,0x3d,0x00,0xaa,0xff,0xeb, +0x00,0x3d,0x00,0xab,0xff,0xeb,0x00,0x3d,0x00,0xac,0xff,0xeb,0x00,0x3d,0x00,0xad,0xff,0xeb,0x00,0x3d,0x00,0xb4,0xff,0xeb,0x00,0x3d,0x00,0xb5,0xff,0xeb,0x00,0x3d,0x00,0xb6,0xff,0xeb,0x00,0x3d,0x00,0xb7,0xff,0xeb,0x00,0x3d,0x00,0xb8,0xff,0xeb,0x00,0x3d,0x00,0xbb,0xff,0xed,0x00,0x3d,0x00,0xbc,0xff,0xed,0x00,0x3d,0x00,0xbd, +0xff,0xed,0x00,0x3d,0x00,0xbe,0xff,0xed,0x00,0x3d,0x00,0xc1,0xff,0xe5,0x00,0x3d,0x01,0x14,0xff,0xe6,0x00,0x3d,0x01,0x15,0xff,0xeb,0x00,0x3d,0x01,0x6f,0x00,0x0d,0x00,0x3e,0x00,0x2d,0xff,0xee,0x00,0x3e,0x00,0x38,0xff,0xee,0x00,0x3e,0x00,0x9b,0xff,0xee,0x00,0x3e,0x00,0x9c,0xff,0xee,0x00,0x3e,0x00,0x9d,0xff,0xee,0x00,0x3e, +0x00,0x9e,0xff,0xee,0x00,0x44,0x00,0x05,0xff,0xbd,0x00,0x44,0x00,0x0a,0xff,0xbd,0x00,0x44,0x00,0x59,0xff,0xf1,0x00,0x44,0x00,0x5c,0xff,0xf1,0x00,0x44,0x00,0xc1,0xff,0xf1,0x00,0x44,0x03,0x34,0xff,0xbd,0x00,0x44,0x03,0x35,0xff,0xbd,0x00,0x44,0x03,0x38,0xff,0xbd,0x00,0x44,0x03,0x39,0xff,0xbd,0x00,0x45,0x00,0x05,0xff,0xe3, +0x00,0x45,0x00,0x0a,0xff,0xe3,0x00,0x45,0x00,0x5b,0xff,0xf1,0x00,0x45,0x00,0x5d,0xff,0xf1,0x00,0x45,0x03,0x34,0xff,0xe3,0x00,0x45,0x03,0x35,0xff,0xe3,0x00,0x45,0x03,0x38,0xff,0xe3,0x00,0x45,0x03,0x39,0xff,0xe3,0x00,0x48,0x00,0x05,0xff,0xf2,0x00,0x48,0x00,0x0a,0xff,0xf2,0x00,0x48,0x00,0x59,0xff,0xf3,0x00,0x48,0x00,0x5c, +0xff,0xf3,0x00,0x48,0x00,0xc1,0xff,0xf3,0x00,0x48,0x03,0x34,0xff,0xf2,0x00,0x48,0x03,0x35,0xff,0xf2,0x00,0x48,0x03,0x38,0xff,0xf2,0x00,0x48,0x03,0x39,0xff,0xf2,0x00,0x49,0x00,0x05,0x00,0x10,0x00,0x49,0x00,0x0a,0x00,0x10,0x00,0x49,0x00,0x0c,0x00,0x14,0x00,0x49,0x00,0x40,0x00,0x12,0x00,0x49,0x00,0x46,0xff,0xe8,0x00,0x49, +0x00,0x47,0xff,0xe8,0x00,0x49,0x00,0x48,0xff,0xe8,0x00,0x49,0x00,0x4a,0xff,0xe8,0x00,0x49,0x00,0x54,0xff,0xe8,0x00,0x49,0x00,0x60,0x00,0x13,0x00,0x49,0x00,0xa9,0xff,0xe8,0x00,0x49,0x00,0xaa,0xff,0xe8,0x00,0x49,0x00,0xab,0xff,0xe8,0x00,0x49,0x00,0xac,0xff,0xe8,0x00,0x49,0x00,0xad,0xff,0xe8,0x00,0x49,0x01,0x15,0xff,0xe8, +0x00,0x49,0x03,0x34,0x00,0x10,0x00,0x49,0x03,0x35,0x00,0x10,0x00,0x49,0x03,0x38,0x00,0x10,0x00,0x49,0x03,0x39,0x00,0x10,0x00,0x4b,0x00,0x05,0xff,0xf0,0x00,0x4b,0x00,0x0a,0xff,0xf0,0x00,0x4b,0x03,0x34,0xff,0xf0,0x00,0x4b,0x03,0x35,0xff,0xf0,0x00,0x4b,0x03,0x38,0xff,0xf0,0x00,0x4b,0x03,0x39,0xff,0xf0,0x00,0x4e,0x00,0x46, +0xff,0xec,0x00,0x4e,0x00,0x47,0xff,0xec,0x00,0x4e,0x00,0x48,0xff,0xec,0x00,0x4e,0x00,0x4a,0xff,0xec,0x00,0x4e,0x00,0x54,0xff,0xec,0x00,0x4e,0x00,0xa9,0xff,0xec,0x00,0x4e,0x00,0xaa,0xff,0xec,0x00,0x4e,0x00,0xab,0xff,0xec,0x00,0x4e,0x00,0xac,0xff,0xec,0x00,0x4e,0x00,0xad,0xff,0xec,0x00,0x4e,0x01,0x15,0xff,0xec,0x00,0x50, +0x00,0x05,0xff,0xf0,0x00,0x50,0x00,0x0a,0xff,0xf0,0x00,0x50,0x03,0x34,0xff,0xf0,0x00,0x50,0x03,0x35,0xff,0xf0,0x00,0x50,0x03,0x38,0xff,0xf0,0x00,0x50,0x03,0x39,0xff,0xf0,0x00,0x51,0x00,0x05,0xff,0xf0,0x00,0x51,0x00,0x0a,0xff,0xf0,0x00,0x51,0x03,0x34,0xff,0xf0,0x00,0x51,0x03,0x35,0xff,0xf0,0x00,0x51,0x03,0x38,0xff,0xf0, +0x00,0x51,0x03,0x39,0xff,0xf0,0x00,0x52,0x00,0x05,0xff,0xec,0x00,0x52,0x00,0x0a,0xff,0xec,0x00,0x52,0x00,0x59,0xff,0xf1,0x00,0x52,0x00,0x5b,0xff,0xeb,0x00,0x52,0x00,0x5c,0xff,0xf1,0x00,0x52,0x00,0x5d,0xff,0xf0,0x00,0x52,0x00,0xc1,0xff,0xf1,0x00,0x52,0x03,0x34,0xff,0xec,0x00,0x52,0x03,0x35,0xff,0xec,0x00,0x52,0x03,0x38, +0xff,0xec,0x00,0x52,0x03,0x39,0xff,0xec,0x00,0x53,0x00,0x05,0xff,0xe3,0x00,0x53,0x00,0x0a,0xff,0xe3,0x00,0x53,0x00,0x5b,0xff,0xf1,0x00,0x53,0x00,0x5d,0xff,0xf1,0x00,0x53,0x03,0x34,0xff,0xe3,0x00,0x53,0x03,0x35,0xff,0xe3,0x00,0x53,0x03,0x38,0xff,0xe3,0x00,0x53,0x03,0x39,0xff,0xe3,0x00,0x55,0x00,0x05,0x00,0x10,0x00,0x55, +0x00,0x0a,0x00,0x10,0x00,0x55,0x00,0x0f,0xff,0x85,0x00,0x55,0x00,0x11,0xff,0x85,0x00,0x55,0x00,0x1d,0xff,0x85,0x00,0x55,0x00,0x46,0xff,0xed,0x00,0x55,0x00,0x47,0xff,0xed,0x00,0x55,0x00,0x48,0xff,0xed,0x00,0x55,0x00,0x49,0x00,0x0f,0x00,0x55,0x00,0x4a,0xff,0xed,0x00,0x55,0x00,0x52,0xff,0xec,0x00,0x55,0x00,0x54,0xff,0xed, +0x00,0x55,0x00,0x57,0x00,0x11,0x00,0x55,0x00,0x59,0x00,0x12,0x00,0x55,0x00,0x5a,0x00,0x11,0x00,0x55,0x00,0x5c,0x00,0x12,0x00,0x55,0x00,0xa9,0xff,0xed,0x00,0x55,0x00,0xaa,0xff,0xed,0x00,0x55,0x00,0xab,0xff,0xed,0x00,0x55,0x00,0xac,0xff,0xed,0x00,0x55,0x00,0xad,0xff,0xed,0x00,0x55,0x00,0xb4,0xff,0xec,0x00,0x55,0x00,0xb5, +0xff,0xec,0x00,0x55,0x00,0xb6,0xff,0xec,0x00,0x55,0x00,0xb7,0xff,0xec,0x00,0x55,0x00,0xb8,0xff,0xec,0x00,0x55,0x00,0xc1,0x00,0x12,0x00,0x55,0x01,0x15,0xff,0xed,0x00,0x55,0x03,0x34,0x00,0x10,0x00,0x55,0x03,0x35,0x00,0x10,0x00,0x55,0x03,0x36,0xff,0x85,0x00,0x55,0x03,0x38,0x00,0x10,0x00,0x55,0x03,0x39,0x00,0x10,0x00,0x55, +0x03,0x3a,0xff,0x85,0x00,0x55,0x03,0x3f,0xff,0x85,0x00,0x59,0x00,0x05,0x00,0x0f,0x00,0x59,0x00,0x0a,0x00,0x0f,0x00,0x59,0x00,0x0f,0xff,0x95,0x00,0x59,0x00,0x11,0xff,0x95,0x00,0x59,0x00,0x1d,0xff,0x95,0x00,0x59,0x00,0x44,0xff,0xf1,0x00,0x59,0x00,0x46,0xff,0xf3,0x00,0x59,0x00,0x47,0xff,0xf3,0x00,0x59,0x00,0x48,0xff,0xf3, +0x00,0x59,0x00,0x49,0x00,0x0d,0x00,0x59,0x00,0x4a,0xff,0xf3,0x00,0x59,0x00,0x52,0xff,0xf1,0x00,0x59,0x00,0x54,0xff,0xf3,0x00,0x59,0x00,0xa2,0xff,0xf1,0x00,0x59,0x00,0xa3,0xff,0xf1,0x00,0x59,0x00,0xa4,0xff,0xf1,0x00,0x59,0x00,0xa5,0xff,0xf1,0x00,0x59,0x00,0xa6,0xff,0xf1,0x00,0x59,0x00,0xa7,0xff,0xf1,0x00,0x59,0x00,0xa9, +0xff,0xf3,0x00,0x59,0x00,0xaa,0xff,0xf3,0x00,0x59,0x00,0xab,0xff,0xf3,0x00,0x59,0x00,0xac,0xff,0xf3,0x00,0x59,0x00,0xad,0xff,0xf3,0x00,0x59,0x00,0xb4,0xff,0xf1,0x00,0x59,0x00,0xb5,0xff,0xf1,0x00,0x59,0x00,0xb6,0xff,0xf1,0x00,0x59,0x00,0xb7,0xff,0xf1,0x00,0x59,0x00,0xb8,0xff,0xf1,0x00,0x59,0x01,0x15,0xff,0xf3,0x00,0x59, +0x03,0x34,0x00,0x0f,0x00,0x59,0x03,0x35,0x00,0x0f,0x00,0x59,0x03,0x36,0xff,0x95,0x00,0x59,0x03,0x38,0x00,0x0f,0x00,0x59,0x03,0x39,0x00,0x0f,0x00,0x59,0x03,0x3a,0xff,0x95,0x00,0x59,0x03,0x3f,0xff,0x95,0x00,0x5a,0x00,0x0f,0xff,0x84,0x00,0x5a,0x00,0x11,0xff,0x84,0x00,0x5a,0x00,0x1d,0xff,0x84,0x00,0x5a,0x03,0x36,0xff,0x84, +0x00,0x5a,0x03,0x3a,0xff,0x84,0x00,0x5a,0x03,0x3f,0xff,0x84,0x00,0x5b,0x00,0x46,0xff,0xec,0x00,0x5b,0x00,0x47,0xff,0xec,0x00,0x5b,0x00,0x48,0xff,0xec,0x00,0x5b,0x00,0x4a,0xff,0xec,0x00,0x5b,0x00,0x52,0xff,0xec,0x00,0x5b,0x00,0x54,0xff,0xec,0x00,0x5b,0x00,0xa9,0xff,0xec,0x00,0x5b,0x00,0xaa,0xff,0xec,0x00,0x5b,0x00,0xab, +0xff,0xec,0x00,0x5b,0x00,0xac,0xff,0xec,0x00,0x5b,0x00,0xad,0xff,0xec,0x00,0x5b,0x00,0xb4,0xff,0xec,0x00,0x5b,0x00,0xb5,0xff,0xec,0x00,0x5b,0x00,0xb6,0xff,0xec,0x00,0x5b,0x00,0xb7,0xff,0xec,0x00,0x5b,0x00,0xb8,0xff,0xec,0x00,0x5b,0x01,0x15,0xff,0xec,0x00,0x5c,0x00,0x05,0x00,0x0f,0x00,0x5c,0x00,0x0a,0x00,0x0f,0x00,0x5c, +0x00,0x0f,0xff,0x95,0x00,0x5c,0x00,0x11,0xff,0x95,0x00,0x5c,0x00,0x1d,0xff,0x95,0x00,0x5c,0x00,0x44,0xff,0xf1,0x00,0x5c,0x00,0x46,0xff,0xf3,0x00,0x5c,0x00,0x47,0xff,0xf3,0x00,0x5c,0x00,0x48,0xff,0xf3,0x00,0x5c,0x00,0x49,0x00,0x0d,0x00,0x5c,0x00,0x4a,0xff,0xf3,0x00,0x5c,0x00,0x52,0xff,0xf1,0x00,0x5c,0x00,0x54,0xff,0xf3, +0x00,0x5c,0x00,0xa2,0xff,0xf1,0x00,0x5c,0x00,0xa3,0xff,0xf1,0x00,0x5c,0x00,0xa4,0xff,0xf1,0x00,0x5c,0x00,0xa5,0xff,0xf1,0x00,0x5c,0x00,0xa6,0xff,0xf1,0x00,0x5c,0x00,0xa7,0xff,0xf1,0x00,0x5c,0x00,0xa9,0xff,0xf3,0x00,0x5c,0x00,0xaa,0xff,0xf3,0x00,0x5c,0x00,0xab,0xff,0xf3,0x00,0x5c,0x00,0xac,0xff,0xf3,0x00,0x5c,0x00,0xad, +0xff,0xf3,0x00,0x5c,0x00,0xb4,0xff,0xf1,0x00,0x5c,0x00,0xb5,0xff,0xf1,0x00,0x5c,0x00,0xb6,0xff,0xf1,0x00,0x5c,0x00,0xb7,0xff,0xf1,0x00,0x5c,0x00,0xb8,0xff,0xf1,0x00,0x5c,0x01,0x15,0xff,0xf3,0x00,0x5c,0x03,0x34,0x00,0x0f,0x00,0x5c,0x03,0x35,0x00,0x0f,0x00,0x5c,0x03,0x36,0xff,0x95,0x00,0x5c,0x03,0x38,0x00,0x0f,0x00,0x5c, +0x03,0x39,0x00,0x0f,0x00,0x5c,0x03,0x3a,0xff,0x95,0x00,0x5c,0x03,0x3f,0xff,0x95,0x00,0x5d,0x00,0x46,0xff,0xf0,0x00,0x5d,0x00,0x47,0xff,0xf0,0x00,0x5d,0x00,0x48,0xff,0xf0,0x00,0x5d,0x00,0x4a,0xff,0xf0,0x00,0x5d,0x00,0x52,0xff,0xf0,0x00,0x5d,0x00,0x54,0xff,0xf0,0x00,0x5d,0x00,0xa9,0xff,0xf0,0x00,0x5d,0x00,0xaa,0xff,0xf0, +0x00,0x5d,0x00,0xab,0xff,0xf0,0x00,0x5d,0x00,0xac,0xff,0xf0,0x00,0x5d,0x00,0xad,0xff,0xf0,0x00,0x5d,0x00,0xb4,0xff,0xf0,0x00,0x5d,0x00,0xb5,0xff,0xf0,0x00,0x5d,0x00,0xb6,0xff,0xf0,0x00,0x5d,0x00,0xb7,0xff,0xf0,0x00,0x5d,0x00,0xb8,0xff,0xf0,0x00,0x5d,0x01,0x15,0xff,0xf0,0x00,0x5e,0x00,0x2d,0xff,0xec,0x00,0x5e,0x00,0x38, +0xff,0xec,0x00,0x5e,0x00,0x9b,0xff,0xec,0x00,0x5e,0x00,0x9c,0xff,0xec,0x00,0x5e,0x00,0x9d,0xff,0xec,0x00,0x5e,0x00,0x9e,0xff,0xec,0x00,0x82,0x00,0x05,0xff,0xb1,0x00,0x82,0x00,0x0a,0xff,0xb1,0x00,0x82,0x00,0x22,0xff,0xc3,0x00,0x82,0x00,0x37,0xff,0x7f,0x00,0x82,0x00,0x38,0xff,0xef,0x00,0x82,0x00,0x39,0xff,0xa9,0x00,0x82, +0x00,0x3a,0xff,0xbb,0x00,0x82,0x00,0x3c,0xff,0xa2,0x00,0x82,0x00,0x52,0xff,0xf4,0x00,0x82,0x00,0x57,0xff,0xef,0x00,0x82,0x00,0x59,0xff,0xce,0x00,0x82,0x00,0x5a,0xff,0xdf,0x00,0x82,0x00,0x5c,0xff,0xce,0x00,0x82,0x00,0x5d,0x00,0x0c,0x00,0x82,0x00,0x9b,0xff,0xef,0x00,0x82,0x00,0x9c,0xff,0xef,0x00,0x82,0x00,0x9d,0xff,0xef, +0x00,0x82,0x00,0x9e,0xff,0xef,0x00,0x82,0x00,0xb4,0xff,0xf4,0x00,0x82,0x00,0xb5,0xff,0xf4,0x00,0x82,0x00,0xb6,0xff,0xf4,0x00,0x82,0x00,0xb7,0xff,0xf4,0x00,0x82,0x00,0xb8,0xff,0xf4,0x00,0x82,0x00,0xc1,0xff,0xce,0x00,0x82,0x01,0x3a,0xff,0xa2,0x00,0x82,0x03,0x34,0xff,0xb1,0x00,0x82,0x03,0x35,0xff,0xb1,0x00,0x82,0x03,0x38, +0xff,0xb1,0x00,0x82,0x03,0x39,0xff,0xb1,0x00,0x83,0x00,0x05,0xff,0xb1,0x00,0x83,0x00,0x0a,0xff,0xb1,0x00,0x83,0x00,0x22,0xff,0xc3,0x00,0x83,0x00,0x37,0xff,0x7f,0x00,0x83,0x00,0x38,0xff,0xef,0x00,0x83,0x00,0x39,0xff,0xa9,0x00,0x83,0x00,0x3a,0xff,0xbb,0x00,0x83,0x00,0x3c,0xff,0xa2,0x00,0x83,0x00,0x52,0xff,0xf4,0x00,0x83, +0x00,0x57,0xff,0xef,0x00,0x83,0x00,0x59,0xff,0xce,0x00,0x83,0x00,0x5a,0xff,0xdf,0x00,0x83,0x00,0x5c,0xff,0xce,0x00,0x83,0x00,0x5d,0x00,0x0c,0x00,0x83,0x00,0x9b,0xff,0xef,0x00,0x83,0x00,0x9c,0xff,0xef,0x00,0x83,0x00,0x9d,0xff,0xef,0x00,0x83,0x00,0x9e,0xff,0xef,0x00,0x83,0x00,0xb4,0xff,0xf4,0x00,0x83,0x00,0xb5,0xff,0xf4, +0x00,0x83,0x00,0xb6,0xff,0xf4,0x00,0x83,0x00,0xb7,0xff,0xf4,0x00,0x83,0x00,0xb8,0xff,0xf4,0x00,0x83,0x00,0xc1,0xff,0xce,0x00,0x83,0x01,0x3a,0xff,0xa2,0x00,0x83,0x03,0x34,0xff,0xb1,0x00,0x83,0x03,0x35,0xff,0xb1,0x00,0x83,0x03,0x38,0xff,0xb1,0x00,0x83,0x03,0x39,0xff,0xb1,0x00,0x84,0x00,0x05,0xff,0xb1,0x00,0x84,0x00,0x0a, +0xff,0xb1,0x00,0x84,0x00,0x22,0xff,0xc3,0x00,0x84,0x00,0x37,0xff,0x7f,0x00,0x84,0x00,0x38,0xff,0xef,0x00,0x84,0x00,0x39,0xff,0xa9,0x00,0x84,0x00,0x3a,0xff,0xbb,0x00,0x84,0x00,0x3c,0xff,0xa2,0x00,0x84,0x00,0x52,0xff,0xf4,0x00,0x84,0x00,0x57,0xff,0xef,0x00,0x84,0x00,0x59,0xff,0xce,0x00,0x84,0x00,0x5a,0xff,0xdf,0x00,0x84, +0x00,0x5c,0xff,0xce,0x00,0x84,0x00,0x5d,0x00,0x0c,0x00,0x84,0x00,0x9b,0xff,0xef,0x00,0x84,0x00,0x9c,0xff,0xef,0x00,0x84,0x00,0x9d,0xff,0xef,0x00,0x84,0x00,0x9e,0xff,0xef,0x00,0x84,0x00,0xb4,0xff,0xf4,0x00,0x84,0x00,0xb5,0xff,0xf4,0x00,0x84,0x00,0xb6,0xff,0xf4,0x00,0x84,0x00,0xb7,0xff,0xf4,0x00,0x84,0x00,0xb8,0xff,0xf4, +0x00,0x84,0x00,0xc1,0xff,0xce,0x00,0x84,0x01,0x3a,0xff,0xa2,0x00,0x84,0x03,0x34,0xff,0xb1,0x00,0x84,0x03,0x35,0xff,0xb1,0x00,0x84,0x03,0x38,0xff,0xb1,0x00,0x84,0x03,0x39,0xff,0xb1,0x00,0x85,0x00,0x05,0xff,0xb1,0x00,0x85,0x00,0x0a,0xff,0xb1,0x00,0x85,0x00,0x22,0xff,0xc3,0x00,0x85,0x00,0x37,0xff,0x7f,0x00,0x85,0x00,0x38, +0xff,0xef,0x00,0x85,0x00,0x39,0xff,0xa9,0x00,0x85,0x00,0x3a,0xff,0xbb,0x00,0x85,0x00,0x3c,0xff,0xa2,0x00,0x85,0x00,0x52,0xff,0xf4,0x00,0x85,0x00,0x57,0xff,0xef,0x00,0x85,0x00,0x59,0xff,0xce,0x00,0x85,0x00,0x5a,0xff,0xdf,0x00,0x85,0x00,0x5c,0xff,0xce,0x00,0x85,0x00,0x5d,0x00,0x0c,0x00,0x85,0x00,0x9b,0xff,0xef,0x00,0x85, +0x00,0x9c,0xff,0xef,0x00,0x85,0x00,0x9d,0xff,0xef,0x00,0x85,0x00,0x9e,0xff,0xef,0x00,0x85,0x00,0xb4,0xff,0xf4,0x00,0x85,0x00,0xb5,0xff,0xf4,0x00,0x85,0x00,0xb6,0xff,0xf4,0x00,0x85,0x00,0xb7,0xff,0xf4,0x00,0x85,0x00,0xb8,0xff,0xf4,0x00,0x85,0x00,0xc1,0xff,0xce,0x00,0x85,0x01,0x3a,0xff,0xa2,0x00,0x85,0x03,0x34,0xff,0xb1, +0x00,0x85,0x03,0x35,0xff,0xb1,0x00,0x85,0x03,0x38,0xff,0xb1,0x00,0x85,0x03,0x39,0xff,0xb1,0x00,0x86,0x00,0x05,0xff,0xb1,0x00,0x86,0x00,0x0a,0xff,0xb1,0x00,0x86,0x00,0x22,0xff,0xc3,0x00,0x86,0x00,0x37,0xff,0x7f,0x00,0x86,0x00,0x38,0xff,0xef,0x00,0x86,0x00,0x39,0xff,0xa9,0x00,0x86,0x00,0x3a,0xff,0xbb,0x00,0x86,0x00,0x3c, +0xff,0xa2,0x00,0x86,0x00,0x52,0xff,0xf4,0x00,0x86,0x00,0x57,0xff,0xef,0x00,0x86,0x00,0x59,0xff,0xce,0x00,0x86,0x00,0x5a,0xff,0xdf,0x00,0x86,0x00,0x5c,0xff,0xce,0x00,0x86,0x00,0x5d,0x00,0x0c,0x00,0x86,0x00,0x9b,0xff,0xef,0x00,0x86,0x00,0x9c,0xff,0xef,0x00,0x86,0x00,0x9d,0xff,0xef,0x00,0x86,0x00,0x9e,0xff,0xef,0x00,0x86, +0x00,0xb4,0xff,0xf4,0x00,0x86,0x00,0xb5,0xff,0xf4,0x00,0x86,0x00,0xb6,0xff,0xf4,0x00,0x86,0x00,0xb7,0xff,0xf4,0x00,0x86,0x00,0xb8,0xff,0xf4,0x00,0x86,0x00,0xc1,0xff,0xce,0x00,0x86,0x01,0x3a,0xff,0xa2,0x00,0x86,0x03,0x34,0xff,0xb1,0x00,0x86,0x03,0x35,0xff,0xb1,0x00,0x86,0x03,0x38,0xff,0xb1,0x00,0x86,0x03,0x39,0xff,0xb1, +0x00,0x87,0x00,0x05,0xff,0xb1,0x00,0x87,0x00,0x0a,0xff,0xb1,0x00,0x87,0x00,0x22,0xff,0xc3,0x00,0x87,0x00,0x37,0xff,0x7f,0x00,0x87,0x00,0x38,0xff,0xef,0x00,0x87,0x00,0x39,0xff,0xa9,0x00,0x87,0x00,0x3a,0xff,0xbb,0x00,0x87,0x00,0x3c,0xff,0xa2,0x00,0x87,0x00,0x52,0xff,0xf4,0x00,0x87,0x00,0x57,0xff,0xef,0x00,0x87,0x00,0x59, +0xff,0xce,0x00,0x87,0x00,0x5a,0xff,0xdf,0x00,0x87,0x00,0x5c,0xff,0xce,0x00,0x87,0x00,0x5d,0x00,0x0c,0x00,0x87,0x00,0x9b,0xff,0xef,0x00,0x87,0x00,0x9c,0xff,0xef,0x00,0x87,0x00,0x9d,0xff,0xef,0x00,0x87,0x00,0x9e,0xff,0xef,0x00,0x87,0x00,0xb4,0xff,0xf4,0x00,0x87,0x00,0xb5,0xff,0xf4,0x00,0x87,0x00,0xb6,0xff,0xf4,0x00,0x87, +0x00,0xb7,0xff,0xf4,0x00,0x87,0x00,0xb8,0xff,0xf4,0x00,0x87,0x00,0xc1,0xff,0xce,0x00,0x87,0x01,0x3a,0xff,0xa2,0x00,0x87,0x03,0x34,0xff,0xb1,0x00,0x87,0x03,0x35,0xff,0xb1,0x00,0x87,0x03,0x38,0xff,0xb1,0x00,0x87,0x03,0x39,0xff,0xb1,0x00,0x89,0x00,0x0c,0xff,0xe6,0x00,0x89,0x00,0x37,0xff,0xe3,0x00,0x89,0x00,0x40,0xff,0xf4, +0x00,0x89,0x00,0x60,0xff,0xef,0x00,0x8a,0x00,0x46,0xff,0xed,0x00,0x8a,0x00,0x47,0xff,0xed,0x00,0x8a,0x00,0x48,0xff,0xed,0x00,0x8a,0x00,0x49,0xff,0xee,0x00,0x8a,0x00,0x4a,0xff,0xed,0x00,0x8a,0x00,0x52,0xff,0xed,0x00,0x8a,0x00,0x54,0xff,0xed,0x00,0x8a,0x00,0x58,0xff,0xef,0x00,0x8a,0x00,0x59,0xff,0xe6,0x00,0x8a,0x00,0x5a, +0xff,0xea,0x00,0x8a,0x00,0x5c,0xff,0xe6,0x00,0x8a,0x00,0xa9,0xff,0xed,0x00,0x8a,0x00,0xaa,0xff,0xed,0x00,0x8a,0x00,0xab,0xff,0xed,0x00,0x8a,0x00,0xac,0xff,0xed,0x00,0x8a,0x00,0xad,0xff,0xed,0x00,0x8a,0x00,0xb4,0xff,0xed,0x00,0x8a,0x00,0xb5,0xff,0xed,0x00,0x8a,0x00,0xb6,0xff,0xed,0x00,0x8a,0x00,0xb7,0xff,0xed,0x00,0x8a, +0x00,0xb8,0xff,0xed,0x00,0x8a,0x00,0xbb,0xff,0xef,0x00,0x8a,0x00,0xbc,0xff,0xef,0x00,0x8a,0x00,0xbd,0xff,0xef,0x00,0x8a,0x00,0xbe,0xff,0xef,0x00,0x8a,0x00,0xc1,0xff,0xe6,0x00,0x8a,0x01,0x15,0xff,0xed,0x00,0x8b,0x00,0x46,0xff,0xed,0x00,0x8b,0x00,0x47,0xff,0xed,0x00,0x8b,0x00,0x48,0xff,0xed,0x00,0x8b,0x00,0x49,0xff,0xee, +0x00,0x8b,0x00,0x4a,0xff,0xed,0x00,0x8b,0x00,0x52,0xff,0xed,0x00,0x8b,0x00,0x54,0xff,0xed,0x00,0x8b,0x00,0x58,0xff,0xef,0x00,0x8b,0x00,0x59,0xff,0xe6,0x00,0x8b,0x00,0x5a,0xff,0xea,0x00,0x8b,0x00,0x5c,0xff,0xe6,0x00,0x8b,0x00,0xa9,0xff,0xed,0x00,0x8b,0x00,0xaa,0xff,0xed,0x00,0x8b,0x00,0xab,0xff,0xed,0x00,0x8b,0x00,0xac, +0xff,0xed,0x00,0x8b,0x00,0xad,0xff,0xed,0x00,0x8b,0x00,0xb4,0xff,0xed,0x00,0x8b,0x00,0xb5,0xff,0xed,0x00,0x8b,0x00,0xb6,0xff,0xed,0x00,0x8b,0x00,0xb7,0xff,0xed,0x00,0x8b,0x00,0xb8,0xff,0xed,0x00,0x8b,0x00,0xbb,0xff,0xef,0x00,0x8b,0x00,0xbc,0xff,0xef,0x00,0x8b,0x00,0xbd,0xff,0xef,0x00,0x8b,0x00,0xbe,0xff,0xef,0x00,0x8b, +0x00,0xc1,0xff,0xe6,0x00,0x8b,0x01,0x15,0xff,0xed,0x00,0x8c,0x00,0x46,0xff,0xed,0x00,0x8c,0x00,0x47,0xff,0xed,0x00,0x8c,0x00,0x48,0xff,0xed,0x00,0x8c,0x00,0x49,0xff,0xee,0x00,0x8c,0x00,0x4a,0xff,0xed,0x00,0x8c,0x00,0x52,0xff,0xed,0x00,0x8c,0x00,0x54,0xff,0xed,0x00,0x8c,0x00,0x58,0xff,0xef,0x00,0x8c,0x00,0x59,0xff,0xe6, +0x00,0x8c,0x00,0x5a,0xff,0xea,0x00,0x8c,0x00,0x5c,0xff,0xe6,0x00,0x8c,0x00,0xa9,0xff,0xed,0x00,0x8c,0x00,0xaa,0xff,0xed,0x00,0x8c,0x00,0xab,0xff,0xed,0x00,0x8c,0x00,0xac,0xff,0xed,0x00,0x8c,0x00,0xad,0xff,0xed,0x00,0x8c,0x00,0xb4,0xff,0xed,0x00,0x8c,0x00,0xb5,0xff,0xed,0x00,0x8c,0x00,0xb6,0xff,0xed,0x00,0x8c,0x00,0xb7, +0xff,0xed,0x00,0x8c,0x00,0xb8,0xff,0xed,0x00,0x8c,0x00,0xbb,0xff,0xef,0x00,0x8c,0x00,0xbc,0xff,0xef,0x00,0x8c,0x00,0xbd,0xff,0xef,0x00,0x8c,0x00,0xbe,0xff,0xef,0x00,0x8c,0x00,0xc1,0xff,0xe6,0x00,0x8c,0x01,0x15,0xff,0xed,0x00,0x8d,0x00,0x46,0xff,0xed,0x00,0x8d,0x00,0x47,0xff,0xed,0x00,0x8d,0x00,0x48,0xff,0xed,0x00,0x8d, +0x00,0x49,0xff,0xee,0x00,0x8d,0x00,0x4a,0xff,0xed,0x00,0x8d,0x00,0x52,0xff,0xed,0x00,0x8d,0x00,0x54,0xff,0xed,0x00,0x8d,0x00,0x58,0xff,0xef,0x00,0x8d,0x00,0x59,0xff,0xe6,0x00,0x8d,0x00,0x5a,0xff,0xea,0x00,0x8d,0x00,0x5c,0xff,0xe6,0x00,0x8d,0x00,0xa9,0xff,0xed,0x00,0x8d,0x00,0xaa,0xff,0xed,0x00,0x8d,0x00,0xab,0xff,0xed, +0x00,0x8d,0x00,0xac,0xff,0xed,0x00,0x8d,0x00,0xad,0xff,0xed,0x00,0x8d,0x00,0xb4,0xff,0xed,0x00,0x8d,0x00,0xb5,0xff,0xed,0x00,0x8d,0x00,0xb6,0xff,0xed,0x00,0x8d,0x00,0xb7,0xff,0xed,0x00,0x8d,0x00,0xb8,0xff,0xed,0x00,0x8d,0x00,0xbb,0xff,0xef,0x00,0x8d,0x00,0xbc,0xff,0xef,0x00,0x8d,0x00,0xbd,0xff,0xef,0x00,0x8d,0x00,0xbe, +0xff,0xef,0x00,0x8d,0x00,0xc1,0xff,0xe6,0x00,0x8d,0x01,0x15,0xff,0xed,0x00,0x8e,0x00,0x24,0x00,0x12,0x00,0x8e,0x00,0x37,0xff,0xe3,0x00,0x8e,0x00,0x3b,0x00,0x11,0x00,0x8e,0x00,0x3c,0xff,0xe4,0x00,0x8e,0x00,0x82,0x00,0x12,0x00,0x8e,0x00,0x83,0x00,0x12,0x00,0x8e,0x00,0x84,0x00,0x12,0x00,0x8e,0x00,0x85,0x00,0x12,0x00,0x8e, +0x00,0x86,0x00,0x12,0x00,0x8e,0x00,0x87,0x00,0x12,0x00,0x8e,0x01,0x3a,0xff,0xe4,0x00,0x8e,0x01,0x6f,0x00,0x12,0x00,0x8f,0x00,0x24,0x00,0x12,0x00,0x8f,0x00,0x37,0xff,0xe3,0x00,0x8f,0x00,0x3b,0x00,0x11,0x00,0x8f,0x00,0x3c,0xff,0xe4,0x00,0x8f,0x00,0x82,0x00,0x12,0x00,0x8f,0x00,0x83,0x00,0x12,0x00,0x8f,0x00,0x84,0x00,0x12, +0x00,0x8f,0x00,0x85,0x00,0x12,0x00,0x8f,0x00,0x86,0x00,0x12,0x00,0x8f,0x00,0x87,0x00,0x12,0x00,0x8f,0x01,0x3a,0xff,0xe4,0x00,0x8f,0x01,0x6f,0x00,0x12,0x00,0x90,0x00,0x24,0x00,0x12,0x00,0x90,0x00,0x37,0xff,0xe3,0x00,0x90,0x00,0x3b,0x00,0x11,0x00,0x90,0x00,0x3c,0xff,0xe4,0x00,0x90,0x00,0x82,0x00,0x12,0x00,0x90,0x00,0x83, +0x00,0x12,0x00,0x90,0x00,0x84,0x00,0x12,0x00,0x90,0x00,0x85,0x00,0x12,0x00,0x90,0x00,0x86,0x00,0x12,0x00,0x90,0x00,0x87,0x00,0x12,0x00,0x90,0x01,0x3a,0xff,0xe4,0x00,0x90,0x01,0x6f,0x00,0x12,0x00,0x91,0x00,0x24,0x00,0x12,0x00,0x91,0x00,0x37,0xff,0xe3,0x00,0x91,0x00,0x3b,0x00,0x11,0x00,0x91,0x00,0x3c,0xff,0xe4,0x00,0x91, +0x00,0x82,0x00,0x12,0x00,0x91,0x00,0x83,0x00,0x12,0x00,0x91,0x00,0x84,0x00,0x12,0x00,0x91,0x00,0x85,0x00,0x12,0x00,0x91,0x00,0x86,0x00,0x12,0x00,0x91,0x00,0x87,0x00,0x12,0x00,0x91,0x01,0x3a,0xff,0xe4,0x00,0x91,0x01,0x6f,0x00,0x12,0x00,0x93,0x00,0x24,0x00,0x12,0x00,0x93,0x00,0x37,0xff,0xe3,0x00,0x93,0x00,0x3b,0x00,0x11, +0x00,0x93,0x00,0x3c,0xff,0xe4,0x00,0x93,0x00,0x82,0x00,0x12,0x00,0x93,0x00,0x83,0x00,0x12,0x00,0x93,0x00,0x84,0x00,0x12,0x00,0x93,0x00,0x85,0x00,0x12,0x00,0x93,0x00,0x86,0x00,0x12,0x00,0x93,0x00,0x87,0x00,0x12,0x00,0x93,0x01,0x3a,0xff,0xe4,0x00,0x93,0x01,0x6f,0x00,0x12,0x00,0x94,0x00,0x0f,0xff,0x9a,0x00,0x94,0x00,0x11, +0xff,0x9a,0x00,0x94,0x00,0x1d,0xff,0x9a,0x00,0x94,0x00,0x24,0xff,0xeb,0x00,0x94,0x00,0x37,0xff,0xe5,0x00,0x94,0x00,0x39,0xff,0xea,0x00,0x94,0x00,0x3b,0xff,0xea,0x00,0x94,0x00,0x3c,0xff,0xd5,0x00,0x94,0x00,0x3d,0xff,0xe9,0x00,0x94,0x00,0x82,0xff,0xeb,0x00,0x94,0x00,0x83,0xff,0xeb,0x00,0x94,0x00,0x84,0xff,0xeb,0x00,0x94, +0x00,0x85,0xff,0xeb,0x00,0x94,0x00,0x86,0xff,0xeb,0x00,0x94,0x00,0x87,0xff,0xeb,0x00,0x94,0x00,0x88,0xff,0xdf,0x00,0x94,0x01,0x3a,0xff,0xd5,0x00,0x94,0x01,0x6f,0xff,0xeb,0x00,0x94,0x03,0x36,0xff,0x9a,0x00,0x94,0x03,0x3a,0xff,0x9a,0x00,0x94,0x03,0x3f,0xff,0x9a,0x00,0x95,0x00,0x0f,0xff,0x9a,0x00,0x95,0x00,0x11,0xff,0x9a, +0x00,0x95,0x00,0x1d,0xff,0x9a,0x00,0x95,0x00,0x24,0xff,0xeb,0x00,0x95,0x00,0x37,0xff,0xe5,0x00,0x95,0x00,0x39,0xff,0xea,0x00,0x95,0x00,0x3b,0xff,0xea,0x00,0x95,0x00,0x3c,0xff,0xd5,0x00,0x95,0x00,0x3d,0xff,0xe9,0x00,0x95,0x00,0x82,0xff,0xeb,0x00,0x95,0x00,0x83,0xff,0xeb,0x00,0x95,0x00,0x84,0xff,0xeb,0x00,0x95,0x00,0x85, +0xff,0xeb,0x00,0x95,0x00,0x86,0xff,0xeb,0x00,0x95,0x00,0x87,0xff,0xeb,0x00,0x95,0x00,0x88,0xff,0xdf,0x00,0x95,0x01,0x3a,0xff,0xd5,0x00,0x95,0x01,0x6f,0xff,0xeb,0x00,0x95,0x03,0x36,0xff,0x9a,0x00,0x95,0x03,0x3a,0xff,0x9a,0x00,0x95,0x03,0x3f,0xff,0x9a,0x00,0x96,0x00,0x0f,0xff,0x9a,0x00,0x96,0x00,0x11,0xff,0x9a,0x00,0x96, +0x00,0x1d,0xff,0x9a,0x00,0x96,0x00,0x24,0xff,0xeb,0x00,0x96,0x00,0x37,0xff,0xe5,0x00,0x96,0x00,0x39,0xff,0xea,0x00,0x96,0x00,0x3b,0xff,0xea,0x00,0x96,0x00,0x3c,0xff,0xd5,0x00,0x96,0x00,0x3d,0xff,0xe9,0x00,0x96,0x00,0x82,0xff,0xeb,0x00,0x96,0x00,0x83,0xff,0xeb,0x00,0x96,0x00,0x84,0xff,0xeb,0x00,0x96,0x00,0x85,0xff,0xeb, +0x00,0x96,0x00,0x86,0xff,0xeb,0x00,0x96,0x00,0x87,0xff,0xeb,0x00,0x96,0x00,0x88,0xff,0xdf,0x00,0x96,0x01,0x3a,0xff,0xd5,0x00,0x96,0x01,0x6f,0xff,0xeb,0x00,0x96,0x03,0x36,0xff,0x9a,0x00,0x96,0x03,0x3a,0xff,0x9a,0x00,0x96,0x03,0x3f,0xff,0x9a,0x00,0x97,0x00,0x0f,0xff,0x9a,0x00,0x97,0x00,0x11,0xff,0x9a,0x00,0x97,0x00,0x1d, +0xff,0x9a,0x00,0x97,0x00,0x24,0xff,0xeb,0x00,0x97,0x00,0x37,0xff,0xe5,0x00,0x97,0x00,0x39,0xff,0xea,0x00,0x97,0x00,0x3b,0xff,0xea,0x00,0x97,0x00,0x3c,0xff,0xd5,0x00,0x97,0x00,0x3d,0xff,0xe9,0x00,0x97,0x00,0x82,0xff,0xeb,0x00,0x97,0x00,0x83,0xff,0xeb,0x00,0x97,0x00,0x84,0xff,0xeb,0x00,0x97,0x00,0x85,0xff,0xeb,0x00,0x97, +0x00,0x86,0xff,0xeb,0x00,0x97,0x00,0x87,0xff,0xeb,0x00,0x97,0x00,0x88,0xff,0xdf,0x00,0x97,0x01,0x3a,0xff,0xd5,0x00,0x97,0x01,0x6f,0xff,0xeb,0x00,0x97,0x03,0x36,0xff,0x9a,0x00,0x97,0x03,0x3a,0xff,0x9a,0x00,0x97,0x03,0x3f,0xff,0x9a,0x00,0x98,0x00,0x0f,0xff,0x9a,0x00,0x98,0x00,0x11,0xff,0x9a,0x00,0x98,0x00,0x1d,0xff,0x9a, +0x00,0x98,0x00,0x24,0xff,0xeb,0x00,0x98,0x00,0x37,0xff,0xe5,0x00,0x98,0x00,0x39,0xff,0xea,0x00,0x98,0x00,0x3b,0xff,0xea,0x00,0x98,0x00,0x3c,0xff,0xd5,0x00,0x98,0x00,0x3d,0xff,0xe9,0x00,0x98,0x00,0x82,0xff,0xeb,0x00,0x98,0x00,0x83,0xff,0xeb,0x00,0x98,0x00,0x84,0xff,0xeb,0x00,0x98,0x00,0x85,0xff,0xeb,0x00,0x98,0x00,0x86, +0xff,0xeb,0x00,0x98,0x00,0x87,0xff,0xeb,0x00,0x98,0x00,0x88,0xff,0xdf,0x00,0x98,0x01,0x3a,0xff,0xd5,0x00,0x98,0x01,0x6f,0xff,0xeb,0x00,0x98,0x03,0x36,0xff,0x9a,0x00,0x98,0x03,0x3a,0xff,0x9a,0x00,0x98,0x03,0x3f,0xff,0x9a,0x00,0x9b,0x00,0x24,0xff,0xea,0x00,0x9b,0x00,0x82,0xff,0xea,0x00,0x9b,0x00,0x83,0xff,0xea,0x00,0x9b, +0x00,0x84,0xff,0xea,0x00,0x9b,0x00,0x85,0xff,0xea,0x00,0x9b,0x00,0x86,0xff,0xea,0x00,0x9b,0x00,0x87,0xff,0xea,0x00,0x9b,0x01,0x6f,0xff,0xea,0x00,0x9c,0x00,0x24,0xff,0xea,0x00,0x9c,0x00,0x82,0xff,0xea,0x00,0x9c,0x00,0x83,0xff,0xea,0x00,0x9c,0x00,0x84,0xff,0xea,0x00,0x9c,0x00,0x85,0xff,0xea,0x00,0x9c,0x00,0x86,0xff,0xea, +0x00,0x9c,0x00,0x87,0xff,0xea,0x00,0x9c,0x01,0x6f,0xff,0xea,0x00,0x9d,0x00,0x24,0xff,0xea,0x00,0x9d,0x00,0x82,0xff,0xea,0x00,0x9d,0x00,0x83,0xff,0xea,0x00,0x9d,0x00,0x84,0xff,0xea,0x00,0x9d,0x00,0x85,0xff,0xea,0x00,0x9d,0x00,0x86,0xff,0xea,0x00,0x9d,0x00,0x87,0xff,0xea,0x00,0x9d,0x01,0x6f,0xff,0xea,0x00,0x9e,0x00,0x24, +0xff,0xea,0x00,0x9e,0x00,0x82,0xff,0xea,0x00,0x9e,0x00,0x83,0xff,0xea,0x00,0x9e,0x00,0x84,0xff,0xea,0x00,0x9e,0x00,0x85,0xff,0xea,0x00,0x9e,0x00,0x86,0xff,0xea,0x00,0x9e,0x00,0x87,0xff,0xea,0x00,0x9e,0x01,0x6f,0xff,0xea,0x00,0xa2,0x00,0x05,0xff,0xbd,0x00,0xa2,0x00,0x0a,0xff,0xbd,0x00,0xa2,0x00,0x59,0xff,0xf1,0x00,0xa2, +0x00,0x5c,0xff,0xf1,0x00,0xa2,0x00,0xc1,0xff,0xf1,0x00,0xa2,0x03,0x34,0xff,0xbd,0x00,0xa2,0x03,0x35,0xff,0xbd,0x00,0xa2,0x03,0x38,0xff,0xbd,0x00,0xa2,0x03,0x39,0xff,0xbd,0x00,0xa3,0x00,0x05,0xff,0xbd,0x00,0xa3,0x00,0x0a,0xff,0xbd,0x00,0xa3,0x00,0x59,0xff,0xf1,0x00,0xa3,0x00,0x5c,0xff,0xf1,0x00,0xa3,0x00,0xc1,0xff,0xf1, +0x00,0xa3,0x03,0x34,0xff,0xbd,0x00,0xa3,0x03,0x35,0xff,0xbd,0x00,0xa3,0x03,0x38,0xff,0xbd,0x00,0xa3,0x03,0x39,0xff,0xbd,0x00,0xa4,0x00,0x05,0xff,0xbd,0x00,0xa4,0x00,0x0a,0xff,0xbd,0x00,0xa4,0x00,0x59,0xff,0xf1,0x00,0xa4,0x00,0x5c,0xff,0xf1,0x00,0xa4,0x00,0xc1,0xff,0xf1,0x00,0xa4,0x03,0x34,0xff,0xbd,0x00,0xa4,0x03,0x35, +0xff,0xbd,0x00,0xa4,0x03,0x38,0xff,0xbd,0x00,0xa4,0x03,0x39,0xff,0xbd,0x00,0xa5,0x00,0x05,0xff,0xbd,0x00,0xa5,0x00,0x0a,0xff,0xbd,0x00,0xa5,0x00,0x59,0xff,0xf1,0x00,0xa5,0x00,0x5c,0xff,0xf1,0x00,0xa5,0x00,0xc1,0xff,0xf1,0x00,0xa5,0x03,0x34,0xff,0xbd,0x00,0xa5,0x03,0x35,0xff,0xbd,0x00,0xa5,0x03,0x38,0xff,0xbd,0x00,0xa5, +0x03,0x39,0xff,0xbd,0x00,0xa6,0x00,0x05,0xff,0xbd,0x00,0xa6,0x00,0x0a,0xff,0xbd,0x00,0xa6,0x00,0x59,0xff,0xf1,0x00,0xa6,0x00,0x5c,0xff,0xf1,0x00,0xa6,0x00,0xc1,0xff,0xf1,0x00,0xa6,0x03,0x34,0xff,0xbd,0x00,0xa6,0x03,0x35,0xff,0xbd,0x00,0xa6,0x03,0x38,0xff,0xbd,0x00,0xa6,0x03,0x39,0xff,0xbd,0x00,0xa7,0x00,0x05,0xff,0xbd, +0x00,0xa7,0x00,0x0a,0xff,0xbd,0x00,0xa7,0x00,0x59,0xff,0xf1,0x00,0xa7,0x00,0x5c,0xff,0xf1,0x00,0xa7,0x00,0xc1,0xff,0xf1,0x00,0xa7,0x03,0x34,0xff,0xbd,0x00,0xa7,0x03,0x35,0xff,0xbd,0x00,0xa7,0x03,0x38,0xff,0xbd,0x00,0xa7,0x03,0x39,0xff,0xbd,0x00,0xaa,0x00,0x05,0xff,0xf2,0x00,0xaa,0x00,0x0a,0xff,0xf2,0x00,0xaa,0x00,0x59, +0xff,0xf3,0x00,0xaa,0x00,0x5c,0xff,0xf3,0x00,0xaa,0x00,0xc1,0xff,0xf3,0x00,0xaa,0x03,0x34,0xff,0xf2,0x00,0xaa,0x03,0x35,0xff,0xf2,0x00,0xaa,0x03,0x38,0xff,0xf2,0x00,0xaa,0x03,0x39,0xff,0xf2,0x00,0xab,0x00,0x05,0xff,0xf2,0x00,0xab,0x00,0x0a,0xff,0xf2,0x00,0xab,0x00,0x59,0xff,0xf3,0x00,0xab,0x00,0x5c,0xff,0xf3,0x00,0xab, +0x00,0xc1,0xff,0xf3,0x00,0xab,0x03,0x34,0xff,0xf2,0x00,0xab,0x03,0x35,0xff,0xf2,0x00,0xab,0x03,0x38,0xff,0xf2,0x00,0xab,0x03,0x39,0xff,0xf2,0x00,0xac,0x00,0x05,0xff,0xf2,0x00,0xac,0x00,0x0a,0xff,0xf2,0x00,0xac,0x00,0x59,0xff,0xf3,0x00,0xac,0x00,0x5c,0xff,0xf3,0x00,0xac,0x00,0xc1,0xff,0xf3,0x00,0xac,0x03,0x34,0xff,0xf2, +0x00,0xac,0x03,0x35,0xff,0xf2,0x00,0xac,0x03,0x38,0xff,0xf2,0x00,0xac,0x03,0x39,0xff,0xf2,0x00,0xad,0x00,0x05,0xff,0xf2,0x00,0xad,0x00,0x0a,0xff,0xf2,0x00,0xad,0x00,0x59,0xff,0xf3,0x00,0xad,0x00,0x5c,0xff,0xf3,0x00,0xad,0x00,0xc1,0xff,0xf3,0x00,0xad,0x03,0x34,0xff,0xf2,0x00,0xad,0x03,0x35,0xff,0xf2,0x00,0xad,0x03,0x38, +0xff,0xf2,0x00,0xad,0x03,0x39,0xff,0xf2,0x00,0xb3,0x00,0x05,0xff,0xf0,0x00,0xb3,0x00,0x0a,0xff,0xf0,0x00,0xb3,0x03,0x34,0xff,0xf0,0x00,0xb3,0x03,0x35,0xff,0xf0,0x00,0xb3,0x03,0x38,0xff,0xf0,0x00,0xb3,0x03,0x39,0xff,0xf0,0x00,0xb4,0x00,0x05,0xff,0xec,0x00,0xb4,0x00,0x0a,0xff,0xec,0x00,0xb4,0x00,0x59,0xff,0xf1,0x00,0xb4, +0x00,0x5b,0xff,0xeb,0x00,0xb4,0x00,0x5c,0xff,0xf1,0x00,0xb4,0x00,0x5d,0xff,0xf0,0x00,0xb4,0x00,0xc1,0xff,0xf1,0x00,0xb4,0x03,0x34,0xff,0xec,0x00,0xb4,0x03,0x35,0xff,0xec,0x00,0xb4,0x03,0x38,0xff,0xec,0x00,0xb4,0x03,0x39,0xff,0xec,0x00,0xb5,0x00,0x05,0xff,0xec,0x00,0xb5,0x00,0x0a,0xff,0xec,0x00,0xb5,0x00,0x59,0xff,0xf1, +0x00,0xb5,0x00,0x5b,0xff,0xeb,0x00,0xb5,0x00,0x5c,0xff,0xf1,0x00,0xb5,0x00,0x5d,0xff,0xf0,0x00,0xb5,0x00,0xc1,0xff,0xf1,0x00,0xb5,0x03,0x34,0xff,0xec,0x00,0xb5,0x03,0x35,0xff,0xec,0x00,0xb5,0x03,0x38,0xff,0xec,0x00,0xb5,0x03,0x39,0xff,0xec,0x00,0xb6,0x00,0x05,0xff,0xec,0x00,0xb6,0x00,0x0a,0xff,0xec,0x00,0xb6,0x00,0x59, +0xff,0xf1,0x00,0xb6,0x00,0x5b,0xff,0xeb,0x00,0xb6,0x00,0x5c,0xff,0xf1,0x00,0xb6,0x00,0x5d,0xff,0xf0,0x00,0xb6,0x00,0xc1,0xff,0xf1,0x00,0xb6,0x03,0x34,0xff,0xec,0x00,0xb6,0x03,0x35,0xff,0xec,0x00,0xb6,0x03,0x38,0xff,0xec,0x00,0xb6,0x03,0x39,0xff,0xec,0x00,0xb7,0x00,0x05,0xff,0xec,0x00,0xb7,0x00,0x0a,0xff,0xec,0x00,0xb7, +0x00,0x59,0xff,0xf1,0x00,0xb7,0x00,0x5b,0xff,0xeb,0x00,0xb7,0x00,0x5c,0xff,0xf1,0x00,0xb7,0x00,0x5d,0xff,0xf0,0x00,0xb7,0x00,0xc1,0xff,0xf1,0x00,0xb7,0x03,0x34,0xff,0xec,0x00,0xb7,0x03,0x35,0xff,0xec,0x00,0xb7,0x03,0x38,0xff,0xec,0x00,0xb7,0x03,0x39,0xff,0xec,0x00,0xb8,0x00,0x05,0xff,0xec,0x00,0xb8,0x00,0x0a,0xff,0xec, +0x00,0xb8,0x00,0x59,0xff,0xf1,0x00,0xb8,0x00,0x5b,0xff,0xeb,0x00,0xb8,0x00,0x5c,0xff,0xf1,0x00,0xb8,0x00,0x5d,0xff,0xf0,0x00,0xb8,0x00,0xc1,0xff,0xf1,0x00,0xb8,0x03,0x34,0xff,0xec,0x00,0xb8,0x03,0x35,0xff,0xec,0x00,0xb8,0x03,0x38,0xff,0xec,0x00,0xb8,0x03,0x39,0xff,0xec,0x00,0xc1,0x00,0x05,0x00,0x0f,0x00,0xc1,0x00,0x0a, +0x00,0x0f,0x00,0xc1,0x00,0x0f,0xff,0x95,0x00,0xc1,0x00,0x11,0xff,0x95,0x00,0xc1,0x00,0x1d,0xff,0x95,0x00,0xc1,0x00,0x44,0xff,0xf1,0x00,0xc1,0x00,0x46,0xff,0xf3,0x00,0xc1,0x00,0x47,0xff,0xf3,0x00,0xc1,0x00,0x48,0xff,0xf3,0x00,0xc1,0x00,0x49,0x00,0x0d,0x00,0xc1,0x00,0x4a,0xff,0xf3,0x00,0xc1,0x00,0x52,0xff,0xf1,0x00,0xc1, +0x00,0x54,0xff,0xf3,0x00,0xc1,0x00,0xa2,0xff,0xf1,0x00,0xc1,0x00,0xa3,0xff,0xf1,0x00,0xc1,0x00,0xa4,0xff,0xf1,0x00,0xc1,0x00,0xa5,0xff,0xf1,0x00,0xc1,0x00,0xa6,0xff,0xf1,0x00,0xc1,0x00,0xa7,0xff,0xf1,0x00,0xc1,0x00,0xa9,0xff,0xf3,0x00,0xc1,0x00,0xaa,0xff,0xf3,0x00,0xc1,0x00,0xab,0xff,0xf3,0x00,0xc1,0x00,0xac,0xff,0xf3, +0x00,0xc1,0x00,0xad,0xff,0xf3,0x00,0xc1,0x00,0xb4,0xff,0xf1,0x00,0xc1,0x00,0xb5,0xff,0xf1,0x00,0xc1,0x00,0xb6,0xff,0xf1,0x00,0xc1,0x00,0xb7,0xff,0xf1,0x00,0xc1,0x00,0xb8,0xff,0xf1,0x00,0xc1,0x01,0x15,0xff,0xf3,0x00,0xc1,0x03,0x34,0x00,0x0f,0x00,0xc1,0x03,0x35,0x00,0x0f,0x00,0xc1,0x03,0x36,0xff,0x95,0x00,0xc1,0x03,0x38, +0x00,0x0f,0x00,0xc1,0x03,0x39,0x00,0x0f,0x00,0xc1,0x03,0x3a,0xff,0x95,0x00,0xc1,0x03,0x3f,0xff,0x95,0x01,0x3a,0x00,0x09,0xff,0xe2,0x01,0x3a,0x00,0x0c,0x00,0x14,0x01,0x3a,0x00,0x0d,0xff,0xcf,0x01,0x3a,0x00,0x0f,0xff,0x2d,0x01,0x3a,0x00,0x10,0xff,0xcc,0x01,0x3a,0x00,0x11,0xff,0x2d,0x01,0x3a,0x00,0x1d,0xff,0x2d,0x01,0x3a, +0x00,0x24,0xff,0xae,0x01,0x3a,0x00,0x26,0xff,0xe3,0x01,0x3a,0x00,0x2a,0xff,0xe3,0x01,0x3a,0x00,0x2d,0xff,0xa0,0x01,0x3a,0x00,0x32,0xff,0xe3,0x01,0x3a,0x00,0x34,0xff,0xe3,0x01,0x3a,0x00,0x36,0xff,0xf0,0x01,0x3a,0x00,0x37,0x00,0x11,0x01,0x3a,0x00,0x38,0xff,0xa0,0x01,0x3a,0x00,0x39,0x00,0x12,0x01,0x3a,0x00,0x3a,0x00,0x11, +0x01,0x3a,0x00,0x3b,0x00,0x0d,0x01,0x3a,0x00,0x3c,0x00,0x12,0x01,0x3a,0x00,0x40,0x00,0x12,0x01,0x3a,0x00,0x44,0xff,0xb7,0x01,0x3a,0x00,0x46,0xff,0xbf,0x01,0x3a,0x00,0x47,0xff,0xbf,0x01,0x3a,0x00,0x48,0xff,0xbf,0x01,0x3a,0x00,0x49,0xff,0xea,0x01,0x3a,0x00,0x4a,0xff,0xbf,0x01,0x3a,0x00,0x50,0xff,0xd8,0x01,0x3a,0x00,0x51, +0xff,0xd8,0x01,0x3a,0x00,0x52,0xff,0xbf,0x01,0x3a,0x00,0x53,0xff,0xd8,0x01,0x3a,0x00,0x54,0xff,0xbf,0x01,0x3a,0x00,0x55,0xff,0xd8,0x01,0x3a,0x00,0x56,0xff,0xc6,0x01,0x3a,0x00,0x57,0xff,0xea,0x01,0x3a,0x00,0x58,0xff,0xd9,0x01,0x3a,0x00,0x59,0xff,0xec,0x01,0x3a,0x00,0x5b,0xff,0xe9,0x01,0x3a,0x00,0x5c,0xff,0xec,0x01,0x3a, +0x00,0x5d,0xff,0xe2,0x01,0x3a,0x00,0x60,0x00,0x13,0x01,0x3a,0x00,0x6d,0xff,0xae,0x01,0x3a,0x00,0x7d,0xff,0xcd,0x01,0x3a,0x00,0x82,0xff,0xae,0x01,0x3a,0x00,0x83,0xff,0xae,0x01,0x3a,0x00,0x84,0xff,0xae,0x01,0x3a,0x00,0x85,0xff,0xae,0x01,0x3a,0x00,0x86,0xff,0xae,0x01,0x3a,0x00,0x87,0xff,0xae,0x01,0x3a,0x00,0x88,0xff,0xa0, +0x01,0x3a,0x00,0x89,0xff,0xe3,0x01,0x3a,0x00,0x94,0xff,0xe3,0x01,0x3a,0x00,0x95,0xff,0xe3,0x01,0x3a,0x00,0x96,0xff,0xe3,0x01,0x3a,0x00,0x97,0xff,0xe3,0x01,0x3a,0x00,0x98,0xff,0xe3,0x01,0x3a,0x00,0x9a,0xff,0xe3,0x01,0x3a,0x00,0x9b,0xff,0xa0,0x01,0x3a,0x00,0x9c,0xff,0xa0,0x01,0x3a,0x00,0x9d,0xff,0xa0,0x01,0x3a,0x00,0x9e, +0xff,0xa0,0x01,0x3a,0x00,0xa2,0xff,0xb7,0x01,0x3a,0x00,0xa3,0xff,0xb7,0x01,0x3a,0x00,0xa4,0xff,0xb7,0x01,0x3a,0x00,0xa5,0xff,0xb7,0x01,0x3a,0x00,0xa6,0xff,0xb7,0x01,0x3a,0x00,0xa7,0xff,0xb7,0x01,0x3a,0x00,0xa8,0xff,0xc1,0x01,0x3a,0x00,0xa9,0xff,0xbf,0x01,0x3a,0x00,0xaa,0xff,0xbf,0x01,0x3a,0x00,0xab,0xff,0xbf,0x01,0x3a, +0x00,0xac,0xff,0xbf,0x01,0x3a,0x00,0xad,0xff,0xbf,0x01,0x3a,0x00,0xb3,0xff,0xd8,0x01,0x3a,0x00,0xb4,0xff,0xbf,0x01,0x3a,0x00,0xb5,0xff,0xbf,0x01,0x3a,0x00,0xb6,0xff,0xbf,0x01,0x3a,0x00,0xb7,0xff,0xbf,0x01,0x3a,0x00,0xb8,0xff,0xbf,0x01,0x3a,0x00,0xba,0xff,0xc0,0x01,0x3a,0x00,0xbb,0xff,0xd9,0x01,0x3a,0x00,0xbc,0xff,0xd9, +0x01,0x3a,0x00,0xbd,0xff,0xd9,0x01,0x3a,0x00,0xbe,0xff,0xd9,0x01,0x3a,0x00,0xc1,0xff,0xec,0x01,0x3a,0x01,0x14,0xff,0xe3,0x01,0x3a,0x01,0x15,0xff,0xbf,0x01,0x3a,0x01,0x3a,0x00,0x12,0x01,0x3a,0x01,0x6f,0xff,0xae,0x01,0x3a,0x01,0x9a,0xff,0xe8,0x01,0x3a,0x03,0x30,0xff,0xcc,0x01,0x3a,0x03,0x31,0xff,0xcc,0x01,0x3a,0x03,0x36, +0xff,0x2d,0x01,0x3a,0x03,0x3a,0xff,0x2d,0x01,0x3a,0x03,0x3d,0xff,0xd3,0x01,0x3a,0x03,0x3f,0xff,0x2d,0x01,0x6f,0x00,0x05,0xff,0xb1,0x01,0x6f,0x00,0x0a,0xff,0xb1,0x01,0x6f,0x00,0x22,0xff,0xc3,0x01,0x6f,0x00,0x37,0xff,0x7f,0x01,0x6f,0x00,0x38,0xff,0xef,0x01,0x6f,0x00,0x39,0xff,0xa9,0x01,0x6f,0x00,0x3a,0xff,0xbb,0x01,0x6f, +0x00,0x3c,0xff,0xa2,0x01,0x6f,0x00,0x52,0xff,0xf4,0x01,0x6f,0x00,0x57,0xff,0xef,0x01,0x6f,0x00,0x59,0xff,0xce,0x01,0x6f,0x00,0x5a,0xff,0xdf,0x01,0x6f,0x00,0x5c,0xff,0xce,0x01,0x6f,0x00,0x5d,0x00,0x0c,0x01,0x6f,0x00,0x9b,0xff,0xef,0x01,0x6f,0x00,0x9c,0xff,0xef,0x01,0x6f,0x00,0x9d,0xff,0xef,0x01,0x6f,0x00,0x9e,0xff,0xef, +0x01,0x6f,0x00,0xb4,0xff,0xf4,0x01,0x6f,0x00,0xb5,0xff,0xf4,0x01,0x6f,0x00,0xb6,0xff,0xf4,0x01,0x6f,0x00,0xb7,0xff,0xf4,0x01,0x6f,0x00,0xb8,0xff,0xf4,0x01,0x6f,0x00,0xc1,0xff,0xce,0x01,0x6f,0x01,0x3a,0xff,0xa2,0x01,0x6f,0x03,0x34,0xff,0xb1,0x01,0x6f,0x03,0x35,0xff,0xb1,0x01,0x6f,0x03,0x38,0xff,0xb1,0x01,0x6f,0x03,0x39, +0xff,0xb1,0x03,0x34,0x00,0x05,0xff,0x95,0x03,0x34,0x00,0x0a,0xff,0x95,0x03,0x34,0x00,0x24,0xff,0x96,0x03,0x34,0x00,0x44,0xff,0xce,0x03,0x34,0x00,0x46,0xff,0xc5,0x03,0x34,0x00,0x47,0xff,0xc5,0x03,0x34,0x00,0x48,0xff,0xc5,0x03,0x34,0x00,0x4a,0xff,0xc5,0x03,0x34,0x00,0x50,0xff,0xec,0x03,0x34,0x00,0x51,0xff,0xec,0x03,0x34, +0x00,0x52,0xff,0xc3,0x03,0x34,0x00,0x53,0xff,0xec,0x03,0x34,0x00,0x54,0xff,0xc5,0x03,0x34,0x00,0x56,0xff,0xd6,0x03,0x34,0x00,0x82,0xff,0x96,0x03,0x34,0x00,0x83,0xff,0x96,0x03,0x34,0x00,0x84,0xff,0x96,0x03,0x34,0x00,0x85,0xff,0x96,0x03,0x34,0x00,0x86,0xff,0x96,0x03,0x34,0x00,0x87,0xff,0x96,0x03,0x34,0x00,0xa2,0xff,0xce, +0x03,0x34,0x00,0xa3,0xff,0xce,0x03,0x34,0x00,0xa4,0xff,0xce,0x03,0x34,0x00,0xa5,0xff,0xce,0x03,0x34,0x00,0xa6,0xff,0xce,0x03,0x34,0x00,0xa7,0xff,0xce,0x03,0x34,0x00,0xa9,0xff,0xc5,0x03,0x34,0x00,0xaa,0xff,0xc5,0x03,0x34,0x00,0xab,0xff,0xc5,0x03,0x34,0x00,0xac,0xff,0xc5,0x03,0x34,0x00,0xad,0xff,0xc5,0x03,0x34,0x00,0xb3, +0xff,0xec,0x03,0x34,0x00,0xb4,0xff,0xc3,0x03,0x34,0x00,0xb5,0xff,0xc3,0x03,0x34,0x00,0xb6,0xff,0xc3,0x03,0x34,0x00,0xb7,0xff,0xc3,0x03,0x34,0x00,0xb8,0xff,0xc3,0x03,0x34,0x01,0x15,0xff,0xc5,0x03,0x34,0x01,0x6f,0xff,0x96,0x03,0x34,0x03,0x34,0xff,0x95,0x03,0x34,0x03,0x35,0xff,0x95,0x03,0x34,0x03,0x38,0xff,0x95,0x03,0x34, +0x03,0x39,0xff,0x95,0x03,0x35,0x00,0x05,0xff,0x95,0x03,0x35,0x00,0x0a,0xff,0x95,0x03,0x35,0x00,0x24,0xff,0x96,0x03,0x35,0x00,0x44,0xff,0xce,0x03,0x35,0x00,0x46,0xff,0xc5,0x03,0x35,0x00,0x47,0xff,0xc5,0x03,0x35,0x00,0x48,0xff,0xc5,0x03,0x35,0x00,0x4a,0xff,0xc5,0x03,0x35,0x00,0x50,0xff,0xec,0x03,0x35,0x00,0x51,0xff,0xec, +0x03,0x35,0x00,0x52,0xff,0xc3,0x03,0x35,0x00,0x53,0xff,0xec,0x03,0x35,0x00,0x54,0xff,0xc5,0x03,0x35,0x00,0x56,0xff,0xd6,0x03,0x35,0x00,0x82,0xff,0x96,0x03,0x35,0x00,0x83,0xff,0x96,0x03,0x35,0x00,0x84,0xff,0x96,0x03,0x35,0x00,0x85,0xff,0x96,0x03,0x35,0x00,0x86,0xff,0x96,0x03,0x35,0x00,0x87,0xff,0x96,0x03,0x35,0x00,0xa2, +0xff,0xce,0x03,0x35,0x00,0xa3,0xff,0xce,0x03,0x35,0x00,0xa4,0xff,0xce,0x03,0x35,0x00,0xa5,0xff,0xce,0x03,0x35,0x00,0xa6,0xff,0xce,0x03,0x35,0x00,0xa7,0xff,0xce,0x03,0x35,0x00,0xa9,0xff,0xc5,0x03,0x35,0x00,0xaa,0xff,0xc5,0x03,0x35,0x00,0xab,0xff,0xc5,0x03,0x35,0x00,0xac,0xff,0xc5,0x03,0x35,0x00,0xad,0xff,0xc5,0x03,0x35, +0x00,0xb3,0xff,0xec,0x03,0x35,0x00,0xb4,0xff,0xc3,0x03,0x35,0x00,0xb5,0xff,0xc3,0x03,0x35,0x00,0xb6,0xff,0xc3,0x03,0x35,0x00,0xb7,0xff,0xc3,0x03,0x35,0x00,0xb8,0xff,0xc3,0x03,0x35,0x01,0x15,0xff,0xc5,0x03,0x35,0x01,0x6f,0xff,0x96,0x03,0x35,0x03,0x34,0xff,0x95,0x03,0x35,0x03,0x35,0xff,0x95,0x03,0x35,0x03,0x38,0xff,0x95, +0x03,0x35,0x03,0x39,0xff,0x95,0x03,0x38,0x00,0x05,0xff,0x95,0x03,0x38,0x00,0x0a,0xff,0x95,0x03,0x38,0x00,0x24,0xff,0x96,0x03,0x38,0x00,0x44,0xff,0xce,0x03,0x38,0x00,0x46,0xff,0xc5,0x03,0x38,0x00,0x47,0xff,0xc5,0x03,0x38,0x00,0x48,0xff,0xc5,0x03,0x38,0x00,0x4a,0xff,0xc5,0x03,0x38,0x00,0x50,0xff,0xec,0x03,0x38,0x00,0x51, +0xff,0xec,0x03,0x38,0x00,0x52,0xff,0xc3,0x03,0x38,0x00,0x53,0xff,0xec,0x03,0x38,0x00,0x54,0xff,0xc5,0x03,0x38,0x00,0x56,0xff,0xd6,0x03,0x38,0x00,0x82,0xff,0x96,0x03,0x38,0x00,0x83,0xff,0x96,0x03,0x38,0x00,0x84,0xff,0x96,0x03,0x38,0x00,0x85,0xff,0x96,0x03,0x38,0x00,0x86,0xff,0x96,0x03,0x38,0x00,0x87,0xff,0x96,0x03,0x38, +0x00,0xa2,0xff,0xce,0x03,0x38,0x00,0xa3,0xff,0xce,0x03,0x38,0x00,0xa4,0xff,0xce,0x03,0x38,0x00,0xa5,0xff,0xce,0x03,0x38,0x00,0xa6,0xff,0xce,0x03,0x38,0x00,0xa7,0xff,0xce,0x03,0x38,0x00,0xa9,0xff,0xc5,0x03,0x38,0x00,0xaa,0xff,0xc5,0x03,0x38,0x00,0xab,0xff,0xc5,0x03,0x38,0x00,0xac,0xff,0xc5,0x03,0x38,0x00,0xad,0xff,0xc5, +0x03,0x38,0x00,0xb3,0xff,0xec,0x03,0x38,0x00,0xb4,0xff,0xc3,0x03,0x38,0x00,0xb5,0xff,0xc3,0x03,0x38,0x00,0xb6,0xff,0xc3,0x03,0x38,0x00,0xb7,0xff,0xc3,0x03,0x38,0x00,0xb8,0xff,0xc3,0x03,0x38,0x01,0x15,0xff,0xc5,0x03,0x38,0x01,0x6f,0xff,0x96,0x03,0x38,0x03,0x34,0xff,0x95,0x03,0x38,0x03,0x35,0xff,0x95,0x03,0x38,0x03,0x38, +0xff,0x95,0x03,0x38,0x03,0x39,0xff,0x95,0x03,0x39,0x00,0x05,0xff,0x95,0x03,0x39,0x00,0x0a,0xff,0x95,0x03,0x39,0x00,0x24,0xff,0x96,0x03,0x39,0x00,0x44,0xff,0xce,0x03,0x39,0x00,0x46,0xff,0xc5,0x03,0x39,0x00,0x47,0xff,0xc5,0x03,0x39,0x00,0x48,0xff,0xc5,0x03,0x39,0x00,0x4a,0xff,0xc5,0x03,0x39,0x00,0x50,0xff,0xec,0x03,0x39, +0x00,0x51,0xff,0xec,0x03,0x39,0x00,0x52,0xff,0xc3,0x03,0x39,0x00,0x53,0xff,0xec,0x03,0x39,0x00,0x54,0xff,0xc5,0x03,0x39,0x00,0x56,0xff,0xd6,0x03,0x39,0x00,0x82,0xff,0x96,0x03,0x39,0x00,0x83,0xff,0x96,0x03,0x39,0x00,0x84,0xff,0x96,0x03,0x39,0x00,0x85,0xff,0x96,0x03,0x39,0x00,0x86,0xff,0x96,0x03,0x39,0x00,0x87,0xff,0x96, +0x03,0x39,0x00,0xa2,0xff,0xce,0x03,0x39,0x00,0xa3,0xff,0xce,0x03,0x39,0x00,0xa4,0xff,0xce,0x03,0x39,0x00,0xa5,0xff,0xce,0x03,0x39,0x00,0xa6,0xff,0xce,0x03,0x39,0x00,0xa7,0xff,0xce,0x03,0x39,0x00,0xa9,0xff,0xc5,0x03,0x39,0x00,0xaa,0xff,0xc5,0x03,0x39,0x00,0xab,0xff,0xc5,0x03,0x39,0x00,0xac,0xff,0xc5,0x03,0x39,0x00,0xad, +0xff,0xc5,0x03,0x39,0x00,0xb3,0xff,0xec,0x03,0x39,0x00,0xb4,0xff,0xc3,0x03,0x39,0x00,0xb5,0xff,0xc3,0x03,0x39,0x00,0xb6,0xff,0xc3,0x03,0x39,0x00,0xb7,0xff,0xc3,0x03,0x39,0x00,0xb8,0xff,0xc3,0x03,0x39,0x01,0x15,0xff,0xc5,0x03,0x39,0x01,0x6f,0xff,0x96,0x03,0x39,0x03,0x34,0xff,0x95,0x03,0x39,0x03,0x35,0xff,0x95,0x03,0x39, +0x03,0x38,0xff,0x95,0x03,0x39,0x03,0x39,0xff,0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x00,0x5c,0x00,0xda,0x01,0x48,0x01,0xca,0x02,0x72,0x02,0x96,0x02,0xd2,0x03,0x16,0x03,0x4a,0x03,0x82,0x03,0xac,0x03,0xd0,0x03,0xec,0x04,0x0a,0x04,0x50,0x04,0x72,0x04,0xc2,0x05,0x34,0x05,0x74,0x05,0xd4, +0x06,0x42,0x06,0x76,0x06,0xe2,0x07,0x4e,0x07,0x60,0x07,0x72,0x07,0x8e,0x07,0xbe,0x07,0xda,0x08,0x34,0x09,0x42,0x09,0x7c,0x09,0xdc,0x0a,0x3a,0x0a,0x7e,0x0a,0xb8,0x0a,0xea,0x0b,0x4a,0x0b,0x7c,0x0b,0x98,0x0b,0xd2,0x0c,0x0e,0x0c,0x32,0x0c,0x70,0x0c,0xa0,0x0c,0xec,0x0d,0x2e,0x0d,0x8a,0x0d,0xe6,0x0e,0x4a,0x0e,0x74,0x0e,0xae, +0x0e,0xdc,0x0f,0x26,0x0f,0x5c,0x0f,0x88,0x0f,0xbc,0x0f,0xec,0x10,0x0a,0x10,0x38,0x10,0x66,0x10,0x88,0x10,0xb0,0x11,0x44,0x11,0xb8,0x12,0x10,0x12,0x86,0x12,0xe6,0x13,0x2e,0x13,0xc0,0x13,0xfe,0x14,0x28,0x14,0x6e,0x14,0xa8,0x14,0xc4,0x15,0x34,0x15,0x88,0x15,0xce,0x16,0x46,0x16,0xbc,0x17,0x0e,0x17,0x70,0x17,0xbe,0x18,0x0e, +0x18,0x3c,0x18,0x9c,0x18,0xd2,0x19,0x1a,0x19,0x4e,0x19,0x9a,0x19,0xb8,0x1a,0x04,0x1a,0x50,0x1a,0x58,0x1a,0x94,0x1a,0xfc,0x1b,0x60,0x1b,0xd4,0x1c,0x26,0x1c,0x54,0x1c,0xe4,0x1d,0x0a,0x1d,0x9c,0x1e,0x4a,0x1e,0x60,0x1e,0x9c,0x1e,0xa4,0x1f,0x3c,0x1f,0x5a,0x1f,0x98,0x1f,0xda,0x20,0x28,0x20,0xbc,0x20,0xe4,0x21,0x46,0x21,0x74, +0x21,0x96,0x21,0xde,0x22,0x00,0x22,0x40,0x22,0x4c,0x22,0x68,0x22,0x84,0x22,0xa0,0x23,0x14,0x23,0x26,0x23,0x38,0x23,0x4a,0x23,0x5c,0x23,0x6e,0x23,0x80,0x23,0xd4,0x23,0xe6,0x23,0xf8,0x24,0x0a,0x24,0x1c,0x24,0x2e,0x24,0x40,0x24,0x52,0x24,0x64,0x24,0x76,0x24,0xcc,0x24,0xde,0x24,0xf0,0x25,0x02,0x25,0x14,0x25,0x26,0x25,0x38, +0x25,0x5e,0x25,0xfc,0x26,0x0e,0x26,0x20,0x26,0x32,0x26,0x44,0x26,0x56,0x26,0xa0,0x27,0x12,0x27,0x24,0x27,0x36,0x27,0x46,0x27,0x56,0x27,0x66,0x27,0x78,0x28,0x14,0x28,0x26,0x28,0x38,0x28,0x4a,0x28,0x5a,0x28,0x6a,0x28,0x7c,0x28,0x8c,0x28,0x9e,0x28,0xb0,0x29,0x22,0x29,0x32,0x29,0x44,0x29,0x56,0x29,0x66,0x29,0x76,0x29,0x86, +0x29,0xc2,0x2a,0x40,0x2a,0x52,0x2a,0x64,0x2a,0x74,0x2a,0x84,0x2a,0x96,0x2a,0xf0,0x2b,0x00,0x2b,0x12,0x2b,0x22,0x2b,0x34,0x2b,0x44,0x2b,0x50,0x2b,0x5c,0x2b,0x6e,0x2b,0x80,0x2b,0x92,0x2b,0xa2,0x2b,0xb4,0x2b,0xc6,0x2b,0xd8,0x2b,0xe8,0x2b,0xfa,0x2c,0x0c,0x2c,0x62,0x2c,0xf2,0x2d,0x04,0x2d,0x14,0x2d,0x26,0x2d,0x36,0x2d,0x48, +0x2d,0x5a,0x2d,0x66,0x2d,0x78,0x2d,0x8a,0x2d,0x9a,0x2d,0xac,0x2d,0xbc,0x2d,0xce,0x2d,0xe0,0x2d,0xf2,0x2e,0x04,0x2e,0x16,0x2e,0x28,0x2e,0x3a,0x2e,0x4c,0x2e,0x9c,0x2e,0xee,0x2f,0x00,0x2f,0x12,0x2f,0x24,0x2f,0x36,0x2f,0x48,0x2f,0x5a,0x2f,0x66,0x2f,0x72,0x2f,0x84,0x2f,0xa0,0x2f,0xac,0x2f,0xb8,0x2f,0xca,0x2f,0xdc,0x2f,0xee, +0x30,0x00,0x30,0x3c,0x30,0x4e,0x30,0x60,0x30,0x72,0x30,0x84,0x30,0x96,0x30,0xa8,0x30,0xba,0x30,0xcc,0x31,0x04,0x31,0x32,0x31,0x44,0x31,0x56,0x31,0x68,0x31,0x7a,0x31,0x8c,0x31,0x9c,0x31,0xae,0x32,0x00,0x32,0x74,0x32,0x86,0x32,0x96,0x32,0xa8,0x32,0xba,0x32,0xcc,0x32,0xde,0x33,0x9a,0x34,0x24,0x34,0x36,0x34,0x48,0x34,0x5a, +0x34,0x6c,0x34,0x7e,0x34,0x8e,0x34,0xa0,0x34,0xb2,0x34,0xc4,0x34,0xd4,0x34,0xe6,0x34,0xf8,0x35,0x0a,0x35,0x1a,0x35,0x2c,0x35,0x3e,0x35,0x50,0x35,0x62,0x35,0x9e,0x35,0xfe,0x36,0x10,0x36,0x20,0x36,0x32,0x36,0x44,0x36,0x56,0x36,0x68,0x36,0x7a,0x36,0x8c,0x36,0x9e,0x36,0xb0,0x36,0xbc,0x36,0xc8,0x36,0xda,0x36,0xec,0x36,0xfe, +0x37,0x0e,0x37,0x20,0x37,0x32,0x37,0x44,0x37,0x56,0x37,0x68,0x37,0x7a,0x37,0x8a,0x37,0xc0,0x38,0x20,0x38,0x80,0x38,0xdc,0x39,0x42,0x39,0xb8,0x39,0xca,0x39,0xdc,0x39,0xee,0x3a,0x00,0x3a,0x12,0x3a,0x24,0x3a,0x36,0x3a,0x48,0x3a,0x5a,0x3a,0x94,0x3a,0x9c,0x3a,0xd2,0x3b,0x08,0x3b,0x40,0x3b,0x5e,0x3b,0x9c,0x3b,0xd4,0x3c,0x4c, +0x3c,0x8a,0x3c,0xdc,0x3c,0xee,0x3d,0x00,0x3d,0x0a,0x3d,0x4a,0x3d,0x8a,0x3d,0xac,0x3d,0xca,0x3d,0xfe,0x3e,0x0a,0x3e,0x12,0x3e,0x24,0x3e,0x36,0x3e,0x48,0x3e,0x54,0x3e,0x60,0x3e,0x6c,0x3e,0x7e,0x3e,0x86,0x3e,0x8e,0x3e,0xb4,0x3e,0xe4,0x3e,0xec,0x3e,0xf4,0x3e,0xfc,0x3f,0x56,0x3f,0x5e,0x3f,0x66,0x3f,0x92,0x3f,0x9a,0x3f,0xa2, +0x3f,0xdc,0x3f,0xe4,0x40,0x0c,0x40,0x14,0x40,0x56,0x40,0x5e,0x40,0x66,0x40,0xce,0x40,0xd6,0x41,0x1a,0x41,0x72,0x41,0x84,0x41,0x96,0x41,0xa8,0x41,0xba,0x41,0xcc,0x41,0xde,0x41,0xf0,0x42,0x9c,0x43,0x2c,0x43,0x62,0x43,0xc4,0x44,0x34,0x44,0x8c,0x44,0xe4,0x45,0x38,0x45,0x72,0x45,0x7a,0x46,0x08,0x46,0x10,0x46,0x18,0x46,0x84, +0x46,0x8c,0x46,0xf0,0x47,0x44,0x47,0x98,0x47,0xe6,0x48,0x10,0x48,0x4e,0x48,0xaa,0x49,0x6a,0x49,0xba,0x4a,0x1e,0x4a,0x30,0x4a,0x40,0x4a,0x52,0x4a,0x64,0x4a,0x76,0x4a,0xe0,0x4c,0x02,0x4c,0x6e,0x4c,0x80,0x4c,0x92,0x4c,0xde,0x4c,0xf0,0x4d,0x5a,0x4d,0xbe,0x4d,0xc6,0x4d,0xd8,0x4d,0xe0,0x4e,0x40,0x4e,0xc6,0x4f,0x08,0x4f,0x1a, +0x4f,0x2c,0x4f,0x3e,0x4f,0x72,0x4f,0x7a,0x4f,0xc4,0x4f,0xcc,0x4f,0xd4,0x50,0x20,0x50,0x28,0x50,0x76,0x50,0xe6,0x51,0x16,0x51,0x28,0x51,0x30,0x51,0x6c,0x51,0x74,0x51,0x7c,0x51,0x84,0x51,0x8c,0x51,0x94,0x51,0x9c,0x51,0xa4,0x51,0xec,0x51,0xf4,0x51,0xfc,0x52,0x30,0x52,0x72,0x52,0xa6,0x52,0xe6,0x53,0x30,0x53,0x7c,0x53,0xbe, +0x54,0x28,0x54,0xa2,0x54,0xea,0x54,0xf2,0x55,0x88,0x55,0xe4,0x56,0x0a,0x56,0x58,0x56,0x60,0x56,0xae,0x57,0x1e,0x57,0x4e,0x57,0x60,0x57,0x9c,0x57,0xd8,0x58,0x16,0x58,0x48,0x58,0x50,0x58,0x78,0x58,0x80,0x58,0xd8,0x59,0x02,0x59,0x0a,0x59,0x94,0x59,0x9c,0x59,0xd0,0x5a,0x0e,0x5a,0x42,0x5a,0x82,0x5a,0xcc,0x5b,0x18,0x5b,0x58, +0x5b,0xc0,0x5c,0x4e,0x5c,0x9a,0x5c,0xac,0x5c,0xbc,0x5d,0x2e,0x5d,0x40,0x5d,0xaa,0x5d,0xb2,0x5d,0xba,0x5d,0xcc,0x5d,0xd4,0x5e,0x30,0x5e,0x82,0x5e,0xd4,0x5e,0xe6,0x5e,0xf8,0x5f,0x08,0x5f,0x3e,0x5f,0xcc,0x60,0x1c,0x60,0x70,0x60,0xc6,0x61,0x8c,0x62,0x5a,0x62,0x9c,0x62,0xe2,0x63,0x36,0x63,0x8c,0x63,0xf6,0x64,0x58,0x64,0xd6, +0x65,0x4c,0x65,0xce,0x66,0x50,0x66,0x58,0x66,0x60,0x66,0xde,0x67,0x5c,0x67,0xba,0x68,0x18,0x68,0x2a,0x68,0x3c,0x68,0x48,0x68,0x54,0x68,0xf8,0x69,0xd4,0x6a,0x94,0x6b,0x4e,0x6b,0xfe,0x6c,0x98,0x6d,0x00,0x6d,0x64,0x6d,0xaa,0x6e,0x0e,0x6e,0x5a,0x6e,0x7a,0x6e,0x9a,0x70,0x22,0x70,0xc8,0x70,0xe2,0x70,0xfc,0x71,0x50,0x71,0xa4, +0x71,0xf4,0x72,0x7a,0x72,0xaa,0x72,0xe6,0x73,0x20,0x73,0x5a,0x73,0xa2,0x73,0xe6,0x73,0xf2,0x73,0xfe,0x74,0x10,0x74,0x22,0x74,0x2e,0x74,0x3a,0x74,0x8a,0x74,0xd8,0x75,0x26,0x75,0x72,0x75,0xb6,0x75,0xfa,0x76,0x06,0x76,0x12,0x76,0x4c,0x76,0x86,0x76,0xd2,0x77,0x1c,0x77,0xae,0x78,0x46,0x78,0x58,0x78,0x6a,0x78,0x76,0x78,0x82, +0x78,0x8a,0x78,0x92,0x78,0xd2,0x79,0x16,0x79,0x22,0x79,0x2e,0x79,0x76,0x79,0xb6,0x79,0xc2,0x79,0xce,0x7a,0x5a,0x7a,0xe2,0x7b,0x22,0x7b,0x32,0x7b,0xaa,0x7c,0x1a,0x7c,0x26,0x7c,0x32,0x7c,0x3a,0x7c,0x4c,0x7c,0x5e,0x7c,0xa6,0x7c,0xee,0x7d,0x00,0x7d,0x12,0x7d,0x62,0x7d,0xb2,0x7d,0xc4,0x7d,0xd6,0x7d,0xe2,0x7d,0xee,0x7e,0x00, +0x7e,0x12,0x7e,0x1a,0x7e,0x2c,0x7e,0x3c,0x7e,0x4e,0x7e,0x5e,0x7e,0x66,0x7e,0x6e,0x7e,0x80,0x7e,0x90,0x7e,0xf4,0x7f,0x04,0x7f,0x16,0x7f,0x2e,0x7f,0x40,0x7f,0x52,0x7f,0x64,0x7f,0x74,0x7f,0xce,0x80,0x46,0x80,0x58,0x80,0x6a,0x80,0x7c,0x80,0x8c,0x80,0x9e,0x80,0xae,0x80,0xb6,0x80,0xbe,0x80,0xd0,0x80,0xe0,0x80,0xf2,0x81,0x02, +0x81,0x14,0x81,0x26,0x81,0x38,0x81,0x48,0x81,0x5a,0x81,0x6c,0x81,0x7e,0x81,0x8e,0x81,0x9a,0x81,0xa6,0x81,0xbc,0x81,0xd2,0x81,0xe6,0x81,0xfc,0x82,0x08,0x82,0x14,0x82,0x5c,0x82,0xa2,0x82,0xe8,0x82,0xf0,0x83,0x4e,0x83,0xca,0x84,0x36,0x84,0xa4,0x85,0x2c,0x85,0xb4,0x86,0x46,0x86,0xc0,0x87,0x34,0x87,0xa4,0x88,0x04,0x88,0x5e, +0x88,0xac,0x88,0xf8,0x89,0x6c,0x89,0x74,0x89,0x80,0x89,0x8c,0x89,0x98,0x89,0xa4,0x89,0xb6,0x89,0xc8,0x89,0xda,0x89,0xec,0x89,0xfe,0x8a,0x10,0x8a,0x22,0x8a,0x34,0x8a,0x40,0x8a,0x4c,0x8a,0x5e,0x8a,0x70,0x8a,0x82,0x8a,0x92,0x8a,0xa4,0x8a,0xb4,0x8a,0xc6,0x8a,0xd8,0x8a,0xea,0x8a,0xfc,0x8b,0x12,0x8b,0x26,0x8b,0x38,0x8b,0x48, +0x8b,0x5a,0x8b,0x6a,0x8b,0x7c,0x8b,0x8c,0x8b,0x9e,0x8b,0xae,0x8b,0xc4,0x8b,0xd8,0x8b,0xea,0x8b,0xf6,0x8c,0x08,0x8c,0x1a,0x8c,0x2c,0x8c,0x3c,0x8c,0x4e,0x8c,0x5e,0x8c,0x70,0x8c,0x80,0x8c,0x92,0x8c,0xa4,0x8c,0xb6,0x8c,0xc8,0x8c,0xe2,0x8c,0xf6,0x8d,0x08,0x8d,0x1a,0x8d,0x2c,0x8d,0x3e,0x8d,0x50,0x8d,0x62,0x8d,0x74,0x8d,0x86, +0x8d,0x98,0x8d,0xa8,0x8d,0xba,0x8d,0xca,0x8d,0xdc,0x8d,0xee,0x8e,0x00,0x8e,0x12,0x8e,0x2c,0x8e,0x46,0x8e,0x58,0x8e,0x6a,0x8e,0x7c,0x8e,0x8e,0x8e,0xa0,0x8e,0xb2,0x8e,0xc4,0x8e,0xd4,0x8e,0xe0,0x8e,0xf2,0x8f,0x04,0x8f,0x10,0x8f,0x22,0x8f,0x34,0x8f,0x46,0x8f,0x58,0x8f,0x6a,0x8f,0x7c,0x8f,0x8e,0x8f,0xa0,0x8f,0xb2,0x8f,0xc2, +0x8f,0xd4,0x8f,0xe0,0x8f,0xf2,0x90,0x02,0x90,0x14,0x90,0x26,0x90,0x38,0x90,0x4a,0x90,0x5c,0x90,0x6c,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x7e,0x90,0x88,0x90,0x92,0x90,0x9c,0x90,0xae,0x90,0xd2,0x90,0xf6,0x91,0x1e,0x91,0x2a,0x91,0x36, +0x91,0x42,0x91,0x78,0x91,0xac,0x91,0xf4,0x92,0x22,0x92,0x2e,0x92,0x3e,0x92,0xf0,0x92,0xf8,0x93,0x00,0x93,0x2e,0x93,0x70,0x93,0x7c,0x93,0x8e,0x93,0xea,0x94,0x46,0x94,0x58,0x94,0xce,0x95,0x76,0x95,0x90,0x96,0x06,0x96,0x66,0x96,0xa8,0x96,0xc2,0x96,0xf2,0x97,0x2c,0x97,0x44,0x97,0x5c,0x97,0x74,0x97,0x8c,0x97,0xca,0x97,0xe0, +0x98,0x04,0x98,0x16,0x98,0x34,0x98,0x8c,0x98,0xbe,0x99,0x14,0x99,0x3c,0x99,0x56,0x99,0x70,0x99,0x9a,0x99,0xae,0x9a,0x02,0x9a,0x0e,0x9a,0x1a,0x9a,0x2a,0x9a,0x2a,0x9b,0x1c,0x9b,0x6a,0x9b,0x7c,0x9b,0x8e,0x9b,0xc2,0x9b,0xf2,0x9c,0x14,0x9c,0x36,0x9c,0x58,0x9c,0x82,0x9c,0x96,0x9c,0xd2,0x9d,0x06,0x9d,0x2e,0x9d,0x4c,0x9d,0x66, +0x9d,0x9c,0x9d,0xb8,0x9d,0xc8,0x9d,0xea,0x9e,0x0c,0x9e,0x20,0x9e,0x44,0x9e,0x56,0x9e,0x74,0x9e,0xa8,0x9e,0xda,0x9e,0xe6,0x9e,0xf6,0x9f,0x08,0x9f,0x1a,0x9f,0x2a,0x9f,0x3a,0x9f,0x4c,0x9f,0x58,0x9f,0x6a,0x9f,0x7c,0x9f,0x8e,0x9f,0xa0,0x9f,0xb2,0x9f,0xc2,0x9f,0xd4,0x9f,0xe4,0xa0,0x1a,0xa0,0x2a,0xa0,0x3c,0xa0,0x4c,0xa0,0x5e, +0xa0,0x70,0xa0,0x82,0xa0,0x94,0xa0,0xa4,0xa0,0xb6,0xa0,0xc8,0xa0,0xda,0xa0,0xec,0xa0,0xfe,0xa1,0x10,0xa1,0x22,0xa1,0x34,0xa1,0x46,0xa1,0x56,0xa1,0x62,0xa1,0x74,0xa1,0x86,0xa1,0x98,0xa1,0xa8,0xa1,0xba,0xa1,0xcc,0xa1,0xde,0xa1,0xee,0xa1,0xfe,0xa2,0x0a,0xa2,0x1c,0xa2,0x2c,0xa2,0x3c,0xa2,0x4c,0xa2,0x5c,0xa2,0x6e,0xa2,0x7e, +0xa2,0x90,0xa2,0x9c,0xa2,0xae,0xa2,0xbe,0xa2,0xd0,0xa2,0xe0,0xa3,0x0a,0xa3,0x1c,0xa3,0x2e,0xa3,0x3e,0xa3,0x4e,0xa3,0x5e,0xa3,0x70,0xa3,0x82,0xa3,0x94,0xa3,0xa6,0xa3,0xb8,0xa3,0xc8,0xa3,0xda,0xa3,0xea,0xa3,0xfa,0xa4,0x0c,0xa4,0x1e,0xa4,0x30,0xa4,0x42,0xa4,0x54,0xa4,0x64,0xa4,0x74,0xa4,0x84,0xa4,0x96,0xa4,0xa8,0xa4,0xba, +0xa4,0xcc,0xa4,0xde,0xa5,0x1a,0xa5,0x56,0xa5,0x5e,0xa5,0x98,0xa5,0xd4,0xa5,0xe6,0xa6,0x0c,0xa6,0x2c,0xa6,0x50,0xa6,0x64,0xa6,0x94,0xa6,0xd6,0xa6,0xfc,0xa7,0x34,0xa7,0x78,0xa7,0x98,0xa7,0xd8,0xa7,0xf0,0xa8,0x14,0xa8,0x30,0xa8,0x58,0xa8,0x7c,0xa8,0x98,0xa8,0xb2,0xa8,0xe2,0xa8,0xf6,0xa9,0x26,0xa9,0x66,0xa9,0x8a,0xa9,0xcc, +0xaa,0x0c,0xaa,0x58,0xaa,0x76,0xaa,0x94,0xaa,0xd4,0xab,0x0a,0xab,0x2e,0xab,0x6e,0xab,0x9e,0xab,0xd2,0xab,0xe6,0xac,0x16,0xac,0x56,0xac,0xa2,0xac,0xc0,0xad,0x0e,0xad,0x52,0xad,0x7a,0xad,0x7a,0xad,0x7a,0x00,0x01,0x00,0x00,0x04,0x0d,0x00,0x97,0x00,0x16,0x00,0x5f,0x00,0x05,0x00,0x02,0x00,0x50,0x00,0x5f,0x00,0x30,0x00,0x00, +0x00,0xa9,0x09,0x25,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x17,0x01,0x1a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x06,0x00,0x1f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x07,0x00,0x25,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x12,0x00,0x2c,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0e,0x00,0x3e,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x15,0x00,0x4c,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0e,0x00,0x61,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x20,0x00,0x6f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x06,0x00,0x8f,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x0b,0x00,0x0a,0x00,0x95,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x13,0x00,0x9f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x0e,0x00,0xb2,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x00,0x00,0x3e,0x00,0xc0,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x01,0x00,0x0c,0x00,0xfe,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x02,0x00,0x0e, +0x01,0x0a,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x03,0x00,0x24,0x01,0x18,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x04,0x00,0x1c,0x01,0x3c,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x05,0x00,0x2a,0x01,0x58,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x06,0x00,0x1c,0x01,0x82,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x07,0x00,0x40,0x01,0x9e,0x00,0x03, +0x00,0x01,0x04,0x09,0x00,0x09,0x00,0x0c,0x01,0xde,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0b,0x00,0x14,0x01,0xea,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0c,0x00,0x26,0x01,0xfe,0x46,0x6f,0x6e,0x74,0x20,0x64,0x61,0x74,0x61,0x20,0x63,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x47,0x6f,0x6f,0x67,0x6c,0x65,0x20,0x32,0x30,0x31, +0x31,0x52,0x6f,0x62,0x6f,0x74,0x6f,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x47,0x6f,0x6f,0x67,0x6c,0x65,0x3a,0x52,0x6f,0x62,0x6f,0x74,0x6f,0x3a,0x32,0x30,0x31,0x31,0x52,0x6f,0x62,0x6f,0x74,0x6f,0x20,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x30,0x30,0x30,0x30,0x30,0x3b,0x20,0x32, +0x30,0x31,0x31,0x52,0x6f,0x62,0x6f,0x74,0x6f,0x2d,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x52,0x6f,0x62,0x6f,0x74,0x6f,0x20,0x69,0x73,0x20,0x61,0x20,0x74,0x72,0x61,0x64,0x65,0x6d,0x61,0x72,0x6b,0x20,0x6f,0x66,0x20,0x47,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x47,0x6f,0x6f,0x67,0x6c,0x65,0x47,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x63,0x6f, +0x6d,0x43,0x68,0x72,0x69,0x73,0x74,0x69,0x61,0x6e,0x20,0x52,0x6f,0x62,0x65,0x72,0x74,0x73,0x6f,0x6e,0x52,0x6f,0x62,0x6f,0x74,0x6f,0x20,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x00,0x46,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x20,0x00,0x64,0x00,0x61,0x00,0x74,0x00,0x61,0x00,0x20,0x00,0x63,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72, +0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00,0x20,0x00,0x47,0x00,0x6f,0x00,0x6f,0x00,0x67,0x00,0x6c,0x00,0x65,0x00,0x20,0x00,0x32,0x00,0x30,0x00,0x31,0x00,0x31,0x00,0x52,0x00,0x6f,0x00,0x62,0x00,0x6f,0x00,0x74,0x00,0x6f,0x00,0x52,0x00,0x65,0x00,0x67,0x00,0x75,0x00,0x6c,0x00,0x61,0x00,0x72,0x00,0x47,0x00,0x6f,0x00,0x6f, +0x00,0x67,0x00,0x6c,0x00,0x65,0x00,0x3a,0x00,0x52,0x00,0x6f,0x00,0x62,0x00,0x6f,0x00,0x74,0x00,0x6f,0x00,0x3a,0x00,0x32,0x00,0x30,0x00,0x31,0x00,0x31,0x00,0x52,0x00,0x6f,0x00,0x62,0x00,0x6f,0x00,0x74,0x00,0x6f,0x00,0x20,0x00,0x52,0x00,0x65,0x00,0x67,0x00,0x75,0x00,0x6c,0x00,0x61,0x00,0x72,0x00,0x56,0x00,0x65,0x00,0x72, +0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x31,0x00,0x2e,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x3b,0x00,0x20,0x00,0x32,0x00,0x30,0x00,0x31,0x00,0x31,0x00,0x52,0x00,0x6f,0x00,0x62,0x00,0x6f,0x00,0x74,0x00,0x6f,0x00,0x2d,0x00,0x52,0x00,0x65,0x00,0x67,0x00,0x75,0x00,0x6c,0x00,0x61,0x00,0x72, +0x00,0x52,0x00,0x6f,0x00,0x62,0x00,0x6f,0x00,0x74,0x00,0x6f,0x00,0x20,0x00,0x69,0x00,0x73,0x00,0x20,0x00,0x61,0x00,0x20,0x00,0x74,0x00,0x72,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x6d,0x00,0x61,0x00,0x72,0x00,0x6b,0x00,0x20,0x00,0x6f,0x00,0x66,0x00,0x20,0x00,0x47,0x00,0x6f,0x00,0x6f,0x00,0x67,0x00,0x6c,0x00,0x65,0x00,0x2e, +0x00,0x47,0x00,0x6f,0x00,0x6f,0x00,0x67,0x00,0x6c,0x00,0x65,0x00,0x47,0x00,0x6f,0x00,0x6f,0x00,0x67,0x00,0x6c,0x00,0x65,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x43,0x00,0x68,0x00,0x72,0x00,0x69,0x00,0x73,0x00,0x74,0x00,0x69,0x00,0x61,0x00,0x6e,0x00,0x20,0x00,0x52,0x00,0x6f,0x00,0x62,0x00,0x65,0x00,0x72,0x00,0x74, +0x00,0x73,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x6a,0x00,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0d,0x01,0x02,0x01,0x03,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,0x00,0x09,0x00,0x0a, +0x00,0x0b,0x00,0x0c,0x00,0x0d,0x00,0x0e,0x00,0x0f,0x00,0x10,0x00,0x11,0x00,0x12,0x00,0x13,0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x18,0x00,0x19,0x00,0x1a,0x00,0x1b,0x00,0x1c,0x00,0x1d,0x00,0x1e,0x00,0x1f,0x00,0x20,0x00,0x21,0x00,0x22,0x00,0x23,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2a, +0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a,0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x3e,0x00,0x3f,0x00,0x40,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x47,0x00,0x48,0x00,0x49,0x00,0x4a, +0x00,0x4b,0x00,0x4c,0x00,0x4d,0x00,0x4e,0x00,0x4f,0x00,0x50,0x00,0x51,0x00,0x52,0x00,0x53,0x00,0x54,0x00,0x55,0x00,0x56,0x00,0x57,0x00,0x58,0x00,0x59,0x00,0x5a,0x00,0x5b,0x00,0x5c,0x00,0x5d,0x00,0x5e,0x00,0x5f,0x00,0x60,0x00,0x61,0x00,0xac,0x00,0xa3,0x00,0x84,0x00,0x85,0x00,0xbd,0x00,0x96,0x00,0xe8,0x00,0x86,0x00,0x8e, +0x00,0x8b,0x00,0x9d,0x00,0xa9,0x00,0xa4,0x01,0x04,0x00,0x8a,0x01,0x05,0x00,0x83,0x00,0x93,0x00,0xf2,0x00,0xf3,0x00,0x8d,0x00,0x97,0x00,0x88,0x01,0x06,0x00,0xde,0x00,0xf1,0x00,0x9e,0x00,0xaa,0x00,0xf5,0x00,0xf4,0x00,0xf6,0x00,0xa2,0x00,0xad,0x00,0xc9,0x00,0xc7,0x00,0xae,0x00,0x62,0x00,0x63,0x00,0x90,0x00,0x64,0x00,0xcb, +0x00,0x65,0x00,0xc8,0x00,0xca,0x00,0xcf,0x00,0xcc,0x00,0xcd,0x00,0xce,0x00,0xe9,0x00,0x66,0x00,0xd3,0x00,0xd0,0x00,0xd1,0x00,0xaf,0x00,0x67,0x00,0xf0,0x00,0x91,0x00,0xd6,0x00,0xd4,0x00,0xd5,0x00,0x68,0x00,0xeb,0x00,0xed,0x00,0x89,0x00,0x6a,0x00,0x69,0x00,0x6b,0x00,0x6d,0x00,0x6c,0x00,0x6e,0x00,0xa0,0x00,0x6f,0x00,0x71, +0x00,0x70,0x00,0x72,0x00,0x73,0x00,0x75,0x00,0x74,0x00,0x76,0x00,0x77,0x00,0xea,0x00,0x78,0x00,0x7a,0x00,0x79,0x00,0x7b,0x00,0x7d,0x00,0x7c,0x00,0xb8,0x00,0xa1,0x00,0x7f,0x00,0x7e,0x00,0x80,0x00,0x81,0x00,0xec,0x00,0xee,0x00,0xba,0x01,0x07,0x01,0x08,0x01,0x09,0x01,0x0a,0x01,0x0b,0x01,0x0c,0x00,0xfd,0x00,0xfe,0x01,0x0d, +0x01,0x0e,0x01,0x0f,0x01,0x10,0x00,0xff,0x01,0x00,0x01,0x11,0x01,0x12,0x01,0x13,0x01,0x14,0x01,0x15,0x01,0x16,0x01,0x17,0x01,0x18,0x01,0x19,0x01,0x1a,0x01,0x1b,0x01,0x1c,0x01,0x1d,0x01,0x1e,0x01,0x1f,0x01,0x20,0x00,0xf8,0x00,0xf9,0x01,0x21,0x01,0x22,0x01,0x23,0x01,0x24,0x01,0x25,0x01,0x26,0x01,0x27,0x01,0x28,0x01,0x29, +0x01,0x2a,0x01,0x2b,0x01,0x2c,0x01,0x2d,0x01,0x2e,0x01,0x2f,0x01,0x30,0x01,0x31,0x00,0xd7,0x01,0x32,0x01,0x33,0x01,0x34,0x01,0x35,0x01,0x36,0x01,0x37,0x01,0x38,0x01,0x39,0x01,0x3a,0x01,0x3b,0x01,0x3c,0x01,0x3d,0x01,0x3e,0x01,0x3f,0x01,0x40,0x00,0xe2,0x00,0xe3,0x01,0x41,0x01,0x42,0x01,0x43,0x01,0x44,0x01,0x45,0x01,0x46, +0x01,0x47,0x01,0x48,0x01,0x49,0x01,0x4a,0x01,0x4b,0x01,0x4c,0x01,0x4d,0x01,0x4e,0x01,0x4f,0x00,0xb0,0x00,0xb1,0x01,0x50,0x01,0x51,0x01,0x52,0x01,0x53,0x01,0x54,0x01,0x55,0x01,0x56,0x01,0x57,0x01,0x58,0x01,0x59,0x00,0xfb,0x00,0xfc,0x00,0xe4,0x00,0xe5,0x01,0x5a,0x01,0x5b,0x01,0x5c,0x01,0x5d,0x01,0x5e,0x01,0x5f,0x01,0x60, +0x01,0x61,0x01,0x62,0x01,0x63,0x01,0x64,0x01,0x65,0x01,0x66,0x01,0x67,0x01,0x68,0x01,0x69,0x01,0x6a,0x01,0x6b,0x01,0x6c,0x01,0x6d,0x01,0x6e,0x01,0x6f,0x00,0xbb,0x01,0x70,0x01,0x71,0x01,0x72,0x01,0x73,0x00,0xe6,0x00,0xe7,0x01,0x74,0x00,0xa6,0x01,0x75,0x01,0x76,0x01,0x77,0x01,0x78,0x01,0x79,0x01,0x7a,0x01,0x7b,0x01,0x7c, +0x01,0x7d,0x01,0x7e,0x01,0x7f,0x01,0x80,0x01,0x81,0x01,0x82,0x01,0x83,0x00,0xd8,0x00,0xe1,0x00,0xdb,0x00,0xdc,0x00,0xdd,0x00,0xe0,0x00,0xd9,0x00,0xdf,0x01,0x84,0x01,0x85,0x01,0x86,0x01,0x87,0x01,0x88,0x01,0x89,0x01,0x8a,0x01,0x8b,0x01,0x8c,0x01,0x8d,0x01,0x8e,0x01,0x8f,0x01,0x90,0x01,0x91,0x01,0x92,0x01,0x93,0x01,0x94, +0x01,0x95,0x01,0x96,0x01,0x97,0x01,0x98,0x01,0x99,0x01,0x9a,0x01,0x9b,0x01,0x9c,0x01,0x9d,0x01,0x9e,0x01,0x9f,0x01,0xa0,0x01,0xa1,0x01,0xa2,0x01,0xa3,0x01,0xa4,0x01,0xa5,0x01,0xa6,0x01,0xa7,0x01,0xa8,0x01,0xa9,0x01,0xaa,0x01,0xab,0x01,0xac,0x00,0x9f,0x01,0xad,0x01,0xae,0x01,0xaf,0x01,0xb0,0x01,0xb1,0x01,0xb2,0x01,0xb3, +0x01,0xb4,0x01,0xb5,0x01,0xb6,0x01,0xb7,0x01,0xb8,0x01,0xb9,0x01,0xba,0x01,0xbb,0x01,0xbc,0x01,0xbd,0x01,0xbe,0x01,0xbf,0x01,0xc0,0x01,0xc1,0x01,0xc2,0x00,0x9b,0x01,0xc3,0x01,0xc4,0x01,0xc5,0x01,0xc6,0x01,0xc7,0x01,0xc8,0x01,0xc9,0x01,0xca,0x01,0xcb,0x01,0xcc,0x01,0xcd,0x01,0xce,0x01,0xcf,0x01,0xd0,0x01,0xd1,0x01,0xd2, +0x01,0xd3,0x01,0xd4,0x01,0xd5,0x01,0xd6,0x01,0xd7,0x01,0xd8,0x01,0xd9,0x01,0xda,0x01,0xdb,0x01,0xdc,0x01,0xdd,0x01,0xde,0x01,0xdf,0x01,0xe0,0x01,0xe1,0x01,0xe2,0x01,0xe3,0x01,0xe4,0x01,0xe5,0x01,0xe6,0x01,0xe7,0x01,0xe8,0x01,0xe9,0x01,0xea,0x01,0xeb,0x01,0xec,0x01,0xed,0x01,0xee,0x01,0xef,0x01,0xf0,0x01,0xf1,0x01,0xf2, +0x01,0xf3,0x01,0xf4,0x01,0xf5,0x01,0xf6,0x01,0xf7,0x01,0xf8,0x01,0xf9,0x01,0xfa,0x01,0xfb,0x01,0xfc,0x01,0xfd,0x01,0xfe,0x01,0xff,0x02,0x00,0x02,0x01,0x02,0x02,0x02,0x03,0x02,0x04,0x02,0x05,0x02,0x06,0x02,0x07,0x02,0x08,0x02,0x09,0x02,0x0a,0x02,0x0b,0x02,0x0c,0x02,0x0d,0x02,0x0e,0x02,0x0f,0x02,0x10,0x02,0x11,0x02,0x12, +0x02,0x13,0x02,0x14,0x02,0x15,0x02,0x16,0x02,0x17,0x02,0x18,0x02,0x19,0x02,0x1a,0x02,0x1b,0x02,0x1c,0x02,0x1d,0x02,0x1e,0x02,0x1f,0x02,0x20,0x02,0x21,0x02,0x22,0x02,0x23,0x02,0x24,0x02,0x25,0x02,0x26,0x02,0x27,0x02,0x28,0x02,0x29,0x02,0x2a,0x02,0x2b,0x02,0x2c,0x02,0x2d,0x02,0x2e,0x02,0x2f,0x02,0x30,0x02,0x31,0x02,0x32, +0x02,0x33,0x02,0x34,0x02,0x35,0x02,0x36,0x02,0x37,0x02,0x38,0x02,0x39,0x02,0x3a,0x02,0x3b,0x02,0x3c,0x02,0x3d,0x02,0x3e,0x02,0x3f,0x02,0x40,0x02,0x41,0x02,0x42,0x02,0x43,0x02,0x44,0x02,0x45,0x02,0x46,0x02,0x47,0x02,0x48,0x02,0x49,0x02,0x4a,0x02,0x4b,0x02,0x4c,0x02,0x4d,0x02,0x4e,0x02,0x4f,0x02,0x50,0x02,0x51,0x02,0x52, +0x02,0x53,0x02,0x54,0x02,0x55,0x02,0x56,0x02,0x57,0x02,0x58,0x02,0x59,0x02,0x5a,0x02,0x5b,0x02,0x5c,0x02,0x5d,0x02,0x5e,0x02,0x5f,0x02,0x60,0x02,0x61,0x02,0x62,0x02,0x63,0x02,0x64,0x02,0x65,0x02,0x66,0x02,0x67,0x02,0x68,0x02,0x69,0x02,0x6a,0x02,0x6b,0x02,0x6c,0x02,0x6d,0x02,0x6e,0x02,0x6f,0x02,0x70,0x02,0x71,0x02,0x72, +0x02,0x73,0x02,0x74,0x02,0x75,0x02,0x76,0x02,0x77,0x02,0x78,0x02,0x79,0x02,0x7a,0x02,0x7b,0x02,0x7c,0x02,0x7d,0x02,0x7e,0x02,0x7f,0x02,0x80,0x02,0x81,0x02,0x82,0x02,0x83,0x02,0x84,0x02,0x85,0x02,0x86,0x02,0x87,0x02,0x88,0x02,0x89,0x02,0x8a,0x02,0x8b,0x02,0x8c,0x02,0x8d,0x02,0x8e,0x02,0x8f,0x02,0x90,0x02,0x91,0x02,0x92, +0x02,0x93,0x02,0x94,0x02,0x95,0x02,0x96,0x02,0x97,0x02,0x98,0x02,0x99,0x02,0x9a,0x02,0x9b,0x02,0x9c,0x02,0x9d,0x02,0x9e,0x02,0x9f,0x02,0xa0,0x02,0xa1,0x02,0xa2,0x02,0xa3,0x02,0xa4,0x02,0xa5,0x02,0xa6,0x02,0xa7,0x02,0xa8,0x02,0xa9,0x02,0xaa,0x02,0xab,0x02,0xac,0x02,0xad,0x02,0xae,0x02,0xaf,0x02,0xb0,0x02,0xb1,0x02,0xb2, +0x02,0xb3,0x02,0xb4,0x02,0xb5,0x02,0xb6,0x02,0xb7,0x02,0xb8,0x02,0xb9,0x02,0xba,0x02,0xbb,0x02,0xbc,0x02,0xbd,0x02,0xbe,0x02,0xbf,0x02,0xc0,0x02,0xc1,0x02,0xc2,0x02,0xc3,0x02,0xc4,0x02,0xc5,0x02,0xc6,0x02,0xc7,0x02,0xc8,0x02,0xc9,0x02,0xca,0x02,0xcb,0x02,0xcc,0x02,0xcd,0x02,0xce,0x02,0xcf,0x02,0xd0,0x02,0xd1,0x02,0xd2, +0x02,0xd3,0x02,0xd4,0x02,0xd5,0x02,0xd6,0x02,0xd7,0x02,0xd8,0x02,0xd9,0x02,0xda,0x02,0xdb,0x02,0xdc,0x02,0xdd,0x02,0xde,0x02,0xdf,0x02,0xe0,0x02,0xe1,0x02,0xe2,0x02,0xe3,0x02,0xe4,0x02,0xe5,0x02,0xe6,0x02,0xe7,0x02,0xe8,0x02,0xe9,0x02,0xea,0x02,0xeb,0x02,0xec,0x02,0xed,0x02,0xee,0x02,0xef,0x02,0xf0,0x02,0xf1,0x02,0xf2, +0x02,0xf3,0x02,0xf4,0x02,0xf5,0x02,0xf6,0x02,0xf7,0x02,0xf8,0x02,0xf9,0x02,0xfa,0x02,0xfb,0x02,0xfc,0x02,0xfd,0x02,0xfe,0x02,0xff,0x03,0x00,0x03,0x01,0x03,0x02,0x03,0x03,0x03,0x04,0x03,0x05,0x03,0x06,0x03,0x07,0x03,0x08,0x03,0x09,0x03,0x0a,0x03,0x0b,0x03,0x0c,0x03,0x0d,0x03,0x0e,0x03,0x0f,0x03,0x10,0x03,0x11,0x03,0x12, +0x03,0x13,0x03,0x14,0x03,0x15,0x03,0x16,0x03,0x17,0x03,0x18,0x03,0x19,0x03,0x1a,0x03,0x1b,0x03,0x1c,0x03,0x1d,0x03,0x1e,0x03,0x1f,0x03,0x20,0x03,0x21,0x03,0x22,0x03,0x23,0x03,0x24,0x03,0x25,0x03,0x26,0x03,0x27,0x03,0x28,0x03,0x29,0x03,0x2a,0x03,0x2b,0x03,0x2c,0x03,0x2d,0x03,0x2e,0x03,0x2f,0x03,0x30,0x03,0x31,0x03,0x32, +0x03,0x33,0x03,0x34,0x03,0x35,0x03,0x36,0x03,0x37,0x03,0x38,0x03,0x39,0x03,0x3a,0x03,0x3b,0x03,0x3c,0x03,0x3d,0x03,0x3e,0x03,0x3f,0x03,0x40,0x03,0x41,0x03,0x42,0x03,0x43,0x03,0x44,0x03,0x45,0x03,0x46,0x03,0x47,0x03,0x48,0x03,0x49,0x03,0x4a,0x03,0x4b,0x03,0x4c,0x03,0x4d,0x03,0x4e,0x03,0x4f,0x03,0x50,0x03,0x51,0x03,0x52, +0x03,0x53,0x03,0x54,0x03,0x55,0x03,0x56,0x03,0x57,0x00,0xb2,0x00,0xb3,0x03,0x58,0x03,0x59,0x00,0xb6,0x00,0xb7,0x00,0xc4,0x03,0x5a,0x00,0xb4,0x00,0xb5,0x00,0xc5,0x00,0x82,0x00,0xc2,0x00,0x87,0x03,0x5b,0x00,0xab,0x00,0xc6,0x03,0x5c,0x03,0x5d,0x00,0xbe,0x00,0xbf,0x03,0x5e,0x00,0xbc,0x03,0x5f,0x03,0x60,0x00,0xf7,0x03,0x61, +0x03,0x62,0x03,0x63,0x03,0x64,0x03,0x65,0x03,0x66,0x03,0x67,0x00,0x8c,0x03,0x68,0x03,0x69,0x03,0x6a,0x03,0x6b,0x03,0x6c,0x00,0x98,0x00,0x9a,0x00,0x99,0x00,0xef,0x00,0xa5,0x00,0x92,0x00,0x9c,0x00,0xa7,0x00,0x8f,0x00,0x94,0x00,0x95,0x00,0xb9,0x03,0x6d,0x00,0xc0,0x03,0x6e,0x03,0x6f,0x03,0x70,0x03,0x71,0x03,0x72,0x03,0x73, +0x03,0x74,0x03,0x75,0x03,0x76,0x03,0x77,0x03,0x78,0x03,0x79,0x03,0x7a,0x03,0x7b,0x03,0x7c,0x03,0x7d,0x03,0x7e,0x03,0x7f,0x03,0x80,0x03,0x81,0x03,0x82,0x03,0x83,0x03,0x84,0x03,0x85,0x03,0x86,0x03,0x87,0x03,0x88,0x03,0x89,0x03,0x8a,0x03,0x8b,0x03,0x8c,0x03,0x8d,0x03,0x8e,0x03,0x8f,0x03,0x90,0x03,0x91,0x03,0x92,0x03,0x93, +0x03,0x94,0x03,0x95,0x03,0x96,0x03,0x97,0x03,0x98,0x03,0x99,0x03,0x9a,0x03,0x9b,0x03,0x9c,0x03,0x9d,0x03,0x9e,0x03,0x9f,0x03,0xa0,0x03,0xa1,0x03,0xa2,0x03,0xa3,0x03,0xa4,0x03,0xa5,0x03,0xa6,0x03,0xa7,0x03,0xa8,0x03,0xa9,0x03,0xaa,0x03,0xab,0x03,0xac,0x03,0xad,0x03,0xae,0x03,0xaf,0x03,0xb0,0x03,0xb1,0x03,0xb2,0x03,0xb3, +0x03,0xb4,0x03,0xb5,0x03,0xb6,0x03,0xb7,0x03,0xb8,0x03,0xb9,0x03,0xba,0x03,0xbb,0x03,0xbc,0x03,0xbd,0x03,0xbe,0x03,0xbf,0x03,0xc0,0x03,0xc1,0x03,0xc2,0x03,0xc3,0x03,0xc4,0x03,0xc5,0x03,0xc6,0x03,0xc7,0x03,0xc8,0x03,0xc9,0x03,0xca,0x03,0xcb,0x03,0xcc,0x03,0xcd,0x03,0xce,0x03,0xcf,0x03,0xd0,0x03,0xd1,0x03,0xd2,0x03,0xd3, +0x03,0xd4,0x03,0xd5,0x03,0xd6,0x03,0xd7,0x03,0xd8,0x03,0xd9,0x03,0xda,0x03,0xdb,0x03,0xdc,0x03,0xdd,0x03,0xde,0x03,0xdf,0x03,0xe0,0x03,0xe1,0x03,0xe2,0x03,0xe3,0x03,0xe4,0x03,0xe5,0x03,0xe6,0x03,0xe7,0x03,0xe8,0x03,0xe9,0x03,0xea,0x03,0xeb,0x03,0xec,0x03,0xed,0x03,0xee,0x03,0xef,0x03,0xf0,0x03,0xf1,0x03,0xf2,0x03,0xf3, +0x03,0xf4,0x03,0xf5,0x03,0xf6,0x03,0xf7,0x03,0xf8,0x03,0xf9,0x03,0xfa,0x03,0xfb,0x03,0xfc,0x03,0xfd,0x03,0xfe,0x03,0xff,0x04,0x00,0x04,0x01,0x04,0x02,0x04,0x03,0x04,0x04,0x04,0x05,0x04,0x06,0x04,0x07,0x04,0x08,0x04,0x09,0x04,0x0a,0x04,0x0b,0x04,0x0c,0x04,0x0d,0x04,0x0e,0x04,0x0f,0x04,0x10,0x04,0x11,0x04,0x12,0x04,0x13, +0x04,0x14,0x04,0x15,0x04,0x4e,0x55,0x4c,0x4c,0x07,0x75,0x6e,0x69,0x30,0x30,0x30,0x32,0x07,0x75,0x6e,0x69,0x30,0x30,0x41,0x44,0x06,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x0e,0x70,0x65,0x72,0x69,0x6f,0x64,0x63,0x65,0x6e,0x74,0x65,0x72,0x65,0x64,0x07,0x41,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x61,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06, +0x41,0x62,0x72,0x65,0x76,0x65,0x06,0x61,0x62,0x72,0x65,0x76,0x65,0x07,0x41,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x61,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x0b,0x43,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x63,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x07,0x75,0x6e,0x69,0x30,0x31,0x30,0x41,0x07,0x75,0x6e, +0x69,0x30,0x31,0x30,0x42,0x06,0x44,0x63,0x61,0x72,0x6f,0x6e,0x06,0x64,0x63,0x61,0x72,0x6f,0x6e,0x06,0x44,0x63,0x72,0x6f,0x61,0x74,0x06,0x64,0x63,0x72,0x6f,0x61,0x74,0x07,0x45,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x65,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x45,0x62,0x72,0x65,0x76,0x65,0x06,0x65,0x62,0x72,0x65,0x76,0x65,0x0a, +0x45,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x0a,0x65,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x07,0x45,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x65,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x06,0x45,0x63,0x61,0x72,0x6f,0x6e,0x06,0x65,0x63,0x61,0x72,0x6f,0x6e,0x0b,0x47,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b, +0x67,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x07,0x75,0x6e,0x69,0x30,0x31,0x32,0x30,0x07,0x75,0x6e,0x69,0x30,0x31,0x32,0x31,0x0c,0x47,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x67,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0b,0x48,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65, +0x78,0x0b,0x68,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x04,0x48,0x62,0x61,0x72,0x04,0x68,0x62,0x61,0x72,0x06,0x49,0x74,0x69,0x6c,0x64,0x65,0x06,0x69,0x74,0x69,0x6c,0x64,0x65,0x07,0x49,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x69,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x49,0x62,0x72,0x65,0x76,0x65,0x06,0x69,0x62,0x72, +0x65,0x76,0x65,0x07,0x49,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x69,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x0a,0x49,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x02,0x49,0x4a,0x02,0x69,0x6a,0x0b,0x4a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x6a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0c,0x4b,0x63,0x6f, +0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6b,0x67,0x72,0x65,0x65,0x6e,0x6c,0x61,0x6e,0x64,0x69,0x63,0x06,0x4c,0x61,0x63,0x75,0x74,0x65,0x06,0x6c,0x61,0x63,0x75,0x74,0x65,0x0c,0x4c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6c, +0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x4c,0x63,0x61,0x72,0x6f,0x6e,0x06,0x6c,0x63,0x61,0x72,0x6f,0x6e,0x04,0x4c,0x64,0x6f,0x74,0x04,0x6c,0x64,0x6f,0x74,0x06,0x4e,0x61,0x63,0x75,0x74,0x65,0x06,0x6e,0x61,0x63,0x75,0x74,0x65,0x0c,0x4e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6e, +0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x4e,0x63,0x61,0x72,0x6f,0x6e,0x06,0x6e,0x63,0x61,0x72,0x6f,0x6e,0x0b,0x6e,0x61,0x70,0x6f,0x73,0x74,0x72,0x6f,0x70,0x68,0x65,0x03,0x45,0x6e,0x67,0x03,0x65,0x6e,0x67,0x07,0x4f,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x6f,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x4f,0x62, +0x72,0x65,0x76,0x65,0x06,0x6f,0x62,0x72,0x65,0x76,0x65,0x0d,0x4f,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x0d,0x6f,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x06,0x52,0x61,0x63,0x75,0x74,0x65,0x06,0x72,0x61,0x63,0x75,0x74,0x65,0x0c,0x52,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65, +0x6e,0x74,0x0c,0x72,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x52,0x63,0x61,0x72,0x6f,0x6e,0x06,0x72,0x63,0x61,0x72,0x6f,0x6e,0x06,0x53,0x61,0x63,0x75,0x74,0x65,0x06,0x73,0x61,0x63,0x75,0x74,0x65,0x0b,0x53,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x73,0x63,0x69,0x72,0x63,0x75,0x6d,0x66, +0x6c,0x65,0x78,0x0c,0x54,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x74,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x54,0x63,0x61,0x72,0x6f,0x6e,0x06,0x74,0x63,0x61,0x72,0x6f,0x6e,0x04,0x54,0x62,0x61,0x72,0x04,0x74,0x62,0x61,0x72,0x06,0x55,0x74,0x69,0x6c,0x64,0x65,0x06,0x75,0x74,0x69, +0x6c,0x64,0x65,0x07,0x55,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x75,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x55,0x62,0x72,0x65,0x76,0x65,0x06,0x75,0x62,0x72,0x65,0x76,0x65,0x05,0x55,0x72,0x69,0x6e,0x67,0x05,0x75,0x72,0x69,0x6e,0x67,0x0d,0x55,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x0d,0x75,0x68,0x75,0x6e, +0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x07,0x55,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x75,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x0b,0x57,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x77,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x59,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x79,0x63, +0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x06,0x5a,0x61,0x63,0x75,0x74,0x65,0x06,0x7a,0x61,0x63,0x75,0x74,0x65,0x0a,0x5a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x0a,0x7a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x05,0x6c,0x6f,0x6e,0x67,0x73,0x05,0x4f,0x68,0x6f,0x72,0x6e,0x05,0x6f,0x68,0x6f,0x72,0x6e,0x05, +0x55,0x68,0x6f,0x72,0x6e,0x05,0x75,0x68,0x6f,0x72,0x6e,0x07,0x75,0x6e,0x69,0x30,0x31,0x46,0x30,0x0a,0x41,0x72,0x69,0x6e,0x67,0x61,0x63,0x75,0x74,0x65,0x0a,0x61,0x72,0x69,0x6e,0x67,0x61,0x63,0x75,0x74,0x65,0x07,0x41,0x45,0x61,0x63,0x75,0x74,0x65,0x07,0x61,0x65,0x61,0x63,0x75,0x74,0x65,0x0b,0x4f,0x73,0x6c,0x61,0x73,0x68, +0x61,0x63,0x75,0x74,0x65,0x0b,0x6f,0x73,0x6c,0x61,0x73,0x68,0x61,0x63,0x75,0x74,0x65,0x0c,0x53,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x73,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x07,0x75,0x6e,0x69,0x30,0x32,0x33,0x37,0x07,0x75,0x6e,0x69,0x30,0x32,0x42,0x43,0x07,0x75,0x6e,0x69,0x30, +0x32,0x46,0x33,0x09,0x67,0x72,0x61,0x76,0x65,0x63,0x6f,0x6d,0x62,0x09,0x61,0x63,0x75,0x74,0x65,0x63,0x6f,0x6d,0x62,0x09,0x74,0x69,0x6c,0x64,0x65,0x63,0x6f,0x6d,0x62,0x04,0x68,0x6f,0x6f,0x6b,0x07,0x75,0x6e,0x69,0x30,0x33,0x30,0x46,0x08,0x64,0x6f,0x74,0x62,0x65,0x6c,0x6f,0x77,0x05,0x74,0x6f,0x6e,0x6f,0x73,0x0d,0x64,0x69, +0x65,0x72,0x65,0x73,0x69,0x73,0x74,0x6f,0x6e,0x6f,0x73,0x0a,0x41,0x6c,0x70,0x68,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x09,0x61,0x6e,0x6f,0x74,0x65,0x6c,0x65,0x69,0x61,0x0c,0x45,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x08,0x45,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x09,0x49,0x6f,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73, +0x0c,0x4f,0x6d,0x69,0x63,0x72,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0c,0x55,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0a,0x4f,0x6d,0x65,0x67,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x11,0x69,0x6f,0x74,0x61,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x74,0x6f,0x6e,0x6f,0x73,0x05,0x41,0x6c,0x70,0x68,0x61,0x04,0x42,0x65, +0x74,0x61,0x05,0x47,0x61,0x6d,0x6d,0x61,0x05,0x44,0x65,0x6c,0x74,0x61,0x07,0x45,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x04,0x5a,0x65,0x74,0x61,0x03,0x45,0x74,0x61,0x05,0x54,0x68,0x65,0x74,0x61,0x04,0x49,0x6f,0x74,0x61,0x05,0x4b,0x61,0x70,0x70,0x61,0x06,0x4c,0x61,0x6d,0x62,0x64,0x61,0x02,0x4d,0x75,0x02,0x4e,0x75,0x02,0x58,0x69, +0x07,0x4f,0x6d,0x69,0x63,0x72,0x6f,0x6e,0x02,0x50,0x69,0x03,0x52,0x68,0x6f,0x05,0x53,0x69,0x67,0x6d,0x61,0x03,0x54,0x61,0x75,0x07,0x55,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x03,0x50,0x68,0x69,0x03,0x43,0x68,0x69,0x03,0x50,0x73,0x69,0x0c,0x49,0x6f,0x74,0x61,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0f,0x55,0x70,0x73,0x69,0x6c, +0x6f,0x6e,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0a,0x61,0x6c,0x70,0x68,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x0c,0x65,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x08,0x65,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x09,0x69,0x6f,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x14,0x75,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x64,0x69,0x65, +0x72,0x65,0x73,0x69,0x73,0x74,0x6f,0x6e,0x6f,0x73,0x05,0x61,0x6c,0x70,0x68,0x61,0x04,0x62,0x65,0x74,0x61,0x05,0x67,0x61,0x6d,0x6d,0x61,0x05,0x64,0x65,0x6c,0x74,0x61,0x07,0x65,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x04,0x7a,0x65,0x74,0x61,0x03,0x65,0x74,0x61,0x05,0x74,0x68,0x65,0x74,0x61,0x04,0x69,0x6f,0x74,0x61,0x05,0x6b,0x61, +0x70,0x70,0x61,0x06,0x6c,0x61,0x6d,0x62,0x64,0x61,0x07,0x75,0x6e,0x69,0x30,0x33,0x42,0x43,0x02,0x6e,0x75,0x02,0x78,0x69,0x07,0x6f,0x6d,0x69,0x63,0x72,0x6f,0x6e,0x03,0x72,0x68,0x6f,0x06,0x73,0x69,0x67,0x6d,0x61,0x31,0x05,0x73,0x69,0x67,0x6d,0x61,0x03,0x74,0x61,0x75,0x07,0x75,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x03,0x70,0x68, +0x69,0x03,0x63,0x68,0x69,0x03,0x70,0x73,0x69,0x05,0x6f,0x6d,0x65,0x67,0x61,0x0c,0x69,0x6f,0x74,0x61,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0f,0x75,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0c,0x6f,0x6d,0x69,0x63,0x72,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0c,0x75,0x70,0x73,0x69,0x6c,0x6f, +0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0a,0x6f,0x6d,0x65,0x67,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x07,0x75,0x6e,0x69,0x30,0x33,0x44,0x31,0x07,0x75,0x6e,0x69,0x30,0x33,0x44,0x32,0x07,0x75,0x6e,0x69,0x30,0x33,0x44,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x30, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x30, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x30,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x31, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x31, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x31,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x32, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x32, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x32,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x33, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x33, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x33,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x34, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x34, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x34,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x35, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x35, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x36, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x36, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x36,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x37, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x37, +0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x37,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x38, +0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x38, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x38,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x39, +0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x39, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x39,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x41, +0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x41, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x41,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x42, +0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x42, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x42,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x43, +0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x43, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x43,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x44, +0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x44, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x44,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x45, +0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x45, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x45,0x46,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x30,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x31,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x32,0x07,0x75,0x6e,0x69,0x30,0x34,0x46, +0x33,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x34,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x35,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x36,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x38,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x41,0x07,0x75,0x6e,0x69,0x30,0x34,0x46, +0x42,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x43,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x44,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x45,0x07,0x75,0x6e,0x69,0x30,0x34,0x46,0x46,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x30,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x31,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x32,0x07,0x75,0x6e,0x69,0x30,0x35,0x30, +0x33,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x34,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x35,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x36,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x37,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x38,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x39,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x41,0x07,0x75,0x6e,0x69,0x30,0x35,0x30, +0x42,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x43,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x44,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x45,0x07,0x75,0x6e,0x69,0x30,0x35,0x30,0x46,0x07,0x75,0x6e,0x69,0x30,0x35,0x31,0x30,0x07,0x75,0x6e,0x69,0x30,0x35,0x31,0x31,0x07,0x75,0x6e,0x69,0x30,0x35,0x31,0x32,0x07,0x75,0x6e,0x69,0x30,0x35,0x31, +0x33,0x07,0x75,0x6e,0x69,0x31,0x45,0x30,0x30,0x07,0x75,0x6e,0x69,0x31,0x45,0x30,0x31,0x07,0x75,0x6e,0x69,0x31,0x45,0x33,0x45,0x07,0x75,0x6e,0x69,0x31,0x45,0x33,0x46,0x06,0x57,0x67,0x72,0x61,0x76,0x65,0x06,0x77,0x67,0x72,0x61,0x76,0x65,0x06,0x57,0x61,0x63,0x75,0x74,0x65,0x06,0x77,0x61,0x63,0x75,0x74,0x65,0x09,0x57,0x64, +0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x09,0x77,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x30,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x31,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x32,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x33,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x34,0x07,0x75,0x6e,0x69,0x31,0x45,0x41, +0x35,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x36,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x37,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x38,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x39,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x41,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x42,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x43,0x07,0x75,0x6e,0x69,0x31,0x45,0x41, +0x44,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x45,0x07,0x75,0x6e,0x69,0x31,0x45,0x41,0x46,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x30,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x31,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x32,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x33,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x34,0x07,0x75,0x6e,0x69,0x31,0x45,0x42, +0x35,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x36,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x37,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x38,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x39,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x41,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x42,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x43,0x07,0x75,0x6e,0x69,0x31,0x45,0x42, +0x44,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x45,0x07,0x75,0x6e,0x69,0x31,0x45,0x42,0x46,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x30,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x31,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x32,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x33,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x34,0x07,0x75,0x6e,0x69,0x31,0x45,0x43, +0x35,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x36,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x37,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x38,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x39,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x41,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x42,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x43,0x07,0x75,0x6e,0x69,0x31,0x45,0x43, +0x44,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x45,0x07,0x75,0x6e,0x69,0x31,0x45,0x43,0x46,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x30,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x31,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x32,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x33,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x34,0x07,0x75,0x6e,0x69,0x31,0x45,0x44, +0x35,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x36,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x37,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x38,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x39,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x41,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x42,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x43,0x07,0x75,0x6e,0x69,0x31,0x45,0x44, +0x44,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x45,0x07,0x75,0x6e,0x69,0x31,0x45,0x44,0x46,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x30,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x31,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x32,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x33,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x34,0x07,0x75,0x6e,0x69,0x31,0x45,0x45, +0x35,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x36,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x37,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x38,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x39,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x41,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x42,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x43,0x07,0x75,0x6e,0x69,0x31,0x45,0x45, +0x44,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x45,0x07,0x75,0x6e,0x69,0x31,0x45,0x45,0x46,0x07,0x75,0x6e,0x69,0x31,0x45,0x46,0x30,0x07,0x75,0x6e,0x69,0x31,0x45,0x46,0x31,0x06,0x59,0x67,0x72,0x61,0x76,0x65,0x06,0x79,0x67,0x72,0x61,0x76,0x65,0x07,0x75,0x6e,0x69,0x31,0x45,0x46,0x34,0x07,0x75,0x6e,0x69,0x31,0x45,0x46,0x35,0x07, +0x75,0x6e,0x69,0x31,0x45,0x46,0x36,0x07,0x75,0x6e,0x69,0x31,0x45,0x46,0x37,0x07,0x75,0x6e,0x69,0x31,0x45,0x46,0x38,0x07,0x75,0x6e,0x69,0x31,0x45,0x46,0x39,0x07,0x75,0x6e,0x69,0x31,0x46,0x34,0x44,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x30,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x31,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x32,0x07, +0x75,0x6e,0x69,0x32,0x30,0x30,0x33,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x34,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x35,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x36,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x37,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x38,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x39,0x07,0x75,0x6e,0x69,0x32,0x30,0x30,0x41,0x07, +0x75,0x6e,0x69,0x32,0x30,0x30,0x42,0x07,0x75,0x6e,0x69,0x32,0x30,0x31,0x35,0x0d,0x75,0x6e,0x64,0x65,0x72,0x73,0x63,0x6f,0x72,0x65,0x64,0x62,0x6c,0x0d,0x71,0x75,0x6f,0x74,0x65,0x72,0x65,0x76,0x65,0x72,0x73,0x65,0x64,0x07,0x75,0x6e,0x69,0x32,0x30,0x32,0x35,0x06,0x6d,0x69,0x6e,0x75,0x74,0x65,0x06,0x73,0x65,0x63,0x6f,0x6e, +0x64,0x09,0x65,0x78,0x63,0x6c,0x61,0x6d,0x64,0x62,0x6c,0x07,0x75,0x6e,0x69,0x32,0x30,0x37,0x34,0x09,0x6e,0x73,0x75,0x70,0x65,0x72,0x69,0x6f,0x72,0x04,0x6c,0x69,0x72,0x61,0x06,0x70,0x65,0x73,0x65,0x74,0x61,0x07,0x75,0x6e,0x69,0x32,0x30,0x41,0x42,0x04,0x45,0x75,0x72,0x6f,0x07,0x75,0x6e,0x69,0x32,0x31,0x30,0x35,0x07,0x75, +0x6e,0x69,0x32,0x31,0x31,0x33,0x07,0x75,0x6e,0x69,0x32,0x31,0x31,0x36,0x09,0x65,0x73,0x74,0x69,0x6d,0x61,0x74,0x65,0x64,0x09,0x6f,0x6e,0x65,0x65,0x69,0x67,0x68,0x74,0x68,0x0c,0x74,0x68,0x72,0x65,0x65,0x65,0x69,0x67,0x68,0x74,0x68,0x73,0x0b,0x66,0x69,0x76,0x65,0x65,0x69,0x67,0x68,0x74,0x68,0x73,0x0c,0x73,0x65,0x76,0x65, +0x6e,0x65,0x69,0x67,0x68,0x74,0x68,0x73,0x0b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x07,0x75,0x6e,0x69,0x46,0x42,0x30,0x32,0x07,0x75,0x6e,0x69,0x46,0x42,0x30,0x33,0x07,0x75,0x6e,0x69,0x46,0x42,0x30,0x34,0x07,0x75,0x6e,0x69,0x46,0x45,0x46,0x46,0x07,0x75,0x6e,0x69,0x46,0x46,0x46,0x43,0x07,0x75,0x6e,0x69, +0x46,0x46,0x46,0x44,0x0d,0x53,0x63,0x65,0x64,0x69,0x6c,0x6c,0x61,0x2e,0x73,0x6d,0x63,0x70,0x10,0x55,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x13,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x74,0x69,0x6c,0x64,0x65,0x63,0x6f,0x6d,0x62,0x12,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c, +0x65,0x78,0x68,0x6f,0x6f,0x6b,0x63,0x6f,0x6d,0x62,0x13,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x67,0x72,0x61,0x76,0x65,0x63,0x6f,0x6d,0x62,0x13,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x61,0x63,0x75,0x74,0x65,0x63,0x6f,0x6d,0x62,0x06,0x41,0x2e,0x73,0x6d,0x63,0x70,0x0e,0x62,0x72,0x65,0x76,0x65,0x67, +0x72,0x61,0x76,0x65,0x63,0x6f,0x6d,0x62,0x11,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x72,0x6f,0x74,0x61,0x74,0x65,0x06,0x42,0x2e,0x73,0x6d,0x63,0x70,0x06,0x43,0x2e,0x73,0x6d,0x63,0x70,0x06,0x44,0x2e,0x73,0x6d,0x63,0x70,0x06,0x45,0x2e,0x73,0x6d,0x63,0x70,0x06,0x46,0x2e,0x73,0x6d,0x63,0x70,0x06,0x47,0x2e, +0x73,0x6d,0x63,0x70,0x06,0x48,0x2e,0x73,0x6d,0x63,0x70,0x06,0x49,0x2e,0x73,0x6d,0x63,0x70,0x06,0x4a,0x2e,0x73,0x6d,0x63,0x70,0x06,0x4b,0x2e,0x73,0x6d,0x63,0x70,0x06,0x4c,0x2e,0x73,0x6d,0x63,0x70,0x06,0x4d,0x2e,0x73,0x6d,0x63,0x70,0x08,0x63,0x72,0x6f,0x73,0x73,0x62,0x61,0x72,0x06,0x4e,0x2e,0x73,0x6d,0x63,0x70,0x06,0x4f, +0x2e,0x73,0x6d,0x63,0x70,0x09,0x7a,0x65,0x72,0x6f,0x2e,0x6c,0x6e,0x75,0x6d,0x0f,0x67,0x65,0x72,0x6d,0x61,0x6e,0x64,0x62,0x6c,0x73,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x5a,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0f,0x5a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x5a,0x61,0x63,0x75, +0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0e,0x59,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x2e,0x73,0x6d,0x63,0x70,0x10,0x59,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x10,0x57,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x55,0x6f,0x67,0x6f,0x6e,0x65,0x6b, +0x2e,0x73,0x6d,0x63,0x70,0x12,0x55,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0a,0x55,0x72,0x69,0x6e,0x67,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x55,0x62,0x72,0x65,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x55,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x55,0x74,0x69, +0x6c,0x64,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x54,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x11,0x54,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x53,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x09,0x66,0x69,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x10,0x53,0x63,0x69, +0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x53,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x52,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x11,0x52,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x52,0x61,0x63,0x75,0x74,0x65,0x2e,0x73, +0x6d,0x63,0x70,0x12,0x4f,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4f,0x62,0x72,0x65,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x4f,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4e,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x11,0x4e,0x63,0x6f,0x6d, +0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4e,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x09,0x4c,0x64,0x6f,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4c,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x11,0x4c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63, +0x70,0x0b,0x4c,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x11,0x4b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70,0x10,0x4a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0f,0x49,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70, +0x0c,0x49,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x49,0x62,0x72,0x65,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x49,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x49,0x74,0x69,0x6c,0x64,0x65,0x2e,0x73,0x6d,0x63,0x70,0x10,0x48,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73, +0x6d,0x63,0x70,0x11,0x47,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x75,0x6e,0x69,0x30,0x31,0x32,0x30,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x47,0x62,0x72,0x65,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x10,0x47,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0b, +0x45,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x45,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x2e,0x73,0x6d,0x63,0x70,0x0f,0x45,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x45,0x62,0x72,0x65,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x45,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63, +0x70,0x0b,0x44,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x43,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x75,0x6e,0x69,0x30,0x31,0x30,0x41,0x2e,0x73,0x6d,0x63,0x70,0x10,0x43,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x43,0x61,0x63,0x75,0x74,0x65,0x2e,0x73, +0x6d,0x63,0x70,0x0c,0x41,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x41,0x62,0x72,0x65,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0c,0x41,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x59,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0e,0x55,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x2e, +0x73,0x6d,0x63,0x70,0x0e,0x62,0x72,0x65,0x76,0x65,0x61,0x63,0x75,0x74,0x65,0x63,0x6f,0x6d,0x62,0x0b,0x55,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x55,0x67,0x72,0x61,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0e,0x4f,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4f,0x74,0x69,0x6c,0x64, +0x65,0x2e,0x73,0x6d,0x63,0x70,0x10,0x4f,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4f,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4f,0x67,0x72,0x61,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x4e,0x74,0x69,0x6c,0x64,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0e,0x49,0x64,0x69,0x65, +0x72,0x65,0x73,0x69,0x73,0x2e,0x73,0x6d,0x63,0x70,0x10,0x49,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x49,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x49,0x67,0x72,0x61,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0e,0x45,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x2e,0x73,0x6d, +0x63,0x70,0x10,0x45,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x45,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x45,0x67,0x72,0x61,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0d,0x43,0x63,0x65,0x64,0x69,0x6c,0x6c,0x61,0x2e,0x73,0x6d,0x63,0x70,0x0f,0x41,0x72,0x69,0x6e,0x67,0x61, +0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0a,0x41,0x72,0x69,0x6e,0x67,0x2e,0x73,0x6d,0x63,0x70,0x0e,0x41,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x41,0x74,0x69,0x6c,0x64,0x65,0x2e,0x73,0x6d,0x63,0x70,0x10,0x41,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x73,0x6d,0x63,0x70, +0x0b,0x41,0x61,0x63,0x75,0x74,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x41,0x67,0x72,0x61,0x76,0x65,0x2e,0x73,0x6d,0x63,0x70,0x09,0x54,0x62,0x61,0x72,0x2e,0x73,0x6d,0x63,0x70,0x08,0x45,0x74,0x68,0x2e,0x73,0x6d,0x63,0x70,0x0b,0x44,0x63,0x72,0x6f,0x61,0x74,0x2e,0x73,0x6d,0x63,0x70,0x06,0x51,0x2e,0x73,0x6d,0x63,0x70,0x06,0x52, +0x2e,0x73,0x6d,0x63,0x70,0x0d,0x63,0x79,0x72,0x69,0x6c,0x6c,0x69,0x63,0x62,0x72,0x65,0x76,0x65,0x0d,0x62,0x72,0x65,0x76,0x65,0x68,0x6f,0x6f,0x6b,0x63,0x6f,0x6d,0x62,0x0e,0x62,0x72,0x65,0x76,0x65,0x74,0x69,0x6c,0x64,0x65,0x63,0x6f,0x6d,0x62,0x0b,0x63,0x79,0x72,0x69,0x6c,0x6c,0x69,0x63,0x74,0x69,0x63,0x10,0x63,0x79,0x72, +0x69,0x6c,0x6c,0x69,0x63,0x68,0x6f,0x6f,0x6b,0x6c,0x65,0x66,0x74,0x0c,0x63,0x79,0x72,0x69,0x6c,0x6c,0x69,0x63,0x68,0x6f,0x6f,0x6b,0x0e,0x6c,0x61,0x72,0x67,0x65,0x72,0x69,0x67,0x68,0x74,0x68,0x6f,0x6f,0x6b,0x08,0x6f,0x6e,0x65,0x2e,0x6c,0x6e,0x75,0x6d,0x08,0x74,0x77,0x6f,0x2e,0x6c,0x6e,0x75,0x6d,0x0a,0x74,0x68,0x72,0x65, +0x65,0x2e,0x6c,0x6e,0x75,0x6d,0x09,0x66,0x6f,0x75,0x72,0x2e,0x6c,0x6e,0x75,0x6d,0x09,0x66,0x69,0x76,0x65,0x2e,0x6c,0x6e,0x75,0x6d,0x08,0x73,0x69,0x78,0x2e,0x6c,0x6e,0x75,0x6d,0x0a,0x73,0x65,0x76,0x65,0x6e,0x2e,0x6c,0x6e,0x75,0x6d,0x06,0x53,0x2e,0x73,0x6d,0x63,0x70,0x06,0x54,0x2e,0x73,0x6d,0x63,0x70,0x06,0x55,0x2e,0x73, +0x6d,0x63,0x70,0x06,0x56,0x2e,0x73,0x6d,0x63,0x70,0x06,0x57,0x2e,0x73,0x6d,0x63,0x70,0x06,0x58,0x2e,0x73,0x6d,0x63,0x70,0x06,0x59,0x2e,0x73,0x6d,0x63,0x70,0x06,0x5a,0x2e,0x73,0x6d,0x63,0x70,0x09,0x7a,0x65,0x72,0x6f,0x2e,0x73,0x6d,0x63,0x70,0x08,0x6f,0x6e,0x65,0x2e,0x73,0x6d,0x63,0x70,0x08,0x74,0x77,0x6f,0x2e,0x73,0x6d, +0x63,0x70,0x0a,0x74,0x68,0x72,0x65,0x65,0x2e,0x73,0x6d,0x63,0x70,0x09,0x66,0x6f,0x75,0x72,0x2e,0x73,0x6d,0x63,0x70,0x08,0x73,0x69,0x78,0x2e,0x73,0x6d,0x63,0x70,0x08,0x6e,0x69,0x6e,0x65,0x2e,0x73,0x75,0x70,0x09,0x65,0x69,0x67,0x68,0x74,0x2e,0x73,0x75,0x70,0x09,0x64,0x61,0x73,0x69,0x61,0x6f,0x78,0x69,0x61,0x09,0x73,0x65, +0x76,0x65,0x6e,0x2e,0x73,0x75,0x70,0x07,0x73,0x69,0x78,0x2e,0x73,0x75,0x70,0x08,0x66,0x69,0x76,0x65,0x2e,0x73,0x75,0x70,0x08,0x66,0x6f,0x75,0x72,0x2e,0x73,0x75,0x70,0x09,0x74,0x68,0x72,0x65,0x65,0x2e,0x73,0x75,0x70,0x07,0x74,0x77,0x6f,0x2e,0x73,0x75,0x70,0x09,0x72,0x69,0x6e,0x67,0x61,0x63,0x75,0x74,0x65,0x07,0x6f,0x6e, +0x65,0x2e,0x73,0x75,0x70,0x08,0x7a,0x65,0x72,0x6f,0x2e,0x73,0x75,0x70,0x09,0x6e,0x69,0x6e,0x65,0x2e,0x73,0x6d,0x63,0x70,0x0a,0x65,0x69,0x67,0x68,0x74,0x2e,0x73,0x6d,0x63,0x70,0x0a,0x73,0x65,0x76,0x65,0x6e,0x2e,0x73,0x6d,0x63,0x70,0x0a,0x65,0x69,0x67,0x68,0x74,0x2e,0x6c,0x6e,0x75,0x6d,0x09,0x6e,0x69,0x6e,0x65,0x2e,0x6c, +0x6e,0x75,0x6d,0x06,0x50,0x2e,0x73,0x6d,0x63,0x70,0x08,0x4e,0x55,0x4c,0x4c,0x2e,0x30,0x30,0x31,0x07,0x75,0x6e,0x69,0x30,0x30,0x30,0x39,0x00,0x00,0x01,0x00,0x01,0xff,0xff,0x00,0x0f,0x00,0x00,0x00,0xc5,0x00,0x9a,0x00,0xc5,0x00,0xc5,0x00,0x9a,0x00,0x9b,0x05,0xb0,0x00,0x00,0x06,0x18,0x04,0x3a,0x00,0x00,0xfe,0x60,0x05,0xc5, +0xff,0xeb,0x06,0x2d,0x04,0x4e,0xff,0xeb,0xfe,0x4b,0x00,0x00,0xb0,0x00,0x2c,0x20,0x64,0xb0,0x20,0x60,0x66,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x2d,0xb0,0x01,0x2c,0x20,0x64,0x20,0xb0,0xc0,0x50,0xb0,0x04,0x26,0x5a,0xb0,0x0b,0x43,0x5b,0x58,0x21,0x23,0x21,0x1b,0x8a,0x58,0x20,0xb0,0x50,0x50,0x58,0x21,0xb0,0x40,0x59,0x1b,0x20, +0xb0,0x38,0x50,0x58,0x21,0xb0,0x38,0x59,0x59,0x20,0xb0,0x05,0x45,0x61,0x64,0xb0,0x28,0x50,0x58,0x21,0xb0,0x05,0x45,0x20,0xb0,0x30,0x50,0x58,0x21,0xb0,0x30,0x59,0x1b,0x20,0xb0,0xc0,0x50,0x58,0x20,0x66,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x0a,0x50,0x58,0x60,0x1b,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x0a,0x60,0x1b,0x20,0xb0,0x36, +0x50,0x58,0x21,0xb0,0x36,0x60,0x1b,0x60,0x59,0x59,0x59,0x1b,0xb0,0x00,0x2b,0x59,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x59,0x2d,0xb0,0x02,0x2c,0xb0,0x07,0x23,0x42,0xb0,0x06,0x23,0x42,0xb0,0x00,0x23,0x42,0xb0,0x00,0x43,0xb0,0x06,0x43,0x51,0x58,0xb0,0x07,0x43,0x2b,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0xb0,0x16,0x65,0x1c, +0x59,0x2d,0xb0,0x03,0x2c,0xb0,0x00,0x43,0x20,0x45,0xb0,0x09,0x43,0x63,0xb0,0x0a,0x43,0x62,0x44,0x2d,0xb0,0x04,0x2c,0xb0,0x00,0x43,0x20,0x45,0x20,0xb0,0x00,0x2b,0x23,0xb1,0x06,0x04,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x00,0x1b,0xb0,0x30,0x50,0x58,0xb0,0x20,0x1b,0xb0,0x40,0x59, +0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb0,0x03,0x25,0x23,0x61,0x44,0x44,0x2d,0xb0,0x05,0x2c,0xb0,0x01,0x60,0x20,0x20,0xb0,0x0d,0x43,0x4a,0xb0,0x00,0x50,0x58,0x20,0xb0,0x0d,0x23,0x42,0x59,0xb0,0x0e,0x43,0x4a,0xb0,0x00,0x52,0x58,0x20,0xb0,0x0e,0x23,0x42,0x59,0x2d,0xb0,0x06,0x2c,0xb0,0x00,0x43,0xb0,0x02,0x25,0x42,0xb2, +0x00,0x01,0x00,0x43,0x60,0x42,0xb1,0x0d,0x02,0x25,0x42,0xb1,0x0e,0x02,0x25,0x42,0xb0,0x01,0x16,0x23,0x20,0xb0,0x03,0x25,0x50,0x58,0xb0,0x00,0x43,0xb0,0x04,0x25,0x42,0x8a,0x8a,0x20,0x8a,0x23,0x61,0xb0,0x05,0x2a,0x21,0x23,0xb0,0x01,0x61,0x20,0x8a,0x23,0x61,0xb0,0x05,0x2a,0x21,0x1b,0xb0,0x00,0x43,0xb0,0x02,0x25,0x42,0xb0, +0x02,0x25,0x61,0xb0,0x05,0x2a,0x21,0x59,0xb0,0x0d,0x43,0x47,0xb0,0x0e,0x43,0x47,0x60,0xb0,0x80,0x62,0xb0,0x09,0x43,0x63,0xb0,0x0a,0x43,0x62,0x20,0xb1,0x01,0x00,0x15,0x43,0x20,0x46,0x8a,0x23,0x61,0x38,0xb0,0x02,0x43,0x20,0x46,0x8a,0x23,0x61,0x38,0xb5,0x02,0x01,0x02,0x01,0x01,0x01,0x43,0x60,0x42,0x43,0x60,0x42,0x2d,0xb0, +0x07,0x2c,0x00,0xb0,0x08,0x23,0x42,0xb6,0x0f,0x0f,0x08,0x02,0x00,0x01,0x08,0x43,0x42,0x42,0x43,0x20,0x60,0x60,0xb0,0x01,0x61,0xb1,0x06,0x02,0x2b,0x2d,0xb0,0x08,0x2c,0x20,0x60,0xb0,0x0f,0x60,0x20,0x43,0x23,0xb0,0x01,0x60,0x43,0xb0,0x02,0x25,0xb0,0x02,0x25,0x51,0x58,0x23,0x20,0x3c,0xb0,0x01,0x60,0x23,0xb0,0x12,0x65,0x1c, +0x1b,0x21,0x21,0x59,0x2d,0xb0,0x09,0x2c,0xb0,0x08,0x2b,0xb0,0x08,0x2a,0x2d,0xb0,0x0a,0x2c,0x20,0x20,0x47,0x20,0xb0,0x09,0x43,0x63,0xb0,0x0a,0x43,0x62,0x23,0x61,0x38,0x23,0x20,0x8a,0x55,0x58,0x20,0x47,0x20,0xb0,0x09,0x43,0x63,0xb0,0x0a,0x43,0x62,0x23,0x61,0x38,0x1b,0x21,0x59,0x2d,0xb0,0x0b,0x2c,0x00,0xb0,0x01,0x16,0xb0, +0x0a,0x2a,0xb0,0x01,0x15,0x30,0x2d,0xb0,0x0c,0x2c,0x20,0x35,0xb0,0x01,0x60,0x2d,0xb0,0x0d,0x2c,0x00,0xb0,0x00,0x45,0x63,0xb0,0x0a,0x43,0x62,0xb0,0x00,0x2b,0xb0,0x09,0x43,0xb0,0x0a,0x43,0x61,0x63,0xb0,0x0a,0x43,0x62,0xb0,0x00,0x2b,0xb0,0x00,0x16,0xb1,0x00,0x00,0x2e,0x23,0xb0,0x00,0x47,0xb0,0x00,0x46,0x61,0x60,0x38,0xb1, +0x0c,0x01,0x15,0x2a,0x2d,0xb0,0x0e,0x2c,0x20,0x3c,0x20,0x47,0xb0,0x09,0x43,0x63,0xb0,0x0a,0x43,0x62,0xb0,0x00,0x43,0x61,0x38,0x2d,0xb0,0x0f,0x2c,0x2e,0x17,0x3c,0x2d,0xb0,0x10,0x2c,0x20,0x3c,0x20,0x47,0xb0,0x09,0x43,0x63,0xb0,0x0a,0x43,0x62,0xb0,0x00,0x43,0x61,0xb0,0x01,0x43,0x63,0x38,0x2d,0xb0,0x11,0x2c,0xb1,0x02,0x00, +0x16,0x25,0x20,0x2e,0xb0,0x08,0x43,0x60,0x20,0x46,0xb0,0x00,0x23,0x42,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0x8a,0x8a,0x49,0x23,0x62,0xb0,0x01,0x23,0x42,0xb2,0x10,0x01,0x01,0x15,0x14,0x2a,0x2d,0xb0,0x12,0x2c,0xb0,0x00,0x15,0x20,0xb0,0x08,0x43,0x60,0x46,0xb0,0x00,0x23,0x42,0xb2,0x00,0x01,0x01,0x15,0x14,0x13,0x2e,0xb0, +0x0e,0x2a,0x2d,0xb0,0x13,0x2c,0xb0,0x00,0x15,0x20,0xb0,0x08,0x43,0x60,0x46,0xb0,0x00,0x23,0x42,0xb2,0x00,0x01,0x01,0x15,0x14,0x13,0x2e,0xb0,0x0e,0x2a,0x2d,0xb0,0x14,0x2c,0xb1,0x00,0x01,0x14,0x13,0xb0,0x0f,0x2a,0x2d,0xb0,0x15,0x2c,0xb0,0x11,0x2a,0x2d,0xb0,0x1a,0x2c,0x2d,0xb0,0x1d,0x2c,0x2d,0xb0,0x1b,0x2c,0xb0,0x00,0x16, +0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x04,0x26,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0xb0,0x01,0x2b,0x23,0x20,0x3c,0x20,0x2e,0x23,0x38,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x18,0x2c,0xb1,0x0c,0x04,0x25,0x42,0xb0,0x00,0x16,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x04,0x25,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0x20,0xb0,0x05, +0x23,0x42,0xb0,0x01,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x03,0x20,0x04,0x20,0x1b,0xb3,0x03,0x26,0x04,0x1a,0x59,0x42,0x42,0x23,0x20,0xb0,0x08,0x43,0x60,0x46,0xb0,0x05,0x43,0xb0,0x80,0x62,0x60,0x20,0xb0,0x00,0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x03,0x43,0x60,0x64,0x23,0xb0,0x04,0x43,0x61,0x64,0x50, +0x58,0xb0,0x03,0x43,0x61,0x1b,0xb0,0x04,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x80,0x62,0x61,0xb0,0x02,0x25,0x46,0x61,0x38,0x23,0x20,0x3c,0x23,0x38,0x1b,0x21,0x20,0xb0,0x08,0x43,0x60,0x2e,0x20,0x3c,0x2f,0x21,0x59,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x17,0x2c,0xb0,0x0c,0x23,0x42,0xb0,0x00,0x13,0x3e,0xb1,0x09,0x01,0x14,0x2b, +0x2d,0xb0,0x19,0x2c,0xb0,0x00,0x16,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0x49,0xb0,0x01,0x2b,0x65,0x8a,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x1c,0x2c,0xb0,0x00,0x16,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x04,0x25,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49, +0x20,0xb0,0x05,0x23,0x42,0xb0,0x01,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x03,0x20,0x04,0x20,0x1b,0xb3,0x03,0x26,0x04,0x1a,0x59,0x42,0x42,0x23,0x20,0xb0,0x08,0x43,0x60,0xb0,0x0c,0x43,0x20,0xb0,0x08,0x43,0x60,0x8a,0x23,0x49,0x23,0x46,0x60,0xb0,0x05,0x43,0xb0,0x80,0x62,0x60,0x20,0xb0,0x00,0x2b,0x20, +0x8a,0x8a,0x61,0x20,0xb0,0x03,0x43,0x60,0x64,0x23,0xb0,0x04,0x43,0x61,0x64,0x50,0x58,0xb0,0x03,0x43,0x61,0x1b,0xb0,0x04,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x80,0x62,0x61,0x23,0x20,0xb0,0x03,0x26,0x23,0x46,0x61,0x38,0x1b,0x23,0xb0,0x0c,0x43,0x46,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0xb0,0x0c,0x43,0xb0,0x08,0x43,0x60,0x49, +0x60,0x20,0xb0,0x05,0x43,0xb0,0x80,0x62,0x60,0x23,0x20,0xb0,0x00,0x2b,0x23,0xb0,0x05,0x43,0x60,0xb0,0x00,0x2b,0xb0,0x05,0x25,0x61,0xb0,0x05,0x25,0xb0,0x80,0x62,0xb0,0x04,0x26,0x61,0x20,0xb0,0x04,0x25,0x60,0x64,0x23,0xb0,0x03,0x25,0x60,0x64,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x23,0x20,0xb0,0x03,0x26,0x23,0x46,0x61,0x38, +0x59,0x23,0x20,0x20,0x3c,0xb0,0x05,0x23,0x42,0x23,0x38,0xb1,0x09,0x01,0x14,0x2b,0xb0,0x05,0x43,0x2e,0xb0,0x09,0x2b,0x2d,0xb0,0x16,0x2c,0xb0,0x00,0x13,0x3e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x1e,0x2c,0xb0,0x00,0x16,0x20,0x20,0xb0,0x04,0x26,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x23,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0x23, +0x3c,0x38,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x1f,0x2c,0xb0,0x00,0x16,0x20,0x20,0xb0,0x04,0x26,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x23,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0x23,0x3c,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x20,0x2c,0xb0,0x00,0x16, +0x20,0x20,0xb0,0x04,0x26,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x23,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0x23,0x3c,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x21,0x2c,0xb0,0x00,0x16,0x20,0x20,0xb0,0x04,0x26,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x23,0x20,0x2e, +0xb0,0x08,0x43,0x60,0x49,0x23,0x3c,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x22,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x0c,0x23,0x42,0x20,0xb0,0x08,0x43,0x60,0x2e,0x20,0x20,0x3c,0x2f,0x2e,0xb1, +0x09,0x01,0x14,0x2b,0x2d,0xb0,0x23,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x0c,0x23,0x42,0x20,0xb0,0x08,0x43,0x60,0x2e,0x20,0x20,0x3c,0x2f,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x24,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x0c,0x23,0x42,0x20,0xb0,0x08,0x43,0x60,0x2e,0x20, +0x20,0x3c,0x2f,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x25,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x0c,0x23,0x42,0x20,0xb0,0x08,0x43,0x60,0x2e,0x20,0x20,0x3c,0x2f,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25, +0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x26,0x2c,0xb0,0x00,0x16,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0xb0,0x00,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0xb0, +0x04,0x25,0xb0,0x03,0x25,0x49,0x63,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0x62,0x23,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x21,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x27,0x2c,0xb0,0x00,0x16,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0xb0,0x02,0x25,0xb0,0x08,0x43, +0x60,0x49,0xb0,0x00,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0xb0,0x04,0x25,0xb0,0x03,0x25,0x49,0x63,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0x62,0x23,0x2e,0x23,0x20,0x20, +0x3c,0x8a,0x38,0x23,0x21,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x28,0x2c,0xb0,0x00,0x16,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0xb0,0x00,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60, +0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0xb0,0x04,0x25,0xb0,0x03,0x25,0x49,0x63,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0x62,0x23,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x21,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x50,0x58,0x20,0x3c,0x59, +0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x29,0x2c,0xb0,0x00,0x16,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0xb0,0x00,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0xb0,0x02,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0xb0,0x04,0x25,0xb0,0x03,0x25,0x49, +0x63,0xb0,0x04,0x25,0xb0,0x08,0x43,0x60,0xb0,0x03,0x25,0xb0,0x08,0x43,0x60,0x49,0xb8,0x10,0x00,0x63,0x62,0x23,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x21,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b, +0x2d,0xb0,0x2a,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x08,0x43,0x60,0xb0,0x0c,0x43,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x80,0x62,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x2b,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x08,0x43,0x60,0xb0,0x0c,0x43,0x20,0x2e,0xb0,0x08,0x43,0x60, +0x49,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x80,0x62,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x2c,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x08,0x43,0x60,0xb0,0x0c,0x43,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0, +0x80,0x62,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x2d,0x2c,0xb0,0x00,0x16,0x20,0xb0,0x08,0x43,0x60,0xb0,0x0c,0x43,0x20,0x2e,0xb0,0x08,0x43,0x60,0x49,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x80,0x62,0x23,0x20,0x20,0x3c,0x8a,0x38, +0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x09,0x01,0x14,0x2b,0x2d,0xb0,0x2e,0x2c,0x2b,0x2d,0xb0,0x2f,0x2c,0xb0,0x2e,0x2a,0xb0,0x01,0x15,0x30,0x2d,0x00,0x00,0x00,0xb9,0x08,0x00,0x08,0x00,0x63,0x20,0xb0,0x0a,0x23,0x42,0x20, +0xb0,0x00,0x23,0x70,0xb0,0x10,0x45,0x20,0x20,0xb0,0x28,0x60,0x66,0x20,0x8a,0x55,0x58,0xb0,0x0a,0x43,0x63,0x23,0x62,0xb0,0x09,0x23,0x42,0xb3,0x05,0x06,0x03,0x02,0x2b,0xb3,0x07,0x0c,0x03,0x02,0x2b,0xb3,0x0d,0x12,0x03,0x02,0x2b,0x1b,0xb1,0x09,0x0a,0x43,0x42,0x59,0xb2,0x0b,0x28,0x02,0x45,0x52,0x42,0xb3,0x07,0x0c,0x04,0x02, +0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, +}; + +read_only global String8 df_g_default_main_font_bytes = {df_g_default_main_font_bytes__data, sizeof(df_g_default_main_font_bytes__data)}; +read_only global U8 df_g_default_code_font_bytes__data[] = +{ +0x00,0x01,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x04,0x00,0x00,0x46,0x46,0x54,0x4d,0x51,0x9f,0x15,0xb9,0x00,0x01,0xa6,0x6c,0x00,0x00,0x00,0x1c,0x47,0x44,0x45,0x46,0x02,0xd0,0x00,0x24,0x00,0x01,0xa6,0x44,0x00,0x00,0x00,0x28,0x4f,0x53,0x2f,0x32,0xf9,0x20,0x77,0x38,0x00,0x00,0x01,0x88,0x00,0x00,0x00,0x60,0x63,0x6d,0x61,0x70, +0x56,0x8d,0x3a,0x45,0x00,0x00,0x07,0x34,0x00,0x00,0x06,0xd6,0x63,0x76,0x74,0x20,0x4d,0x16,0x5e,0xb5,0x00,0x00,0x19,0x80,0x00,0x00,0x02,0x3c,0x66,0x70,0x67,0x6d,0x73,0xd3,0x23,0xb0,0x00,0x00,0x0e,0x0c,0x00,0x00,0x07,0x05,0x67,0x61,0x73,0x70,0x00,0x18,0x00,0x09,0x00,0x01,0xa6,0x34,0x00,0x00,0x00,0x10,0x67,0x6c,0x79,0x66, +0x6e,0xf8,0x35,0xc7,0x00,0x00,0x21,0x00,0x00,0x01,0x68,0x3c,0x68,0x65,0x61,0x64,0xf9,0x1e,0x9e,0x36,0x00,0x00,0x01,0x0c,0x00,0x00,0x00,0x36,0x68,0x68,0x65,0x61,0x0b,0x59,0x02,0x59,0x00,0x00,0x01,0x44,0x00,0x00,0x00,0x24,0x68,0x6d,0x74,0x78,0xb9,0x9c,0xc8,0xcc,0x00,0x00,0x01,0xe8,0x00,0x00,0x05,0x4a,0x6c,0x6f,0x63,0x61, +0x98,0x1a,0xf7,0xee,0x00,0x00,0x1b,0xbc,0x00,0x00,0x05,0x44,0x6d,0x61,0x78,0x70,0x06,0x89,0x04,0xec,0x00,0x00,0x01,0x68,0x00,0x00,0x00,0x20,0x6e,0x61,0x6d,0x65,0x1c,0x78,0x1c,0xda,0x00,0x01,0x89,0x3c,0x00,0x00,0x08,0x6a,0x70,0x6f,0x73,0x74,0x8d,0x83,0x67,0x12,0x00,0x01,0x91,0xa8,0x00,0x00,0x14,0x8a,0x70,0x72,0x65,0x70, +0xd9,0x98,0xf7,0x94,0x00,0x00,0x15,0x14,0x00,0x00,0x04,0x6a,0x00,0x01,0x00,0x00,0x00,0x01,0x11,0xeb,0x0d,0x7b,0x61,0x56,0x5f,0x0f,0x3c,0xf5,0x00,0x1f,0x08,0x00,0x00,0x00,0x00,0x00,0xca,0x9f,0x21,0x86,0x00,0x00,0x00,0x00,0xca,0x9f,0x21,0x86,0xff,0xce,0xfd,0x99,0x04,0xdf,0x06,0xa9,0x00,0x00,0x00,0x08,0x00,0x02,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x06,0xa9,0xfd,0x99,0x00,0x00,0x04,0xcd,0xff,0xce,0xff,0xee,0x04,0xdf,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x00,0x02,0xa1,0x01,0x22,0x00,0x48,0x00,0x80,0x00,0x05,0x00,0x02,0x00,0x10,0x00,0x2f,0x00,0x5a,0x00,0x00, +0x03,0x2d,0x03,0x17,0x00,0x03,0x00,0x02,0x00,0x03,0x04,0xcd,0x01,0x90,0x00,0x05,0x00,0x00,0x05,0x9a,0x05,0x33,0x00,0x00,0x01,0x1d,0x05,0x9a,0x05,0x33,0x00,0x00,0x03,0x61,0x00,0x66,0x02,0x12,0x08,0x05,0x02,0x07,0x04,0x09,0x02,0x02,0x05,0x02,0x04,0x04,0xa0,0x00,0x02,0xaf,0x40,0x00,0x78,0xfb,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x31,0x41,0x53,0x43,0x00,0x40,0x00,0x21,0xfb,0x02,0x04,0xe7,0xfe,0x7e,0x02,0x26,0x06,0xa9,0x02,0x67,0x60,0x00,0x00,0x9f,0xdf,0xd7,0x00,0x00,0x04,0x3a,0x05,0x45,0x00,0x00,0x00,0x20,0x00,0x01,0x04,0xcd,0x00,0x44,0x00,0x00,0x00,0x00,0x02,0xaa,0x00,0x00,0x04,0xcd,0x00,0x00,0x02,0x03,0x01,0x15,0x00,0x36,0x00,0x42, +0x00,0x00,0x00,0x2b,0x01,0xf6,0x01,0x56,0x01,0x50,0x00,0xf8,0x00,0x74,0x01,0x03,0x01,0x4e,0x01,0xf0,0x00,0x72,0x00,0x7c,0x00,0x94,0x00,0x90,0x00,0x80,0x00,0x67,0x00,0x80,0x00,0x97,0x00,0x9e,0x00,0x85,0x00,0x8d,0x01,0xf0,0x01,0x60,0x00,0x74,0x00,0x74,0x00,0x74,0x00,0x5e,0x00,0x2c,0x00,0x00,0x00,0xa2,0x00,0x71,0x00,0xa2, +0x00,0xa2,0x00,0xc2,0x00,0x71,0x00,0xa2,0x00,0xca,0x00,0xb0,0x00,0xa2,0x00,0xed,0x00,0x81,0x00,0xa2,0x00,0x66,0x00,0xa2,0x00,0x66,0x00,0xa2,0x00,0x4f,0x00,0x4c,0x00,0x8e,0x00,0x0a,0x00,0x00,0x00,0x24,0x00,0x24,0x00,0x49,0x01,0x9a,0x00,0x73,0x01,0x0e,0x00,0x85,0xff,0xfb,0x01,0x92,0x00,0x80,0x00,0xb3,0x00,0x82,0x00,0x8a, +0x00,0x85,0x00,0x8a,0x00,0x8f,0x00,0xb9,0x00,0x8f,0x00,0x75,0x00,0xec,0x00,0x86,0x00,0x63,0x00,0xb3,0x00,0x82,0x00,0xb3,0x00,0x8a,0x00,0xf2,0x00,0xa7,0x00,0xbe,0x00,0xb9,0x00,0x45,0x00,0x15,0x00,0x5e,0x00,0x42,0x00,0x93,0x00,0xe3,0x02,0x13,0x00,0xa7,0x00,0x6c,0x02,0x03,0x00,0x85,0x00,0x38,0x00,0x9e,0x00,0x34,0x02,0x13, +0x00,0x9f,0x01,0x4f,0x00,0x1f,0x00,0xce,0x00,0x7f,0x00,0x74,0x00,0x1f,0xff,0xfb,0x01,0x47,0x00,0x74,0x01,0x38,0x01,0x32,0x01,0x92,0x00,0x90,0x00,0x7f,0x01,0xf0,0x00,0x77,0x01,0x1d,0x00,0xe2,0x00,0x6b,0x00,0x1b,0x00,0x11,0x00,0x0b,0x00,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x71, +0x00,0xa2,0x00,0xa2,0x00,0xa2,0x00,0xa2,0x00,0xca,0x00,0xca,0x00,0xca,0x00,0xca,0x00,0x1b,0x00,0xa2,0x00,0x66,0x00,0x66,0x00,0x66,0x00,0x66,0x00,0x66,0x00,0x9d,0x00,0x38,0x00,0x8e,0x00,0x8e,0x00,0x8e,0x00,0x8e,0x00,0x24,0x00,0xa2,0x00,0x8e,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x14,0x00,0x82, +0x00,0x85,0x00,0x85,0x00,0x85,0x00,0x85,0x00,0x8f,0x00,0x8f,0x00,0x8f,0x00,0x8f,0x00,0x7d,0x00,0xb3,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x82,0x00,0x74,0x00,0x6e,0x00,0xb9,0x00,0xb9,0x00,0xb9,0x00,0xb9,0x00,0x42,0x00,0xb9,0x00,0x42,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x71,0x00,0x82, +0x00,0x71,0x00,0x82,0x00,0x71,0x00,0x82,0x00,0x71,0x00,0x82,0x00,0xa2,0x00,0x1f,0x00,0x1b,0x00,0x8a,0x00,0xa2,0x00,0x85,0x00,0xa2,0x00,0x85,0x00,0xa2,0x00,0x85,0x00,0xa2,0x00,0x85,0x00,0xa2,0x00,0x85,0x00,0x71,0x00,0x8f,0x00,0x71,0x00,0x8f,0x00,0x71,0x00,0x8f,0x00,0x71,0x00,0x8f,0x00,0xa2,0x00,0xb9,0x00,0x02,0x00,0x35, +0x00,0xca,0x00,0x8f,0x00,0xca,0x00,0x8f,0x00,0xca,0x00,0x8f,0x00,0xca,0x00,0x8f,0x00,0xca,0x00,0x8f,0x00,0x62,0x00,0xd8,0x00,0xb0,0x00,0xd5,0x00,0xa2,0x00,0xec,0x00,0xec,0x00,0xed,0x00,0x86,0x00,0xed,0x00,0x86,0x00,0xed,0x00,0x55,0x00,0xed,0x00,0x86,0x00,0x36,0x00,0x86,0x00,0xa2,0x00,0xb3,0x00,0xa2,0x00,0xb3,0x00,0xa2, +0x00,0xb3,0x00,0x05,0x00,0xb3,0x00,0xb3,0x00,0x66,0x00,0x82,0x00,0x66,0x00,0x82,0x00,0x66,0x00,0x82,0x00,0x14,0x00,0x1c,0x00,0xa2,0x00,0xf2,0x00,0xa2,0x00,0xcb,0x00,0xa2,0x00,0xf2,0x00,0x4f,0x00,0xa7,0x00,0x4f,0x00,0xa7,0x00,0x4f,0x00,0xa7,0x00,0x4f,0x00,0xa7,0x00,0x4c,0x00,0xbe,0x00,0x4c,0x00,0x65,0x00,0x4c,0x00,0xc8, +0x00,0x8e,0x00,0xb9,0x00,0x8e,0x00,0xb9,0x00,0x8e,0x00,0xb9,0x00,0x8e,0x00,0xb9,0x00,0x8e,0x00,0xb9,0x00,0x8e,0x00,0xb9,0x00,0x00,0x00,0x15,0x00,0x24,0x00,0x42,0x00,0x24,0x00,0x49,0x00,0x93,0x00,0x49,0x00,0x93,0x00,0x49,0x00,0x93,0x01,0x90,0x00,0xea,0x00,0x00,0x00,0x80,0x00,0x01,0x00,0x14,0x00,0x38,0x00,0x6e,0x00,0x4f, +0x00,0xa7,0x00,0x4c,0x00,0xbe,0x01,0x1b,0x01,0x1b,0x01,0x51,0x01,0x2d,0x02,0x03,0x01,0x74,0x01,0xb9,0x00,0xff,0x00,0x1d,0x01,0xdb,0x01,0x37,0x00,0x00,0x01,0xf0,0xff,0xcf,0x00,0x00,0x00,0x01,0xff,0xcf,0x00,0x00,0xff,0xce,0x00,0x95,0x00,0x00,0x00,0xa2,0x00,0xe0,0x00,0x0c,0x00,0xa2,0x00,0x49,0x00,0xa2,0x00,0x66,0x00,0xca, +0x00,0xa2,0x00,0x0a,0x00,0x81,0x00,0xa2,0x00,0x87,0x00,0x66,0x00,0xa3,0x00,0xa2,0x00,0x6c,0x00,0x4c,0x00,0x24,0x00,0x08,0x00,0x24,0x00,0x31,0x00,0x3b,0x00,0xca,0x00,0x24,0x00,0x81,0x00,0xaf,0x00,0xb3,0x00,0x95,0x00,0xa3,0x00,0x81,0x00,0xac,0x00,0x35,0x00,0x70,0x00,0xaf,0x00,0xb8,0x00,0xb3,0x00,0x97,0x00,0x95,0x00,0xec, +0x00,0x72,0x00,0x9c,0x00,0x5c,0x00,0xbf,0x00,0x82,0x00,0x16,0x00,0x9d,0x00,0xb0,0x00,0x5c,0x00,0x95,0x00,0xa3,0x00,0x32,0x00,0x3a,0x00,0x58,0x00,0x35,0x00,0x95,0x00,0xa3,0x00,0x82,0x00,0xa3,0x00,0x35,0x00,0xa2,0x00,0xa2,0x00,0x00,0x00,0xe0,0x00,0x71,0x00,0x4f,0x00,0xca,0x00,0xca,0x00,0xb0,0x00,0x00,0x00,0x47,0x00,0x00, +0x00,0xa8,0x00,0xa2,0x00,0x14,0x00,0x9c,0x00,0x00,0x00,0xa2,0x00,0xa2,0x00,0xe0,0x00,0x05,0x00,0xa2,0x00,0x00,0x00,0x43,0x00,0xa2,0x00,0xa2,0x00,0xa8,0xff,0xfe,0x00,0x81,0x00,0xa2,0x00,0x66,0x00,0xa2,0x00,0xa2,0x00,0x71,0x00,0x4c,0x00,0x14,0x00,0x08,0x00,0x24,0x00,0x80,0x00,0x5f,0x00,0x59,0x00,0x56,0x00,0x00,0x00,0x69, +0x00,0xa2,0x00,0x57,0x00,0x56,0x00,0x34,0x00,0x80,0x00,0x8c,0x00,0xb9,0x01,0x09,0x00,0x16,0x00,0x85,0x00,0x01,0x00,0x8a,0x00,0xb9,0x00,0xb9,0x00,0xda,0x00,0x06,0x00,0x66,0x00,0xb5,0x00,0x82,0x00,0xb5,0x00,0xb3,0x00,0x82,0x00,0x82,0x00,0x42,0x00,0x46,0x00,0x5e,0x00,0xb0,0x00,0x9a,0x00,0x66,0x00,0x5c,0xff,0xff,0x00,0x6a, +0x00,0xcc,0x00,0x7c,0x00,0x46,0x00,0x45,0x00,0x85,0x00,0x85,0x00,0x35,0x01,0x09,0x00,0x91,0x00,0xa7,0x00,0x8f,0x00,0x8f,0x00,0x75,0x00,0x19,0x00,0x5c,0x00,0x35,0x00,0xda,0x00,0xb9,0x00,0x42,0x00,0xb5,0x00,0xe2,0x00,0xf4,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x24,0x00,0x42,0x01,0x4e,0x01,0x4e, +0x00,0xaa,0xff,0xf6,0xff,0xf6,0xff,0xfb,0x01,0x8d,0x01,0x8f,0x01,0x5d,0x01,0x8e,0x00,0xb1,0x00,0xb2,0x00,0xb2,0x00,0xb6,0x00,0xb6,0x01,0x50,0x00,0x75,0x00,0x00,0x01,0xf6,0x01,0x15,0x01,0x5a,0x01,0x6e,0x00,0xed,0xff,0xfb,0x00,0xcc,0x01,0x65,0x00,0x22,0x00,0x50,0x00,0x2d,0x00,0x5b,0x00,0x00,0x01,0x1e,0x00,0x16,0x00,0x04, +0x00,0x3b,0x00,0x5f,0x00,0x01,0x00,0x09,0x00,0x25,0x00,0x39,0x00,0x08,0x01,0x76,0x00,0x08,0x01,0x76,0x00,0x08,0x01,0x76,0x01,0x76,0x00,0x69,0x00,0x0c,0x00,0x69,0x00,0x1b,0x00,0x75,0x01,0xf0,0x00,0x4e,0x00,0x1d,0x00,0x34,0x00,0x9c,0x00,0xeb,0x00,0x6c,0x00,0x74,0x00,0x74,0x00,0x73,0x00,0x74,0x00,0x8a,0x00,0x73,0x02,0x1e, +0x00,0xcb,0xff,0xf6,0x02,0x1e,0x02,0x1e,0xff,0xf6,0x02,0x1e,0xff,0xf6,0x02,0x1e,0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0x01,0x6a,0x02,0x1e,0x01,0x6a,0x01,0x6a,0xff,0xf6,0xff,0xf6,0xff,0xf6,0x02,0x1e,0x01,0x6a,0x01,0x6a,0xff,0xf6,0xff,0xf6,0xff,0xf6,0x02,0x1e,0x01,0x6a,0x01,0x6a,0xff,0xf6,0xff,0xf6,0xff,0xf6, +0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0xff,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x00,0x02,0x01,0x68,0x01,0x68,0x00,0x08,0x00,0x0f,0x00,0x34,0x00,0x0f,0x00,0x02,0x00,0x73,0x00,0xa3,0x00,0xae,0x00,0x25,0x00,0x25,0x01,0x6e, +0x00,0x1b,0x00,0x1b,0x00,0x1a,0x01,0x3c,0x00,0xa4,0x00,0x66,0x00,0x61,0x00,0x66,0x00,0x84,0x01,0x1a,0x00,0x70,0x00,0x54,0x00,0x54,0x01,0xdb,0x01,0x05,0x01,0xdb,0x01,0xdb,0x00,0xd5,0x01,0x25,0x00,0xfa,0x00,0xea,0x00,0xc5,0x01,0x04,0x00,0xfc,0x01,0x11,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x1c, +0x00,0x01,0x00,0x00,0x00,0x00,0x04,0xcc,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x1c,0x00,0x04,0x04,0xb0,0x00,0x00,0x00,0xb8,0x00,0x80,0x00,0x06,0x00,0x38,0x00,0x7e,0x01,0x7f,0x01,0x92,0x01,0xff,0x02,0x1b,0x02,0xc7,0x02,0xc9,0x02,0xdd,0x03,0x7e,0x03,0x8a,0x03,0x8c,0x03,0xa1,0x03,0xce,0x04,0x5f,0x04,0x91,0x1e,0x85,0x1e,0xf3, +0x20,0x11,0x20,0x15,0x20,0x1e,0x20,0x22,0x20,0x26,0x20,0x30,0x20,0x33,0x20,0x3a,0x20,0x3c,0x20,0x3e,0x20,0x44,0x20,0x7f,0x20,0xa4,0x20,0xa7,0x20,0xac,0x21,0x05,0x21,0x13,0x21,0x16,0x21,0x22,0x21,0x26,0x21,0x2e,0x21,0x5e,0x21,0x95,0x21,0xa8,0x22,0x02,0x22,0x06,0x22,0x0f,0x22,0x12,0x22,0x15,0x22,0x1a,0x22,0x1f,0x22,0x29, +0x22,0x2b,0x22,0x48,0x22,0x61,0x22,0x65,0x23,0x02,0x23,0x10,0x23,0x21,0x25,0x00,0x25,0x02,0x25,0x0c,0x25,0x10,0x25,0x14,0x25,0x18,0x25,0x1c,0x25,0x24,0x25,0x2c,0x25,0x34,0x25,0x3c,0x25,0x6c,0x25,0x80,0x25,0x84,0x25,0x88,0x25,0x8c,0x25,0x93,0x25,0xa1,0x25,0xac,0x25,0xb2,0x25,0xba,0x25,0xbc,0x25,0xc4,0x25,0xcb,0x25,0xcf, +0x25,0xd9,0x25,0xe6,0x26,0x3c,0x26,0x40,0x26,0x42,0x26,0x60,0x26,0x63,0x26,0x66,0x26,0x6b,0xfb,0x02,0xff,0xff,0x00,0x00,0x00,0x20,0x00,0xa0,0x01,0x92,0x01,0xfa,0x02,0x18,0x02,0xc6,0x02,0xc9,0x02,0xd8,0x03,0x7e,0x03,0x84,0x03,0x8c,0x03,0x8e,0x03,0xa3,0x04,0x00,0x04,0x90,0x1e,0x80,0x1e,0xf2,0x20,0x10,0x20,0x13,0x20,0x17, +0x20,0x20,0x20,0x26,0x20,0x30,0x20,0x32,0x20,0x39,0x20,0x3c,0x20,0x3e,0x20,0x44,0x20,0x7f,0x20,0xa3,0x20,0xa7,0x20,0xac,0x21,0x05,0x21,0x13,0x21,0x16,0x21,0x22,0x21,0x26,0x21,0x2e,0x21,0x5b,0x21,0x90,0x21,0xa8,0x22,0x02,0x22,0x06,0x22,0x0f,0x22,0x11,0x22,0x15,0x22,0x19,0x22,0x1e,0x22,0x29,0x22,0x2b,0x22,0x48,0x22,0x60, +0x22,0x64,0x23,0x02,0x23,0x10,0x23,0x20,0x25,0x00,0x25,0x02,0x25,0x0c,0x25,0x10,0x25,0x14,0x25,0x18,0x25,0x1c,0x25,0x24,0x25,0x2c,0x25,0x34,0x25,0x3c,0x25,0x50,0x25,0x80,0x25,0x84,0x25,0x88,0x25,0x8c,0x25,0x90,0x25,0xa0,0x25,0xaa,0x25,0xb2,0x25,0xba,0x25,0xbc,0x25,0xc4,0x25,0xca,0x25,0xcf,0x25,0xd8,0x25,0xe6,0x26,0x3a, +0x26,0x40,0x26,0x42,0x26,0x60,0x26,0x63,0x26,0x65,0x26,0x6a,0xfb,0x01,0xff,0xff,0xff,0xe3,0x00,0x00,0xff,0xae,0xff,0x47,0xff,0x2f,0xfe,0x85,0xfe,0x84,0xfe,0x76,0xfc,0xa0,0xfd,0xd0,0xfd,0xcf,0xfd,0xce,0xfd,0xcd,0xfd,0x9c,0xfd,0x6c,0xe3,0x7e,0xe3,0x12,0xe1,0xf6,0xe1,0xf5,0xe1,0xf4,0xe1,0xf3,0xe1,0xf0,0xe1,0xe7,0xe1,0xe6, +0xe1,0xe1,0xe1,0xe0,0xe1,0xdf,0xe1,0xda,0xe1,0xa0,0xe1,0x7d,0xe1,0x7b,0xe1,0x77,0xe1,0x1f,0xe1,0x12,0xe1,0x10,0xe1,0x05,0xe1,0x02,0xe0,0xfb,0xe0,0xcf,0xe0,0x9e,0xe0,0x8c,0xe0,0x33,0xe0,0x30,0xe0,0x28,0xe0,0x27,0xe0,0x09,0xe0,0x21,0xe0,0x1e,0xe0,0x15,0xe0,0x14,0xdf,0xf8,0xdf,0xe1,0xdf,0xdf,0xdf,0x43,0xdf,0x36,0xdf,0x27, +0xdd,0x49,0xdd,0x48,0xdd,0x3f,0xdd,0x3c,0xdd,0x39,0xdd,0x36,0xdd,0x33,0xdd,0x2c,0xdd,0x25,0xdd,0x1e,0xdd,0x17,0xdd,0x04,0xdc,0xf1,0xdc,0xee,0xdc,0xeb,0xdc,0xe8,0xdc,0xe5,0xdc,0xd9,0xdc,0xd1,0xdc,0xcc,0xdc,0xc5,0xdc,0xc4,0xdc,0xbd,0xdc,0xb8,0xdc,0xb5,0xdc,0xad,0xdc,0xa1,0xdc,0x4e,0xdc,0x4b,0xdc,0x4a,0xdc,0x2d,0xdc,0x2b, +0xdc,0x2a,0xdc,0x27,0x07,0x92,0x00,0x01,0x00,0x00,0x00,0xb6,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,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,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,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,0x03,0x00,0x62,0x00,0x63,0x00,0x64,0x00,0x65,0x00,0x66,0x00,0x67,0x00,0x68,0x00,0x69,0x00,0x6a,0x00,0x6b,0x00,0x6c,0x00,0x6d,0x00,0x10,0x00,0x6e,0x00,0x6f,0x00,0x70,0x00,0x71,0x00,0x72,0x00,0x73,0x00,0x74,0x00,0x75,0x00,0x76,0x00,0x77,0x00,0x78,0x00,0x79,0x00,0x7a,0x00,0x7b,0x00,0x7c,0x00,0x7d,0x00,0x7e,0x00,0x7f, +0x00,0x80,0x00,0x81,0x00,0x82,0x00,0x83,0x00,0x84,0x00,0x85,0x00,0x86,0x00,0x87,0x00,0x88,0x00,0x89,0x00,0x8a,0x00,0x8b,0x00,0x8c,0x00,0x8d,0x00,0x8e,0x00,0x8f,0x00,0x90,0x00,0x91,0x00,0x92,0x00,0x93,0x00,0x94,0x00,0x95,0x00,0x96,0x00,0x97,0x00,0x98,0x00,0x99,0x00,0x9a,0x00,0x9b,0x00,0x9c,0x00,0x9d,0x00,0x9e,0x00,0x9f, +0x00,0xa0,0x00,0xa1,0x00,0xa2,0x00,0xa3,0x00,0xa4,0x00,0xa5,0x00,0xa6,0x00,0xa7,0x00,0xa8,0x00,0xa9,0x00,0xaa,0x00,0xab,0x00,0xac,0x00,0xad,0x00,0xae,0x00,0xaf,0x00,0xb0,0x00,0xb1,0x00,0xb2,0x00,0xb3,0x00,0xb4,0x00,0xb5,0x00,0xb6,0x00,0xb7,0x00,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,0xbe,0x00,0xbf, +0x00,0xc0,0x00,0xc1,0x00,0xc2,0x00,0xc3,0x00,0xc4,0x00,0xc5,0x00,0xc6,0x00,0xc7,0x00,0xc8,0x00,0xc9,0x00,0xca,0x00,0xcb,0x00,0xcc,0x00,0xcd,0x00,0xce,0x00,0xcf,0x00,0xd0,0x00,0xd1,0x00,0xd2,0x00,0xd3,0x00,0xd4,0x00,0xd5,0x00,0xd6,0x00,0xd7,0x00,0xd8,0x00,0xd9,0x00,0xda,0x00,0xdb,0x00,0xdc,0x00,0xdd,0x00,0xde,0x00,0xdf, +0x00,0xe0,0x00,0xe1,0x00,0xe2,0x00,0xe3,0x00,0xe4,0x00,0xe5,0x00,0xe6,0x00,0xe7,0x00,0xe8,0x00,0xe9,0x00,0xea,0x00,0xeb,0x00,0xec,0x00,0xed,0x00,0xee,0x00,0xef,0x00,0xf0,0x00,0xf1,0x00,0xf2,0x00,0xf3,0x00,0xf4,0x00,0xf5,0x00,0xf6,0x00,0xf7,0x00,0xf8,0x00,0xf9,0x00,0xfa,0x00,0xfb,0x00,0xfc,0x00,0xfd,0x00,0xfe,0x00,0xff, +0x01,0x00,0x01,0x01,0x01,0x02,0x01,0x03,0x01,0x04,0x01,0x05,0x01,0x06,0x01,0x07,0x01,0x08,0x01,0x09,0x01,0x0a,0x01,0x0b,0x01,0x0c,0x01,0x0d,0x01,0x0e,0x01,0x0f,0x01,0x10,0x01,0x11,0x01,0x12,0x01,0x13,0x01,0x14,0x01,0x15,0x01,0x16,0x01,0x17,0x01,0x18,0x01,0x19,0x01,0x1a,0x01,0x1b,0x01,0x1c,0x01,0x1d,0x01,0x1e,0x01,0x1f, +0x01,0x20,0x01,0x21,0x01,0x22,0x01,0x23,0x01,0x24,0x01,0x25,0x01,0x26,0x01,0x27,0x01,0x28,0x01,0x29,0x01,0x2a,0x01,0x2b,0x01,0x2c,0x01,0x2d,0x01,0x2e,0x01,0x2f,0x01,0x30,0x01,0x31,0x01,0x32,0x01,0x33,0x01,0x34,0x01,0x35,0x01,0x36,0x01,0x37,0x01,0x38,0x01,0x39,0x01,0x3a,0x01,0x3b,0x01,0x3c,0x01,0x3d,0x01,0x3e,0x01,0x3f, +0x00,0x06,0x02,0x0a,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,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,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,0x00,0x09,0x00,0x0a,0x00,0x0b,0x00,0x0c,0x00,0x0d,0x00,0x0e,0x00,0x0f,0x00,0x10,0x00,0x11,0x00,0x12,0x00,0x13,0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x18,0x00,0x19,0x00,0x1a,0x00,0x1b,0x00,0x1c,0x00,0x1d, +0x00,0x1e,0x00,0x1f,0x00,0x20,0x00,0x21,0x00,0x22,0x00,0x23,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2a,0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a,0x00,0x3b,0x00,0x3c,0x00,0x3d, +0x00,0x3e,0x00,0x3f,0x00,0x40,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x47,0x00,0x48,0x00,0x49,0x00,0x4a,0x00,0x4b,0x00,0x4c,0x00,0x4d,0x00,0x4e,0x00,0x4f,0x00,0x50,0x00,0x51,0x00,0x52,0x00,0x53,0x00,0x54,0x00,0x55,0x00,0x56,0x00,0x57,0x00,0x58,0x00,0x59,0x00,0x5a,0x00,0x5b,0x00,0x5c,0x00,0x5d, +0x00,0x5e,0x00,0x5f,0x00,0x60,0x00,0x61,0x00,0x00,0x00,0x84,0x00,0x85,0x00,0x87,0x00,0x89,0x00,0x91,0x00,0x96,0x00,0x9c,0x00,0xa1,0x00,0xa0,0x00,0xa2,0x00,0xa4,0x00,0xa3,0x00,0xa5,0x00,0xa7,0x00,0xa9,0x00,0xa8,0x00,0xaa,0x00,0xab,0x00,0xad,0x00,0xac,0x00,0xae,0x00,0xaf,0x00,0xb1,0x00,0xb3,0x00,0xb2,0x00,0xb4,0x00,0xb6, +0x00,0xb5,0x00,0xba,0x00,0xb9,0x00,0xbb,0x00,0xbc,0x02,0x13,0x00,0x70,0x00,0x63,0x00,0x64,0x00,0x68,0x02,0x15,0x00,0x76,0x00,0x9f,0x00,0x6e,0x00,0x6a,0x02,0x27,0x00,0x74,0x00,0x69,0x02,0x41,0x00,0x86,0x00,0x98,0x02,0x3c,0x00,0x71,0x02,0x43,0x02,0x44,0x00,0x66,0x00,0x75,0x02,0x35,0x02,0x38,0x02,0x37,0x01,0x8d,0x02,0x3f, +0x00,0x6b,0x00,0x7a,0x01,0x76,0x00,0xa6,0x00,0xb8,0x00,0x7f,0x00,0x62,0x00,0x6d,0x02,0x3b,0x01,0x40,0x02,0x40,0x02,0x36,0x00,0x6c,0x00,0x7b,0x02,0x16,0x00,0x03,0x00,0x80,0x00,0x83,0x00,0x95,0x01,0x12,0x01,0x13,0x02,0x08,0x02,0x09,0x02,0x10,0x02,0x11,0x02,0x0c,0x02,0x0d,0x00,0xb7,0x02,0x82,0x00,0xbf,0x01,0x38,0x02,0x1e, +0x02,0x23,0x02,0x1a,0x02,0x1b,0x02,0x93,0x02,0x94,0x02,0x14,0x00,0x77,0x02,0x0e,0x02,0x12,0x02,0x17,0x00,0x82,0x00,0x8a,0x00,0x81,0x00,0x8b,0x00,0x88,0x00,0x8d,0x00,0x8e,0x00,0x8f,0x00,0x8c,0x00,0x93,0x00,0x94,0x00,0x00,0x00,0x92,0x00,0x9a,0x00,0x9b,0x00,0x99,0x00,0xf1,0x01,0x4b,0x01,0x52,0x00,0x6f,0x01,0x4e,0x01,0x4f, +0x01,0x50,0x00,0x78,0x01,0x53,0x01,0x51,0x01,0x4c,0x00,0x00,0x40,0x45,0x59,0x58,0x55,0x54,0x53,0x52,0x51,0x50,0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,0x47,0x46,0x45,0x44,0x43,0x42,0x41,0x40,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x31,0x30,0x2f,0x2e,0x2d,0x2c,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x1f, +0x18,0x14,0x11,0x10,0x0f,0x0e,0x0d,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x2c,0x45,0x23,0x46,0x60,0x20,0xb0,0x26,0x60,0xb0,0x04,0x26,0x23,0x48,0x48,0x2d,0x2c,0x45,0x23,0x46,0x23,0x61,0x20,0xb0,0x26,0x61,0xb0,0x04,0x26,0x23,0x48,0x48,0x2d,0x2c,0x45,0x23,0x46,0x60,0xb0,0x20,0x61,0x20,0xb0,0x46,0x60, +0xb0,0x04,0x26,0x23,0x48,0x48,0x2d,0x2c,0x45,0x23,0x46,0x23,0x61,0xb0,0x20,0x60,0x20,0xb0,0x26,0x61,0xb0,0x20,0x61,0xb0,0x04,0x26,0x23,0x48,0x48,0x2d,0x2c,0x45,0x23,0x46,0x60,0xb0,0x40,0x61,0x20,0xb0,0x66,0x60,0xb0,0x04,0x26,0x23,0x48,0x48,0x2d,0x2c,0x45,0x23,0x46,0x23,0x61,0xb0,0x40,0x60,0x20,0xb0,0x26,0x61,0xb0,0x40, +0x61,0xb0,0x04,0x26,0x23,0x48,0x48,0x2d,0x2c,0x01,0x10,0x20,0x3c,0x00,0x3c,0x2d,0x2c,0x20,0x45,0x23,0x20,0xb0,0xcd,0x44,0x23,0x20,0xb8,0x01,0x5a,0x51,0x58,0x23,0x20,0xb0,0x8d,0x44,0x23,0x59,0x20,0xb0,0xed,0x51,0x58,0x23,0x20,0xb0,0x4d,0x44,0x23,0x59,0x20,0xb0,0x04,0x26,0x51,0x58,0x23,0x20,0xb0,0x0d,0x44,0x23,0x59,0x21, +0x21,0x2d,0x2c,0x20,0x20,0x45,0x18,0x68,0x44,0x20,0xb0,0x01,0x60,0x20,0x45,0xb0,0x46,0x76,0x68,0x8a,0x45,0x60,0x44,0x2d,0x2c,0x01,0xb1,0x0b,0x0a,0x43,0x23,0x43,0x65,0x0a,0x2d,0x2c,0x00,0xb1,0x0a,0x0b,0x43,0x23,0x43,0x0b,0x2d,0x2c,0x00,0xb0,0x28,0x23,0x70,0xb1,0x01,0x28,0x3e,0x01,0xb0,0x28,0x23,0x70,0xb1,0x02,0x28,0x45, +0x3a,0xb1,0x02,0x00,0x08,0x0d,0x2d,0x2c,0x20,0x45,0xb0,0x03,0x25,0x45,0x61,0x64,0xb0,0x50,0x51,0x58,0x45,0x44,0x1b,0x21,0x21,0x59,0x2d,0x2c,0x49,0xb0,0x0e,0x23,0x44,0x2d,0x2c,0x20,0x45,0xb0,0x00,0x43,0x60,0x44,0x2d,0x2c,0x01,0xb0,0x06,0x43,0xb0,0x07,0x43,0x65,0x0a,0x2d,0x2c,0x20,0x69,0xb0,0x40,0x61,0xb0,0x00,0x8b,0x20, +0xb1,0x2c,0xc0,0x8a,0x8c,0xb8,0x10,0x00,0x62,0x60,0x2b,0x0c,0x64,0x23,0x64,0x61,0x5c,0x58,0xb0,0x03,0x61,0x59,0x2d,0x2c,0x8a,0x03,0x45,0x8a,0x8a,0x87,0xb0,0x11,0x2b,0xb0,0x29,0x23,0x44,0xb0,0x29,0x7a,0xe4,0x18,0x2d,0x2c,0x45,0x65,0xb0,0x2c,0x23,0x44,0x45,0xb0,0x2b,0x23,0x44,0x2d,0x2c,0x4b,0x52,0x58,0x45,0x44,0x1b,0x21, +0x21,0x59,0x2d,0x2c,0x4b,0x51,0x58,0x45,0x44,0x1b,0x21,0x21,0x59,0x2d,0x2c,0x01,0xb0,0x05,0x25,0x10,0x23,0x20,0x8a,0xf5,0x00,0xb0,0x01,0x60,0x23,0xed,0xec,0x2d,0x2c,0x01,0xb0,0x05,0x25,0x10,0x23,0x20,0x8a,0xf5,0x00,0xb0,0x01,0x61,0x23,0xed,0xec,0x2d,0x2c,0x01,0xb0,0x06,0x25,0x10,0xf5,0x00,0xed,0xec,0x2d,0x2c,0x46,0x23, +0x46,0x60,0x8a,0x8a,0x46,0x23,0x20,0x46,0x8a,0x60,0x8a,0x61,0xb8,0xff,0x80,0x62,0x23,0x20,0x10,0x23,0x8a,0xb1,0x0c,0x0c,0x8a,0x70,0x45,0x60,0x20,0xb0,0x00,0x50,0x58,0xb0,0x01,0x61,0xb8,0xff,0xba,0x8b,0x1b,0xb0,0x46,0x8c,0x59,0xb0,0x10,0x60,0x68,0x01,0x3a,0x2d,0x2c,0x20,0x45,0xb0,0x03,0x25,0x46,0x52,0x4b,0xb0,0x13,0x51, +0x5b,0x58,0xb0,0x02,0x25,0x46,0x20,0x68,0x61,0xb0,0x03,0x25,0xb0,0x03,0x25,0x3f,0x23,0x21,0x38,0x1b,0x21,0x11,0x59,0x2d,0x2c,0x20,0x45,0xb0,0x03,0x25,0x46,0x50,0x58,0xb0,0x02,0x25,0x46,0x20,0x68,0x61,0xb0,0x03,0x25,0xb0,0x03,0x25,0x3f,0x23,0x21,0x38,0x1b,0x21,0x11,0x59,0x2d,0x2c,0x00,0xb0,0x07,0x43,0xb0,0x06,0x43,0x0b, +0x2d,0x2c,0x21,0x21,0x0c,0x64,0x23,0x64,0x8b,0xb8,0x40,0x00,0x62,0x2d,0x2c,0x21,0xb0,0x80,0x51,0x58,0x0c,0x64,0x23,0x64,0x8b,0xb8,0x20,0x00,0x62,0x1b,0xb2,0x00,0x40,0x2f,0x2b,0x59,0xb0,0x02,0x60,0x2d,0x2c,0x21,0xb0,0xc0,0x51,0x58,0x0c,0x64,0x23,0x64,0x8b,0xb8,0x15,0x55,0x62,0x1b,0xb2,0x00,0x80,0x2f,0x2b,0x59,0xb0,0x02, +0x60,0x2d,0x2c,0x0c,0x64,0x23,0x64,0x8b,0xb8,0x40,0x00,0x62,0x60,0x23,0x21,0x2d,0x2c,0x4b,0x53,0x58,0x8a,0xb0,0x04,0x25,0x49,0x64,0x23,0x45,0x69,0xb0,0x40,0x8b,0x61,0xb0,0x80,0x62,0xb0,0x20,0x61,0x6a,0xb0,0x0e,0x23,0x44,0x23,0x10,0xb0,0x0e,0xf6,0x1b,0x21,0x23,0x8a,0x12,0x11,0x20,0x39,0x2f,0x59,0x2d,0x2c,0x4b,0x53,0x58, +0x20,0xb0,0x03,0x25,0x49,0x64,0x69,0x20,0xb0,0x05,0x26,0xb0,0x06,0x25,0x49,0x64,0x23,0x61,0xb0,0x80,0x62,0xb0,0x20,0x61,0x6a,0xb0,0x0e,0x23,0x44,0xb0,0x04,0x26,0x10,0xb0,0x0e,0xf6,0x8a,0x10,0xb0,0x0e,0x23,0x44,0xb0,0x0e,0xf6,0xb0,0x0e,0x23,0x44,0xb0,0x0e,0xed,0x1b,0x8a,0xb0,0x04,0x26,0x11,0x12,0x20,0x39,0x23,0x20,0x39, +0x2f,0x2f,0x59,0x2d,0x2c,0x45,0x23,0x45,0x60,0x23,0x45,0x60,0x23,0x45,0x60,0x23,0x76,0x68,0x18,0xb0,0x80,0x62,0x20,0x2d,0x2c,0xb0,0x48,0x2b,0x2d,0x2c,0x20,0x45,0xb0,0x00,0x54,0x58,0xb0,0x40,0x44,0x20,0x45,0xb0,0x40,0x61,0x44,0x1b,0x21,0x21,0x59,0x2d,0x2c,0x45,0xb1,0x30,0x2f,0x45,0x23,0x45,0x61,0x60,0xb0,0x01,0x60,0x69, +0x44,0x2d,0x2c,0x4b,0x51,0x58,0xb0,0x2f,0x23,0x70,0xb0,0x14,0x23,0x42,0x1b,0x21,0x21,0x59,0x2d,0x2c,0x4b,0x51,0x58,0x20,0xb0,0x03,0x25,0x45,0x69,0x53,0x58,0x44,0x1b,0x21,0x21,0x59,0x1b,0x21,0x21,0x59,0x2d,0x2c,0x45,0xb0,0x14,0x43,0xb0,0x00,0x60,0x63,0xb0,0x01,0x60,0x69,0x44,0x2d,0x2c,0xb0,0x2f,0x45,0x44,0x2d,0x2c,0x45, +0x23,0x20,0x45,0x8a,0x60,0x44,0x2d,0x2c,0x45,0x23,0x45,0x60,0x44,0x2d,0x2c,0x4b,0x23,0x51,0x58,0xb9,0x00,0x33,0xff,0xe0,0xb1,0x34,0x20,0x1b,0xb3,0x33,0x00,0x34,0x00,0x59,0x44,0x44,0x2d,0x2c,0xb0,0x16,0x43,0x58,0xb0,0x03,0x26,0x45,0x8a,0x58,0x64,0x66,0xb0,0x1f,0x60,0x1b,0x64,0xb0,0x20,0x60,0x66,0x20,0x58,0x1b,0x21,0xb0, +0x40,0x59,0xb0,0x01,0x61,0x59,0x23,0x58,0x65,0x59,0xb0,0x29,0x23,0x44,0x23,0x10,0xb0,0x29,0xe0,0x1b,0x21,0x21,0x21,0x21,0x21,0x59,0x2d,0x2c,0xb0,0x02,0x43,0x54,0x58,0x4b,0x53,0x23,0x4b,0x51,0x5a,0x58,0x38,0x1b,0x21,0x21,0x59,0x1b,0x21,0x21,0x21,0x21,0x59,0x2d,0x2c,0xb0,0x16,0x43,0x58,0xb0,0x04,0x25,0x45,0x64,0xb0,0x20, +0x60,0x66,0x20,0x58,0x1b,0x21,0xb0,0x40,0x59,0xb0,0x01,0x61,0x23,0x58,0x1b,0x65,0x59,0xb0,0x29,0x23,0x44,0xb0,0x05,0x25,0xb0,0x08,0x25,0x08,0x20,0x58,0x02,0x1b,0x03,0x59,0xb0,0x04,0x25,0x10,0xb0,0x05,0x25,0x20,0x46,0xb0,0x04,0x25,0x23,0x42,0x3c,0xb0,0x04,0x25,0xb0,0x07,0x25,0x08,0xb0,0x07,0x25,0x10,0xb0,0x06,0x25,0x20, +0x46,0xb0,0x04,0x25,0xb0,0x01,0x60,0x23,0x42,0x3c,0x20,0x58,0x01,0x1b,0x00,0x59,0xb0,0x04,0x25,0x10,0xb0,0x05,0x25,0xb0,0x29,0xe0,0xb0,0x29,0x20,0x45,0x65,0x44,0xb0,0x07,0x25,0x10,0xb0,0x06,0x25,0xb0,0x29,0xe0,0xb0,0x05,0x25,0xb0,0x08,0x25,0x08,0x20,0x58,0x02,0x1b,0x03,0x59,0xb0,0x05,0x25,0xb0,0x03,0x25,0x43,0x48,0xb0, +0x04,0x25,0xb0,0x07,0x25,0x08,0xb0,0x06,0x25,0xb0,0x03,0x25,0xb0,0x01,0x60,0x43,0x48,0x1b,0x21,0x59,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x2d,0x2c,0x02,0xb0,0x04,0x25,0x20,0x20,0x46,0xb0,0x04,0x25,0x23,0x42,0xb0,0x05,0x25,0x08,0xb0,0x03,0x25,0x45,0x48,0x21,0x21,0x21,0x21,0x2d,0x2c,0x02,0xb0,0x03,0x25,0x20,0xb0,0x04,0x25, +0x08,0xb0,0x02,0x25,0x43,0x48,0x21,0x21,0x21,0x2d,0x2c,0x45,0x23,0x20,0x45,0x18,0x20,0xb0,0x00,0x50,0x20,0x58,0x23,0x65,0x23,0x59,0x23,0x68,0x20,0xb0,0x40,0x50,0x58,0x21,0xb0,0x40,0x59,0x23,0x58,0x65,0x59,0x8a,0x60,0x44,0x2d,0x2c,0x4b,0x53,0x23,0x4b,0x51,0x5a,0x58,0x20,0x45,0x8a,0x60,0x44,0x1b,0x21,0x21,0x59,0x2d,0x2c, +0x4b,0x54,0x58,0x20,0x45,0x8a,0x60,0x44,0x1b,0x21,0x21,0x59,0x2d,0x2c,0x4b,0x53,0x23,0x4b,0x51,0x5a,0x58,0x38,0x1b,0x21,0x21,0x59,0x2d,0x2c,0xb0,0x00,0x21,0x4b,0x54,0x58,0x38,0x1b,0x21,0x21,0x59,0x2d,0x2c,0xb0,0x02,0x43,0x54,0x58,0xb0,0x46,0x2b,0x1b,0x21,0x21,0x21,0x21,0x59,0x2d,0x2c,0xb0,0x02,0x43,0x54,0x58,0xb0,0x47, +0x2b,0x1b,0x21,0x21,0x21,0x59,0x2d,0x2c,0xb0,0x02,0x43,0x54,0x58,0xb0,0x48,0x2b,0x1b,0x21,0x21,0x21,0x21,0x59,0x2d,0x2c,0xb0,0x02,0x43,0x54,0x58,0xb0,0x49,0x2b,0x1b,0x21,0x21,0x21,0x59,0x2d,0x2c,0x20,0x8a,0x08,0x23,0x4b,0x53,0x8a,0x4b,0x51,0x5a,0x58,0x23,0x38,0x1b,0x21,0x21,0x59,0x2d,0x2c,0x00,0xb0,0x02,0x25,0x49,0xb0, +0x00,0x53,0x58,0x20,0xb0,0x40,0x38,0x11,0x1b,0x21,0x59,0x2d,0x2c,0x01,0x46,0x23,0x46,0x60,0x23,0x46,0x61,0x23,0x20,0x10,0x20,0x46,0x8a,0x61,0xb8,0xff,0x80,0x62,0x8a,0xb1,0x40,0x40,0x8a,0x70,0x45,0x60,0x68,0x3a,0x2d,0x2c,0x20,0x8a,0x23,0x49,0x64,0x8a,0x23,0x53,0x58,0x3c,0x1b,0x21,0x59,0x2d,0x2c,0x4b,0x52,0x58,0x7d,0x1b, +0x7a,0x59,0x2d,0x2c,0xb0,0x12,0x00,0x4b,0x01,0x4b,0x54,0x42,0x2d,0x2c,0xb1,0x02,0x00,0x42,0xb1,0x23,0x01,0x88,0x51,0xb1,0x40,0x01,0x88,0x53,0x5a,0x58,0xb9,0x10,0x00,0x00,0x20,0x88,0x54,0x58,0xb2,0x02,0x01,0x02,0x43,0x60,0x42,0x59,0xb1,0x24,0x01,0x88,0x51,0x58,0xb9,0x20,0x00,0x00,0x40,0x88,0x54,0x58,0xb2,0x02,0x02,0x02, +0x43,0x60,0x42,0xb1,0x24,0x01,0x88,0x54,0x58,0xb2,0x02,0x20,0x02,0x43,0x60,0x42,0x00,0x4b,0x01,0x4b,0x52,0x58,0xb2,0x02,0x08,0x02,0x43,0x60,0x42,0x59,0x1b,0xb9,0x40,0x00,0x00,0x80,0x88,0x54,0x58,0xb2,0x02,0x04,0x02,0x43,0x60,0x42,0x59,0xb9,0x40,0x00,0x00,0x80,0x63,0xb8,0x01,0x00,0x88,0x54,0x58,0xb2,0x02,0x08,0x02,0x43, +0x60,0x42,0x59,0xb9,0x40,0x00,0x01,0x00,0x63,0xb8,0x02,0x00,0x88,0x54,0x58,0xb2,0x02,0x10,0x02,0x43,0x60,0x42,0x59,0xb9,0x40,0x00,0x02,0x00,0x63,0xb8,0x04,0x00,0x88,0x54,0x58,0xb2,0x02,0x40,0x02,0x43,0x60,0x42,0x59,0x59,0x59,0x59,0x59,0x2d,0x2c,0x45,0x18,0x68,0x23,0x4b,0x51,0x58,0x23,0x20,0x45,0x20,0x64,0xb0,0x40,0x50, +0x58,0x7c,0x59,0x68,0x8a,0x60,0x59,0x44,0x2d,0x2c,0xb0,0x00,0x16,0xb0,0x02,0x25,0xb0,0x02,0x25,0x01,0xb0,0x01,0x23,0x3e,0x00,0xb0,0x02,0x23,0x3e,0xb1,0x01,0x02,0x06,0x0c,0xb0,0x0a,0x23,0x65,0x42,0xb0,0x0b,0x23,0x42,0x01,0xb0,0x01,0x23,0x3f,0x00,0xb0,0x02,0x23,0x3f,0xb1,0x01,0x02,0x06,0x0c,0xb0,0x06,0x23,0x65,0x42,0xb0, +0x07,0x23,0x42,0xb0,0x01,0x16,0x01,0x2d,0x2c,0x7a,0x8a,0x10,0x45,0x23,0xf5,0x18,0x2d,0x00,0x00,0x00,0x40,0x64,0x09,0x03,0x04,0xfd,0x01,0xf5,0x50,0x28,0x1f,0xf2,0x46,0x28,0x1f,0xf1,0x46,0x2a,0x1f,0xf0,0x46,0x35,0x1f,0x8b,0xee,0x9b,0xee,0xab,0xee,0x03,0x6b,0xef,0x8b,0xef,0x02,0xbb,0xef,0x01,0xa4,0xef,0x01,0x1b,0xef,0x5b, +0xef,0x6b,0xef,0x03,0x04,0xec,0x44,0xec,0x02,0x0a,0xeb,0x46,0xff,0x1f,0xe7,0xe4,0x26,0x1f,0xe6,0xe4,0x3d,0x1f,0xe5,0xe4,0x1e,0x1f,0xe3,0xe2,0x46,0x1f,0x0b,0xe2,0x01,0x40,0xe2,0x46,0x16,0x1f,0xe1,0xe0,0x46,0x1f,0xbb,0xe0,0xcb,0xe0,0xdb,0xe0,0x03,0x40,0xe0,0x33,0x36,0x46,0xe0,0x46,0x18,0x1f,0xbc,0x01,0x14,0x00,0x3e,0x01, +0x12,0x00,0x55,0x01,0x13,0x40,0x0c,0x3d,0x03,0x55,0xdf,0x3d,0xdd,0x55,0xde,0x3d,0xdc,0x55,0xbb,0x41,0x09,0x01,0x16,0x00,0x01,0x00,0x54,0x01,0x16,0x00,0x64,0x01,0x16,0x00,0x02,0xff,0xc0,0x01,0x16,0xb3,0x0c,0x16,0x46,0x20,0xb8,0x01,0x16,0xb2,0x01,0x02,0x00,0xbc,0x01,0x16,0x00,0x10,0x01,0x16,0x00,0x02,0x01,0x15,0xb2,0xdc, +0x3d,0x1f,0xb8,0x01,0x11,0x40,0x63,0x03,0xff,0x1f,0x10,0xdd,0x20,0xdd,0x40,0xdd,0x50,0xdd,0x80,0xdd,0xb0,0xdd,0x06,0x20,0xdc,0x50,0xdc,0x80,0xdc,0xb0,0xdc,0x04,0x0f,0xdc,0x01,0xd0,0x15,0x33,0x1f,0x5f,0xc8,0x6f,0xc8,0x7f,0xc8,0x03,0x5f,0xc3,0x6f,0xc3,0x7f,0xc3,0x03,0xbf,0xc2,0x01,0xc1,0x50,0x26,0x1f,0x70,0xbe,0x01,0x20, +0xbe,0x30,0xbe,0xc0,0xbe,0x03,0x70,0xbe,0x80,0xbe,0x02,0x0f,0xbc,0x1f,0xbc,0x02,0x2f,0xbc,0x3f,0xbc,0x6f,0xbc,0xaf,0xbc,0xdf,0xbc,0x05,0xb9,0xad,0x26,0x1f,0x20,0xb8,0x30,0xb8,0x50,0xb8,0x70,0xb8,0x80,0xb8,0x05,0xb8,0xff,0xc0,0x40,0x1c,0xb8,0x13,0x29,0x46,0x10,0xb7,0x01,0x20,0xb7,0x50,0xb7,0x80,0xb7,0xb0,0xb7,0x04,0x80, +0xb5,0xb0,0xb5,0x02,0x0f,0xb3,0x3f,0xb3,0xef,0xb3,0x03,0xb8,0x01,0x0d,0x40,0x2b,0xaa,0x48,0x1f,0x80,0xb0,0x90,0xb0,0x02,0xb0,0xb0,0xc0,0xb0,0xd0,0xb0,0x03,0x2f,0xaf,0x3f,0xaf,0x02,0xa0,0xad,0xb0,0xad,0x02,0xc0,0xad,0xd0,0xad,0x02,0x2f,0xac,0x3f,0xac,0x02,0x9f,0xab,0x01,0xc0,0xaa,0xd0,0xaa,0x02,0x41,0x0f,0x01,0x0f,0x00, +0x32,0x01,0x0e,0x00,0x55,0x00,0x00,0x01,0x0e,0x00,0x10,0x01,0x0e,0x00,0x20,0x01,0x0e,0x00,0x70,0x01,0x0e,0x00,0x04,0x00,0x0f,0x01,0x10,0x40,0x15,0x01,0x50,0x9c,0x60,0x9c,0x70,0x9c,0x03,0x99,0x96,0x26,0x1f,0x98,0x46,0x26,0x1f,0x30,0x97,0x40,0x97,0x02,0xb8,0xff,0xc0,0xb3,0x96,0x16,0x1c,0x46,0xb8,0xff,0xc0,0x40,0x2a,0x96, +0x0e,0x11,0x46,0x95,0x1b,0xff,0x1f,0x0f,0x94,0xaf,0x94,0xbf,0x94,0x03,0x40,0x94,0x1d,0x31,0x46,0x40,0x94,0x16,0x1b,0x46,0x40,0x94,0x0c,0x0f,0x46,0x0f,0x93,0x2f,0x93,0x3f,0x93,0x7f,0x93,0xef,0x93,0x05,0x0f,0xba,0x01,0x0c,0x00,0x6f,0x01,0x0c,0x40,0x20,0x02,0x92,0x8d,0x26,0x1f,0x91,0x53,0xff,0x1f,0xdf,0x90,0x01,0x30,0x90, +0x01,0x1f,0x90,0x2f,0x90,0x02,0x6f,0x90,0x7f,0x90,0x02,0x00,0x8f,0x10,0x8f,0x20,0x8f,0x03,0xb8,0xff,0xc0,0x40,0x20,0x8f,0x18,0x1c,0x46,0x20,0x8e,0x30,0x8e,0x02,0x4f,0x8d,0x5f,0x8d,0x6f,0x8d,0x03,0x30,0x8c,0x01,0x0f,0x8c,0x1f,0x8c,0x2f,0x8c,0x03,0x40,0x8c,0x10,0x13,0x46,0x10,0xbf,0x01,0x0b,0x00,0x20,0x01,0x0b,0x00,0x30, +0x01,0x0b,0x00,0x03,0xff,0xc0,0x01,0x0b,0xb2,0x17,0x20,0x46,0xb9,0xff,0xc0,0x01,0x0b,0x40,0x50,0x10,0x14,0x46,0x8b,0x82,0x26,0x1f,0x89,0x4a,0x3c,0x1f,0x88,0x87,0x3d,0x1f,0x87,0x84,0x3c,0x1f,0x86,0x4a,0xff,0x1f,0x9f,0x85,0x01,0x10,0x84,0x20,0x84,0x30,0x84,0x03,0x30,0x83,0x01,0x7f,0x82,0x01,0x40,0x82,0x09,0x0c,0x46,0x73, +0x50,0x26,0x1f,0x6f,0x46,0x35,0x1f,0x6e,0x46,0x35,0x1f,0x1a,0x01,0x18,0x55,0x19,0x33,0x18,0x55,0x07,0x33,0x03,0x55,0x06,0x03,0xff,0x1f,0x60,0x50,0x26,0x1f,0x5f,0x50,0x26,0x1f,0xb9,0xff,0xe0,0x01,0x07,0xb2,0x1f,0x26,0x46,0xb9,0xff,0xe0,0x01,0x07,0x40,0x1f,0x13,0x1c,0x46,0x5e,0x5a,0x48,0x1f,0x5c,0x46,0x31,0x1f,0x5b,0x5a, +0x48,0x1f,0x5a,0x46,0x31,0x1f,0x13,0x32,0x12,0x55,0x05,0x01,0x03,0x55,0x04,0x32,0x03,0x55,0xb8,0x01,0x08,0xb5,0x1b,0x3c,0x1f,0x0f,0x03,0x01,0xb9,0x01,0x19,0x01,0x18,0xb2,0x35,0x1f,0x40,0xb8,0x01,0x18,0xb2,0x17,0x28,0x46,0xb8,0x01,0x0a,0x40,0x25,0x50,0x26,0x1f,0x52,0x50,0x1b,0x1f,0xef,0x51,0xff,0x51,0x02,0x40,0x51,0x35, +0x38,0x46,0x40,0x51,0x25,0x28,0x46,0xcf,0x50,0x01,0xdf,0x4c,0x01,0x4c,0x46,0x1d,0x1f,0x4b,0x46,0x48,0x1f,0x50,0xb8,0x01,0x1b,0x40,0x5a,0x01,0x4a,0x46,0x26,0x1f,0x49,0x46,0x35,0x1f,0x48,0x46,0x35,0x1f,0x47,0x46,0x35,0x1f,0xaf,0x46,0x01,0xdf,0x46,0xef,0x46,0x02,0x80,0x46,0x01,0x16,0x32,0x15,0x55,0x11,0x01,0x0f,0x55,0x10, +0x32,0x0f,0x55,0x02,0x01,0x00,0x55,0x01,0x00,0x01,0x1f,0x1f,0x0f,0x3f,0x0f,0x5f,0x0f,0x7f,0x0f,0x04,0x0f,0x0f,0x2f,0x0f,0x4f,0x0f,0x6f,0x0f,0x8f,0x0f,0xdf,0x0f,0xff,0x0f,0x07,0x3f,0x0f,0x7f,0x0f,0xef,0x0f,0x03,0x6f,0x00,0x01,0x4f,0x00,0x01,0xa0,0x16,0x01,0x05,0x01,0xb8,0x01,0x90,0xb1,0x54,0x53,0x2b,0x2b,0x4b,0xb8,0x07, +0xff,0x52,0x4b,0xb0,0x09,0x50,0x5b,0xb0,0x01,0x88,0xb0,0x25,0x53,0xb0,0x01,0x88,0xb0,0x40,0x51,0x5a,0xb0,0x06,0x88,0xb0,0x00,0x55,0x5a,0x5b,0x58,0xb1,0x01,0x01,0x8e,0x59,0x85,0x8d,0x8d,0x00,0x42,0x1d,0x4b,0xb0,0x32,0x53,0x58,0xb0,0x60,0x1d,0x59,0x4b,0xb0,0x64,0x53,0x58,0xb0,0x40,0x1d,0x59,0x4b,0xb0,0x80,0x53,0x58,0xb0, +0x10,0x1d,0xb1,0x16,0x00,0x42,0x59,0x73,0x74,0x73,0x74,0x75,0x2b,0x2b,0x2b,0x2b,0x2b,0x01,0x73,0x74,0x75,0x2b,0x2b,0x2b,0x2b,0x73,0x00,0x2b,0x2b,0x74,0x74,0x2b,0x2b,0x73,0x2b,0x2b,0x2b,0x2b,0x73,0x2b,0x2b,0x2b,0x2b,0x01,0x2b,0x2b,0x2b,0x00,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x01,0x2b,0x2b,0x00,0x2b,0x01,0x2b, +0x73,0x74,0x74,0x73,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x73,0x00,0x2b,0x73,0x74,0x74,0x74,0x2b,0x75,0x73,0x74,0x74,0x74,0x2b,0x2b,0x73,0x73,0x2b,0x2b,0x2b,0x73,0x2b,0x01,0x2b,0x2b,0x73,0x2b,0x2b,0x00,0x73,0x74,0x73,0x2b,0x01,0x73,0x73,0x74,0x00,0x73,0x74,0x74,0x73,0x74,0x2b,0x73,0x01,0x73,0x00,0x73,0x74,0x2b,0x73,0x2b, +0x73,0x74,0x01,0x73,0x74,0x75,0x00,0x2b,0x73,0x01,0x74,0x00,0x74,0x2b,0x73,0x73,0x73,0x2b,0x2b,0x73,0x5f,0x73,0x2b,0x74,0x74,0x2b,0x2b,0x2b,0x2b,0x01,0x2b,0x2b,0x74,0x2b,0x2b,0x5e,0x73,0x2b,0x00,0x2b,0x2b,0x2b,0x01,0x2b,0x5e,0x73,0x00,0x73,0x73,0x73,0x74,0x73,0x01,0x2b,0x2b,0x2b,0x00,0x2b,0x73,0x18,0x5f,0x5e,0x00,0x00, +0x05,0xcc,0x05,0xcc,0x00,0x7d,0x05,0x45,0x00,0x15,0x00,0x60,0x05,0x45,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x3a,0x00,0x14,0x00,0x77,0x00,0x00,0xff,0xec,0x00,0x00,0x00,0x00,0xff,0xec,0x00,0x00,0x00,0x00,0xff,0xec,0x00,0x00,0xfe,0x57,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,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,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0x00,0xbd,0x00,0xaa,0x00,0xa0,0x00,0xc8,0x00,0xb4,0x00,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x00,0x7e,0x00,0xa5,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xbf,0x00,0xc9,0x00,0xab,0x00,0x8c,0x00,0xbc,0x00,0x9b, +0x00,0x8d,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,0xb9,0x00,0xb4,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x94,0x00,0x5f,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,0x01,0xa8,0x00,0x6f,0x00,0x78,0x00,0xa4,0x00,0xc8,0x00,0x83,0x00,0x8d,0x00,0xbb,0x00,0x5e,0x01,0x8a,0x01,0x03,0x00,0x60,0x00,0x74,0x00,0x81,0x00,0xb8,0x00,0xc0,0x00,0x50,0x04,0xb1,0x04,0xc3,0xfe,0x4c,0x00,0xeb,0x01,0xb2,0x00,0xc3,0x01,0x09,0x00,0x7b,0x01,0x2b,0x02,0x96,0x00,0xc9,0x00,0x96,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x92,0x00,0xa8,0x00,0x6b,0x00,0x92,0x00,0xb7,0x00,0x6b,0x00,0x9b,0x00,0x00,0x00,0x00,0x02,0xf2,0x00,0x92,0x02,0x3e,0x00,0x6e,0x02,0xa5,0x03,0x45,0x00,0x89,0x00,0xa0,0x00,0x60,0x02,0x4c,0x00,0x00,0x00,0xc3,0x00,0x00, +0x01,0x4e,0x00,0xa4,0x01,0x5b,0x00,0x5e,0x00,0x80,0x00,0x69,0x00,0x6f,0x00,0x00,0x00,0x5e,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x03,0x4a,0x00,0x87,0x00,0x7b,0x00,0x00,0x00,0x75,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x82,0x02,0x33,0x00,0x0b,0xff,0xf4, +0x00,0x83,0x00,0x89,0x00,0x8f,0x00,0x96,0x00,0x69,0x00,0x71,0x00,0x5b,0x00,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb2,0x02,0x03,0x00,0x00,0x00,0x8d,0x03,0x1f,0x00,0xbb,0x00,0xae,0x00,0xb5,0x00,0x00,0x00,0x00,0x00,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xa9,0x03,0x70,0x02,0xbc,0x02,0x08,0xfd,0x99,0x00,0x91, +0x00,0x91,0x00,0x4d,0x00,0x4d,0x00,0x64,0x00,0x64,0x01,0x81,0x00,0x9f,0x00,0xa8,0xfe,0x68,0xfe,0x9c,0x00,0x9b,0x01,0x45,0x01,0x45,0x00,0x90,0xfe,0xf6,0x00,0x17,0x00,0x7a,0x05,0x45,0x02,0x4d,0x00,0x0c,0xff,0xee,0x05,0x98,0x02,0x8b,0x00,0x6e,0x00,0x4c,0x00,0x62,0x00,0x46,0x00,0xe8,0x00,0x44,0x05,0x11,0x00,0x00,0x00,0x2c, +0x00,0x2c,0x00,0x2c,0x00,0x2c,0x00,0x54,0x00,0x7e,0x01,0x30,0x02,0x30,0x03,0x06,0x04,0x08,0x04,0x24,0x04,0x5c,0x04,0x92,0x05,0x0c,0x05,0x4a,0x05,0x76,0x05,0x92,0x05,0xac,0x05,0xda,0x06,0x5c,0x06,0xa8,0x07,0x22,0x07,0xe8,0x08,0x32,0x08,0xbc,0x09,0x64,0x09,0x9e,0x0a,0x6a,0x0b,0x0e,0x0b,0x34,0x0b,0x78,0x0b,0xc8,0x0c,0x02, +0x0c,0x52,0x0c,0xc8,0x0e,0x08,0x0e,0x6a,0x0e,0xee,0x0f,0x80,0x0f,0xda,0x10,0x1e,0x10,0x58,0x10,0xdc,0x11,0x20,0x11,0x66,0x11,0xb0,0x12,0x18,0x12,0x3a,0x12,0xd0,0x13,0x32,0x13,0xa4,0x13,0xfc,0x14,0x8a,0x15,0x06,0x15,0xb6,0x15,0xee,0x16,0x46,0x16,0xaa,0x17,0xa0,0x18,0x24,0x18,0x86,0x18,0xd8,0x19,0x04,0x19,0x34,0x19,0x5c, +0x19,0xa4,0x19,0xb8,0x19,0xd6,0x1a,0x84,0x1b,0x02,0x1b,0x88,0x1c,0x0a,0x1c,0x94,0x1c,0xf4,0x1d,0xa2,0x1d,0xf2,0x1e,0x2e,0x1e,0x7e,0x1e,0xf2,0x1f,0x22,0x1f,0xb8,0x20,0x0e,0x20,0x72,0x20,0xfa,0x21,0x80,0x21,0xd4,0x22,0x66,0x22,0xbe,0x23,0x18,0x23,0x82,0x24,0x72,0x24,0xee,0x25,0x7a,0x25,0xbc,0x26,0x3c,0x26,0x56,0x26,0xd6, +0x27,0x38,0x27,0x62,0x27,0xdc,0x28,0x76,0x29,0x40,0x29,0xc4,0x29,0xec,0x2a,0xf4,0x2b,0x20,0x2c,0x22,0x2c,0xb4,0x2d,0x04,0x2d,0x26,0x2d,0xfc,0x2e,0x06,0x2e,0x66,0x2e,0xba,0x2f,0x16,0x2f,0x9e,0x2f,0xbc,0x30,0x2a,0x30,0x6c,0x30,0x74,0x30,0xc8,0x31,0x08,0x31,0x64,0x31,0xb2,0x31,0xd8,0x31,0xf6,0x32,0x18,0x32,0x92,0x32,0xaa, +0x32,0xc2,0x32,0xda,0x32,0xf2,0x33,0x0c,0x33,0x24,0x33,0x94,0x33,0xa8,0x33,0xc0,0x33,0xd8,0x33,0xf0,0x34,0x0a,0x34,0x22,0x34,0x3a,0x34,0x52,0x34,0x6c,0x34,0xe8,0x35,0x00,0x35,0x18,0x35,0x30,0x35,0x48,0x35,0x60,0x35,0x7a,0x35,0xe4,0x36,0x92,0x36,0xaa,0x36,0xc2,0x36,0xda,0x36,0xf4,0x37,0x0c,0x37,0x6a,0x38,0x22,0x38,0x3a, +0x38,0x50,0x38,0x6a,0x38,0x88,0x38,0xa4,0x38,0xbc,0x39,0x9c,0x39,0xb0,0x39,0xc8,0x39,0xde,0x39,0xf4,0x3a,0x0c,0x3a,0x28,0x3a,0x3e,0x3a,0x5c,0x3a,0x80,0x3b,0x32,0x3b,0x48,0x3b,0x60,0x3b,0x76,0x3b,0x8c,0x3b,0xa2,0x3b,0xba,0x3c,0x06,0x3c,0xc4,0x3c,0xdc,0x3c,0xf2,0x3d,0x0a,0x3d,0x24,0x3d,0x3a,0x3d,0xbe,0x3d,0xd6,0x3d,0xee, +0x3e,0x06,0x3e,0x1e,0x3e,0x34,0x3e,0x48,0x3e,0x5c,0x3e,0x74,0x3e,0x8a,0x3e,0xa2,0x3e,0xb8,0x3e,0xd0,0x3e,0xe2,0x3e,0xfa,0x3f,0x10,0x3f,0x28,0x3f,0xc0,0x3f,0xc8,0x40,0x68,0x40,0x80,0x40,0x96,0x40,0xae,0x40,0xc4,0x40,0xdc,0x40,0xee,0x41,0x02,0x41,0x16,0x41,0x2e,0x41,0x46,0x41,0x5e,0x41,0x74,0x41,0x8c,0x41,0xa2,0x41,0xba, +0x41,0xcc,0x41,0xde,0x41,0xf4,0x42,0x0c,0x42,0x90,0x42,0xf6,0x43,0x68,0x43,0x80,0x43,0x98,0x43,0xb0,0x43,0xc8,0x43,0xe0,0x43,0xf6,0x44,0x0a,0x44,0x1e,0x44,0x36,0x44,0x66,0x44,0xca,0x45,0x38,0x45,0x50,0x45,0x66,0x45,0x7a,0x45,0x8e,0x46,0x02,0x46,0x1a,0x46,0x6a,0x46,0x7e,0x46,0x92,0x46,0xa8,0x46,0xc0,0x46,0xd4,0x46,0xe0, +0x47,0x2e,0x47,0x90,0x47,0xa8,0x47,0xc0,0x47,0xd4,0x47,0xe8,0x48,0x00,0x48,0x16,0x48,0x30,0x48,0xcc,0x49,0x40,0x49,0x58,0x49,0x6e,0x49,0x86,0x49,0x9c,0x49,0xb6,0x49,0xd0,0x4a,0x4a,0x4b,0x02,0x4b,0x1a,0x4b,0x30,0x4b,0x44,0x4b,0x58,0x4b,0x70,0x4b,0x88,0x4b,0xa0,0x4b,0xb6,0x4b,0xce,0x4b,0xe4,0x4b,0xf8,0x4c,0x0c,0x4c,0x24, +0x4c,0x3a,0x4c,0x46,0x4c,0x52,0x4c,0x6a,0x4c,0x80,0x4c,0xd4,0x4d,0x46,0x4d,0x5e,0x4d,0x76,0x4d,0x8e,0x4d,0xa6,0x4d,0xbe,0x4d,0xd6,0x4d,0xfa,0x4e,0x14,0x4e,0x2e,0x4e,0x48,0x4e,0x5a,0x4e,0x6e,0x4e,0x86,0x4e,0x9e,0x4e,0xb6,0x4e,0xce,0x4e,0xe8,0x4f,0x00,0x4f,0x16,0x4f,0x2e,0x4f,0x40,0x4f,0x58,0x4f,0x6e,0x4f,0xb2,0x50,0x10, +0x51,0x02,0x52,0x32,0x52,0x4a,0x52,0x60,0x52,0x78,0x52,0x8e,0x52,0x9a,0x52,0xa6,0x52,0xb2,0x52,0xbe,0x52,0xe6,0x53,0x10,0x53,0x28,0x53,0x60,0x53,0x78,0x53,0xf8,0x54,0x36,0x54,0x8e,0x54,0xd4,0x54,0xfc,0x55,0x52,0x55,0x6a,0x55,0x8c,0x55,0xac,0x56,0x02,0x56,0x22,0x56,0x3a,0x56,0xa6,0x57,0x62,0x57,0x7c,0x57,0x84,0x57,0x8c, +0x57,0xac,0x58,0x0e,0x58,0x16,0x58,0x1e,0x58,0x26,0x58,0xc8,0x58,0xd0,0x58,0xd8,0x59,0x2a,0x59,0x32,0x59,0x3a,0x59,0x98,0x59,0xa0,0x59,0xd4,0x59,0xdc,0x5a,0x2c,0x5a,0x34,0x5a,0x3c,0x5a,0xd4,0x5a,0xdc,0x5b,0x44,0x5c,0x02,0x5c,0x1c,0x5c,0x36,0x5c,0x4c,0x5c,0x62,0x5c,0x78,0x5c,0x8e,0x5c,0xa8,0x5d,0x4a,0x5d,0xec,0x5e,0x76, +0x5f,0x14,0x5f,0xa8,0x60,0x36,0x60,0x8e,0x61,0x2a,0x61,0x78,0x61,0x80,0x62,0x24,0x62,0x94,0x62,0xf8,0x63,0xb8,0x63,0xc0,0x64,0x38,0x64,0xbc,0x65,0x4c,0x65,0xd2,0x66,0x30,0x66,0x82,0x67,0x14,0x67,0xb4,0x68,0x2a,0x68,0xd4,0x68,0xee,0x69,0x08,0x69,0x1e,0x69,0x34,0x69,0x4a,0x69,0x52,0x69,0x6c,0x69,0xe0,0x69,0xf8,0x6a,0x96, +0x6a,0x9e,0x6a,0xa6,0x6a,0xc0,0x6a,0xc8,0x6b,0x42,0x6b,0xa4,0x6b,0xfa,0x6c,0x12,0x6c,0x1e,0x6c,0x36,0x6c,0x7c,0x6c,0x84,0x6c,0xec,0x6c,0xf4,0x6c,0xfc,0x6d,0x60,0x6d,0x68,0x6e,0x1e,0x6e,0xea,0x6f,0x58,0x6f,0x70,0x6f,0xdc,0x70,0x3e,0x70,0x46,0x70,0x4e,0x70,0x56,0x70,0x8a,0x70,0x92,0x70,0x9a,0x70,0xa2,0x71,0x0c,0x71,0x14, +0x71,0x1c,0x71,0x5c,0x71,0xaa,0x71,0xf8,0x72,0x5e,0x72,0xba,0x73,0x2a,0x73,0x86,0x74,0x1e,0x74,0x9e,0x75,0x1c,0x75,0x24,0x75,0xbe,0x76,0x30,0x76,0x56,0x76,0xc4,0x76,0xcc,0x77,0x88,0x78,0x2c,0x78,0x7e,0x78,0x94,0x79,0x12,0x79,0x6a,0x79,0xea,0x7a,0x22,0x7a,0x2a,0x7a,0x56,0x7a,0x5e,0x7a,0x66,0x7a,0x96,0x7a,0x9e,0x7b,0x2c, +0x7b,0x34,0x7b,0x80,0x7b,0xd4,0x7c,0x1c,0x7c,0x86,0x7c,0xd6,0x7d,0x46,0x7d,0x90,0x7e,0x22,0x7e,0xae,0x7f,0x14,0x7f,0x20,0x7f,0x38,0x7f,0xc6,0x7f,0xde,0x80,0x64,0x80,0x6c,0x80,0x7e,0x80,0x96,0x80,0x9e,0x81,0x1a,0x81,0x7c,0x81,0xee,0x82,0x04,0x82,0x10,0x82,0x26,0x82,0x5c,0x82,0x96,0x82,0xd0,0x82,0xe8,0x83,0x00,0x83,0x18, +0x83,0x2e,0x83,0x48,0x83,0x60,0x83,0x78,0x83,0x90,0x83,0xac,0x83,0xc8,0x83,0xdc,0x83,0xf0,0x84,0x04,0x84,0x2a,0x84,0x50,0x84,0x7a,0x84,0xa8,0x84,0xd4,0x85,0x18,0x85,0x64,0x85,0xb2,0x85,0xe4,0x86,0x34,0x86,0x70,0x86,0xa6,0x87,0xc8,0x87,0xe4,0x88,0x0e,0x88,0x3c,0x88,0x6a,0x88,0xaa,0x88,0xb4,0x88,0xd6,0x89,0x28,0x89,0x70, +0x8a,0x26,0x8b,0x20,0x8b,0xc2,0x8c,0x96,0x8d,0x38,0x8d,0xe4,0x8e,0x72,0x8f,0x30,0x8f,0xa4,0x8f,0xc8,0x8f,0xec,0x90,0x12,0x90,0x3c,0x90,0x6a,0x90,0x9c,0x90,0xcc,0x90,0xfc,0x91,0x40,0x91,0x8e,0x91,0xea,0x92,0x80,0x92,0xe2,0x93,0x18,0x93,0x70,0x93,0x8a,0x93,0xac,0x93,0xec,0x94,0x98,0x94,0xb2,0x94,0xf6,0x95,0x4a,0x96,0x08, +0x96,0x70,0x96,0xac,0x97,0x0c,0x97,0x6c,0x97,0x9e,0x97,0xc4,0x98,0x02,0x98,0x40,0x98,0x58,0x98,0x6e,0x98,0x8e,0x98,0xaa,0x98,0xc8,0x98,0xe4,0x99,0x08,0x99,0x2a,0x99,0x4e,0x99,0x72,0x99,0xa0,0x99,0xc6,0x99,0xea,0x9a,0x14,0x9a,0x3e,0x9a,0x72,0x9a,0x9a,0x9a,0xc2,0x9a,0xf4,0x9b,0x1e,0x9b,0x48,0x9b,0x7c,0x9b,0xa4,0x9b,0xcc, +0x9b,0xfe,0x9c,0x2e,0x9c,0x60,0x9c,0x9e,0x9c,0xcc,0x9c,0xfc,0x9d,0x3a,0x9d,0x6a,0x9d,0x98,0x9d,0xd6,0x9e,0x06,0x9e,0x34,0x9e,0x74,0x9e,0xb6,0x9e,0xf8,0x9f,0x4c,0x9f,0x62,0x9f,0x78,0x9f,0x8e,0x9f,0xa4,0x9f,0xba,0xa1,0x6e,0xa4,0x90,0xa7,0x9c,0xa7,0xb0,0xa7,0xd8,0xa7,0xf0,0xa8,0x1c,0xa8,0x30,0xa8,0x44,0xa8,0x5a,0xa8,0x70, +0xa8,0x84,0xa8,0xca,0xa9,0x28,0xa9,0x5e,0xa9,0x94,0xa9,0xee,0xaa,0x3e,0xab,0x1c,0xab,0xb8,0xac,0x64,0xac,0xd6,0xad,0x56,0xad,0xc4,0xae,0x44,0xae,0x96,0xae,0xd2,0xaf,0x28,0xaf,0xb2,0xb0,0x28,0xb0,0x8c,0xb0,0xae,0xb0,0xe4,0xb1,0x0a,0xb1,0x2a,0xb1,0x6a,0xb1,0xac,0xb2,0x04,0xb2,0x92,0xb2,0xea,0xb3,0x50,0xb3,0x84,0xb4,0x1e, +0x00,0x02,0x00,0x44,0x00,0x00,0x02,0x64,0x05,0x55,0x00,0x03,0x00,0x07,0x00,0x2e,0xb1,0x01,0x00,0x2f,0x3c,0xb2,0x07,0x04,0x1c,0xed,0x32,0xb1,0x06,0x05,0xdc,0x3c,0xb2,0x03,0x02,0x1c,0xed,0x32,0x00,0xb1,0x03,0x00,0x2f,0x3c,0xb2,0x05,0x04,0x1c,0xed,0x32,0xb2,0x07,0x06,0x1d,0xfc,0x3c,0xb2,0x01,0x02,0x1c,0xed,0x32,0x33,0x11, +0x21,0x11,0x25,0x21,0x11,0x21,0x44,0x02,0x20,0xfe,0x24,0x01,0x98,0xfe,0x68,0x05,0x55,0xfa,0xab,0x44,0x04,0xcd,0x00,0x00,0x00,0x02,0x02,0x03,0x00,0x00,0x02,0xc9,0x05,0x44,0x00,0x03,0x00,0x07,0x00,0x29,0x40,0x15,0x03,0x07,0x98,0x02,0x00,0x04,0x10,0x04,0x02,0x04,0x04,0x08,0x09,0x01,0x01,0x02,0x05,0x9d,0x04,0x02,0x03,0x00, +0x3f,0x2f,0xed,0x11,0x39,0x2f,0x11,0x12,0x01,0x39,0x2f,0x5d,0x33,0xed,0x32,0x31,0x30,0x01,0x23,0x03,0x33,0x03,0x35,0x33,0x15,0x02,0xb1,0x94,0x18,0xc4,0xc6,0xc2,0x01,0x8d,0x03,0xb7,0xfa,0xbc,0xc9,0xc9,0x00,0x02,0x01,0x15,0x03,0x4d,0x03,0xb6,0x05,0xcc,0x00,0x03,0x00,0x07,0x00,0x27,0x40,0x14,0x03,0x96,0x02,0x02,0x09,0x07, +0x96,0x2f,0x06,0x01,0x00,0x06,0x01,0x06,0x05,0x00,0x00,0x06,0x02,0x00,0x00,0x3f,0x33,0x33,0x2f,0x32,0x01,0x2f,0x5d,0x5d,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x01,0x23,0x03,0x33,0x01,0x23,0x03,0x33,0x03,0x8c,0x8e,0x28,0xe0,0xfe,0x15,0x8d,0x29,0xe0,0x03,0x4d,0x02,0x7f,0xfd,0x81,0x02,0x7f,0x00,0x00,0x00,0x00,0x02,0x00,0x36, +0x00,0x00,0x04,0x8b,0x05,0x45,0x00,0x1b,0x00,0x1f,0x00,0xf0,0xb9,0x00,0x04,0xff,0xf0,0x40,0x99,0x0d,0x11,0x48,0x06,0x1d,0x16,0x1d,0x26,0x1d,0x03,0x06,0x01,0x16,0x01,0x26,0x01,0x03,0x12,0x0f,0x0e,0x0b,0x04,0x0a,0x13,0x08,0x1d,0x1c,0x15,0x04,0x14,0x09,0x04,0x01,0x00,0x19,0x04,0x18,0x05,0x16,0x1f,0x1e,0x07,0x04,0x06,0x17, +0x13,0xac,0x14,0x05,0xac,0x06,0x17,0xac,0x18,0x1a,0x2f,0x03,0x3f,0x03,0x02,0x03,0x1a,0x03,0x18,0x30,0x06,0x40,0x06,0x50,0x06,0x03,0x10,0x18,0x20,0x18,0x02,0xe0,0x18,0xf0,0x18,0x02,0x14,0x06,0x18,0x18,0x06,0x14,0x03,0x0a,0x21,0x11,0x11,0x0c,0x0c,0x09,0xac,0x00,0x0a,0x01,0x0a,0x08,0x04,0x0c,0xaf,0x0d,0x1d,0x01,0x0d,0x1c, +0x00,0x10,0xaf,0x11,0x19,0x15,0x11,0x4f,0x11,0x01,0x4f,0x11,0x5f,0x11,0xef,0x11,0x03,0x11,0x40,0x1f,0x22,0x48,0x7f,0x0d,0x8f,0x0d,0x9f,0x0d,0x03,0x4f,0x0d,0x5f,0x0d,0x02,0x0d,0x11,0x0d,0x11,0x05,0x17,0x13,0x03,0x0a,0x05,0x00,0x2f,0x33,0x3f,0x33,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x71,0x2b,0x5d,0x71,0x11,0x33,0x33,0x10,0xed, +0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x01,0x2f,0x5d,0xed,0x33,0x2f,0x33,0x2f,0x11,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x5d,0x71,0x71,0x11,0x33,0x33,0x2f,0x5d,0x2f,0x10,0xed,0x10,0xed,0x10,0xed,0x11,0x12,0x17,0x39,0x11,0x12,0x17,0x39,0x11,0x12,0x17,0x39,0x11,0x12,0x17,0x39,0x31,0x30,0x5d,0x5d,0x2b,0x01,0x03,0x21,0x15, +0x21,0x03,0x23,0x13,0x21,0x03,0x23,0x13,0x23,0x35,0x33,0x13,0x23,0x35,0x21,0x13,0x33,0x03,0x21,0x13,0x33,0x03,0x33,0x15,0x21,0x03,0x21,0x13,0x03,0xa2,0x43,0x01,0x04,0xfe,0xe5,0x58,0x6e,0x56,0xfe,0x95,0x54,0x6e,0x54,0xc9,0xe1,0x43,0xf1,0x01,0x07,0x59,0x6e,0x58,0x01,0x6b,0x58,0x6e,0x58,0xd3,0xfd,0x40,0x45,0x01,0x6a,0x43, +0x03,0x41,0xfe,0xc3,0x6c,0xfe,0x68,0x01,0x98,0xfe,0x68,0x01,0x98,0x6c,0x01,0x3d,0x6c,0x01,0x98,0xfe,0x68,0x01,0x98,0xfe,0x68,0x6c,0xfe,0xc3,0x01,0x3d,0x00,0x00,0x00,0x03,0x00,0x42,0xff,0x73,0x04,0x7e,0x05,0xc4,0x00,0x39,0x00,0x44,0x00,0x4f,0x01,0x19,0x40,0xc7,0x44,0x3d,0x54,0x3d,0x02,0x65,0x4e,0x01,0x6e,0x47,0x01,0x65, +0x3c,0x01,0x6a,0x2f,0x01,0x75,0x2a,0x85,0x2a,0x02,0x76,0x29,0x86,0x29,0x02,0x76,0x22,0x86,0x22,0x02,0x65,0x0e,0x01,0x79,0x0a,0x89,0x0a,0x02,0x79,0x09,0x89,0x09,0x02,0x79,0x03,0x89,0x03,0x02,0x7a,0x1f,0x8a,0x1f,0x02,0x2c,0x6f,0x2d,0x2d,0x45,0x4b,0x33,0x27,0x06,0x3f,0x24,0x11,0x07,0x07,0x1f,0x75,0x00,0x85,0x00,0x02,0x00, +0x6f,0x00,0x45,0x10,0x45,0x20,0x45,0x60,0x45,0x70,0x45,0x05,0x10,0x45,0x20,0x45,0x30,0x45,0x70,0x45,0x90,0x45,0xa0,0x45,0xb0,0x45,0x07,0x45,0x45,0x51,0x0c,0x6f,0x0b,0x40,0x12,0x20,0x48,0x8e,0x0b,0x01,0x0b,0x0b,0x3a,0x6f,0x00,0x1f,0x40,0x1f,0x02,0x00,0x1f,0x10,0x1f,0xf0,0x1f,0x03,0x1f,0x32,0x40,0x73,0x24,0x4a,0x12,0x73, +0x33,0x3f,0x3f,0x24,0x2d,0x2d,0x27,0x24,0x25,0x40,0x20,0x27,0x48,0x25,0x40,0x12,0x17,0x48,0x25,0x25,0x24,0x06,0x4b,0x11,0x73,0x08,0x00,0x0c,0x10,0x0c,0x40,0x0c,0x50,0x0c,0x60,0x0c,0x05,0x40,0x0c,0x50,0x0c,0xa0,0x0c,0xb0,0x0c,0xf0,0x0c,0x05,0x0c,0x0c,0x08,0x90,0x07,0x01,0x07,0x07,0x05,0x08,0x18,0x00,0x3f,0x33,0x33,0x2f, +0x5d,0x11,0x33,0x2f,0x5d,0x71,0x10,0xed,0x32,0x3f,0x33,0x2f,0x2b,0x2b,0x11,0x33,0x33,0x2f,0x11,0x39,0x2f,0x33,0xed,0x32,0x10,0xed,0x32,0x01,0x2f,0x5d,0x71,0xed,0x33,0x2f,0x5d,0x2b,0xed,0x11,0x33,0x2f,0x5d,0x71,0xed,0x5d,0x12,0x39,0x2f,0x33,0x33,0x33,0xcd,0x32,0x32,0x32,0x11,0x33,0x2f,0xed,0x5d,0x31,0x30,0x00,0x5d,0x5d, +0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x01,0x14,0x0e,0x02,0x07,0x15,0x23,0x35,0x2e,0x01,0x27,0x37,0x1e,0x03,0x17,0x11,0x26,0x27,0x26,0x27,0x26,0x23,0x2e,0x05,0x35,0x34,0x3e,0x02,0x37,0x35,0x33,0x15,0x1e,0x03,0x17,0x07,0x2e,0x03,0x27,0x11,0x1e,0x05,0x01,0x14,0x1e,0x02,0x17,0x11,0x0e,0x03,0x01,0x34,0x2e, +0x02,0x27,0x11,0x3e,0x03,0x04,0x7e,0x38,0x72,0xaf,0x77,0x80,0xd7,0xf3,0x22,0xaa,0x0b,0x2d,0x4d,0x70,0x4d,0x08,0x07,0x04,0x06,0x03,0x02,0x31,0x62,0x58,0x4c,0x38,0x1f,0x40,0x72,0x9d,0x5d,0x80,0x66,0x91,0x66,0x40,0x14,0xae,0x0a,0x27,0x3f,0x58,0x3b,0x3a,0x72,0x67,0x58,0x41,0x24,0xfc,0xb0,0x28,0x45,0x5d,0x36,0x47,0x62,0x3c, +0x1b,0x02,0xa4,0x30,0x50,0x6a,0x3a,0x41,0x6b,0x4d,0x2b,0x01,0x7c,0x4b,0x80,0x5f,0x39,0x05,0xa1,0xa1,0x07,0xb9,0xa7,0x25,0x36,0x5b,0x44,0x29,0x04,0x01,0xe9,0x02,0x02,0x01,0x02,0x01,0x0c,0x1d,0x27,0x37,0x49,0x61,0x3f,0x52,0x77,0x4f,0x28,0x03,0x82,0x82,0x04,0x2c,0x50,0x75,0x4c,0x21,0x30,0x4f,0x39,0x21,0x04,0xfe,0x56,0x0e, +0x1f,0x2b,0x3a,0x51,0x6c,0x02,0x36,0x36,0x47,0x2f,0x1e,0x0e,0x01,0x9d,0x03,0x21,0x35,0x45,0xfd,0x5e,0x3f,0x51,0x34,0x21,0x0f,0xfe,0x29,0x04,0x1e,0x38,0x52,0x00,0x00,0x05,0x00,0x00,0xff,0xf4,0x04,0xce,0x05,0x51,0x00,0x03,0x00,0x17,0x00,0x2b,0x00,0x3f,0x00,0x53,0x00,0xc1,0xb9,0x00,0x3e,0xff,0xd8,0x40,0x0e,0x09,0x0e,0x48, +0x38,0x28,0x09,0x0c,0x48,0x34,0x28,0x09,0x0c,0x48,0x2e,0xb8,0xff,0xd8,0xb3,0x09,0x0e,0x48,0x16,0xb8,0xff,0xd8,0x40,0x0e,0x09,0x0e,0x48,0x10,0x28,0x09,0x0c,0x48,0x0c,0x28,0x09,0x0c,0x48,0x06,0xb8,0xff,0xd8,0x40,0x16,0x09,0x0e,0x48,0x79,0x02,0x89,0x02,0x02,0x02,0x03,0x56,0x00,0x76,0x00,0x86,0x00,0x03,0x00,0x01,0x03,0x10, +0x01,0xba,0xff,0xf0,0x00,0x03,0xff,0xc0,0x40,0x3a,0x0a,0x0e,0x48,0x1f,0x01,0x2f,0x01,0x3f,0x01,0x03,0x03,0x01,0x03,0x01,0x13,0x31,0x4a,0xb4,0x3b,0xb5,0x31,0xb4,0x70,0x40,0x80,0x40,0x02,0x40,0x40,0x13,0x55,0x18,0xb4,0x09,0xb5,0x22,0xb4,0x13,0x45,0xb6,0x2c,0xb7,0x4f,0xb6,0x36,0x19,0x27,0xb6,0x0e,0xb7,0x1d,0xb6,0x04,0x07, +0x02,0x06,0x00,0x18,0x00,0x3f,0x3f,0x3f,0xed,0xf4,0xed,0x3f,0xed,0xf4,0xed,0x01,0x2f,0xed,0xf4,0xed,0x11,0x12,0x39,0x2f,0x5d,0xfd,0xf4,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x2b,0x38,0x38,0x11,0x33,0x5d,0x11,0x33,0x5d,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x33,0x23,0x01,0x33,0x25,0x32,0x1e,0x02,0x15, +0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x13,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x13,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0xdd,0x91,0x03,0xa4,0x93, +0xfc,0xa0,0x3a,0x67,0x4d,0x2d,0x2d,0x4e,0x68,0x3c,0x3c,0x69,0x4e,0x2c,0x2d,0x4e,0x6a,0xc6,0x12,0x23,0x33,0x21,0x23,0x36,0x24,0x12,0x13,0x24,0x35,0x22,0x20,0x33,0x24,0x13,0x02,0x08,0x3a,0x67,0x4d,0x2d,0x2d,0x4e,0x68,0x3c,0x3c,0x69,0x4e,0x2c,0x2d,0x4e,0x6a,0xc6,0x12,0x23,0x33,0x21,0x23,0x36,0x24,0x12,0x13,0x24,0x35,0x22, +0x20,0x33,0x24,0x13,0x05,0x49,0x08,0x1f,0x4d,0x81,0x63,0x60,0x82,0x50,0x23,0x23,0x4f,0x83,0x60,0x63,0x81,0x4d,0x1f,0xfe,0xb0,0x42,0x58,0x35,0x15,0x16,0x35,0x57,0x42,0x40,0x57,0x36,0x17,0x17,0x36,0x57,0xfe,0xd8,0x1f,0x4d,0x81,0x63,0x60,0x82,0x50,0x23,0x23,0x4f,0x83,0x60,0x63,0x81,0x4d,0x1f,0xfe,0xb0,0x42,0x58,0x35,0x15, +0x16,0x35,0x57,0x42,0x40,0x57,0x36,0x17,0x17,0x36,0x57,0x00,0x00,0x03,0x00,0x2b,0xff,0xec,0x04,0xa1,0x05,0x4d,0x00,0x3d,0x00,0x4f,0x00,0x5f,0x00,0xf4,0x40,0x18,0x73,0x4e,0x83,0x4e,0x02,0x79,0x51,0x89,0x51,0x02,0x65,0x58,0x75,0x58,0x85,0x58,0x03,0x69,0x53,0x01,0x39,0x25,0x01,0x20,0xb8,0xff,0xe8,0xb3,0x09,0x0e,0x48,0x1c, +0xb8,0xff,0xe8,0xb3,0x09,0x0c,0x48,0x2e,0xb8,0xff,0xf0,0x40,0x3d,0x09,0x0c,0x48,0x25,0x12,0x01,0x06,0x12,0x16,0x12,0x02,0x48,0x49,0x19,0x23,0x49,0x3e,0x30,0x3e,0x01,0x30,0x3b,0x01,0x3b,0x3b,0x31,0x49,0x30,0x6b,0x50,0x01,0x0c,0x14,0x1c,0x14,0x6c,0x14,0x03,0x28,0x4b,0x53,0x14,0x04,0x3e,0x2d,0x50,0x34,0x05,0x04,0x19,0x70, +0x3e,0x80,0x3e,0x90,0x3e,0x03,0x3e,0x3e,0x30,0x19,0xb8,0xff,0xc0,0x40,0x3f,0x10,0x13,0x48,0x3f,0x30,0x01,0x19,0x30,0x19,0x30,0x61,0x56,0x48,0x0f,0x40,0x0b,0x17,0x48,0x0f,0x60,0x2d,0x70,0x2d,0x80,0x2d,0x03,0x65,0x50,0x01,0x29,0x50,0x01,0x05,0x50,0x34,0x2d,0x04,0x0a,0x30,0x45,0x4b,0x55,0x4b,0x65,0x4b,0x03,0x4b,0x14,0x30, +0x28,0x53,0x05,0x5b,0x43,0x51,0x1e,0x03,0x37,0x5b,0x51,0x00,0x0a,0x16,0x00,0x3f,0x33,0xed,0x32,0x3f,0xed,0x12,0x17,0x39,0x5d,0x2f,0x12,0x17,0x39,0x5d,0x5d,0x5d,0x01,0x2f,0x2b,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x2b,0x12,0x39,0x2f,0x5d,0x11,0x17,0x39,0x12,0x17,0x39,0x5d,0x5d,0x10,0xed,0x32,0x2f,0x5d,0x5d,0x10,0xed,0x10, +0xed,0x31,0x30,0x00,0x5d,0x5d,0x2b,0x2b,0x2b,0x5d,0x01,0x5d,0x00,0x5d,0x01,0x5d,0x00,0x5d,0x05,0x22,0x2e,0x02,0x27,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x37,0x2e,0x03,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x1e,0x03,0x17,0x3e,0x01,0x37,0x17,0x0e,0x01,0x07,0x1e,0x01,0x33,0x32,0x36, +0x37,0x15,0x0e,0x01,0x01,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x16,0x17,0x3e,0x03,0x03,0x2e,0x01,0x27,0x0e,0x01,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x04,0x30,0x29,0x4c,0x43,0x3a,0x16,0x1c,0x47,0x56,0x67,0x3b,0x6d,0x9e,0x66,0x31,0x2d,0x4e,0x6b,0x3e,0x0f,0x1b,0x15,0x0c,0x2b,0x57,0x84,0x59,0x45,0x76,0x56,0x30, +0x44,0x72,0x93,0x4e,0x1f,0x3e,0x44,0x4a,0x2a,0x2a,0x3f,0x14,0x91,0x1a,0x57,0x31,0x2b,0x61,0x28,0x1a,0x30,0x15,0x18,0x38,0xfe,0xbb,0x18,0x2d,0x40,0x27,0x2c,0x49,0x35,0x1e,0x26,0x17,0x40,0x71,0x55,0x31,0x4a,0x59,0xa1,0x42,0x55,0x5e,0x20,0x40,0x61,0x41,0x27,0x47,0x3c,0x31,0x0c,0x15,0x23,0x2f,0x1a,0x19,0x32,0x26,0x18,0x3a, +0x66,0x8a,0x50,0x4d,0x7e,0x67,0x51,0x20,0x1c,0x44,0x49,0x4c,0x25,0x3e,0x6d,0x51,0x2e,0x23,0x44,0x64,0x40,0x47,0x6c,0x56,0x46,0x21,0x36,0x64,0x60,0x5d,0x2e,0x57,0xc6,0x79,0x2b,0x8b,0xe5,0x5e,0x36,0x33,0x07,0x09,0x87,0x0b,0x0b,0x04,0x49,0x22,0x38,0x27,0x16,0x19,0x2e,0x43,0x2a,0x41,0x74,0x2b,0x1b,0x32,0x3a,0x47,0xfc,0xcb, +0x64,0xe1,0x74,0x2e,0x95,0x65,0x34,0x5c,0x44,0x27,0x13,0x1e,0x26,0x00,0x00,0x00,0x00,0x01,0x01,0xf6,0x03,0x4d,0x02,0xd6,0x05,0xcc,0x00,0x03,0x00,0x1c,0x40,0x0d,0x03,0x96,0x00,0x02,0x01,0x02,0x02,0x04,0x05,0x00,0x00,0x02,0x00,0x00,0x3f,0x33,0x2f,0x11,0x12,0x01,0x39,0x2f,0x5d,0xed,0x31,0x30,0x01,0x23,0x03,0x33,0x02,0xac, +0x8d,0x29,0xe0,0x03,0x4d,0x02,0x7f,0x00,0x00,0x01,0x01,0x56,0xfe,0x57,0x03,0x7b,0x05,0xcc,0x00,0x15,0x00,0x28,0x40,0x16,0x10,0x06,0xf0,0x11,0x0f,0x05,0x1f,0x05,0x02,0x05,0x05,0x17,0x00,0xf0,0x00,0x0b,0x01,0x0b,0x10,0x00,0x06,0x1b,0x00,0x3f,0x3f,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x33,0xed,0x32,0x31,0x30,0x01,0x14, +0x1e,0x02,0x17,0x23,0x2e,0x03,0x35,0x34,0x3e,0x02,0x37,0x33,0x0e,0x03,0x02,0x11,0x29,0x58,0x89,0x60,0xbe,0x5c,0x87,0x59,0x2b,0x2b,0x59,0x87,0x5c,0xbe,0x60,0x89,0x58,0x29,0x02,0x12,0x8a,0xf4,0xe6,0xe1,0x76,0x71,0xdb,0xe6,0xfb,0x90,0x90,0xf9,0xe5,0xd9,0x71,0x76,0xe1,0xe6,0xf4,0x00,0x00,0x01,0x01,0x50,0xfe,0x57,0x03,0x75, +0x05,0xcc,0x00,0x15,0x00,0x24,0x40,0x13,0x00,0xf0,0x0b,0x0b,0x17,0x11,0x05,0xf0,0x10,0x00,0x06,0x10,0x06,0x02,0x06,0x10,0x00,0x05,0x1b,0x00,0x3f,0x3f,0x01,0x2f,0x5d,0x33,0xed,0x32,0x12,0x39,0x2f,0xed,0x31,0x30,0x01,0x14,0x0e,0x02,0x07,0x23,0x3e,0x03,0x35,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x03,0x75,0x2a,0x58,0x87,0x5c, +0xc0,0x60,0x8a,0x58,0x2a,0x2a,0x58,0x8a,0x60,0xc0,0x5c,0x87,0x58,0x2a,0x02,0x14,0x90,0xfb,0xe6,0xdb,0x71,0x76,0xe1,0xe6,0xf4,0x8a,0x89,0xf4,0xe6,0xe1,0x76,0x71,0xd9,0xe5,0xf9,0x00,0x00,0x01,0x00,0xf8,0x02,0xfc,0x03,0xd4,0x05,0xcb,0x00,0x0e,0x00,0xaf,0x40,0x17,0x5b,0x06,0x6b,0x06,0x02,0x00,0x03,0x50,0x03,0x60,0x03,0x03, +0x0f,0x09,0x5f,0x09,0x6f,0x09,0x03,0x0b,0x03,0x07,0x08,0xb8,0xff,0xc0,0x40,0x4c,0x0b,0x11,0x48,0x08,0x08,0x0a,0x0d,0x05,0x04,0x40,0x0b,0x11,0x48,0x04,0x04,0x02,0x0e,0x0e,0x0a,0x0d,0x0e,0x70,0x0a,0x80,0x0a,0x02,0x0a,0x06,0x0e,0x00,0x0d,0x10,0x0d,0x02,0x0d,0x0d,0x0f,0x10,0x02,0x0a,0x0a,0x01,0x0b,0x00,0x0c,0x75,0x0c,0x85, +0x0c,0x02,0x03,0x09,0x04,0x08,0x7f,0x0b,0x8f,0x0b,0x02,0x0b,0x08,0x06,0x09,0x0c,0x0b,0x05,0x0d,0x05,0x70,0x07,0x80,0x07,0x90,0x07,0x03,0x07,0xb8,0xff,0xc0,0xb6,0x09,0x0c,0x48,0x07,0x07,0x0d,0x00,0x00,0x3f,0x33,0x2f,0x2b,0x5d,0x33,0x12,0x17,0x39,0x2f,0x5d,0x11,0x33,0x11,0x33,0x5d,0x11,0x33,0x11,0x33,0x33,0x11,0x33,0x11, +0x12,0x01,0x39,0x2f,0x5d,0xcd,0x39,0xc4,0x5d,0x2b,0x01,0x18,0x10,0x4d,0xe4,0x39,0x2f,0x2b,0x33,0x11,0x12,0x39,0x2f,0x2b,0x33,0x31,0x30,0x5f,0x5e,0x5d,0x5d,0x00,0x5d,0x01,0x25,0x17,0x05,0x17,0x07,0x0b,0x01,0x27,0x37,0x25,0x37,0x05,0x03,0x33,0x02,0x9f,0x01,0x08,0x2d,0xfe,0xe6,0xb9,0x77,0x96,0x9c,0x77,0xbd,0xfe,0xe8,0x2d, +0x01,0x0b,0x0c,0x88,0x04,0xa4,0x67,0x84,0x49,0xfa,0x48,0x01,0x02,0xff,0x00,0x48,0xf8,0x49,0x86,0x6b,0x01,0x29,0x00,0x00,0x00,0x01,0x00,0x74,0x00,0xb4,0x04,0x57,0x04,0x9e,0x00,0x0b,0x00,0x49,0x40,0x25,0x0b,0x0e,0x01,0x04,0x02,0x0e,0x04,0x09,0x01,0xaa,0x40,0x06,0x00,0x02,0x01,0x0a,0x03,0x02,0x02,0x0c,0x0d,0x02,0x0e,0x04, +0x07,0x05,0x0e,0x30,0x07,0x01,0x07,0x00,0x04,0xad,0x09,0x05,0xb3,0x00,0x3f,0x33,0xed,0x32,0xc6,0x5d,0x2b,0x00,0x18,0x10,0x4d,0xe6,0x11,0x12,0x01,0x39,0x2f,0x5f,0x5e,0x5d,0x33,0x1a,0xed,0x32,0xc6,0x2b,0x01,0x18,0x10,0x4d,0xe6,0x31,0x30,0x01,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x33,0x11,0x21,0x15,0x02,0xaf,0x93,0xfe,0x58, +0x01,0xa8,0x93,0x01,0xa8,0x02,0x60,0xfe,0x54,0x01,0xac,0x92,0x01,0xac,0xfe,0x54,0x92,0x00,0x00,0x00,0x00,0x01,0x01,0x03,0xfe,0x95,0x02,0xb5,0x01,0x2b,0x00,0x03,0x00,0x39,0x40,0x27,0x09,0x00,0x19,0x00,0x02,0x00,0x10,0x0e,0x11,0x48,0x09,0x02,0x19,0x02,0x02,0x02,0x10,0x0e,0x11,0x48,0x01,0x99,0x02,0x97,0x03,0x9a,0x2f,0x00, +0x6f,0x00,0x7f,0x00,0x03,0x00,0x00,0x9c,0x01,0x9b,0x04,0x00,0x10,0xf6,0xed,0x01,0x2f,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x2b,0x5d,0x01,0x13,0x21,0x01,0x01,0x03,0xa9,0x01,0x09,0xfe,0xc9,0xfe,0x95,0x02,0x96,0xfd,0x6a,0x00,0x01,0x01,0x4e,0x01,0xd0,0x03,0x7e,0x02,0x70,0x00,0x03,0x00,0x1d,0x40,0x0f,0x03,0x03,0x05,0x00, +0x00,0x10,0x00,0x02,0x00,0x00,0xba,0x2f,0x01,0x01,0x01,0x00,0x2f,0x5d,0xed,0x01,0x2f,0x5d,0x12,0x39,0x2f,0x31,0x30,0x01,0x35,0x21,0x15,0x01,0x4e,0x02,0x30,0x01,0xd0,0xa0,0xa0,0x00,0x00,0x01,0x01,0xf0,0x00,0x00,0x02,0xdb,0x01,0x2b,0x00,0x03,0x00,0x1a,0x40,0x0c,0x03,0x96,0x00,0x00,0x01,0x00,0x00,0x04,0x05,0x01,0x9b,0x00, +0x00,0x2f,0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0xed,0x31,0x30,0x21,0x11,0x33,0x11,0x01,0xf0,0xeb,0x01,0x2b,0xfe,0xd5,0x00,0x00,0x01,0x00,0x72,0xff,0xec,0x04,0x59,0x05,0xcc,0x00,0x03,0x00,0x3d,0x40,0x1c,0x8a,0x01,0x01,0x39,0x01,0x69,0x01,0x79,0x01,0x03,0x01,0x02,0x10,0x02,0x02,0x05,0x85,0x03,0x01,0x36,0x03,0x66,0x03,0x76, +0x03,0x03,0x03,0x00,0xb8,0xff,0xf0,0xb7,0x00,0x00,0x01,0x00,0x03,0x19,0x01,0x00,0x00,0x3f,0x3f,0x01,0x2f,0x5d,0x38,0x32,0x5d,0x5d,0x12,0x39,0x2f,0x38,0x33,0x5d,0x5d,0x31,0x30,0x17,0x01,0x33,0x01,0x72,0x03,0x35,0xb2,0xfc,0xcf,0x14,0x05,0xe0,0xfa,0x20,0x00,0x00,0x00,0x03,0x00,0x7c,0xff,0xec,0x04,0x4f,0x05,0x5a,0x00,0x13, +0x00,0x27,0x00,0x2b,0x00,0x79,0x40,0x52,0x36,0x20,0x01,0x46,0x11,0x56,0x11,0x02,0x46,0x0d,0x56,0x0d,0x02,0x49,0x07,0x59,0x07,0x02,0x49,0x03,0x59,0x03,0x02,0x10,0x2a,0x20,0x2a,0x02,0x40,0x2a,0x50,0x2a,0x02,0x00,0x29,0x01,0x2a,0x29,0x2a,0x29,0x1e,0x00,0x6e,0x40,0x14,0x50,0x14,0x02,0x00,0x14,0x01,0x14,0x14,0x2d,0x1e,0x6f, +0x00,0x0a,0x10,0x0a,0x02,0x0a,0x4f,0x28,0x01,0x4f,0x28,0x5f,0x28,0x02,0x28,0x29,0x29,0x23,0x19,0x73,0x0f,0x07,0x23,0x73,0x05,0x19,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xcd,0x5d,0x71,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x71,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x01, +0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x1e,0x01,0x12,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x25,0x35,0x33,0x15,0x04,0x4f,0x4d,0x85,0xb4,0x66,0x67,0xb2,0x83,0x4b,0x4b,0x84,0xb4,0x6a,0x65,0xb1,0x84,0x4c,0xb7,0x28,0x4e,0x71,0x48,0x4c,0x74, +0x4f,0x28,0x29,0x4f,0x72,0x49,0x47,0x72,0x4f,0x2b,0xfe,0x58,0xeb,0x02,0xa3,0xc3,0xfe,0xf7,0xa4,0x47,0x47,0xa3,0x01,0x0a,0xc3,0xcc,0x01,0x0c,0x9f,0x40,0x40,0x9f,0xfe,0xf4,0xcc,0x9f,0xd4,0x7e,0x34,0x35,0x7e,0xd3,0x9f,0x9a,0xd2,0x80,0x38,0x38,0x80,0xd2,0x22,0xf9,0xf9,0x00,0x00,0x00,0x00,0x01,0x00,0x94,0x00,0x00,0x04,0x6a, +0x05,0x45,0x00,0x12,0x00,0x59,0x40,0x39,0x00,0x11,0x01,0x11,0x11,0x10,0x6f,0x02,0x08,0x08,0x1f,0x01,0x01,0x0f,0x01,0x3f,0x01,0x4f,0x01,0x5f,0x01,0x8f,0x01,0x9f,0x01,0xaf,0x01,0x07,0x01,0x01,0x0e,0x10,0x02,0x01,0x10,0x02,0x70,0x02,0x80,0x02,0x03,0x02,0x02,0x13,0x14,0x08,0x73,0x09,0x09,0x03,0x0e,0x06,0x10,0x01,0x73,0x00, +0x18,0x00,0x3f,0xed,0x32,0x3f,0x33,0x33,0x2f,0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0x71,0x33,0x33,0x2f,0x5d,0x71,0x33,0x2f,0x10,0xed,0x32,0x2f,0x5d,0x31,0x30,0x33,0x35,0x21,0x11,0x0e,0x03,0x23,0x35,0x32,0x3e,0x02,0x37,0x33,0x11,0x21,0x15,0x9d,0x01,0xb7,0x13,0x60,0x7d,0x8e,0x42,0x4a,0x8f,0x7c,0x60,0x1a,0xa6,0x01,0x61,0x91, +0x03,0xfd,0x28,0x47,0x34,0x1f,0x94,0x22,0x3d,0x54,0x32,0xfb,0x4c,0x91,0x00,0x00,0x00,0x01,0x00,0x90,0x00,0x00,0x04,0x3c,0x05,0x5a,0x00,0x26,0x00,0x87,0x40,0x5c,0x75,0x06,0x85,0x06,0x02,0x39,0x20,0x01,0x74,0x1b,0x84,0x1b,0x02,0x76,0x1a,0x86,0x1a,0x02,0x77,0x15,0x87,0x15,0x02,0x77,0x16,0x87,0x16,0x02,0x69,0x0a,0x01,0x6b, +0x10,0x01,0x59,0x10,0x01,0x05,0x1a,0x01,0x26,0x26,0x1d,0x6e,0x1f,0x08,0x3f,0x08,0x02,0x6f,0x08,0xbf,0x08,0x02,0x08,0x08,0x00,0x28,0x12,0x6e,0x13,0x13,0x00,0x60,0x24,0x70,0x24,0x80,0x24,0x03,0x24,0x24,0xcf,0x00,0x01,0x00,0x00,0x10,0x00,0x02,0x00,0x12,0x12,0x0d,0x73,0x18,0x07,0x01,0x24,0x73,0x00,0x18,0x00,0x3f,0xed,0x32, +0x3f,0xed,0x33,0x2f,0x01,0x2f,0x5d,0x5d,0x33,0x2f,0x5d,0x11,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f,0x5d,0x71,0xed,0x32,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x33,0x35,0x3e,0x05,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x04,0x07,0x21,0x15, +0x90,0x2c,0x90,0xa3,0xa5,0x85,0x54,0x27,0x47,0x61,0x3b,0x36,0x5d,0x46,0x2c,0x07,0xb8,0x09,0x40,0x6f,0xa2,0x6a,0x69,0xa7,0x75,0x3e,0x56,0x87,0xa4,0x9c,0x80,0x20,0x02,0xd3,0x75,0x61,0xa4,0x91,0x84,0x81,0x85,0x4a,0x3c,0x57,0x39,0x1b,0x1e,0x3c,0x59,0x3b,0x11,0x4c,0x86,0x65,0x3a,0x30,0x5d,0x8a,0x59,0x5e,0xa1,0x90,0x82,0x80, +0x81,0x46,0x92,0x00,0x00,0x01,0x00,0x80,0xff,0xec,0x04,0x4b,0x05,0x5a,0x00,0x3b,0x00,0xe6,0x40,0x63,0x75,0x39,0x85,0x39,0x02,0x63,0x39,0x01,0x40,0x39,0x50,0x39,0x02,0x78,0x34,0x88,0x34,0x02,0x6c,0x34,0x01,0x4b,0x34,0x5b,0x34,0x02,0x74,0x2f,0x84,0x2f,0x02,0x06,0x2e,0x76,0x2e,0x86,0x2e,0x03,0x77,0x29,0x87,0x29,0x02,0x6c, +0x25,0x01,0x5a,0x25,0x01,0x63,0x12,0x01,0x64,0x0d,0x01,0x55,0x0d,0x01,0x79,0x08,0x89,0x08,0x02,0x79,0x07,0x89,0x07,0x02,0x79,0x03,0x89,0x03,0x02,0x7b,0x02,0x8b,0x02,0x02,0x36,0x1a,0x31,0x6e,0x3f,0x20,0x5f,0x20,0x02,0x20,0x20,0x00,0x6e,0x13,0x40,0x13,0x01,0x00,0x13,0x01,0x13,0xb8,0xff,0xc0,0x40,0x3c,0x15,0x18,0x48,0x1a, +0x13,0x1a,0x13,0x0a,0x3d,0x26,0x6e,0x27,0x27,0x0b,0x6e,0xcf,0x0a,0xdf,0x0a,0xef,0x0a,0x03,0x00,0x0a,0x10,0x0a,0x02,0x0a,0x36,0x19,0x73,0x1a,0x1a,0x10,0x2c,0x26,0x26,0x23,0x73,0x2c,0x07,0x10,0x73,0x05,0x40,0x0b,0x90,0x0b,0x02,0x40,0x0b,0x90,0x0b,0xf0,0x0b,0x03,0x0b,0x0b,0x05,0x19,0x00,0x3f,0x33,0x2f,0x5d,0x71,0x10,0xed, +0x3f,0xed,0x33,0x2f,0x11,0x12,0x39,0x2f,0xed,0x39,0x01,0x2f,0x5d,0x5d,0xed,0x33,0x2f,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x2b,0x5d,0x71,0x10,0xed,0x33,0x2f,0x71,0xed,0x11,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02, +0x27,0x37,0x1e,0x03,0x33,0x32,0x36,0x35,0x34,0x2e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x15,0x1e,0x03,0x04,0x4b,0x3f,0x79,0xb2,0x74,0x82,0xb4,0x74,0x3a,0x09,0xba,0x08,0x2b,0x4a,0x6d,0x49,0x88,0x9b,0x45,0x67,0x79,0x33,0x66, +0x62,0x33,0x6e,0x5b,0x3b,0x85,0x83,0x77,0x93,0x0c,0xb5,0x0b,0x50,0x7b,0x9e,0x59,0x77,0xa9,0x6c,0x33,0x25,0x49,0x6f,0x4a,0x52,0x7d,0x54,0x2b,0x01,0x72,0x5b,0x91,0x64,0x36,0x41,0x6b,0x89,0x49,0x11,0x38,0x5c,0x42,0x24,0x7e,0x79,0x44,0x5a,0x35,0x16,0x9c,0x19,0x37,0x59,0x3f,0x6a,0x77,0x7a,0x6f,0x0e,0x5d,0x8a,0x5b,0x2d,0x38, +0x60,0x81,0x49,0x37,0x67,0x56,0x40,0x0f,0x04,0x09,0x3c,0x57,0x6a,0x00,0x00,0x00,0x00,0x02,0x00,0x67,0x00,0x00,0x04,0x65,0x05,0x45,0x00,0x0a,0x00,0x0d,0x00,0x55,0x40,0x35,0x69,0x06,0x79,0x06,0x89,0x06,0x03,0x7f,0x09,0x01,0x09,0x09,0x08,0x01,0x6f,0x0d,0x06,0x90,0x02,0xa0,0x02,0x02,0x02,0x02,0x0f,0x0c,0x6f,0x10,0x04,0x01, +0x04,0x00,0x04,0x73,0x08,0x05,0x0f,0x0c,0x1f,0x0c,0x2f,0x0c,0x6f,0x0c,0x04,0x0c,0x0c,0x01,0x0b,0x06,0x06,0x01,0x18,0x00,0x3f,0x3f,0x33,0x12,0x39,0x2f,0x5d,0x33,0x33,0xed,0x32,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x33,0x33,0xed,0x32,0x32,0x2f,0x5d,0x31,0x30,0x5d,0x01,0x11,0x23,0x11,0x21,0x35,0x01,0x33,0x11,0x33,0x15, +0x09,0x01,0x21,0x03,0xa9,0xb4,0xfd,0x72,0x02,0x7b,0xc7,0xbc,0xfe,0x90,0xfe,0x0c,0x01,0xf4,0x01,0x3f,0xfe,0xc1,0x01,0x3f,0x8c,0x03,0x7a,0xfc,0x88,0x8e,0x03,0x43,0xfd,0x4b,0x00,0x00,0x00,0x01,0x00,0x80,0xff,0xec,0x04,0x4b,0x05,0x45,0x00,0x2c,0x00,0x8e,0x40,0x5e,0x69,0x08,0x79,0x08,0x89,0x08,0x03,0x69,0x07,0x79,0x07,0x89, +0x07,0x03,0x4a,0x17,0x5a,0x17,0x02,0x45,0x13,0x55,0x13,0x02,0x22,0x40,0x0d,0x11,0x48,0x22,0x22,0x00,0x6e,0x15,0x25,0x24,0x21,0x1f,0x6f,0x20,0x20,0x0a,0x40,0x15,0x01,0x00,0x15,0xc0,0x15,0xd0,0x15,0x03,0x15,0x15,0x2e,0x0b,0x6e,0xf0,0x0a,0x01,0xcf,0x0a,0xdf,0x0a,0x02,0x00,0x0a,0x10,0x0a,0x02,0x0a,0x25,0x73,0x20,0x20,0x1a, +0x73,0x6f,0x28,0x01,0x28,0x28,0x10,0x24,0x73,0x21,0x06,0x10,0x73,0x05,0x0b,0x0b,0x05,0x19,0x00,0x3f,0x33,0x2f,0x10,0xed,0x3f,0xed,0x12,0x39,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x01,0x2f,0x5d,0x5d,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0x12,0x39,0x2f,0xed,0x33,0x32,0x32,0x10,0xed,0x32,0x2f,0x2b,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d, +0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x07,0x23,0x13,0x21,0x15,0x21,0x03,0x3e,0x01,0x33,0x32,0x1e,0x02,0x04,0x4b,0x40,0x7e,0xbb,0x7b,0x6f,0xa5,0x72,0x43,0x0e,0xb6,0x0b,0x28,0x45,0x65,0x48,0x46,0x72,0x51,0x2c,0x2a,0x4e,0x71,0x48,0x2d,0x4c, +0x41,0x35,0x17,0xb0,0x2f,0x03,0x21,0xfd,0x85,0x1d,0x30,0x90,0x63,0x69,0xa8,0x76,0x40,0x01,0xbc,0x64,0xab,0x7b,0x46,0x34,0x5b,0x7a,0x46,0x15,0x28,0x4b,0x3b,0x23,0x2b,0x50,0x75,0x49,0x3c,0x67,0x4c,0x2b,0x10,0x1c,0x25,0x14,0x02,0xd8,0x91,0xfe,0x57,0x25,0x35,0x40,0x71,0x9c,0x00,0x00,0x00,0x02,0x00,0x97,0xff,0xec,0x04,0x48, +0x05,0x5a,0x00,0x24,0x00,0x38,0x00,0xab,0x40,0x7d,0x7a,0x03,0x8a,0x03,0x02,0x7a,0x02,0x8a,0x02,0x02,0x68,0x03,0x78,0x03,0x88,0x03,0x03,0x67,0x23,0x77,0x23,0x87,0x23,0x03,0x67,0x22,0x77,0x22,0x87,0x22,0x03,0x45,0x37,0x55,0x37,0x02,0x43,0x31,0x53,0x31,0x02,0x4a,0x2d,0x5a,0x2d,0x02,0x4b,0x27,0x5b,0x27,0x02,0x1c,0x1b,0x2c, +0x1b,0x3c,0x1b,0x03,0x15,0x6e,0x14,0x14,0x00,0x6e,0xaf,0x25,0x01,0x40,0x25,0x01,0x00,0x25,0xc0,0x25,0xd0,0x25,0x03,0x25,0x25,0x3a,0x1d,0x2f,0x6e,0x90,0x0a,0xa0,0x0a,0x02,0x00,0x0a,0x10,0x0a,0xe0,0x0a,0xf0,0x0a,0x04,0x0a,0x2a,0x73,0x6f,0x20,0x01,0x10,0x20,0x20,0x20,0x02,0x20,0x20,0x34,0x18,0x73,0x0f,0x8f,0x15,0x01,0x15, +0x15,0x0f,0x07,0x34,0x73,0x05,0x19,0x00,0x3f,0xed,0x3f,0x33,0x2f,0x5d,0x10,0xed,0x12,0x39,0x2f,0x5d,0x5d,0xed,0x01,0x2f,0x5d,0x71,0xed,0x32,0x12,0x39,0x2f,0x5d,0x71,0x71,0xed,0x32,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x12,0x3e,0x01, +0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x01,0x23,0x22,0x0e,0x02,0x15,0x3e,0x01,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x04,0x48,0x3b,0x73,0xaa,0x6f,0x7b,0xb8,0x7a,0x3d,0x45,0x82,0xbb,0x76,0x48,0x7e,0x67,0x4e,0x17,0xac,0x1c,0x7b,0x51,0x4a,0x78,0x54,0x2d,0x31,0xb2, +0x73,0x60,0x9d,0x6f,0x3c,0xb7,0x24,0x48,0x6a,0x46,0x31,0x64,0x51,0x33,0x28,0x4b,0x6a,0x42,0x41,0x67,0x48,0x26,0x01,0xbe,0x64,0xab,0x7d,0x46,0x5d,0xac,0xf5,0x98,0xb1,0x01,0x10,0xb8,0x5f,0x1e,0x43,0x6e,0x50,0x1f,0x5b,0x51,0x45,0x86,0xc5,0x81,0x5b,0x5f,0x3e,0x72,0xa0,0x6b,0x43,0x70,0x50,0x2d,0x21,0x41,0x62,0x41,0x48,0x81, +0x62,0x39,0x2d,0x52,0x74,0x00,0x00,0x00,0x00,0x01,0x00,0x9e,0x00,0x00,0x04,0x2d,0x05,0x45,0x00,0x0e,0x00,0x35,0x40,0x10,0x05,0x6e,0x06,0x06,0x0c,0x00,0x6f,0x0b,0x0b,0x10,0x00,0x0c,0x10,0x0c,0x02,0x0c,0xb8,0xff,0xc0,0x40,0x0b,0x14,0x18,0x48,0x0c,0x00,0x0c,0x73,0x0d,0x06,0x05,0x18,0x00,0x3f,0x3f,0xed,0x32,0x01,0x2f,0x2b, +0x5d,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x01,0x06,0x0a,0x02,0x15,0x23,0x34,0x1a,0x02,0x37,0x21,0x35,0x21,0x04,0x2d,0x60,0xab,0x82,0x4c,0xbc,0x50,0x86,0xb0,0x61,0xfd,0x1f,0x03,0x8f,0x04,0xba,0x8a,0xfe,0xda,0xfe,0xcf,0xfe,0xc6,0x9f,0x9e,0x01,0x3b,0x01,0x32,0x01,0x24,0x85,0x91,0x00,0x00,0x00,0x03,0x00,0x85, +0xff,0xec,0x04,0x46,0x05,0x5a,0x00,0x29,0x00,0x3d,0x00,0x51,0x00,0xb6,0x40,0x7e,0x75,0x28,0x85,0x28,0x02,0x76,0x0c,0x86,0x0c,0x02,0x78,0x02,0x88,0x02,0x02,0x78,0x08,0x88,0x08,0x02,0x77,0x1d,0x87,0x1d,0x02,0x79,0x22,0x89,0x22,0x02,0x78,0x12,0x88,0x12,0x02,0x6a,0x46,0x01,0x6a,0x40,0x01,0x65,0x50,0x01,0x65,0x4a,0x01,0x65, +0x3c,0x01,0x65,0x36,0x01,0x24,0x10,0x1f,0x34,0x6e,0x15,0x1f,0x6e,0x2a,0x15,0x2a,0x15,0x2a,0x0a,0x00,0x6e,0x40,0x3e,0x01,0x00,0x3e,0xc0,0x3e,0xd0,0x3e,0x03,0x3e,0x3e,0x53,0x48,0x6e,0xe0,0x0a,0xf0,0x0a,0x02,0xcf,0x0a,0xdf,0x0a,0x02,0x00,0x0a,0x10,0x0a,0x02,0x0a,0x24,0x10,0x10,0x43,0x73,0x39,0x39,0x4d,0x76,0x1a,0x86,0x1a, +0x02,0x2f,0x73,0x1a,0x07,0x79,0x05,0x89,0x05,0x02,0x4d,0x73,0x05,0x19,0x00,0x3f,0xed,0x5d,0x3f,0xed,0x5d,0x12,0x39,0x2f,0xed,0x39,0x11,0x33,0x01,0x2f,0x5d,0x5d,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x12,0x39,0x39,0x2f,0x2f,0x10,0xed,0x10,0xed,0x12,0x39,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, +0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x37,0x35,0x2e,0x03,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x15,0x1e,0x03,0x03,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x13,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02, +0x33,0x32,0x3e,0x02,0x04,0x46,0x39,0x75,0xb5,0x7d,0x7c,0xb5,0x77,0x39,0x2f,0x4f,0x65,0x36,0x3b,0x5d,0x3f,0x21,0x39,0x70,0xa6,0x6d,0x73,0xa9,0x6f,0x36,0x21,0x3f,0x5d,0x3d,0x3d,0x68,0x4d,0x2b,0xde,0x1b,0x3e,0x64,0x49,0x46,0x63,0x3f,0x1c,0x16,0x3a,0x66,0x50,0x56,0x66,0x37,0x11,0x23,0x1c,0x44,0x73,0x56,0x4f,0x6f,0x45,0x20, +0x20,0x46,0x72,0x51,0x53,0x6f,0x44,0x1d,0x01,0x7a,0x54,0x91,0x6c,0x3d,0x3d,0x6b,0x91,0x53,0x47,0x73,0x54,0x34,0x09,0x04,0x0e,0x3e,0x54,0x64,0x35,0x44,0x7d,0x60,0x39,0x3a,0x60,0x7e,0x44,0x34,0x64,0x54,0x3d,0x0c,0x04,0x0a,0x35,0x54,0x71,0x02,0x33,0x2f,0x52,0x3c,0x23,0x23,0x3c,0x52,0x2f,0x25,0x52,0x45,0x2d,0x2e,0x45,0x52, +0xfd,0xbb,0x2d,0x59,0x47,0x2c,0x2c,0x48,0x5a,0x2f,0x3b,0x65,0x4a,0x2a,0x29,0x4b,0x67,0x00,0x00,0x00,0x00,0x02,0x00,0x8d,0xff,0xec,0x04,0x3f,0x05,0x5a,0x00,0x24,0x00,0x38,0x00,0xa5,0x40,0x77,0x7a,0x08,0x8a,0x08,0x02,0x7a,0x07,0x8a,0x07,0x02,0x67,0x20,0x77,0x20,0x87,0x20,0x03,0x68,0x1a,0x78,0x1a,0x88,0x1a,0x03,0x45,0x37, +0x55,0x37,0x02,0x45,0x31,0x55,0x31,0x02,0x4a,0x2d,0x5a,0x2d,0x02,0x4b,0x27,0x5b,0x27,0x02,0x13,0x11,0x23,0x11,0x33,0x11,0x03,0x13,0x00,0x6e,0x3f,0x25,0x8f,0x25,0x9f,0x25,0xaf,0x25,0x04,0xc0,0x25,0xd0,0x25,0x02,0x25,0x25,0x1d,0x3a,0x0b,0x6e,0x0a,0x0a,0x2f,0x6e,0xe0,0x1d,0xf0,0x1d,0x02,0xcf,0x1d,0x01,0x00,0x1d,0x10,0x1d, +0x02,0x1d,0x34,0x73,0x13,0x18,0x40,0x13,0x16,0x48,0x18,0x18,0x0e,0x2a,0x73,0x22,0x07,0x0e,0x73,0x05,0x70,0x0b,0x80,0x0b,0x02,0x0b,0x0b,0x05,0x19,0x00,0x3f,0x33,0x2f,0x5d,0x10,0xed,0x3f,0xed,0x12,0x39,0x2f,0x2b,0x33,0xed,0x01,0x2f,0x5d,0x5d,0x5d,0xed,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f,0x5d,0x71,0xed,0x33,0x31,0x30,0x00, +0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x01,0x33,0x32,0x3e,0x02,0x37,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x12,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x04,0x3f,0x46,0x84,0xbd,0x77,0x51,0x82, +0x66,0x48,0x16,0xac,0x1c,0x77,0x5b,0x4a,0x78,0x55,0x31,0x01,0x15,0x49,0x5d,0x6b,0x38,0x60,0x9b,0x6c,0x3b,0x3f,0x78,0xaf,0x6f,0xec,0xf1,0xc4,0x25,0x49,0x6b,0x46,0x41,0x68,0x48,0x27,0x23,0x46,0x68,0x45,0x32,0x67,0x53,0x35,0x02,0xbf,0xb1,0xfe,0xf2,0xb7,0x5d,0x21,0x46,0x70,0x4f,0x1b,0x5b,0x55,0x44,0x84,0xc4,0x81,0x2f,0x4a, +0x33,0x1b,0x44,0x7a,0xa9,0x65,0x68,0xa9,0x78,0x42,0xfe,0xb4,0xb0,0x49,0x83,0x63,0x3b,0x2d,0x53,0x73,0x46,0x42,0x73,0x57,0x32,0x22,0x43,0x65,0x00,0x02,0x01,0xf0,0x00,0x00,0x02,0xdb,0x04,0x3a,0x00,0x03,0x00,0x07,0x00,0x24,0x40,0x12,0x06,0x05,0x03,0x96,0x00,0x00,0x01,0x00,0x00,0x09,0x08,0x04,0x9b,0x05,0x0f,0x01,0x9b,0x00, +0x00,0x2f,0xed,0x3f,0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0xed,0x33,0x32,0x31,0x30,0x21,0x11,0x33,0x11,0x03,0x11,0x33,0x11,0x01,0xf0,0xeb,0xeb,0xeb,0x01,0x2b,0xfe,0xd5,0x03,0x0f,0x01,0x2b,0xfe,0xd5,0x00,0x00,0x02,0x01,0x60,0xfe,0x95,0x03,0x12,0x04,0x3a,0x00,0x03,0x00,0x07,0x00,0x58,0x40,0x3e,0x09,0x04,0x19,0x04,0x02,0x04, +0x10,0x0e,0x11,0x48,0x09,0x06,0x19,0x06,0x02,0x06,0x10,0x0e,0x11,0x48,0x02,0x96,0x01,0x40,0x1a,0x1e,0x48,0x01,0x40,0x11,0x15,0x48,0x01,0x01,0x04,0x05,0x99,0x06,0x97,0x07,0x9a,0x00,0x04,0x10,0x04,0x80,0x04,0x90,0x04,0xa0,0x04,0x05,0x04,0x04,0x9c,0x05,0x9b,0x08,0x00,0x9b,0x01,0x0f,0x00,0x3f,0xed,0x10,0xf6,0xed,0x01,0x2f, +0x5d,0xed,0xfd,0xed,0x12,0x39,0x2f,0x2b,0x2b,0xed,0x31,0x30,0x2b,0x5d,0x2b,0x5d,0x01,0x11,0x33,0x11,0x01,0x13,0x21,0x01,0x01,0xf0,0xeb,0xfe,0x85,0xa9,0x01,0x09,0xfe,0xc9,0x03,0x0f,0x01,0x2b,0xfe,0xd5,0xfb,0x86,0x02,0x96,0xfd,0x6a,0x00,0x00,0x00,0x01,0x00,0x74,0x00,0x9a,0x04,0x57,0x04,0xaa,0x00,0x06,0x00,0x77,0xb5,0x00, +0x01,0x52,0x05,0x04,0x05,0xb8,0x01,0x0d,0x40,0x10,0x06,0x00,0x14,0x06,0x00,0x05,0x06,0x01,0x02,0x01,0x52,0x03,0x04,0x01,0x04,0x03,0xb8,0x01,0x0d,0x40,0x28,0x02,0x01,0x14,0x02,0x01,0x03,0x02,0x06,0x08,0x04,0x00,0x00,0x10,0x00,0x02,0x00,0x01,0x00,0x04,0x04,0x02,0x05,0x3f,0x06,0x6f,0x06,0x7f,0x06,0x03,0x06,0x40,0x12,0x15, +0x48,0x06,0x03,0x0f,0x02,0x01,0x02,0x00,0x2f,0x5d,0x33,0x2f,0x2b,0x5d,0x33,0x12,0x39,0x3d,0x2f,0x33,0x33,0x01,0x18,0x2f,0x5d,0x33,0x10,0xde,0xd4,0xc1,0x87,0x04,0x2b,0x10,0x01,0xc1,0x87,0x04,0x2b,0x10,0xc4,0x10,0x01,0xc1,0x87,0x04,0x18,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x13,0x35,0x01,0x15,0x09,0x01,0x15,0x74,0x03,0xe3,0xfc, +0xa6,0x03,0x5a,0x02,0x3b,0xcd,0x01,0xa2,0x9a,0xfe,0x92,0xfe,0x91,0x99,0x00,0x00,0x00,0x02,0x00,0x74,0x01,0x58,0x04,0x57,0x03,0xec,0x00,0x03,0x00,0x07,0x00,0x4c,0x40,0x37,0x07,0x02,0x09,0x04,0x00,0x01,0x10,0x01,0x02,0x01,0x05,0xad,0x1f,0x04,0x7f,0x04,0x9f,0x04,0xaf,0x04,0xbf,0x04,0x05,0x04,0x40,0x12,0x16,0x48,0x04,0x00, +0xad,0x30,0x01,0x50,0x01,0x60,0x01,0x70,0x01,0x04,0x50,0x01,0x70,0x01,0x80,0x01,0xb0,0x01,0xd0,0x01,0x05,0x0f,0x01,0x01,0x01,0x00,0x2f,0x5d,0x5d,0x71,0xed,0x2f,0x2b,0x71,0xed,0x01,0x2f,0x5d,0x33,0x10,0xce,0x32,0x31,0x30,0x13,0x35,0x21,0x15,0x01,0x35,0x21,0x15,0x74,0x03,0xe3,0xfc,0x1d,0x03,0xe3,0x03,0x58,0x94,0x94,0xfe, +0x00,0x94,0x94,0x00,0x00,0x01,0x00,0x74,0x00,0x9a,0x04,0x57,0x04,0xaa,0x00,0x06,0x00,0x77,0xb5,0x06,0x01,0x52,0x01,0x02,0x01,0xb8,0x01,0x0d,0x40,0x10,0x00,0x06,0x14,0x00,0x06,0x01,0x00,0x05,0x04,0x01,0x52,0x03,0x02,0x05,0x02,0x03,0xb8,0x01,0x0d,0x40,0x28,0x04,0x05,0x14,0x04,0x05,0x03,0x04,0x02,0x06,0x08,0x04,0x00,0x00, +0x10,0x00,0x02,0x00,0x06,0x05,0x02,0x02,0x03,0x0f,0x04,0x01,0x04,0x01,0x3f,0x00,0x6f,0x00,0x7f,0x00,0x03,0x00,0x40,0x12,0x15,0x48,0x00,0x00,0x2f,0x2b,0x5d,0x32,0x2f,0x5d,0x33,0x39,0x3d,0x2f,0x33,0x33,0x01,0x18,0x2f,0x5d,0xc4,0x10,0xce,0x32,0x10,0xc1,0x87,0x04,0x2b,0x10,0x01,0xc1,0x87,0x04,0x2b,0x10,0xc4,0x10,0x01,0xc1, +0x87,0x04,0x18,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x37,0x35,0x09,0x01,0x35,0x01,0x15,0x74,0x03,0x5a,0xfc,0xa6,0x03,0xe3,0x9a,0x99,0x01,0x6f,0x01,0x6e,0x9a,0xfe,0x5e,0xcd,0x00,0x00,0x00,0x00,0x02,0x00,0x5e,0x00,0x00,0x04,0x31,0x05,0x5a,0x00,0x27,0x00,0x2b,0x00,0x6d,0x40,0x49,0x69,0x06,0x79,0x06,0x89,0x06,0x03,0x69,0x04,0x79, +0x04,0x89,0x04,0x03,0x4a,0x1b,0x5a,0x1b,0x02,0x07,0x25,0x17,0x25,0x02,0x66,0x00,0x76,0x00,0x86,0x00,0x03,0x09,0x2b,0x98,0x0a,0x28,0x28,0x1e,0x00,0x98,0x00,0x13,0x01,0x13,0x13,0x2d,0x1d,0x98,0x1e,0x0a,0x40,0x0f,0x14,0x48,0x0a,0x0a,0x23,0x29,0x9d,0x28,0x66,0x23,0x76,0x23,0x86,0x23,0x03,0x1d,0x1d,0x18,0x9e,0x23,0x04,0x00, +0x3f,0xed,0x33,0x2f,0x5d,0x2f,0xed,0x11,0x39,0x2f,0x2b,0x01,0x2f,0xed,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x06,0x07,0x23,0x3e,0x07,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x01,0x35,0x33,0x15,0x04,0x31,0x25, +0x3e,0x4f,0x52,0x4f,0x3f,0x27,0x01,0xaf,0x02,0x27,0x3e,0x4e,0x50,0x4d,0x3c,0x25,0x29,0x4d,0x6d,0x44,0x44,0x6f,0x52,0x32,0x07,0xb8,0x0c,0x4a,0x7e,0xb0,0x70,0x6c,0xb1,0x7e,0x44,0xfd,0x8f,0xc3,0x03,0xea,0x45,0x68,0x52,0x42,0x3b,0x3b,0x44,0x53,0x37,0x43,0x66,0x51,0x41,0x3b,0x3b,0x44,0x53,0x35,0x37,0x54,0x39,0x1e,0x26,0x47, +0x65,0x3e,0x0c,0x5a,0x97,0x6c,0x3d,0x30,0x5d,0x89,0xfb,0xbc,0xc9,0xc9,0x00,0x00,0x00,0x02,0x00,0x2c,0xfe,0xe5,0x04,0xa5,0x05,0xcc,0x00,0x5f,0x00,0x78,0x01,0x3b,0x40,0x91,0x01,0x44,0x11,0x44,0x02,0x35,0x3f,0x55,0x3f,0x75,0x3f,0x03,0x01,0x3e,0x11,0x3e,0x02,0x6c,0x34,0x7c,0x34,0x8c,0x34,0x03,0x17,0x18,0x0b,0x0e,0x48,0x6c, +0x08,0x7c,0x08,0x8c,0x08,0x03,0x6c,0x66,0x7c,0x66,0x02,0x4a,0x66,0x5a,0x66,0x02,0x26,0x5d,0x01,0x6a,0x53,0x01,0x65,0x49,0x75,0x49,0x85,0x49,0x03,0x7f,0x3f,0x8f,0x3f,0x02,0x3f,0x40,0x0b,0x0e,0x48,0x7e,0x39,0x01,0x03,0x6f,0x2a,0x7f,0x2a,0x8f,0x2a,0x03,0x02,0x4f,0x2a,0x5f,0x2a,0x02,0x17,0x18,0x0b,0x0e,0x48,0x6a,0x37,0x7a, +0x37,0x8a,0x37,0x03,0x69,0x51,0x01,0x4b,0x0f,0x4c,0x1f,0x4c,0x02,0x4c,0x4c,0x56,0x00,0xd3,0x37,0x29,0x2f,0xd3,0x0a,0x60,0x28,0x0a,0x6a,0xd2,0x1a,0x37,0x40,0x14,0x18,0x48,0x10,0x37,0x01,0x2f,0x1a,0x3f,0x1a,0x02,0x37,0x0a,0x1a,0x1a,0x0a,0x37,0x03,0x7a,0x41,0xb8,0xff,0xe8,0xb5,0x0d,0x11,0x48,0x41,0xd3,0x56,0xb8,0xff,0xc0, +0x40,0x26,0x17,0x20,0x48,0x56,0x32,0x6f,0xd6,0x15,0x0f,0x05,0x15,0x63,0xd6,0x21,0x28,0x28,0x19,0x26,0x01,0x26,0x21,0x0f,0x15,0x1f,0x15,0x2f,0x15,0x9f,0x15,0xaf,0x15,0x05,0x90,0x21,0xa0,0x21,0x02,0x21,0xb8,0xff,0xc0,0x40,0x17,0x09,0x0c,0x48,0x4b,0x15,0x21,0x21,0x15,0x4b,0x03,0x46,0x3c,0x10,0x0d,0x11,0x48,0x3c,0xd5,0x5b, +0x00,0x46,0xd5,0x51,0xb8,0x01,0x0f,0x00,0x3f,0xed,0x3f,0xed,0x2b,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x2b,0x5d,0x5d,0x11,0x33,0x5d,0x33,0x2f,0x10,0xed,0x11,0x33,0x33,0x10,0xed,0x32,0x01,0x2f,0x2b,0xed,0x2b,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x5d,0x5d,0x2b,0x10,0xed,0x11,0x33,0x33,0x10,0xed,0x32,0x10,0xed,0x11,0x39,0x2f,0x5d,0x33, +0x00,0x5d,0x01,0x5d,0x31,0x30,0x00,0x2b,0x5d,0x5f,0x5d,0x5f,0x5d,0x2b,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x2b,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x3c,0x01,0x3e,0x01,0x35,0x23,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x04,0x33,0x32,0x1e,0x02,0x17,0x33,0x37,0x33,0x03,0x0e,0x03,0x15, +0x14,0x16,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x01,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x1a,0x01,0x36,0x33,0x32,0x1e,0x01,0x12,0x05,0x34,0x26,0x23,0x22,0x0e,0x04,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x3e,0x03,0x04,0xa5,0x29,0x4e, +0x72,0x48,0x1e,0x34,0x27,0x16,0x01,0x01,0x06,0x0f,0x2e,0x3b,0x49,0x2a,0x3f,0x56,0x35,0x17,0x17,0x2c,0x41,0x51,0x62,0x38,0x2a,0x3e,0x2b,0x1c,0x09,0x05,0x20,0x74,0x63,0x08,0x0f,0x0b,0x06,0x1d,0x14,0x28,0x41,0x2f,0x19,0x35,0x65,0x94,0x60,0x78,0xbb,0x7f,0x42,0x3b,0x6f,0xa2,0x66,0x3b,0x66,0x59,0x51,0x26,0x47,0x2b,0x61,0x6f, +0x7e,0x49,0x7f,0xcc,0x8e,0x4d,0x54,0xa1,0xe9,0x96,0x83,0xc3,0x80,0x3f,0xfe,0x62,0x46,0x3b,0x25,0x40,0x34,0x28,0x1b,0x0e,0x0b,0x1b,0x2c,0x20,0x27,0x47,0x3a,0x2e,0x0d,0x03,0x08,0x07,0x04,0x02,0xf3,0x90,0xef,0xac,0x60,0x10,0x25,0x3c,0x2c,0x02,0x0b,0x0c,0x0a,0x03,0x27,0x47,0x36,0x1f,0x41,0x6b,0x8b,0x4a,0x4c,0x96,0x88,0x75, +0x55,0x30,0x1b,0x2f,0x3f,0x24,0x97,0xfe,0x05,0x2a,0x51,0x49,0x3d,0x15,0x34,0x24,0x50,0x91,0xc9,0x79,0x81,0xe0,0xa6,0x60,0x86,0xe7,0xfe,0xc8,0xb1,0x98,0xfa,0xb3,0x62,0x19,0x2a,0x3a,0x21,0x57,0x25,0x44,0x35,0x1f,0x71,0xd0,0x01,0x26,0xb6,0xd1,0x01,0x63,0x01,0x04,0x92,0x76,0xc8,0xfe,0xf8,0x76,0x6a,0x6d,0x2c,0x4b,0x64,0x71, +0x77,0x39,0x3c,0x67,0x4b,0x2b,0x37,0x64,0x8f,0x57,0x13,0x34,0x36,0x31,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x04,0xcc,0x05,0x45,0x00,0x07,0x00,0x14,0x00,0x72,0x40,0x42,0x13,0x02,0x03,0x05,0x01,0x52,0x03,0x0d,0x03,0x5e,0x04,0x05,0x14,0x04,0x05,0x03,0x04,0x14,0x01,0x00,0x06,0x01,0x52,0x00,0x0d,0x00,0x5e,0x07,0x06,0x14, +0x07,0x06,0x0d,0x04,0x10,0x07,0x01,0x07,0x07,0x16,0x7f,0x04,0x8f,0x04,0x02,0x04,0x07,0x01,0x02,0x5f,0x14,0x13,0x13,0x5a,0x0d,0x01,0x4b,0x0d,0x01,0x0d,0x06,0x05,0x03,0x04,0x00,0x12,0x00,0x3f,0x32,0x3f,0x33,0x33,0x5d,0x5d,0x39,0x2f,0x33,0xed,0x32,0x2f,0x01,0x2f,0x5d,0x11,0x33,0x2f,0x5d,0x12,0x39,0x87,0x2b,0x87,0x2b,0xc4, +0x10,0xc0,0xc0,0x10,0x00,0xc1,0x87,0x05,0x18,0x2b,0x87,0x2b,0xc4,0x10,0xc0,0xc0,0x31,0x30,0x21,0x03,0x21,0x03,0x23,0x01,0x33,0x09,0x01,0x2e,0x03,0x27,0x0e,0x03,0x07,0x03,0x21,0x04,0x0a,0x8a,0xfd,0xcd,0x89,0xc4,0x01,0xfe,0xd9,0x01,0xf5,0xfd,0xf1,0x0d,0x1c,0x17,0x11,0x04,0x04,0x10,0x17,0x19,0x0d,0x97,0x01,0xcf,0x01,0x7e, +0xfe,0x82,0x05,0x45,0xfa,0xbb,0x03,0xba,0x26,0x4e,0x46,0x35,0x0c,0x0c,0x36,0x46,0x4e,0x25,0xfe,0x59,0x00,0x03,0x00,0xa2,0x00,0x00,0x04,0x80,0x05,0x45,0x00,0x16,0x00,0x21,0x00,0x2e,0x00,0x77,0x40,0x4f,0x65,0x2d,0x01,0x6a,0x24,0x01,0x66,0x20,0x01,0x7b,0x02,0x8b,0x02,0x02,0x74,0x0b,0x84,0x0b,0x94,0x0b,0x03,0x07,0x0b,0x01, +0x6f,0x12,0x01,0x4b,0x12,0x5b,0x12,0x02,0x12,0x29,0x0d,0x5a,0x17,0x40,0x0d,0x14,0x48,0x17,0x17,0x06,0x00,0x5a,0x00,0x22,0x01,0x22,0x22,0x30,0x1c,0x29,0x5a,0x00,0x06,0x10,0x06,0xa0,0x06,0xb0,0x06,0x04,0x06,0x12,0x28,0x5f,0x1c,0x1c,0x29,0x1b,0x5f,0x07,0x03,0x29,0x5f,0x06,0x12,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed, +0x39,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x2b,0xed,0x11,0x39,0x5d,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x21,0x11,0x21,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x1e,0x03,0x01,0x34,0x26,0x2b,0x01,0x11,0x33,0x32,0x3e,0x02,0x13,0x34,0x2e,0x02,0x2b,0x01,0x11, +0x21,0x32,0x3e,0x02,0x04,0x80,0x54,0x8e,0xbc,0x68,0xfe,0x28,0x01,0x9c,0x75,0xb8,0x80,0x43,0x21,0x43,0x64,0x44,0x55,0x83,0x58,0x2e,0xfe,0xee,0x97,0x97,0xdf,0xe1,0x51,0x72,0x48,0x21,0x51,0x33,0x5d,0x82,0x50,0xfc,0x01,0x0a,0x49,0x7d,0x5b,0x33,0x01,0x7c,0x67,0x90,0x5b,0x2a,0x05,0x45,0x26,0x4f,0x7c,0x56,0x38,0x65,0x51,0x3b, +0x0e,0x09,0x38,0x57,0x71,0x02,0x28,0x6b,0x5b,0xfe,0x60,0x1f,0x39,0x50,0xfd,0xd9,0x3f,0x58,0x39,0x1a,0xfe,0x22,0x17,0x38,0x5e,0x00,0x00,0x00,0x00,0x01,0x00,0x71,0xff,0xec,0x04,0x76,0x05,0x5a,0x00,0x29,0x00,0xa4,0x40,0x2d,0x39,0x27,0x01,0x46,0x1d,0x56,0x1d,0x66,0x1d,0x03,0x66,0x1c,0x01,0x36,0x03,0x01,0x20,0x1f,0x30,0x1f, +0x02,0x60,0x1f,0x70,0x1f,0x02,0xa0,0x1f,0x01,0x1f,0x1f,0x20,0x40,0x1d,0x24,0x48,0x20,0x20,0x0a,0x0b,0x0b,0xb0,0x0a,0x01,0x0a,0xb8,0xff,0xc0,0x40,0x45,0x09,0x0c,0x48,0x0a,0x0a,0x2b,0x76,0x00,0x86,0x00,0x02,0x00,0x5b,0x30,0x15,0x40,0x15,0x50,0x15,0x03,0x00,0x15,0x10,0x15,0x02,0x15,0x46,0x1a,0x56,0x1a,0x02,0x25,0x5f,0x1a, +0x20,0x20,0x1a,0x04,0x10,0x0a,0x20,0x0a,0x30,0x0a,0x60,0x0a,0x70,0x0a,0x05,0x30,0x0a,0x80,0x0a,0xd0,0x0a,0xe0,0x0a,0x04,0x0a,0x0a,0x49,0x10,0x59,0x10,0x02,0x05,0x5f,0x10,0x13,0x00,0x3f,0xed,0x5d,0x33,0x2f,0x5d,0x71,0x3f,0x33,0x2f,0x10,0xed,0x5d,0x01,0x2f,0x5d,0x71,0xed,0x5d,0x12,0x39,0x2f,0x2b,0x5d,0x33,0x2f,0x11,0x33, +0x2f,0x2b,0x33,0x2f,0x5d,0x71,0x72,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x23,0x22,0x0e,0x02,0x01,0x3a,0x28,0x54,0x83,0x5c,0x3f,0x65,0x4f,0x3a,0x15,0x9f,0x1c,0x52,0x74,0x9b, +0x66,0x8d,0xcd,0x87,0x41,0x40,0x84,0xca,0x8a,0x65,0x98,0x6f,0x4d,0x19,0xa8,0x0f,0x34,0x49,0x61,0x3c,0x59,0x7f,0x52,0x26,0x02,0xa9,0x83,0xcb,0x8c,0x48,0x30,0x4e,0x66,0x36,0x41,0x46,0x85,0x69,0x40,0x65,0xb8,0x01,0x02,0x9e,0xa6,0x01,0x01,0xaf,0x5b,0x37,0x5d,0x79,0x42,0x41,0x2e,0x58,0x44,0x2a,0x44,0x87,0xc7,0x00,0x00,0x00, +0x00,0x02,0x00,0xa2,0x00,0x00,0x04,0x65,0x05,0x45,0x00,0x0c,0x00,0x17,0x00,0x61,0x40,0x45,0x75,0x02,0x85,0x02,0x02,0x7a,0x10,0x8a,0x10,0x02,0x70,0x17,0x80,0x17,0x02,0x14,0x17,0x24,0x17,0x64,0x17,0x03,0x7f,0x0f,0x8f,0x0f,0x02,0x1b,0x0f,0x2b,0x0f,0x6b,0x0f,0x03,0x34,0x0b,0x01,0x34,0x0a,0x01,0x3b,0x03,0x01,0x00,0x5a,0x00, +0x0d,0xa0,0x0d,0x02,0x0d,0x0d,0x19,0x14,0x5a,0x00,0x06,0x10,0x06,0x02,0x06,0x13,0x5f,0x07,0x03,0x14,0x5f,0x06,0x12,0x00,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x21,0x11,0x21,0x32,0x1e,0x02,0x07,0x34,0x2e, +0x02,0x2b,0x01,0x11,0x33,0x32,0x12,0x04,0x65,0x50,0x98,0xdd,0x8c,0xfe,0x8e,0x01,0x37,0x9e,0xf3,0xa6,0x55,0xc0,0x38,0x72,0xac,0x75,0x79,0xa2,0xd4,0xce,0x02,0xb0,0xa8,0xfe,0xff,0xae,0x59,0x05,0x45,0x4d,0xa2,0xfa,0xac,0x87,0xc0,0x79,0x39,0xfb,0xf3,0x01,0x0a,0x00,0x00,0x01,0x00,0xa2,0x00,0x00,0x04,0x62,0x05,0x45,0x00,0x0b, +0x00,0x5a,0x40,0x3b,0x07,0x40,0x0a,0x14,0x48,0x07,0x07,0x00,0x0a,0x03,0x03,0x00,0x0a,0x01,0x0a,0x0a,0x0d,0x05,0x09,0x5a,0x00,0x00,0x10,0x00,0x02,0x00,0x08,0x5f,0x0f,0x05,0x3f,0x05,0x7f,0x05,0x8f,0x05,0x04,0x6f,0x05,0x8f,0x05,0x9f,0x05,0xbf,0x05,0xdf,0x05,0x05,0x05,0x05,0x09,0x04,0x5f,0x01,0x03,0x09,0x5f,0x00,0x12,0x00, +0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0x71,0x72,0xed,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0x33,0x2f,0x11,0x12,0x39,0x2f,0x2b,0x31,0x30,0x33,0x11,0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x15,0xa2,0x03,0x97,0xfd,0x28,0x02,0x9c,0xfd,0x64,0x03,0x01,0x05,0x45,0x9c,0xfe,0x5a,0x9a,0xfe,0x33,0x9c,0x00,0x01,0x00,0xc2, +0x00,0x00,0x04,0x3d,0x05,0x45,0x00,0x09,0x00,0x47,0x40,0x2d,0x02,0x02,0x06,0x08,0x08,0x0b,0x01,0x05,0x5a,0x00,0x06,0x10,0x06,0x02,0x06,0x04,0x5f,0x3f,0x01,0x7f,0x01,0x8f,0x01,0x03,0x3f,0x01,0x6f,0x01,0x9f,0x01,0x03,0x01,0x40,0x15,0x29,0x48,0x01,0x01,0x05,0x00,0x5f,0x07,0x03,0x05,0x12,0x00,0x3f,0x3f,0xed,0x12,0x39,0x2f, +0x2b,0x5d,0x72,0xed,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x12,0x39,0x2f,0x31,0x30,0x01,0x11,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x15,0x01,0x81,0x02,0xa4,0xfd,0x5c,0xbf,0x03,0x7b,0x04,0xa9,0xfe,0x12,0x9e,0xfd,0xe3,0x05,0x45,0x9c,0x00,0x00,0x00,0x01,0x00,0x71,0xff,0xec,0x04,0x4f,0x05,0x5a,0x00,0x29,0x00,0x88,0x40,0x4a, +0x08,0x02,0x01,0x15,0x1e,0x25,0x1e,0x75,0x1e,0x85,0x1e,0x04,0x55,0x12,0x01,0x27,0x27,0x0a,0x25,0xaf,0x15,0x01,0x15,0x15,0x14,0x14,0x00,0x5a,0xc0,0x25,0xd0,0x25,0x02,0x7f,0x25,0x8f,0x25,0x02,0x00,0x25,0x01,0x25,0x25,0x2b,0x36,0x1d,0x76,0x1d,0x86,0x1d,0xb6,0x1d,0x04,0x1d,0x5b,0x30,0x0a,0x40,0x0a,0x50,0x0a,0x03,0x00,0x0a, +0x10,0x0a,0x02,0x0a,0x27,0x5f,0x28,0x28,0x20,0x0f,0xb8,0xff,0xf0,0x40,0x0e,0x0d,0x11,0x48,0x18,0x5f,0x0f,0x15,0x15,0x0f,0x04,0x20,0x5f,0x05,0x13,0x00,0x3f,0xed,0x3f,0x33,0x2f,0x10,0xed,0x2b,0x12,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x5d,0x12,0x39,0x2f,0x5d,0x5d,0x5d,0xed,0x32,0x2f,0x33,0x2f,0x5d,0x11,0x12,0x39,0x2f, +0x31,0x30,0x00,0x5d,0x5d,0x5d,0x25,0x0e,0x03,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x01,0x23,0x22,0x0e,0x02,0x15,0x10,0x12,0x33,0x32,0x3e,0x02,0x37,0x11,0x21,0x35,0x21,0x04,0x4d,0x24,0x5f,0x74,0x89,0x4e,0x86,0xc6,0x82,0x40,0x3e,0x82,0xc8,0x89,0x64,0x97,0x6f,0x4b,0x18,0xab, +0x26,0x8b,0x6f,0x5a,0x7e,0x4f,0x23,0xa9,0xac,0x30,0x53,0x43,0x31,0x0d,0xfe,0xdb,0x01,0xdf,0x85,0x18,0x36,0x2d,0x1e,0x69,0xba,0x01,0x01,0x99,0xa7,0x01,0x01,0xaf,0x5a,0x34,0x59,0x79,0x45,0x38,0x6e,0x79,0x45,0x87,0xc7,0x82,0xfe,0xf4,0xfe,0xea,0x11,0x17,0x19,0x09,0x01,0x50,0xa0,0x00,0x00,0x01,0x00,0xa2,0x00,0x00,0x04,0x2a, +0x05,0x45,0x00,0x0b,0x00,0x57,0x40,0x3c,0x0b,0x5a,0x08,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x6f,0x00,0x7f,0x00,0x05,0x6f,0x00,0x7f,0x00,0x8f,0x00,0xbf,0x00,0x04,0x00,0x00,0x0d,0x07,0x03,0x5a,0x70,0x04,0x01,0x00,0x04,0x10,0x04,0xa0,0x04,0xb0,0x04,0x04,0x04,0x02,0x5f,0x50,0x07,0x01,0xa0,0x07,0xb0,0x07,0x02,0x07,0x07,0x09,0x05, +0x03,0x04,0x00,0x12,0x00,0x3f,0x32,0x3f,0x33,0x39,0x2f,0x5d,0x71,0xed,0x01,0x2f,0x5d,0x71,0xed,0x32,0x12,0x39,0x2f,0x5d,0x71,0x33,0xed,0x31,0x30,0x21,0x11,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x03,0x6b,0xfd,0xf6,0xbf,0xbf,0x02,0x0a,0xbf,0x02,0x6f,0xfd,0x91,0x05,0x45,0xfd,0xca,0x02,0x36,0xfa,0xbb,0x00,0x00, +0x00,0x01,0x00,0xca,0x00,0x00,0x04,0x01,0x05,0x45,0x00,0x0b,0x00,0x59,0x40,0x38,0x06,0x06,0x01,0x0e,0x04,0x07,0x07,0x00,0x00,0x09,0x0e,0x70,0x00,0x01,0x00,0x04,0x5a,0x0f,0x09,0x3f,0x09,0x8f,0x09,0x9f,0x09,0x04,0x4f,0x09,0x5f,0x09,0x7f,0x09,0x8f,0x09,0xcf,0x09,0xdf,0x09,0x06,0x10,0x09,0x01,0x09,0x09,0x0c,0x0d,0x04,0x08, +0x5f,0x07,0x12,0x03,0x0b,0x5f,0x00,0x03,0x00,0x3f,0xed,0x32,0x3f,0xed,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0x5d,0x71,0xed,0xc4,0x5d,0x2b,0x11,0x01,0x33,0x18,0x2f,0x10,0x4d,0xe4,0x32,0x2f,0x31,0x30,0x13,0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x35,0x21,0x11,0x21,0xca,0x03,0x37,0xfe,0xc4,0x01,0x3c,0xfc,0xc9,0x01,0x3c,0xfe,0xc4, +0x05,0x45,0x9c,0xfb,0xf3,0x9c,0x9c,0x04,0x0d,0x00,0x00,0x00,0x00,0x01,0x00,0xb0,0xff,0xec,0x03,0xda,0x05,0x45,0x00,0x15,0x00,0x4b,0xb7,0x65,0x10,0x75,0x10,0x85,0x10,0x03,0x0b,0xb8,0xff,0xe8,0x40,0x22,0x0d,0x11,0x48,0x13,0x13,0x08,0x00,0x5a,0x11,0x11,0x08,0x17,0x80,0x09,0x01,0x09,0x09,0x00,0x08,0x10,0x08,0x02,0x08,0x13, +0x5f,0x14,0x03,0x0e,0x5f,0x05,0x09,0x09,0x05,0x13,0x00,0x3f,0x33,0x2f,0x10,0xed,0x3f,0xed,0x01,0x2f,0x5d,0x33,0x2f,0x5d,0x11,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0x31,0x30,0x00,0x2b,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x37,0x1e,0x03,0x33,0x32,0x36,0x35,0x11,0x21,0x35,0x21,0x03,0xda,0x33,0x65,0x96,0x62,0xab,0xcc, +0x23,0xbb,0x0a,0x2a,0x3a,0x49,0x29,0x68,0x69,0xfe,0xc9,0x01,0xf5,0x01,0xa4,0x64,0xa3,0x73,0x3e,0xb2,0xc0,0x1f,0x40,0x5d,0x3c,0x1d,0x8f,0x8a,0x03,0x09,0x9c,0x00,0x00,0x01,0x00,0xa2,0x00,0x00,0x04,0xcb,0x05,0x45,0x00,0x0b,0x00,0x97,0x40,0x34,0x74,0x0a,0x84,0x0a,0x02,0x46,0x0a,0x56,0x0a,0x66,0x0a,0x03,0x64,0x07,0x74,0x07, +0x84,0x07,0x03,0x8d,0x00,0x01,0x6b,0x00,0x7b,0x00,0x02,0x49,0x00,0x59,0x00,0x02,0x39,0x0a,0x01,0x14,0x0a,0x01,0x01,0x20,0x0b,0x11,0x48,0x0a,0x01,0x0b,0x72,0x09,0x82,0x09,0x02,0x09,0xb8,0xff,0xe0,0x40,0x2d,0x0b,0x0f,0x48,0x08,0x09,0x10,0x09,0x09,0x00,0x0b,0x10,0x00,0x0b,0x10,0x0b,0x02,0x0b,0x0b,0x0d,0x07,0x03,0x5a,0x00, +0x04,0x10,0x04,0x02,0x04,0x02,0x07,0x0a,0x01,0x76,0x07,0x86,0x07,0x02,0x07,0x01,0x08,0x05,0x03,0x04,0x00,0x12,0x00,0x3f,0x32,0x3f,0x33,0x39,0x39,0x5d,0x11,0x33,0x11,0x33,0x01,0x2f,0x5d,0xed,0x32,0x11,0x33,0x2f,0x5d,0x38,0x33,0x33,0x2f,0x38,0x33,0x2b,0x5d,0x11,0x39,0x39,0x00,0x2b,0x31,0x30,0x5d,0x5d,0x01,0x5d,0x5d,0x5d, +0x00,0x5d,0x01,0x5d,0x5d,0x21,0x01,0x07,0x11,0x23,0x11,0x33,0x11,0x01,0x33,0x09,0x01,0x03,0xeb,0xfe,0x19,0xa3,0xbf,0xbf,0x02,0x3c,0xe1,0xfe,0x08,0x02,0x45,0x02,0x7e,0xa9,0xfe,0x2b,0x05,0x45,0xfd,0x5f,0x02,0xa1,0xfd,0xc4,0xfc,0xf7,0x00,0x00,0x00,0x01,0x00,0xed,0x00,0x00,0x04,0x4c,0x05,0x45,0x00,0x05,0x00,0x26,0x40,0x16, +0x04,0x04,0x07,0x03,0x5a,0x2f,0x00,0x3f,0x00,0x02,0x00,0x00,0x10,0x00,0x02,0x00,0x01,0x03,0x03,0x5f,0x00,0x12,0x00,0x3f,0xed,0x3f,0x01,0x2f,0x5d,0x5d,0xed,0x12,0x39,0x2f,0x31,0x30,0x33,0x11,0x33,0x11,0x21,0x15,0xed,0xbf,0x02,0xa0,0x05,0x45,0xfb,0x57,0x9c,0x00,0x00,0x01,0x00,0x81,0x00,0x00,0x04,0x4b,0x05,0x45,0x00,0x2c, +0x00,0x99,0xb9,0x00,0x1e,0xff,0xe8,0x40,0x13,0x0d,0x11,0x48,0x26,0x1e,0x36,0x1e,0x02,0x2a,0x18,0x0d,0x11,0x48,0x29,0x2a,0x39,0x2a,0x02,0x0c,0xb8,0xff,0xf0,0x40,0x19,0x0b,0x11,0x48,0x0d,0x10,0x0b,0x11,0x48,0x0d,0x0c,0x24,0x24,0x1c,0x2c,0x5c,0x2a,0x00,0x40,0x19,0x1c,0x48,0x00,0x00,0x2e,0x1e,0xb8,0xff,0xf0,0x40,0x0d,0x0a, +0x11,0x00,0x4c,0x1e,0x1b,0x5c,0x00,0x1c,0x10,0x1c,0x02,0x1c,0xb8,0xff,0xc0,0xb3,0x28,0x2d,0x48,0x1c,0xb8,0xff,0xc0,0x40,0x09,0x18,0x1e,0x48,0x1c,0x06,0x15,0x15,0x1d,0x24,0xb8,0xff,0xc0,0x40,0x0c,0x0e,0x11,0x48,0x24,0x0d,0x0d,0x2a,0x1d,0x03,0x1c,0x00,0x12,0x00,0x3f,0x32,0x3f,0x33,0x39,0x2f,0x33,0x2b,0x11,0x33,0x11,0x33, +0x01,0x2f,0x2b,0x2b,0x5d,0xed,0x32,0x2b,0x12,0x39,0x2f,0x2b,0x33,0xed,0x11,0x39,0x11,0x33,0x33,0x2b,0x2b,0x31,0x30,0x5d,0x2b,0x5d,0x2b,0x21,0x11,0x34,0x36,0x37,0x36,0x37,0x06,0x07,0x0e,0x01,0x07,0x03,0x23,0x03,0x2e,0x03,0x27,0x26,0x27,0x16,0x17,0x1e,0x01,0x15,0x11,0x23,0x11,0x33,0x13,0x1e,0x01,0x17,0x16,0x17,0x36,0x37, +0x3e,0x01,0x37,0x13,0x33,0x11,0x03,0xa9,0x01,0x02,0x02,0x01,0x11,0x11,0x0e,0x21,0x0e,0xa4,0x89,0xa6,0x06,0x0e,0x0f,0x10,0x08,0x12,0x13,0x01,0x01,0x01,0x01,0xa0,0xed,0xb9,0x09,0x17,0x0b,0x0c,0x0d,0x0e,0x0c,0x0b,0x18,0x09,0xb9,0xe1,0x03,0x64,0x33,0x6a,0x2c,0x33,0x31,0x37,0x35,0x2d,0x64,0x26,0xfe,0x4a,0x01,0xb6,0x0f,0x29, +0x2f,0x31,0x18,0x37,0x3c,0x30,0x34,0x2d,0x69,0x33,0xfc,0x9c,0x05,0x45,0xfe,0x17,0x17,0x4d,0x26,0x2c,0x31,0x2f,0x2b,0x25,0x4e,0x19,0x01,0xea,0xfa,0xbb,0x00,0x00,0x00,0x01,0x00,0xa2,0x00,0x00,0x04,0x2a,0x05,0x45,0x00,0x13,0x00,0x78,0x40,0x24,0x12,0x5c,0x00,0x18,0x09,0x11,0x48,0x00,0x80,0x11,0x90,0x11,0xd0,0x11,0xe0,0x11, +0x04,0x3f,0x11,0x01,0xc0,0x11,0xd0,0x11,0x02,0x6f,0x11,0x7f,0x11,0x8f,0x11,0x03,0x11,0x11,0x15,0x0a,0xb8,0xff,0xe8,0x40,0x2d,0x0b,0x11,0x48,0x0a,0x07,0x5c,0x70,0x08,0x01,0x00,0x08,0x10,0x08,0xa0,0x08,0xb0,0x08,0x04,0x08,0x8c,0x01,0x01,0x7a,0x01,0x01,0x69,0x01,0x01,0x11,0x01,0x09,0x03,0x83,0x0b,0x01,0x75,0x0b,0x01,0x66, +0x0b,0x01,0x0b,0x00,0x08,0x12,0x00,0x3f,0x33,0x33,0x5d,0x5d,0x5d,0x3f,0x33,0x33,0x5d,0x5d,0x5d,0x01,0x2f,0x5d,0x71,0xed,0x32,0x2b,0x12,0x39,0x2f,0x5d,0x5d,0x71,0x71,0x33,0x2b,0xed,0x31,0x30,0x21,0x01,0x16,0x17,0x1e,0x01,0x15,0x11,0x23,0x11,0x33,0x01,0x26,0x27,0x2e,0x01,0x35,0x11,0x33,0x11,0x03,0x44,0xfd,0xf8,0x04,0x04, +0x03,0x05,0xaa,0xde,0x02,0x10,0x05,0x04,0x04,0x05,0xac,0x04,0x6a,0x2b,0x2d,0x26,0x59,0x27,0xfc,0x94,0x05,0x45,0xfb,0x8e,0x28,0x2e,0x27,0x62,0x33,0x03,0x60,0xfa,0xbb,0x00,0x00,0x00,0x00,0x02,0x00,0x66,0xff,0xec,0x04,0x66,0x05,0x5a,0x00,0x11,0x00,0x1d,0x00,0x79,0x40,0x56,0x76,0x1d,0x86,0x1d,0x02,0x34,0x1d,0x01,0x76,0x19, +0x86,0x19,0x02,0x34,0x19,0x01,0x79,0x17,0x89,0x17,0x02,0x3b,0x17,0x01,0x79,0x13,0x89,0x13,0x02,0x3b,0x13,0x01,0x56,0x10,0x01,0x45,0x10,0x01,0x46,0x0d,0x56,0x0d,0x02,0x49,0x07,0x59,0x07,0x02,0x49,0x03,0x59,0x03,0x02,0x00,0x5b,0x5f,0x12,0x01,0x12,0x40,0x19,0x1c,0x48,0x00,0x12,0x01,0x12,0x12,0x1f,0x18,0x5b,0x50,0x0a,0x01, +0x10,0x0a,0x01,0x0a,0x15,0x5f,0x0f,0x04,0x1b,0x5f,0x05,0x13,0x00,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x2b,0x71,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x00,0x03, +0x10,0x02,0x23,0x22,0x02,0x11,0x10,0x12,0x33,0x32,0x12,0x04,0x66,0x46,0x84,0xbf,0x78,0x7f,0xc0,0x80,0x40,0x44,0x82,0xbf,0x7c,0xf7,0x01,0x08,0xc9,0x9e,0x98,0x9c,0x9c,0x9e,0x99,0xa3,0x94,0x02,0xa9,0xad,0xfe,0xfa,0xb1,0x59,0x5e,0xb3,0x01,0x05,0xa7,0xad,0x01,0x02,0xac,0x56,0xfe,0xa5,0xfe,0xaa,0x01,0x0e,0x01,0x07,0xfe,0xf9, +0xfe,0xf2,0xfe,0xf2,0xfe,0xec,0x01,0x18,0x00,0x02,0x00,0xa2,0x00,0x00,0x04,0x5f,0x05,0x45,0x00,0x0e,0x00,0x19,0x00,0x5b,0x40,0x3e,0x66,0x17,0x01,0x76,0x00,0x86,0x00,0x02,0x49,0x0f,0x59,0x0f,0x69,0x0f,0x03,0x00,0x5a,0x7f,0x0f,0x8f,0x0f,0x02,0x0f,0x40,0x19,0x1c,0x48,0x00,0x0f,0x01,0x0f,0x0f,0x1b,0x14,0x07,0x5a,0x00,0x08, +0x10,0x08,0xa0,0x08,0xb0,0x08,0x04,0x08,0x06,0x5f,0x14,0x40,0x09,0x11,0x48,0x14,0x14,0x07,0x13,0x5f,0x09,0x03,0x07,0x12,0x00,0x3f,0x3f,0xed,0x12,0x39,0x2f,0x2b,0xed,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0x2b,0x5d,0xed,0x5d,0x5d,0x31,0x30,0x00,0x5d,0x01,0x14,0x0e,0x02,0x23,0x21,0x11,0x23,0x11,0x21,0x32,0x1e,0x02, +0x07,0x34,0x26,0x2b,0x01,0x11,0x33,0x32,0x3e,0x02,0x04,0x5f,0x3b,0x79,0xb6,0x7b,0xfe,0xe7,0xbf,0x01,0xcc,0x7d,0xba,0x7c,0x3e,0xc0,0xa4,0xa4,0xf6,0xfe,0x52,0x79,0x4f,0x26,0x03,0xb1,0x54,0x9b,0x78,0x48,0xfd,0xfe,0x05,0x45,0x3a,0x6a,0x95,0x5e,0x7d,0x81,0xfd,0xed,0x2b,0x4a,0x66,0x00,0x00,0x02,0x00,0x66,0xfe,0x7d,0x04,0x71, +0x05,0x5a,0x00,0x20,0x00,0x2c,0x00,0x8b,0x40,0x62,0x35,0x2c,0x75,0x2c,0x85,0x2c,0x03,0x35,0x28,0x75,0x28,0x85,0x28,0x03,0x3a,0x26,0x7a,0x26,0x8a,0x26,0x03,0x3a,0x22,0x7a,0x22,0x8a,0x22,0x03,0x69,0x11,0x79,0x11,0x89,0x11,0x03,0x4a,0x04,0x5a,0x04,0x02,0x46,0x1f,0x56,0x1f,0x02,0x46,0x1c,0x56,0x1c,0x02,0x05,0x5a,0x14,0x0b, +0x0b,0x00,0x5b,0x21,0x5f,0x21,0x01,0x21,0x40,0x19,0x1c,0x48,0x00,0x21,0x01,0x14,0x21,0x14,0x21,0x2e,0x27,0x5b,0x50,0x19,0x01,0x10,0x19,0x01,0x19,0x24,0x5f,0x1e,0x04,0x05,0x2a,0x5f,0x14,0x13,0x08,0x60,0x5f,0x0f,0x01,0x0f,0x00,0x2f,0x5d,0xed,0x3f,0xed,0x33,0x3f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d, +0x2b,0x71,0x10,0xed,0x32,0x2f,0x10,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x07,0x1e,0x01,0x33,0x32,0x36,0x37,0x15,0x0e,0x01,0x23,0x22,0x2e,0x02,0x27,0x2e,0x03,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x00,0x03,0x10,0x02,0x23,0x22,0x02,0x11,0x10,0x12,0x33,0x32,0x12,0x04,0x66,0x33,0x62, +0x8d,0x5a,0x29,0x86,0x65,0x1c,0x40,0x17,0x26,0x5b,0x31,0x55,0x81,0x61,0x46,0x1b,0x70,0xa8,0x71,0x38,0x44,0x82,0xbf,0x7c,0xf7,0x01,0x08,0xc9,0x9e,0x98,0x9c,0x9c,0x9e,0x99,0xa3,0x94,0x02,0xa9,0x93,0xeb,0xac,0x6d,0x16,0x7e,0x72,0x08,0x05,0x86,0x09,0x0d,0x33,0x5f,0x8a,0x57,0x0b,0x67,0xb2,0xf9,0x9c,0xad,0x01,0x02,0xac,0x56, +0xfe,0xa5,0xfe,0xaa,0x01,0x0e,0x01,0x07,0xfe,0xf9,0xfe,0xf2,0xfe,0xf2,0xfe,0xec,0x01,0x18,0x00,0x00,0x00,0x02,0x00,0xa2,0x00,0x00,0x04,0x99,0x05,0x45,0x00,0x11,0x00,0x1b,0x00,0x97,0xb9,0x00,0x1a,0xff,0xf0,0xb3,0x0f,0x00,0x4d,0x10,0xb8,0xff,0xe0,0x40,0x23,0x0f,0x11,0x00,0x4c,0x89,0x01,0x01,0x0b,0x00,0x01,0x00,0x20,0x0e, +0x11,0x48,0x00,0x11,0x10,0x11,0x11,0x01,0x04,0x10,0x01,0x10,0x10,0x03,0x76,0x0b,0x86,0x0b,0x02,0x0b,0x5a,0x12,0xb8,0xff,0xc0,0x40,0x36,0x15,0x18,0x48,0x7f,0x12,0x8f,0x12,0x02,0x00,0x12,0x01,0x12,0x12,0x1d,0x16,0x03,0x5a,0x00,0x04,0x10,0x04,0xa0,0x04,0xb0,0x04,0x04,0x04,0x10,0x02,0x5f,0x1f,0x16,0x7f,0x16,0x02,0x3f,0x16, +0x6f,0x16,0x9f,0x16,0xef,0x16,0x04,0x16,0x16,0x00,0x15,0x5f,0x05,0x03,0x04,0x00,0x12,0x00,0x3f,0x32,0x3f,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x32,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0x5d,0x2b,0xed,0x5d,0x11,0x39,0x2f,0x5d,0x33,0x32,0x2f,0x38,0x33,0x2b,0x5d,0x5d,0x31,0x30,0x2b,0x00,0x2b,0x21,0x01,0x23,0x11,0x23, +0x11,0x21,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x01,0x03,0x34,0x29,0x01,0x11,0x21,0x32,0x3e,0x02,0x03,0xbd,0xfe,0x92,0xee,0xbf,0x01,0xe2,0x78,0xb3,0x77,0x3b,0x27,0x54,0x82,0x5b,0x01,0x90,0xf8,0xfe,0xd0,0xfe,0xf0,0x01,0x18,0x53,0x71,0x45,0x1f,0x02,0x3f,0xfd,0xc1,0x05,0x45,0x33,0x61,0x8a,0x57,0x3e,0x7b,0x67,0x4c,0x0f, +0xfd,0xab,0x03,0xcd,0xdf,0xfe,0x2a,0x28,0x43,0x5a,0x00,0x00,0x00,0x01,0x00,0x4f,0xff,0xec,0x04,0x68,0x05,0x5a,0x00,0x3f,0x00,0xb0,0x40,0x79,0x34,0x3d,0x01,0x6d,0x2d,0x01,0x4b,0x1d,0x5b,0x1d,0x02,0x6b,0x10,0x01,0x60,0x0c,0x01,0x74,0x3e,0x84,0x3e,0x02,0x74,0x3d,0x01,0x40,0x3d,0x50,0x3d,0x02,0x86,0x3c,0x01,0x44,0x3c,0x54, +0x3c,0x02,0x76,0x37,0x86,0x37,0x02,0x74,0x27,0x84,0x27,0x02,0x04,0x21,0x74,0x21,0x84,0x21,0x03,0x54,0x0b,0x01,0x89,0x07,0x01,0x7a,0x07,0x01,0x8b,0x02,0x01,0x79,0x02,0x01,0x2a,0x5a,0x29,0x29,0x00,0x5a,0x00,0x13,0x01,0x13,0x13,0x1f,0x41,0x09,0x5a,0x7f,0x08,0x8f,0x08,0x02,0x08,0x34,0x5a,0x00,0x1f,0x10,0x1f,0x02,0x1f,0x34, +0x13,0x05,0x2f,0x60,0x24,0x2a,0x2a,0x24,0x04,0x0e,0x5f,0x05,0x40,0x09,0x50,0x09,0x02,0x09,0x09,0x05,0x13,0x00,0x3f,0x33,0x2f,0x5d,0x10,0xed,0x3f,0x33,0x2f,0x10,0xed,0x12,0x39,0x39,0x01,0x2f,0x5d,0xed,0xd6,0x5d,0xed,0x11,0x12,0x39,0x2f,0x5d,0xed,0x32,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, +0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x24,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x27,0x2e,0x05,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x17,0x1e,0x05,0x04,0x68,0x3e,0x7f,0xc3,0x86,0xea,0xfe,0xfb, +0x24,0xb9,0x0c,0x30,0x54,0x7a,0x55,0x48,0x77,0x55,0x30,0x41,0x6a,0x85,0x44,0x32,0x66,0x5e,0x51,0x3d,0x22,0x48,0x7e,0xac,0x64,0x74,0xa3,0x71,0x44,0x14,0xbc,0x0b,0x2b,0x47,0x64,0x44,0x50,0x6c,0x42,0x1d,0x35,0x5b,0x79,0x45,0x37,0x70,0x67,0x59,0x42,0x26,0x01,0x72,0x55,0x8f,0x68,0x3a,0xb8,0xae,0x25,0x37,0x5a,0x41,0x24,0x1b, +0x3a,0x5a,0x3f,0x46,0x58,0x38,0x23,0x11,0x0d,0x1d,0x27,0x35,0x4b,0x65,0x43,0x60,0x89,0x57,0x28,0x29,0x52,0x79,0x50,0x21,0x33,0x50,0x36,0x1c,0x21,0x39,0x4e,0x2d,0x3c,0x4b,0x31,0x20,0x12,0x0e,0x1f,0x2a,0x39,0x52,0x6e,0x00,0x00,0x01,0x00,0x4c,0x00,0x00,0x04,0x80,0x05,0x45,0x00,0x07,0x00,0x4a,0x40,0x31,0x07,0x0e,0x01,0x04, +0x02,0x0e,0x04,0x01,0x5a,0x0f,0x02,0x3f,0x02,0x8f,0x02,0x9f,0x02,0xbf,0x02,0xcf,0x02,0x06,0x4f,0x02,0x5f,0x02,0x7f,0x02,0x8f,0x02,0xcf,0x02,0xdf,0x02,0x06,0x10,0x02,0x01,0x02,0x02,0x08,0x09,0x00,0x04,0x5f,0x05,0x03,0x01,0x12,0x00,0x3f,0x3f,0xed,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0x5d,0x71,0xed,0xc6,0x2b,0x01,0x18,0x10, +0x4d,0xe6,0x31,0x30,0x01,0x11,0x23,0x11,0x21,0x35,0x21,0x15,0x02,0xc5,0xbe,0xfe,0x45,0x04,0x34,0x04,0xa9,0xfb,0x57,0x04,0xa9,0x9c,0x9c,0x00,0x00,0x01,0x00,0x8e,0xff,0xec,0x04,0x3d,0x05,0x45,0x00,0x19,0x00,0x5e,0x40,0x44,0x65,0x15,0x75,0x15,0x85,0x15,0x03,0x65,0x0f,0x75,0x0f,0x85,0x0f,0x03,0x00,0x5a,0x80,0x17,0x90,0x17, +0xd0,0x17,0xe0,0x17,0xf0,0x17,0x05,0x3f,0x17,0x01,0xc0,0x17,0xd0,0x17,0x02,0x7f,0x17,0x8f,0x17,0x02,0x17,0x17,0x1b,0x0d,0x5a,0x8f,0x0a,0x9f,0x0a,0xaf,0x0a,0x03,0xcf,0x0a,0x01,0x00,0x0a,0x10,0x0a,0x02,0x0a,0x18,0x0b,0x03,0x12,0x5f,0x05,0x13,0x00,0x3f,0xed,0x3f,0x33,0x01,0x2f,0x5d,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x5d, +0x71,0x71,0xed,0x31,0x30,0x00,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x11,0x33,0x04,0x3d,0x3a,0x77,0xb5,0x7a,0x74,0xae,0x73,0x3a,0xbf,0x19,0x3d,0x69,0x50,0x53,0x6f,0x44,0x1d,0xbe,0x01,0xea,0x89,0xc2,0x7b,0x38,0x35,0x75,0xbb,0x87,0x03,0x6d,0xfc,0xad, +0x61,0x8a,0x58,0x28,0x28,0x59,0x90,0x67,0x03,0x46,0x00,0x00,0x00,0x01,0x00,0x0a,0x00,0x00,0x04,0xc2,0x05,0x45,0x00,0x10,0x00,0x82,0x40,0x55,0x0f,0x20,0x0e,0x11,0x48,0x29,0x0f,0x39,0x0f,0x02,0x2b,0x0f,0x01,0x76,0x03,0x86,0x03,0x02,0x54,0x03,0x64,0x03,0x02,0x36,0x03,0x46,0x03,0x02,0x24,0x03,0x01,0x00,0x01,0x52,0x0f,0x09, +0x0f,0x5e,0x10,0x00,0x14,0x10,0x10,0x00,0x01,0x01,0x52,0x03,0x09,0x03,0x5e,0x02,0x01,0x14,0x02,0x01,0x03,0x02,0x09,0x02,0x10,0x10,0x01,0x10,0x10,0x12,0x7f,0x02,0x8f,0x02,0x02,0x02,0x0f,0x02,0x03,0x55,0x09,0x01,0x44,0x09,0x01,0x09,0x00,0x01,0x12,0x00,0x3f,0x33,0x33,0x5d,0x5d,0x3f,0x33,0x01,0x2f,0x5d,0x11,0x33,0x2f,0x5d, +0x12,0x39,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87,0x2b,0xc4,0x87,0x18,0x10,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x01,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x2b,0x21,0x23,0x01,0x33,0x01,0x1e,0x01,0x17,0x16,0x17,0x36,0x37,0x3e,0x01,0x37,0x01,0x33,0x02,0xc9,0xc6,0xfe,0x07,0xc9,0x01,0x40,0x10,0x1d,0x0c,0x0e,0x0d,0x0c,0x0e,0x0c,0x1e,0x10,0x01, +0x3e,0xc9,0x05,0x45,0xfc,0x7a,0x2d,0x61,0x2a,0x30,0x2f,0x2d,0x30,0x29,0x62,0x2f,0x03,0x86,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0xcc,0x05,0x45,0x00,0x32,0x01,0x4c,0x40,0x11,0x21,0x08,0x0c,0x00,0x4d,0x02,0x18,0x10,0x00,0x4d,0x02,0x18,0x0b,0x0c,0x00,0x4c,0x10,0xb8,0xff,0xe8,0xb4,0x0b,0x0c,0x00,0x4c,0x1a,0xb8,0xff, +0xf0,0x40,0x10,0x10,0x11,0x00,0x4c,0x31,0x18,0x11,0x00,0x4d,0x31,0x18,0x0b,0x0c,0x00,0x4c,0x14,0xb8,0xff,0xf0,0xb4,0x0b,0x0c,0x00,0x4c,0x23,0xb8,0xff,0xe0,0x40,0x1c,0x0b,0x0f,0x00,0x4c,0x22,0x18,0x0b,0x0f,0x00,0x4c,0x22,0x10,0x0a,0x00,0x4d,0x01,0x20,0x0b,0x11,0x00,0x4c,0x00,0x20,0x10,0x11,0x00,0x4c,0x00,0xb8,0xff,0xe0, +0xb4,0x0d,0x0e,0x00,0x4c,0x00,0xb8,0xff,0xe0,0xb4,0x09,0x0a,0x00,0x4c,0x12,0xb8,0xff,0xf0,0x40,0x11,0x10,0x11,0x00,0x4c,0x12,0x28,0x0d,0x0e,0x00,0x4c,0x12,0x28,0x09,0x0a,0x00,0x4c,0x11,0xb8,0xff,0xe0,0x40,0x13,0x0b,0x11,0x00,0x4c,0x22,0x09,0x32,0x09,0x02,0x02,0x04,0x09,0x01,0x01,0x01,0x52,0x23,0x2b,0x23,0xb8,0x01,0x07, +0x40,0x0c,0x09,0x01,0x14,0x09,0x01,0x23,0x11,0x01,0x52,0x22,0x1a,0x22,0xb8,0x01,0x07,0x40,0x48,0x09,0x11,0x14,0x09,0x09,0x11,0x00,0x01,0x52,0x31,0x2b,0x31,0x5e,0x32,0x00,0x14,0x32,0x32,0x00,0x12,0x01,0x52,0x14,0x1a,0x14,0x5e,0x13,0x12,0x14,0x13,0x12,0x14,0x13,0x2b,0x09,0x1a,0x03,0x13,0x10,0x32,0x01,0x32,0x32,0x34,0x13, +0x09,0x2f,0x22,0x4f,0x22,0x5f,0x22,0x03,0x22,0x22,0x1a,0x31,0x13,0x03,0x2b,0x1a,0x00,0x01,0x24,0x1a,0x01,0x1a,0x11,0x01,0x03,0x12,0x12,0x00,0x3f,0x17,0x33,0x5d,0x11,0x33,0x11,0x33,0x3f,0x33,0x12,0x39,0x2f,0x5d,0x33,0x01,0x2f,0x11,0x33,0x2f,0x5d,0x12,0x17,0x39,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87,0x2b,0xc4,0x87,0x18,0x10, +0x2b,0x87,0x2b,0xc4,0x87,0x18,0x10,0x2b,0x87,0x2b,0xc4,0x00,0xc1,0x87,0x05,0x18,0x2b,0x87,0x2b,0xc4,0x00,0x5d,0x5f,0x5d,0x01,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x31,0x30,0x2b,0x2b,0x2b,0x2b,0x21,0x23,0x03,0x2e,0x03,0x27,0x26,0x27,0x06,0x07,0x0e,0x03,0x07,0x03,0x23,0x03,0x33,0x13, +0x1e,0x01,0x17,0x16,0x17,0x36,0x37,0x3e,0x03,0x37,0x13,0x33,0x13,0x1e,0x03,0x17,0x16,0x17,0x32,0x3e,0x02,0x37,0x13,0x33,0x03,0xfa,0xd0,0x68,0x05,0x0e,0x0f,0x0f,0x07,0x11,0x11,0x12,0x11,0x07,0x0f,0x0f,0x0e,0x05,0x6a,0xd0,0xd3,0xbd,0x6d,0x08,0x0b,0x05,0x05,0x04,0x10,0x10,0x07,0x0e,0x0f,0x0e,0x06,0x6d,0xaf,0x6d,0x06,0x0e, +0x0f,0x0e,0x07,0x10,0x10,0x01,0x06,0x0a,0x0c,0x06,0x68,0xbd,0x01,0x83,0x13,0x34,0x3b,0x3f,0x1e,0x46,0x4c,0x4d,0x46,0x1e,0x3f,0x3b,0x33,0x13,0xfe,0x7d,0x05,0x45,0xfc,0xbd,0x41,0x7c,0x31,0x39,0x33,0x45,0x43,0x1d,0x3d,0x3c,0x37,0x17,0x01,0x8f,0xfe,0x71,0x16,0x38,0x3b,0x3d,0x1d,0x43,0x46,0x44,0x66,0x7a,0x36,0x03,0x43,0x00, +0x00,0x01,0x00,0x24,0x00,0x00,0x04,0xa9,0x05,0x45,0x00,0x0b,0x00,0xc8,0x40,0x5c,0x09,0x09,0x01,0x0b,0x06,0x01,0x09,0x03,0x59,0x03,0x02,0x29,0x01,0x01,0x04,0x01,0x01,0x03,0x02,0x07,0x00,0x01,0x08,0x0b,0x04,0x0b,0x06,0x02,0x07,0x09,0x01,0x08,0x0a,0x05,0x0a,0x06,0x03,0x02,0x07,0x02,0x09,0x00,0x01,0x07,0x02,0x01,0x52,0x01, +0x08,0x07,0x08,0x01,0x5e,0x02,0x07,0x14,0x02,0x02,0x07,0x05,0x0a,0x01,0x52,0x0b,0x04,0x05,0x04,0x0b,0x5e,0x0a,0x05,0x14,0x0a,0x05,0x0b,0x0a,0x10,0x0a,0x20,0x0a,0x02,0x02,0x0a,0x02,0x0a,0x03,0x06,0x00,0x09,0x04,0x08,0x04,0xb8,0xff,0xc0,0x40,0x18,0x0a,0x1c,0x48,0x04,0x04,0x0d,0x08,0x40,0x0b,0x1b,0x48,0x08,0x00,0x09,0x03, +0x06,0x04,0x01,0x08,0x04,0x12,0x0a,0x01,0x03,0x00,0x3f,0x33,0x3f,0x33,0x12,0x17,0x39,0x01,0x2f,0x2b,0x11,0x33,0x2f,0x2b,0x12,0x17,0x39,0x39,0x39,0x2f,0x2f,0x71,0x10,0x00,0xc1,0x87,0x05,0x2b,0x10,0x00,0xc1,0x87,0x05,0x2b,0x10,0xc4,0x87,0x18,0x10,0x2b,0x10,0x00,0xc1,0x87,0x05,0x2b,0x10,0xc4,0x10,0xc0,0xc0,0x10,0x87,0xc0, +0xc0,0x10,0x87,0x08,0xc0,0x08,0xc0,0x10,0x87,0x08,0xc0,0x08,0xc0,0x31,0x30,0x01,0x5d,0x5d,0x00,0x5d,0x5d,0x5d,0x09,0x01,0x33,0x09,0x01,0x23,0x09,0x01,0x23,0x09,0x01,0x33,0x02,0x66,0x01,0x4d,0xcd,0xfe,0x4d,0x01,0xdc,0xcd,0xfe,0x8a,0xfe,0x8b,0xcd,0x01,0xdc,0xfe,0x4d,0xcd,0x03,0x44,0x02,0x01,0xfd,0x7c,0xfd,0x3f,0x02,0x3d, +0xfd,0xc3,0x02,0xc1,0x02,0x84,0x00,0x00,0x00,0x01,0x00,0x24,0x00,0x00,0x04,0xa8,0x05,0x45,0x00,0x08,0x00,0x96,0x40,0x68,0x34,0x06,0x44,0x06,0x54,0x06,0x03,0x5c,0x07,0x01,0x3b,0x07,0x4b,0x07,0x02,0x09,0x07,0x19,0x07,0x29,0x07,0x03,0x53,0x05,0x01,0x34,0x05,0x44,0x05,0x02,0x03,0x00,0x05,0x10,0x05,0x20,0x05,0x03,0x0c,0x05, +0x07,0x08,0x0e,0x01,0x04,0x02,0x0e,0x05,0x2f,0x04,0x01,0x04,0x06,0x01,0x5a,0x0f,0x02,0x3f,0x02,0x8f,0x02,0x9f,0x02,0xbf,0x02,0xcf,0x02,0x06,0x4f,0x02,0x5f,0x02,0x7f,0x02,0x8f,0x02,0x04,0x10,0x02,0x01,0x02,0x02,0x0a,0x09,0x06,0x03,0x40,0x00,0x50,0x00,0x60,0x00,0x03,0x3f,0x00,0x01,0x00,0x00,0x01,0x07,0x04,0x03,0x01,0x12, +0x00,0x3f,0x3f,0x33,0x12,0x39,0x2f,0x5d,0x5d,0x33,0x33,0x11,0x12,0x01,0x39,0x2f,0x5d,0x5d,0x71,0xed,0x39,0xc6,0x5d,0x32,0x2b,0x01,0x18,0x10,0x4d,0xe6,0x32,0x31,0x30,0x5f,0x5e,0x5d,0x5f,0x5d,0x5d,0x5d,0x5d,0x5d,0x00,0x5d,0x01,0x11,0x23,0x11,0x01,0x33,0x09,0x01,0x33,0x02,0xc4,0xbc,0xfe,0x1c,0xcd,0x01,0x76,0x01,0x74,0xcd, +0x02,0x48,0xfd,0xb8,0x02,0x48,0x02,0xfd,0xfd,0x9d,0x02,0x63,0x00,0x01,0x00,0x49,0x00,0x00,0x04,0x83,0x05,0x45,0x00,0x09,0x00,0x75,0x40,0x26,0x89,0x08,0x01,0x69,0x08,0x01,0x57,0x08,0x77,0x08,0x02,0x29,0x08,0x39,0x08,0x49,0x08,0x03,0x04,0x08,0x14,0x08,0x02,0x08,0x01,0x52,0x03,0x02,0x03,0x5e,0x07,0x08,0x14,0x07,0x08,0x03, +0x07,0x04,0xb8,0xff,0xc0,0xb3,0x0f,0x14,0x48,0x00,0xb8,0xff,0xc0,0x40,0x1d,0x09,0x0e,0x48,0x04,0x07,0x00,0x00,0x07,0x04,0x03,0x0b,0x2f,0x01,0x3f,0x01,0x4f,0x01,0x03,0x01,0x07,0x04,0x5f,0x05,0x03,0x02,0x08,0x5f,0x01,0x12,0x00,0x3f,0xed,0x32,0x3f,0xed,0x32,0x01,0x2f,0x5d,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x2b,0x2b,0x10,0x00, +0xc1,0x87,0x05,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x01,0x5d,0x5d,0x5d,0x5d,0x5d,0x29,0x01,0x35,0x01,0x21,0x35,0x21,0x15,0x01,0x21,0x04,0x83,0xfb,0xc6,0x03,0x32,0xfd,0x17,0x03,0xc2,0xfc,0xce,0x03,0x61,0x8f,0x04,0x1a,0x9c,0x8b,0xfb,0xe2,0x00,0x00,0x00,0x01,0x01,0x9a,0xfe,0x57,0x03,0xbd,0x05,0xcc,0x00,0x07,0x00,0x2f,0x40,0x1c, +0x02,0x07,0x07,0x09,0x05,0xf2,0x7f,0x00,0x8f,0x00,0x02,0x3f,0x00,0x6f,0x00,0x02,0x00,0x00,0x01,0x00,0x04,0xf5,0x01,0x00,0x05,0xf5,0x00,0x1b,0x00,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x5d,0x5d,0x5d,0xed,0x12,0x39,0x2f,0x33,0x31,0x30,0x01,0x11,0x21,0x15,0x21,0x11,0x21,0x15,0x01,0x9a,0x02,0x23,0xfe,0x91,0x01,0x6f,0xfe,0x57,0x07, +0x75,0x8b,0xf9,0xa1,0x8b,0x00,0x00,0x00,0x00,0x01,0x00,0x73,0xff,0xec,0x04,0x5a,0x05,0xcc,0x00,0x03,0x00,0x3f,0x40,0x1d,0x8b,0x00,0x01,0x7a,0x00,0x01,0x39,0x00,0x69,0x00,0x02,0x00,0x03,0x10,0x03,0x03,0x05,0x85,0x02,0x01,0x36,0x02,0x66,0x02,0x76,0x02,0x03,0x02,0x01,0xb8,0xff,0xf0,0xb7,0x00,0x01,0x01,0x01,0x02,0x00,0x00, +0x19,0x00,0x3f,0x3f,0x01,0x2f,0x5d,0x38,0x33,0x5d,0x5d,0x12,0x39,0x2f,0x38,0x33,0x5d,0x5d,0x5d,0x31,0x30,0x05,0x01,0x33,0x01,0x03,0xa4,0xfc,0xcf,0xb2,0x03,0x35,0x14,0x05,0xe0,0xfa,0x20,0x00,0x00,0x00,0x00,0x01,0x01,0x0e,0xfe,0x57,0x03,0x31,0x05,0xcc,0x00,0x07,0x00,0x29,0x40,0x17,0x07,0xf2,0x60,0x02,0x01,0x02,0x02,0x09, +0x04,0x00,0x00,0x30,0x00,0x02,0x00,0x04,0xf5,0x05,0x00,0x01,0xf5,0x00,0x1b,0x00,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x5d,0x33,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x01,0x35,0x21,0x11,0x21,0x35,0x21,0x11,0x01,0x0e,0x01,0x6f,0xfe,0x91,0x02,0x23,0xfe,0x57,0x8b,0x06,0x5f,0x8b,0xf8,0x8b,0x00,0x00,0x01,0x00,0x85,0x01,0xba,0x04,0x46, +0x05,0x45,0x00,0x06,0x00,0x63,0x40,0x2f,0x85,0x05,0x01,0x79,0x04,0x89,0x04,0x02,0x05,0x04,0x01,0x8c,0x00,0x01,0x29,0x00,0x69,0x00,0x79,0x00,0x03,0x00,0x01,0x03,0x06,0x10,0x00,0x06,0x10,0x06,0x70,0x06,0x80,0x06,0x04,0x06,0x06,0x08,0x66,0x02,0x76,0x02,0x86,0x02,0x03,0x02,0x03,0xb8,0xff,0xf0,0x40,0x0f,0x00,0x03,0x01,0x03, +0x00,0x01,0x10,0x01,0x02,0x02,0x00,0x00,0x01,0x04,0x03,0x00,0x3f,0x33,0x33,0x2f,0x32,0x5d,0x01,0x2f,0x5d,0x38,0x33,0x5d,0x12,0x39,0x2f,0x5d,0x38,0x12,0x39,0x33,0x5d,0x5d,0x11,0x33,0x33,0x5d,0x5d,0x31,0x30,0x09,0x02,0x23,0x01,0x33,0x01,0x03,0xac,0xfe,0xb7,0xfe,0xba,0x98,0x01,0x7a,0xcb,0x01,0x7c,0x01,0xba,0x03,0x23,0xfc, +0xdd,0x03,0x8b,0xfc,0x75,0x00,0x00,0x00,0x00,0x01,0xff,0xfb,0xff,0x24,0x04,0xd1,0xff,0x84,0x00,0x03,0x00,0x0e,0xb4,0x03,0x00,0x00,0xbb,0x01,0x00,0x2f,0xed,0x01,0x2f,0x2f,0x31,0x30,0x07,0x35,0x21,0x15,0x05,0x04,0xd6,0xdc,0x60,0x60,0x00,0x00,0x00,0x01,0x01,0x92,0x04,0xb1,0x03,0x3a,0x05,0xb4,0x00,0x05,0x00,0x1a,0x40,0x0e, +0x74,0x03,0x84,0x03,0x02,0x80,0x04,0x01,0x04,0x01,0x03,0x8c,0x00,0x93,0x00,0x3f,0xed,0x01,0x2f,0xcd,0x5d,0x31,0x30,0x5d,0x01,0x25,0x35,0x33,0x17,0x15,0x02,0xbe,0xfe,0xd4,0xc5,0xe3,0x04,0xb1,0xe6,0x1d,0xef,0x14,0x00,0x00,0x00,0x02,0x00,0x80,0xff,0xec,0x04,0x88,0x04,0x4e,0x00,0x32,0x00,0x41,0x00,0xa5,0x40,0x3f,0x8a,0x24, +0x01,0x7a,0x1e,0x8a,0x1e,0x02,0x69,0x3d,0x79,0x3d,0x89,0x3d,0x03,0x25,0x36,0x35,0x36,0x02,0x13,0x20,0x09,0x0c,0x48,0x06,0x17,0x16,0x17,0x02,0x1d,0x09,0x2d,0x09,0x3d,0x09,0x03,0x05,0x2d,0x15,0x2d,0x02,0x00,0x03,0x01,0x03,0x03,0x30,0x46,0x1b,0x0c,0x4f,0x38,0x5f,0x38,0x02,0x38,0x38,0x15,0x43,0x26,0x47,0x27,0xb8,0xff,0xf8, +0x40,0x2d,0xc0,0x27,0x01,0x27,0x27,0x3f,0x47,0x00,0x15,0x01,0x15,0x39,0x51,0x1b,0x1b,0x33,0x2c,0x0f,0x26,0x1f,0x26,0x02,0x2f,0x26,0x8f,0x26,0xff,0x26,0x03,0x26,0x26,0x21,0x50,0x2c,0x10,0x33,0x50,0x12,0x00,0x51,0x07,0x07,0x0c,0x12,0x16,0x00,0x3f,0x33,0x33,0x2f,0xed,0x10,0xed,0x3f,0xed,0x33,0x2f,0x5d,0x71,0x11,0x12,0x39, +0x2f,0xed,0x01,0x2f,0x5d,0xed,0x33,0x2f,0x5d,0x38,0xed,0x11,0x12,0x39,0x2f,0x5d,0x33,0x33,0xed,0x32,0x2f,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x2b,0x5d,0x5d,0x5d,0x5d,0x25,0x32,0x36,0x37,0x15,0x0e,0x01,0x23,0x22,0x2e,0x02,0x27,0x23,0x0e,0x03,0x23,0x22,0x26,0x35,0x34,0x3e,0x02,0x3f,0x01,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e, +0x02,0x07,0x27,0x3e,0x03,0x33,0x32,0x16,0x15,0x11,0x14,0x16,0x25,0x32,0x3e,0x02,0x3d,0x01,0x07,0x0e,0x03,0x15,0x14,0x16,0x04,0x4d,0x0f,0x1e,0x0e,0x22,0x43,0x26,0x33,0x49,0x2e,0x18,0x03,0x06,0x1c,0x44,0x58,0x72,0x4a,0x9e,0xa0,0x4f,0x80,0xa3,0x54,0xec,0x1b,0x37,0x54,0x38,0x32,0x51,0x3a,0x25,0x06,0xbc,0x0a,0x37,0x64,0x97, +0x6b,0xc8,0xc9,0x2a,0xfd,0xda,0x53,0x7a,0x51,0x28,0xbe,0x37,0x6f,0x59,0x38,0x59,0x6f,0x04,0x03,0x70,0x08,0x08,0x1b,0x37,0x51,0x36,0x34,0x54,0x3b,0x20,0xac,0x96,0x6b,0x89,0x4e,0x1f,0x01,0x04,0x3b,0x43,0x5e,0x3a,0x1b,0x0f,0x27,0x43,0x33,0x11,0x40,0x6b,0x4e,0x2b,0xbb,0xb1,0xfe,0x2e,0x50,0x51,0x06,0x3f,0x60,0x74,0x35,0x59, +0x04,0x01,0x0f,0x30,0x5b,0x4c,0x52,0x64,0x00,0x02,0x00,0xb3,0xff,0xec,0x04,0x42,0x05,0xcc,0x00,0x20,0x00,0x34,0x00,0x61,0x40,0x42,0x7a,0x02,0x8a,0x02,0x02,0x44,0x33,0x54,0x33,0x64,0x33,0x03,0x4b,0x23,0x5b,0x23,0x6b,0x23,0x03,0x3a,0x05,0x01,0x35,0x1c,0x01,0x05,0x1f,0x15,0x1f,0x75,0x1f,0x85,0x1f,0x04,0x00,0x47,0x60,0x21, +0x01,0x21,0x21,0x36,0x2b,0x06,0x14,0x46,0x00,0x13,0x80,0x13,0x02,0x13,0x26,0x50,0x1a,0x1e,0x10,0x13,0x00,0x0d,0x15,0x30,0x50,0x06,0x03,0x16,0x00,0x3f,0x33,0xed,0x3f,0x3f,0x3f,0x33,0xed,0x01,0x2f,0x5d,0xed,0x32,0x32,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x10,0x02,0x23,0x22,0x26,0x27, +0x23,0x14,0x0e,0x02,0x07,0x23,0x3e,0x03,0x35,0x11,0x33,0x11,0x14,0x06,0x07,0x06,0x07,0x33,0x3e,0x01,0x33,0x32,0x12,0x03,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x04,0x42,0xcb,0xbd,0x74,0xaa,0x30,0x02,0x02,0x03,0x03,0x01,0xae,0x01,0x02,0x02,0x01,0xb4,0x01,0x01,0x01,0x01,0x04,0x30,0xa9, +0x75,0xc3,0xc4,0xba,0x1e,0x3f,0x5f,0x42,0x42,0x6a,0x49,0x28,0x28,0x49,0x69,0x41,0x3f,0x60,0x40,0x21,0x02,0x22,0xfe,0xe4,0xfe,0xe6,0x56,0x62,0x1a,0x37,0x2e,0x21,0x04,0x09,0x2b,0x3c,0x48,0x27,0x04,0xed,0xfe,0x59,0x1d,0x39,0x16,0x1a,0x17,0x69,0x5f,0xfe,0xeb,0xfe,0xe1,0x70,0xa1,0x67,0x31,0x2d,0x67,0xa9,0x7c,0x77,0x9e,0x5f, +0x27,0x2e,0x66,0xa3,0x00,0x01,0x00,0x82,0xff,0xec,0x04,0x38,0x04,0x4e,0x00,0x25,0x00,0x9d,0x40,0x52,0x64,0x16,0x01,0x64,0x10,0x01,0x79,0x1e,0x89,0x1e,0x02,0x64,0x1a,0x01,0x44,0x15,0x54,0x15,0x02,0x4b,0x11,0x5b,0x11,0x02,0x75,0x08,0x85,0x08,0x02,0x0b,0x47,0x0a,0x0a,0x1c,0x47,0x3f,0x1b,0x4f,0x1b,0x8f,0x1b,0x9f,0x1b,0xaf, +0x1b,0x05,0xcf,0x1b,0xdf,0x1b,0xff,0x1b,0x03,0x60,0x1b,0x01,0x1b,0x1b,0x27,0x13,0x47,0x00,0x00,0x01,0x00,0x70,0x1b,0x01,0x00,0x1b,0x10,0x1b,0x60,0x1b,0x70,0x1b,0x80,0x1b,0xc0,0x1b,0x06,0x1b,0xb8,0xff,0xc0,0x40,0x1c,0x1b,0x1e,0x48,0x1b,0x1b,0x18,0x50,0x21,0x16,0x0e,0x50,0x05,0x1f,0x0b,0x7f,0x0b,0x8f,0x0b,0x03,0x0b,0x40, +0x1b,0x1e,0x48,0x0b,0x0b,0x05,0x10,0x00,0x3f,0x33,0x2f,0x2b,0x5d,0x10,0xed,0x3f,0xed,0x33,0x2f,0x2b,0x5d,0x71,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x5d,0x71,0xed,0x32,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x13,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x01,0x23,0x22,0x0e,0x02,0x15, +0x14,0x1e,0x02,0x33,0x32,0x36,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x82,0x56,0x8d,0xb4,0x5f,0x62,0x9a,0x6f,0x46,0x0d,0xc0,0x10,0x80,0x76,0x56,0x75,0x47,0x1f,0x1f,0x47,0x75,0x55,0x6c,0x8e,0x11,0xbe,0x09,0x44,0x72,0x9e,0x64,0x89,0xbf,0x77,0x36,0x02,0x1e,0xa3,0xd8,0x80,0x35,0x32,0x57,0x76,0x44,0x0e,0x5b,0x69,0x37,0x69, +0x9b,0x64,0x64,0x9f,0x6e,0x3a,0x6a,0x6d,0x0c,0x43,0x7c,0x5e,0x39,0x56,0x97,0xcd,0x00,0x02,0x00,0x8a,0xff,0xe6,0x04,0x19,0x05,0xcc,0x00,0x1f,0x00,0x33,0x00,0x6b,0x40,0x4b,0x44,0x22,0x54,0x22,0x64,0x22,0x03,0x4b,0x32,0x5b,0x32,0x6b,0x32,0x03,0x3a,0x01,0x6a,0x01,0x02,0x35,0x0a,0x01,0x05,0x07,0x15,0x07,0x75,0x07,0x85,0x07, +0x04,0x0a,0x04,0x1a,0x04,0x7a,0x04,0x8a,0x04,0x04,0x13,0x46,0x2a,0x00,0x50,0x12,0x01,0x90,0x12,0xa0,0x12,0x02,0x12,0x12,0x35,0x20,0x47,0x00,0x06,0x01,0x06,0x1a,0x15,0x12,0x00,0x2f,0x50,0x0b,0x08,0x10,0x25,0x50,0x00,0x03,0x16,0x00,0x3f,0x33,0xed,0x3f,0x33,0xed,0x3f,0x3f,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0x33, +0x33,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x25,0x0e,0x01,0x23,0x22,0x02,0x11,0x10,0x21,0x32,0x16,0x17,0x33,0x34,0x26,0x34,0x26,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x17,0x23,0x2e,0x03,0x35,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x03,0x5e,0x31,0xa2,0x79,0xca,0xbe,0x01, +0x88,0x79,0xa3,0x31,0x02,0x01,0x01,0xb4,0x01,0x02,0x02,0x01,0xac,0x01,0x04,0x03,0x02,0xfd,0xe1,0x1d,0x3d,0x60,0x43,0x45,0x6b,0x49,0x25,0x25,0x48,0x6a,0x45,0x40,0x60,0x3f,0x20,0xae,0x69,0x5f,0x01,0x16,0x01,0x18,0x02,0x36,0x56,0x62,0x05,0x2a,0x32,0x2d,0x09,0x01,0xa3,0xfb,0x13,0x27,0x48,0x3c,0x2b,0x09,0x04,0x24,0x32,0x3a, +0x1a,0x01,0x6c,0x70,0xa0,0x68,0x31,0x30,0x69,0xa8,0x78,0x74,0x9d,0x60,0x2a,0x2e,0x66,0xa3,0x00,0x00,0x00,0x02,0x00,0x85,0xff,0xec,0x04,0x46,0x04,0x4e,0x00,0x20,0x00,0x2b,0x00,0x90,0x40,0x65,0x64,0x24,0x01,0x64,0x03,0x01,0x49,0x29,0x59,0x29,0x69,0x29,0x03,0x49,0x24,0x59,0x24,0x02,0x75,0x1d,0x85,0x1d,0x02,0x77,0x1c,0x87, +0x1c,0x02,0x78,0x0e,0x88,0x0e,0x02,0x7a,0x0d,0x8a,0x0d,0x02,0x44,0x02,0x54,0x02,0x64,0x02,0x03,0x27,0x47,0x1f,0x1f,0x0b,0x49,0xcf,0x0a,0xdf,0x0a,0xff,0x0a,0x03,0x00,0x0a,0x10,0x0a,0x60,0x0a,0x03,0x0a,0x0a,0x2d,0x26,0x00,0x47,0x00,0x15,0xe0,0x15,0x02,0x15,0x00,0x50,0x26,0x26,0x05,0x21,0x50,0x1a,0x10,0x05,0x50,0x10,0xdf, +0x0a,0xef,0x0a,0x02,0x80,0x0a,0x01,0x0a,0x0a,0x10,0x16,0x00,0x3f,0x33,0x2f,0x5d,0x5d,0x10,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0x5d,0xed,0x32,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03, +0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x1d,0x01,0x01,0x22,0x0e,0x02,0x07,0x21,0x2e,0x03,0x01,0x42,0x26,0x4c,0x71,0x4a,0x37,0x5d,0x4a,0x32,0x0c,0x9e,0x10,0x40,0x6a,0x98,0x68,0x73,0xb6,0x7e,0x43,0x4f,0x86,0xaf,0x60,0x83,0xb5,0x72,0x33,0xfe,0x25,0x2e,0x65,0x56,0x3b,0x03,0x02,0x48,0x08,0x34,0x4d,0x62, +0x01,0xf7,0x55,0x8f,0x67,0x39,0x19,0x2c,0x3d,0x24,0x2d,0x2d,0x5b,0x49,0x2f,0x48,0x8e,0xd5,0x8d,0x9c,0xd4,0x82,0x38,0x54,0x97,0xd4,0x80,0x18,0x01,0xd2,0x1d,0x4a,0x7f,0x62,0x5e,0x7e,0x4c,0x20,0x00,0x00,0x00,0x01,0x00,0x8a,0x00,0x00,0x04,0x4b,0x05,0xcc,0x00,0x1f,0x00,0x5e,0xb9,0x00,0x0a,0xff,0xf0,0x40,0x36,0x09,0x0c,0x48, +0x1d,0x01,0x46,0x02,0x3f,0x05,0x01,0x05,0x05,0x06,0x02,0x1e,0x1e,0x11,0x2f,0x02,0x3f,0x02,0x6f,0x02,0x7f,0x02,0x8f,0x02,0x05,0x02,0x40,0x14,0x25,0x48,0x00,0x02,0x01,0x02,0x11,0x02,0x11,0x20,0x21,0x17,0x50,0x0c,0x00,0x00,0x04,0x50,0x1d,0x05,0x0f,0x01,0x15,0x00,0x3f,0x3f,0x33,0xed,0x32,0x3f,0xed,0x11,0x12,0x01,0x39,0x39, +0x2f,0x2f,0x5d,0x2b,0x5d,0x11,0x33,0x2f,0x11,0x33,0x33,0x2f,0x5d,0x10,0xed,0x32,0x31,0x30,0x00,0x2b,0x01,0x11,0x23,0x11,0x21,0x35,0x21,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x15,0x2e,0x03,0x23,0x22,0x0e,0x02,0x1d,0x01,0x21,0x15,0x02,0x44,0xb4,0xfe,0xfa,0x01,0x06,0x2d,0x64,0x9f,0x72,0x1d,0x50,0x50,0x47,0x15,0x12, +0x48,0x4f,0x48,0x13,0x42,0x62,0x40,0x1f,0x01,0xeb,0x03,0xac,0xfc,0x54,0x03,0xac,0x8e,0x19,0x65,0x8f,0x5b,0x2a,0x03,0x06,0x08,0x04,0x91,0x03,0x06,0x05,0x03,0x14,0x36,0x5e,0x4b,0x0a,0x8e,0x00,0x00,0x00,0x00,0x02,0x00,0x8f,0xfe,0x58,0x04,0x1e,0x04,0x4b,0x00,0x31,0x00,0x45,0x00,0x9c,0x40,0x3e,0x7a,0x30,0x8a,0x30,0x02,0x66, +0x3f,0x01,0x45,0x0c,0x55,0x0c,0x65,0x0c,0x03,0x4b,0x3a,0x5b,0x3a,0x6b,0x3a,0x03,0x35,0x21,0x01,0x05,0x1d,0x15,0x1d,0x75,0x1d,0x85,0x1d,0x04,0x0a,0x17,0x1a,0x17,0x7a,0x17,0x8a,0x17,0x04,0x2f,0x46,0x32,0x22,0x50,0x0e,0x01,0x90,0x0e,0xa0,0x0e,0x02,0x0e,0x0e,0x1a,0x47,0x06,0x46,0x05,0xba,0xff,0xf0,0x00,0x05,0xff,0xc0,0x40, +0x28,0x0f,0x15,0x48,0x05,0x05,0x3c,0x47,0xb0,0x1a,0x01,0x00,0x1a,0xd0,0x1a,0x02,0x1a,0x28,0x0f,0x37,0x50,0x22,0x1f,0x10,0x41,0x50,0x0f,0x15,0x15,0x09,0x50,0x00,0x20,0x06,0x30,0x06,0x02,0x06,0x06,0x00,0x1b,0x00,0x3f,0x32,0x2f,0x5d,0x10,0xed,0x3f,0x33,0xed,0x3f,0x33,0xed,0x3f,0x01,0x2f,0x5d,0x71,0xed,0x33,0x2f,0x2b,0x38, +0xed,0x11,0x12,0x39,0x2f,0x5d,0x71,0x33,0x33,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x22,0x2e,0x02,0x27,0x37,0x1e,0x01,0x33,0x32,0x3e,0x02,0x3d,0x01,0x23,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x33,0x34,0x3e,0x02,0x37,0x33,0x0e,0x03,0x15,0x11,0x14,0x06,0x13,0x34,0x2e, +0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x02,0x67,0x5a,0x89,0x63,0x3d,0x0d,0xb8,0x11,0x71,0x5c,0x39,0x5b,0x41,0x23,0x02,0x13,0x3b,0x53,0x6e,0x48,0x66,0x90,0x5c,0x2b,0x2b,0x5f,0x98,0x6e,0x71,0xa7,0x2d,0x03,0x03,0x03,0x05,0x01,0xab,0x01,0x02,0x02,0x01,0xd4,0x21,0x30,0x4f,0x65,0x35,0x43,0x62,0x40, +0x1e,0x1e,0x3f,0x61,0x42,0x35,0x66,0x50,0x31,0xfe,0x58,0x26,0x47,0x62,0x3c,0x19,0x4b,0x51,0x22,0x4b,0x78,0x56,0xc2,0x28,0x4c,0x3a,0x23,0x42,0x86,0xca,0x87,0x83,0xcc,0x8d,0x4a,0x69,0x61,0x19,0x3e,0x37,0x28,0x03,0x09,0x2b,0x3c,0x49,0x27,0xfc,0xc6,0xe3,0xe5,0x03,0xcf,0x71,0x9e,0x63,0x2c,0x2d,0x63,0x9d,0x71,0x75,0x9c,0x5e, +0x27,0x2b,0x60,0x9b,0x00,0x01,0x00,0xb9,0x00,0x00,0x04,0x19,0x05,0xcc,0x00,0x1f,0x00,0x3f,0x40,0x27,0x70,0x0e,0x80,0x0e,0x02,0x04,0x0d,0x14,0x0d,0x74,0x0d,0x84,0x0d,0x04,0x11,0x46,0x12,0x12,0x21,0x05,0x02,0x1e,0x46,0x00,0x1f,0x80,0x1f,0x02,0x1f,0x1f,0x11,0x15,0x18,0x50,0x05,0x0b,0x10,0x00,0x00,0x00,0x3f,0x3f,0x33,0xed, +0x3f,0x33,0x01,0x2f,0x5d,0xed,0x32,0x32,0x12,0x39,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x13,0x33,0x11,0x14,0x06,0x07,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0xb9,0xb5,0x06,0x03,0x03,0x18,0x40,0x52,0x69,0x40,0x53,0x82,0x5a,0x2f,0xb5,0x21,0x3b,0x50,0x30,0x3b, +0x67,0x4d,0x2c,0xb4,0x05,0xcc,0xfe,0x7a,0x32,0x65,0x2e,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfd,0x2f,0x02,0xb7,0x50,0x67,0x3d,0x18,0x2d,0x55,0x7d,0x51,0xfd,0x8d,0x00,0x00,0x00,0x00,0x02,0x00,0x8f,0x00,0x00,0x04,0x65,0x05,0xcc,0x00,0x09,0x00,0x0d,0x00,0x40,0x40,0x22,0x07,0x07,0x05,0x04,0x04,0x05,0x0b,0x4a,0x0c,0x0c, +0x01,0x01,0x00,0x46,0xa0,0x05,0x01,0x05,0x05,0x0e,0x0f,0x0a,0x53,0x0b,0x00,0x07,0x50,0x08,0x0f,0x00,0x04,0x50,0x03,0x15,0x00,0x3f,0xed,0x32,0x3f,0xed,0x3f,0xed,0x11,0x12,0x01,0x39,0x2f,0x71,0xed,0x32,0x2f,0x32,0x2f,0xed,0x11,0x33,0x2f,0x12,0x39,0x2f,0x31,0x30,0x25,0x21,0x15,0x21,0x35,0x21,0x11,0x21,0x35,0x21,0x27,0x35, +0x33,0x15,0x02,0xe9,0x01,0x7c,0xfc,0x2a,0x01,0xa6,0xfe,0xc1,0x01,0xf3,0xc8,0xc8,0x8e,0x8e,0x8e,0x03,0x1e,0x8e,0xd2,0xc0,0xc0,0x00,0x00,0x00,0x00,0x02,0x00,0x75,0xfe,0x57,0x03,0x44,0x05,0xcc,0x00,0x19,0x00,0x1d,0x00,0x45,0x40,0x28,0x75,0x13,0x85,0x13,0x02,0x0a,0x03,0x1a,0x03,0x02,0x18,0x18,0x0a,0x15,0x1a,0x4a,0x1d,0x1d, +0x00,0x46,0x00,0x15,0x01,0x15,0x15,0x1e,0x1f,0x0a,0x1a,0x53,0x1b,0x00,0x17,0x50,0x18,0x0f,0x10,0x50,0x05,0x1b,0x00,0x3f,0xed,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x11,0x12,0x39,0x2f,0x5d,0xed,0x32,0x2f,0xed,0x11,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x05,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x35,0x1e,0x03,0x33,0x32,0x3e, +0x02,0x35,0x11,0x21,0x35,0x21,0x27,0x35,0x33,0x15,0x03,0x44,0x47,0x76,0x9c,0x56,0x29,0x52,0x4c,0x41,0x18,0x16,0x3c,0x48,0x4f,0x28,0x38,0x61,0x48,0x29,0xfe,0x69,0x02,0x4b,0xc8,0xc8,0x1c,0x6d,0x97,0x5f,0x2a,0x07,0x0c,0x0f,0x09,0x8c,0x05,0x0c,0x0a,0x07,0x1c,0x3d,0x5f,0x43,0x03,0xc5,0x8e,0xd2,0xc0,0xc0,0x00,0x01,0x00,0xec, +0x00,0x00,0x04,0x65,0x05,0xcc,0x00,0x0b,0x00,0xaf,0x40,0x2c,0x66,0x07,0x76,0x07,0x86,0x07,0x03,0x64,0x09,0x74,0x09,0x84,0x09,0x03,0x7b,0x01,0x8b,0x01,0x02,0x49,0x01,0x59,0x01,0x69,0x01,0x03,0x49,0x08,0x59,0x08,0x02,0x6b,0x00,0x7b,0x00,0x8b,0x00,0x03,0x49,0x00,0x59,0x00,0x02,0x0a,0xb8,0xff,0xe8,0x40,0x28,0x0b,0x11,0x48, +0x01,0x0a,0x08,0x09,0x10,0x44,0x09,0x54,0x09,0x02,0x09,0x09,0x00,0x9f,0x0b,0xaf,0x0b,0xbf,0x0b,0x03,0x00,0x0b,0x10,0x0b,0x02,0x0b,0x10,0x0b,0x0b,0x0d,0x07,0x03,0x46,0x00,0x04,0x01,0x04,0xb8,0xff,0xc0,0xb3,0x1f,0x25,0x48,0x04,0xb8,0xff,0xc0,0xb3,0x16,0x1b,0x48,0x04,0xb8,0xff,0xc0,0x40,0x11,0x0d,0x11,0x48,0x04,0x02,0x07, +0x0a,0x01,0x07,0x01,0x08,0x0f,0x05,0x00,0x04,0x00,0x15,0x00,0x3f,0x32,0x3f,0x3f,0x39,0x39,0x11,0x33,0x11,0x33,0x01,0x2f,0x2b,0x2b,0x2b,0x5d,0xed,0x32,0x11,0x33,0x2f,0x38,0x5d,0x5d,0x33,0x33,0x2f,0x5d,0x38,0x33,0x39,0x39,0x31,0x30,0x2b,0x5d,0x5d,0x5d,0x00,0x5d,0x5d,0x01,0x5d,0x00,0x5d,0x21,0x01,0x07,0x11,0x23,0x11,0x33, +0x11,0x01,0x33,0x09,0x01,0x03,0x92,0xfe,0x92,0x84,0xb4,0xb4,0x01,0xdb,0xd3,0xfe,0x49,0x01,0xce,0x01,0xf3,0x62,0xfe,0x6f,0x05,0xcc,0xfc,0x61,0x02,0x0d,0xfe,0x2f,0xfd,0x97,0x00,0x00,0x00,0x01,0x00,0x86,0x00,0x00,0x04,0x5c,0x05,0xcc,0x00,0x09,0x00,0x33,0x40,0x1a,0x08,0x08,0x05,0x04,0x04,0x05,0x01,0x01,0x00,0x46,0xa0,0x05, +0x01,0x05,0x05,0x0a,0x0b,0x07,0x50,0x08,0x00,0x00,0x04,0x50,0x03,0x15,0x00,0x3f,0xed,0x32,0x3f,0xed,0x11,0x12,0x01,0x39,0x2f,0x71,0xed,0x32,0x2f,0x11,0x33,0x2f,0x12,0x39,0x2f,0x31,0x30,0x25,0x21,0x15,0x21,0x35,0x21,0x11,0x21,0x35,0x21,0x02,0xe0,0x01,0x7c,0xfc,0x2a,0x01,0xa6,0xfe,0xdf,0x01,0xd5,0x8e,0x8e,0x8e,0x04,0xb0, +0x8e,0x00,0x00,0x00,0x00,0x01,0x00,0x63,0x00,0x00,0x04,0x64,0x04,0x4e,0x00,0x39,0x00,0x8e,0xb9,0x00,0x2a,0xff,0xd0,0xb3,0x09,0x0f,0x48,0x20,0xb8,0xff,0xd0,0x40,0x59,0x09,0x0d,0x48,0x22,0x39,0x48,0x00,0x00,0x0d,0x2e,0x48,0xbf,0x2f,0xcf,0x2f,0xff,0x2f,0x03,0x60,0x2f,0x70,0x2f,0x02,0x1f,0x2f,0x2f,0x2f,0x3f,0x2f,0x03,0x4f, +0x2f,0x5f,0x2f,0x7f,0x2f,0x8f,0x2f,0x04,0x10,0x2f,0x20,0x2f,0x30,0x2f,0x03,0x2f,0x2f,0x3b,0x19,0x0c,0x48,0x00,0x0d,0x10,0x0d,0x02,0xf0,0x0d,0x01,0x0f,0x0d,0x3f,0x0d,0x02,0xcf,0x0d,0xdf,0x0d,0x02,0x10,0x0d,0x01,0x0d,0x35,0x06,0x50,0x19,0x22,0x28,0x03,0x1f,0x10,0x13,0x0f,0x2f,0x0d,0x00,0x15,0x00,0x3f,0x32,0x32,0x3f,0x3f, +0x17,0x33,0xed,0x32,0x01,0x2f,0x5d,0x5d,0x71,0x71,0x72,0xed,0x32,0x12,0x39,0x2f,0x5d,0x5d,0x71,0x71,0x71,0xed,0x12,0x39,0x2f,0xed,0x39,0x31,0x30,0x00,0x2b,0x2b,0x21,0x11,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x15,0x33,0x3e,0x03,0x33,0x32,0x16,0x17,0x33,0x3e,0x03,0x33, +0x32,0x1e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x23,0x22,0x06,0x15,0x11,0x02,0x13,0x0c,0x1b,0x2b,0x20,0x21,0x34,0x26,0x14,0xa9,0x01,0x02,0x02,0x01,0x95,0x01,0x02,0x02,0x01,0x02,0x0d,0x24,0x33,0x46,0x2e,0x58,0x57,0x13,0x02,0x12,0x2b,0x38,0x48,0x2f,0x3d,0x54,0x34,0x17,0xa8,0x0c,0x1b,0x2b,0x20,0x42,0x4d,0x02,0xae,0x4f, +0x6a,0x41,0x1b,0x33,0x5d,0x83,0x51,0xfd,0xa1,0x03,0x53,0x22,0x4b,0x43,0x30,0x07,0x05,0x29,0x35,0x38,0x14,0x27,0x47,0x36,0x1f,0x60,0x64,0x2f,0x49,0x32,0x1a,0x2c,0x5c,0x90,0x65,0xfd,0x2f,0x02,0xae,0x4f,0x6a,0x41,0x1b,0xa8,0xa8,0xfd,0x8d,0x00,0x00,0x01,0x00,0xb3,0x00,0x00,0x04,0x19,0x04,0x4e,0x00,0x25,0x00,0x3d,0x40,0x26, +0x70,0x22,0x80,0x22,0x02,0x04,0x21,0x14,0x21,0x74,0x21,0x84,0x21,0x04,0x25,0x46,0x00,0x00,0x27,0x19,0x0c,0x46,0x00,0x0d,0x80,0x0d,0x02,0x0d,0x19,0x06,0x50,0x1f,0x10,0x13,0x0f,0x0d,0x00,0x15,0x00,0x3f,0x32,0x3f,0x3f,0xed,0x33,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x21,0x11,0x34,0x2e,0x02, +0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x15,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x11,0x03,0x64,0x21,0x3b,0x50,0x30,0x3b,0x67,0x4d,0x2c,0xb4,0x01,0x02,0x02,0x01,0xaa,0x01,0x02,0x03,0x02,0x03,0x18,0x41,0x55,0x6a,0x42,0x53,0x80,0x57,0x2d,0x02,0xb7,0x50,0x67,0x3d,0x18,0x2d,0x55,0x7d, +0x51,0xfd,0x8d,0x03,0x53,0x22,0x4b,0x43,0x30,0x07,0x05,0x2c,0x39,0x3b,0x14,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfd,0x2f,0x00,0x00,0x00,0x00,0x02,0x00,0x82,0xff,0xec,0x04,0x49,0x04,0x4e,0x00,0x0f,0x00,0x23,0x00,0x59,0x40,0x3d,0x64,0x22,0x01,0x46,0x22,0x56,0x22,0x02,0x64,0x1c,0x01,0x46,0x1c,0x56,0x1c,0x02,0x6b,0x18, +0x01,0x49,0x18,0x59,0x18,0x02,0x6b,0x12,0x01,0x49,0x12,0x59,0x12,0x02,0x00,0x47,0xaf,0x10,0x01,0x00,0x10,0x10,0x10,0x60,0x10,0x03,0x10,0x10,0x25,0x1a,0x47,0x00,0x0a,0x01,0x0a,0x15,0x50,0x0d,0x10,0x1f,0x50,0x05,0x16,0x00,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d, +0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x10,0x12,0x33,0x32,0x12,0x03,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x04,0x49,0x43,0x7e,0xb5,0x72,0x6d,0xb1,0x7d,0x44,0xfd,0xe8,0xf4,0xee,0xbd,0x2b,0x4d,0x6a,0x40,0x41,0x6e,0x4f,0x2d,0x2f,0x4f,0x69,0x39,0x41,0x6f, +0x50,0x2d,0x02,0x1e,0x8e,0xd3,0x8c,0x45,0x44,0x8c,0xd3,0x8f,0x01,0x17,0x01,0x19,0xfe,0xea,0xfe,0xe6,0x7e,0xa4,0x62,0x27,0x29,0x63,0xa4,0x7b,0x7e,0xa5,0x62,0x28,0x27,0x62,0xa6,0x00,0x00,0x02,0x00,0xb3,0xfe,0x57,0x04,0x42,0x04,0x50,0x00,0x28,0x00,0x3c,0x00,0x65,0x40,0x44,0x64,0x3b,0x01,0x46,0x3b,0x56,0x3b,0x02,0x6b,0x2b, +0x01,0x49,0x2b,0x59,0x2b,0x02,0x06,0x26,0x16,0x26,0x76,0x26,0x86,0x26,0x04,0x34,0x21,0x01,0x3b,0x08,0x01,0x79,0x03,0x89,0x03,0x02,0x00,0x47,0x60,0x29,0x01,0x29,0x29,0x3e,0x33,0x1e,0x11,0x46,0x00,0x12,0x80,0x12,0x02,0x12,0x2e,0x50,0x1e,0x24,0x10,0x18,0x0f,0x11,0x1b,0x38,0x50,0x0a,0x05,0x16,0x00,0x3f,0x33,0xed,0x3f,0x3f, +0x3f,0x33,0xed,0x01,0x2f,0x5d,0xed,0x32,0x32,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x23,0x1e,0x03,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x15,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02, +0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x04,0x42,0x28,0x5c,0x96,0x6e,0x37,0x64,0x56,0x43,0x17,0x05,0x01,0x01,0x01,0x01,0xb5,0x01,0x02,0x02,0x01,0xaf,0x01,0x03,0x03,0x03,0x04,0x19,0x3f,0x50,0x64,0x3e,0x6e,0x96,0x5c,0x28,0xba,0x18,0x3b,0x61,0x49,0x3b,0x68,0x4d,0x2d,0x25,0x48,0x6a,0x44,0x49,0x62,0x3b,0x19,0x02,0x22,0x7b, +0xd0,0x96,0x55,0x14,0x2c,0x46,0x32,0x02,0x1f,0x2e,0x3a,0x1d,0xfe,0x59,0x05,0x03,0x28,0x4a,0x3b,0x2a,0x09,0x03,0x25,0x34,0x3c,0x1a,0x34,0x4c,0x31,0x17,0x50,0x93,0xce,0x7d,0x64,0x9c,0x6b,0x38,0x25,0x61,0xac,0x87,0x73,0x9d,0x61,0x2a,0x39,0x6e,0xa2,0x00,0x00,0x00,0x00,0x02,0x00,0x8a,0xfe,0x57,0x04,0x1a,0x04,0x4a,0x00,0x24, +0x00,0x38,0x00,0x66,0x40,0x47,0x4b,0x2d,0x5b,0x2d,0x6b,0x2d,0x03,0x44,0x31,0x54,0x31,0x64,0x31,0x03,0x3a,0x1c,0x01,0x35,0x03,0x01,0x05,0x24,0x15,0x24,0x75,0x24,0x85,0x24,0x04,0x0a,0x20,0x1a,0x20,0x7a,0x20,0x8a,0x20,0x04,0x12,0x46,0x25,0x05,0x50,0x13,0x01,0x90,0x13,0xa0,0x13,0x02,0x13,0x13,0x3a,0x2f,0x47,0x00,0x22,0x01, +0x22,0x34,0x50,0x19,0x1f,0x16,0x12,0x1b,0x2a,0x50,0x05,0x00,0x10,0x00,0x3f,0x32,0xed,0x3f,0x3f,0x33,0xed,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0x33,0x33,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x32,0x1e,0x02,0x17,0x33,0x34,0x3e,0x02,0x37,0x33,0x0e,0x03,0x15,0x11,0x23,0x11,0x34,0x36,0x37,0x36,0x37, +0x23,0x0e,0x03,0x23,0x22,0x02,0x11,0x10,0x12,0x01,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x02,0x11,0x42,0x66,0x4f,0x3d,0x18,0x02,0x03,0x03,0x05,0x01,0xaf,0x01,0x02,0x02,0x01,0xb5,0x01,0x01,0x01,0x01,0x02,0x19,0x3f,0x51,0x65,0x41,0xca,0xbe,0xc3,0x02,0x12,0x28,0x4a,0x69,0x41,0x44,0x61, +0x3d,0x1d,0x1c,0x3c,0x60,0x45,0x3b,0x68,0x4e,0x2d,0x04,0x4a,0x16,0x2e,0x45,0x2f,0x19,0x39,0x31,0x23,0x03,0x09,0x28,0x44,0x62,0x43,0xfb,0x36,0x01,0xb7,0x1a,0x3a,0x1a,0x1e,0x1c,0x33,0x4e,0x35,0x1a,0x01,0x19,0x01,0x15,0x01,0x19,0x01,0x1d,0xfd,0xe0,0x77,0x9e,0x5e,0x28,0x33,0x69,0xa1,0x6e,0x6a,0x9f,0x6a,0x36,0x27,0x63,0xab, +0x00,0x01,0x00,0xf2,0x00,0x00,0x04,0x15,0x04,0x4e,0x00,0x1f,0x00,0x46,0x40,0x2b,0x78,0x06,0x88,0x06,0x02,0x04,0x1a,0x14,0x1a,0x02,0x04,0x19,0x14,0x19,0x02,0x1f,0x1f,0x21,0x16,0x09,0x46,0x0a,0x10,0x10,0x1f,0x0a,0x6f,0x0a,0x7f,0x0a,0x8f,0x0a,0x04,0x0a,0x16,0x03,0x52,0x1c,0x10,0x10,0x0f,0x09,0x15,0x00,0x3f,0x3f,0x3f,0xed, +0x33,0x01,0x2f,0x5d,0x33,0x7c,0x2f,0x18,0x10,0xed,0x32,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x2e,0x01,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x17,0x33,0x3e,0x03,0x33,0x32,0x16,0x17,0x04,0x15,0x2f,0x67,0x3e,0x54,0x86,0x5c,0x31,0xb4,0x0c,0x10,0x12,0x06,0xab,0x07,0x0f,0x0e, +0x0a,0x02,0x05,0x1c,0x3e,0x55,0x74,0x52,0x38,0x6c,0x2a,0x03,0x96,0x08,0x0b,0x44,0x75,0x9c,0x58,0xfe,0x04,0x02,0xbd,0x38,0x74,0x67,0x52,0x18,0x18,0x3e,0x43,0x44,0x1d,0x3e,0x64,0x46,0x26,0x0a,0x07,0x00,0x00,0x01,0x00,0xa7,0xff,0xec,0x04,0x24,0x04,0x4b,0x00,0x38,0x00,0x85,0x40,0x58,0x6c,0x18,0x01,0x79,0x17,0x89,0x17,0x02, +0x6c,0x17,0x01,0x6a,0x36,0x01,0x73,0x31,0x83,0x31,0x02,0x47,0x31,0x57,0x31,0x02,0x24,0x37,0x01,0x2a,0x1d,0x01,0x0a,0x03,0x1a,0x03,0x02,0x05,0x20,0x15,0x20,0x02,0x28,0x49,0x27,0x27,0x00,0x48,0x15,0x15,0x1f,0x3a,0x0b,0x49,0x0a,0x0a,0x2f,0x48,0x00,0x1f,0x60,0x1f,0x70,0x1f,0x80,0x1f,0x04,0x1f,0x2f,0x15,0x05,0x2d,0x50,0x22, +0x20,0x28,0x90,0x28,0x02,0x28,0x28,0x22,0x10,0x10,0x50,0x05,0x0b,0x0b,0x05,0x16,0x00,0x3f,0x33,0x2f,0x10,0xed,0x3f,0x33,0x2f,0x5d,0x10,0xed,0x12,0x39,0x39,0x01,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f,0xed,0x32,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23, +0x22,0x2e,0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x27,0x2e,0x03,0x35,0x34,0x36,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x23,0x22,0x15,0x14,0x1e,0x02,0x17,0x1e,0x03,0x04,0x24,0x3b,0x70,0xa3,0x69,0x5e,0x97,0x72,0x4d,0x12,0x9f,0x0c,0x35,0x4b,0x62,0x39,0x3a,0x63,0x48,0x29,0x33,0x58,0x79,0x47,0x40, +0x7e,0x63,0x3d,0xd4,0xc9,0x4f,0x8a,0x6c,0x49,0x0e,0xa2,0x07,0x2e,0x43,0x54,0x2e,0xf5,0x2b,0x4e,0x6c,0x41,0x41,0x89,0x71,0x49,0x01,0x35,0x4c,0x7a,0x55,0x2e,0x1b,0x3e,0x67,0x4c,0x1f,0x37,0x41,0x22,0x0b,0x11,0x29,0x41,0x30,0x32,0x3d,0x2a,0x1e,0x13,0x11,0x28,0x41,0x64,0x4d,0x93,0xa6,0x1d,0x3f,0x63,0x45,0x14,0x2d,0x38,0x21, +0x0c,0x97,0x2e,0x39,0x26,0x1b,0x11,0x10,0x2a,0x46,0x6d,0x00,0x00,0x01,0x00,0xbe,0xff,0xf0,0x03,0xf9,0x05,0x54,0x00,0x1b,0x00,0x58,0x40,0x36,0x6a,0x18,0x7a,0x18,0x8a,0x18,0x03,0x18,0x28,0x09,0x0e,0x48,0x06,0x06,0x12,0x12,0x1d,0x05,0x09,0x46,0x1a,0x90,0x01,0x01,0x01,0x01,0x02,0x1a,0x40,0x12,0x25,0x48,0x1a,0x40,0x0b,0x0e, +0x48,0x00,0x1a,0x01,0x1a,0x0c,0x50,0x17,0x16,0x08,0x00,0x50,0x01,0x03,0x03,0x05,0x01,0x0f,0x00,0x3f,0x33,0x33,0x2f,0x10,0xed,0x32,0x3f,0xed,0x01,0x2f,0x5d,0x2b,0x2b,0x33,0x33,0x2f,0x5d,0x10,0xed,0x32,0x12,0x39,0x2f,0x33,0x2f,0x31,0x30,0x00,0x2b,0x5d,0x13,0x35,0x33,0x13,0x33,0x11,0x21,0x15,0x21,0x11,0x14,0x16,0x33,0x32, +0x3e,0x02,0x37,0x15,0x0e,0x03,0x23,0x22,0x26,0x35,0x11,0xbe,0xaa,0x3a,0x78,0x01,0xb0,0xfe,0x50,0x55,0x61,0x28,0x55,0x4f,0x45,0x18,0x16,0x46,0x57,0x66,0x36,0xa2,0xa2,0x03,0xac,0x8e,0x01,0x1a,0xfe,0xe6,0x8e,0xfd,0x74,0x4f,0x4c,0x07,0x0a,0x0c,0x05,0x89,0x06,0x10,0x0e,0x0a,0x89,0x94,0x02,0x9f,0x00,0x00,0x00,0x01,0x00,0xb9, +0xff,0xec,0x04,0x1f,0x04,0x3a,0x00,0x25,0x00,0x45,0x40,0x2c,0x7f,0x22,0x8f,0x22,0x02,0x7b,0x21,0x8b,0x21,0x02,0x0a,0x21,0x1a,0x21,0x2a,0x21,0x03,0x39,0x1c,0x01,0x19,0x0e,0x46,0x0b,0x0b,0x27,0x01,0x46,0x00,0x24,0x80,0x24,0x02,0x24,0x19,0x06,0x50,0x1f,0x16,0x14,0x15,0x0c,0x00,0x0f,0x00,0x3f,0x32,0x3f,0x3f,0xed,0x33,0x01, +0x2f,0x5d,0xed,0x12,0x39,0x2f,0xed,0x33,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x11,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x17,0x23,0x2e,0x03,0x35,0x23,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x11,0x01,0x6d,0x17,0x35,0x55,0x3f,0x40,0x67,0x49,0x27,0xb5,0x01,0x02,0x02,0x01,0xaa,0x01,0x02,0x03, +0x02,0x03,0x1a,0x3e,0x52,0x6a,0x46,0x5a,0x82,0x54,0x27,0x04,0x3a,0xfd,0x52,0x4f,0x6a,0x41,0x1b,0x2d,0x55,0x7d,0x51,0x02,0x73,0xfc,0xad,0x22,0x4b,0x43,0x30,0x07,0x05,0x2c,0x39,0x3b,0x14,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x91,0x64,0x02,0xd1,0x00,0x00,0x01,0x00,0x45,0x00,0x00,0x04,0x87,0x04,0x3a,0x00,0x10,0x00,0x94,0x40,0x42, +0x56,0x04,0x01,0x49,0x0e,0x59,0x0e,0x02,0x1b,0x0f,0x5b,0x0f,0x02,0x09,0x0f,0x01,0x25,0x03,0x55,0x03,0x02,0x06,0x03,0x16,0x03,0x02,0x28,0x01,0x68,0x01,0x02,0x00,0x01,0x52,0x0f,0x09,0x0f,0x4b,0x10,0x00,0x14,0x10,0x10,0x00,0x01,0x01,0x52,0x03,0x09,0x03,0x4b,0x02,0x01,0x14,0x02,0x01,0x03,0x02,0x09,0x02,0x70,0x10,0x80,0x10, +0x02,0x10,0xb8,0xff,0xc0,0x40,0x1e,0x0a,0x0e,0x48,0x10,0x10,0x12,0x02,0x40,0x0b,0x0e,0x48,0x02,0x0f,0x02,0x0f,0x55,0x09,0x01,0x44,0x09,0x01,0x2a,0x09,0x3a,0x09,0x02,0x09,0x00,0x01,0x15,0x00,0x3f,0x33,0x33,0x5d,0x5d,0x5d,0x3f,0x33,0x01,0x2f,0x2b,0x11,0x33,0x2f,0x2b,0x5d,0x12,0x39,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87,0x2b, +0xc4,0x87,0x18,0x10,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x01,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x21,0x23,0x01,0x33,0x01,0x1e,0x03,0x17,0x3e,0x03,0x37,0x01,0x33,0x02,0xcb,0xd5,0xfe,0x4f,0xca,0x01,0x0c,0x08,0x12,0x14,0x11,0x06,0x06,0x13,0x14,0x15,0x08,0x01,0x14,0xc9,0x04,0x3a,0xfd,0x40,0x16,0x3f,0x44,0x3f,0x15,0x15,0x3f,0x42, +0x3f,0x16,0x02,0xc2,0x00,0x01,0x00,0x15,0x00,0x00,0x04,0xb8,0x04,0x3a,0x00,0x2a,0x01,0x52,0x40,0x10,0x74,0x1e,0x84,0x1e,0x02,0x46,0x1e,0x56,0x1e,0x02,0x24,0x1e,0x34,0x1e,0x02,0x1d,0xb8,0xff,0xe0,0x40,0x4a,0x13,0x18,0x48,0x90,0x1d,0x01,0x65,0x1d,0x75,0x1d,0x85,0x1d,0x03,0x24,0x1d,0x34,0x1d,0x02,0x06,0x1d,0x16,0x1d,0x02, +0x1c,0x20,0x13,0x18,0x48,0x9f,0x1c,0x01,0x6b,0x1c,0x7b,0x1c,0x8b,0x1c,0x03,0x1d,0x1c,0x2d,0x1c,0x3d,0x1c,0x03,0x0b,0x1c,0x01,0x7b,0x1b,0x8b,0x1b,0x02,0x1b,0x20,0x0b,0x0e,0x48,0x0e,0x20,0x0d,0x11,0x48,0x1a,0x0e,0x2a,0x0e,0x3a,0x0e,0x03,0x0b,0x0e,0x01,0x0d,0xb8,0xff,0xe0,0x40,0x1f,0x13,0x18,0x48,0x90,0x0d,0x01,0x25,0x0d, +0x35,0x0d,0x75,0x0d,0x85,0x0d,0x04,0x01,0x20,0x13,0x18,0x48,0x9f,0x01,0x01,0x2a,0x01,0x3a,0x01,0x7a,0x01,0x03,0x00,0xb8,0xff,0xe0,0x40,0x70,0x0d,0x11,0x48,0x15,0x00,0x25,0x00,0x35,0x00,0x03,0x03,0x06,0x00,0x01,0x0e,0x01,0x52,0x10,0x16,0x10,0x4b,0x0f,0x0e,0x14,0x0f,0x0f,0x0e,0x0d,0x01,0x52,0x1c,0x16,0x1c,0x4c,0x07,0x0d, +0x14,0x07,0x0d,0x01,0x01,0x52,0x1d,0x23,0x1d,0x4c,0x07,0x01,0x14,0x07,0x01,0x1d,0x07,0x00,0x01,0x52,0x29,0x23,0x29,0x4b,0x2a,0x00,0x14,0x2a,0x00,0x23,0x07,0x16,0x03,0x0f,0x14,0x2a,0x74,0x2a,0x84,0x2a,0x03,0x2a,0x2a,0x2c,0x0f,0x2a,0x66,0x07,0x01,0x32,0x07,0x01,0x02,0x07,0x1c,0x1c,0x16,0x29,0x2a,0x10,0x03,0x0f,0x0f,0x23, +0x16,0x75,0x16,0x85,0x16,0x02,0x16,0x0d,0x01,0x00,0x0e,0x15,0x00,0x3f,0x33,0x33,0x33,0x33,0x5d,0x11,0x33,0x3f,0x17,0x33,0x12,0x39,0x2f,0x33,0x5f,0x5d,0x5d,0x2f,0x01,0x2f,0x11,0x33,0x2f,0x5d,0x12,0x17,0x39,0x87,0x2b,0x87,0x2b,0xc4,0x10,0x00,0xc1,0x87,0x05,0x18,0x2b,0x87,0x2b,0xc4,0x87,0x18,0x2b,0x87,0x2b,0xc4,0x87,0x18, +0x10,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x01,0x5d,0x5f,0x5d,0x2b,0x5d,0x5d,0x2b,0x5d,0x5d,0x2b,0x5d,0x5d,0x2b,0x2b,0x5d,0x5d,0x5d,0x5d,0x5d,0x2b,0x5d,0x5d,0x5d,0x5d,0x2b,0x5d,0x5d,0x5d,0x21,0x23,0x03,0x2e,0x01,0x27,0x26,0x27,0x06,0x07,0x0e,0x01,0x07,0x03,0x23,0x03,0x33,0x13,0x1e,0x03,0x15,0x36,0x37,0x3e,0x01,0x37,0x13,0x33, +0x13,0x1e,0x01,0x17,0x16,0x17,0x34,0x3e,0x02,0x37,0x13,0x33,0x03,0xfa,0xcc,0x8f,0x08,0x14,0x09,0x0b,0x09,0x09,0x0b,0x09,0x14,0x0a,0x94,0xcb,0xb7,0xb2,0x5d,0x03,0x0b,0x0b,0x08,0x0b,0x0b,0x09,0x14,0x07,0x87,0xc1,0x82,0x06,0x13,0x09,0x0b,0x0a,0x08,0x0c,0x0c,0x03,0x65,0xb0,0x01,0xd7,0x1b,0x45,0x20,0x25,0x25,0x25,0x24,0x1f, +0x47,0x1f,0xfe,0x2d,0x04,0x3a,0xfd,0xa1,0x18,0x55,0x60,0x5c,0x1d,0x2d,0x29,0x23,0x49,0x14,0x01,0xa8,0xfe,0x57,0x14,0x47,0x23,0x29,0x2e,0x1e,0x5a,0x5f,0x56,0x19,0x02,0x5f,0x00,0x00,0x00,0x01,0x00,0x5e,0x00,0x00,0x04,0x6d,0x04,0x3a,0x00,0x0b,0x00,0xb9,0x40,0x70,0x47,0x04,0x01,0x76,0x07,0x86,0x07,0x02,0x39,0x01,0x79,0x01, +0x89,0x01,0x03,0x76,0x08,0x01,0x19,0x08,0x59,0x08,0x02,0x0a,0x02,0x09,0x07,0x03,0x08,0x06,0x0b,0x06,0x01,0x02,0x09,0x04,0x03,0x08,0x05,0x00,0x05,0x0a,0x01,0x02,0x09,0x02,0x07,0x04,0x03,0x02,0x09,0x01,0x52,0x08,0x03,0x02,0x03,0x08,0x4b,0x09,0x02,0x14,0x09,0x09,0x02,0x00,0x01,0x52,0x06,0x0b,0x06,0x4b,0x05,0x00,0x14,0x05, +0x00,0x06,0x05,0x0a,0x01,0x07,0x04,0x04,0x03,0x0b,0x09,0x09,0x10,0x0b,0x70,0x0b,0x80,0x0b,0x03,0x0b,0x0b,0x0d,0x05,0x05,0x03,0x07,0x0a,0x04,0x01,0x04,0x08,0x05,0x0f,0x03,0x00,0x15,0x00,0x3f,0x32,0x3f,0x33,0x17,0x39,0x01,0x2f,0x33,0x2f,0x11,0x33,0x2f,0x5d,0x33,0x2f,0x11,0x12,0x17,0x39,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87, +0x2b,0xc4,0x87,0x18,0x10,0x2b,0x10,0x00,0xc1,0x87,0x05,0x2b,0x10,0xc4,0x10,0xc0,0xc0,0x10,0x87,0xc0,0xc0,0x10,0x87,0x08,0xc0,0x08,0xc0,0x10,0x87,0x08,0xc0,0x08,0xc0,0x31,0x30,0x01,0x5d,0x5d,0x00,0x5d,0x5d,0x01,0x5d,0x21,0x09,0x01,0x23,0x09,0x01,0x33,0x09,0x01,0x33,0x09,0x01,0x03,0xa4,0xfe,0xbf,0xfe,0xbd,0xc2,0x01,0x9f, +0xfe,0x73,0xc7,0x01,0x2c,0x01,0x2a,0xc9,0xfe,0x73,0x01,0xa4,0x01,0xbc,0xfe,0x44,0x02,0x2c,0x02,0x0e,0xfe,0x5b,0x01,0xa5,0xfd,0xf4,0xfd,0xd2,0x00,0x01,0x00,0x42,0xfe,0x57,0x04,0x89,0x04,0x3a,0x00,0x1f,0x00,0xaf,0x40,0x52,0x1e,0x18,0x0f,0x12,0x48,0x65,0x12,0x75,0x12,0x85,0x12,0x03,0x49,0x1d,0x59,0x1d,0x02,0x03,0x20,0x0d, +0x11,0x48,0x2d,0x03,0x3d,0x03,0x02,0x2b,0x02,0x3b,0x02,0x02,0x00,0x48,0x0c,0x49,0x75,0x00,0x85,0x00,0x02,0x26,0x00,0x66,0x00,0x02,0x6a,0x10,0x7a,0x10,0x8a,0x10,0x03,0x49,0x10,0x59,0x10,0x02,0x00,0x10,0x18,0x69,0x18,0x79,0x18,0x89,0x18,0x03,0x18,0x10,0x09,0x0c,0x48,0x18,0x1f,0x08,0x08,0x11,0x1e,0x1f,0x10,0x1f,0xb8,0xff, +0xc0,0xb7,0x0a,0x11,0x48,0x1f,0x1f,0x21,0x12,0x11,0xb8,0xff,0xf0,0x40,0x0a,0x11,0x40,0x0b,0x0f,0x48,0x11,0x82,0x18,0x01,0x18,0xb8,0xff,0xe0,0x40,0x0d,0x0d,0x10,0x48,0x18,0x10,0x10,0x1e,0x11,0x0f,0x0c,0x50,0x05,0x1b,0x00,0x3f,0xed,0x3f,0x33,0x39,0x2f,0x33,0x2b,0x5d,0x01,0x2f,0x2b,0x38,0x33,0x11,0x33,0x2f,0x2b,0x38,0x33, +0x12,0x39,0x2f,0x12,0x39,0x2b,0x5d,0x11,0x33,0x33,0x5d,0x5d,0x5d,0x5d,0x31,0x30,0x00,0x2b,0x5d,0x5d,0x2b,0x01,0x5d,0x5d,0x2b,0x21,0x0e,0x03,0x23,0x22,0x26,0x27,0x35,0x1e,0x01,0x33,0x32,0x36,0x3f,0x01,0x01,0x33,0x01,0x1e,0x03,0x17,0x3e,0x03,0x37,0x13,0x33,0x02,0xc1,0x25,0x50,0x62,0x78,0x4e,0x22,0x3a,0x20,0x13,0x30,0x11, +0x4f,0x8b,0x30,0x12,0xfe,0x2a,0xc0,0x01,0x08,0x0b,0x20,0x1e,0x17,0x02,0x03,0x17,0x1e,0x1f,0x0c,0xfc,0xbe,0x62,0x9d,0x6f,0x3b,0x04,0x07,0x87,0x03,0x03,0x76,0x81,0x31,0x04,0x2f,0xfd,0x7e,0x1b,0x4f,0x4d,0x3e,0x09,0x0b,0x3d,0x4b,0x4f,0x1d,0x02,0x81,0x00,0x00,0x00,0x00,0x01,0x00,0x93,0x00,0x00,0x04,0x2c,0x04,0x3a,0x00,0x09, +0x00,0x58,0x40,0x37,0x06,0x07,0x16,0x07,0x26,0x07,0x56,0x07,0x04,0x07,0x01,0x52,0x02,0x01,0x02,0x4b,0x06,0x07,0x14,0x06,0x07,0x02,0x06,0x60,0x06,0x01,0x03,0x06,0x08,0x08,0x06,0x03,0x03,0x0b,0x9f,0x01,0xaf,0x01,0xbf,0x01,0x03,0x00,0x01,0x01,0x01,0x06,0x03,0x50,0x04,0x0f,0x01,0x07,0x50,0x00,0x15,0x00,0x3f,0xed,0x32,0x3f, +0xed,0x32,0x01,0x2f,0x5d,0x5d,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x5d,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x01,0x5d,0x33,0x35,0x01,0x21,0x35,0x21,0x15,0x01,0x21,0x15,0x93,0x02,0xa9,0xfd,0x7f,0x03,0x4c,0xfd,0x56,0x02,0xcf,0x89,0x03,0x26,0x8b,0x89,0xfc,0xda,0x8b,0x00,0x00,0x01,0x00,0xe3,0xfe,0x57,0x04,0x25, +0x05,0xcc,0x00,0x31,0x00,0x75,0x40,0x12,0x76,0x0f,0x86,0x0f,0x02,0x69,0x08,0x79,0x08,0x89,0x08,0x03,0x02,0x18,0x09,0x0c,0x48,0x14,0xb8,0xff,0xe0,0x40,0x37,0x09,0x0c,0x48,0x18,0x80,0x31,0x01,0x31,0x31,0x33,0x20,0x2c,0xf1,0x05,0x25,0x05,0x3f,0x0c,0x01,0x0c,0x0c,0x11,0x7f,0x05,0x01,0x00,0x05,0x01,0x05,0x25,0x0b,0xf5,0x0f, +0x0c,0x4f,0x0c,0x6f,0x0c,0x03,0x8f,0x0c,0xaf,0x0c,0x02,0x0c,0x0c,0x30,0x19,0xf5,0x18,0x00,0x30,0xf5,0x00,0x1b,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x39,0x01,0x2f,0x5d,0x5d,0x33,0x33,0x2f,0x5d,0x12,0x39,0x10,0xed,0x32,0x12,0x39,0x2f,0x5d,0x33,0x31,0x30,0x00,0x2b,0x2b,0x5d,0x5d,0x01,0x22,0x2e,0x02,0x35, +0x11,0x34,0x2e,0x02,0x27,0x35,0x3e,0x03,0x35,0x11,0x34,0x3e,0x02,0x33,0x21,0x15,0x23,0x22,0x0e,0x02,0x15,0x11,0x14,0x0e,0x02,0x07,0x15,0x1e,0x03,0x15,0x11,0x14,0x16,0x3b,0x01,0x15,0x03,0x1c,0x41,0x6c,0x4e,0x2b,0x2f,0x4e,0x63,0x33,0x33,0x63,0x4e,0x2f,0x2b,0x4e,0x6c,0x41,0x01,0x09,0xd5,0x2d,0x41,0x2a,0x13,0x29,0x42,0x53, +0x29,0x2b,0x53,0x41,0x28,0x50,0x5b,0xd5,0xfe,0x57,0x2c,0x50,0x6f,0x44,0x01,0x5f,0x3f,0x57,0x36,0x1a,0x02,0x89,0x02,0x1a,0x37,0x56,0x3e,0x01,0x60,0x46,0x70,0x4f,0x2a,0x8b,0x15,0x2e,0x4a,0x36,0xfe,0xa6,0x39,0x5c,0x45,0x2c,0x0a,0x02,0x0a,0x2d,0x44,0x5d,0x3a,0xfe,0xa5,0x6a,0x59,0x8b,0x00,0x01,0x02,0x13,0xfe,0x57,0x02,0xb9, +0x05,0xcc,0x00,0x03,0x00,0x17,0x40,0x0a,0x03,0xab,0x00,0x00,0x04,0x05,0x01,0x00,0x00,0x1b,0x00,0x3f,0x3f,0x11,0x12,0x01,0x39,0x2f,0xed,0x31,0x30,0x01,0x11,0x33,0x11,0x02,0x13,0xa6,0xfe,0x57,0x07,0x75,0xf8,0x8b,0x00,0x00,0x00,0x01,0x00,0xa7,0xfe,0x57,0x03,0xe9,0x05,0xcc,0x00,0x31,0x00,0x73,0x40,0x0d,0x76,0x22,0x86,0x22, +0x02,0x69,0x29,0x79,0x29,0x89,0x29,0x03,0x1c,0xb8,0xff,0xe0,0x40,0x3d,0x09,0x0d,0x48,0x2f,0x18,0x09,0x0d,0x48,0x0b,0x30,0x25,0x01,0x25,0x25,0x20,0x2c,0xf1,0x11,0x05,0x05,0x33,0x19,0x4f,0x00,0x7f,0x00,0x8f,0x00,0x03,0x00,0x00,0x01,0x00,0x0b,0x26,0xf5,0x0f,0x25,0x2f,0x25,0x4f,0x25,0x6f,0x25,0x04,0x8f,0x25,0xaf,0x25,0x02, +0x25,0x25,0x01,0x18,0xf5,0x19,0x00,0x01,0xf5,0x00,0x1b,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x39,0x01,0x2f,0x5d,0x5d,0x33,0x12,0x39,0x2f,0x33,0xed,0x32,0x32,0x2f,0x5d,0x39,0x31,0x30,0x00,0x2b,0x2b,0x5d,0x5d,0x13,0x35,0x33,0x32,0x36,0x35,0x11,0x34,0x3e,0x02,0x37,0x35,0x2e,0x03,0x35,0x11,0x34,0x2e,0x02, +0x2b,0x01,0x35,0x21,0x32,0x1e,0x02,0x15,0x11,0x14,0x1e,0x02,0x17,0x15,0x0e,0x03,0x15,0x11,0x14,0x0e,0x02,0x23,0xa7,0xd5,0x5b,0x51,0x28,0x41,0x52,0x2b,0x29,0x52,0x42,0x29,0x14,0x2a,0x41,0x2d,0xd5,0x01,0x09,0x41,0x6c,0x4e,0x2b,0x2f,0x4e,0x63,0x33,0x33,0x63,0x4e,0x2f,0x2b,0x4e,0x6c,0x41,0xfe,0x57,0x8b,0x59,0x6a,0x01,0x5b, +0x3a,0x5d,0x44,0x2d,0x0a,0x02,0x0a,0x2c,0x45,0x5c,0x39,0x01,0x5a,0x36,0x4a,0x2e,0x15,0x8b,0x2a,0x4f,0x70,0x46,0xfe,0xa0,0x3e,0x56,0x37,0x1a,0x02,0x89,0x02,0x1a,0x36,0x57,0x3f,0xfe,0xa1,0x44,0x6f,0x50,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x6c,0x02,0x29,0x04,0x60,0x03,0x27,0x00,0x20,0x00,0x5d,0x40,0x1a,0x16,0x04,0x26,0x04, +0x36,0x04,0x66,0x04,0x96,0x04,0xa6,0x04,0x06,0x10,0x30,0x09,0x14,0x00,0x4c,0x11,0x30,0x09,0x14,0x00,0x4c,0x1e,0xb8,0xff,0xc0,0x40,0x25,0x09,0x14,0x00,0x4c,0x1f,0x30,0x09,0x14,0x00,0x4c,0x0d,0x22,0x10,0x1d,0x01,0x1d,0x18,0xad,0x0d,0x00,0x40,0x17,0x1c,0x48,0x00,0x40,0x09,0x0c,0x48,0x00,0x1d,0x0a,0xad,0x0f,0x13,0x01,0x13, +0x00,0x2f,0x5d,0xed,0x33,0xdd,0x2b,0x2b,0x32,0xed,0x01,0x2f,0x5d,0x10,0xce,0x31,0x30,0x2b,0x00,0x2b,0x2b,0x2b,0x5d,0x01,0x32,0x1e,0x02,0x17,0x1e,0x03,0x33,0x32,0x36,0x37,0x15,0x0e,0x03,0x23,0x22,0x26,0x27,0x26,0x23,0x22,0x0e,0x02,0x07,0x35,0x3e,0x01,0x01,0x73,0x29,0x4f,0x4d,0x4b,0x25,0x15,0x32,0x33,0x33,0x17,0x45,0x7b, +0x34,0x1f,0x3c,0x3d,0x44,0x28,0x45,0x91,0x49,0x81,0x58,0x26,0x41,0x3c,0x38,0x1d,0x32,0x84,0x03,0x27,0x0d,0x14,0x1a,0x0d,0x07,0x10,0x0e,0x08,0x32,0x2a,0x95,0x16,0x1f,0x13,0x08,0x2c,0x1a,0x2d,0x0c,0x17,0x20,0x15,0x8f,0x26,0x2e,0x00,0x00,0x00,0x00,0x02,0x02,0x03,0xfe,0xf6,0x02,0xc9,0x04,0x3a,0x00,0x03,0x00,0x07,0x00,0x2c, +0x40,0x15,0x02,0x04,0x98,0x03,0x00,0x07,0x10,0x07,0x02,0x07,0x07,0x08,0x09,0x00,0x00,0x03,0x06,0x9d,0x07,0x0f,0x03,0xb8,0x01,0x0e,0x00,0x3f,0x3f,0xed,0x11,0x39,0x2f,0x11,0x12,0x01,0x39,0x2f,0x5d,0x33,0xed,0x32,0x31,0x30,0x01,0x33,0x13,0x23,0x13,0x15,0x23,0x35,0x02,0x1b,0x94,0x18,0xc4,0xc6,0xc2,0x02,0xad,0xfc,0x49,0x05, +0x44,0xc9,0xc9,0x00,0x00,0x02,0x00,0x85,0xff,0xc3,0x04,0x46,0x05,0x63,0x00,0x06,0x00,0x25,0x00,0x76,0x00,0xb0,0x11,0x2f,0xb0,0x08,0xcd,0xb0,0x00,0x32,0x7d,0xb0,0x13,0xcd,0x18,0xb0,0x01,0x2f,0xb0,0x07,0x33,0xb0,0x1c,0xcd,0xb0,0x1f,0x32,0xb0,0x1c,0x10,0x7d,0xb0,0x1d,0xcd,0x18,0x01,0xb0,0x26,0x2f,0xb0,0x18,0xd6,0xb0,0x04, +0xcd,0xb0,0x04,0x10,0xb0,0x13,0xdc,0xb1,0x00,0x1c,0x32,0x32,0xb0,0x12,0xcd,0xb1,0x07,0x1e,0x32,0x32,0xb0,0x12,0x10,0xb0,0x0c,0xdc,0xb0,0x24,0x32,0xb0,0x0d,0xcd,0xb0,0x23,0x32,0xb0,0x0d,0x10,0xb0,0x27,0xd6,0x00,0xb1,0x08,0x11,0x11,0x12,0xb1,0x14,0x15,0x39,0x39,0xb0,0x01,0x11,0xb4,0x0c,0x0d,0x18,0x23,0x24,0x24,0x17,0x39, +0xb0,0x1c,0x12,0xb1,0x1b,0x20,0x39,0x39,0x30,0x31,0x01,0x11,0x0e,0x01,0x10,0x17,0x16,0x13,0x11,0x36,0x37,0x36,0x37,0x17,0x06,0x07,0x06,0x07,0x15,0x23,0x35,0x26,0x27,0x26,0x35,0x10,0x37,0x36,0x37,0x35,0x33,0x15,0x16,0x17,0x16,0x17,0x07,0x26,0x02,0x3a,0x6e,0x90,0x54,0x41,0xe9,0x7d,0x39,0x17,0x09,0xb6,0x1e,0xce,0x46,0x5a, +0x80,0xd6,0x72,0x6d,0xfb,0x52,0x68,0x80,0xf6,0x64,0x1f,0x0d,0xb9,0x20,0x01,0x12,0x03,0x0b,0x10,0xb4,0xfe,0x7d,0x64,0x4e,0x02,0xfa,0xfc,0xf4,0x15,0x61,0x28,0x36,0x0c,0xd2,0x5b,0x1f,0x08,0xc3,0xc3,0x10,0x90,0x88,0xe2,0x01,0x68,0x80,0x2a,0x09,0xb8,0xb8,0x14,0xb7,0x38,0x3f,0x0e,0xa9,0x00,0x01,0x00,0x38,0x00,0x00,0x04,0x93, +0x05,0x5a,0x00,0x36,0x00,0x9c,0x40,0x62,0x03,0x18,0x0c,0x0f,0x48,0x06,0x14,0x01,0x1b,0x6f,0x22,0x29,0x2d,0x6f,0x10,0x4f,0x22,0x5f,0x22,0x02,0x7f,0x0c,0x8f,0x0c,0x02,0x0f,0x2a,0x01,0x0c,0x2a,0x22,0x22,0x2a,0x0c,0x03,0x06,0x00,0x6f,0x00,0x36,0x01,0x36,0x36,0x38,0x32,0x6e,0x06,0x0f,0x0f,0x06,0x40,0x17,0x24,0x48,0x00,0x06, +0x10,0x06,0x02,0x06,0x2c,0x0e,0x73,0x29,0x1f,0x0f,0x01,0x3f,0x0f,0x6f,0x0f,0x9f,0x0f,0xcf,0x0f,0xdf,0x0f,0xef,0x0f,0x06,0x0f,0x0f,0x32,0x25,0x73,0x16,0x22,0x22,0x16,0x07,0x07,0x32,0x73,0x06,0x36,0x36,0x06,0x18,0x00,0x3f,0x33,0x2f,0x10,0xed,0x32,0x3f,0x33,0x2f,0x10,0xed,0x12,0x39,0x2f,0x5d,0x71,0x33,0xed,0x32,0x01,0x7c, +0x2f,0x5d,0x2b,0x33,0x18,0x2f,0x10,0xed,0x12,0x39,0x7d,0x2f,0x5d,0x18,0xed,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x5d,0x5d,0x5d,0x33,0xed,0x32,0x10,0xed,0x31,0x30,0x00,0x5d,0x2b,0x25,0x0e,0x03,0x23,0x21,0x35,0x3e,0x03,0x3d,0x01,0x23,0x35,0x33,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x32,0x0e,0x02,0x07,0x06,0x07,0x2e,0x01, +0x23,0x22,0x06,0x1d,0x01,0x21,0x15,0x21,0x15,0x14,0x0e,0x02,0x07,0x21,0x32,0x36,0x37,0x04,0x93,0x09,0x20,0x36,0x51,0x3a,0xfc,0x8f,0x2b,0x48,0x33,0x1d,0xba,0xba,0x33,0x68,0x9f,0x6c,0x4a,0x7e,0x65,0x48,0x12,0x01,0x0e,0x18,0x1f,0x11,0x27,0x32,0x16,0x75,0x4e,0x7a,0x78,0x01,0x98,0xfe,0x68,0x0f,0x24,0x3c,0x2c,0x02,0x58,0x3b, +0x39,0x0b,0xf0,0x2b,0x56,0x44,0x2b,0x9a,0x16,0x30,0x46,0x66,0x4b,0x8d,0x8e,0xdc,0x5c,0x93,0x66,0x37,0x1d,0x3a,0x56,0x39,0x06,0x08,0x0a,0x05,0x0c,0x10,0x3f,0x40,0x73,0x7d,0xd8,0x8e,0x8b,0x3b,0x60,0x4d,0x3c,0x17,0x35,0x35,0x00,0x02,0x00,0x9e,0x00,0xe1,0x04,0x2f,0x04,0x73,0x00,0x23,0x00,0x37,0x00,0xea,0x40,0x9d,0x49,0x22, +0x59,0x22,0x02,0x2d,0x22,0x3d,0x22,0x02,0x49,0x1d,0x59,0x1d,0x02,0x2d,0x1d,0x3d,0x1d,0x02,0x49,0x19,0x59,0x19,0x02,0x2d,0x19,0x3d,0x19,0x02,0x46,0x14,0x56,0x14,0x02,0x22,0x14,0x32,0x14,0x02,0x46,0x10,0x56,0x10,0x02,0x22,0x10,0x32,0x10,0x02,0x46,0x0b,0x56,0x0b,0x02,0x22,0x0b,0x32,0x0b,0x02,0x46,0x07,0x56,0x07,0x02,0x22, +0x07,0x32,0x07,0x02,0x49,0x02,0x59,0x02,0x02,0x2d,0x02,0x3d,0x02,0x02,0x03,0x21,0x06,0x1e,0x0c,0x18,0x0f,0x15,0x15,0x18,0x1e,0x21,0x04,0x00,0x0e,0x16,0x16,0x12,0xaa,0x6f,0x2e,0x01,0x10,0x2e,0x01,0x2e,0x2e,0x00,0x39,0x04,0x20,0x20,0x24,0xaa,0x00,0x00,0x10,0x00,0x80,0x00,0x03,0x00,0x0c,0x06,0x0f,0x03,0x15,0x21,0x18,0x1e, +0x1e,0x21,0x03,0x06,0x04,0x09,0x1b,0x17,0x1f,0x1f,0x29,0xb0,0x40,0x1b,0x60,0x1b,0x02,0x3f,0x1b,0x01,0x1b,0x0d,0x05,0x05,0x33,0xb0,0x09,0x00,0x2f,0xed,0x33,0x2f,0x33,0x2f,0x5d,0x5d,0xed,0x33,0x2f,0x33,0x11,0x12,0x17,0x39,0x11,0x33,0x11,0x33,0x11,0x33,0x11,0x33,0x01,0x2f,0x5d,0xed,0x33,0x2f,0x33,0x11,0x12,0x39,0x2f,0x5d, +0x5d,0xed,0x32,0x2f,0x33,0x11,0x17,0x39,0x11,0x33,0x11,0x33,0x11,0x33,0x11,0x33,0x31,0x30,0x5d,0x5d,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x5d,0x5d,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x13,0x34,0x36,0x37,0x27,0x37,0x17,0x3e,0x01,0x33,0x32,0x16,0x17,0x37,0x17,0x07,0x1e,0x01,0x15,0x14,0x06,0x07,0x17,0x07,0x27,0x0e, +0x01,0x23,0x22,0x26,0x27,0x07,0x27,0x37,0x2e,0x01,0x37,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0xb6,0x29,0x25,0x64,0x68,0x63,0x36,0x7f,0x49,0x47,0x7e,0x36,0x61,0x68,0x60,0x25,0x2b,0x2c,0x26,0x64,0x66,0x65,0x36,0x7e,0x47,0x48,0x80,0x34,0x69,0x66,0x66,0x25,0x29,0x9a,0x2d,0x4c,0x66,0x3a, +0x39,0x66,0x4d,0x2c,0x2c,0x4d,0x66,0x39,0x3a,0x66,0x4c,0x2d,0x02,0xac,0x47,0x7f,0x36,0x64,0x67,0x65,0x27,0x2b,0x2a,0x26,0x61,0x69,0x60,0x36,0x7f,0x47,0x47,0x80,0x35,0x64,0x69,0x65,0x25,0x29,0x2a,0x26,0x69,0x69,0x66,0x36,0x7f,0x49,0x3a,0x66,0x4c,0x2c,0x2c,0x4c,0x66,0x3a,0x3a,0x66,0x4d,0x2c,0x2c,0x4d,0x66,0x00,0x00,0x00, +0x00,0x01,0x00,0x34,0x00,0x00,0x04,0x98,0x05,0x45,0x00,0x16,0x00,0xb3,0x40,0x6f,0x5d,0x15,0x01,0x4b,0x15,0x01,0x19,0x15,0x29,0x15,0x39,0x15,0x03,0x52,0x13,0x01,0x03,0x40,0x13,0x01,0x14,0x13,0x24,0x13,0x34,0x13,0x03,0x00,0x00,0x40,0x00,0x50,0x00,0x03,0x0f,0x11,0x4f,0x11,0x5f,0x11,0x03,0x0c,0x04,0x01,0x06,0x06,0x16,0x08, +0x10,0x0b,0x0b,0x12,0x09,0x15,0x16,0x0e,0x08,0x12,0x09,0x0e,0x13,0x2f,0x12,0x01,0x12,0x14,0x04,0x00,0x08,0x5c,0x11,0x0d,0x4f,0x09,0x5f,0x09,0x7f,0x09,0x8f,0x09,0x04,0x10,0x09,0x01,0x09,0x09,0x17,0x18,0x07,0x0b,0x60,0x0c,0x04,0x0c,0x03,0x0f,0x60,0x10,0x14,0x00,0x10,0x0c,0x10,0x0c,0x10,0x08,0x15,0x12,0x03,0x08,0x12,0x00, +0x3f,0x3f,0x33,0x12,0x39,0x39,0x2f,0x2f,0x11,0x33,0x33,0x10,0xed,0x32,0x11,0x33,0x10,0xed,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0x5d,0x33,0x33,0xed,0x32,0x32,0x39,0xc4,0x5d,0x32,0x2b,0x01,0x18,0x10,0x4d,0xe4,0x32,0x11,0x12,0x39,0x2f,0x33,0x11,0x12,0x39,0x2f,0x33,0x31,0x30,0x5f,0x5e,0x5d,0x5d,0x5d,0x5d,0x5f,0x5d,0x5d,0x5d, +0x5d,0x01,0x21,0x15,0x21,0x15,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x35,0x21,0x37,0x21,0x35,0x21,0x01,0x33,0x09,0x01,0x33,0x02,0xfc,0x01,0x41,0xfe,0x81,0x01,0x7f,0xfe,0x81,0xb2,0xfe,0x83,0x01,0x7d,0x02,0xfe,0x81,0x01,0x40,0xfe,0x65,0xc7,0x01,0x69,0x01,0x6d,0xc7,0x02,0xa7,0x8e,0x89,0x90,0xff,0x00,0x01,0x00,0x90,0x89,0x8e, +0x02,0x9e,0xfd,0x97,0x02,0x69,0x00,0x00,0x00,0x02,0x02,0x13,0xfe,0x39,0x02,0xb9,0x05,0xae,0x00,0x03,0x00,0x07,0x00,0x25,0x40,0x11,0x03,0x07,0xab,0x00,0x04,0x04,0x08,0x09,0x05,0x00,0x05,0x00,0x01,0x04,0x1b,0x01,0x00,0x00,0x3f,0x3f,0x12,0x39,0x39,0x2f,0x2f,0x11,0x12,0x01,0x39,0x2f,0x33,0xed,0x32,0x31,0x30,0x01,0x11,0x33, +0x11,0x03,0x11,0x33,0x11,0x02,0x13,0xa6,0xa6,0xa6,0x02,0xa4,0x03,0x0a,0xfc,0xf6,0xfb,0x95,0x03,0x0b,0xfc,0xf5,0x00,0x00,0x00,0x02,0x00,0x9f,0xff,0x54,0x04,0x2c,0x05,0xcc,0x00,0x4d,0x00,0x61,0x01,0x05,0x40,0x73,0x73,0x10,0x83,0x10,0x02,0x69,0x56,0x01,0x75,0x60,0x85,0x60,0x02,0x43,0x5f,0x53,0x5f,0x02,0x43,0x5b,0x53,0x5b, +0x02,0x43,0x5a,0x53,0x5a,0x73,0x5a,0x83,0x5a,0x04,0x43,0x3e,0x53,0x3e,0x02,0x6a,0x15,0x7a,0x15,0x8a,0x15,0x03,0x2a,0x14,0x4a,0x14,0x5a,0x14,0x03,0x2a,0x51,0x4a,0x51,0x5a,0x51,0x6a,0x51,0x04,0x2a,0x50,0x01,0x50,0x18,0x0d,0x11,0x48,0x2a,0x48,0x01,0x6c,0x39,0x7c,0x39,0x8c,0x39,0x03,0x2a,0x39,0x01,0x05,0x1f,0x15,0x1f,0x02, +0x0a,0x24,0x1a,0x24,0x02,0x05,0x4d,0x15,0x4d,0x02,0x5d,0x1d,0x22,0x58,0x49,0x41,0x46,0x53,0x4e,0x0e,0x49,0x4b,0x06,0x49,0x05,0x37,0x49,0x22,0x4b,0xb8,0xff,0xc0,0x40,0x40,0x12,0x19,0x48,0x41,0x4b,0x05,0x22,0x22,0x05,0x4b,0x41,0x04,0x2c,0x18,0x49,0x00,0x4e,0x10,0x4e,0x02,0x4e,0x4e,0x63,0x2d,0x49,0x00,0x2c,0x01,0x2c,0x53, +0x13,0x46,0x5d,0x3c,0x1d,0x76,0x46,0x86,0x46,0x02,0x6a,0x46,0x01,0x46,0x1d,0x00,0x32,0x51,0x27,0x20,0x2d,0x80,0x2d,0x02,0x2d,0x2d,0x27,0x0b,0x51,0x00,0x06,0x06,0x00,0x00,0x00,0x3f,0x32,0x2f,0x10,0xed,0x2f,0x33,0x2f,0x5d,0x10,0xed,0x12,0x39,0x39,0x5d,0x5d,0x11,0x33,0x33,0x11,0x33,0x33,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f, +0x5d,0xed,0x11,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x2b,0x10,0xed,0x10,0xed,0x10,0xed,0x12,0x39,0x39,0x10,0xed,0x11,0x39,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x2b,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x23,0x22,0x06,0x15,0x14,0x1e,0x02,0x17,0x1e,0x03,0x15, +0x14,0x0e,0x02,0x07,0x1e,0x03,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x27,0x2e,0x03,0x35,0x34,0x3e,0x02,0x37,0x2e,0x03,0x35,0x34,0x36,0x01,0x34,0x2e,0x02,0x27,0x0e,0x03,0x15,0x14,0x1e,0x02,0x17,0x3e,0x03,0x02,0x78,0x4f,0x8a,0x6c,0x49,0x0f,0xa1,0x08,0x2e,0x43, +0x55,0x2e,0x7d,0x81,0x32,0x53,0x6d,0x3b,0x44,0x8b,0x70,0x46,0x1c,0x37,0x52,0x36,0x31,0x4f,0x37,0x1e,0x3a,0x70,0xa4,0x6b,0x5d,0x9a,0x75,0x4f,0x13,0xa1,0x0c,0x37,0x4e,0x63,0x39,0x3a,0x66,0x4d,0x2c,0x39,0x5f,0x7b,0x41,0x41,0x83,0x68,0x41,0x20,0x3b,0x54,0x35,0x2a,0x4b,0x39,0x21,0xd3,0x01,0xe1,0x35,0x58,0x71,0x3d,0x3a,0x59, +0x3c,0x1f,0x31,0x52,0x6c,0x3c,0x36,0x5d,0x44,0x27,0x05,0xcc,0x1e,0x3f,0x62,0x45,0x14,0x2d,0x3d,0x25,0x11,0x59,0x47,0x2d,0x40,0x2e,0x20,0x0e,0x10,0x2e,0x49,0x6a,0x4c,0x2d,0x57,0x49,0x37,0x0d,0x15,0x33,0x40,0x51,0x33,0x49,0x75,0x53,0x2c,0x1b,0x40,0x68,0x4d,0x1f,0x37,0x47,0x29,0x10,0x15,0x2d,0x44,0x2f,0x36,0x49,0x33,0x23, +0x10,0x0f,0x2e,0x49,0x6a,0x49,0x2d,0x53,0x47,0x35,0x0f,0x0e,0x2e,0x40,0x50,0x30,0x8b,0x9b,0xfc,0xcb,0x30,0x45,0x33,0x23,0x0e,0x03,0x21,0x34,0x45,0x27,0x2e,0x42,0x30,0x22,0x0f,0x01,0x18,0x2f,0x46,0x00,0x00,0x02,0x01,0x4f,0x04,0xc3,0x03,0x7c,0x05,0x7b,0x00,0x03,0x00,0x07,0x00,0x31,0x40,0x1f,0x03,0x85,0x00,0x00,0x07,0x85, +0x10,0x04,0x01,0x04,0x05,0x01,0x90,0x04,0x0f,0x00,0x3f,0x00,0x5f,0x00,0xaf,0x00,0xbf,0x00,0x05,0x00,0x40,0x16,0x1e,0x48,0x00,0x00,0x2f,0x2b,0x5d,0x32,0xed,0x32,0x01,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x31,0x30,0x01,0x35,0x33,0x15,0x21,0x35,0x33,0x15,0x02,0xd9,0xa3,0xfd,0xd3,0xa5,0x04,0xc3,0xb8,0xb8,0xb8,0xb8,0x00,0x00,0x00, +0x00,0x03,0x00,0x1f,0x00,0x26,0x04,0xad,0x05,0xcc,0x00,0x29,0x00,0x3d,0x00,0x51,0x01,0x1c,0x40,0x77,0x7b,0x50,0x8b,0x50,0x02,0x74,0x4a,0x84,0x4a,0x02,0x76,0x4f,0x86,0x4f,0x02,0x76,0x4b,0x86,0x4b,0x02,0x74,0x46,0x84,0x46,0x02,0x7b,0x40,0x8b,0x40,0x02,0x79,0x45,0x89,0x45,0x02,0x79,0x41,0x89,0x41,0x02,0x03,0x50,0x13,0x50, +0x02,0x03,0x4a,0x13,0x4a,0x02,0x0c,0x12,0x1c,0x12,0x2c,0x12,0x03,0x03,0x18,0x13,0x18,0x23,0x18,0x03,0x66,0x00,0x76,0x00,0x86,0x00,0x03,0x00,0xc4,0x15,0x0a,0x20,0xc6,0x1f,0x0b,0x1f,0x70,0x1f,0x80,0x1f,0x02,0x0f,0x1f,0x1f,0x1f,0x02,0x2f,0x15,0x3f,0x15,0x02,0x15,0x40,0x10,0x14,0x48,0x15,0x1f,0x15,0x1f,0x34,0x3e,0x10,0x0d, +0x11,0x48,0x3e,0xc3,0x10,0x2a,0x01,0x2a,0x2a,0x53,0x48,0xb8,0xff,0xf0,0x40,0x57,0x0d,0x11,0x48,0x48,0xc3,0x34,0x30,0x0a,0x40,0x0a,0xb0,0x0a,0xc0,0x0a,0xd0,0x0a,0x05,0x30,0x0a,0xb0,0x0a,0xc0,0x0a,0x03,0x0a,0x0a,0x05,0xc9,0x10,0x25,0xc9,0x1a,0x20,0x20,0x1a,0x7f,0x10,0x8f,0x10,0xef,0x10,0xff,0x10,0x04,0x50,0x1a,0xb0,0x1a, +0xc0,0x1a,0x03,0x00,0x1a,0x10,0x1a,0x70,0x1a,0x80,0x1a,0x04,0x10,0x1a,0x10,0x1a,0x4d,0x69,0x43,0x79,0x43,0x89,0x43,0x03,0x43,0xc8,0x39,0x00,0x66,0x4d,0x76,0x4d,0x86,0x4d,0x03,0x4d,0xc8,0x2f,0xd0,0x00,0x3f,0xed,0x5d,0x3f,0xed,0x5d,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x71,0x5d,0x11,0x33,0x2f,0x10,0xed,0x10,0xed,0x33,0x2f,0x5d, +0x71,0x01,0x2f,0xed,0x2b,0x11,0x33,0x2f,0x5d,0xed,0x2b,0x11,0x39,0x39,0x2f,0x2f,0x2b,0x5d,0x5d,0x5d,0x11,0x33,0x10,0xed,0x32,0x10,0xed,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x00,0x5d,0x5d,0x01,0x5d,0x5d,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34, +0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x23,0x22,0x0e,0x02,0x05,0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x1e,0x01,0x12,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x01,0x8e,0x1c,0x38,0x54,0x38,0x29,0x3f,0x2f,0x21,0x0c,0x73,0x13,0x34, +0x4a,0x63,0x43,0x5a,0x85,0x57,0x2b,0x2b,0x56,0x82,0x57,0x43,0x63,0x48,0x31,0x10,0x72,0x0a,0x20,0x2e,0x3c,0x27,0x3a,0x53,0x35,0x19,0x03,0x1f,0x5b,0x9e,0xd5,0x79,0x78,0xd4,0x9f,0x5c,0x5c,0x9e,0xd4,0x79,0x79,0xd5,0x9e,0x5b,0x5c,0x4d,0x86,0xb2,0x66,0x65,0xb2,0x84,0x4d,0x4d,0x84,0xb2,0x65,0x66,0xb2,0x86,0x4d,0x02,0xfb,0x48, +0x78,0x56,0x30,0x1b,0x2d,0x38,0x1c,0x23,0x2b,0x51,0x3f,0x26,0x40,0x72,0x9e,0x5e,0x62,0x9c,0x6f,0x3b,0x24,0x3b,0x4b,0x27,0x21,0x1a,0x32,0x26,0x17,0x2e,0x53,0x76,0x4a,0xbb,0xfe,0xef,0xb2,0x55,0x55,0xb2,0x01,0x11,0xbb,0xbb,0x01,0x11,0xb1,0x56,0x56,0xb1,0xfe,0xef,0xbb,0xa7,0xee,0x98,0x47,0x47,0x98,0xee,0xa7,0xa8,0xef,0x98, +0x46,0x46,0x98,0xef,0x00,0x02,0x00,0xce,0x02,0x8b,0x03,0xfd,0x05,0x98,0x00,0x2a,0x00,0x3b,0x00,0x7a,0xb9,0x00,0x03,0xff,0xe8,0xb3,0x09,0x0c,0x48,0x14,0xb8,0xff,0xd8,0x40,0x37,0x09,0x0d,0x48,0x22,0x28,0x09,0x11,0x48,0x29,0x18,0x0d,0x11,0x48,0x29,0x28,0x09,0x0c,0x48,0x1e,0x1e,0x17,0xe2,0x24,0x06,0x00,0x35,0x01,0x35,0x35, +0x00,0x3d,0x0d,0xe3,0x0e,0x0e,0x2b,0xe3,0x00,0x00,0x10,0x00,0x02,0x00,0x1a,0x30,0xe4,0x28,0x36,0xe4,0x05,0x05,0x13,0x24,0x21,0x28,0xb8,0x01,0x16,0xb4,0x0d,0x0d,0x0a,0xe4,0x13,0xb8,0x01,0x15,0x00,0x3f,0xed,0x33,0x2f,0x3f,0x33,0x33,0x12,0x39,0x2f,0xed,0x10,0xed,0x32,0x01,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f, +0x5d,0x33,0x33,0xed,0x32,0x2f,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x2b,0x13,0x34,0x3e,0x02,0x3f,0x01,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0x27,0x3e,0x03,0x33,0x32,0x16,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x15,0x0e,0x01,0x23,0x22,0x26,0x27,0x23,0x0e,0x01,0x23,0x22,0x26,0x37,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x3d,0x01, +0x07,0x0e,0x03,0xce,0x3a,0x63,0x82,0x47,0xbf,0x5e,0x56,0x54,0x5c,0x0b,0x95,0x08,0x30,0x54,0x79,0x4f,0x99,0xa6,0x1f,0x2b,0x0c,0x1c,0x09,0x17,0x38,0x17,0x52,0x4b,0x03,0x04,0x2b,0x92,0x66,0x79,0x89,0x93,0x12,0x26,0x39,0x27,0x3b,0x5c,0x41,0x22,0x9a,0x32,0x5a,0x44,0x28,0x03,0x66,0x45,0x5c,0x38,0x18,0x01,0x04,0x2b,0x5d,0x59, +0x44,0x4d,0x0a,0x2f,0x52,0x3e,0x23,0x86,0x85,0xfe,0xdd,0x3a,0x3c,0x05,0x03,0x5e,0x06,0x07,0x55,0x4b,0x4d,0x59,0x72,0x7d,0x1c,0x32,0x26,0x16,0x2d,0x44,0x51,0x25,0x33,0x04,0x01,0x0d,0x1e,0x35,0x00,0x00,0x00,0x02,0x00,0x7f,0x00,0x8d,0x04,0x60,0x03,0xac,0x00,0x08,0x00,0x11,0x00,0x50,0x40,0x2b,0x00,0xeb,0x08,0x03,0xeb,0x04, +0xec,0x06,0xeb,0x01,0x01,0x13,0x0a,0x09,0xeb,0x11,0x0c,0xeb,0x0d,0xec,0x0f,0xeb,0x00,0x0a,0x01,0x0a,0x0b,0x02,0x0a,0x01,0x0c,0x09,0x00,0x01,0x02,0x0f,0x03,0x06,0x06,0x03,0xef,0x00,0xee,0x00,0x3f,0xe4,0x39,0x3d,0x2f,0x17,0x33,0x11,0x33,0x32,0x11,0x33,0x11,0x33,0x01,0x18,0x2f,0x5d,0xed,0xfd,0xed,0xd4,0xed,0x11,0x12,0x39, +0x2f,0xed,0xfd,0xed,0xd4,0xed,0x31,0x30,0x25,0x01,0x35,0x01,0x33,0x15,0x09,0x01,0x15,0x21,0x01,0x35,0x01,0x33,0x15,0x09,0x01,0x15,0x03,0xac,0xfe,0xae,0x01,0x52,0xb2,0xfe,0xae,0x01,0x54,0xfd,0x6f,0xfe,0xb0,0x01,0x50,0xb1,0xfe,0xb1,0x01,0x51,0x8d,0x01,0x6d,0x3f,0x01,0x73,0x1f,0xfe,0x8c,0xfe,0x91,0x1d,0x01,0x6d,0x3f,0x01, +0x73,0x1f,0xfe,0x8c,0xfe,0x91,0x1d,0x00,0x00,0x01,0x00,0x74,0x00,0xb4,0x04,0x57,0x02,0xf2,0x00,0x05,0x00,0x21,0x40,0x12,0x00,0xaa,0x05,0x07,0x00,0x02,0x10,0x02,0x02,0x02,0x3f,0x00,0x01,0x00,0x02,0xad,0x03,0xb3,0x00,0x3f,0xfd,0xc6,0x5d,0x01,0x2f,0x5d,0x10,0xde,0xed,0x31,0x30,0x25,0x11,0x21,0x35,0x21,0x11,0x03,0xc6,0xfc, +0xae,0x03,0xe3,0xb4,0x01,0xac,0x92,0xfd,0xc2,0x00,0x00,0x00,0x00,0x04,0x00,0x1f,0x00,0x26,0x04,0xad,0x05,0xcc,0x00,0x13,0x00,0x27,0x00,0x35,0x00,0x3e,0x00,0xec,0x40,0x29,0x7b,0x26,0x8b,0x26,0x02,0x74,0x20,0x84,0x20,0x02,0x76,0x25,0x86,0x25,0x02,0x76,0x21,0x86,0x21,0x02,0x74,0x1c,0x84,0x1c,0x02,0x7b,0x16,0x8b,0x16,0x02, +0x79,0x1b,0x89,0x1b,0x02,0x79,0x17,0x89,0x17,0x02,0x2f,0xb8,0xff,0xd8,0x40,0x15,0x0b,0x11,0x48,0x33,0x28,0x09,0x0c,0x48,0x03,0x26,0x13,0x26,0x02,0x03,0x20,0x13,0x20,0x02,0x34,0x29,0x29,0xb8,0xff,0xf0,0x40,0x26,0x29,0x31,0x3b,0x2b,0xc4,0x2c,0x28,0x35,0x10,0x35,0x35,0x31,0xc4,0x36,0x70,0x36,0x80,0x36,0x02,0x2c,0x36,0x2c, +0x36,0x0a,0x14,0x10,0x0d,0x11,0x48,0x14,0xc3,0x10,0x00,0x01,0x00,0x00,0x40,0x1e,0xb8,0xff,0xf0,0x40,0x32,0x0d,0x11,0x48,0x1e,0xc3,0x0a,0x28,0x2c,0x34,0x2a,0xc8,0x3b,0x3a,0xc8,0x2d,0x00,0x2d,0x10,0x2d,0x02,0x2c,0x3b,0x2d,0x2d,0x3b,0x2c,0x03,0x23,0x69,0x19,0x79,0x19,0x89,0x19,0x03,0x19,0xc8,0x0f,0x00,0x66,0x23,0x76,0x23, +0x86,0x23,0x03,0x23,0xc8,0x05,0xd0,0x00,0x3f,0xed,0x5d,0x3f,0xed,0x5d,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x5d,0x10,0xed,0x10,0xed,0x32,0x11,0x33,0x01,0x2f,0xed,0x2b,0x11,0x33,0x2f,0x5d,0xed,0x2b,0x11,0x39,0x39,0x2f,0x2f,0x5d,0x10,0xed,0x32,0x2f,0x38,0x33,0x10,0xed,0x32,0x11,0x39,0x38,0x11,0x33,0x31,0x30,0x00,0x5d,0x5d,0x2b, +0x2b,0x5d,0x5d,0x01,0x5d,0x5d,0x00,0x5d,0x5d,0x01,0x5d,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x1e,0x01,0x12,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x05,0x03,0x23,0x11,0x23,0x11,0x21,0x32,0x16,0x15,0x14,0x06,0x07,0x13,0x03,0x34, +0x26,0x2b,0x01,0x11,0x33,0x32,0x36,0x04,0xad,0x5b,0x9e,0xd5,0x79,0x78,0xd4,0x9f,0x5c,0x5c,0x9e,0xd4,0x79,0x79,0xd5,0x9e,0x5b,0x5c,0x4d,0x86,0xb2,0x66,0x65,0xb2,0x84,0x4d,0x4d,0x84,0xb2,0x65,0x66,0xb2,0x86,0x4d,0xfe,0xde,0xc7,0xa1,0x7f,0x01,0x33,0x8e,0x97,0x68,0x55,0xdd,0x9f,0x5f,0x51,0xaa,0xb6,0x50,0x54,0x02,0xf9,0xbb, +0xfe,0xef,0xb2,0x55,0x55,0xb2,0x01,0x11,0xbb,0xbb,0x01,0x11,0xb1,0x56,0x56,0xb1,0xfe,0xef,0xbb,0xa7,0xee,0x98,0x47,0x47,0x98,0xee,0xa7,0xa8,0xef,0x98,0x46,0x46,0x98,0xef,0xfa,0x01,0x50,0xfe,0xb0,0x03,0x3f,0x7e,0x6f,0x66,0x7b,0x13,0xfe,0xa2,0x02,0x50,0x45,0x48,0xfe,0xd3,0x55,0x00,0xff,0xff,0xff,0xfb,0x05,0xf2,0x04,0xd1, +0x06,0x52,0x12,0x07,0x00,0x42,0x00,0x00,0x06,0xce,0x00,0x00,0x00,0x02,0x01,0x47,0x03,0x20,0x03,0x85,0x05,0x5a,0x00,0x13,0x00,0x27,0x00,0x4a,0xb9,0x00,0x11,0xff,0xe8,0xb3,0x09,0x0c,0x48,0x0d,0xb8,0xff,0xe8,0x40,0x26,0x09,0x0c,0x48,0x07,0x18,0x09,0x0c,0x48,0x03,0x18,0x09,0x0c,0x48,0x14,0xac,0x00,0x00,0x1e,0xac,0x00,0x0a, +0x10,0x0a,0x80,0x0a,0x03,0x0a,0x23,0xaf,0x00,0x05,0x01,0x05,0x05,0x19,0xaf,0x0f,0x04,0x00,0x3f,0xed,0x33,0x2f,0x5d,0xed,0x01,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14, +0x1e,0x02,0x33,0x32,0x3e,0x02,0x03,0x85,0x2d,0x4e,0x69,0x3b,0x3b,0x68,0x4e,0x2e,0x2e,0x4e,0x68,0x3b,0x3b,0x69,0x4e,0x2d,0x6d,0x1b,0x30,0x41,0x26,0x25,0x41,0x30,0x1c,0x1c,0x30,0x41,0x25,0x26,0x41,0x30,0x1b,0x04,0x3d,0x3b,0x68,0x4d,0x2d,0x2d,0x4d,0x68,0x3b,0x3c,0x68,0x4d,0x2c,0x2c,0x4d,0x68,0x3c,0x26,0x41,0x31,0x1c,0x1c, +0x31,0x41,0x26,0x25,0x41,0x31,0x1d,0x1d,0x31,0x41,0x00,0x00,0x00,0x02,0x00,0x74,0x00,0x00,0x04,0x57,0x04,0xc3,0x00,0x0b,0x00,0x0f,0x00,0x6a,0x40,0x37,0x0f,0x0c,0x04,0x0b,0x0e,0x01,0x04,0x02,0x0e,0x04,0x09,0x01,0xaa,0x06,0x00,0x02,0x01,0x0a,0x03,0x02,0x02,0x10,0x11,0x0d,0xad,0x40,0x0c,0x02,0x0e,0x04,0x07,0x05,0x0e,0x2f, +0x07,0x3f,0x07,0x8f,0x07,0x03,0x8f,0x07,0x9f,0x07,0xdf,0x07,0xef,0x07,0x04,0x07,0x00,0x04,0xad,0x09,0x05,0xb8,0xff,0xc0,0xb3,0x13,0x16,0x48,0x05,0x00,0x2f,0x2b,0x33,0xed,0x32,0xc6,0x5d,0x71,0x2b,0x00,0x18,0x10,0x4d,0xe6,0x2f,0x1a,0xed,0x11,0x12,0x01,0x39,0x2f,0x5f,0x5e,0x5d,0x33,0xed,0x32,0xc6,0x2b,0x01,0x18,0x10,0x4d, +0xe6,0x11,0x33,0x32,0x31,0x30,0x01,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x33,0x11,0x21,0x15,0x01,0x35,0x21,0x15,0x02,0xaf,0x93,0xfe,0x58,0x01,0xa8,0x93,0x01,0xa8,0xfc,0x1d,0x03,0xe3,0x02,0xa8,0xfe,0x75,0x01,0x8b,0x91,0x01,0x8a,0xfe,0x76,0x91,0xfd,0x58,0x91,0x91,0x00,0x01,0x01,0x38,0x02,0x33,0x03,0x94,0x05,0x8d,0x00,0x20, +0x00,0x53,0xb5,0x5a,0x02,0x6a,0x02,0x02,0x15,0xb8,0xff,0xd8,0x40,0x28,0x09,0x0e,0x48,0x1f,0x1f,0x17,0xe1,0x6f,0x08,0x8f,0x08,0x02,0x08,0x08,0x00,0x22,0x0e,0xe0,0x0f,0x0f,0x00,0x1e,0x1e,0x00,0x00,0x10,0x00,0x02,0x00,0x0e,0x0e,0x0b,0xe4,0x14,0xde,0x01,0x1e,0xe4,0x00,0xdd,0x00,0x3f,0xed,0x32,0x3f,0xed,0x33,0x2f,0x01,0x2f, +0x5d,0x33,0x2f,0x11,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f,0x5d,0xed,0x32,0x2f,0x31,0x30,0x00,0x2b,0x01,0x5d,0x01,0x27,0x3e,0x05,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0x27,0x3e,0x03,0x33,0x32,0x16,0x15,0x14,0x0e,0x04,0x07,0x21,0x17,0x01,0x3a,0x02,0x1b,0x58,0x64,0x67,0x52,0x34,0x47,0x4a,0x44,0x58,0x08,0x85,0x06,0x2e,0x4c,0x6c, +0x43,0x83,0x91,0x36,0x55,0x67,0x63,0x53,0x16,0x01,0xcb,0x02,0x02,0x33,0x67,0x3d,0x5f,0x50,0x47,0x49,0x52,0x32,0x3e,0x4b,0x49,0x44,0x08,0x33,0x57,0x40,0x25,0x7f,0x70,0x3d,0x62,0x52,0x49,0x49,0x4e,0x2f,0x6b,0x00,0x00,0x00,0x00,0x01,0x01,0x32,0x02,0x27,0x03,0x99,0x05,0x8d,0x00,0x35,0x00,0x7b,0xb9,0x00,0x2a,0xff,0xe8,0x40, +0x20,0x09,0x0f,0x48,0x02,0x28,0x09,0x0c,0x48,0x30,0x2d,0x16,0x22,0xe1,0x23,0x23,0x08,0x2d,0xe1,0x1c,0x4f,0x16,0x5f,0x16,0x02,0x16,0x1c,0x16,0x1c,0x08,0x00,0xe1,0x0f,0xb8,0xff,0xc0,0x40,0x22,0x09,0x0c,0x48,0x0f,0x0f,0x37,0x09,0xe1,0x00,0x08,0x10,0x08,0x02,0x08,0x30,0x15,0xe4,0x16,0x16,0x0c,0x28,0x22,0x22,0x1f,0xe4,0x28, +0xde,0x0c,0xe4,0x03,0x09,0x09,0x03,0xdf,0x00,0x3f,0x33,0x2f,0x10,0xed,0x3f,0xed,0x33,0x2f,0x11,0x12,0x39,0x2f,0xed,0x39,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x2b,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x10,0xed,0x11,0x33,0x2f,0xed,0x11,0x12,0x39,0x31,0x30,0x00,0x2b,0x2b,0x01,0x14,0x06,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x01, +0x33,0x32,0x36,0x35,0x34,0x2e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x14,0x06,0x07,0x15,0x1e,0x03,0x03,0x99,0x9b,0x8e,0x57,0x74,0x49,0x24,0x06,0x88,0x09,0x58,0x55,0x4d,0x53,0x25,0x38,0x43,0x1d,0x3d,0x39,0x1d,0x3d,0x32,0x20,0x4a,0x47,0x44,0x54, +0x06,0x87,0x07,0x32,0x4f,0x67,0x3a,0x45,0x68,0x46,0x23,0x56,0x5a,0x34,0x4b,0x30,0x16,0x03,0x1b,0x74,0x80,0x27,0x40,0x51,0x2b,0x0d,0x43,0x45,0x48,0x4c,0x2d,0x36,0x1d,0x09,0x6d,0x0d,0x1f,0x35,0x28,0x3c,0x45,0x46,0x41,0x0c,0x3a,0x56,0x39,0x1c,0x21,0x3b,0x4f,0x2e,0x4b,0x6e,0x14,0x02,0x05,0x25,0x36,0x44,0x00,0x01,0x01,0x92, +0x04,0xb1,0x03,0x3a,0x05,0xb4,0x00,0x05,0x00,0x1a,0x40,0x0e,0x7b,0x02,0x8b,0x02,0x02,0x80,0x03,0x01,0x03,0x00,0x02,0x8c,0x05,0x93,0x00,0x3f,0xed,0x01,0x2f,0xcd,0x5d,0x31,0x30,0x5d,0x01,0x35,0x37,0x33,0x15,0x05,0x01,0x92,0xe3,0xc5,0xfe,0xd4,0x04,0xb1,0x14,0xef,0x1d,0xe6,0x00,0x00,0x00,0x01,0x00,0x90,0xfe,0x77,0x04,0x3c, +0x04,0x3a,0x00,0x27,0x00,0x68,0x40,0x18,0x0b,0x10,0x0f,0x12,0x48,0x39,0x07,0x01,0x22,0x46,0x05,0x10,0x1f,0x20,0x1f,0x02,0x60,0x1f,0xc0,0x1f,0xd0,0x1f,0x03,0x1f,0xb8,0xff,0xc0,0x40,0x2a,0x24,0x53,0x48,0x1f,0x1f,0x29,0x15,0x0d,0x11,0x46,0x12,0x40,0x27,0x53,0x48,0x12,0x40,0x1c,0x23,0x48,0x12,0x40,0x12,0x15,0x48,0x00,0x12, +0x01,0x12,0x20,0x13,0x0f,0x12,0x1b,0x1a,0x50,0x0c,0x05,0x09,0x16,0x00,0x15,0x00,0x3f,0x3f,0x33,0x33,0xed,0x3f,0x3f,0x33,0x01,0x2f,0x5d,0x2b,0x2b,0x2b,0xed,0x32,0x32,0x12,0x39,0x2f,0x2b,0x5d,0x71,0x33,0xed,0x31,0x30,0x00,0x5d,0x2b,0x21,0x2e,0x03,0x35,0x23,0x0e,0x01,0x23,0x22,0x26,0x27,0x23,0x1e,0x01,0x15,0x11,0x23,0x11, +0x33,0x11,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x17,0x03,0x94,0x01,0x03,0x03,0x03,0x04,0x35,0xa7,0x72,0x52,0x80,0x20,0x04,0x03,0x01,0xb6,0xb6,0x1b,0x3f,0x65,0x49,0x43,0x70,0x52,0x2e,0xb5,0x01,0x02,0x02,0x01,0x06,0x31,0x3e,0x3f,0x13,0x6d,0x6e,0x40,0x3a,0x20,0x3f,0x1b,0xfe,0x8b,0x05,0xc3, +0xfd,0x7c,0x45,0x74,0x55,0x2f,0x34,0x5b,0x7e,0x4b,0x02,0x69,0xfc,0xaf,0x22,0x4c,0x43,0x31,0x07,0x00,0x00,0x01,0x00,0x7f,0xfe,0xbc,0x04,0x38,0x05,0x45,0x00,0x13,0x00,0x41,0x40,0x18,0x05,0x9a,0x00,0x06,0x01,0x06,0x06,0x0c,0x02,0x13,0x13,0x01,0x9a,0x02,0x02,0x15,0x00,0x0c,0x10,0x0c,0x02,0x0c,0x04,0x13,0xb8,0x01,0x10,0xb7, +0x12,0x07,0x07,0x01,0x12,0x03,0x06,0x01,0x00,0x2f,0x33,0x3f,0x12,0x39,0x2f,0x10,0xed,0x32,0x01,0x2f,0x5d,0x12,0x39,0x2f,0xed,0x32,0x2f,0x11,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x01,0x11,0x23,0x11,0x23,0x11,0x23,0x11,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x21,0x15,0x03,0xb7,0x84,0xc5,0x85,0x50,0x85,0x60,0x35,0x32,0x5f, +0x8a,0x57,0x02,0x47,0x04,0xcb,0xf9,0xf1,0x06,0x0f,0xf9,0xf1,0x03,0xbe,0x2d,0x58,0x86,0x58,0x54,0x85,0x5d,0x32,0x7a,0x00,0xff,0xff,0x01,0xf0,0x01,0xa4,0x02,0xdb,0x02,0xcf,0x12,0x06,0x02,0x3a,0x00,0x00,0x00,0x01,0x00,0x77,0xfe,0x44,0x01,0xe3,0x00,0x00,0x00,0x1b,0x00,0x52,0xb9,0x00,0x1a,0xff,0xe8,0x40,0x2f,0x0f,0x13,0x48, +0x44,0x1a,0x54,0x1a,0x02,0x03,0x18,0x0d,0x13,0x48,0x18,0x19,0x19,0x17,0x16,0x40,0x09,0x0c,0x48,0x16,0x16,0x08,0x10,0x87,0x00,0x00,0x00,0x08,0x01,0x08,0x13,0x92,0x19,0x40,0x0d,0x10,0x48,0x19,0x19,0x17,0x0b,0x8d,0x05,0x95,0x00,0x3f,0xed,0x2f,0x39,0x2f,0x2b,0xed,0x01,0x2f,0x5d,0x33,0x2f,0xed,0x11,0x39,0x2f,0x2b,0x33,0x33, +0x11,0x33,0x31,0x30,0x00,0x2b,0x5d,0x2b,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x35,0x16,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x23,0x2a,0x01,0x07,0x37,0x33,0x07,0x1e,0x01,0x01,0xe3,0x1e,0x41,0x68,0x4b,0x14,0x2d,0x19,0x32,0x24,0x29,0x39,0x22,0x0f,0x3d,0x48,0x0e,0x1d,0x0e,0x41,0x6b,0x27,0x5e,0x5e,0xfe,0xfe,0x2a,0x45,0x31, +0x1a,0x01,0x03,0x62,0x06,0x0d,0x16,0x20,0x13,0x28,0x2a,0x02,0xb6,0x64,0x03,0x53,0x00,0x01,0x01,0x1d,0x02,0x33,0x03,0x9b,0x05,0x82,0x00,0x12,0x00,0x3f,0x40,0x22,0x3f,0x11,0x01,0x11,0x11,0x10,0xe0,0x02,0x08,0x08,0x01,0x01,0x0e,0x00,0x02,0x10,0x02,0x02,0x02,0x02,0x13,0x14,0x08,0xe4,0x09,0x09,0x03,0x0e,0xdc,0x10,0x01,0xe4, +0x00,0xdd,0x00,0x3f,0xed,0x32,0x3f,0x33,0x33,0x2f,0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0x33,0x33,0x2f,0x33,0x2f,0x10,0xed,0x32,0x2f,0x5d,0x31,0x30,0x01,0x35,0x21,0x11,0x0e,0x03,0x23,0x35,0x32,0x3e,0x02,0x37,0x33,0x11,0x33,0x15,0x01,0x23,0x01,0x09,0x0d,0x37,0x4a,0x56,0x2b,0x30,0x57,0x49,0x38,0x11,0x79,0xec,0x02,0x33,0x6b, +0x02,0x62,0x1a,0x2a,0x1e,0x11,0x6d,0x12,0x23,0x32,0x21,0xfd,0x1c,0x6b,0x00,0x00,0x00,0x02,0x00,0xe2,0x02,0x8b,0x03,0xea,0x05,0x98,0x00,0x13,0x00,0x21,0x00,0x52,0x40,0x30,0x7a,0x19,0x8a,0x19,0x02,0x7a,0x15,0x8a,0x15,0x02,0x75,0x21,0x85,0x21,0x02,0x75,0x1c,0x85,0x1c,0x02,0x00,0xe3,0x90,0x14,0xa0,0x14,0xc0,0x14,0x03,0x14, +0x14,0x23,0x1a,0xe3,0x6f,0x0a,0x01,0x00,0x0a,0x10,0x0a,0x50,0x0a,0x03,0x0a,0x17,0xe4,0x0f,0xb8,0x01,0x15,0xb2,0x1f,0xe4,0x05,0xb8,0x01,0x16,0x00,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32, +0x1e,0x02,0x07,0x34,0x26,0x23,0x22,0x06,0x15,0x14,0x1e,0x02,0x33,0x32,0x36,0x03,0xea,0x31,0x62,0x92,0x62,0x5d,0x90,0x61,0x33,0x30,0x61,0x92,0x62,0x67,0x93,0x5d,0x2c,0x95,0x78,0x72,0x74,0x7d,0x22,0x3d,0x55,0x33,0x75,0x7f,0x04,0x12,0x57,0x8f,0x68,0x39,0x39,0x68,0x8f,0x57,0x54,0x8f,0x68,0x3b,0x3a,0x68,0x8f,0x55,0x97,0x86, +0x88,0x95,0x4c,0x6d,0x45,0x20,0x85,0x00,0x00,0x02,0x00,0x6b,0x00,0x8d,0x04,0x4c,0x03,0xac,0x00,0x08,0x00,0x11,0x00,0x50,0x40,0x2a,0x03,0xeb,0x08,0xec,0x01,0x06,0xeb,0x05,0x00,0xeb,0x01,0x01,0x13,0x0a,0x0c,0xeb,0x10,0xec,0x0a,0x0f,0xeb,0x0e,0x09,0xeb,0x0a,0x11,0x08,0x10,0x07,0x0f,0x09,0x00,0x07,0x08,0x0c,0x03,0x03,0x03, +0x06,0xef,0x00,0xee,0x00,0x3f,0xe4,0x39,0x3d,0x2f,0x17,0x33,0x11,0x33,0x32,0x11,0x33,0x11,0x33,0x01,0x18,0x2f,0xed,0xd4,0xed,0x10,0xfd,0xed,0x11,0x12,0x39,0x2f,0xed,0xd4,0xed,0x10,0xfd,0xed,0x31,0x30,0x25,0x23,0x35,0x09,0x01,0x35,0x33,0x01,0x15,0x01,0x23,0x35,0x09,0x01,0x35,0x33,0x01,0x15,0x02,0xfa,0xb2,0x01,0x52,0xfe, +0xb0,0xb0,0x01,0x52,0xfc,0xd3,0xb4,0x01,0x52,0xfe,0xb0,0xb2,0x01,0x4f,0x8d,0x1d,0x01,0x6f,0x01,0x74,0x1f,0xfe,0x8d,0x3f,0xfe,0x93,0x1d,0x01,0x6f,0x01,0x74,0x1f,0xfe,0x8d,0x3f,0x00,0xff,0xff,0x00,0x1b,0x00,0x00,0x04,0xcd,0x05,0x45,0x10,0x27,0x02,0x9a,0xfe,0xf6,0x00,0x00,0x10,0x26,0x02,0x1e,0x00,0x00,0x11,0x07,0x02,0x9d, +0x01,0x98,0xfd,0xb6,0x00,0x28,0x40,0x17,0x03,0x02,0x18,0x18,0x03,0x02,0x50,0x19,0x01,0x40,0x19,0x01,0x19,0x01,0x60,0x14,0x01,0x14,0x00,0x20,0x00,0x01,0x00,0x11,0x5d,0x35,0x11,0x5d,0x35,0x11,0x5d,0x5d,0x35,0x35,0x00,0x3f,0x35,0x35,0x00,0x00,0xff,0xff,0x00,0x11,0x00,0x00,0x04,0xb0,0x05,0x45,0x10,0x27,0x02,0x9a,0xfe,0xec, +0x00,0x00,0x10,0x26,0x02,0x1e,0xf0,0x00,0x11,0x07,0x02,0x9b,0x01,0xac,0xfd,0xb4,0x00,0x18,0x40,0x0d,0x02,0x17,0x18,0x01,0x60,0x14,0x01,0x14,0x00,0x20,0x00,0x01,0x00,0x11,0x5d,0x35,0x11,0x5d,0x35,0x00,0x3f,0x35,0x00,0x00,0xff,0xff,0x00,0x0b,0x00,0x00,0x04,0xcd,0x05,0x51,0x10,0x27,0x02,0x9c,0xff,0x21,0x00,0x00,0x10,0x26, +0x02,0x1e,0x19,0x00,0x11,0x07,0x02,0x9d,0x01,0x98,0xfd,0xb6,0x00,0x20,0x40,0x12,0x03,0x02,0x35,0x18,0x03,0x02,0x50,0x3a,0x01,0x40,0x3a,0x01,0x3a,0x00,0x40,0x00,0x01,0x00,0x11,0x5d,0x35,0x11,0x5d,0x5d,0x35,0x35,0x00,0x3f,0x35,0x35,0x00,0x00,0x00,0x02,0x00,0x99,0xfe,0xdf,0x04,0x6c,0x04,0x39,0x00,0x27,0x00,0x2b,0x00,0x77, +0x40,0x36,0x66,0x06,0x76,0x06,0x86,0x06,0x03,0x66,0x04,0x76,0x04,0x86,0x04,0x03,0x45,0x1b,0x55,0x1b,0x02,0x69,0x00,0x79,0x00,0x89,0x00,0x03,0x0a,0x09,0x28,0x98,0x2b,0x2b,0x00,0x1e,0x98,0x00,0x1d,0x70,0x1d,0x80,0x1d,0x03,0x1d,0x1d,0x2d,0x13,0x98,0x00,0x00,0x10,0x00,0x02,0x00,0x09,0xb8,0xff,0xc0,0x40,0x15,0x0f,0x13,0x48, +0x09,0x09,0x23,0x2a,0x9d,0x2b,0x69,0x23,0x79,0x23,0x89,0x23,0x03,0x1d,0x1d,0x18,0x9e,0x23,0xb8,0x01,0x0e,0x00,0x3f,0xed,0x33,0x2f,0x5d,0x2f,0xed,0x11,0x39,0x2f,0x2b,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0xed,0x33,0x32,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x37,0x34,0x3e,0x06,0x37,0x33,0x0e,0x07,0x15, +0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x01,0x15,0x23,0x35,0x99,0x25,0x3e,0x4f,0x52,0x4f,0x3f,0x27,0x01,0xaf,0x02,0x27,0x3e,0x4e,0x50,0x4d,0x3c,0x25,0x29,0x4d,0x6d,0x44,0x44,0x6f,0x52,0x32,0x07,0xb8,0x0c,0x4a,0x7e,0xaf,0x71,0x6c,0xb1,0x7e,0x44,0x02,0x71,0xc3,0x4f,0x45,0x68,0x52,0x42, +0x3b,0x3b,0x44,0x53,0x37,0x43,0x66,0x51,0x41,0x3b,0x3b,0x44,0x53,0x35,0x37,0x54,0x39,0x1e,0x26,0x47,0x65,0x3e,0x0c,0x5a,0x97,0x6c,0x3d,0x30,0x5d,0x89,0x04,0x44,0xc9,0xc9,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa7,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x00,0x43,0xff,0xa3,0x00,0xf3,0x00,0x15,0xb4,0x02, +0x15,0x05,0x26,0x02,0xb8,0xff,0xa3,0xb4,0x16,0x19,0x04,0x07,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa8,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x5d,0x00,0xf4,0x00,0x13,0x40,0x0b,0x02,0x15,0x05,0x26,0x02,0x5d,0x15,0x18,0x04,0x07,0x25,0x01,0x2b,0x35,0x00,0x2b, +0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa8,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x01,0x4b,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x02,0x16,0x05,0x26,0x02,0x00,0x1b,0x15,0x04,0x07,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0x9d,0x12,0x26, +0x00,0x24,0x00,0x00,0x11,0x07,0x01,0x52,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x02,0x15,0x05,0x26,0x02,0x00,0x20,0x30,0x04,0x07,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0x5d,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x00,0x00,0xe2,0x00,0x17,0x40,0x0d, +0x03,0x02,0x15,0x05,0x26,0x03,0x02,0x00,0x19,0x17,0x04,0x07,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0x60,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x06,0x01,0x50,0x03,0x55,0x00,0x16,0x40,0x0c,0x03,0x02,0x38,0x03,0x03,0x02,0x03,0x1f,0x15,0x04,0x07,0x25,0x01,0x2b, +0x35,0x35,0x00,0x3f,0x35,0x35,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x04,0xab,0x05,0x45,0x00,0x0f,0x00,0x18,0x00,0x85,0x40,0x51,0x0b,0x04,0x2b,0x04,0x9b,0x04,0x03,0x17,0x01,0x02,0x04,0x01,0x52,0x02,0x11,0x02,0x5e,0x03,0x04,0x14,0x03,0x04,0x02,0x03,0x09,0x05,0x09,0x05,0x0d,0x08,0x0c,0x5c,0x18,0x0f,0x0f,0x03,0x0d,0x0d, +0x1a,0x03,0x01,0x5f,0x17,0x0b,0x5f,0x08,0x0f,0x08,0x3f,0x08,0x7f,0x08,0x8f,0x08,0x04,0x6f,0x08,0x8f,0x08,0x9f,0x08,0xbf,0x08,0xdf,0x08,0x05,0x17,0x08,0x17,0x08,0x0c,0x11,0x07,0x5f,0x04,0x03,0x0c,0x5f,0x03,0x0f,0x12,0x00,0x3f,0x33,0xed,0x3f,0xed,0x32,0x12,0x39,0x39,0x2f,0x2f,0x71,0x72,0x10,0xed,0x10,0xed,0x01,0x2f,0x12, +0x39,0x2f,0x12,0x39,0x2f,0x33,0xed,0x32,0x12,0x39,0x39,0x2f,0x2f,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87,0x2b,0xc4,0x10,0xc0,0xc0,0x31,0x30,0x01,0x5d,0x01,0x21,0x03,0x23,0x01,0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x11,0x23,0x0e,0x03,0x07,0x03,0x21,0x02,0x86,0xfe,0xb1,0x8e,0xa8,0x01,0xe6,0x02,0x9b,0xfe,0xaf, +0x01,0x47,0xfe,0xb9,0x01,0x7a,0xfd,0xdb,0x49,0x04,0x14,0x15,0x15,0x06,0x8b,0x01,0x1c,0x01,0x9c,0xfe,0x64,0x05,0x45,0x98,0xfe,0x52,0x96,0xfe,0x2f,0x98,0x04,0xb2,0x10,0x42,0x48,0x44,0x12,0xfe,0x6f,0x00,0xff,0xff,0x00,0x71,0xfe,0x44,0x04,0x76,0x05,0x5a,0x12,0x26,0x00,0x26,0x00,0x00,0x11,0x07,0x00,0x78,0x01,0x62,0x00,0x00, +0x00,0x0b,0xb6,0x01,0x1b,0x32,0x2a,0x15,0x0b,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0xa8,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x00,0x43,0xff,0xb9,0x00,0xf4,0x00,0x15,0xb4,0x01,0x0c,0x05,0x26,0x01,0xb8,0xff,0x9d,0xb4,0x0d,0x10,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00, +0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0xa8,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x5b,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x0c,0x05,0x26,0x01,0x3f,0x0c,0x0f,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0xa8,0x12,0x26,0x00,0x28,0x00,0x00, +0x11,0x07,0x01,0x4b,0x00,0x00,0x00,0xf4,0x00,0x15,0xb4,0x01,0x0d,0x05,0x26,0x01,0xb8,0xff,0xe4,0xb4,0x12,0x0c,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0x5d,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x14,0x00,0xe2,0x00,0x19,0xb6,0x02,0x01,0x0c,0x05,0x26, +0x02,0x01,0xb8,0xff,0xf8,0xb4,0x10,0x0e,0x00,0x0a,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0xa8,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x00,0x43,0xff,0xaf,0x00,0xf4,0x00,0x15,0xb4,0x01,0x0c,0x05,0x26,0x01,0xb8,0xff,0xb0,0xb4,0x0d,0x10,0x00,0x01,0x25,0x01,0x2b,0x35, +0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0xa8,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x67,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x0c,0x05,0x26,0x01,0x67,0x0c,0x0f,0x00,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0xa8,0x12,0x26, +0x00,0x2c,0x00,0x00,0x11,0x07,0x01,0x4b,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x0d,0x05,0x26,0x01,0x00,0x12,0x0c,0x00,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0x5d,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x00,0x00,0xe2,0x00,0x17,0x40,0x0d, +0x02,0x01,0x0c,0x05,0x26,0x02,0x01,0x00,0x10,0x0e,0x00,0x01,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0x00,0x02,0x00,0x1b,0x00,0x00,0x04,0x65,0x05,0x45,0x00,0x10,0x00,0x1f,0x00,0x8e,0x40,0x62,0x72,0x16,0x82,0x16,0x02,0x02,0x30,0x16,0x60,0x16,0x02,0x14,0x16,0x24,0x16,0x02,0x79,0x1a,0x89,0x1a,0x02,0x7f, +0x19,0x8f,0x19,0x02,0x1b,0x19,0x2b,0x19,0x3b,0x19,0x6b,0x19,0x04,0x11,0x11,0x06,0x00,0x5a,0x00,0x17,0x01,0x17,0x17,0x21,0x1e,0x13,0x5a,0x06,0x0a,0x06,0x08,0x08,0x00,0x06,0x10,0x06,0x02,0x06,0x12,0x08,0x5f,0x1e,0x1f,0x09,0x4f,0x09,0x02,0x3f,0x09,0x6f,0x09,0x9f,0x09,0xcf,0x09,0xdf,0x09,0xef,0x09,0x06,0x09,0x40,0x1f,0x28, +0x48,0x09,0x09,0x13,0x1d,0x5f,0x0b,0x03,0x13,0x5f,0x06,0x12,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0x2b,0x5d,0x71,0x33,0xed,0x32,0x01,0x2f,0x5d,0x33,0x2f,0x11,0x33,0x10,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5f,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x21,0x11,0x23,0x35, +0x33,0x11,0x21,0x32,0x1e,0x02,0x01,0x21,0x11,0x33,0x32,0x12,0x11,0x34,0x2e,0x02,0x2b,0x01,0x11,0x21,0x04,0x65,0x50,0x98,0xdd,0x8c,0xfe,0x8e,0x87,0x87,0x01,0x37,0x9e,0xf3,0xa6,0x55,0xfe,0x1d,0xfe,0xdf,0xa2,0xd4,0xce,0x38,0x72,0xac,0x75,0x79,0x01,0x21,0x02,0xb0,0xa8,0xfe,0xff,0xae,0x59,0x02,0x55,0x95,0x02,0x5b,0x4d,0xa2, +0xfa,0xfe,0xf9,0xfe,0x47,0x01,0x0a,0x01,0x0a,0x87,0xc0,0x79,0x39,0xfe,0x41,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x06,0x9e,0x12,0x26,0x00,0x31,0x00,0x00,0x11,0x07,0x01,0x52,0x00,0x00,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x14,0x05,0x26,0x01,0x00,0x1f,0x2f,0x08,0x12,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x06,0xa8,0x12,0x26,0x00,0x32,0x00,0x00,0x11,0x07,0x00,0x43,0xff,0xaa,0x00,0xf4,0x00,0x15,0xb4,0x02,0x1e,0x05,0x26,0x02,0xb8,0xff,0xaa,0xb4,0x1f,0x22,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x06,0xa8,0x12,0x26,0x00,0x32,0x00,0x00, +0x11,0x07,0x00,0x74,0x00,0x62,0x00,0xf4,0x00,0x13,0x40,0x0b,0x02,0x1e,0x05,0x26,0x02,0x62,0x1e,0x21,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x06,0xa8,0x12,0x26,0x00,0x32,0x00,0x00,0x11,0x07,0x01,0x4b,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x02,0x1f,0x05,0x26, +0x02,0x00,0x24,0x1e,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x06,0x9d,0x12,0x26,0x00,0x32,0x00,0x00,0x11,0x07,0x01,0x52,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x02,0x1e,0x05,0x26,0x02,0x00,0x29,0x39,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x06,0x5d,0x12,0x26,0x00,0x32,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x03,0x00,0xe2,0x00,0x17,0x40,0x0d,0x03,0x02,0x1e,0x05,0x26,0x03,0x02,0x02,0x22,0x20,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0x00,0x01,0x00,0x9d,0x00,0xe1,0x04,0x2e,0x04,0x73,0x00,0x0b, +0x00,0x8e,0x40,0x1d,0xb9,0x02,0xc9,0x02,0xd9,0x02,0x03,0xb9,0x00,0xc9,0x00,0xd9,0x00,0x03,0xb6,0x08,0xc6,0x08,0xd6,0x08,0x03,0xb6,0x06,0xc6,0x06,0xd6,0x06,0x03,0x07,0xb8,0xff,0xf0,0x40,0x0e,0x12,0x16,0x48,0x01,0x10,0x12,0x16,0x48,0x0a,0x10,0x12,0x16,0x48,0x04,0xb8,0xff,0xf0,0xb3,0x12,0x16,0x48,0x05,0xb8,0xff,0xf0,0xb6, +0x12,0x16,0x48,0x19,0x05,0x01,0x03,0xb8,0xff,0xf0,0x40,0x26,0x12,0x16,0x48,0x19,0x03,0x01,0x09,0x10,0x12,0x16,0x48,0x16,0x09,0x01,0x0b,0x10,0x12,0x16,0x48,0x16,0x0b,0x01,0x04,0x80,0x0a,0x01,0x4f,0x0a,0x01,0x00,0x0a,0x10,0x0a,0x02,0x0a,0x07,0x01,0xb2,0x00,0x19,0x3f,0x33,0x01,0x2f,0x5d,0x5d,0x5d,0x33,0x31,0x30,0x00,0x5d, +0x2b,0x5d,0x2b,0x5d,0x2b,0x5d,0x2b,0x2b,0x2b,0x01,0x2b,0x2b,0x5d,0x5d,0x5d,0x5d,0x13,0x09,0x01,0x37,0x09,0x01,0x17,0x09,0x01,0x07,0x09,0x01,0x9d,0x01,0x62,0xfe,0xa0,0x68,0x01,0x5e,0x01,0x5e,0x69,0xfe,0xa2,0x01,0x60,0x66,0xfe,0x9f,0xfe,0x9c,0x01,0x4a,0x01,0x62,0x01,0x60,0x67,0xfe,0x9f,0x01,0x5f,0x69,0xfe,0xa4,0xfe,0xa0, +0x69,0x01,0x61,0xfe,0x9d,0x00,0x00,0x00,0x00,0x03,0x00,0x38,0xff,0xda,0x04,0x92,0x05,0x70,0x00,0x1a,0x00,0x22,0x00,0x2b,0x00,0xc5,0x40,0x8c,0x8b,0x1d,0x01,0x65,0x19,0x75,0x19,0x85,0x19,0x03,0x6a,0x0c,0x7a,0x0c,0x8a,0x0c,0x03,0x77,0x0b,0x01,0x67,0x25,0x87,0x25,0x02,0x46,0x14,0x56,0x14,0x02,0x46,0x11,0x56,0x11,0x02,0x49, +0x07,0x59,0x07,0x02,0x49,0x03,0x59,0x03,0x02,0x34,0x22,0x74,0x22,0x84,0x22,0x03,0x76,0x1f,0x86,0x1f,0x02,0x7b,0x1e,0x8b,0x1e,0x02,0x36,0x1e,0x01,0x74,0x26,0x01,0x39,0x26,0x01,0x3b,0x2b,0x7b,0x2b,0x8b,0x2b,0x03,0x1d,0x26,0x1e,0x25,0x04,0x23,0x1b,0x18,0x15,0x08,0x0b,0x04,0x0e,0x17,0x00,0x5b,0x5f,0x1b,0x01,0x1b,0x40,0x19, +0x1c,0x48,0x00,0x1b,0x01,0x1b,0x1b,0x2d,0x23,0x5b,0x0a,0x50,0x0e,0x01,0x10,0x0e,0x01,0x0e,0x1e,0x25,0x1d,0x26,0x04,0x20,0x29,0x5f,0x08,0x0b,0x18,0x15,0x04,0x05,0x16,0x13,0x04,0x20,0x5f,0x09,0x05,0x13,0x00,0x3f,0x33,0xed,0x3f,0x33,0x12,0x17,0x39,0xed,0x11,0x17,0x39,0x01,0x2f,0x5d,0x71,0x33,0xed,0x12,0x39,0x2f,0x5d,0x2b, +0x71,0xed,0x32,0x11,0x17,0x39,0x11,0x12,0x17,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x00,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x22,0x26,0x27,0x07,0x27,0x37,0x2e,0x01,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x17,0x37,0x17,0x07,0x1e,0x01,0x07,0x34,0x27,0x01,0x16,0x33, +0x32,0x12,0x01,0x14,0x17,0x01,0x2e,0x01,0x23,0x22,0x02,0x04,0x66,0x46,0x84,0xbf,0x78,0x6f,0xac,0x3f,0x75,0x5e,0x8d,0x30,0x2f,0x44,0x82,0xbf,0x7c,0xd9,0x80,0x74,0x5e,0x8c,0x30,0x30,0xc9,0x1e,0xfe,0x00,0x4f,0x98,0xa3,0x94,0xfd,0x92,0x1e,0x02,0x00,0x27,0x74,0x4b,0x9c,0x9c,0x02,0xa9,0xad,0xfe,0xfa,0xb1,0x59,0x46,0x44,0x9c, +0x41,0xbd,0x58,0xe8,0x91,0xad,0x01,0x02,0xac,0x56,0x86,0x9c,0x41,0xbb,0x55,0xe4,0x92,0xa4,0x72,0xfd,0x52,0x8a,0x01,0x18,0x01,0x0a,0xa6,0x74,0x02,0xac,0x42,0x41,0xfe,0xf9,0x00,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0xa8,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x00,0x43,0xff,0x9f,0x00,0xf4,0x00,0x15,0xb4,0x01, +0x1a,0x05,0x26,0x01,0xb8,0xff,0xa0,0xb4,0x1b,0x1e,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0xa8,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x56,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x1a,0x05,0x26,0x01,0x56,0x1a,0x1d,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b, +0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0xa8,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x01,0x4b,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x1b,0x05,0x26,0x01,0x00,0x20,0x1a,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0x5d,0x12,0x26, +0x00,0x38,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x00,0x00,0xe2,0x00,0x17,0x40,0x0d,0x02,0x01,0x1a,0x05,0x26,0x02,0x01,0x00,0x1e,0x1c,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x24,0x00,0x00,0x04,0xa8,0x06,0xa8,0x12,0x26,0x00,0x3c,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x65,0x00,0xf4, +0x00,0x13,0x40,0x0b,0x01,0x09,0x05,0x26,0x01,0x65,0x09,0x0c,0x04,0x08,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0x00,0x02,0x00,0xa2,0x00,0x00,0x04,0x5f,0x05,0x45,0x00,0x10,0x00,0x1b,0x00,0x63,0x40,0x42,0x76,0x0f,0x86,0x0f,0x02,0x65,0x1a,0x75,0x1a,0x85,0x1a,0x03,0x6a,0x12,0x7a,0x12,0x8a,0x12,0x03,0x00,0x5a,0x7f, +0x11,0x8f,0x11,0x02,0x11,0x40,0x19,0x1c,0x48,0x00,0x11,0x01,0x11,0x11,0x1d,0x16,0x0b,0x07,0x5a,0x00,0x08,0x10,0x08,0xa0,0x08,0xb0,0x08,0x04,0x08,0x16,0x60,0x06,0x15,0x60,0x0b,0x06,0x0b,0x06,0x0b,0x07,0x09,0x03,0x07,0x12,0x00,0x3f,0x3f,0x12,0x39,0x39,0x2f,0x2f,0x10,0xed,0x10,0xed,0x01,0x2f,0x5d,0xed,0x32,0x32,0x12,0x39, +0x2f,0x5d,0x2b,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x21,0x15,0x23,0x11,0x33,0x15,0x21,0x32,0x1e,0x02,0x07,0x34,0x26,0x2b,0x01,0x11,0x33,0x32,0x3e,0x02,0x04,0x5f,0x3b,0x79,0xb6,0x7b,0xfe,0xe7,0xbf,0xbf,0x01,0x0d,0x7d,0xba,0x7c,0x3e,0xc0,0xa4,0xa4,0xf6,0xfe,0x52,0x79,0x4f,0x26,0x02,0xb4,0x58, +0x9f,0x78,0x47,0xfe,0x05,0x45,0xeb,0x3c,0x6f,0x9c,0x63,0x86,0x95,0xfd,0xc0,0x2c,0x4f,0x6b,0x00,0x00,0x00,0x01,0x00,0x8e,0xff,0xe3,0x04,0x8f,0x05,0xcc,0x00,0x43,0x00,0xbd,0x40,0x29,0x7c,0x3a,0x8c,0x3a,0x02,0x75,0x38,0x85,0x38,0x02,0x65,0x42,0x01,0x66,0x41,0x01,0x44,0x3f,0x54,0x3f,0x74,0x3f,0x84,0x3f,0x04,0x65,0x2f,0x01, +0x65,0x2e,0x75,0x2e,0x85,0x2e,0x03,0x03,0x28,0x09,0x0c,0x48,0x33,0xb8,0xff,0xe8,0x40,0x25,0x09,0x0c,0x48,0x39,0x1f,0x01,0x36,0x48,0x1f,0x26,0x3d,0x36,0x3d,0x02,0x3d,0x48,0x18,0x40,0x18,0x50,0x18,0x90,0x18,0xa0,0x18,0x04,0x1f,0x09,0x18,0x18,0x09,0x1f,0x03,0x2a,0x00,0x48,0x11,0xb8,0xff,0xc0,0xb3,0x12,0x17,0x48,0x11,0xb8, +0xff,0xc0,0x40,0x29,0x09,0x0e,0x48,0x11,0x11,0x45,0x2a,0x46,0x2b,0x40,0x12,0x15,0x48,0x00,0x2b,0x01,0x2b,0x11,0x3d,0x1f,0x03,0x05,0x24,0x50,0x31,0x00,0x2b,0x15,0x60,0x09,0x70,0x09,0x80,0x09,0x03,0x09,0x09,0x0e,0x50,0x05,0x16,0x00,0x3f,0xed,0x33,0x2f,0x5d,0x3f,0x3f,0xed,0x12,0x17,0x39,0x01,0x2f,0x5d,0x2b,0xed,0x12,0x39, +0x2f,0x2b,0x2b,0xed,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x5d,0x10,0xed,0x5d,0x10,0xed,0x5d,0x31,0x30,0x00,0x2b,0x2b,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x00,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x2f,0x01,0x1e,0x03,0x33,0x32,0x36,0x35,0x34,0x2e,0x04,0x35,0x34,0x3e,0x04,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23, +0x11,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x04,0x15,0x14,0x1e,0x04,0x04,0x8f,0x29,0x57,0x87,0x5f,0x50,0x94,0x37,0x02,0x1a,0x42,0x4a,0x4e,0x25,0x5c,0x62,0x36,0x51,0x5f,0x51,0x36,0x21,0x31,0x3a,0x31,0x21,0x21,0x3f,0x5a,0x39,0x44,0x6b,0x49,0x27,0xb4,0x3f,0x78,0xae,0x6e,0x66,0x9b,0x69,0x35,0x21,0x33,0x3a,0x33, +0x21,0x37,0x52,0x5f,0x52,0x37,0x01,0x27,0x42,0x76,0x58,0x34,0x19,0x18,0xa4,0x0f,0x1a,0x12,0x0a,0x5f,0x4f,0x3b,0x52,0x3f,0x39,0x47,0x5e,0x46,0x33,0x49,0x3a,0x30,0x34,0x3f,0x2b,0x25,0x3e,0x2d,0x1a,0x23,0x4d,0x7a,0x58,0xfc,0x03,0x04,0x03,0x77,0xac,0x70,0x36,0x2e,0x50,0x6d,0x3e,0x3b,0x57,0x43,0x34,0x31,0x32,0x20,0x28,0x3d, +0x3a,0x40,0x54,0x6f,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88,0x05,0xb4,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x06,0x00,0x43,0x8e,0x00,0x00,0x15,0xb4,0x02,0x42,0x11,0x26,0x02,0xb8,0xff,0x70,0xb4,0x43,0x46,0x15,0x03,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88,0x05,0xb4,0x12,0x26, +0x00,0x44,0x00,0x00,0x11,0x06,0x00,0x74,0x4d,0x00,0x00,0x13,0x40,0x0b,0x02,0x42,0x11,0x26,0x02,0x2f,0x42,0x45,0x15,0x03,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88,0x05,0xb4,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x06,0x01,0x4b,0xee,0x00,0x00,0x19,0xb7,0x02,0x43,0x11,0x26,0x02,0x20,0x48, +0x01,0xb8,0xff,0xd0,0xb4,0x48,0x42,0x15,0x03,0x25,0x01,0x2b,0x5d,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88,0x05,0xa9,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x06,0x01,0x52,0xf8,0x00,0x00,0x22,0x40,0x0e,0x02,0x42,0x11,0x26,0x02,0x30,0x4d,0x01,0x20,0x4d,0x01,0x10,0x4d,0x01,0xb8,0xff,0xda,0xb4, +0x4d,0x5d,0x15,0x03,0x25,0x01,0x2b,0x5d,0x5d,0x5d,0x35,0x00,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88,0x05,0x7b,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x06,0x00,0x69,0xf0,0x00,0x00,0x1e,0x40,0x0a,0x03,0x02,0x42,0x11,0x26,0x03,0x02,0x20,0x46,0x01,0xb8,0xff,0xd2,0xb4,0x46,0x44,0x15,0x03,0x25,0x01,0x2b,0x5d, +0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88,0x06,0x0b,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x06,0x01,0x50,0xf8,0x00,0x00,0x17,0x40,0x0d,0x03,0x02,0x47,0x11,0x26,0x03,0x02,0x12,0x4c,0x42,0x27,0x2f,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x03,0x00,0x14,0xff,0xec,0x04,0xb8, +0x04,0x4e,0x00,0x41,0x00,0x50,0x00,0x59,0x00,0xc6,0x40,0x81,0x7c,0x58,0x8c,0x58,0x02,0x7c,0x54,0x8c,0x54,0x02,0x6a,0x13,0x7a,0x13,0x8a,0x13,0x03,0x6c,0x11,0x7c,0x11,0x8c,0x11,0x03,0x05,0x3d,0x15,0x3d,0x02,0x05,0x37,0x15,0x37,0x02,0x03,0x21,0x13,0x21,0x02,0x1b,0x28,0x09,0x0e,0x48,0x14,0x38,0x56,0x00,0x49,0x4b,0x24,0x4b, +0x09,0x49,0x0a,0x0a,0x40,0x48,0x57,0xcf,0x4b,0xdf,0x4b,0x02,0x10,0x57,0x01,0x4b,0x57,0x4b,0x57,0x1e,0x5b,0x2f,0x48,0x30,0x30,0x42,0x48,0x4f,0x1e,0x5f,0x1e,0x9f,0x1e,0xaf,0x1e,0x04,0x1e,0x51,0x2a,0x50,0x35,0x00,0x50,0x56,0x4b,0x51,0x24,0x56,0x24,0x56,0x24,0x3b,0x38,0x35,0x2f,0x2f,0x8f,0x2f,0x02,0x2f,0x2f,0x35,0x10,0x06, +0x45,0x50,0x19,0x14,0x0f,0x19,0x80,0x09,0x01,0x09,0x09,0x19,0x16,0x00,0x3f,0x33,0x2f,0x5d,0x11,0x33,0x33,0x10,0xed,0x32,0x3f,0x33,0x2f,0x5d,0x11,0x33,0x33,0x39,0x39,0x2f,0x2f,0x10,0xed,0x10,0xed,0x10,0xed,0x32,0x01,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x10,0xed,0x32,0x2f,0xed,0x11,0x33, +0x10,0xed,0x32,0x39,0x39,0x31,0x30,0x00,0x2b,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x15,0x1e,0x03,0x33,0x32,0x36,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x27,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x3f,0x01,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x07,0x27,0x3e,0x03,0x33,0x32,0x16,0x17,0x3e,0x01,0x33,0x32, +0x1e,0x02,0x1d,0x01,0x05,0x14,0x16,0x33,0x32,0x3e,0x02,0x3d,0x01,0x07,0x0e,0x03,0x01,0x22,0x0e,0x02,0x07,0x21,0x2e,0x01,0x02,0xa7,0x01,0x15,0x2c,0x46,0x31,0x4b,0x59,0x10,0x8a,0x0c,0x2b,0x49,0x6d,0x4d,0x39,0x5c,0x48,0x35,0x12,0x15,0x36,0x49,0x5c,0x3a,0x44,0x61,0x3f,0x1e,0x39,0x5d,0x76,0x3e,0xa7,0x0f,0x21,0x34,0x24,0x20, +0x33,0x26,0x17,0x04,0xa8,0x08,0x28,0x4a,0x71,0x50,0x5b,0x79,0x23,0x2d,0x7d,0x4c,0x60,0x81,0x4e,0x20,0xfc,0x05,0x39,0x39,0x38,0x51,0x34,0x19,0x7a,0x25,0x4a,0x3a,0x25,0x02,0x9e,0x1c,0x3e,0x33,0x23,0x02,0x01,0x69,0x09,0x58,0x01,0xf7,0x11,0x52,0x88,0x62,0x37,0x5e,0x48,0x2d,0x2d,0x5b,0x49,0x2f,0x18,0x37,0x59,0x40,0x31,0x55, +0x3e,0x24,0x2c,0x54,0x77,0x4b,0x6b,0x89,0x4e,0x1f,0x01,0x04,0x3b,0x43,0x5e,0x3a,0x1b,0x0f,0x27,0x43,0x33,0x11,0x40,0x6b,0x4e,0x2b,0x46,0x45,0x4a,0x41,0x58,0x9b,0xd2,0x7a,0x18,0xcc,0x52,0x64,0x3f,0x60,0x74,0x35,0x59,0x04,0x01,0x0f,0x30,0x5b,0x02,0x52,0x1d,0x4a,0x7f,0x62,0xab,0x9d,0xff,0xff,0x00,0x82,0xfe,0x44,0x04,0x38, +0x04,0x4e,0x12,0x26,0x00,0x46,0x00,0x00,0x11,0x07,0x00,0x78,0x01,0x51,0x00,0x00,0x00,0x0b,0xb6,0x01,0x21,0x2e,0x26,0x00,0x1c,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0xb4,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x00,0x43,0xb1,0x00,0x00,0x15,0xb4,0x02,0x2c,0x11,0x26,0x02,0xb8,0xff, +0xb2,0xb4,0x2d,0x30,0x15,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0xb4,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x00,0x74,0x6f,0x00,0x00,0x13,0x40,0x0b,0x02,0x2c,0x11,0x26,0x02,0x6f,0x2c,0x2f,0x15,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x85, +0xff,0xec,0x04,0x46,0x05,0xb4,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x01,0x4b,0x07,0x00,0x00,0x13,0x40,0x0b,0x02,0x2d,0x11,0x26,0x02,0x07,0x32,0x2c,0x15,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0x7b,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x00,0x69,0x08,0x00,0x00,0x17, +0x40,0x0d,0x03,0x02,0x2c,0x11,0x26,0x03,0x02,0x08,0x30,0x2e,0x15,0x1f,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x65,0x05,0xb4,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x00,0x43,0xbd,0x00,0x00,0x1e,0x40,0x0b,0x01,0x0a,0x11,0x26,0x01,0x60,0x0b,0x01,0x50,0x0b,0x01,0xb8,0xff,0xa9, +0xb4,0x0b,0x0e,0x03,0x01,0x25,0x01,0x2b,0x5d,0x5d,0x35,0x00,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x65,0x05,0xb4,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x00,0x74,0x68,0x00,0x00,0x13,0x40,0x0b,0x01,0x0a,0x11,0x26,0x01,0x54,0x0a,0x0d,0x03,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x8f, +0x00,0x00,0x04,0x65,0x05,0xb4,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x01,0x4b,0x0a,0x00,0x00,0x22,0x40,0x0e,0x01,0x0b,0x11,0x26,0x01,0x60,0x10,0x01,0x50,0x10,0x01,0x30,0x10,0x01,0xb8,0xff,0xf6,0xb4,0x10,0x0a,0x03,0x01,0x25,0x01,0x2b,0x5d,0x5d,0x5d,0x35,0x00,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x65, +0x05,0x7b,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x00,0x69,0x29,0x00,0x00,0x2f,0x40,0x1f,0x02,0x01,0x0a,0x11,0x26,0x02,0x01,0x90,0x0e,0x01,0x80,0x0e,0x01,0x70,0x0e,0x01,0x60,0x0e,0x01,0x50,0x0e,0x01,0x40,0x0e,0x01,0x00,0x0e,0x0c,0x06,0x09,0x25,0x01,0x2b,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x35,0x35,0x00,0x2b,0x35,0x35,0x00, +0x00,0x02,0x00,0x7d,0xff,0xec,0x04,0x4e,0x05,0xd8,0x00,0x25,0x00,0x37,0x00,0xbb,0x40,0x81,0x45,0x36,0x55,0x36,0x65,0x36,0x03,0x45,0x31,0x55,0x31,0x65,0x31,0x03,0x4a,0x2e,0x5a,0x2e,0x6a,0x2e,0x03,0x4a,0x28,0x5a,0x28,0x6a,0x28,0x03,0x2b,0x04,0x3b,0x04,0x6b,0x04,0x03,0x05,0x24,0x15,0x24,0x02,0x13,0x10,0x06,0x09,0x04,0x12, +0x08,0x08,0x0c,0x12,0x0c,0x12,0x21,0x17,0x47,0x03,0x70,0x26,0x01,0xa0,0x26,0x01,0x00,0x26,0x10,0x26,0x60,0x26,0x03,0x26,0x26,0x39,0x30,0x47,0xff,0x21,0x01,0xff,0x21,0x01,0x00,0x21,0x01,0x21,0x65,0x10,0x75,0x10,0x85,0x10,0x03,0x6a,0x06,0x7a,0x06,0x8a,0x06,0x03,0x10,0x09,0x13,0x06,0x04,0x07,0x11,0x2b,0x50,0x00,0x03,0x00, +0x00,0x00,0x10,0x00,0x02,0x07,0x00,0x07,0x00,0x0c,0x33,0x50,0x1c,0x16,0x12,0x11,0x11,0x0c,0x00,0x00,0x3f,0x33,0x2f,0x33,0x3f,0xed,0x11,0x39,0x39,0x2f,0x2f,0x5d,0x11,0x33,0x10,0xed,0x11,0x12,0x17,0x39,0x5d,0x5d,0x01,0x2f,0x5d,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x71,0x72,0x33,0xed,0x11,0x39,0x39,0x2f,0x2f,0x33,0x2f,0x12, +0x17,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x32,0x16,0x17,0x2e,0x01,0x27,0x05,0x27,0x37,0x2e,0x01,0x27,0x33,0x1e,0x01,0x17,0x25,0x17,0x07,0x16,0x12,0x1d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x01,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x16,0x33,0x32,0x3e,0x02,0x02,0x64,0x47, +0x75,0x2b,0x27,0x69,0x4c,0xfe,0xfc,0x37,0xda,0x38,0x78,0x42,0xd1,0x2d,0x53,0x2a,0x01,0x08,0x37,0xd3,0xa4,0xa7,0x39,0x78,0xbc,0x84,0x7d,0xb5,0x76,0x38,0x34,0x74,0xba,0x01,0xb2,0x21,0x47,0x71,0x50,0x51,0x73,0x49,0x21,0x90,0x91,0x51,0x76,0x4b,0x24,0x03,0xd3,0x20,0x1b,0x59,0x9f,0x45,0x73,0x6e,0x5e,0x2d,0x4e,0x23,0x14,0x33, +0x1f,0x72,0x6c,0x5c,0x95,0xfe,0x7d,0xf4,0x06,0x79,0xc4,0x8a,0x4b,0x49,0x84,0xb9,0x6f,0x6b,0xb6,0x86,0x4b,0xfe,0x0e,0x5e,0x89,0x5a,0x2c,0x2d,0x5c,0x88,0x5c,0xbe,0xb2,0x2c,0x5a,0x8b,0xff,0xff,0x00,0xb3,0x00,0x00,0x04,0x19,0x05,0xa9,0x12,0x26,0x00,0x51,0x00,0x00,0x11,0x06,0x01,0x52,0x0a,0x00,0x00,0x13,0x40,0x0b,0x01,0x26, +0x11,0x26,0x01,0x09,0x31,0x41,0x13,0x24,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0xb4,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x06,0x00,0x43,0xba,0x00,0x00,0x15,0xb4,0x02,0x24,0x11,0x26,0x02,0xb8,0xff,0xbb,0xb4,0x25,0x28,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0xb4,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x06,0x00,0x74,0x65,0x00,0x00,0x13,0x40,0x0b,0x02,0x24,0x11,0x26,0x02,0x65,0x24,0x27,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0xb4,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x06,0x01,0x4b, +0x00,0x00,0x00,0x13,0x40,0x0b,0x02,0x25,0x11,0x26,0x02,0x00,0x2a,0x24,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0xa9,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x06,0x01,0x52,0x00,0x00,0x00,0x13,0x40,0x0b,0x02,0x24,0x11,0x26,0x02,0x00,0x2f,0x3f,0x0a,0x00,0x25,0x01,0x2b,0x35, +0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0x7b,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x06,0x00,0x69,0x00,0x00,0x00,0x17,0x40,0x0d,0x03,0x02,0x24,0x11,0x26,0x03,0x02,0x00,0x28,0x26,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x03,0x00,0x74,0x00,0xdf,0x04,0x57,0x04,0x75,0x00,0x03, +0x00,0x07,0x00,0x0b,0x00,0x63,0x40,0x3c,0x06,0x0e,0x0b,0x05,0x08,0x0e,0x70,0x05,0x01,0x05,0x03,0x0b,0xab,0x00,0x3f,0x08,0x4f,0x08,0x02,0x00,0x08,0x01,0x0a,0x03,0x08,0x08,0x0d,0x0c,0x09,0xae,0x40,0x08,0x0e,0x04,0x01,0x05,0x0e,0x00,0xae,0x2f,0x01,0x3f,0x01,0x4f,0x01,0x03,0x4f,0x01,0x8f,0x01,0x9f,0x01,0xef,0x01,0x04,0x01, +0x04,0xad,0x05,0xb3,0x00,0x3f,0xed,0xd6,0x5d,0x71,0xed,0x2b,0x00,0x18,0x10,0x4d,0xf6,0x1a,0xed,0x11,0x12,0x01,0x39,0x2f,0x5f,0x5e,0x5d,0x5d,0x33,0xed,0x32,0xc4,0x5d,0x2b,0x01,0x18,0x10,0x4d,0xe4,0x31,0x30,0x01,0x35,0x33,0x15,0x01,0x35,0x21,0x15,0x01,0x35,0x33,0x15,0x02,0x11,0xa8,0xfd,0xbb,0x03,0xe3,0xfd,0xba,0xa8,0x03, +0xbe,0xb7,0xb7,0xfe,0xa2,0x92,0x92,0xfe,0x7f,0xb7,0xb7,0x00,0x00,0x03,0x00,0x6e,0xff,0xec,0x04,0x5d,0x04,0x4e,0x00,0x19,0x00,0x25,0x00,0x31,0x00,0xdb,0x40,0x24,0x45,0x24,0x55,0x24,0x65,0x24,0x03,0x6b,0x30,0x01,0x4a,0x30,0x5a,0x30,0x02,0x0c,0x20,0x0b,0x11,0x48,0x79,0x07,0x89,0x07,0x02,0x07,0x40,0x0b,0x0f,0x48,0x74,0x19, +0x84,0x19,0x02,0x19,0xb8,0xff,0xc0,0x40,0x09,0x0b,0x0f,0x48,0x74,0x14,0x84,0x14,0x02,0x14,0xb8,0xff,0xc0,0x40,0x67,0x0b,0x0f,0x48,0x1d,0x2a,0x1e,0x29,0x04,0x26,0x1a,0x18,0x15,0x08,0x0b,0x04,0x0e,0x17,0x17,0x00,0x47,0x20,0x1a,0x30,0x1a,0x40,0x1a,0x70,0x1a,0x80,0x1a,0x90,0x1a,0x06,0x00,0x1a,0x50,0x1a,0xa0,0x1a,0xb0,0x1a, +0xc0,0x1a,0x05,0x00,0x1a,0x10,0x1a,0x60,0x1a,0x70,0x1a,0x80,0x1a,0xe0,0x1a,0x06,0x1a,0x1a,0x33,0x26,0x47,0x0e,0x0a,0x0a,0x0e,0x40,0x28,0x2e,0x48,0x0e,0x40,0x18,0x1b,0x48,0x0e,0x2a,0x1d,0x29,0x1e,0x04,0x21,0x2d,0x08,0x0b,0x18,0x15,0x04,0x13,0x05,0x16,0x16,0x2d,0x50,0x13,0x10,0x21,0x50,0x05,0x09,0x09,0x05,0x16,0x00,0x3f, +0x33,0x2f,0x10,0xed,0x3f,0xed,0x33,0x2f,0x11,0x12,0x17,0x39,0x11,0x12,0x17,0x39,0x01,0x2f,0x2b,0x2b,0x33,0x2f,0x10,0xed,0x12,0x39,0x2f,0x5d,0x71,0x72,0xed,0x32,0x2f,0x11,0x17,0x39,0x11,0x12,0x17,0x39,0x31,0x30,0x00,0x2b,0x5d,0x01,0x2b,0x5d,0x00,0x2b,0x5d,0x01,0x2b,0x00,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x26, +0x27,0x07,0x27,0x37,0x2e,0x01,0x35,0x34,0x3e,0x02,0x33,0x32,0x17,0x37,0x17,0x07,0x16,0x07,0x34,0x26,0x27,0x01,0x1e,0x01,0x33,0x32,0x3e,0x02,0x25,0x14,0x16,0x17,0x01,0x2e,0x01,0x23,0x22,0x0e,0x02,0x04,0x5d,0x46,0x83,0xbc,0x77,0x65,0xa6,0x40,0x4d,0x4c,0x54,0x30,0x33,0x43,0x81,0xbc,0x79,0xd5,0x7a,0x48,0x4e,0x50,0x61,0xbd, +0x11,0x10,0xfe,0x03,0x2b,0x72,0x40,0x45,0x76,0x56,0x30,0xfd,0x8b,0x11,0x11,0x01,0xfd,0x2a,0x71,0x45,0x45,0x75,0x55,0x30,0x02,0x1e,0x8e,0xd3,0x8c,0x45,0x35,0x36,0x57,0x44,0x5f,0x45,0xbc,0x7a,0x8c,0xd1,0x8d,0x46,0x64,0x52,0x44,0x5a,0x89,0xf7,0x4c,0x78,0x2e,0xfd,0xc0,0x35,0x2a,0x27,0x62,0xa6,0x7e,0x4b,0x75,0x2e,0x02,0x40, +0x32,0x27,0x29,0x63,0xa4,0x00,0x00,0x00,0xff,0xff,0x00,0xb9,0xff,0xec,0x04,0x1f,0x05,0xb4,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x06,0x00,0x43,0xa2,0x00,0x00,0x15,0xb4,0x01,0x26,0x11,0x26,0x01,0xb8,0xff,0x9c,0xb4,0x27,0x2a,0x24,0x13,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xb9,0xff,0xec,0x04,0x1f, +0x05,0xb4,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x06,0x00,0x74,0x5a,0x00,0x00,0x13,0x40,0x0b,0x01,0x26,0x11,0x26,0x01,0x54,0x26,0x29,0x24,0x13,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xb9,0xff,0xec,0x04,0x1f,0x05,0xb4,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x06,0x01,0x4b,0x00,0x00,0x00,0x15,0xb4,0x01,0x27,0x11, +0x26,0x01,0xb8,0xff,0xfa,0xb4,0x2c,0x26,0x24,0x13,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xb9,0xff,0xec,0x04,0x1f,0x05,0x7b,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x06,0x00,0x69,0x00,0x00,0x00,0x19,0xb6,0x02,0x01,0x26,0x11,0x26,0x02,0x01,0xb8,0xff,0xfa,0xb4,0x2a,0x28,0x24,0x13,0x25,0x01,0x2b,0x35, +0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x42,0xfe,0x57,0x04,0x89,0x05,0xb4,0x12,0x26,0x00,0x5c,0x00,0x00,0x11,0x06,0x00,0x74,0x6b,0x00,0x00,0x13,0x40,0x0b,0x01,0x20,0x11,0x26,0x01,0x6b,0x20,0x23,0x11,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x02,0x00,0xb9,0xfe,0x57,0x04,0x42,0x05,0xcc,0x00,0x13, +0x00,0x38,0x00,0x65,0x40,0x44,0x79,0x21,0x89,0x21,0x02,0x64,0x12,0x01,0x46,0x12,0x56,0x12,0x02,0x6b,0x02,0x01,0x49,0x02,0x59,0x02,0x02,0x35,0x16,0x01,0x3a,0x26,0x01,0x06,0x1b,0x16,0x1b,0x76,0x1b,0x86,0x1b,0x04,0x1e,0x47,0x60,0x00,0x01,0x00,0x00,0x3a,0x32,0x0a,0x2f,0x46,0x00,0x30,0x80,0x30,0x02,0x30,0x31,0x00,0x2f,0x1b, +0x28,0x0f,0x50,0x23,0x16,0x14,0x05,0x50,0x19,0x10,0x00,0x3f,0xed,0x33,0x3f,0xed,0x33,0x3f,0x3f,0x01,0x2f,0x5d,0xed,0x32,0x32,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x01,0x3e,0x03,0x33,0x32,0x1e,0x02, +0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x23,0x1e,0x03,0x15,0x11,0x23,0x11,0x33,0x11,0x14,0x06,0x07,0x06,0x07,0x03,0x88,0x18,0x3b,0x61,0x49,0x3b,0x68,0x4d,0x2d,0x25,0x48,0x6a,0x44,0x49,0x62,0x3b,0x19,0xfd,0xe8,0x19,0x3f,0x50,0x64,0x3e,0x6e,0x96,0x5c,0x28,0x28,0x5c,0x96,0x6e,0x37,0x64,0x56,0x43,0x17,0x05,0x01,0x01, +0x01,0x01,0xb5,0xb4,0x01,0x01,0x01,0x01,0x02,0x22,0x64,0x9c,0x6b,0x38,0x25,0x61,0xac,0x87,0x73,0x9d,0x61,0x2a,0x39,0x6e,0xa2,0x01,0xce,0x34,0x4c,0x31,0x17,0x50,0x93,0xce,0x7d,0x7b,0xd0,0x96,0x55,0x14,0x2c,0x46,0x32,0x02,0x1f,0x2e,0x3a,0x1d,0xfe,0x59,0x07,0x75,0xfe,0x59,0x1d,0x39,0x16,0x1a,0x17,0x00,0xff,0xff,0x00,0x42, +0xfe,0x57,0x04,0x89,0x05,0x7b,0x12,0x26,0x00,0x5c,0x00,0x00,0x11,0x06,0x00,0x69,0x05,0x00,0x00,0x17,0x40,0x0d,0x02,0x01,0x20,0x11,0x26,0x02,0x01,0x05,0x24,0x22,0x11,0x1f,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0x5e,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x01,0x4d, +0x00,0x02,0x01,0x0b,0x00,0x13,0x40,0x0b,0x02,0x15,0x05,0x26,0x02,0x00,0x16,0x15,0x04,0x07,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88,0x05,0x53,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x06,0x01,0x4d,0xdb,0x00,0x00,0x15,0xb4,0x02,0x42,0x11,0x26,0x02,0xb8,0xff,0xf4,0xb4,0x43,0x42, +0x27,0x2f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa9,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x01,0x4e,0x00,0x00,0x00,0xf5,0x00,0x13,0x40,0x0b,0x02,0x15,0x05,0x26,0x02,0x00,0x1a,0x22,0x04,0x07,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x80, +0xff,0xec,0x04,0x88,0x05,0xb4,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x06,0x01,0x4e,0xed,0x00,0x00,0x13,0x40,0x0b,0x02,0x42,0x11,0x26,0x02,0x07,0x47,0x4f,0x27,0x2f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x00,0xfe,0x60,0x04,0xdf,0x05,0x45,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x01,0x51,0x01,0xc8,0x00,0x0b, +0x00,0x0b,0xb6,0x02,0x12,0x20,0x20,0x00,0x00,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x80,0xfe,0x55,0x04,0x88,0x04,0x4e,0x12,0x26,0x00,0x44,0x00,0x00,0x11,0x07,0x01,0x51,0x01,0x71,0x00,0x00,0x00,0x0e,0xb9,0x00,0x02,0xff,0xc2,0xb4,0x4e,0x4e,0x03,0x03,0x25,0x01,0x2b,0x35,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x76, +0x06,0xa8,0x12,0x26,0x00,0x26,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x84,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x2a,0x05,0x26,0x01,0x76,0x2a,0x2d,0x15,0x0b,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x38,0x05,0xb4,0x12,0x26,0x00,0x46,0x00,0x00,0x11,0x06,0x00,0x74,0x66,0x00,0x00,0x13, +0x40,0x0b,0x01,0x26,0x11,0x26,0x01,0x6f,0x26,0x29,0x00,0x1c,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x76,0x06,0xa9,0x12,0x26,0x00,0x26,0x00,0x00,0x11,0x07,0x01,0x4b,0x00,0x14,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x2b,0x05,0x26,0x01,0x06,0x30,0x2a,0x15,0x0b,0x25,0x01,0x2b,0x35,0x00,0x2b, +0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x38,0x05,0xb4,0x12,0x26,0x00,0x46,0x00,0x00,0x11,0x06,0x01,0x4b,0x00,0x00,0x00,0x13,0x40,0x0b,0x01,0x27,0x11,0x26,0x01,0x09,0x2c,0x26,0x00,0x1c,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x76,0x06,0x66,0x12,0x26,0x00,0x26,0x00,0x00, +0x11,0x07,0x01,0x4f,0x00,0x1e,0x00,0x9a,0x00,0x13,0x40,0x0b,0x01,0x2a,0x05,0x26,0x01,0x11,0x2a,0x2c,0x15,0x0b,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x38,0x05,0xcc,0x12,0x26,0x00,0x46,0x00,0x00,0x11,0x06,0x01,0x4f,0x14,0x00,0x00,0x0b,0xb6,0x01,0x1e,0x26,0x28,0x00,0x1c,0x25, +0x01,0x2b,0x35,0x00,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x76,0x06,0xa9,0x12,0x26,0x00,0x26,0x00,0x00,0x11,0x07,0x01,0x4c,0x00,0x11,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x2a,0x05,0x26,0x01,0x03,0x2c,0x32,0x15,0x0b,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x38,0x05,0xb4,0x12,0x26, +0x00,0x46,0x00,0x00,0x11,0x06,0x01,0x4c,0xfc,0x00,0x00,0x13,0x40,0x0b,0x01,0x26,0x11,0x26,0x01,0x05,0x28,0x2e,0x00,0x1c,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x65,0x06,0xa9,0x12,0x26,0x00,0x27,0x00,0x00,0x11,0x07,0x01,0x4c,0xff,0xe3,0x00,0xf5,0x00,0x15,0xb4,0x02,0x18,0x05,0x26,0x02, +0xb8,0xff,0xc6,0xb4,0x1a,0x20,0x06,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x03,0x00,0x1f,0xff,0xe6,0x04,0xcf,0x05,0xcc,0x00,0x24,0x00,0x38,0x00,0x3e,0x00,0x78,0x40,0x18,0x66,0x3e,0x76,0x3e,0x86,0x3e,0x03,0x05,0x0b,0x75,0x0b,0x85,0x0b,0x03,0x0a,0x05,0x7a,0x05,0x8a,0x05,0x03,0x3e,0x83,0x39,0xb8,0x01,0x0b,0x40, +0x21,0x3b,0x86,0x3c,0x3c,0x40,0x18,0x46,0x2f,0x00,0x3f,0x17,0x01,0x00,0x17,0x40,0x17,0x50,0x17,0x03,0x17,0x17,0x40,0x25,0x47,0x08,0x40,0x0b,0x20,0x48,0x08,0x1f,0x15,0x3e,0xb8,0x01,0x0c,0x40,0x0e,0x3b,0x3b,0x17,0x00,0x34,0x50,0x11,0x0d,0x10,0x2a,0x50,0x00,0x03,0x16,0x00,0x3f,0x33,0xed,0x3f,0x33,0xed,0x3f,0x33,0x2f,0xed, +0x3f,0x01,0x2f,0x2b,0xed,0x12,0x39,0x2f,0x5d,0x71,0x33,0x33,0xed,0x11,0x33,0x2f,0xed,0xfd,0xed,0x31,0x30,0x00,0x5d,0x5d,0x01,0x5d,0x25,0x0e,0x01,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x33,0x34,0x26,0x34,0x26,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x17,0x23,0x2e,0x03,0x35,0x01,0x14,0x1e,0x02,0x33,0x32, +0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x01,0x35,0x13,0x33,0x15,0x03,0x02,0x97,0x31,0x85,0x61,0x50,0x83,0x5c,0x32,0x34,0x5e,0x81,0x4e,0x62,0x84,0x31,0x02,0x01,0x01,0xb4,0x01,0x02,0x02,0x01,0xac,0x01,0x04,0x03,0x02,0xfe,0x3e,0x18,0x30,0x4b,0x33,0x31,0x59,0x45,0x29,0x29,0x44,0x5a,0x30,0x30,0x4a,0x33,0x1a,0x02, +0xe2,0x4f,0xc5,0xab,0xae,0x69,0x5f,0x45,0x8c,0xd1,0x8c,0x8e,0xd5,0x8d,0x46,0x56,0x62,0x05,0x2a,0x32,0x2d,0x09,0x01,0xa3,0xfb,0x13,0x27,0x48,0x3c,0x2b,0x09,0x04,0x24,0x32,0x3a,0x1a,0x01,0x6c,0x70,0xa0,0x68,0x31,0x35,0x6e,0xa6,0x70,0x6c,0x9b,0x65,0x2f,0x2e,0x66,0xa3,0x01,0xf9,0x21,0x01,0x24,0x25,0xfe,0xe0,0x00,0x00,0x00, +0xff,0xff,0x00,0x1b,0x00,0x00,0x04,0x65,0x05,0x45,0x12,0x06,0x00,0x90,0x00,0x00,0x00,0x02,0x00,0x8a,0xff,0xe6,0x04,0x96,0x05,0xcc,0x00,0x27,0x00,0x3b,0x00,0x96,0x40,0x56,0x4a,0x3a,0x5a,0x3a,0x6a,0x3a,0x03,0x45,0x2a,0x55,0x2a,0x65,0x2a,0x03,0x3a,0x0e,0x01,0x35,0x17,0x01,0x05,0x14,0x15,0x14,0x75,0x14,0x85,0x14,0x04,0x0a, +0x11,0x1a,0x11,0x7a,0x11,0x8a,0x11,0x04,0x21,0x21,0x23,0x13,0x26,0x26,0x00,0x24,0x46,0x0c,0x1f,0x32,0x03,0x50,0x23,0x01,0x90,0x23,0xa0,0x23,0x02,0x23,0x23,0x3d,0x28,0x47,0x00,0x13,0x01,0x13,0x23,0x00,0x00,0x20,0x51,0x25,0xaf,0x21,0xbf,0x21,0x02,0x21,0x21,0x23,0x37,0x50,0x18,0x15,0xb8,0xff,0xc0,0x40,0x0c,0x09,0x0c,0x48, +0x15,0x0f,0x2d,0x50,0x0c,0x10,0x16,0x07,0x15,0x00,0x3f,0x3f,0x33,0xed,0x3f,0x2b,0x33,0xed,0x12,0x39,0x2f,0x5d,0x33,0xed,0x32,0x3f,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0x17,0x33,0xed,0x32,0x32,0x2f,0x11,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x11,0x14,0x1e,0x02,0x17,0x23,0x2e,0x03,0x35, +0x23,0x0e,0x01,0x23,0x22,0x02,0x11,0x10,0x21,0x32,0x16,0x17,0x33,0x34,0x26,0x34,0x26,0x3d,0x01,0x21,0x35,0x21,0x35,0x33,0x15,0x33,0x15,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x04,0x13,0x01,0x02,0x02,0x01,0xac,0x01,0x04,0x03,0x02,0x05,0x31,0xa2,0x79,0xca,0xbe,0x01,0x88,0x79,0xa3, +0x31,0x02,0x01,0x01,0xfe,0xd4,0x01,0x2c,0xb4,0x83,0xfc,0xae,0x1d,0x3d,0x60,0x43,0x45,0x6b,0x49,0x25,0x25,0x48,0x6a,0x45,0x40,0x60,0x3f,0x20,0x04,0xac,0xfc,0x33,0x27,0x48,0x3c,0x2b,0x09,0x04,0x24,0x32,0x3a,0x1a,0x69,0x5f,0x01,0x0f,0x01,0x10,0x02,0x2b,0x56,0x62,0x05,0x2a,0x32,0x2d,0x09,0x9d,0x83,0x9d,0x9d,0x83,0xfd,0x5f, +0x6c,0x9b,0x64,0x2f,0x2e,0x66,0xa2,0x73,0x70,0x99,0x5f,0x29,0x2e,0x64,0x9e,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0x5e,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x01,0x4d,0x00,0x12,0x01,0x0b,0x00,0x15,0xb4,0x01,0x0c,0x05,0x26,0x01,0xb8,0xff,0xf5,0xb4,0x0d,0x0c,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00, +0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0x53,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x01,0x4d,0x02,0x00,0x00,0x13,0x40,0x0b,0x02,0x2c,0x11,0x26,0x02,0x01,0x2d,0x2c,0x15,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0xa9,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x01,0x4e, +0x00,0x00,0x00,0xf5,0x00,0x15,0xb4,0x01,0x0c,0x05,0x26,0x01,0xb8,0xff,0xe4,0xb4,0x11,0x19,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0xb4,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x01,0x4e,0x04,0x00,0x00,0x13,0x40,0x0b,0x02,0x2c,0x11,0x26,0x02,0x04,0x31,0x39,0x15,0x1f, +0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0x66,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x01,0x4f,0x00,0x00,0x00,0x9a,0x00,0x15,0xb4,0x01,0x0c,0x05,0x26,0x01,0xb8,0xff,0xe5,0xb4,0x0c,0x0e,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46, +0x05,0xcc,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x01,0x4f,0x02,0x00,0x00,0x0b,0xb6,0x02,0x03,0x2c,0x2e,0x15,0x1f,0x25,0x01,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0xfe,0x55,0x04,0x62,0x05,0x45,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x01,0x51,0x01,0x4b,0x00,0x00,0x00,0x0e,0xb9,0x00,0x01,0xff,0xc2,0xb4,0x18,0x18,0x0a,0x0a, +0x25,0x01,0x2b,0x35,0xff,0xff,0x00,0x85,0xfe,0x55,0x04,0x46,0x04,0x4e,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x01,0x51,0x3e,0x00,0x00,0x0e,0xb9,0x00,0x02,0xfe,0xee,0xb4,0x38,0x38,0x0b,0x0b,0x25,0x01,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0xa9,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x01,0x4c, +0x00,0x00,0x00,0xf5,0x00,0x15,0xb4,0x01,0x0c,0x05,0x26,0x01,0xb8,0xff,0xe4,0xb4,0x0e,0x14,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0xb4,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x01,0x4c,0xf9,0x00,0x00,0x15,0xb4,0x02,0x2c,0x11,0x26,0x02,0xb8,0xff,0xfa,0xb4,0x2e,0x34, +0x15,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x4f,0x06,0xa9,0x12,0x26,0x00,0x2a,0x00,0x00,0x11,0x07,0x01,0x4b,0x00,0x00,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x2b,0x05,0x26,0x01,0x06,0x30,0x2a,0x0a,0x14,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8f, +0xfe,0x58,0x04,0x1e,0x05,0xb4,0x12,0x26,0x00,0x4a,0x00,0x00,0x11,0x06,0x01,0x4b,0xf7,0x00,0x00,0x13,0x40,0x0b,0x02,0x47,0x11,0x26,0x02,0x06,0x4c,0x46,0x1a,0x29,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x4f,0x06,0xa9,0x12,0x26,0x00,0x2a,0x00,0x00,0x11,0x07,0x01,0x4e,0x00,0x03,0x00,0xf5, +0x00,0x13,0x40,0x0b,0x01,0x2a,0x05,0x26,0x01,0x09,0x2f,0x37,0x0a,0x14,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8f,0xfe,0x58,0x04,0x1e,0x05,0xb4,0x12,0x26,0x00,0x4a,0x00,0x00,0x11,0x06,0x01,0x4e,0xf7,0x00,0x00,0x13,0x40,0x0b,0x02,0x46,0x11,0x26,0x02,0x06,0x4b,0x53,0x1a,0x29,0x25,0x01,0x2b,0x35, +0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x4f,0x06,0x66,0x12,0x26,0x00,0x2a,0x00,0x00,0x11,0x07,0x01,0x4f,0x00,0x0a,0x00,0x9a,0x00,0x13,0x40,0x0b,0x01,0x2a,0x05,0x26,0x01,0x11,0x2a,0x2c,0x0a,0x14,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8f,0xfe,0x58,0x04,0x1e,0x05,0xcc,0x12,0x26, +0x00,0x4a,0x00,0x00,0x11,0x06,0x01,0x4f,0xf7,0x00,0x00,0x0b,0xb6,0x02,0x07,0x46,0x48,0x1a,0x29,0x25,0x01,0x2b,0x35,0x00,0xff,0xff,0x00,0x71,0xfe,0x59,0x04,0x4f,0x05,0x5a,0x12,0x26,0x00,0x2a,0x00,0x00,0x11,0x06,0x02,0x95,0x00,0x00,0x00,0x0b,0xb6,0x01,0x05,0x2a,0x2d,0x0a,0x14,0x25,0x01,0x2b,0x35,0x00,0xff,0xff,0x00,0x8f, +0xfe,0x58,0x04,0x1e,0x06,0x00,0x12,0x26,0x00,0x4a,0x00,0x00,0x11,0x06,0x02,0x98,0xff,0x00,0x00,0x13,0x40,0x0b,0x02,0x48,0x11,0x26,0x02,0x0d,0x49,0x46,0x1a,0x29,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x06,0xa9,0x12,0x26,0x00,0x2b,0x00,0x00,0x11,0x07,0x01,0x4b,0x00,0x00,0x00,0xf5, +0x00,0x13,0x40,0x0b,0x01,0x0d,0x05,0x26,0x01,0x00,0x12,0x0c,0x04,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0x00,0x02,0x00,0xb9,0x00,0x00,0x04,0x19,0x06,0xa9,0x00,0x1f,0x00,0x29,0x00,0x8c,0xb9,0x00,0x29,0xff,0xf0,0x40,0x58,0x0e,0x11,0x48,0x28,0x10,0x0e,0x11,0x48,0x27,0x24,0x37,0x24,0x47,0x24,0x03,0x20,0x0e, +0x70,0x0e,0x80,0x0e,0x03,0x04,0x0d,0x14,0x0d,0x74,0x0d,0x84,0x0d,0x04,0x29,0x28,0x23,0x23,0x26,0x22,0x83,0x50,0x21,0x60,0x21,0x80,0x21,0x03,0x21,0x21,0x25,0x83,0x26,0x26,0x1f,0x11,0x46,0x12,0x12,0x2b,0x05,0x02,0x1e,0x46,0x00,0x1f,0x80,0x1f,0x02,0x1f,0x23,0x20,0x0b,0x0f,0x48,0x23,0x8e,0x29,0x8c,0x25,0x22,0x18,0x50,0x05, +0x0b,0x0b,0x1f,0x11,0x15,0x00,0x03,0x00,0x3f,0x3f,0x33,0x39,0x2f,0x33,0xed,0x2f,0x33,0xfd,0xed,0x2b,0x01,0x2f,0x5d,0xed,0x32,0x32,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0xed,0x33,0x2f,0x5d,0xed,0x12,0x39,0x11,0x33,0x33,0x31,0x30,0x00,0x5d,0x5d,0x01,0x5d,0x2b,0x2b,0x13,0x33,0x11,0x14,0x06,0x07,0x33,0x3e,0x03,0x33,0x32,0x1e, +0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x01,0x15,0x23,0x27,0x23,0x07,0x23,0x35,0x37,0x33,0xb9,0xb5,0x06,0x03,0x03,0x18,0x40,0x52,0x69,0x40,0x53,0x82,0x5a,0x2f,0xb5,0x21,0x3b,0x50,0x30,0x3b,0x67,0x4d,0x2c,0xb4,0x02,0xf8,0x69,0xdb,0x02,0xe8,0x68,0xfe,0xa4,0x05,0x45,0xfe,0xc5,0x32,0x65, +0x2e,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfd,0x6b,0x02,0x7b,0x50,0x67,0x3d,0x18,0x2d,0x55,0x7d,0x51,0xfd,0xc9,0x05,0xb9,0x14,0x8b,0x8b,0x14,0xf0,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x00,0x04,0xca,0x05,0x45,0x00,0x13,0x00,0x17,0x00,0x80,0x40,0x51,0x70,0x09,0x01,0x09,0x09,0x07,0x0b,0x5a,0x14,0x04,0x1f,0x0c,0x2f,0x0c, +0x3f,0x0c,0x6f,0x0c,0x7f,0x0c,0x05,0x6f,0x0c,0x7f,0x0c,0x8f,0x0c,0x03,0x0c,0x0c,0x19,0x17,0x03,0x0f,0x5a,0x10,0x7f,0x12,0x01,0x12,0x12,0x00,0x70,0x10,0x01,0x00,0x10,0xa0,0x10,0xb0,0x10,0x03,0x10,0x16,0x0a,0x12,0x60,0x07,0x03,0x13,0x13,0x01,0x0e,0x5f,0x50,0x17,0x01,0xa0,0x17,0xb0,0x17,0x02,0x17,0x17,0x01,0x10,0x0b,0x12, +0x05,0x01,0x03,0x00,0x3f,0x33,0x3f,0x33,0x12,0x39,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x33,0x33,0xed,0x32,0x32,0x01,0x2f,0x5d,0x71,0x33,0x33,0x2f,0x71,0x10,0xed,0x32,0x32,0x12,0x39,0x2f,0x5d,0x71,0x33,0x33,0xed,0x32,0x32,0x2f,0x71,0x31,0x30,0x13,0x35,0x33,0x15,0x21,0x35,0x33,0x15,0x33,0x15,0x23,0x11,0x23,0x11,0x21,0x11, +0x23,0x11,0x23,0x35,0x01,0x35,0x21,0x15,0xa2,0xbf,0x02,0x0a,0xbf,0xa0,0xa0,0xbf,0xfd,0xf6,0xbf,0xa0,0x03,0x69,0xfd,0xf6,0x04,0x81,0xc4,0xc4,0xc4,0xc4,0x94,0xfc,0x13,0x02,0x6f,0xfd,0x91,0x03,0xed,0x94,0xfe,0x8e,0xde,0xde,0x00,0x01,0x00,0x35,0x00,0x00,0x04,0x19,0x05,0xcc,0x00,0x27,0x00,0x71,0x40,0x3e,0x74,0x12,0x84,0x12, +0x02,0x05,0x11,0x15,0x11,0x25,0x11,0x75,0x11,0x85,0x11,0x05,0x36,0x0c,0x01,0x03,0x03,0x22,0x15,0x46,0x16,0x16,0x29,0x09,0x02,0x22,0x46,0x23,0x26,0x26,0x27,0x00,0x23,0x80,0x23,0x02,0x23,0x23,0x15,0x15,0x05,0x25,0x51,0x02,0x26,0x26,0x00,0x1c,0x50,0x00,0x0f,0x01,0xe0,0x0f,0xf0,0x0f,0x02,0x0f,0xb8,0xff,0xc0,0xb6,0x09,0x0c, +0x48,0x0f,0x0f,0x00,0x00,0x00,0x3f,0x3f,0x2b,0x5d,0x71,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x3f,0x33,0x01,0x2f,0x5d,0x33,0x33,0x2f,0x10,0xed,0x32,0x32,0x12,0x39,0x2f,0xed,0x11,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x13,0x33,0x15,0x21,0x15,0x21,0x15,0x14,0x06,0x07,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x11,0x23,0x11, +0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x23,0x35,0x33,0xb9,0xb5,0x01,0x2b,0xfe,0xd5,0x06,0x03,0x03,0x18,0x40,0x52,0x69,0x40,0x53,0x82,0x5a,0x2f,0xb5,0x21,0x3b,0x50,0x30,0x3b,0x67,0x4d,0x2c,0xb4,0x84,0x84,0x05,0xcc,0x9d,0x83,0x84,0x32,0x65,0x2e,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfd,0x4d,0x02,0x99, +0x50,0x67,0x3d,0x18,0x2d,0x55,0x7d,0x51,0xfd,0xab,0x04,0xac,0x83,0x00,0x00,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0x9e,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x01,0x52,0x00,0x01,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x0c,0x05,0x26,0x01,0x01,0x17,0x27,0x00,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x65,0x05,0xa9,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x01,0x52,0x00,0x00,0x00,0x15,0xb4,0x01,0x0a,0x11,0x26,0x01,0xb8,0xff,0xec,0xb4,0x15,0x25,0x03,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0x5e,0x12,0x26,0x00,0x2c,0x00,0x00, +0x11,0x07,0x01,0x4d,0x00,0x02,0x01,0x0b,0x00,0x13,0x40,0x0b,0x01,0x0c,0x05,0x26,0x01,0x01,0x0d,0x0c,0x00,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x65,0x05,0x53,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x01,0x4d,0x08,0x00,0x00,0x15,0xb4,0x01,0x0a,0x11,0x26,0x01,0xb8,0xff, +0xf3,0xb4,0x0b,0x0a,0x03,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0xa8,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x01,0x4e,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x0c,0x05,0x26,0x01,0x00,0x11,0x19,0x00,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x65,0x05,0xb4,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x01,0x4e,0x14,0x00,0x00,0x13,0x40,0x0b,0x01,0x0a,0x11,0x26,0x01,0x00,0x0f,0x17,0x03,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xca,0xfe,0x55,0x04,0x01,0x05,0x45,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x06,0x01,0x51, +0x0d,0x00,0x00,0x0e,0xb7,0x01,0x01,0x0f,0x12,0x0c,0x00,0x01,0x25,0x01,0x2b,0x35,0x00,0x35,0x00,0x00,0xff,0xff,0x00,0x8f,0xfe,0x55,0x04,0x65,0x05,0xcc,0x12,0x26,0x00,0x4c,0x00,0x00,0x11,0x06,0x01,0x51,0x38,0x00,0x00,0x0e,0xb7,0x02,0x02,0x26,0x14,0x0e,0x03,0x01,0x25,0x01,0x2b,0x35,0x00,0x35,0x00,0x00,0xff,0xff,0x00,0xca, +0x00,0x00,0x04,0x01,0x06,0x66,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x01,0x4f,0x00,0x00,0x00,0x9a,0x00,0x13,0x40,0x0b,0x01,0x0c,0x05,0x26,0x01,0x01,0x0c,0x0e,0x00,0x01,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0x00,0x01,0x00,0x8f,0x00,0x00,0x04,0x65,0x04,0x3a,0x00,0x09,0x00,0x33,0x40,0x1a,0x07,0x07,0x05,0x04, +0x04,0x05,0x01,0x01,0x00,0x46,0xa0,0x05,0x01,0x05,0x05,0x0b,0x0a,0x07,0x50,0x08,0x0f,0x00,0x04,0x50,0x03,0x15,0x00,0x3f,0xed,0x32,0x3f,0xed,0x11,0x12,0x01,0x39,0x2f,0x71,0xed,0x32,0x2f,0x11,0x33,0x2f,0x12,0x39,0x2f,0x31,0x30,0x25,0x21,0x15,0x21,0x35,0x21,0x11,0x21,0x35,0x21,0x02,0xe9,0x01,0x7c,0xfc,0x2a,0x01,0xa6,0xfe, +0xc1,0x01,0xf3,0x8e,0x8e,0x8e,0x03,0x1e,0x8e,0x00,0x00,0x00,0x00,0x02,0x00,0x62,0xff,0xec,0x04,0x85,0x05,0x45,0x00,0x03,0x00,0x19,0x00,0x71,0x40,0x2e,0x75,0x06,0x85,0x06,0x02,0x61,0x18,0x71,0x18,0x81,0x18,0x03,0x0a,0x13,0x01,0x0a,0x0f,0x01,0x10,0x09,0x20,0x09,0x30,0x09,0x03,0x09,0x09,0x03,0x07,0x17,0x5a,0x16,0x0c,0x5a, +0x07,0x9f,0x16,0xaf,0x16,0x02,0x90,0x07,0xa0,0x07,0x02,0x07,0xb8,0xff,0xc0,0x40,0x18,0x09,0x0c,0x48,0x16,0x07,0x16,0x07,0x1b,0x02,0x5a,0x03,0x17,0x17,0x04,0x5f,0x11,0x13,0x09,0x5f,0x00,0x0a,0x03,0x03,0x12,0x00,0x3f,0x3f,0x33,0xed,0x3f,0xed,0x33,0x2f,0x01,0x2f,0xed,0x12,0x39,0x39,0x2f,0x2f,0x2b,0x5d,0x5d,0x10,0xed,0x10, +0xed,0x11,0x12,0x39,0x2f,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x13,0x33,0x11,0x23,0x25,0x32,0x36,0x35,0x11,0x21,0x35,0x21,0x11,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x01,0x62,0xbf,0xbf,0x02,0x9e,0x68,0x5f,0xfe,0xf1,0x01,0xcd,0x30,0x61,0x93,0x62,0x55,0x83,0x5e,0x3e,0x12,0xba,0x14,0x67,0x05,0x45,0xfa,0xbb, +0x87,0x8f,0x8a,0x03,0x09,0x9c,0xfc,0x5f,0x64,0xa3,0x73,0x3e,0x2c,0x5a,0x8c,0x60,0x1f,0x81,0x75,0x00,0x00,0x04,0x00,0xd8,0xfe,0x57,0x04,0x25,0x05,0xcc,0x00,0x03,0x00,0x07,0x00,0x1f,0x00,0x23,0x00,0x6d,0x40,0x27,0x75,0x1d,0x85,0x1d,0x02,0x0a,0x0d,0x1a,0x0d,0x02,0x14,0x14,0x03,0x1f,0x20,0x4a,0x23,0x23,0x0a,0x46,0x60,0x1f, +0x01,0x1f,0x1f,0x25,0x03,0x04,0x4a,0x07,0x07,0x02,0x46,0x00,0x03,0xd0,0x03,0x02,0x03,0xb8,0xff,0xc0,0x40,0x19,0x1f,0x25,0x48,0x03,0x1a,0x50,0x0f,0x1b,0x03,0x15,0x08,0x00,0x0f,0x20,0x30,0x04,0x60,0x04,0x02,0x80,0x04,0x01,0x04,0x21,0x05,0x00,0x2f,0x33,0x2f,0x5d,0x71,0x33,0x3f,0x32,0x3f,0x3f,0xed,0x01,0x2f,0x2b,0x5d,0xed, +0x32,0x2f,0xed,0x11,0x12,0x39,0x2f,0x5d,0xed,0x32,0x2f,0xed,0x11,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x13,0x33,0x11,0x23,0x03,0x35,0x33,0x15,0x05,0x33,0x11,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x35,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x03,0x35,0x33,0x15,0xed,0xb3,0xb4,0x14,0xc8,0x01,0xd1,0xb4,0x47,0x76,0x9c,0x56, +0x29,0x52,0x4c,0x41,0x18,0x16,0x3c,0x48,0x4f,0x28,0x38,0x61,0x48,0x29,0x14,0xc8,0x04,0x3a,0xfb,0xc6,0x05,0x0c,0xc0,0xc0,0xd2,0xfb,0xaa,0x6d,0x97,0x5f,0x2a,0x07,0x0c,0x0f,0x09,0x8c,0x05,0x0c,0x0a,0x07,0x1c,0x3d,0x5f,0x43,0x05,0x25,0xc0,0xc0,0xff,0xff,0x00,0xb0,0xff,0xec,0x04,0x29,0x06,0xa9,0x12,0x26,0x00,0x2d,0x00,0x00, +0x11,0x07,0x01,0x4b,0x00,0x78,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x17,0x05,0x26,0x01,0x99,0x1c,0x16,0x08,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xd5,0xfe,0x57,0x04,0x18,0x05,0xb4,0x12,0x26,0x02,0x99,0x00,0x00,0x11,0x06,0x01,0x4b,0x67,0x00,0x00,0x13,0x40,0x0b,0x01,0x1b,0x11,0x26,0x01,0x90, +0x20,0x1a,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0xfe,0x59,0x04,0xcb,0x05,0x45,0x12,0x26,0x00,0x2e,0x00,0x00,0x11,0x06,0x02,0x95,0x00,0x00,0x00,0x0e,0xb9,0x00,0x01,0xff,0xaf,0xb4,0x0c,0x0f,0x04,0x0b,0x25,0x01,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0xec,0xfe,0x59,0x04,0x65,0x05,0xcc,0x12,0x26, +0x00,0x4e,0x00,0x00,0x11,0x06,0x02,0x95,0x00,0x00,0x00,0x0e,0xb9,0x00,0x01,0xff,0xbd,0xb4,0x0c,0x0f,0x04,0x0b,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0x01,0x00,0xec,0x00,0x00,0x04,0x65,0x04,0x3a,0x00,0x0b,0x00,0xb0,0x40,0x2d,0x66,0x07,0x76,0x07,0x86,0x07,0x03,0x64,0x09,0x74,0x09,0x84,0x09,0x03,0x8d,0x01,0x01,0x7b,0x01,0x01, +0x49,0x01,0x59,0x01,0x69,0x01,0x03,0x49,0x08,0x59,0x08,0x02,0x6b,0x00,0x7b,0x00,0x8b,0x00,0x03,0x49,0x00,0x59,0x00,0x02,0x0a,0xb8,0xff,0xe8,0x40,0x28,0x0b,0x11,0x48,0x44,0x09,0x54,0x09,0x02,0x01,0x0a,0x08,0x09,0x10,0x09,0x09,0x00,0x9f,0x0b,0xaf,0x0b,0xbf,0x0b,0x03,0x00,0x0b,0x10,0x0b,0x02,0x0b,0x10,0x0b,0x0b,0x0d,0x07, +0x03,0x46,0x00,0x04,0x01,0x04,0xb8,0xff,0xc0,0xb3,0x1f,0x25,0x48,0x04,0xb8,0xff,0xc0,0xb3,0x16,0x1b,0x48,0x04,0xb8,0xff,0xc0,0x40,0x10,0x0d,0x11,0x48,0x04,0x02,0x07,0x0a,0x01,0x07,0x01,0x08,0x05,0x0f,0x04,0x00,0x15,0x00,0x3f,0x32,0x3f,0x33,0x39,0x39,0x11,0x33,0x11,0x33,0x01,0x2f,0x2b,0x2b,0x2b,0x5d,0xed,0x32,0x11,0x33, +0x2f,0x38,0x5d,0x5d,0x33,0x33,0x2f,0x38,0x33,0x39,0x39,0x5d,0x31,0x30,0x2b,0x5d,0x5d,0x5d,0x00,0x5d,0x5d,0x5d,0x01,0x5d,0x00,0x5d,0x21,0x01,0x07,0x11,0x23,0x11,0x33,0x11,0x01,0x33,0x09,0x01,0x03,0x92,0xfe,0x92,0x84,0xb4,0xb4,0x01,0xdb,0xd3,0xfe,0x49,0x01,0xce,0x01,0xee,0x62,0xfe,0x74,0x04,0x3a,0xfd,0xe6,0x02,0x1a,0xfe, +0x2f,0xfd,0x97,0x00,0xff,0xff,0x00,0xed,0x00,0x00,0x04,0x4c,0x06,0xa9,0x12,0x26,0x00,0x2f,0x00,0x00,0x11,0x07,0x00,0x74,0xff,0x9e,0x00,0xf5,0x00,0x15,0xb4,0x01,0x06,0x05,0x26,0x01,0xb8,0xff,0x68,0xb4,0x06,0x09,0x00,0x04,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x02,0x00,0x86,0x00,0x00,0x04,0x5c,0x06,0xa9,0x00,0x09, +0x00,0x0f,0x00,0x61,0x40,0x0a,0x0c,0x86,0x76,0x0d,0x86,0x0d,0x02,0x0d,0x82,0x0f,0xb8,0xff,0xf0,0x40,0x2c,0x0b,0x0f,0x48,0x0f,0x84,0x15,0x0a,0x01,0x03,0x0a,0x01,0x02,0x0a,0x0a,0x08,0x08,0x05,0x04,0x04,0x05,0x01,0x01,0x00,0x46,0xa0,0x05,0x01,0x05,0x05,0x11,0x10,0x0c,0x8c,0x0f,0x0f,0x07,0x50,0x08,0x03,0x00,0x04,0x50,0x03, +0x15,0x00,0x3f,0xed,0x32,0x3f,0xed,0x33,0x2f,0xed,0x11,0x12,0x01,0x39,0x2f,0x71,0xed,0x32,0x2f,0x11,0x33,0x2f,0x12,0x39,0x2f,0x32,0x2f,0x5f,0x5d,0x5d,0xed,0x2b,0xfd,0x5d,0xed,0x31,0x30,0x25,0x21,0x15,0x21,0x35,0x21,0x11,0x21,0x35,0x21,0x27,0x35,0x37,0x33,0x15,0x05,0x02,0xe0,0x01,0x7c,0xfc,0x2a,0x01,0xa6,0xfe,0xdf,0x01, +0xd5,0xcd,0xe3,0xc5,0xfe,0xd4,0x8e,0x8e,0x8e,0x04,0x29,0x8e,0x60,0x14,0xf0,0x1d,0xe7,0x00,0x00,0x00,0xff,0xff,0x00,0xed,0xfe,0x59,0x04,0x4c,0x05,0x45,0x12,0x26,0x00,0x2f,0x00,0x00,0x11,0x06,0x02,0x95,0x0a,0x00,0x00,0x0e,0xb9,0x00,0x01,0xff,0xd3,0xb4,0x06,0x09,0x00,0x04,0x25,0x01,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0x86, +0xfe,0x59,0x04,0x5c,0x05,0xcc,0x12,0x26,0x00,0x4f,0x00,0x00,0x11,0x06,0x02,0x95,0x00,0x00,0x00,0x0e,0xb9,0x00,0x01,0xff,0xf4,0xb4,0x0a,0x0d,0x03,0x01,0x25,0x01,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0xed,0x00,0x00,0x04,0x4c,0x05,0x45,0x12,0x26,0x00,0x2f,0x00,0x00,0x11,0x07,0x02,0x95,0x01,0x2c,0x05,0xa7,0x00,0x12,0x40,0x0a, +0x01,0x08,0x03,0x01,0xf4,0x06,0x09,0x00,0x04,0x25,0x01,0x2b,0x35,0x00,0x3f,0x35,0xff,0xff,0x00,0x55,0x00,0x00,0x04,0x93,0x05,0xcc,0x10,0x26,0x00,0x4f,0xcf,0x00,0x11,0x07,0x02,0x97,0x01,0xa4,0x00,0x00,0x00,0x14,0xb3,0x01,0x0c,0x00,0x01,0xb8,0x01,0xc9,0xb4,0x0a,0x0d,0x03,0x01,0x25,0x01,0x2b,0x35,0x00,0x3f,0x35,0x00,0x00, +0xff,0xff,0x00,0xed,0x00,0x00,0x04,0x4c,0x05,0x45,0x12,0x26,0x00,0x2f,0x00,0x00,0x11,0x07,0x01,0x4f,0x00,0x9c,0xfd,0x54,0x00,0x0b,0xb6,0x01,0x66,0x06,0x08,0x00,0x04,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x86,0x00,0x00,0x04,0x6b,0x05,0xcc,0x12,0x26,0x00,0x4f,0x00,0x00,0x10,0x07,0x01,0x4f,0x01,0xa0,0xfd,0x54, +0x00,0x01,0x00,0x36,0x00,0x00,0x04,0x4c,0x05,0x45,0x00,0x0d,0x00,0x64,0x40,0x3d,0x8b,0x01,0x01,0x84,0x07,0x01,0x60,0x07,0x70,0x07,0x02,0x09,0x09,0x0b,0x0d,0x0d,0x0f,0x07,0x0b,0x5a,0x00,0x04,0x00,0x03,0x03,0x2f,0x00,0x3f,0x00,0x02,0x00,0x00,0x10,0x00,0x02,0x00,0x09,0x03,0x01,0x0a,0x04,0x07,0x04,0x02,0x6f,0x08,0x7f,0x08, +0x8f,0x08,0x03,0x08,0x02,0x08,0x02,0x05,0x03,0x0b,0x5f,0x00,0x12,0x00,0x3f,0xed,0x3f,0x39,0x39,0x2f,0x2f,0x5d,0x12,0x17,0x39,0x32,0x33,0x01,0x2f,0x5d,0x5d,0x33,0x2f,0x11,0x33,0x10,0xed,0x32,0x12,0x39,0x2f,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x33,0x11,0x07,0x27,0x37,0x11,0x33,0x11,0x25,0x17,0x05,0x11,0x21,0x15, +0xed,0x75,0x42,0xb7,0xbf,0x01,0x24,0x3d,0xfe,0x9f,0x02,0xa0,0x01,0xca,0x3d,0x79,0x60,0x02,0xdf,0xfd,0x84,0x97,0x79,0xb9,0xfe,0x6e,0x9c,0x00,0x00,0x01,0x00,0x86,0x00,0x00,0x04,0x5c,0x05,0xcc,0x00,0x11,0x00,0x7c,0x40,0x15,0x10,0x10,0x08,0x09,0x60,0x0c,0x01,0x9f,0x0c,0x01,0x7f,0x02,0x8f,0x02,0x9f,0x02,0x03,0x4f,0x02,0x01, +0x02,0xb8,0xff,0xc0,0x40,0x32,0x09,0x0c,0x48,0x0c,0x02,0x0c,0x02,0x05,0x08,0x08,0x09,0x05,0x05,0x00,0x04,0x46,0x0d,0xa0,0x09,0x01,0x09,0x09,0x12,0x13,0x00,0x0d,0x03,0x0a,0x04,0x0b,0x3f,0x0b,0x01,0x20,0x01,0x01,0x01,0x0b,0x01,0x0b,0x08,0x0f,0x50,0x10,0x00,0x04,0x08,0x50,0x07,0x15,0x00,0x3f,0xed,0x32,0x3f,0xed,0x12,0x39, +0x39,0x2f,0x2f,0x5d,0x5d,0x12,0x17,0x39,0x11,0x12,0x01,0x39,0x2f,0x71,0x33,0xed,0x32,0x32,0x2f,0x11,0x33,0x2f,0x12,0x39,0x39,0x2f,0x2f,0x2b,0x5d,0x71,0x5d,0x71,0x11,0x12,0x39,0x2f,0x31,0x30,0x01,0x37,0x17,0x05,0x11,0x21,0x15,0x21,0x35,0x21,0x11,0x07,0x27,0x25,0x11,0x21,0x35,0x21,0x02,0xe0,0xe1,0x3e,0xfe,0xe1,0x01,0x7c, +0xfc,0x2a,0x01,0xa6,0xda,0x40,0x01,0x1a,0xfe,0xad,0x02,0x07,0x03,0x74,0x81,0x71,0xa4,0xfd,0xae,0x8e,0x8e,0x01,0xed,0x7b,0x70,0x9f,0x02,0x2f,0x8e,0x00,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x06,0xa9,0x12,0x26,0x00,0x31,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x7a,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x14,0x05,0x26, +0x01,0x7a,0x14,0x17,0x08,0x12,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xb3,0x00,0x00,0x04,0x19,0x05,0xb4,0x12,0x26,0x00,0x51,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x89,0x00,0x00,0x00,0x13,0x40,0x0b,0x01,0x26,0x11,0x26,0x01,0x89,0x26,0x29,0x13,0x24,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0xa2,0xfe,0x59,0x04,0x2a,0x05,0x45,0x12,0x26,0x00,0x31,0x00,0x00,0x11,0x06,0x02,0x95,0xe1,0x00,0x00,0x0e,0xb9,0x00,0x01,0xff,0xe0,0xb4,0x14,0x17,0x08,0x12,0x25,0x01,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0xb3,0xfe,0x59,0x04,0x19,0x04,0x4e,0x12,0x26,0x00,0x51,0x00,0x00,0x11,0x06,0x02,0x95,0xe5,0x00,0x00,0x0e, +0xb9,0x00,0x01,0xff,0xe4,0xb4,0x26,0x29,0x13,0x24,0x25,0x01,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x06,0xa9,0x12,0x26,0x00,0x31,0x00,0x00,0x11,0x07,0x01,0x4c,0x00,0x06,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x14,0x05,0x26,0x01,0x06,0x16,0x1c,0x08,0x12,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0xb3,0x00,0x00,0x04,0x19,0x05,0xb4,0x12,0x26,0x00,0x51,0x00,0x00,0x11,0x06,0x01,0x4c,0x00,0x00,0x00,0x13,0x40,0x0b,0x01,0x26,0x11,0x26,0x01,0x00,0x28,0x2e,0x13,0x24,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x05,0x00,0x00,0x04,0x82,0x05,0x46,0x10,0x26,0x00,0x51,0x69,0x00,0x11,0x07,0x02,0x95, +0xfe,0x2a,0x05,0xa8,0x00,0x18,0xb6,0x01,0x28,0x03,0x01,0x20,0x26,0x01,0xb8,0xfd,0xc0,0xb4,0x26,0x29,0x13,0x24,0x25,0x01,0x2b,0x5d,0x35,0x00,0x3f,0x35,0x00,0x00,0x00,0x01,0x00,0xb3,0xff,0xec,0x04,0x55,0x05,0x5a,0x00,0x37,0x00,0x9c,0x40,0x36,0x14,0x30,0x24,0x30,0x34,0x30,0x03,0x0c,0x03,0x1c,0x03,0x2c,0x03,0x7c,0x03,0x8c, +0x03,0x05,0x73,0x35,0x83,0x35,0x02,0x05,0x34,0x15,0x34,0x25,0x34,0x75,0x34,0x85,0x34,0x05,0x74,0x0b,0x84,0x0b,0x02,0x0b,0x0f,0x0a,0x01,0x0a,0x0a,0x21,0x00,0x5c,0x40,0x15,0xe0,0x15,0x02,0x15,0xb8,0xff,0xc0,0x40,0x17,0x15,0x18,0x48,0x7f,0x15,0x8f,0x15,0x02,0x00,0x15,0x01,0x15,0x15,0x39,0x2e,0x21,0x5c,0x00,0x22,0x10,0x22, +0x02,0x22,0xb8,0xff,0xc0,0xb3,0x1c,0x20,0x48,0x22,0xb8,0xff,0xc0,0x40,0x14,0x11,0x14,0x48,0x22,0x2e,0x1b,0x60,0x32,0x04,0x28,0x03,0x22,0x12,0x10,0x5f,0x05,0x0b,0x0b,0x05,0x13,0x00,0x3f,0x33,0x2f,0x10,0xed,0x3f,0x3f,0x3f,0xed,0x33,0x01,0x2f,0x2b,0x2b,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0x5d,0x2b,0x71,0xed,0x12,0x39,0x2f, +0x5d,0x33,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x11,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x15,0x33,0x3e,0x01,0x33,0x32,0x1e,0x02,0x15,0x04,0x55,0x1f,0x4d,0x83,0x64,0x3e,0x59,0x41, +0x30,0x15,0x83,0x0f,0x1e,0x25,0x2e,0x1f,0x2e,0x3b,0x23,0x0d,0x24,0x41,0x58,0x33,0x42,0x76,0x58,0x33,0xb4,0x01,0x02,0x02,0x01,0xaa,0x01,0x02,0x03,0x02,0x03,0x31,0xbe,0x93,0x57,0x87,0x5d,0x30,0x02,0x1e,0x82,0xd0,0x92,0x4e,0x19,0x2a,0x37,0x1e,0x64,0x15,0x24,0x1b,0x0f,0x3a,0x6b,0x99,0x5f,0x01,0xa1,0x50,0x67,0x3d,0x18,0x2d, +0x55,0x7d,0x51,0xfc,0x81,0x04,0x5f,0x22,0x4b,0x43,0x30,0x07,0x05,0x2c,0x39,0x3b,0x14,0x5f,0x6e,0x2c,0x5c,0x90,0x65,0x00,0x00,0x01,0x00,0xb3,0xfe,0x57,0x04,0x19,0x04,0x4e,0x00,0x35,0x00,0x4f,0x40,0x33,0x22,0x20,0x09,0x0f,0x48,0x73,0x1c,0x83,0x1c,0x02,0x05,0x1b,0x15,0x1b,0x25,0x1b,0x75,0x1b,0x85,0x1b,0x05,0x27,0x27,0x07, +0x1f,0x46,0x30,0x30,0x37,0x13,0x06,0x46,0x00,0x07,0x80,0x07,0x02,0x07,0x2b,0x50,0x24,0x1b,0x13,0x00,0x50,0x19,0x10,0x0d,0x0f,0x07,0x15,0x00,0x3f,0x3f,0x3f,0xed,0x33,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x2b,0x01,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02, +0x27,0x33,0x1e,0x03,0x15,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x11,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x35,0x1e,0x01,0x33,0x32,0x3e,0x02,0x35,0x11,0x34,0x2e,0x02,0x02,0x88,0x3b,0x67,0x4d,0x2c,0xb4,0x01,0x02,0x02,0x01,0xaa,0x01,0x02,0x03,0x02,0x03,0x18,0x41,0x55,0x6a,0x42,0x53,0x80,0x57,0x2d,0x16,0x36,0x5d,0x48,0x22, +0x41,0x1c,0x0d,0x24,0x0d,0x26,0x31,0x1c,0x0a,0x21,0x3b,0x50,0x03,0xc3,0x2d,0x55,0x7d,0x51,0xfd,0x8d,0x03,0x53,0x22,0x4b,0x43,0x30,0x07,0x05,0x2c,0x39,0x3b,0x14,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfc,0xa9,0x3e,0x6a,0x4e,0x2d,0x04,0x05,0x8b,0x02,0x04,0x14,0x2b,0x43,0x2e,0x03,0x22,0x50,0x67,0x3d,0x18,0x00,0x00,0x00, +0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x06,0x5e,0x12,0x26,0x00,0x32,0x00,0x00,0x11,0x07,0x01,0x4d,0x00,0x02,0x01,0x0b,0x00,0x13,0x40,0x0b,0x02,0x1e,0x05,0x26,0x02,0x00,0x1f,0x1e,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0x53,0x12,0x26,0x00,0x52,0x00,0x00, +0x11,0x06,0x01,0x4d,0x02,0x00,0x00,0x13,0x40,0x0b,0x02,0x24,0x11,0x26,0x02,0x01,0x25,0x24,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x06,0xa9,0x12,0x26,0x00,0x32,0x00,0x00,0x11,0x07,0x01,0x4e,0x00,0x00,0x00,0xf5,0x00,0x13,0x40,0x0b,0x02,0x1e,0x05,0x26,0x02,0x00,0x23,0x2b, +0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0xb4,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x06,0x01,0x4e,0x00,0x00,0x00,0x13,0x40,0x0b,0x02,0x24,0x11,0x26,0x02,0x00,0x29,0x31,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66, +0x06,0xa8,0x12,0x26,0x00,0x32,0x00,0x00,0x11,0x07,0x01,0x53,0x01,0x2d,0x00,0xf4,0x00,0x17,0x40,0x0d,0x03,0x02,0x1e,0x05,0x26,0x03,0x02,0x5f,0x24,0x21,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x53,0x05,0xb4,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x07,0x01,0x53, +0x01,0x40,0x00,0x00,0x00,0x17,0x40,0x0d,0x03,0x02,0x24,0x11,0x26,0x03,0x02,0x72,0x2a,0x27,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0x00,0x02,0x00,0x14,0xff,0xfb,0x04,0xc5,0x05,0x4b,0x00,0x17,0x00,0x28,0x00,0x74,0x40,0x49,0x76,0x26,0x86,0x26,0x02,0x46,0x09,0x56,0x09,0x02,0x49,0x04,0x59,0x04, +0x02,0x12,0x0e,0x12,0x0e,0x16,0x11,0x15,0x5c,0x1b,0x1b,0x06,0x16,0x16,0x2a,0x24,0x5c,0x06,0x14,0x5f,0x0f,0x11,0x3f,0x11,0x7f,0x11,0x8f,0x11,0x04,0x6f,0x11,0x8f,0x11,0x9f,0x11,0xbf,0x11,0xdf,0x11,0x05,0x11,0x11,0x0e,0x18,0x16,0x5f,0x17,0x03,0x03,0x17,0x12,0x1f,0x0f,0x5f,0x0e,0x0b,0x0b,0x0e,0x03,0x00,0x3f,0x33,0x2f,0x10, +0xed,0x32,0x3f,0x33,0x2f,0x10,0xed,0x32,0x11,0x39,0x2f,0x71,0x72,0xed,0x01,0x2f,0xed,0x12,0x39,0x2f,0x12,0x39,0x2f,0xed,0x32,0x12,0x39,0x39,0x2f,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x21,0x0e,0x01,0x23,0x22,0x02,0x11,0x34,0x12,0x3e,0x01,0x33,0x32,0x17,0x21,0x15,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x15,0x25,0x32,0x36,0x37, +0x11,0x2e,0x01,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x02,0x61,0x17,0x31,0x1a,0xff,0xec,0x3d,0x7b,0xb9,0x7c,0x3a,0x33,0x02,0x2e,0xfe,0x72,0x01,0x6f,0xfe,0x91,0x01,0xb7,0xfd,0x3b,0x16,0x3b,0x13,0x13,0x3b,0x15,0x4e,0x75,0x4e,0x27,0x28,0x4f,0x74,0x02,0x03,0x01,0x52,0x01,0x5c,0xb4,0x01,0x00,0xa2,0x4c,0x06,0x98,0xfe,0x48, +0x96,0xfe,0x39,0x98,0x8c,0x02,0x04,0x04,0x21,0x03,0x03,0x3a,0x7f,0xc8,0x8f,0x8e,0xcc,0x84,0x3f,0x00,0x00,0x03,0x00,0x1c,0xff,0xec,0x04,0xb4,0x04,0x4e,0x00,0x26,0x00,0x3a,0x00,0x43,0x00,0xaa,0x40,0x73,0x7b,0x42,0x8b,0x42,0x02,0x7a,0x3e,0x8a,0x3e,0x02,0x76,0x38,0x86,0x38,0x02,0x79,0x2a,0x89,0x2a,0x02,0x66,0x03,0x76,0x03, +0x86,0x03,0x03,0x64,0x33,0x74,0x33,0x84,0x33,0x03,0x6b,0x2f,0x7b,0x2f,0x8b,0x2f,0x03,0x05,0x22,0x15,0x22,0x02,0x05,0x1a,0x15,0x1a,0x02,0x0a,0x15,0x1a,0x15,0x02,0x10,0x1d,0x40,0x00,0x48,0x27,0x27,0x18,0x25,0x08,0x49,0x09,0x09,0x25,0x48,0x10,0x41,0x01,0x41,0x41,0x45,0x31,0x48,0x4f,0x18,0x5f,0x18,0x9f,0x18,0xaf,0x18,0x04, +0x18,0x00,0x50,0x40,0x40,0x36,0x3b,0x2c,0x50,0x20,0x1d,0x1b,0x10,0x05,0x36,0x50,0x13,0x10,0x0e,0x13,0x80,0x08,0x01,0x08,0x08,0x13,0x16,0x00,0x3f,0x33,0x2f,0x5d,0x11,0x33,0x33,0x10,0xed,0x32,0x3f,0x33,0x33,0xed,0x32,0x12,0x39,0x2f,0xed,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0xed,0x32,0x2f,0xed,0x11,0x12,0x39,0x2f,0xed, +0x32,0x39,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x1e,0x02,0x33,0x32,0x36,0x37,0x17,0x0e,0x03,0x23,0x22,0x27,0x0e,0x01,0x23,0x22,0x2e,0x02,0x35,0x10,0x12,0x33,0x32,0x17,0x3e,0x01,0x33,0x32,0x1e,0x02,0x1d,0x01,0x25,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32, +0x3e,0x02,0x01,0x22,0x0e,0x02,0x07,0x21,0x2e,0x01,0x02,0xc8,0x13,0x29,0x40,0x2c,0x41,0x4e,0x0e,0x8a,0x0b,0x28,0x44,0x66,0x48,0xb6,0x51,0x2a,0x85,0x5b,0x4b,0x78,0x55,0x2d,0xaa,0xa2,0xbb,0x4f,0x2d,0x85,0x51,0x5b,0x7b,0x4a,0x1f,0xfd,0x6b,0x18,0x2c,0x3f,0x27,0x27,0x41,0x2f,0x19,0x1b,0x2e,0x3e,0x23,0x28,0x41,0x2e,0x19,0x01, +0x4c,0x19,0x37,0x2f,0x20,0x02,0x01,0x44,0x08,0x50,0x01,0xf7,0x55,0x8f,0x67,0x39,0x5e,0x48,0x2d,0x2d,0x5b,0x49,0x2f,0xb7,0x5d,0x5a,0x44,0x8c,0xd3,0x8f,0x01,0x17,0x01,0x19,0xb1,0x5e,0x53,0x58,0x9b,0xd2,0x7a,0x18,0x27,0x7e,0xa4,0x62,0x27,0x29,0x63,0xa4,0x7b,0x7e,0xa5,0x62,0x28,0x27,0x62,0xa6,0x02,0x29,0x1d,0x4a,0x7f,0x62, +0xab,0x9d,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x99,0x06,0xa9,0x12,0x26,0x00,0x35,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x48,0x00,0xf5,0x00,0x13,0x40,0x0b,0x02,0x1c,0x05,0x26,0x02,0x10,0x1c,0x1f,0x04,0x11,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xf2,0x00,0x00,0x04,0x15,0x05,0xb4,0x12,0x26, +0x00,0x55,0x00,0x00,0x11,0x06,0x00,0x74,0x59,0x00,0x00,0x13,0x40,0x0b,0x01,0x20,0x11,0x26,0x01,0x3b,0x20,0x23,0x10,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0xfe,0x59,0x04,0x99,0x05,0x45,0x12,0x26,0x00,0x35,0x00,0x00,0x11,0x06,0x02,0x95,0xfd,0x00,0x00,0x0e,0xb9,0x00,0x02,0xff,0xc5,0xb4,0x1c,0x1f, +0x04,0x11,0x25,0x01,0x2b,0x35,0x00,0x00,0xff,0xff,0x00,0xcb,0xfe,0x59,0x04,0x15,0x04,0x4e,0x12,0x26,0x00,0x55,0x00,0x00,0x11,0x07,0x02,0x95,0xfe,0xf0,0x00,0x00,0x00,0x0e,0xb9,0x00,0x01,0xfe,0xd2,0xb4,0x20,0x23,0x10,0x00,0x25,0x01,0x2b,0x35,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x99,0x06,0xa9,0x12,0x26,0x00,0x35,0x00,0x00, +0x11,0x07,0x01,0x4c,0xff,0xed,0x00,0xf5,0x00,0x15,0xb4,0x02,0x1c,0x05,0x26,0x02,0xb8,0xff,0xb6,0xb4,0x1e,0x24,0x04,0x11,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xf2,0x00,0x00,0x04,0x15,0x05,0xb4,0x12,0x26,0x00,0x55,0x00,0x00,0x11,0x06,0x01,0x4c,0x14,0x00,0x00,0x15,0xb4,0x01,0x20,0x11,0x26,0x01,0xb8,0xff, +0xf7,0xb4,0x22,0x28,0x10,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x4f,0xff,0xec,0x04,0x68,0x06,0xa9,0x12,0x26,0x00,0x36,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x78,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x40,0x05,0x26,0x01,0x82,0x40,0x43,0x08,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0xa7,0xff,0xec,0x04,0x24,0x05,0xb4,0x12,0x26,0x00,0x56,0x00,0x00,0x11,0x06,0x00,0x74,0x56,0x00,0x00,0x13,0x40,0x0b,0x01,0x39,0x11,0x26,0x01,0x56,0x39,0x3c,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x4f,0xff,0xec,0x04,0x68,0x06,0xa9,0x12,0x26,0x00,0x36,0x00,0x00,0x11,0x07,0x01,0x4b, +0x00,0x04,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x41,0x05,0x26,0x01,0x0e,0x46,0x40,0x08,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xa7,0xff,0xec,0x04,0x24,0x05,0xb4,0x12,0x26,0x00,0x56,0x00,0x00,0x11,0x06,0x01,0x4b,0x0f,0x00,0x00,0x13,0x40,0x0b,0x01,0x3a,0x11,0x26,0x01,0x0f,0x3f,0x39,0x0a,0x00, +0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x4f,0xfe,0x44,0x04,0x68,0x05,0x5a,0x12,0x26,0x00,0x36,0x00,0x00,0x11,0x07,0x00,0x78,0x01,0x4c,0x00,0x00,0x00,0x0b,0xb6,0x01,0x1d,0x48,0x40,0x08,0x00,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xa7,0xfe,0x44,0x04,0x24,0x04,0x4b,0x12,0x26,0x00,0x56,0x00,0x00, +0x11,0x07,0x00,0x78,0x01,0x56,0x00,0x00,0x00,0x0b,0xb6,0x01,0x1d,0x41,0x39,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x4f,0xff,0xec,0x04,0x68,0x06,0xa8,0x12,0x26,0x00,0x36,0x00,0x00,0x11,0x07,0x01,0x4c,0x00,0x00,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x40,0x05,0x26,0x01,0x0a,0x42,0x48,0x08,0x00,0x25,0x01, +0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xa7,0xff,0xec,0x04,0x24,0x05,0xb4,0x12,0x26,0x00,0x56,0x00,0x00,0x11,0x06,0x01,0x4c,0x05,0x00,0x00,0x13,0x40,0x0b,0x01,0x39,0x11,0x26,0x01,0x05,0x3b,0x41,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x4c,0xfe,0x44,0x04,0x80,0x05,0x45,0x10,0x27, +0x00,0x78,0x01,0x4c,0x00,0x00,0x12,0x06,0x00,0x37,0x00,0x00,0xff,0xff,0x00,0xbe,0xfe,0x44,0x03,0xf9,0x05,0x54,0x10,0x27,0x00,0x78,0x01,0x56,0x00,0x00,0x12,0x06,0x00,0x57,0x00,0x00,0xff,0xff,0x00,0x4c,0x00,0x00,0x04,0x80,0x06,0xa9,0x12,0x26,0x00,0x37,0x00,0x00,0x11,0x07,0x01,0x4c,0x00,0x00,0x00,0xf5,0x00,0x13,0x40,0x0b, +0x01,0x08,0x05,0x26,0x01,0x00,0x0a,0x10,0x04,0x06,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x65,0xff,0xf0,0x04,0xc5,0x05,0xcc,0x10,0x26,0x00,0x57,0xa7,0x00,0x11,0x07,0x02,0x97,0x01,0xd6,0x00,0x00,0x00,0x11,0xb1,0x01,0x01,0xb8,0x02,0x38,0xb4,0x1c,0x1f,0x00,0x11,0x25,0x01,0x2b,0x35,0x00,0x35,0x00, +0x00,0x01,0x00,0x4c,0x00,0x00,0x04,0x80,0x05,0x45,0x00,0x0f,0x00,0x6f,0x40,0x44,0x02,0x02,0x0e,0x05,0x09,0x09,0x06,0x0d,0x0e,0x0e,0x01,0x05,0x5a,0x06,0x40,0x0d,0x06,0x0e,0x0d,0x0a,0x0f,0x06,0x3f,0x06,0x8f,0x06,0x9f,0x06,0xbf,0x06,0xcf,0x06,0x06,0x4f,0x06,0x5f,0x06,0x7f,0x06,0x8f,0x06,0xcf,0x06,0xdf,0x06,0x06,0x10,0x06, +0x01,0x06,0x06,0x10,0x11,0x00,0x0c,0x5f,0x0d,0x04,0x08,0x5f,0x01,0x09,0x09,0x05,0x0d,0x03,0x05,0x12,0x00,0x3f,0x3f,0x12,0x39,0x2f,0x33,0xed,0x32,0x10,0xed,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0x5d,0x71,0x33,0xc4,0x2b,0x01,0x1a,0x18,0x10,0x4d,0xfd,0x32,0xe4,0x11,0x12,0x39,0x2f,0x11,0x12,0x39,0x2f,0x31,0x30,0x01,0x11,0x33, +0x15,0x23,0x11,0x23,0x11,0x23,0x35,0x33,0x11,0x21,0x35,0x21,0x15,0x02,0xc5,0xf0,0xf0,0xbe,0xf0,0xf0,0xfe,0x45,0x04,0x34,0x04,0xa9,0xfe,0x58,0x95,0xfd,0x94,0x02,0x6c,0x95,0x01,0xa8,0x9c,0x9c,0x00,0x00,0x00,0x01,0x00,0xc8,0xff,0xf0,0x04,0x03,0x05,0x54,0x00,0x23,0x00,0x7b,0x40,0x4e,0x6a,0x12,0x7a,0x12,0x8a,0x12,0x03,0x12, +0x28,0x09,0x0e,0x48,0x01,0x21,0x21,0x0b,0x0b,0x25,0x23,0x1f,0x03,0x46,0x14,0x1a,0x90,0x16,0x01,0x16,0x16,0x18,0x1c,0x03,0x2f,0x14,0x3f,0x14,0x4f,0x14,0x03,0x14,0x40,0x20,0x24,0x48,0x14,0x40,0x1a,0x1e,0x48,0x14,0x40,0x12,0x18,0x48,0x00,0x14,0x01,0x14,0x22,0x1a,0x50,0x1b,0x02,0x16,0x50,0x23,0x17,0x17,0x1f,0x1b,0x1d,0x1d, +0x1b,0x0f,0x06,0x50,0x11,0x16,0x00,0x3f,0xed,0x3f,0x33,0x2f,0x11,0x33,0x39,0x2f,0x33,0xed,0x32,0x10,0xed,0x32,0x01,0x2f,0x5d,0x2b,0x2b,0x2b,0x5d,0x17,0x33,0x2f,0x5d,0x33,0x10,0xed,0x32,0x32,0x12,0x39,0x2f,0x33,0x2f,0x33,0x31,0x30,0x00,0x2b,0x5d,0x01,0x15,0x21,0x15,0x14,0x16,0x33,0x32,0x3e,0x02,0x37,0x15,0x0e,0x03,0x23, +0x22,0x26,0x3d,0x01,0x23,0x35,0x33,0x11,0x23,0x35,0x33,0x13,0x33,0x11,0x21,0x15,0x21,0x11,0x03,0xd4,0xfe,0x50,0x55,0x61,0x28,0x55,0x4f,0x45,0x18,0x16,0x46,0x57,0x66,0x36,0xa2,0xa2,0xa8,0xa8,0xa8,0xaa,0x3a,0x78,0x01,0xb0,0xfe,0x50,0x02,0x87,0x84,0xe3,0x4f,0x4c,0x07,0x0a,0x0c,0x05,0x89,0x06,0x10,0x0e,0x0a,0x89,0x94,0xf6, +0x84,0x01,0x25,0x8e,0x01,0x1a,0xfe,0xe6,0x8e,0xfe,0xdb,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0x9e,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x01,0x52,0x00,0x01,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x1a,0x05,0x26,0x01,0x01,0x25,0x35,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xb9, +0xff,0xec,0x04,0x1f,0x05,0xa9,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x06,0x01,0x52,0x01,0x00,0x00,0x15,0xb4,0x01,0x26,0x11,0x26,0x01,0xb8,0xff,0xfb,0xb4,0x31,0x41,0x24,0x13,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0x5e,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x01,0x4d, +0x00,0x02,0x01,0x0b,0x00,0x13,0x40,0x0b,0x01,0x1a,0x05,0x26,0x01,0x01,0x1b,0x1a,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xb9,0xff,0xec,0x04,0x1f,0x05,0x53,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x06,0x01,0x4d,0x02,0x00,0x00,0x15,0xb4,0x01,0x26,0x11,0x26,0x01,0xb8,0xff,0xfb,0xb4,0x27,0x26, +0x24,0x13,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0xa9,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x01,0x4e,0x00,0x00,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x1a,0x05,0x26,0x01,0x00,0x1f,0x27,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xb9, +0xff,0xec,0x04,0x1f,0x05,0xb4,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x06,0x01,0x4e,0x00,0x00,0x00,0x15,0xb4,0x01,0x26,0x11,0x26,0x01,0xb8,0xff,0xfa,0xb4,0x2b,0x33,0x24,0x13,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x3d,0x06,0xa9,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x01,0x50, +0x00,0x00,0x00,0x9e,0x00,0x2e,0xb2,0x02,0x01,0x1f,0xb8,0xff,0xc0,0x40,0x18,0x14,0x18,0x48,0x90,0x1f,0x01,0x70,0x1f,0x01,0x10,0x1f,0x01,0x00,0x1f,0x01,0x1f,0x02,0x01,0x00,0x24,0x1a,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x11,0x5d,0x5d,0x5d,0x5d,0x2b,0x35,0x35,0xff,0xff,0x00,0xb9,0xff,0xec,0x04,0x1f,0x06,0x0b,0x12,0x26, +0x00,0x58,0x00,0x00,0x11,0x06,0x01,0x50,0x00,0x00,0x00,0x19,0xb6,0x02,0x01,0x2b,0x11,0x26,0x02,0x01,0xb8,0xff,0xfa,0xb4,0x30,0x26,0x24,0x13,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8e,0xff,0xec,0x04,0x4b,0x06,0xa9,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x07,0x01,0x53,0x01,0x38,0x00,0xf5, +0x00,0x17,0x40,0x0d,0x02,0x01,0x1a,0x05,0x26,0x02,0x01,0x6a,0x20,0x1d,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xb9,0xff,0xec,0x04,0x51,0x05,0xb4,0x12,0x26,0x00,0x58,0x00,0x00,0x11,0x07,0x01,0x53,0x01,0x3e,0x00,0x00,0x00,0x17,0x40,0x0d,0x02,0x01,0x26,0x11,0x26,0x02,0x01,0x6a, +0x2c,0x29,0x24,0x13,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x8e,0xfe,0x55,0x04,0x3d,0x05,0x45,0x12,0x26,0x00,0x38,0x00,0x00,0x11,0x06,0x01,0x51,0x3b,0x00,0x00,0x0b,0xb6,0x01,0x3d,0x20,0x1a,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0xff,0xff,0x00,0xb9,0xfe,0x55,0x04,0x38,0x04,0x3a,0x12,0x26, +0x00,0x58,0x00,0x00,0x11,0x07,0x01,0x51,0x01,0x21,0x00,0x00,0x00,0x0b,0xb6,0x01,0x00,0x31,0x31,0x14,0x14,0x25,0x01,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa9,0x12,0x26,0x00,0x3a,0x00,0x00,0x11,0x07,0x01,0x4b,0xff,0xfc,0x00,0xf5,0x00,0x15,0xb4,0x01,0x34,0x05,0x26,0x01,0xb8,0xff,0xfc,0xb4, +0x39,0x33,0x13,0x32,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x15,0x00,0x00,0x04,0xb8,0x05,0xb4,0x12,0x26,0x00,0x5a,0x00,0x00,0x11,0x06,0x01,0x4b,0xfc,0x00,0x00,0x15,0xb4,0x01,0x2c,0x11,0x26,0x01,0xb8,0xff,0xfc,0xb4,0x31,0x2b,0x0f,0x2a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x24, +0x00,0x00,0x04,0xa8,0x06,0xa9,0x12,0x26,0x00,0x3c,0x00,0x00,0x11,0x07,0x01,0x4b,0xff,0xfc,0x00,0xf5,0x00,0x15,0xb4,0x01,0x0a,0x05,0x26,0x01,0xb8,0xff,0xfc,0xb4,0x0f,0x09,0x04,0x08,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x42,0xfe,0x57,0x04,0x89,0x05,0xb4,0x12,0x26,0x00,0x5c,0x00,0x00,0x11,0x06,0x01,0x4b, +0xfc,0x00,0x00,0x15,0xb4,0x01,0x21,0x11,0x26,0x01,0xb8,0xff,0xfd,0xb4,0x26,0x20,0x11,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x24,0x00,0x00,0x04,0xa8,0x06,0x5d,0x12,0x26,0x00,0x3c,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x01,0x00,0xe2,0x00,0x17,0x40,0x0d,0x02,0x01,0x09,0x05,0x26,0x02,0x01,0x00, +0x0d,0x0b,0x04,0x08,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x49,0x00,0x00,0x04,0x83,0x06,0xa9,0x12,0x26,0x00,0x3d,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x66,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x0a,0x05,0x26,0x01,0x66,0x0a,0x0d,0x01,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0x93,0x00,0x00,0x04,0x2c,0x05,0xb4,0x12,0x26,0x00,0x5d,0x00,0x00,0x11,0x06,0x00,0x74,0x55,0x00,0x00,0x13,0x40,0x0b,0x01,0x0a,0x11,0x26,0x01,0x5b,0x0a,0x0d,0x00,0x08,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x49,0x00,0x00,0x04,0x83,0x06,0x66,0x12,0x26,0x00,0x3d,0x00,0x00,0x11,0x07,0x01,0x4f, +0x00,0x0d,0x00,0x9a,0x00,0x13,0x40,0x0b,0x01,0x0a,0x05,0x26,0x01,0x0e,0x0a,0x0c,0x01,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x93,0x00,0x00,0x04,0x2c,0x05,0xcc,0x12,0x26,0x00,0x5d,0x00,0x00,0x11,0x06,0x01,0x4f,0xfd,0x00,0x00,0x0b,0xb6,0x01,0x04,0x0a,0x0c,0x00,0x08,0x25,0x01,0x2b,0x35,0x00, +0xff,0xff,0x00,0x49,0x00,0x00,0x04,0x83,0x06,0xa8,0x12,0x26,0x00,0x3d,0x00,0x00,0x11,0x07,0x01,0x4c,0x00,0x0a,0x00,0xf4,0x00,0x13,0x40,0x0b,0x01,0x0a,0x05,0x26,0x01,0x0a,0x0c,0x12,0x01,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x93,0x00,0x00,0x04,0x2c,0x05,0xb4,0x12,0x26,0x00,0x5d,0x00,0x00, +0x11,0x06,0x01,0x4c,0x01,0x00,0x00,0x13,0x40,0x0b,0x01,0x0a,0x11,0x26,0x01,0x07,0x0c,0x12,0x00,0x08,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x01,0x01,0x90,0x00,0x00,0x04,0x4b,0x05,0xcc,0x00,0x17,0x00,0x3e,0xb9,0x00,0x05,0xff,0xe8,0x40,0x24,0x09,0x0c,0x48,0x00,0x46,0x2f,0x01,0x3f,0x01,0x6f,0x01,0x7f,0x01,0x8f,0x01, +0x05,0x01,0x40,0x14,0x25,0x48,0x00,0x01,0x01,0x01,0x0c,0x01,0x0c,0x18,0x19,0x12,0x50,0x07,0x00,0x00,0x15,0x00,0x3f,0x3f,0xed,0x11,0x12,0x01,0x39,0x39,0x2f,0x2f,0x5d,0x2b,0x5d,0xed,0x31,0x30,0x00,0x2b,0x21,0x23,0x11,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x15,0x2e,0x03,0x23,0x22,0x0e,0x02,0x15,0x02,0x44,0xb4,0x2d,0x64, +0x9f,0x72,0x1d,0x50,0x50,0x47,0x15,0x12,0x48,0x4f,0x48,0x13,0x42,0x62,0x40,0x1f,0x04,0x53,0x65,0x8f,0x5b,0x2a,0x03,0x06,0x08,0x04,0x91,0x03,0x06,0x05,0x03,0x14,0x36,0x5e,0x4b,0x00,0x00,0x01,0x00,0xea,0xfe,0x57,0x04,0x2d,0x05,0x59,0x00,0x1b,0x00,0x5c,0x40,0x33,0x10,0x0d,0x11,0x6f,0x12,0x14,0x14,0x12,0x0e,0x0e,0x03,0x0d, +0x6f,0x16,0x13,0x16,0x00,0x16,0x10,0x16,0x02,0x00,0x12,0x10,0x12,0x02,0x12,0x16,0x12,0x16,0x1c,0x1d,0x03,0x03,0x1d,0x10,0x14,0x51,0x0d,0x70,0x15,0x01,0x15,0x15,0x00,0x11,0x1b,0x07,0x73,0x00,0x07,0x00,0x3f,0xed,0x3f,0x12,0x39,0x2f,0x5d,0x33,0xed,0x32,0x11,0x01,0x33,0x2f,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x12,0x39, +0x10,0xed,0x11,0x39,0x2f,0x11,0x33,0x2f,0x10,0xed,0x11,0x39,0x31,0x30,0x01,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x0e,0x02,0x0f,0x01,0x21,0x07,0x21,0x03,0x23,0x13,0x23,0x37,0x33,0x37,0x3e,0x03,0x03,0x8d,0x2e,0x56,0x1c,0x28,0x14,0x4b,0x23,0x2d,0x3d,0x29,0x18,0x09,0x1b,0x01,0x2e,0x19,0xfe,0xd1,0xf3,0xb4,0xf3,0xfc,0x1b, +0xfb,0x1d,0x0e,0x2f,0x54,0x80,0x05,0x59,0x0f,0x08,0x88,0x07,0x0c,0x10,0x25,0x3c,0x2b,0x89,0x83,0xfb,0x32,0x04,0xce,0x83,0x98,0x3b,0x66,0x4c,0x2c,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa9,0x00,0x16,0x00,0x24,0x00,0x2a,0x00,0x3e,0x01,0x21,0x40,0x0b,0x0b,0x28,0x09,0x0c,0x48,0x02,0x28,0x09,0x0c,0x48, +0x14,0xb8,0xff,0xe8,0xb3,0x09,0x11,0x48,0x10,0xb8,0xff,0xe8,0x40,0x09,0x09,0x11,0x48,0x74,0x28,0x84,0x28,0x02,0x28,0xb8,0xff,0xf0,0x40,0x7f,0x09,0x0c,0x48,0x17,0x24,0x06,0x05,0x1c,0x05,0x17,0x1c,0x05,0x22,0x23,0x07,0x08,0x1d,0x08,0x22,0x1d,0x08,0x03,0x01,0x52,0x05,0x1c,0x05,0x5e,0x04,0x03,0x14,0x04,0x04,0x03,0x0a,0x01, +0x52,0x08,0x1d,0x08,0x5e,0x09,0x0a,0x14,0x09,0x09,0x0a,0x27,0x86,0x44,0x28,0x54,0x28,0x64,0x28,0x03,0x28,0x82,0x2a,0x84,0x70,0x25,0x80,0x25,0x02,0x25,0x0d,0x2b,0x84,0x80,0x00,0x01,0x00,0x35,0x84,0x0d,0x0d,0x0a,0x1d,0x00,0x03,0x1c,0x1c,0x1d,0x09,0x05,0x10,0x04,0x01,0x04,0x04,0x40,0x08,0x7f,0x09,0x8f,0x09,0x02,0x09,0x70, +0x27,0x80,0x27,0x02,0x27,0x8c,0x7f,0x2a,0x8f,0x2a,0x02,0x2a,0x12,0x06,0x24,0x07,0x5f,0x23,0x3a,0x8e,0x1d,0x1c,0x0a,0x03,0x03,0x1d,0x1d,0xb8,0xff,0xc0,0x40,0x12,0x09,0x0c,0x48,0x23,0x1d,0x23,0x1d,0x05,0x30,0x8e,0x12,0xdc,0x09,0x08,0x04,0x03,0x05,0x12,0x00,0x3f,0x17,0x33,0x3f,0xed,0x12,0x39,0x39,0x2f,0x2f,0x2b,0x11,0x17, +0x33,0x10,0xed,0x10,0xed,0x33,0x32,0x10,0xd6,0x5d,0xed,0x5d,0x01,0x2f,0x5d,0x33,0x11,0x33,0x2f,0x5d,0x33,0x12,0x39,0x39,0x11,0x33,0x33,0x11,0x33,0x33,0x2f,0xed,0x2f,0x5d,0xed,0x10,0xd4,0x5d,0xed,0xfd,0x5d,0xed,0x87,0x10,0x2b,0x87,0x2b,0xc4,0x87,0x18,0x10,0x2b,0x87,0x2b,0xc4,0x11,0x12,0x00,0x39,0x10,0x87,0x05,0xc0,0xc0, +0xc0,0x11,0x12,0x00,0x39,0x10,0x87,0x05,0xc0,0xc0,0xc0,0x01,0x2b,0x5d,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x01,0x14,0x06,0x07,0x01,0x23,0x03,0x21,0x03,0x23,0x01,0x2e,0x01,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x03,0x2e,0x03,0x27,0x23,0x0e,0x03,0x07,0x03,0x21,0x01,0x35,0x37,0x33,0x15,0x05,0x17,0x34,0x2e,0x02,0x23,0x22, +0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x03,0x58,0x2b,0x2c,0x01,0xcb,0xc2,0x8a,0xfd,0xcd,0x89,0xc4,0x01,0xd1,0x2f,0x2e,0x1e,0x3c,0x5b,0x3d,0x3d,0x5b,0x3c,0x1e,0x9b,0x0a,0x16,0x15,0x11,0x06,0x12,0x06,0x10,0x13,0x14,0x0b,0x8c,0x01,0xb9,0xfe,0xc9,0xe3,0xc5,0xfe,0xd4,0x56,0x0d,0x1d,0x2e,0x21,0x21,0x2e,0x1e,0x0d, +0x0d,0x1e,0x2e,0x21,0x21,0x2e,0x1d,0x0d,0x04,0xbb,0x30,0x53,0x1d,0xfb,0xe5,0x01,0x43,0xfe,0xbd,0x04,0x17,0x1d,0x56,0x31,0x27,0x48,0x37,0x21,0x21,0x37,0x48,0xfe,0x49,0x1a,0x38,0x36,0x2f,0x11,0x11,0x30,0x36,0x38,0x19,0xfe,0xb1,0x03,0xc9,0x14,0xf0,0x1d,0xe7,0xea,0x0f,0x1d,0x18,0x0f,0x0f,0x18,0x1d,0x0f,0x0f,0x1e,0x18,0x0f, +0x0f,0x18,0x1e,0x00,0x00,0x04,0x00,0x80,0xff,0xec,0x04,0x88,0x06,0xa9,0x00,0x42,0x00,0x51,0x00,0x57,0x00,0x6b,0x01,0x36,0x40,0x1d,0x8a,0x28,0x01,0x7a,0x4d,0x8a,0x4d,0x02,0x65,0x04,0x01,0x6a,0x36,0x7a,0x36,0x8a,0x36,0x03,0x37,0x28,0x09,0x11,0x48,0x02,0x28,0x09,0x11,0x48,0x40,0xb8,0xff,0xe8,0xb3,0x09,0x11,0x48,0x3c,0xb8, +0xff,0xe8,0x40,0x1a,0x09,0x11,0x48,0x1d,0x13,0x2d,0x13,0x3d,0x13,0x03,0x1d,0x20,0x09,0x0c,0x48,0x06,0x21,0x16,0x21,0x02,0x34,0x18,0x09,0x0c,0x48,0x55,0xb8,0xff,0xe0,0x40,0x61,0x09,0x11,0x48,0x54,0x86,0x55,0x82,0x57,0x84,0x52,0x52,0x62,0x84,0x39,0x36,0x03,0x39,0x00,0x84,0x58,0x70,0x58,0x80,0x58,0x02,0x39,0x58,0x39,0x58, +0x1f,0x48,0x0e,0x0e,0x07,0x46,0x25,0x16,0x4f,0x48,0x5f,0x48,0x02,0x48,0x48,0x1f,0x6d,0x30,0x47,0xc0,0x31,0x01,0x31,0x31,0x4f,0x47,0x00,0x1f,0x01,0x1f,0x49,0x51,0x25,0xdf,0x30,0xef,0x30,0xff,0x30,0x03,0x30,0x40,0x09,0x0c,0x48,0x30,0x30,0x36,0x36,0x03,0x03,0x2b,0x67,0x5d,0x8e,0x3e,0x40,0x19,0x21,0x48,0x3e,0x52,0x80,0x67, +0xf0,0x67,0x02,0x67,0xb8,0xff,0xc0,0xb3,0x09,0x0d,0x48,0x52,0xb8,0xff,0xc0,0xb3,0x11,0x19,0x48,0x52,0xb8,0xff,0xc0,0x40,0x1c,0x0b,0x0f,0x48,0xbf,0x25,0xcf,0x25,0x02,0x20,0x25,0x60,0x25,0x02,0x25,0x67,0x52,0x52,0x67,0x25,0x03,0x54,0x0a,0x43,0x50,0x16,0x11,0x1c,0x16,0x00,0x3f,0x33,0x33,0xed,0x32,0x2f,0x17,0x39,0x2f,0x2f, +0x2f,0x5d,0x5d,0x2b,0x2b,0x2b,0x5d,0x10,0xd6,0x2b,0xed,0x10,0xcd,0x39,0x11,0x33,0x11,0x33,0x2f,0x2b,0x5d,0x10,0xed,0x01,0x2f,0x5d,0xed,0x33,0x2f,0x5d,0xed,0x11,0x12,0x39,0x2f,0x5d,0x33,0x33,0xed,0x32,0x2f,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x10,0xed,0x11,0x39,0x39,0x10,0xed,0x33,0x2f,0xed,0xfd,0xed,0x2b,0x31,0x30,0x00, +0x2b,0x5d,0x2b,0x5d,0x2b,0x2b,0x2b,0x2b,0x01,0x5d,0x00,0x5d,0x5d,0x5d,0x01,0x14,0x06,0x07,0x1e,0x01,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x15,0x0e,0x01,0x23,0x22,0x2e,0x02,0x27,0x23,0x0e,0x03,0x23,0x22,0x26,0x35,0x34,0x3e,0x02,0x3f,0x01,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x07,0x27,0x3e,0x03,0x37,0x2e,0x01,0x35, +0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x01,0x32,0x3e,0x02,0x3d,0x01,0x07,0x0e,0x03,0x15,0x14,0x16,0x13,0x35,0x37,0x33,0x15,0x05,0x17,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x03,0x4e,0x33,0x35,0x81,0x81,0x2a,0x3b,0x0f,0x1e,0x0e,0x22,0x43,0x26,0x33,0x49,0x2e,0x18,0x03,0x06,0x1c,0x44,0x58, +0x72,0x4a,0x9e,0xa0,0x4f,0x80,0xa3,0x54,0xec,0x1b,0x37,0x54,0x38,0x32,0x51,0x3a,0x25,0x06,0xbc,0x08,0x27,0x44,0x63,0x45,0x31,0x30,0x1e,0x3c,0x5b,0x3d,0x3d,0x5b,0x3c,0x1e,0xfe,0x9e,0x53,0x7a,0x51,0x28,0xbe,0x37,0x6f,0x59,0x38,0x59,0x66,0xe3,0xc5,0xfe,0xd4,0x5d,0x0d,0x1d,0x2e,0x21,0x21,0x2e,0x1e,0x0d,0x0d,0x1e,0x2e,0x21, +0x21,0x2e,0x1d,0x0d,0x04,0xe8,0x34,0x5a,0x1c,0x1e,0xb0,0x8e,0xfe,0x2e,0x50,0x51,0x04,0x03,0x70,0x08,0x08,0x1b,0x37,0x51,0x36,0x34,0x54,0x3b,0x20,0xac,0x96,0x6b,0x89,0x4e,0x1f,0x01,0x04,0x3b,0x43,0x5e,0x3a,0x1b,0x0f,0x27,0x43,0x33,0x11,0x34,0x5b,0x48,0x34,0x0d,0x1c,0x58,0x32,0x27,0x48,0x37,0x21,0x21,0x37,0x48,0xfb,0x66, +0x3f,0x60,0x74,0x35,0x59,0x04,0x01,0x0f,0x30,0x5b,0x4c,0x52,0x64,0x05,0x63,0x14,0xbd,0x1d,0xb4,0xf0,0x0f,0x1d,0x18,0x0f,0x0f,0x18,0x1d,0x0f,0x0f,0x1e,0x18,0x0f,0x0f,0x18,0x1e,0x00,0xff,0xff,0x00,0x01,0x00,0x00,0x04,0xab,0x06,0xa9,0x12,0x26,0x00,0x86,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0xf5,0x00,0xf5,0x00,0x15,0xb4,0x02, +0x19,0x05,0x26,0x02,0xb8,0x01,0x05,0xb4,0x19,0x1c,0x03,0x0d,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x14,0xff,0xec,0x04,0xb8,0x05,0xb4,0x12,0x26,0x00,0xa6,0x00,0x00,0x11,0x06,0x00,0x74,0x5a,0x00,0x00,0x13,0x40,0x0b,0x03,0x5a,0x11,0x26,0x03,0x5a,0x5a,0x5d,0x1e,0x40,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00, +0xff,0xff,0x00,0x38,0xff,0xda,0x04,0x92,0x06,0xa9,0x12,0x26,0x00,0x98,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x64,0x00,0xf5,0x00,0x13,0x40,0x0b,0x03,0x2c,0x05,0x26,0x03,0x65,0x2c,0x2f,0x0a,0x17,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x6e,0xff,0xec,0x04,0x5d,0x05,0xb4,0x12,0x26,0x00,0xb8,0x00,0x00, +0x11,0x06,0x00,0x74,0x64,0x00,0x00,0x13,0x40,0x0b,0x03,0x32,0x11,0x26,0x03,0x64,0x32,0x35,0x0e,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x4f,0xfe,0x59,0x04,0x68,0x05,0x5a,0x10,0x26,0x02,0x95,0xe3,0x00,0x12,0x06,0x00,0x36,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0xa7,0xfe,0x59,0x04,0x24,0x04,0x4b,0x10,0x26, +0x02,0x95,0x05,0x00,0x12,0x06,0x00,0x56,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x4c,0xfe,0x59,0x04,0x80,0x05,0x45,0x10,0x26,0x02,0x95,0xe3,0x00,0x12,0x06,0x00,0x37,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0xbe,0xfe,0x59,0x03,0xf9,0x05,0x54,0x10,0x26,0x02,0x95,0x05,0x00,0x12,0x06,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x1b, +0x04,0xb1,0x03,0xb1,0x05,0xb4,0x00,0x09,0x00,0x25,0x40,0x17,0x20,0x01,0x50,0x01,0x60,0x01,0x80,0x01,0x04,0x01,0x06,0x03,0x20,0x0b,0x0f,0x48,0x03,0x8e,0x09,0x8c,0x05,0x02,0x93,0x00,0x3f,0x33,0xfd,0xed,0x2b,0x01,0x2f,0xc4,0x5d,0x31,0x30,0x01,0x15,0x23,0x27,0x23,0x07,0x23,0x35,0x37,0x33,0x03,0xb1,0x69,0xdb,0x02,0xe8,0x68, +0xfe,0xa4,0x04,0xc5,0x14,0x8a,0x8a,0x14,0xef,0x00,0x00,0x00,0x00,0x01,0x01,0x1b,0x04,0xb1,0x03,0xb1,0x05,0xb4,0x00,0x09,0x00,0x2b,0x40,0x0e,0x20,0x08,0x50,0x08,0x60,0x08,0x80,0x08,0x04,0x08,0x03,0x07,0x04,0x06,0xb8,0xff,0xe0,0x40,0x09,0x0b,0x0f,0x48,0x06,0x8e,0x04,0x8c,0x01,0x93,0x00,0x3f,0xed,0xed,0x2b,0x11,0x33,0x01, +0x2f,0xc4,0x5d,0x31,0x30,0x01,0x23,0x27,0x35,0x33,0x17,0x33,0x37,0x33,0x15,0x02,0xbd,0xa4,0xfe,0x68,0xe8,0x02,0xdb,0x69,0x04,0xb1,0xef,0x14,0x8a,0x8a,0x14,0x00,0x00,0x01,0x01,0x51,0x04,0xd4,0x03,0x78,0x05,0x53,0x00,0x03,0x00,0x14,0x40,0x09,0x0f,0x00,0x01,0x00,0x01,0x03,0x8f,0x00,0x94,0x00,0x3f,0xed,0x01,0x2f,0xcd,0x5d, +0x31,0x30,0x01,0x21,0x35,0x21,0x03,0x78,0xfd,0xd9,0x02,0x27,0x04,0xd4,0x7f,0x00,0x00,0x01,0x01,0x2d,0x04,0xb1,0x03,0x9f,0x05,0xb4,0x00,0x11,0x00,0x31,0x40,0x1f,0x0c,0x84,0x0f,0x0d,0x1f,0x0d,0x2f,0x0d,0x03,0x0d,0x0d,0x06,0x84,0x00,0x05,0x20,0x05,0x02,0x05,0x0c,0x06,0x8c,0x75,0x09,0x85,0x09,0x02,0x09,0x8f,0x00,0x93,0x00, +0x3f,0xed,0x5d,0xe4,0x32,0x01,0x2f,0x5d,0xed,0x33,0x2f,0x5d,0xed,0x31,0x30,0x01,0x22,0x2e,0x02,0x27,0x33,0x1e,0x01,0x33,0x32,0x36,0x37,0x33,0x0e,0x03,0x02,0x65,0x4a,0x6e,0x4c,0x2c,0x08,0x7f,0x11,0x56,0x52,0x55,0x55,0x11,0x7f,0x09,0x2c,0x4b,0x6e,0x04,0xb1,0x2f,0x4b,0x5c,0x2d,0x3f,0x46,0x46,0x3f,0x2d,0x5c,0x4b,0x2f,0x00, +0x00,0x01,0x02,0x03,0x05,0x0c,0x02,0xcb,0x05,0xcc,0x00,0x03,0x00,0x15,0x40,0x0a,0x03,0x4a,0x10,0x00,0x01,0x00,0x00,0x53,0x01,0x00,0x00,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x31,0x30,0x01,0x35,0x33,0x15,0x02,0x03,0xc8,0x05,0x0c,0xc0,0xc0,0x00,0x00,0x00,0x02,0x01,0x74,0x04,0x7c,0x03,0x58,0x06,0x0b,0x00,0x13,0x00,0x27,0x00,0x8b, +0xb9,0x00,0x11,0xff,0xe8,0xb3,0x09,0x0f,0x48,0x0d,0xb8,0xff,0xe8,0x40,0x61,0x09,0x0f,0x48,0x07,0x18,0x09,0x0f,0x48,0x03,0x18,0x09,0x0f,0x48,0x14,0x84,0x00,0x00,0x10,0x00,0x20,0x00,0x03,0x30,0x00,0x70,0x00,0x80,0x00,0xb0,0x00,0xc0,0x00,0xd0,0x00,0x06,0x60,0x00,0x01,0x0f,0x00,0x1f,0x00,0x02,0x00,0x1e,0x84,0x00,0x0a,0x01, +0x0a,0x19,0x8e,0x7f,0x0f,0x8f,0x0f,0x02,0x0f,0x40,0x09,0x0c,0x48,0x0f,0x23,0x8e,0x2f,0x05,0x4f,0x05,0x6f,0x05,0xdf,0x05,0x04,0x0f,0x05,0x2f,0x05,0x3f,0x05,0x4f,0x05,0x6f,0x05,0x7f,0x05,0x9f,0x05,0xbf,0x05,0x08,0x05,0x40,0x16,0x19,0x48,0x05,0x00,0x2f,0x2b,0x5d,0x71,0xed,0xd4,0x2b,0x5d,0xed,0x01,0x2f,0x5d,0xed,0xd4,0x5d, +0x5d,0x71,0x72,0xed,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x03,0x58,0x1e,0x3c,0x5b,0x3d,0x3d,0x5b,0x3c,0x1e,0x1e,0x3c,0x5b,0x3d,0x3d,0x5b,0x3c,0x1e,0x79,0x0d,0x1d, +0x2e,0x21,0x21,0x2e,0x1e,0x0d,0x0d,0x1e,0x2e,0x21,0x21,0x2e,0x1d,0x0d,0x05,0x44,0x27,0x48,0x38,0x21,0x21,0x38,0x48,0x27,0x27,0x48,0x37,0x21,0x21,0x37,0x48,0x27,0x0f,0x1d,0x18,0x0f,0x0f,0x18,0x1d,0x0f,0x0f,0x1e,0x18,0x0f,0x0f,0x18,0x1e,0x00,0x00,0x01,0x01,0xb9,0xfe,0x55,0x03,0x17,0x00,0x00,0x00,0x17,0x00,0x30,0x40,0x1c, +0x08,0x40,0x0d,0x10,0x48,0x05,0x40,0x0d,0x14,0x48,0x0c,0x87,0x0b,0x0b,0x06,0x00,0x00,0x11,0x84,0x00,0x06,0x01,0x06,0x0b,0x14,0x8e,0x03,0x95,0x00,0x3f,0xed,0x2f,0x01,0x2f,0x5d,0xed,0x33,0x2f,0x12,0x39,0x2f,0xed,0x31,0x30,0x2b,0x2b,0x01,0x0e,0x01,0x23,0x22,0x26,0x35,0x34,0x3e,0x02,0x37,0x33,0x0e,0x03,0x15,0x14,0x16,0x33, +0x32,0x36,0x37,0x03,0x17,0x1c,0x47,0x28,0x69,0x6a,0x22,0x30,0x36,0x13,0x85,0x19,0x34,0x2b,0x1b,0x31,0x2d,0x1d,0x3a,0x1c,0xfe,0x70,0x0c,0x0f,0x66,0x55,0x2f,0x4f,0x3d,0x2a,0x0b,0x0e,0x2d,0x3b,0x46,0x27,0x2a,0x30,0x0d,0x0b,0x00,0x01,0x00,0xff,0x04,0xb1,0x03,0xcc,0x05,0xa9,0x00,0x1f,0x00,0x51,0x40,0x10,0x0a,0x1f,0x1a,0x1f, +0x02,0x1e,0x18,0x09,0x0f,0x48,0x05,0x0f,0x15,0x0f,0x02,0x0e,0xb8,0xff,0xe8,0x40,0x24,0x09,0x0f,0x48,0x1a,0x83,0x0f,0x1b,0x2f,0x1b,0x3f,0x1b,0x7f,0x1b,0x8f,0x1b,0x05,0x1b,0x1b,0x0a,0x83,0x00,0x0b,0x30,0x0b,0x02,0x0b,0x1a,0x05,0x8f,0x10,0x8c,0x15,0x8f,0x0a,0x00,0x93,0x00,0x3f,0x32,0xed,0xfd,0xed,0x33,0x01,0x2f,0x5d,0xed, +0x33,0x2f,0x5d,0xed,0x31,0x30,0x00,0x2b,0x5d,0x2b,0x5d,0x01,0x22,0x2e,0x02,0x23,0x22,0x0e,0x02,0x07,0x23,0x3e,0x03,0x33,0x32,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x33,0x0e,0x03,0x03,0x02,0x2a,0x54,0x50,0x4d,0x23,0x17,0x1d,0x13,0x0a,0x05,0x6f,0x05,0x14,0x2d,0x4a,0x3b,0x2c,0x54,0x50,0x4a,0x21,0x17,0x1e,0x14,0x0a,0x04,0x70, +0x05,0x14,0x2b,0x4a,0x04,0xb1,0x25,0x2d,0x25,0x10,0x1e,0x2c,0x1d,0x2d,0x58,0x47,0x2c,0x25,0x2d,0x25,0x10,0x1f,0x2c,0x1c,0x2c,0x58,0x47,0x2d,0x00,0x02,0x00,0x1d,0x04,0xb1,0x03,0x13,0x05,0xb4,0x00,0x05,0x00,0x0b,0x00,0x5a,0x40,0x0f,0x02,0x89,0x74,0x03,0x84,0x03,0x02,0x06,0x03,0x16,0x03,0x02,0x03,0x8b,0x05,0xb8,0xff,0xe8, +0x40,0x16,0x0b,0x0f,0x48,0x05,0x8a,0x00,0x00,0x08,0x89,0x74,0x09,0x84,0x09,0x02,0x06,0x09,0x16,0x09,0x02,0x09,0x8b,0x0b,0xb8,0xff,0xe8,0x40,0x0f,0x0b,0x0f,0x48,0x0b,0x8a,0x00,0x06,0x01,0x06,0x08,0x02,0x8c,0x0b,0x05,0x93,0x00,0x3f,0x33,0xed,0x32,0x01,0x7c,0x2f,0x5d,0x18,0xed,0x2b,0xfd,0x5d,0x5d,0xed,0x33,0x2f,0xed,0x2b, +0xfd,0x5d,0x5d,0xed,0x31,0x30,0x01,0x35,0x37,0x33,0x15,0x05,0x21,0x35,0x37,0x33,0x15,0x05,0x01,0x89,0xcf,0xbb,0xfe,0xd4,0xfe,0x36,0xcf,0xbb,0xfe,0xd4,0x04,0xb1,0x14,0xef,0x1d,0xe6,0x14,0xef,0x1d,0xe6,0x00,0x01,0x01,0xdb,0x04,0xb1,0x02,0xef,0x05,0xf6,0x00,0x05,0x00,0x2e,0x40,0x0a,0x66,0x05,0x76,0x05,0x86,0x05,0x03,0x02, +0x86,0x03,0xb8,0x01,0x0b,0x40,0x09,0x05,0x83,0x2f,0x00,0x3f,0x00,0x02,0x00,0x02,0xb8,0x01,0x0c,0xb1,0x05,0x93,0x00,0x3f,0xed,0x01,0x7d,0x2f,0x5d,0x18,0xed,0xfd,0xed,0x31,0x30,0x5d,0x01,0x35,0x13,0x33,0x15,0x03,0x01,0xdb,0x4f,0xc5,0xab,0x04,0xb1,0x21,0x01,0x24,0x25,0xfe,0xe0,0x00,0x00,0x03,0x01,0x37,0x04,0xb1,0x03,0x96, +0x06,0x41,0x00,0x05,0x00,0x09,0x00,0x0d,0x00,0x75,0xb2,0x02,0x86,0x03,0xb8,0x01,0x0b,0x40,0x0a,0x67,0x05,0x77,0x05,0x87,0x05,0x03,0x05,0x83,0x00,0xb8,0xff,0xc0,0xb3,0x22,0x26,0x48,0x00,0xb8,0xff,0xc0,0x40,0x32,0x17,0x1b,0x48,0x00,0x00,0x06,0x0d,0x88,0x54,0x0a,0x01,0x34,0x0a,0x44,0x0a,0x54,0x0a,0x84,0x0a,0x94,0x0a,0xa4, +0x0a,0xe4,0x0a,0xf4,0x0a,0x08,0x10,0x0a,0x20,0x0a,0x02,0x02,0x00,0x0a,0x01,0x0a,0x09,0x88,0x0f,0x06,0x01,0x06,0x08,0x0b,0x90,0x09,0x0a,0x02,0xb8,0x01,0x0c,0xb1,0x05,0x93,0x00,0x3f,0xed,0xd4,0x32,0xed,0x32,0x01,0x2f,0x71,0xed,0x2f,0x5d,0x5f,0x5d,0x5d,0x71,0xed,0x12,0x39,0x2f,0x2b,0x2b,0xed,0x5d,0xfd,0xed,0x31,0x30,0x01, +0x35,0x13,0x33,0x15,0x03,0x37,0x35,0x33,0x15,0x21,0x35,0x33,0x15,0x02,0x09,0x36,0xc5,0x92,0x95,0x8f,0xfd,0xa1,0x91,0x04,0xb1,0x21,0x01,0x6f,0x25,0xfe,0x95,0x12,0xb8,0xb8,0xb8,0xb8,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x05,0x46,0x12,0x26,0x00,0x24,0x00,0x00,0x11,0x07,0x01,0x54,0xfe,0x26,0xff,0x50,0x00,0x14,0xb3,0x02, +0x17,0x03,0x02,0xb8,0xfe,0x25,0xb4,0x15,0x18,0x04,0x07,0x25,0x01,0x2b,0x35,0x00,0x3f,0x35,0x00,0x00,0x00,0x01,0x01,0xf0,0x01,0xa4,0x02,0xdb,0x02,0xcf,0x00,0x03,0x00,0x28,0x40,0x1b,0x03,0x96,0x20,0x00,0x01,0x00,0x00,0xa0,0x00,0x02,0x00,0x00,0x9b,0x0f,0x01,0x3f,0x01,0x6f,0x01,0x9f,0x01,0xcf,0x01,0xef,0x01,0x06,0x01,0x00, +0x2f,0x5d,0xed,0x01,0x2f,0x5d,0x71,0xed,0x31,0x30,0x01,0x11,0x33,0x11,0x01,0xf0,0xeb,0x01,0xa4,0x01,0x2b,0xfe,0xd5,0x00,0xff,0xff,0xff,0xcf,0x00,0x00,0x04,0xc3,0x05,0x46,0x10,0x26,0x00,0x28,0x61,0x00,0x11,0x07,0x01,0x54,0xfd,0xf4,0xff,0x50,0x00,0x26,0xb4,0x01,0x0e,0x03,0x01,0x0f,0xb8,0xff,0xc0,0xb3,0x15,0x1c,0x48,0x0f, +0xb8,0xff,0xc0,0xb2,0x09,0x12,0x48,0xb8,0xff,0xe0,0xb4,0x0f,0x0f,0x00,0x00,0x25,0x01,0x2b,0x2b,0x2b,0x35,0x00,0x3f,0x35,0x00,0x02,0x00,0x00,0x00,0x00,0x04,0x69,0x05,0x45,0x00,0x0b,0x00,0x11,0x00,0x68,0x40,0x1e,0x66,0x11,0x76,0x11,0x86,0x11,0x03,0x0b,0x5a,0x00,0x08,0x00,0x07,0x03,0x5a,0x10,0x00,0x01,0x0f,0x04,0x01,0x04, +0x00,0x04,0x00,0x0c,0x13,0x0e,0x86,0x0f,0xb8,0x01,0x0b,0x40,0x12,0x11,0x83,0x0c,0x02,0x5f,0x50,0x07,0x01,0xa0,0x07,0xb0,0x07,0x02,0x07,0x07,0x00,0x05,0x11,0xb8,0x01,0x0c,0xb7,0x0e,0x0e,0x09,0x05,0x03,0x04,0x00,0x12,0x00,0x3f,0x32,0x3f,0x33,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f,0x5d,0x71,0xed,0x01,0x2f,0xed,0xfd,0xed,0x11, +0x12,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0xed,0x32,0x11,0x33,0x10,0xed,0x31,0x30,0x5d,0x21,0x11,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x01,0x35,0x13,0x33,0x15,0x03,0x03,0xaf,0xfe,0x58,0xbf,0xbf,0x01,0xa8,0xba,0xfb,0x97,0x4f,0xc5,0xab,0x02,0x6f,0xfd,0x91,0x05,0x45,0xfd,0xca,0x02,0x36,0xfa,0xbb,0x04,0x00,0x21,0x01, +0x24,0x25,0xfe,0xe0,0xff,0xff,0x00,0x01,0x00,0x00,0x04,0x80,0x05,0x46,0x10,0x26,0x00,0x2c,0x7f,0x00,0x11,0x07,0x01,0x54,0xfe,0x26,0xff,0x50,0x00,0x26,0xb4,0x01,0x0e,0x03,0x01,0x0f,0xb8,0xff,0xc0,0xb3,0x12,0x13,0x48,0x0f,0xb8,0xff,0xc0,0xb2,0x09,0x0f,0x48,0xb8,0xff,0xcc,0xb4,0x0f,0x0f,0x00,0x00,0x25,0x01,0x2b,0x2b,0x2b, +0x35,0x00,0x3f,0x35,0xff,0xff,0xff,0xcf,0xff,0xec,0x04,0xac,0x05,0x5a,0x10,0x26,0x00,0x32,0x46,0x00,0x11,0x07,0x01,0x54,0xfd,0xf4,0xff,0x50,0x00,0x14,0xb3,0x02,0x20,0x03,0x02,0xb8,0xfd,0xad,0xb4,0x1e,0x21,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x3f,0x35,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x04,0xaf,0x05,0x45,0x00,0x08, +0x00,0x0e,0x00,0x96,0x40,0x14,0x06,0x0e,0x16,0x0e,0x26,0x0e,0x03,0x2c,0x07,0x01,0x07,0x18,0x0d,0x10,0x48,0x23,0x05,0x01,0x03,0x05,0xb8,0xff,0xe8,0x40,0x26,0x0d,0x10,0x48,0x00,0x06,0x10,0x06,0x20,0x06,0x03,0x0f,0x04,0x07,0x08,0x0e,0x01,0x04,0x02,0x0e,0x05,0x0f,0x04,0x01,0x04,0x06,0x01,0x5a,0x02,0x40,0x0b,0x0e,0x48,0x02, +0x02,0x10,0x0b,0x86,0x0c,0xb8,0x01,0x0b,0x40,0x14,0x0e,0x83,0x09,0x06,0x03,0x40,0x00,0x50,0x00,0x60,0x00,0x03,0x3f,0x00,0x01,0x00,0x00,0x04,0x01,0x0e,0xb8,0x01,0x0c,0xb6,0x0b,0x0b,0x07,0x04,0x03,0x01,0x12,0x00,0x3f,0x3f,0x33,0x33,0x10,0xed,0x11,0x12,0x39,0x2f,0x5d,0x5d,0x33,0x33,0x01,0x2f,0xed,0xfd,0xed,0x12,0x39,0x2f, +0x2b,0xed,0x39,0xc6,0x5d,0x32,0x2b,0x01,0x18,0x10,0x4d,0xe6,0x32,0x31,0x30,0x00,0x5f,0x5e,0x5d,0x01,0x2b,0x5f,0x5d,0x2b,0x5d,0x5d,0x01,0x11,0x23,0x11,0x01,0x33,0x1b,0x01,0x33,0x01,0x35,0x13,0x33,0x15,0x03,0x03,0x4d,0xbc,0xfe,0x9e,0xc9,0xf8,0xf6,0xc9,0xfb,0x51,0x4f,0xc5,0xab,0x02,0x48,0xfd,0xb8,0x02,0x48,0x02,0xfd,0xfd, +0xa7,0x02,0x59,0xfe,0xbb,0x21,0x01,0x24,0x25,0xfe,0xe0,0x00,0x00,0x02,0xff,0xce,0x00,0x00,0x04,0x9b,0x05,0x5a,0x00,0x39,0x00,0x3f,0x00,0xbf,0x40,0x36,0x66,0x3f,0x76,0x3f,0x86,0x3f,0x03,0x6b,0x09,0x7b,0x09,0x8b,0x09,0x03,0x6b,0x31,0x7b,0x31,0x8b,0x31,0x03,0x62,0x25,0x72,0x25,0x82,0x25,0x03,0x62,0x15,0x72,0x15,0x82,0x15, +0x03,0x45,0x38,0x55,0x38,0x02,0x45,0x02,0x55,0x02,0x02,0x3a,0x1f,0x01,0x3a,0x1b,0x01,0x3c,0x86,0x3d,0xb8,0x01,0x0b,0x40,0x35,0x3f,0x83,0x3a,0x40,0x1a,0x21,0x48,0x3a,0x3a,0x35,0x30,0x5c,0x28,0x0a,0x5c,0x12,0x28,0x12,0x28,0x12,0x35,0x18,0x10,0x10,0x05,0x5a,0x10,0x18,0x20,0x18,0x30,0x18,0x80,0x18,0x04,0x10,0x18,0x01,0x18, +0x18,0x41,0x40,0x2a,0x2a,0x22,0x5a,0x35,0x40,0x10,0x14,0x48,0x35,0x3f,0xb8,0x01,0x0c,0x40,0x0f,0x3c,0x03,0x13,0x27,0x27,0x10,0x2a,0x5f,0x12,0x29,0x12,0x1d,0x5f,0x00,0x04,0x00,0x3f,0xed,0x3f,0x33,0xed,0x32,0x32,0x2f,0x33,0x3f,0xed,0x01,0x2f,0x2b,0xed,0x33,0x2f,0x11,0x12,0x39,0x2f,0x5d,0x71,0xed,0x32,0x2f,0x11,0x12,0x39, +0x39,0x2f,0x2f,0x10,0xed,0x10,0xed,0x11,0x33,0x2f,0x2b,0xed,0xfd,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x36,0x37,0x3e,0x01,0x3b,0x01,0x15,0x21,0x35,0x3e,0x03,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x17,0x15,0x21,0x35,0x33, +0x32,0x16,0x17,0x16,0x17,0x2e,0x03,0x35,0x34,0x3e,0x02,0x01,0x35,0x13,0x33,0x15,0x03,0x02,0x8d,0x71,0xb9,0x84,0x48,0x26,0x4f,0x77,0x51,0x1a,0x1a,0x16,0x30,0x13,0xc8,0xfe,0x31,0x4b,0x5f,0x36,0x14,0x27,0x4c,0x73,0x4c,0x4d,0x73,0x4d,0x27,0x14,0x36,0x5f,0x4b,0xfe,0x31,0xc8,0x13,0x30,0x16,0x1a,0x1a,0x51,0x77,0x4f,0x26,0x49, +0x84,0xb9,0xfd,0xb1,0x4f,0xc5,0xab,0x05,0x5a,0x55,0x9d,0xdd,0x88,0x5f,0xb3,0xa0,0x8a,0x36,0x03,0x03,0x02,0x03,0x9c,0xe0,0x37,0x7d,0x88,0x90,0x4a,0x69,0xa8,0x77,0x40,0x40,0x77,0xa8,0x69,0x4a,0x90,0x88,0x7d,0x37,0xe0,0x9c,0x03,0x02,0x03,0x03,0x36,0x8a,0xa0,0xb3,0x5f,0x88,0xdd,0x9d,0x55,0xfe,0xa6,0x21,0x01,0x24,0x25,0xfe, +0xe0,0x00,0x00,0x00,0xff,0xff,0x00,0x95,0xff,0xec,0x04,0x5d,0x06,0x41,0x12,0x26,0x01,0x86,0x00,0x00,0x11,0x06,0x01,0x55,0xf3,0x00,0x00,0x19,0xb5,0x03,0x02,0x01,0x03,0x02,0x01,0xb8,0xff,0xe1,0xb4,0x1e,0x1c,0x11,0x07,0x25,0x01,0x2b,0x35,0x35,0x35,0x00,0x35,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc, +0x05,0x45,0x12,0x06,0x00,0x24,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x80,0x05,0x45,0x12,0x06,0x00,0x25,0x00,0x00,0x00,0x01,0x00,0xe0,0x00,0x00,0x04,0x5b,0x05,0x45,0x00,0x05,0x00,0x20,0x40,0x11,0x03,0x03,0x07,0x00,0x5a,0x00,0x01,0x10,0x01,0x02,0x01,0x05,0x5f,0x02,0x03,0x00,0x12,0x00,0x3f,0x3f,0xed,0x01,0x2f,0x5d, +0xed,0x12,0x39,0x2f,0x31,0x30,0x21,0x23,0x11,0x21,0x15,0x21,0x01,0x9f,0xbf,0x03,0x7b,0xfd,0x44,0x05,0x45,0x9c,0x00,0x00,0x00,0x02,0x00,0x0c,0x00,0x00,0x04,0xc0,0x05,0x45,0x00,0x05,0x00,0x12,0x00,0x79,0x40,0x4c,0x29,0x02,0x01,0x06,0x03,0x01,0x03,0x01,0x52,0x12,0x0b,0x12,0x5e,0x04,0x03,0x14,0x04,0x04,0x03,0x02,0x01,0x52, +0x11,0x0b,0x11,0x5e,0x01,0x02,0x14,0x01,0x01,0x02,0x02,0x03,0x0b,0x03,0x01,0x04,0x5a,0x6f,0x12,0x7f,0x12,0x8f,0x12,0x03,0x10,0x12,0x01,0x12,0x12,0x14,0x11,0x5a,0x01,0x5a,0x0b,0x01,0x4b,0x0b,0x01,0x0b,0x03,0x02,0x03,0x12,0x04,0x01,0x01,0x04,0x12,0x03,0x11,0x5f,0x00,0x12,0x00,0x3f,0xed,0x17,0x32,0x2f,0x2f,0x2f,0x3f,0x33, +0x33,0x5d,0x5d,0x01,0x2f,0xed,0x12,0x39,0x2f,0x5d,0x5d,0xed,0x11,0x17,0x39,0x87,0x10,0x2b,0x87,0x2b,0xc4,0x87,0x18,0x10,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x01,0x5d,0x5d,0x33,0x35,0x01,0x33,0x01,0x15,0x01,0x2e,0x03,0x27,0x0e,0x03,0x07,0x01,0x21,0x0c,0x01,0xdd,0xf4,0x01,0xe3,0xfe,0x06,0x12,0x22,0x1b,0x11,0x02,0x01,0x12,0x1b, +0x22,0x12,0xfe,0xca,0x03,0x34,0x91,0x04,0xb4,0xfb,0x4e,0x93,0x03,0xa9,0x2e,0x5e,0x4f,0x36,0x04,0x04,0x36,0x4f,0x5f,0x2d,0xfc,0xf3,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x05,0x45,0x12,0x06,0x00,0x28,0x00,0x00,0xff,0xff,0x00,0x49,0x00,0x00,0x04,0x83,0x05,0x45,0x12,0x06,0x00,0x3d,0x00,0x00,0xff,0xff,0x00,0xa2, +0x00,0x00,0x04,0x2a,0x05,0x45,0x12,0x06,0x00,0x2b,0x00,0x00,0x00,0x03,0x00,0x66,0xff,0xec,0x04,0x66,0x05,0x5a,0x00,0x11,0x00,0x1d,0x00,0x21,0x00,0xca,0x40,0x51,0x56,0x10,0x01,0x45,0x10,0x01,0x46,0x0d,0x56,0x0d,0x02,0x49,0x07,0x59,0x07,0x02,0x49,0x03,0x59,0x03,0x02,0x76,0x1d,0x86,0x1d,0x02,0x34,0x1d,0x01,0x76,0x19,0x86, +0x19,0x02,0x34,0x19,0x01,0x79,0x17,0x89,0x17,0x02,0x3b,0x17,0x01,0x79,0x13,0x89,0x13,0x02,0x3b,0x13,0x01,0x1f,0x1e,0x2f,0x1e,0x3f,0x1e,0x7f,0x1e,0x8f,0x1e,0x05,0x1e,0x40,0x15,0x1c,0x48,0x10,0x21,0x20,0x21,0x30,0x21,0x70,0x21,0x80,0x21,0x05,0x21,0xb8,0xff,0xc0,0x40,0x42,0x15,0x1c,0x48,0x21,0x1e,0x21,0x1e,0x0a,0x00,0x5b, +0x5f,0x12,0x01,0x12,0x40,0x19,0x1c,0x48,0x00,0x12,0x01,0x12,0x12,0x23,0x18,0x5b,0x50,0x0a,0x01,0x10,0x0a,0x01,0x0a,0x20,0x5f,0x0f,0x21,0x3f,0x21,0x7f,0x21,0x8f,0x21,0x04,0x6f,0x21,0x8f,0x21,0x9f,0x21,0xbf,0x21,0xdf,0x21,0x05,0x21,0x21,0x1b,0x15,0x5f,0x0f,0x04,0x1b,0x5f,0x05,0x13,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f, +0x71,0x72,0xed,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x2b,0x71,0xed,0x11,0x39,0x39,0x2f,0x2f,0x2b,0x5d,0x2b,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x00,0x03,0x10,0x02,0x23,0x22,0x02, +0x11,0x10,0x12,0x33,0x32,0x12,0x03,0x15,0x21,0x35,0x04,0x66,0x46,0x84,0xbf,0x78,0x7f,0xc0,0x80,0x40,0x44,0x82,0xbf,0x7c,0xf7,0x01,0x08,0xc9,0x9e,0x98,0x9c,0x9c,0x9e,0x99,0xa3,0x94,0x8f,0xfe,0xb1,0x02,0xa9,0xad,0xfe,0xfa,0xb1,0x59,0x5e,0xb3,0x01,0x05,0xa7,0xad,0x01,0x02,0xac,0x56,0xfe,0xa5,0xfe,0xaa,0x01,0x0e,0x01,0x07, +0xfe,0xf9,0xfe,0xf2,0xfe,0xf2,0xfe,0xec,0x01,0x18,0x01,0x56,0x9a,0x9a,0x00,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x05,0x45,0x12,0x06,0x00,0x2c,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0xcb,0x05,0x45,0x12,0x06,0x00,0x2e,0x00,0x00,0x00,0x01,0x00,0x0a,0x00,0x00,0x04,0xc2,0x05,0x45,0x00,0x10,0x00,0x5f,0x40,0x37, +0x10,0x01,0x52,0x01,0x07,0x01,0x5e,0x00,0x10,0x14,0x00,0x10,0x01,0x00,0x0f,0x01,0x52,0x0d,0x07,0x0d,0x5e,0x0e,0x0f,0x14,0x0e,0x0f,0x0d,0x0e,0x07,0x0e,0x10,0x00,0x01,0x00,0x00,0x12,0x7f,0x0e,0x8f,0x0e,0x02,0x0e,0x5a,0x07,0x01,0x4b,0x07,0x01,0x07,0x10,0x0f,0x03,0x0e,0x00,0x12,0x00,0x3f,0x32,0x3f,0x33,0x33,0x5d,0x5d,0x01, +0x2f,0x5d,0x11,0x33,0x2f,0x5d,0x12,0x39,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87,0x2b,0xc4,0x10,0x00,0xc1,0x87,0x05,0x18,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x21,0x23,0x01,0x2e,0x01,0x27,0x26,0x27,0x06,0x07,0x0e,0x01,0x07,0x01,0x23,0x01,0x33,0x04,0xc2,0xc9,0xfe,0xc2,0x10,0x1e,0x0c,0x0e,0x0c,0x0d,0x0e,0x0c,0x1d,0x10,0xfe,0xc0,0xc9, +0x01,0xf9,0xc6,0x03,0x86,0x30,0x61,0x29,0x30,0x2d,0x2f,0x30,0x2a,0x61,0x2d,0xfc,0x7a,0x05,0x45,0x00,0xff,0xff,0x00,0x81,0x00,0x00,0x04,0x4b,0x05,0x45,0x12,0x06,0x00,0x30,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x05,0x45,0x12,0x06,0x00,0x31,0x00,0x00,0x00,0x03,0x00,0x87,0x00,0x00,0x04,0x46,0x05,0x45,0x00,0x03, +0x00,0x07,0x00,0x0b,0x00,0x87,0x40,0x65,0xc0,0x07,0xd0,0x07,0xe0,0x07,0x03,0xe0,0x07,0xf0,0x07,0x02,0xbf,0x02,0xcf,0x02,0xdf,0x02,0x03,0x02,0x40,0x21,0x24,0x48,0x9f,0x08,0xaf,0x08,0xbf,0x08,0x03,0x00,0x0b,0xc0,0x0b,0xd0,0x0b,0xe0,0x0b,0x04,0x00,0x0b,0xe0,0x0b,0xf0,0x0b,0x03,0x00,0x0b,0x08,0x02,0x07,0x07,0x02,0x08,0x0b, +0x00,0x05,0x0d,0xcf,0x04,0x01,0x00,0x04,0x10,0x04,0x02,0x04,0x0a,0x5f,0x0f,0x0b,0x3f,0x0b,0x7f,0x0b,0x8f,0x0b,0x04,0x6f,0x0b,0x8f,0x0b,0x9f,0x0b,0xbf,0x0b,0xdf,0x0b,0x05,0x0b,0x0b,0x01,0x05,0x5f,0x04,0x12,0x00,0x5f,0x01,0x03,0x00,0x3f,0xed,0x3f,0xed,0x11,0x39,0x2f,0x71,0x72,0xed,0x01,0x2f,0x5d,0x71,0x12,0x17,0x39,0x2f, +0x2f,0x2f,0x2f,0x2f,0x5d,0x71,0x5d,0x2b,0x5d,0x5d,0x71,0x31,0x30,0x13,0x35,0x21,0x15,0x01,0x35,0x21,0x15,0x03,0x15,0x21,0x35,0x9b,0x03,0x97,0xfc,0x55,0x03,0xbf,0x91,0xfd,0x63,0x04,0xa9,0x9c,0x9c,0xfb,0x57,0x9c,0x9c,0x03,0x03,0x9a,0x9a,0x00,0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x05,0x5a,0x12,0x06,0x00,0x32,0x00,0x00, +0x00,0x01,0x00,0xa3,0x00,0x00,0x04,0x2a,0x05,0x45,0x00,0x07,0x00,0x43,0x40,0x2f,0x03,0x5a,0x1f,0x04,0x2f,0x04,0x3f,0x04,0x6f,0x04,0x7f,0x04,0x05,0x6f,0x04,0x7f,0x04,0x8f,0x04,0xbf,0x04,0x04,0x04,0x04,0x09,0x07,0x5a,0x70,0x00,0x01,0x00,0x00,0x10,0x00,0xa0,0x00,0xb0,0x00,0x04,0x00,0x06,0x5f,0x01,0x03,0x04,0x00,0x12,0x00, +0x3f,0x32,0x3f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x31,0x30,0x33,0x11,0x21,0x11,0x23,0x11,0x21,0x11,0xa3,0x03,0x87,0xbf,0xfd,0xf7,0x05,0x45,0xfa,0xbb,0x04,0xa9,0xfb,0x57,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x5f,0x05,0x45,0x12,0x06,0x00,0x33,0x00,0x00,0x00,0x01,0x00,0x6c,0x00,0x00,0x04,0xa1, +0x05,0x45,0x00,0x0c,0x00,0x67,0x40,0x19,0x76,0x08,0x86,0x08,0x02,0x08,0x02,0x02,0x05,0x01,0x07,0x5b,0x9f,0x05,0xaf,0x05,0xbf,0x05,0x03,0x03,0x05,0x03,0x05,0x01,0x0b,0xb8,0xff,0xc0,0x40,0x1f,0x09,0x16,0x48,0x0b,0x0b,0x0e,0x0a,0x5b,0x10,0x01,0x01,0x01,0x03,0x07,0x5f,0x04,0x09,0x08,0x40,0x02,0x01,0x02,0x02,0x09,0x04,0x03, +0x01,0x0a,0x5f,0x00,0x12,0x00,0x3f,0xed,0x32,0x3f,0x12,0x39,0x19,0x2f,0x71,0x33,0x33,0x18,0x10,0xed,0x32,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x2b,0x12,0x39,0x39,0x2f,0x2f,0x5d,0xed,0x11,0x12,0x39,0x2f,0xcd,0x31,0x30,0x00,0x5d,0x33,0x35,0x09,0x01,0x35,0x21,0x15,0x21,0x01,0x15,0x01,0x21,0x15,0x6c,0x02,0x1a,0xfd,0xf7,0x03, +0xe7,0xfc,0xf0,0x01,0xca,0xfe,0x16,0x03,0x6d,0xa2,0x02,0x25,0x01,0xdd,0xa1,0x9c,0xfe,0x61,0x7c,0xfe,0x0e,0x9c,0x00,0x00,0xff,0xff,0x00,0x4c,0x00,0x00,0x04,0x80,0x05,0x45,0x12,0x06,0x00,0x37,0x00,0x00,0xff,0xff,0x00,0x24,0x00,0x00,0x04,0xa8,0x05,0x45,0x12,0x06,0x00,0x3c,0x00,0x00,0x00,0x03,0x00,0x08,0xff,0xf5,0x04,0xc5, +0x05,0x4f,0x00,0x1d,0x00,0x2a,0x00,0x37,0x00,0x94,0xb9,0x00,0x2d,0xff,0xe0,0xb3,0x0c,0x0f,0x48,0x29,0xb8,0xff,0xe0,0x40,0x52,0x0c,0x0f,0x48,0x36,0x18,0x0c,0x0f,0x48,0x20,0x18,0x0c,0x0f,0x48,0x1e,0x5a,0x40,0x00,0x0e,0x07,0x0f,0x08,0x0e,0x2b,0x5a,0x0f,0x25,0x18,0x07,0x5c,0x31,0x15,0x7f,0x08,0x8f,0x08,0x02,0x0f,0x08,0x3f, +0x08,0xbf,0x08,0xcf,0x08,0x04,0x4f,0x08,0x5f,0x08,0x7f,0x08,0x8f,0x08,0x04,0x08,0x08,0x39,0x38,0x23,0x32,0x60,0x15,0x18,0x15,0x26,0x31,0x60,0x09,0x06,0x09,0x90,0x15,0x01,0x15,0x09,0x15,0x09,0x07,0x16,0x03,0x07,0x13,0x00,0x3f,0x3f,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x11,0x33,0x10,0xed,0x32,0x11,0x33,0x10,0xed,0x32,0x11,0x12, +0x01,0x39,0x2f,0x5d,0x71,0x72,0x33,0x33,0xed,0x32,0x32,0x7d,0xd4,0x18,0xed,0x2b,0x01,0x18,0x10,0x4d,0xf4,0x1a,0xed,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x01,0x14,0x0e,0x02,0x2b,0x01,0x15,0x23,0x35,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x3b,0x01,0x35,0x33,0x15,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x2b,0x01,0x11,0x33, +0x32,0x3e,0x02,0x25,0x14,0x1e,0x02,0x3b,0x01,0x11,0x23,0x22,0x0e,0x02,0x04,0xc5,0x3f,0x79,0xb1,0x72,0x29,0xb5,0x29,0x72,0xb1,0x79,0x3f,0x41,0x7c,0xb5,0x74,0x1e,0xb5,0x1d,0x74,0xb6,0x7c,0x41,0xc2,0x2d,0x52,0x76,0x48,0x05,0x0c,0x4a,0x73,0x4f,0x2a,0xfc,0xc7,0x2a,0x4f,0x74,0x49,0x0c,0x08,0x48,0x74,0x52,0x2c,0x02,0xc2,0x61, +0xb5,0x8b,0x53,0xd9,0xd9,0x53,0x8b,0xb5,0x61,0x6a,0xb1,0x7f,0x47,0xac,0xac,0x47,0x7f,0xb1,0x6e,0x56,0x80,0x55,0x2b,0xfd,0x48,0x32,0x5d,0x83,0x50,0x50,0x83,0x5d,0x32,0x02,0xb8,0x2b,0x55,0x80,0x00,0x00,0xff,0xff,0x00,0x24,0x00,0x00,0x04,0xa9,0x05,0x45,0x12,0x06,0x00,0x3b,0x00,0x00,0x00,0x01,0x00,0x31,0x00,0x00,0x04,0x9c, +0x05,0x45,0x00,0x23,0x00,0x69,0x40,0x3f,0x02,0x16,0x12,0x16,0x22,0x16,0x03,0x02,0x0d,0x12,0x0d,0x22,0x0d,0x03,0x0c,0x04,0x19,0x5c,0x40,0x1c,0x0e,0x23,0x07,0x00,0x0e,0x13,0x23,0x5c,0x00,0x0a,0x5c,0xaf,0x07,0x01,0x07,0x10,0x3f,0x00,0x01,0x7f,0x00,0x8f,0x00,0x02,0x10,0x00,0x01,0x00,0x00,0x24,0x25,0x13,0x10,0x60,0x22,0x01, +0x01,0x1a,0x11,0x08,0x03,0x00,0x12,0x00,0x3f,0x3f,0x33,0x33,0x39,0x2f,0x33,0xed,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0x5d,0x71,0x33,0xd4,0x5d,0xed,0x10,0xed,0x32,0x2b,0x01,0x18,0x10,0x4d,0xf4,0x1a,0xed,0x31,0x30,0x00,0x5f,0x5e,0x5d,0x5d,0x21,0x11,0x23,0x22,0x2e,0x02,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x3b,0x01,0x11,0x33, +0x11,0x33,0x32,0x3e,0x02,0x35,0x11,0x33,0x11,0x14,0x0e,0x02,0x2b,0x01,0x11,0x02,0x19,0x3a,0x72,0xa3,0x68,0x31,0xa1,0x1f,0x43,0x69,0x49,0x33,0x9b,0x33,0x49,0x68,0x43,0x20,0xa1,0x31,0x69,0xa2,0x72,0x3a,0x01,0x8d,0x54,0x8f,0xbc,0x68,0x01,0xb1,0xfe,0x4b,0x50,0x8b,0x66,0x3a,0x03,0x30,0xfc,0xd0,0x3a,0x66,0x8b,0x50,0x01,0xb5, +0xfe,0x4f,0x68,0xbc,0x8f,0x54,0xfe,0x73,0x00,0x01,0x00,0x3b,0x00,0x00,0x04,0x93,0x05,0x5a,0x00,0x39,0x00,0xda,0x40,0x78,0x79,0x15,0x89,0x15,0x02,0x76,0x25,0x86,0x25,0x02,0x6b,0x09,0x7b,0x09,0x8b,0x09,0x03,0x6b,0x31,0x7b,0x31,0x8b,0x31,0x03,0x66,0x25,0x76,0x25,0x86,0x25,0x03,0x66,0x15,0x76,0x15,0x86,0x15,0x03,0x46,0x38, +0x56,0x38,0x02,0x46,0x02,0x56,0x02,0x02,0x39,0x1b,0x01,0x39,0x1f,0x01,0x30,0x5c,0x28,0x0a,0x5c,0x12,0x20,0x12,0x30,0x12,0x50,0x12,0x60,0x12,0x70,0x12,0x05,0x4f,0x12,0x01,0xdf,0x28,0xef,0x28,0xff,0x28,0x03,0x00,0x28,0x10,0x28,0x20,0x28,0x03,0x70,0x28,0x80,0x28,0x02,0x28,0x12,0x28,0x12,0x35,0x18,0x10,0x10,0x05,0x5a,0x80, +0x18,0x90,0x18,0xd0,0x18,0xe0,0x18,0xf0,0x18,0x05,0x90,0x18,0xa0,0x18,0x02,0x18,0xb8,0xff,0xc0,0x40,0x23,0x09,0x0c,0x48,0x18,0x18,0x35,0x3b,0x2a,0x2a,0x22,0x5a,0x2f,0x35,0x3f,0x35,0x02,0x35,0x40,0x21,0x24,0x48,0x35,0x13,0x27,0x27,0x10,0x2a,0x5f,0x12,0x29,0x12,0x1d,0x5f,0x00,0x04,0x00,0x3f,0xed,0x3f,0x33,0xed,0x32,0x32, +0x2f,0x33,0x01,0x2f,0x2b,0x5d,0xed,0x33,0x2f,0x11,0x12,0x39,0x2f,0x2b,0x5d,0x71,0xed,0x32,0x2f,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x71,0x71,0x71,0x72,0x10,0xed,0x10,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x36,0x37,0x3e,0x01,0x3b,0x01,0x15, +0x21,0x35,0x3e,0x03,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x17,0x15,0x21,0x35,0x33,0x32,0x16,0x17,0x16,0x17,0x2e,0x03,0x35,0x34,0x3e,0x02,0x02,0x67,0x7c,0xc5,0x8a,0x49,0x2d,0x55,0x7e,0x51,0x20,0x1e,0x1a,0x36,0x13,0xc8,0xfe,0x1d,0x4b,0x66,0x3d,0x1a,0x27,0x53,0x7f,0x57,0x58,0x80,0x52,0x28,0x1a,0x3d, +0x66,0x4b,0xfe,0x1d,0xc8,0x13,0x36,0x1a,0x1e,0x20,0x51,0x7e,0x55,0x2d,0x49,0x8a,0xc5,0x05,0x5a,0x55,0x9d,0xdd,0x88,0x5f,0xb3,0xa0,0x8a,0x36,0x03,0x03,0x02,0x03,0x9c,0xe0,0x37,0x7d,0x88,0x90,0x4a,0x69,0xa8,0x77,0x40,0x40,0x77,0xa8,0x69,0x4a,0x90,0x88,0x7d,0x37,0xe0,0x9c,0x03,0x02,0x03,0x03,0x36,0x8a,0xa0,0xb3,0x5f,0x88, +0xdd,0x9d,0x55,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0x86,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x02,0x01,0x0b,0x00,0x17,0x40,0x0d,0x02,0x01,0x0c,0x05,0x26,0x02,0x01,0x02,0x10,0x0e,0x00,0x01,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x24,0x00,0x00,0x04,0xa8, +0x06,0x86,0x12,0x26,0x00,0x3c,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x12,0x01,0x0b,0x00,0x17,0x40,0x0d,0x02,0x01,0x09,0x05,0x26,0x02,0x01,0x11,0x0d,0x0b,0x04,0x08,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x81,0xff,0xec,0x04,0x90,0x05,0xf6,0x12,0x26,0x01,0x7e,0x00,0x00,0x11,0x06,0x01,0x54, +0x3c,0x00,0x00,0x13,0x40,0x0b,0x02,0x3c,0x11,0x26,0x02,0x18,0x3c,0x3f,0x08,0x17,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xaf,0xff,0xec,0x04,0x41,0x05,0xf6,0x12,0x26,0x01,0x82,0x00,0x00,0x11,0x06,0x01,0x54,0x50,0x00,0x00,0x13,0x40,0x0b,0x01,0x3a,0x11,0x26,0x01,0x3d,0x3a,0x3d,0x10,0x06,0x25,0x01,0x2b,0x35, +0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xb3,0xfe,0x57,0x04,0x19,0x05,0xf6,0x12,0x26,0x01,0x84,0x00,0x00,0x11,0x06,0x01,0x54,0x50,0x00,0x00,0x13,0x40,0x0b,0x01,0x26,0x11,0x26,0x01,0x4f,0x26,0x29,0x13,0x24,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x95,0xff,0xec,0x04,0x5d,0x05,0xf6,0x12,0x26,0x01,0x86,0x00,0x00, +0x11,0x06,0x01,0x54,0x1e,0x00,0x00,0x13,0x40,0x0b,0x01,0x14,0x11,0x26,0x01,0x0a,0x14,0x17,0x11,0x07,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa3,0xff,0xec,0x04,0x44,0x06,0x41,0x12,0x26,0x01,0x92,0x00,0x00,0x11,0x06,0x01,0x55,0xf1,0x00,0x00,0x19,0xb5,0x03,0x02,0x01,0x03,0x02,0x01,0xb8,0xff,0xe4,0xb4,0x2a, +0x28,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x35,0x00,0x35,0x35,0x35,0x00,0x00,0x00,0x00,0x02,0x00,0x81,0xff,0xec,0x04,0x90,0x04,0x4e,0x00,0x27,0x00,0x3b,0x00,0x96,0x40,0x6a,0x7a,0x25,0x8a,0x25,0x02,0x7a,0x34,0x8a,0x34,0x02,0x7a,0x30,0x8a,0x30,0x02,0x65,0x2a,0x01,0x4a,0x3a,0x5a,0x3a,0x6a,0x3a,0x03,0x25,0x0d,0x35,0x0d,0x02, +0x0b,0x06,0x1b,0x06,0x7b,0x06,0x8b,0x06,0x04,0x7b,0x22,0x8b,0x22,0x02,0x22,0x21,0x7b,0x16,0x8b,0x16,0x02,0x21,0x16,0x17,0x17,0x1c,0x49,0x10,0x00,0x60,0x32,0x70,0x32,0x02,0x90,0x32,0xa0,0x32,0xd0,0x32,0xe0,0x32,0x04,0x32,0x32,0x3d,0x28,0x47,0x00,0x08,0x01,0x08,0x22,0x15,0x16,0x0f,0x37,0x50,0x74,0x10,0x84,0x10,0x02,0x10, +0x0b,0x10,0x2d,0x50,0x7b,0x27,0x8b,0x27,0x02,0x27,0x05,0x16,0x00,0x3f,0x33,0x5d,0xed,0x3f,0x33,0x5d,0xed,0x3f,0x3f,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0x33,0x33,0xed,0x32,0x2f,0x33,0x33,0x5d,0x2f,0x33,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x5d,0x25,0x0e,0x03,0x23,0x22,0x02,0x11,0x10,0x12,0x33, +0x32,0x1e,0x02,0x17,0x33,0x3e,0x03,0x37,0x33,0x0e,0x03,0x07,0x1e,0x03,0x17,0x23,0x2e,0x03,0x27,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x2e,0x03,0x23,0x22,0x0e,0x02,0x03,0x76,0x19,0x42,0x57,0x6f,0x46,0xcd,0xc1,0xd9,0xd1,0x45,0x70,0x56,0x3f,0x14,0x02,0x04,0x0e,0x13,0x17,0x0d,0xbc,0x16,0x2e,0x27,0x1e,0x05,0x03,0x17, +0x1f,0x24,0x12,0xb7,0x0b,0x15,0x10,0x0d,0x03,0xfd,0xc4,0x1c,0x3b,0x5d,0x42,0x36,0x64,0x52,0x3d,0x0e,0x0c,0x2d,0x47,0x66,0x46,0x42,0x60,0x40,0x1f,0xed,0x38,0x5e,0x45,0x26,0x01,0x14,0x01,0x18,0x01,0x1c,0x01,0x1a,0x27,0x45,0x5d,0x36,0x15,0x38,0x3f,0x41,0x1e,0x2f,0x80,0x8b,0x8b,0x3a,0x67,0xaf,0x90,0x6e,0x27,0x1c,0x42,0x41, +0x3a,0x14,0x01,0x31,0x70,0xa0,0x67,0x30,0x34,0x6b,0xa0,0x6c,0x56,0x9a,0x73,0x44,0x2e,0x66,0xa3,0x00,0x00,0x02,0x00,0xac,0xfe,0x57,0x04,0x67,0x05,0xcc,0x00,0x20,0x00,0x40,0x00,0x8d,0xb7,0x6a,0x29,0x7a,0x29,0x8a,0x29,0x03,0x34,0xb8,0xff,0xe0,0x40,0x34,0x0d,0x11,0x48,0x45,0x1f,0x55,0x1f,0x65,0x1f,0x03,0x64,0x3f,0x74,0x3f, +0x84,0x3f,0x03,0x35,0x3f,0x45,0x3f,0x55,0x3f,0x03,0x0a,0x03,0x1a,0x03,0x02,0x05,0x14,0x15,0x14,0x02,0x1c,0x17,0x3c,0x3c,0x0d,0x17,0x48,0x21,0x21,0x0e,0x00,0x48,0x00,0x36,0x10,0x36,0x02,0x36,0xb8,0xff,0xc0,0x40,0x1d,0x10,0x13,0x48,0x36,0x36,0x42,0x2c,0x0d,0x46,0x00,0x0e,0x01,0x0e,0x1c,0x3b,0x50,0x3c,0x3c,0x12,0x31,0x50, +0x05,0x16,0x26,0x50,0x12,0x00,0x0d,0x1b,0x00,0x3f,0x3f,0xed,0x3f,0xed,0x11,0x39,0x2f,0xed,0x39,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x2b,0x5d,0xed,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0x12,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x2b,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x23,0x1e,0x01,0x15,0x11,0x23,0x11, +0x34,0x36,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x1e,0x03,0x01,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x35,0x3e,0x03,0x04,0x67,0x35,0x6f,0xad,0x78,0x66,0xa0,0x38,0x06,0x03,0x03,0xb4,0xe4,0xe2,0x63,0x98,0x66,0x35,0x23,0x3d,0x51,0x2e,0x39,0x72,0x5b,0x38, +0xfe,0xf4,0x1b,0x39,0x57,0x3c,0x46,0x68,0x44,0x22,0x1c,0x47,0x51,0x57,0x2b,0x48,0x6e,0x49,0x26,0x2e,0x61,0x99,0x6b,0x51,0x74,0x4b,0x23,0x01,0x95,0x58,0x9b,0x74,0x42,0x37,0x27,0x39,0x5c,0x35,0xfe,0xd7,0x05,0xac,0xed,0xdc,0x2f,0x5a,0x82,0x52,0x49,0x6f,0x52,0x38,0x12,0x0b,0x37,0x5d,0x89,0x02,0x7a,0x2c,0x4d,0x39,0x20,0x23, +0x4d,0x7a,0x58,0xfc,0xd0,0x13,0x22,0x19,0x0e,0x29,0x4c,0x6a,0x42,0x41,0x6e,0x51,0x2d,0x8e,0x06,0x2e,0x4b,0x64,0x00,0x00,0x00,0x01,0x00,0x35,0xfe,0x58,0x04,0x90,0x04,0x3a,0x00,0x18,0x00,0xb8,0x40,0x19,0x54,0x0b,0x01,0x45,0x0b,0x01,0x40,0x0e,0x50,0x0e,0x02,0x2f,0x0e,0x01,0x13,0x47,0x8a,0x17,0x01,0x17,0x18,0x0d,0x10,0x48, +0x0e,0xb8,0xff,0xf0,0x40,0x21,0x0c,0x11,0x48,0x17,0x0e,0x06,0x69,0x06,0x01,0x06,0x0d,0x14,0x14,0x18,0x0c,0x20,0x0d,0x11,0x48,0x28,0x0c,0x38,0x0c,0x02,0x03,0x0c,0x70,0x0d,0x80,0x0d,0x02,0x02,0x0d,0xb8,0xff,0xc0,0x40,0x3d,0x0a,0x0f,0x48,0x0d,0x0d,0x1a,0x82,0x00,0x01,0x73,0x00,0x01,0x64,0x00,0x01,0x53,0x00,0x01,0x44,0x00, +0x01,0x35,0x00,0x01,0x26,0x00,0x01,0x12,0x00,0x01,0x04,0x00,0x01,0x00,0x18,0x40,0x0b,0x13,0x48,0x18,0x76,0x06,0x86,0x06,0x02,0x3b,0x0e,0x4b,0x0e,0x5b,0x0e,0x03,0x0e,0x06,0x17,0x17,0x13,0x1b,0x0c,0x00,0x0f,0x00,0x3f,0x32,0x3f,0x39,0x2f,0x33,0x33,0x5d,0x5d,0x01,0x2f,0x2b,0x33,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, +0x11,0x33,0x2f,0x2b,0x5f,0x5d,0x33,0x5f,0x5d,0x2b,0x12,0x39,0x2f,0x12,0x39,0x5d,0x11,0x33,0x33,0x2b,0x2b,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x09,0x01,0x1e,0x03,0x17,0x3e,0x03,0x37,0x01,0x33,0x01,0x0e,0x03,0x07,0x23,0x3e,0x01,0x37,0x01,0x00,0xff,0x01,0x0f,0x0b,0x1d,0x1c,0x15,0x02,0x03,0x17,0x1e,0x1f,0x0c,0x00, +0xff,0xc5,0xfe,0x4b,0x11,0x1f,0x1b,0x16,0x08,0xbf,0x11,0x30,0x18,0xfe,0x29,0x04,0x3a,0xfd,0x6f,0x1b,0x4f,0x4d,0x3e,0x09,0x0b,0x40,0x4e,0x52,0x1d,0x02,0x87,0xfb,0xfb,0x2d,0x6f,0x7c,0x84,0x41,0x83,0xd5,0x5b,0x04,0x2f,0x00,0x00,0x02,0x00,0x70,0xff,0xec,0x04,0x55,0x05,0xcc,0x00,0x13,0x00,0x32,0x00,0xa3,0x40,0x1b,0x75,0x1b, +0x85,0x1b,0x02,0x69,0x08,0x01,0x6a,0x07,0x01,0x44,0x12,0x54,0x12,0x64,0x12,0x03,0x63,0x0c,0x01,0x44,0x0c,0x54,0x0c,0x02,0x1a,0xb8,0xff,0xe8,0x40,0x55,0x0b,0x11,0x48,0x32,0x32,0x1f,0x47,0x00,0x70,0x19,0x80,0x19,0x02,0x53,0x19,0x63,0x19,0x02,0x24,0x19,0x34,0x19,0x44,0x19,0x03,0x19,0x2e,0x05,0x00,0x2f,0x2f,0x29,0x70,0x00, +0x80,0x00,0x90,0x00,0x03,0x50,0x00,0xa0,0x00,0x02,0x00,0x00,0x10,0x00,0x60,0x00,0x70,0x00,0x80,0x00,0x05,0x00,0x00,0x34,0x0a,0x47,0x29,0x40,0x28,0x2d,0x48,0x29,0x40,0x18,0x1b,0x48,0x00,0x29,0x01,0x29,0x2f,0x32,0x50,0x2e,0x05,0x31,0x00,0x0f,0x50,0x24,0x16,0x00,0x3f,0xed,0x3f,0x39,0x39,0xed,0x32,0x01,0x2f,0x5d,0x2b,0x2b, +0xed,0x12,0x39,0x2f,0x5d,0x71,0x72,0x12,0x39,0x2f,0x12,0x39,0x39,0x33,0x5d,0x5d,0x5d,0x10,0xed,0x32,0x2f,0x31,0x30,0x00,0x2b,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x34,0x2e,0x02,0x27,0x0e,0x03,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x01,0x22,0x2e,0x02,0x27,0x01,0x1e,0x03,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34, +0x3e,0x02,0x37,0x01,0x35,0x21,0x15,0x03,0x98,0x36,0x4b,0x50,0x1a,0x49,0x8a,0x6c,0x41,0x28,0x4e,0x75,0x4c,0x51,0x75,0x4b,0x23,0xfe,0xf0,0x0d,0x29,0x2d,0x2a,0x0d,0x01,0x3c,0x37,0x6b,0x55,0x34,0x45,0x80,0xb8,0x74,0x72,0xb9,0x82,0x47,0x4e,0x84,0xae,0x60,0xfe,0xc1,0x02,0xec,0x01,0xd7,0x55,0x91,0x73,0x56,0x1b,0x1a,0x51,0x72, +0x92,0x5b,0x4c,0x83,0x60,0x37,0x36,0x5f,0x83,0x03,0xb4,0x02,0x03,0x02,0x01,0xfe,0xc7,0x36,0x74,0x86,0x9f,0x62,0x6e,0xb6,0x83,0x48,0x44,0x7f,0xb7,0x73,0x70,0xb0,0x87,0x61,0x21,0x01,0x48,0x82,0x8f,0x00,0x00,0x01,0x00,0xaf,0xff,0xec,0x04,0x41,0x04,0x4e,0x00,0x39,0x00,0x8a,0x40,0x58,0x73,0x12,0x83,0x12,0x02,0x7c,0x19,0x8c, +0x19,0x02,0x79,0x25,0x89,0x25,0x02,0x76,0x03,0x86,0x03,0x02,0x0a,0x0d,0x1a,0x0d,0x02,0x05,0x1e,0x15,0x1e,0x25,0x1e,0x03,0x2a,0x46,0x15,0x2f,0x20,0x2f,0x01,0x1b,0x2f,0x1b,0x2f,0x10,0x06,0x24,0x23,0x23,0x05,0x60,0x06,0x70,0x06,0x80,0x06,0x03,0x06,0x06,0x3b,0x37,0x47,0x00,0x10,0x01,0x10,0x15,0x30,0x50,0x2f,0x2f,0x00,0x27, +0x50,0x20,0x20,0x24,0x01,0x24,0x24,0x20,0x10,0x00,0x50,0x0b,0x05,0x05,0x0b,0x16,0x00,0x3f,0x33,0x2f,0x10,0xed,0x3f,0x33,0x2f,0x5d,0x10,0xed,0x12,0x39,0x2f,0xed,0x39,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x33,0x33,0x2f,0x33,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x12,0x39,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, +0x25,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x37,0x35,0x2e,0x03,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x15,0x14,0x1e,0x02,0x33,0x15,0x22,0x0e,0x04,0x15,0x14,0x16,0x02,0x6d,0x45,0x73,0x5b,0x43,0x15,0x69,0x20,0x59,0x75,0x95,0x5d,0x73,0xa4,0x69,0x32,0x2d, +0x4b,0x64,0x36,0x33,0x58,0x41,0x25,0x37,0x6c,0xa0,0x69,0x94,0xd3,0x43,0x80,0x2f,0x91,0x69,0x80,0x77,0x48,0x77,0x9a,0x53,0x35,0x6d,0x66,0x58,0x42,0x26,0x84,0x72,0x1f,0x30,0x39,0x19,0x64,0x27,0x47,0x35,0x20,0x2e,0x54,0x74,0x45,0x3a,0x5f,0x45,0x2a,0x05,0x02,0x06,0x28,0x40,0x56,0x33,0x3e,0x6a,0x4d,0x2c,0x56,0x63,0x58,0x47, +0x44,0x55,0x4a,0x39,0x46,0x25,0x0c,0x87,0x04,0x0e,0x1a,0x2d,0x41,0x2e,0x5b,0x5d,0x00,0x01,0x00,0xb8,0xfe,0x95,0x04,0x4e,0x05,0xcc,0x00,0x3a,0x00,0x7a,0x40,0x2a,0x79,0x38,0x01,0x69,0x37,0x01,0x6a,0x19,0x7a,0x19,0x8a,0x19,0x03,0x73,0x02,0x83,0x02,0x02,0x45,0x02,0x55,0x02,0x65,0x02,0x03,0x8c,0x2a,0x01,0x19,0x2a,0x01,0x2a, +0x34,0x34,0x0c,0x49,0x00,0x17,0x10,0x17,0x02,0x17,0xb8,0xff,0xc0,0x40,0x21,0x0f,0x13,0x48,0x17,0x17,0x23,0x3c,0x32,0x32,0x00,0x47,0x00,0x23,0x01,0x23,0x34,0x31,0x50,0x32,0x66,0x05,0x76,0x05,0x86,0x05,0x03,0x05,0x1c,0x1c,0x11,0x32,0x00,0x11,0xb8,0x01,0x09,0x00,0x3f,0x3f,0x12,0x39,0x2f,0x33,0x5d,0x10,0xfd,0xc4,0x01,0x2f, +0x5d,0xed,0x33,0x2f,0x11,0x12,0x39,0x2f,0x2b,0x5d,0xed,0x32,0x2f,0x33,0x5d,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x1e,0x02,0x17,0x1e,0x05,0x15,0x14,0x0e,0x02,0x07,0x27,0x3e,0x03,0x35,0x34,0x2e,0x02,0x27,0x2e,0x05,0x35,0x34,0x3e,0x04,0x37,0x35,0x0e,0x03,0x23,0x21,0x35,0x21,0x15,0x0e,0x05,0x01,0x77,0x41, +0x66,0x7e,0x3d,0x27,0x55,0x53,0x4b,0x39,0x22,0x12,0x1a,0x1d,0x0a,0x7e,0x09,0x13,0x10,0x0b,0x34,0x57,0x71,0x3d,0x2d,0x66,0x64,0x5c,0x46,0x2a,0x3c,0x67,0x89,0x9c,0xa5,0x4f,0x0c,0x23,0x2a,0x2d,0x17,0xfe,0x32,0x03,0x22,0x4d,0xa3,0x9a,0x88,0x67,0x3b,0x01,0x7b,0x40,0x4d,0x2f,0x1b,0x0f,0x09,0x16,0x1d,0x27,0x35,0x48,0x2e,0x22, +0x47,0x42,0x36,0x11,0x38,0x0c,0x21,0x26,0x27,0x13,0x22,0x31,0x25,0x1c,0x0c,0x09,0x19,0x24,0x35,0x4c,0x65,0x43,0x54,0xac,0xac,0xaa,0xa3,0x98,0x44,0x06,0x01,0x02,0x02,0x01,0x8e,0x8a,0x46,0x9b,0xa4,0xaa,0xa8,0xa4,0x00,0x00,0x00,0x01,0x00,0xb3,0xfe,0x57,0x04,0x19,0x04,0x4e,0x00,0x25,0x00,0x40,0x40,0x29,0x70,0x22,0x80,0x22, +0x02,0x04,0x21,0x14,0x21,0x24,0x21,0x74,0x21,0x84,0x21,0x05,0x25,0x46,0x00,0x00,0x27,0x19,0x0c,0x46,0x00,0x0d,0x80,0x0d,0x02,0x0d,0x19,0x06,0x50,0x1f,0x10,0x13,0x0f,0x0d,0x15,0x00,0x1b,0x00,0x3f,0x3f,0x3f,0x3f,0xed,0x33,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x01,0x11,0x34,0x2e,0x02,0x23, +0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x15,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x11,0x03,0x64,0x21,0x3b,0x50,0x30,0x3b,0x67,0x4d,0x2c,0xb4,0x01,0x02,0x02,0x01,0xaa,0x01,0x02,0x03,0x02,0x03,0x18,0x41,0x55,0x6a,0x42,0x53,0x80,0x57,0x2d,0xfe,0x57,0x04,0x60,0x50,0x67,0x3d,0x18,0x2d,0x55, +0x7d,0x51,0xfd,0x8d,0x03,0x53,0x22,0x4b,0x43,0x30,0x07,0x05,0x2c,0x39,0x3b,0x14,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfb,0x86,0x00,0x00,0x00,0x03,0x00,0x97,0xff,0xec,0x04,0x36,0x05,0xcb,0x00,0x0f,0x00,0x1a,0x00,0x25,0x00,0xb7,0xb6,0x6b,0x24,0x01,0x63,0x1d,0x01,0x18,0xb8,0xff,0xe8,0x40,0x6a,0x0e,0x11,0x48,0x13,0x18, +0x0e,0x11,0x48,0x5f,0x23,0x6f,0x23,0x02,0x4b,0x23,0x01,0x5f,0x1e,0x6f,0x1e,0x02,0x3b,0x1e,0x4b,0x1e,0x02,0x50,0x18,0x60,0x18,0x02,0x44,0x18,0x01,0x26,0x18,0x36,0x18,0x02,0x50,0x13,0x60,0x13,0x02,0x42,0x13,0x01,0x26,0x13,0x36,0x13,0x02,0x21,0x00,0x47,0x4f,0x15,0x5f,0x15,0x6f,0x15,0x9f,0x15,0xaf,0x15,0x05,0x3f,0x15,0x4f, +0x15,0x8f,0x15,0x9f,0x15,0x04,0xcf,0x15,0xdf,0x15,0xff,0x15,0x03,0x15,0x40,0x26,0x2a,0x48,0x15,0x15,0x27,0x20,0x16,0x47,0x90,0x08,0x01,0x00,0x08,0xc0,0x08,0xd0,0x08,0xe0,0x08,0x04,0x08,0xb8,0xff,0xc0,0x40,0x10,0x22,0x27,0x48,0x08,0x16,0x51,0x20,0x20,0x10,0x1b,0x51,0x0b,0x10,0x50,0x03,0x16,0x00,0x3f,0xed,0x2f,0xed,0x12, +0x39,0x2f,0xed,0x01,0x2f,0x2b,0x5d,0x72,0xed,0x32,0x12,0x39,0x2f,0x2b,0x5d,0x71,0x72,0xed,0x33,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x2b,0x2b,0x5d,0x5d,0x01,0x10,0x02,0x23,0x22,0x2e,0x01,0x02,0x35,0x10,0x12,0x33,0x32,0x1e,0x01,0x12,0x01,0x32,0x3e,0x02,0x37,0x21,0x1e,0x03,0x13,0x22,0x0e, +0x02,0x07,0x21,0x2e,0x03,0x04,0x36,0xf0,0xe4,0x6c,0xab,0x76,0x3e,0xe9,0xe8,0x79,0xaf,0x70,0x36,0xfe,0x2a,0x3e,0x64,0x49,0x2a,0x03,0xfd,0xdd,0x03,0x2c,0x47,0x5e,0x42,0x3d,0x64,0x48,0x2a,0x03,0x02,0x23,0x03,0x28,0x45,0x61,0x02,0xdd,0xfe,0x83,0xfe,0x8c,0x5c,0xba,0x01,0x1b,0xc0,0x01,0x76,0x01,0x78,0x5d,0xbc,0xfe,0xe7,0xfc, +0xd8,0x34,0x80,0xd8,0xa4,0xa3,0xd8,0x81,0x34,0x04,0xd9,0x33,0x7e,0xd4,0xa1,0xa1,0xd4,0x7e,0x33,0x00,0x00,0x01,0x00,0x95,0xff,0xec,0x04,0x5d,0x04,0x3a,0x00,0x13,0x00,0x58,0x40,0x3b,0x0c,0x18,0x09,0x0d,0x48,0x20,0x07,0x30,0x07,0x40,0x07,0xb0,0x07,0x04,0x07,0x07,0x00,0x46,0x0f,0x00,0x12,0x01,0x12,0x12,0x1f,0x0f,0x4f,0x0f, +0x5f,0x0f,0x6f,0x0f,0x04,0x0f,0x40,0x12,0x3c,0x48,0x0f,0x0f,0x14,0x15,0x11,0x50,0x12,0x0f,0x30,0x06,0x40,0x06,0x50,0x06,0x03,0x06,0x06,0x03,0x50,0x0a,0x16,0x00,0x3f,0xed,0x33,0x2f,0x5d,0x3f,0xed,0x11,0x12,0x01,0x39,0x2f,0x2b,0x5d,0x33,0x2f,0x5d,0x10,0xed,0x32,0x2f,0x5d,0x31,0x30,0x00,0x2b,0x01,0x14,0x16,0x33,0x32,0x36, +0x37,0x17,0x0e,0x01,0x23,0x22,0x2e,0x02,0x35,0x11,0x21,0x35,0x21,0x02,0x88,0x50,0x54,0x42,0x67,0x2a,0x5e,0x3a,0x95,0x63,0x5c,0x82,0x53,0x26,0xfe,0xc1,0x01,0xf3,0x01,0x5a,0x6f,0x65,0x3e,0x2c,0x78,0x40,0x4c,0x2e,0x5c,0x8a,0x5d,0x02,0x4f,0x8e,0xff,0xff,0x00,0xec,0x00,0x00,0x04,0x65,0x04,0x3a,0x12,0x06,0x00,0xf8,0x00,0x00, +0x00,0x01,0x00,0x72,0x00,0x00,0x04,0x52,0x05,0xcc,0x00,0x23,0x00,0xd4,0x40,0x7c,0x74,0x00,0x84,0x00,0x02,0x78,0x17,0x88,0x17,0x02,0x73,0x14,0x83,0x14,0x02,0x02,0x40,0x14,0x50,0x14,0x60,0x14,0x03,0x71,0x13,0x81,0x13,0x02,0x25,0x13,0x35,0x13,0x45,0x13,0x65,0x13,0x04,0x64,0x11,0x74,0x11,0x84,0x11,0x03,0x22,0x10,0x32,0x10, +0x42,0x10,0x03,0x6c,0x16,0x7c,0x16,0x8c,0x16,0x03,0x16,0x10,0x0b,0x0e,0x48,0x63,0x22,0x73,0x22,0x83,0x22,0x03,0x36,0x22,0x46,0x22,0x56,0x22,0x03,0x25,0x22,0x01,0x06,0x22,0x16,0x22,0x02,0x48,0x00,0x58,0x00,0x88,0x00,0x03,0x14,0x00,0x1c,0x46,0x1c,0x56,0x1c,0x02,0x1c,0x15,0x0a,0x0a,0x23,0x89,0x16,0x01,0x16,0x15,0x10,0x70, +0x15,0x80,0x15,0x02,0x0f,0x15,0x01,0x15,0x15,0x25,0x22,0x23,0xb8,0xff,0xf0,0x40,0x1a,0x00,0x23,0x10,0x23,0x02,0x23,0x5b,0x1c,0x01,0x1c,0x14,0x00,0x40,0x0f,0x12,0x48,0x00,0x00,0x0f,0x23,0x15,0x15,0x06,0x50,0x0f,0x00,0x00,0x3f,0xed,0x3f,0x33,0x12,0x39,0x2f,0x2b,0x33,0x33,0x5d,0x01,0x2f,0x5d,0x38,0x33,0x11,0x33,0x2f,0x5d, +0x5d,0x38,0x33,0x5d,0x12,0x39,0x2f,0x12,0x39,0x5d,0x11,0x33,0x33,0x5d,0x31,0x30,0x5d,0x5d,0x5d,0x5d,0x2b,0x5d,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5f,0x5d,0x01,0x5d,0x00,0x5d,0x01,0x27,0x2e,0x03,0x23,0x22,0x06,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x17,0x01,0x23,0x03,0x2e,0x03,0x27,0x0e,0x03,0x07,0x01,0x23,0x02,0x33,0x24, +0x1f,0x2d,0x2c,0x35,0x26,0x0f,0x31,0x11,0x23,0x11,0x29,0x2c,0x2a,0x11,0x3c,0x58,0x47,0x3f,0x24,0x01,0xab,0xbe,0xcf,0x08,0x12,0x12,0x10,0x05,0x07,0x16,0x19,0x18,0x08,0xfe,0xff,0xbb,0x03,0xc5,0x63,0x54,0x6c,0x3d,0x17,0x08,0x04,0x84,0x05,0x08,0x07,0x04,0x24,0x51,0x83,0x5f,0xfb,0x8b,0x02,0x41,0x16,0x39,0x3a,0x38,0x15,0x15, +0x3c,0x3d,0x38,0x12,0xfd,0xc1,0x00,0x00,0x00,0x01,0x00,0x9c,0xfe,0x57,0x04,0x7d,0x04,0x3a,0x00,0x27,0x00,0x6b,0x40,0x48,0x7a,0x25,0x8a,0x25,0x02,0x1b,0x1f,0x2b,0x1f,0x3b,0x1f,0x03,0x1f,0x0b,0x16,0x16,0x0e,0x46,0x0f,0x0b,0x1f,0x0b,0x02,0x0f,0x0b,0xaf,0x0b,0x02,0x4f,0x0b,0x5f,0x0b,0xbf,0x0b,0x03,0x0b,0x0b,0x29,0x03,0x27, +0x46,0x9f,0x00,0xaf,0x00,0x02,0x00,0x40,0x27,0x2d,0x48,0x00,0x40,0x1c,0x20,0x48,0x00,0x00,0x01,0x00,0x13,0x08,0x50,0x1f,0x1a,0x23,0x16,0x0c,0x01,0x0f,0x00,0x1b,0x00,0x3f,0x3f,0x33,0x3f,0x33,0x33,0xed,0x32,0x01,0x2f,0x5d,0x2b,0x2b,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0x71,0x72,0xed,0x32,0x2f,0x11,0x39,0x5d,0x31,0x30,0x00, +0x5d,0x13,0x11,0x33,0x11,0x14,0x1e,0x02,0x33,0x32,0x36,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x33,0x32,0x36,0x37,0x15,0x0e,0x01,0x23,0x22,0x2e,0x02,0x27,0x23,0x0e,0x01,0x23,0x22,0x26,0x27,0x11,0x9c,0xb5,0x20,0x3a,0x54,0x34,0x80,0x92,0xb4,0x0b,0x14,0x1d,0x12,0x0b,0x20,0x0b,0x1a,0x33,0x24,0x36,0x47,0x2c,0x14,0x02,0x03,0x34, +0x93,0x64,0x43,0x6d,0x1f,0xfe,0x57,0x05,0xe3,0xfd,0x52,0x4e,0x6a,0x41,0x1c,0xae,0xa2,0x02,0x73,0xfc,0xd0,0x2b,0x39,0x20,0x0d,0x05,0x03,0x81,0x08,0x0c,0x1e,0x34,0x47,0x29,0x5f,0x63,0x29,0x26,0xfe,0x1c,0x00,0x01,0x00,0x5c,0x00,0x00,0x04,0x36,0x04,0x3a,0x00,0x12,0x00,0x7e,0xb5,0x06,0x08,0x16,0x08,0x02,0x08,0xb8,0xff,0xf0, +0x40,0x47,0x0d,0x11,0x48,0x49,0x06,0x01,0x7a,0x02,0x01,0x37,0x09,0x01,0x10,0x46,0x0f,0x0f,0x0c,0x70,0x05,0x80,0x05,0x02,0x65,0x05,0x01,0x05,0x06,0x01,0x52,0x08,0x09,0x08,0x4b,0x07,0x06,0x14,0x07,0x06,0x08,0x07,0x0a,0x09,0x1a,0x09,0x6a,0x09,0x03,0x09,0x07,0x00,0x46,0x00,0x0c,0x10,0x0c,0x60,0x0c,0x03,0x0c,0x0c,0x14,0x1f, +0x07,0x01,0x07,0x0f,0x07,0x0f,0x09,0x06,0x15,0x00,0x3f,0x33,0x3f,0x33,0x01,0x2f,0x5d,0x12,0x39,0x2f,0x5d,0xed,0x11,0x39,0x5d,0x10,0x00,0xc1,0x87,0x05,0x2b,0x87,0x2b,0xc4,0x01,0x32,0x5d,0x5d,0x11,0x33,0x18,0x2f,0xed,0x5d,0x31,0x30,0x00,0x5d,0x01,0x5d,0x2b,0x5d,0x01,0x14,0x0e,0x02,0x07,0x23,0x01,0x33,0x01,0x36,0x12,0x35, +0x34,0x26,0x27,0x33,0x1e,0x01,0x04,0x36,0x42,0x70,0x93,0x51,0xaa,0xfe,0x66,0xbd,0x01,0x4b,0x95,0x89,0x1d,0x14,0xb1,0x18,0x1c,0x03,0x4e,0x66,0xdc,0xdb,0xd3,0x5e,0x04,0x3a,0xfc,0x60,0xb9,0x01,0x4f,0xa3,0x51,0x77,0x2d,0x2d,0x71,0x00,0x00,0x00,0x00,0x01,0x00,0xbf,0xfe,0x9a,0x04,0x23,0x05,0xcc,0x00,0x50,0x00,0xaa,0x40,0x60, +0x7a,0x2e,0x8a,0x2e,0x02,0x6a,0x09,0x7a,0x09,0x8a,0x09,0x03,0x4a,0x2c,0x5a,0x2c,0x02,0x45,0x25,0x55,0x25,0x02,0x74,0x32,0x84,0x32,0x02,0x46,0x32,0x56,0x32,0x66,0x32,0x03,0x05,0x37,0x15,0x37,0x02,0x0b,0x02,0x1b,0x02,0x02,0x0d,0x0d,0x1d,0x0d,0x2d,0x0d,0x03,0x05,0x28,0x23,0x46,0x0b,0x10,0x1c,0x1c,0x40,0x09,0x0c,0x48,0x28, +0x1c,0x1a,0x0b,0x0b,0x1a,0x1c,0x28,0x04,0x00,0x3a,0x49,0x60,0x45,0x70,0x45,0x80,0x45,0x03,0x45,0x45,0x52,0x30,0x47,0x00,0x00,0x01,0x00,0x05,0x29,0x51,0x28,0x35,0xb8,0x01,0x0a,0xb6,0x4a,0x28,0x4a,0x28,0x4a,0x1a,0x3f,0xb8,0x01,0x09,0xb4,0x1c,0x19,0x50,0x1a,0x00,0x00,0x3f,0xed,0x32,0x3f,0x12,0x39,0x39,0x2f,0x2f,0x10,0xed, +0x10,0xed,0x39,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0xed,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x2b,0x11,0x33,0x10,0xed,0x11,0x33,0x31,0x30,0x5d,0x5d,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x00,0x5d,0x13,0x34,0x3e,0x02,0x37,0x35,0x2e,0x03,0x35,0x34,0x3e,0x02,0x37,0x35,0x0e,0x05,0x2b,0x01,0x35,0x21,0x15,0x0e,0x05,0x15, +0x14,0x1e,0x02,0x17,0x15,0x0e,0x05,0x15,0x14,0x1e,0x02,0x17,0x1e,0x03,0x15,0x14,0x0e,0x02,0x07,0x27,0x3e,0x03,0x35,0x34,0x2e,0x02,0x27,0x2e,0x05,0xbf,0x3a,0x7c,0xc1,0x88,0x52,0x8a,0x63,0x37,0x30,0x53,0x6e,0x3e,0x08,0x29,0x37,0x3f,0x39,0x30,0x0c,0x5e,0x02,0xde,0x33,0x6f,0x6b,0x60,0x49,0x2b,0x4a,0x7a,0x9e,0x54,0x42,0x87, +0x7d,0x6d,0x51,0x2e,0x3e,0x62,0x7b,0x3d,0x3a,0x76,0x60,0x3d,0x12,0x1a,0x1d,0x0a,0x7e,0x09,0x13,0x10,0x0b,0x27,0x48,0x65,0x3d,0x2d,0x65,0x62,0x59,0x44,0x28,0x01,0x62,0x4c,0x93,0x7c,0x5a,0x13,0x02,0x05,0x27,0x44,0x60,0x3e,0x40,0x59,0x3d,0x24,0x0a,0x08,0x01,0x01,0x02,0x02,0x01,0x01,0x8e,0x88,0x06,0x11,0x1a,0x24,0x33,0x43, +0x2d,0x3f,0x51,0x31,0x18,0x06,0x83,0x08,0x1e,0x2c,0x3b,0x4c,0x5e,0x38,0x40,0x4f,0x32,0x1e,0x0f,0x0e,0x22,0x39,0x59,0x44,0x22,0x46,0x3f,0x35,0x11,0x38,0x0c,0x21,0x26,0x27,0x13,0x22,0x2f,0x23,0x1b,0x0c,0x09,0x19,0x24,0x34,0x4a,0x63,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x04,0x4e,0x12,0x06,0x00,0x52,0x00,0x00, +0x00,0x01,0x00,0x16,0xff,0xec,0x04,0xa2,0x04,0x3a,0x00,0x2e,0x00,0x67,0x40,0x41,0x6f,0x19,0x01,0x10,0x10,0x09,0x11,0x48,0x10,0x20,0x09,0x11,0x48,0x0a,0x0a,0x2d,0x2d,0x00,0x1a,0x47,0x1b,0x5f,0x26,0x01,0x26,0x1b,0x26,0x21,0x00,0x46,0x70,0x13,0x80,0x13,0x02,0x13,0x40,0x0b,0x0e,0x48,0x13,0x13,0x30,0x14,0x46,0x00,0x21,0x40, +0x21,0x50,0x21,0x03,0x21,0x14,0x00,0x21,0x50,0x2c,0x0f,0x1b,0x15,0x06,0x50,0x0d,0x16,0x00,0x3f,0xed,0x3f,0x3f,0xed,0x32,0x32,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x2b,0x5d,0xed,0x11,0x33,0x33,0x2f,0x5d,0x2f,0xed,0x11,0x33,0x2f,0x33,0x2f,0x31,0x30,0x2b,0x00,0x2b,0x5d,0x01,0x11,0x14,0x1e,0x02,0x33,0x32,0x36,0x37,0x17,0x0e, +0x01,0x23,0x22,0x2e,0x02,0x35,0x11,0x21,0x15,0x14,0x0e,0x02,0x07,0x23,0x3e,0x03,0x3d,0x01,0x22,0x0e,0x02,0x07,0x35,0x3e,0x03,0x33,0x21,0x15,0x03,0xd6,0x0d,0x18,0x23,0x16,0x0e,0x27,0x0d,0x14,0x1f,0x45,0x2b,0x3a,0x53,0x34,0x18,0xfe,0x8c,0x07,0x10,0x1a,0x13,0xbc,0x13,0x1e,0x14,0x0b,0x27,0x49,0x3d,0x2f,0x0c,0x0c,0x2b,0x33, +0x36,0x17,0x03,0xd5,0x03,0xac,0xfd,0x5e,0x2b,0x39,0x20,0x0d,0x05,0x03,0x81,0x08,0x0c,0x1c,0x3b,0x5e,0x42,0x02,0xc9,0x48,0x82,0xf9,0xdf,0xc0,0x4a,0x4c,0xc2,0xde,0xf3,0x7d,0x50,0x06,0x0b,0x0d,0x07,0x96,0x06,0x0b,0x08,0x04,0x8e,0x00,0x00,0x00,0x00,0x02,0x00,0x9d,0xfe,0x57,0x04,0x54,0x04,0x4f,0x00,0x1a,0x00,0x2f,0x00,0x7b, +0x40,0x2f,0x43,0x2e,0x53,0x2e,0x63,0x2e,0x03,0x4c,0x23,0x5c,0x23,0x6c,0x23,0x03,0x3c,0x08,0x4c,0x08,0x5c,0x08,0x03,0x1d,0x48,0x0f,0x49,0x3c,0x1d,0x4c,0x1d,0x5c,0x1d,0x03,0x00,0x47,0x50,0x1b,0xa0,0x1b,0x02,0x00,0x1b,0x10,0x1b,0x60,0x1b,0x03,0x1b,0xb8,0xff,0xc0,0x40,0x27,0x29,0x2c,0x48,0x1b,0x1b,0x31,0x26,0x0f,0x46,0x9f, +0x10,0xaf,0x10,0x02,0x10,0x40,0x27,0x2d,0x48,0x10,0x40,0x1c,0x20,0x48,0x00,0x10,0x01,0x10,0x20,0x50,0x16,0x10,0x0f,0x1b,0x2b,0x50,0x0a,0x05,0x16,0x00,0x3f,0x33,0xed,0x3f,0x3f,0xed,0x01,0x2f,0x5d,0x2b,0x2b,0x5d,0xed,0x32,0x12,0x39,0x2f,0x2b,0x5d,0x71,0xed,0x31,0x30,0x00,0x5d,0x2b,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23, +0x22,0x2e,0x02,0x27,0x23,0x1e,0x01,0x15,0x11,0x23,0x11,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x1e,0x03,0x33,0x32,0x3e,0x02,0x04,0x54,0x3f,0x73,0xa1,0x62,0x3d,0x63,0x50,0x41,0x1d,0x04,0x02,0x02,0xb4,0x3c,0x74,0xaa,0x6d,0x67,0xb5,0x86,0x4e,0xc1,0x2c,0x53,0x74,0x48,0x45,0x64, +0x40,0x1e,0x1d,0x47,0x50,0x57,0x2c,0x43,0x64,0x43,0x21,0x02,0x04,0x76,0xc5,0x8e,0x4f,0x14,0x25,0x35,0x21,0x1e,0x3d,0x20,0xfe,0x57,0x03,0xee,0x77,0xc1,0x88,0x4a,0x4f,0x96,0xda,0x84,0x68,0xa6,0x73,0x3d,0x35,0x65,0x92,0x5d,0xfe,0xc3,0x23,0x37,0x25,0x14,0x3a,0x6b,0x98,0x00,0x00,0x00,0x00,0x01,0x00,0xb0,0xfe,0x9c,0x04,0x28, +0x04,0x4e,0x00,0x37,0x00,0x82,0x40,0x57,0x83,0x0f,0x01,0x6c,0x1e,0x7c,0x1e,0x8c,0x1e,0x03,0x6a,0x24,0x01,0x6a,0x35,0x7a,0x35,0x8a,0x35,0x03,0x6a,0x35,0x7a,0x35,0x8a,0x35,0x03,0x43,0x09,0x53,0x09,0x02,0x2a,0x03,0x3a,0x03,0x6a,0x03,0x03,0x33,0x32,0x32,0x11,0x49,0x1c,0x40,0x15,0x18,0x48,0x60,0x1c,0x01,0x1c,0x1c,0x39,0x36, +0x07,0x76,0x07,0x86,0x07,0x03,0x07,0x47,0x00,0x26,0x01,0x26,0x65,0x0c,0x75,0x0c,0x85,0x0c,0x03,0x0c,0x21,0x21,0x2d,0x16,0x33,0x33,0x00,0x50,0x2d,0x10,0x16,0xb8,0x01,0x09,0x00,0x3f,0x3f,0xed,0x33,0x2f,0x11,0x12,0x39,0x2f,0x33,0x5d,0x01,0x2f,0x5d,0xed,0x5d,0x12,0x39,0x2f,0x5d,0x2b,0xed,0x32,0x2f,0x33,0x31,0x30,0x00,0x5d, +0x5d,0x5d,0x01,0x5d,0x00,0x5d,0x5d,0x5d,0x01,0x22,0x0e,0x04,0x15,0x14,0x1e,0x02,0x17,0x1e,0x03,0x15,0x14,0x0e,0x02,0x07,0x27,0x3e,0x03,0x35,0x34,0x2e,0x02,0x27,0x2e,0x03,0x35,0x34,0x3e,0x04,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x02,0xb0,0x3d,0x60,0x47,0x31,0x1f,0x0d,0x29,0x57,0x85,0x5d,0x39,0x79,0x64,0x41,0x12,0x1a, +0x1d,0x0a,0x7e,0x09,0x13,0x10,0x0b,0x27,0x49,0x69,0x42,0x67,0xa6,0x76,0x40,0x15,0x31,0x4e,0x72,0x98,0x62,0x45,0x6f,0x59,0x43,0x18,0x71,0x16,0x34,0x3d,0x47,0x03,0xc1,0x2d,0x4c,0x64,0x6e,0x71,0x34,0x44,0x5f,0x46,0x37,0x1c,0x11,0x26,0x3c,0x5a,0x44,0x22,0x44,0x3e,0x33,0x11,0x38,0x0c,0x21,0x26,0x27,0x13,0x1e,0x2d,0x25,0x20, +0x11,0x1a,0x40,0x64,0x98,0x72,0x3b,0x8e,0x8f,0x86,0x68,0x3e,0x1a,0x2b,0x36,0x1d,0x72,0x18,0x2d,0x23,0x15,0x00,0x00,0x00,0x00,0x02,0x00,0x5c,0xff,0xec,0x04,0xcd,0x04,0x3a,0x00,0x1c,0x00,0x2f,0x00,0x81,0x40,0x5c,0x44,0x2e,0x54,0x2e,0x64,0x2e,0x03,0x63,0x29,0x01,0x44,0x29,0x54,0x29,0x02,0x6d,0x26,0x01,0x4b,0x26,0x5b,0x26, +0x02,0x2a,0x26,0x3a,0x26,0x02,0x22,0x17,0x0a,0xc0,0x10,0xd0,0x10,0xf0,0x10,0x03,0x10,0x10,0x00,0x47,0xcf,0x1d,0xdf,0x1d,0xff,0x1d,0x03,0x1d,0x40,0x28,0x35,0x48,0x00,0x1d,0x10,0x1d,0x60,0x1d,0x03,0x1d,0x1d,0x31,0x67,0x0a,0x01,0x28,0x47,0x1f,0x0a,0x01,0x0a,0x40,0x28,0x35,0x48,0x0a,0x40,0x18,0x21,0x48,0x0a,0x11,0x23,0x50, +0x0f,0x0f,0x2b,0x50,0x05,0x16,0x00,0x3f,0xed,0x3f,0xed,0x32,0x01,0x2f,0x2b,0x2b,0x5d,0xed,0x5d,0x12,0x39,0x2f,0x5d,0x2b,0x5d,0xed,0x32,0x2f,0x5d,0x11,0x39,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x21,0x15,0x23,0x22,0x2e,0x02,0x27,0x15,0x1e,0x03, +0x07,0x34,0x2e,0x02,0x27,0x23,0x22,0x0e,0x02,0x15,0x14,0x16,0x33,0x32,0x3e,0x02,0x04,0x36,0x3d,0x7b,0xb7,0x7b,0x7b,0xba,0x7c,0x3f,0x56,0x99,0xd5,0x7e,0x02,0x2f,0x9b,0x09,0x23,0x2b,0x2c,0x11,0x1c,0x37,0x2b,0x1a,0xbd,0x14,0x22,0x2d,0x19,0x59,0x52,0x90,0x6b,0x3d,0x97,0x93,0x4e,0x75,0x4c,0x26,0x01,0xeb,0x70,0xbc,0x87,0x4c, +0x4a,0x8b,0xca,0x81,0x90,0xd2,0x8a,0x42,0x8e,0x01,0x02,0x02,0x01,0x04,0x2a,0x60,0x6f,0x7f,0x4e,0x4a,0x81,0x6f,0x60,0x2a,0x2f,0x64,0x9d,0x6e,0xcf,0xce,0x34,0x61,0x8b,0x00,0x00,0x00,0x00,0x01,0x00,0x95,0xff,0xec,0x04,0x1c,0x04,0x3a,0x00,0x25,0x00,0x4d,0x40,0x2f,0x0a,0x22,0x1a,0x22,0x2a,0x22,0x03,0x21,0x18,0x09,0x0f,0x48, +0x19,0x19,0x9f,0x0c,0xaf,0x0c,0x02,0x0c,0x0c,0x0f,0x46,0x24,0x0f,0x05,0x1f,0x05,0x02,0x05,0x05,0x00,0x24,0x01,0x24,0x24,0x26,0x27,0x14,0x50,0x1f,0x16,0x0e,0x00,0x50,0x0b,0x0f,0x00,0x3f,0xed,0x32,0x3f,0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0x33,0x2f,0x5d,0x10,0xed,0x32,0x2f,0x5d,0x39,0x7c,0x2f,0x31,0x30,0x00,0x2b,0x5d,0x01, +0x22,0x0e,0x02,0x07,0x35,0x3e,0x03,0x33,0x21,0x15,0x21,0x11,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x15,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x11,0x01,0x91,0x27,0x4f,0x45,0x35,0x0c,0x0c,0x2b,0x33,0x36,0x17,0x02,0xd0,0xfe,0x8a,0x16,0x24,0x2c,0x16,0x07,0x27,0x2b,0x27,0x08,0x0f,0x30,0x36,0x37,0x15,0x3a,0x5c,0x40,0x21,0x03, +0xac,0x06,0x0b,0x0d,0x07,0x96,0x06,0x0b,0x08,0x04,0x8e,0xfd,0x54,0x2b,0x36,0x1c,0x0a,0x02,0x03,0x04,0x01,0x83,0x04,0x07,0x06,0x03,0x19,0x3a,0x5e,0x46,0x02,0xc9,0x00,0x01,0x00,0xa3,0xff,0xec,0x04,0x44,0x04,0x3a,0x00,0x1f,0x00,0x45,0x40,0x2b,0x64,0x0e,0x01,0x44,0x13,0x54,0x13,0x02,0x0a,0x07,0x1a,0x07,0x02,0x1b,0x47,0x00, +0x1a,0x01,0x1a,0x1a,0x00,0x47,0x15,0x15,0x21,0x0d,0x46,0x00,0x0a,0x01,0x0a,0x1a,0x0b,0x0f,0x79,0x05,0x89,0x05,0x02,0x10,0x50,0x05,0x16,0x00,0x3f,0xed,0x5d,0x3f,0x33,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0xed,0x33,0x2f,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x11,0x33,0x11,0x14, +0x16,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x27,0x33,0x1e,0x03,0x04,0x44,0x3b,0x79,0xb6,0x7b,0x6d,0xa6,0x70,0x39,0xb5,0x89,0x86,0x4a,0x6d,0x49,0x24,0x14,0x21,0x28,0x15,0xbc,0x12,0x28,0x20,0x15,0x02,0x3b,0x88,0xdb,0x9a,0x52,0x32,0x6b,0xa6,0x74,0x02,0x97,0xfd,0x63,0x92,0x94,0x32,0x6c,0xaa,0x78,0x44,0x93,0x8b,0x79,0x28, +0x28,0x71,0x86,0x95,0x00,0x02,0x00,0x32,0xfe,0x57,0x04,0x99,0x04,0x52,0x00,0x25,0x00,0x30,0x00,0x93,0xb5,0x75,0x23,0x85,0x23,0x02,0x26,0xb8,0xff,0x98,0xb2,0x0f,0x49,0x26,0xb8,0xff,0xc8,0xb3,0x0b,0x0e,0x48,0x19,0xb8,0xff,0xd8,0x40,0x15,0x0b,0x0f,0x48,0x16,0x38,0x0b,0x11,0x48,0x6a,0x15,0x7a,0x15,0x8a,0x15,0x03,0x05,0x1f, +0x15,0x1f,0x02,0x13,0xb8,0xff,0xc0,0x40,0x36,0x09,0x11,0x48,0x13,0x13,0x0d,0x2f,0x06,0x49,0x1b,0x07,0x07,0x0d,0x00,0x48,0x10,0x26,0xe0,0x26,0x02,0x26,0x26,0x32,0x66,0x0d,0x01,0x18,0x48,0x4f,0x0d,0x5f,0x0d,0x6f,0x0d,0x9f,0x0d,0xaf,0x0d,0x05,0x0d,0x2f,0x1b,0x51,0x05,0x08,0x15,0x13,0x2b,0x51,0x12,0x21,0x10,0x06,0x1b,0x00, +0x3f,0x3f,0x33,0xed,0x32,0x3f,0x33,0xed,0x32,0x01,0x2f,0x5d,0xed,0x5d,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x12,0x39,0x2f,0x2b,0x31,0x30,0x00,0x5d,0x5d,0x2b,0x2b,0x2b,0x2b,0x5d,0x01,0x14,0x0e,0x02,0x07,0x11,0x23,0x11,0x2e,0x03,0x35,0x34,0x3e,0x02,0x37,0x17,0x0e,0x03,0x15,0x14,0x16,0x17,0x11,0x34,0x3e, +0x02,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x06,0x15,0x11,0x24,0x04,0x99,0x49,0x83,0xb3,0x6b,0xa0,0x6e,0xb1,0x7c,0x42,0x30,0x63,0x99,0x69,0x15,0x42,0x60,0x40,0x1f,0x9d,0x97,0x28,0x4d,0x73,0x4b,0x51,0x7f,0x58,0x2f,0xa9,0x18,0x2c,0x40,0x28,0x4b,0x4a,0x01,0x41,0x02,0x35,0x97,0xd7,0x8c,0x47,0x06,0xfe,0x69,0x01, +0x97,0x05,0x48,0x8a,0xcf,0x8d,0x66,0xbc,0x96,0x67,0x12,0x88,0x0f,0x4d,0x72,0x8f,0x50,0xd5,0xd3,0x08,0x02,0x44,0x60,0x9a,0x6c,0x39,0x4c,0x8d,0xc7,0x79,0x60,0x9a,0x6b,0x39,0x94,0x8d,0xfd,0xb9,0x0d,0x00,0x00,0x01,0x00,0x3a,0xfe,0x58,0x04,0x8e,0x04,0x50,0x00,0x18,0x00,0xe2,0x40,0x37,0x36,0x18,0x01,0x06,0x10,0x16,0x10,0x02, +0x64,0x0f,0x74,0x0f,0x84,0x0f,0x03,0x05,0x0f,0x15,0x0f,0x45,0x0f,0x55,0x0f,0x04,0x45,0x16,0x65,0x16,0x75,0x16,0x85,0x16,0x04,0x06,0x16,0x16,0x16,0x36,0x16,0x03,0x36,0x16,0x01,0x09,0x16,0x19,0x16,0x02,0x14,0x47,0x15,0x10,0x15,0x15,0x03,0xb8,0xff,0xe0,0x40,0x2a,0x12,0x16,0x48,0x26,0x03,0x76,0x03,0x86,0x03,0x03,0x66,0x00, +0x01,0x65,0x13,0x75,0x13,0x85,0x13,0x03,0x27,0x13,0x01,0x03,0x16,0x13,0x00,0x03,0x04,0x0a,0x18,0x47,0x17,0x10,0x84,0x17,0x01,0x70,0x17,0x01,0x02,0x17,0xb8,0xff,0xc0,0x40,0x09,0x0a,0x0f,0x48,0x17,0x17,0x1a,0x01,0x47,0x02,0xb8,0xff,0xf0,0x40,0x2e,0x02,0x02,0x0a,0x40,0x0b,0x11,0x48,0x0a,0x14,0x0f,0x24,0x13,0x74,0x13,0x84, +0x13,0x03,0x7f,0x00,0x8f,0x00,0x02,0x4b,0x00,0x5b,0x00,0x02,0x39,0x00,0x01,0x2d,0x00,0x01,0x00,0x16,0x03,0x13,0x04,0x01,0x07,0x50,0x0d,0x10,0x18,0x01,0x1b,0x00,0x3f,0x33,0x3f,0xed,0x12,0x17,0x39,0x5d,0x5d,0x5d,0x5d,0x5d,0x3f,0x01,0x2f,0x2b,0x33,0x2f,0x38,0xed,0x11,0x33,0x2f,0x2b,0x5f,0x5d,0x5d,0x38,0xed,0x12,0x17,0x39, +0x5f,0x5d,0x5d,0x5d,0x5d,0x2b,0x33,0x2f,0x38,0xed,0x31,0x30,0x00,0x5d,0x5d,0x01,0x5d,0x5d,0x00,0x5d,0x5d,0x5d,0x01,0x5d,0x25,0x01,0x23,0x01,0x03,0x2e,0x01,0x23,0x22,0x07,0x27,0x3e,0x01,0x33,0x32,0x1e,0x02,0x17,0x13,0x01,0x33,0x09,0x01,0x23,0x02,0x73,0xfe,0x95,0xbc,0x01,0xd6,0xbe,0x3b,0x5e,0x33,0x1f,0x1d,0x22,0x18,0x48, +0x20,0x30,0x4b,0x44,0x44,0x28,0xa2,0x01,0x26,0xbb,0xfe,0x72,0x01,0xb4,0xbe,0xef,0xfd,0x69,0x03,0x39,0x01,0x57,0x6b,0x70,0x0f,0x83,0x0b,0x0e,0x1c,0x3f,0x65,0x4a,0xfe,0xd9,0x02,0x1b,0xfd,0x47,0xfc,0xd7,0x00,0x01,0x00,0x58,0xfe,0x57,0x04,0x71,0x05,0x3c,0x00,0x1f,0x00,0x88,0x40,0x5f,0x7d,0x12,0x8d,0x12,0x02,0x7d,0x0b,0x8d, +0x0b,0x02,0x0a,0x12,0x1a,0x12,0x02,0x0a,0x0b,0x1a,0x0b,0x02,0x00,0x0e,0x49,0x1d,0x0f,0x0f,0x15,0x08,0x49,0x7f,0x05,0x8f,0x05,0x02,0x20,0x05,0x30,0x05,0x02,0xf0,0x05,0x01,0xcf,0x05,0xdf,0x05,0x02,0xb0,0x05,0x01,0x05,0x40,0x0b,0x0e,0x48,0x10,0x05,0x01,0x05,0x05,0x21,0x18,0x49,0x0f,0x15,0x5f,0x15,0x8f,0x15,0x9f,0x15,0xaf, +0x15,0x05,0x30,0x15,0x70,0x15,0x80,0x15,0x03,0x15,0x1e,0x1e,0x06,0x16,0x0f,0x0d,0x00,0x1d,0x50,0x10,0x16,0x0e,0x1b,0x00,0x3f,0x3f,0xed,0x32,0x33,0x3f,0x33,0x33,0x2f,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x2b,0x5d,0x5d,0x71,0x72,0x72,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x25,0x3e, +0x03,0x35,0x11,0x33,0x11,0x14,0x0e,0x02,0x07,0x11,0x23,0x11,0x2e,0x03,0x35,0x11,0x33,0x11,0x14,0x1e,0x02,0x17,0x11,0x33,0x02,0xb4,0x4c,0x6c,0x45,0x21,0x9f,0x32,0x6b,0xa9,0x77,0xa0,0x76,0xa9,0x6b,0x32,0xa1,0x20,0x44,0x6c,0x4b,0xa0,0x72,0x01,0x20,0x4b,0x7b,0x5b,0x02,0x86,0xfd,0x7c,0x7a,0xac,0x6e,0x35,0x01,0xfe,0x6b,0x01, +0x95,0x01,0x35,0x6e,0xac,0x7a,0x02,0x84,0xfd,0x7a,0x5a,0x7a,0x4b,0x21,0x02,0x04,0xca,0x00,0x00,0x00,0x00,0x01,0x00,0x35,0xff,0xec,0x04,0x99,0x04,0x4f,0x00,0x41,0x00,0x9f,0x40,0x71,0x0a,0x18,0x1a,0x18,0x02,0x0a,0x27,0x1a,0x27,0x02,0x0f,0x0f,0x0a,0x00,0x30,0x30,0x2a,0x1f,0x00,0x49,0x3f,0x3f,0x2a,0x15,0x48,0x2f,0x0a,0x3f, +0x0a,0x4f,0x0a,0x6f,0x0a,0x7f,0x0a,0x8f,0x0a,0x06,0x0f,0x0a,0xbf,0x0a,0xcf,0x0a,0x03,0x0a,0x40,0x1f,0x22,0x48,0x10,0x0a,0xb0,0x0a,0xe0,0x0a,0xf0,0x0a,0x04,0x0a,0x0a,0x43,0x35,0x48,0x40,0x2a,0x60,0x2a,0x70,0x2a,0xd0,0x2a,0xe0,0x2a,0x05,0x3f,0x2a,0x01,0x4f,0x2a,0x5f,0x2a,0x6f,0x2a,0x9f,0x2a,0xaf,0x2a,0x05,0x2a,0x40,0x40, +0x10,0x70,0x1f,0x80,0x1f,0x02,0x1f,0x1a,0x05,0x76,0x3a,0x86,0x3a,0x02,0x3a,0x50,0x25,0x16,0x2f,0x10,0x10,0x00,0x3f,0x33,0x3f,0xed,0x5d,0x32,0x33,0x33,0x5d,0x11,0x39,0x2f,0x01,0x2f,0x5d,0x71,0x71,0xed,0x12,0x39,0x2f,0x5d,0x2b,0x71,0x72,0xed,0x12,0x39,0x2f,0xed,0x39,0x12,0x39,0x2f,0x11,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d, +0x5d,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x27,0x37,0x1e,0x03,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x23,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x37,0x17,0x0e,0x03,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x3d,0x01,0x33,0x02,0xb7,0x18,0x2c,0x3c,0x25,0x25,0x37,0x24,0x12,0x15,0x2f, +0x4c,0x38,0x1f,0x57,0x80,0x54,0x29,0x2c,0x4f,0x70,0x45,0x32,0x54,0x40,0x2e,0x0c,0x04,0x0c,0x2e,0x40,0x54,0x32,0x45,0x70,0x4f,0x2c,0x29,0x54,0x80,0x57,0x1f,0x38,0x4d,0x2f,0x14,0x12,0x24,0x37,0x25,0x29,0x3e,0x2a,0x15,0x9f,0x01,0xc1,0x4d,0x7d,0x57,0x2f,0x39,0x69,0x93,0x5a,0x52,0x98,0x7b,0x55,0x0f,0x86,0x12,0x70,0xa1,0xc2, +0x65,0x80,0xc8,0x89,0x48,0x26,0x47,0x62,0x3c,0x3c,0x62,0x47,0x26,0x48,0x89,0xc8,0x80,0x65,0xc2,0xa1,0x70,0x12,0x86,0x0f,0x55,0x7b,0x98,0x52,0x5a,0x93,0x69,0x39,0x36,0x5b,0x7a,0x45,0xfc,0x00,0x00,0x00,0xff,0xff,0x00,0x95,0xff,0xec,0x04,0x5d,0x05,0x7b,0x12,0x26,0x01,0x86,0x00,0x00,0x11,0x06,0x00,0x69,0xe4,0x00,0x00,0x19, +0xb6,0x02,0x01,0x14,0x11,0x26,0x02,0x01,0xb8,0xff,0xd1,0xb4,0x18,0x16,0x11,0x07,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xa3,0xff,0xec,0x04,0x44,0x05,0x7b,0x12,0x26,0x01,0x92,0x00,0x00,0x11,0x06,0x00,0x69,0xe4,0x00,0x00,0x19,0xb6,0x02,0x01,0x20,0x11,0x26,0x02,0x01,0xb8,0xff,0xd6,0xb4, +0x24,0x22,0x0a,0x00,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x05,0xf6,0x12,0x26,0x00,0x52,0x00,0x00,0x11,0x06,0x01,0x54,0x3c,0x00,0x00,0x13,0x40,0x0b,0x02,0x24,0x11,0x26,0x02,0x3b,0x24,0x27,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa3, +0xff,0xec,0x04,0x44,0x05,0xf6,0x12,0x26,0x01,0x92,0x00,0x00,0x11,0x06,0x01,0x54,0x14,0x00,0x00,0x13,0x40,0x0b,0x01,0x20,0x11,0x26,0x01,0x05,0x20,0x23,0x0a,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x35,0xff,0xec,0x04,0x99,0x05,0xf6,0x12,0x26,0x01,0x96,0x00,0x00,0x11,0x06,0x01,0x54,0x2d,0x00,0x00,0x13, +0x40,0x0b,0x01,0x42,0x11,0x26,0x01,0x2b,0x42,0x45,0x2a,0x15,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0xa8,0x10,0x06,0x00,0x88,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x06,0x5d,0x12,0x26,0x00,0x28,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x14,0x00,0xe2,0x00,0x19,0xb6,0x02, +0x01,0x0c,0x05,0x26,0x02,0x01,0xb8,0xff,0xf8,0xb4,0x10,0x0e,0x00,0x0a,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x01,0x00,0x00,0xff,0xec,0x04,0x8a,0x05,0x45,0x00,0x2b,0x00,0x68,0xb5,0x2a,0x28,0x09,0x0c,0x48,0x23,0xb8,0xff,0xe8,0x40,0x36,0x09,0x0c,0x48,0x06,0x05,0x1a,0x05,0x1a,0x0c,0x1c,0x14,0x5a,0x15,0x15, +0x17,0x27,0x5a,0x10,0x0c,0x20,0x0c,0x90,0x0c,0xa0,0x0c,0x04,0x0c,0x0c,0x2d,0x17,0x10,0x5f,0x30,0x21,0xe0,0x21,0x02,0x21,0x21,0x09,0x1b,0x17,0x5f,0x18,0x03,0x15,0x12,0x09,0x5f,0x00,0x06,0x06,0x00,0x13,0x00,0x3f,0x32,0x2f,0x10,0xed,0x3f,0x3f,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x01,0x2f,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39, +0x2f,0xed,0x32,0x11,0x39,0x39,0x2f,0x2f,0x33,0x31,0x30,0x00,0x2b,0x2b,0x05,0x22,0x2e,0x02,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x3d,0x01,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x21,0x35,0x21,0x15,0x21,0x11,0x3e,0x03,0x33,0x32,0x1e,0x02,0x1d,0x01,0x14,0x0e,0x02,0x03,0x65,0x26,0x48,0x3f,0x33,0x11,0x65,0x1d,0x41,0x2d, +0x2c,0x3c,0x50,0x60,0x4d,0xa4,0x47,0xbe,0xfe,0xda,0x03,0x37,0xfe,0xad,0x24,0x4e,0x52,0x53,0x29,0x60,0x87,0x57,0x28,0x25,0x49,0x6e,0x14,0x14,0x26,0x34,0x20,0x72,0x33,0x33,0x66,0x6e,0xc7,0x7a,0x6d,0x20,0x12,0xfd,0x2a,0x04,0xa9,0x9c,0x9c,0xfe,0xbe,0x0a,0x15,0x11,0x0b,0x2f,0x5c,0x89,0x59,0xe0,0x51,0x86,0x5e,0x34,0x00,0x00, +0xff,0xff,0x00,0xe0,0x00,0x00,0x04,0x5b,0x06,0xa9,0x12,0x26,0x01,0x61,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x78,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x06,0x05,0x26,0x01,0x40,0x06,0x09,0x01,0x03,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0x00,0x01,0x00,0x71,0xff,0xec,0x04,0x76,0x05,0x5a,0x00,0x2c,0x00,0xb5,0x40,0x23, +0x46,0x1d,0x56,0x1d,0x66,0x1d,0x03,0x84,0x08,0x01,0x35,0x03,0x01,0x7b,0x20,0x8b,0x20,0x02,0x20,0x1f,0x0f,0x2b,0x01,0x2b,0x1f,0x2b,0x1f,0x15,0x7b,0x0a,0x8b,0x0a,0x02,0x0a,0x0b,0xb8,0xff,0xc0,0x40,0x5a,0x09,0x0c,0x48,0x0b,0x0b,0x2e,0x2a,0x77,0x00,0x87,0x00,0x02,0x00,0x5b,0x00,0x15,0x10,0x15,0x02,0x15,0x00,0x60,0x0f,0x2a, +0x3f,0x2a,0x02,0x6f,0x2a,0x8f,0x2a,0x9f,0x2a,0xbf,0x2a,0xdf,0x2a,0x05,0x6f,0x2a,0x01,0x2a,0x2a,0x05,0x46,0x1a,0x56,0x1a,0x66,0x1a,0x03,0x25,0x5f,0x1a,0x20,0x20,0x1a,0x04,0x49,0x10,0x59,0x10,0x02,0x05,0x5f,0x10,0x10,0x0a,0x20,0x0a,0x30,0x0a,0x60,0x0a,0x70,0x0a,0x05,0x30,0x0a,0x80,0x0a,0xd0,0x0a,0xe0,0x0a,0x04,0x0a,0x0a, +0x10,0x13,0x00,0x3f,0x33,0x2f,0x5d,0x71,0x10,0xed,0x5d,0x3f,0x33,0x2f,0x10,0xed,0x5d,0x12,0x39,0x2f,0x5d,0x71,0x72,0xed,0x01,0x2f,0x5d,0xed,0x5d,0x32,0x12,0x39,0x2f,0x2b,0x33,0x5d,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x11,0x33,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22, +0x2e,0x01,0x02,0x35,0x34,0x12,0x3e,0x01,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x23,0x22,0x0e,0x02,0x07,0x21,0x15,0x01,0x3b,0x05,0x2e,0x54,0x7e,0x55,0x3f,0x65,0x4f,0x3a,0x15,0x9f,0x1c,0x52,0x74,0x9b,0x66,0x8d,0xcd,0x87,0x41,0x40,0x84,0xca,0x8a,0x65,0x98,0x6f,0x4d,0x19,0xa8,0x0f,0x34,0x49,0x61,0x3c,0x52,0x7a,0x52,0x2c, +0x05,0x01,0xab,0x02,0x61,0x72,0xb1,0x78,0x3f,0x30,0x4e,0x66,0x36,0x41,0x46,0x85,0x69,0x40,0x65,0xb8,0x01,0x02,0x9e,0xa6,0x01,0x01,0xaf,0x5b,0x37,0x5d,0x79,0x42,0x41,0x2e,0x58,0x44,0x2a,0x3b,0x74,0xac,0x71,0x91,0x00,0x00,0xff,0xff,0x00,0x4f,0xff,0xec,0x04,0x68,0x05,0x5a,0x12,0x06,0x00,0x36,0x00,0x00,0xff,0xff,0x00,0xca, +0x00,0x00,0x04,0x01,0x05,0x45,0x12,0x06,0x00,0x2c,0x00,0x00,0xff,0xff,0x00,0xca,0x00,0x00,0x04,0x01,0x06,0x5d,0x12,0x26,0x00,0x2c,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x01,0x00,0xe2,0x00,0x17,0x40,0x0d,0x02,0x01,0x0c,0x05,0x26,0x02,0x01,0x01,0x10,0x0e,0x00,0x01,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0xb0,0xff,0xec,0x03,0xda,0x05,0x45,0x12,0x06,0x00,0x2d,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xf0,0x04,0xb1,0x05,0x45,0x00,0x26,0x00,0x33,0x00,0x5d,0x40,0x1d,0x08,0x1f,0x21,0x2e,0x5c,0x06,0x00,0x06,0x01,0x00,0x1f,0x01,0x00,0x1f,0x40,0x1f,0x50,0x1f,0x60,0x1f,0x04,0x1f,0x06,0x1f,0x06,0x13,0x00,0x5c,0x27,0xb8, +0xff,0xc0,0x40,0x18,0x0b,0x0f,0x48,0x27,0x27,0x35,0x13,0x2d,0x60,0x21,0x21,0x2e,0x08,0x60,0x1f,0x03,0x17,0x60,0x10,0x13,0x2e,0x60,0x06,0x12,0x00,0x3f,0xed,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x01,0x2f,0x12,0x39,0x2f,0x2b,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x71,0x71,0x10,0xed,0x32,0x10,0xcd,0x31,0x30,0x01,0x14,0x0e, +0x02,0x2b,0x01,0x11,0x23,0x03,0x0e,0x05,0x23,0x22,0x26,0x27,0x35,0x1e,0x01,0x33,0x32,0x3e,0x04,0x37,0x13,0x21,0x11,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x2b,0x01,0x11,0x33,0x32,0x3e,0x02,0x04,0xb1,0x33,0x5f,0x87,0x54,0xe1,0xb5,0x1d,0x0b,0x1a,0x22,0x2e,0x40,0x54,0x37,0x19,0x2a,0x0e,0x0b,0x1e,0x0a,0x1c,0x2c,0x25,0x1d, +0x1a,0x17,0x0c,0x29,0x01,0xeb,0x2a,0x57,0x8c,0x62,0x34,0xa2,0x20,0x38,0x4c,0x2c,0x31,0x39,0x2d,0x49,0x35,0x1d,0x01,0x89,0x52,0x90,0x6a,0x3d,0x04,0xb9,0xfe,0x54,0xa8,0xf9,0xb1,0x71,0x41,0x19,0x05,0x05,0x84,0x04,0x03,0x0e,0x2e,0x59,0x98,0xde,0x9d,0x02,0x26,0xfd,0xc0,0x37,0x63,0x8c,0x58,0x38,0x59,0x3f,0x22,0xfe,0x14,0x23, +0x41,0x5d,0x00,0x00,0x00,0x02,0x00,0x47,0x00,0x00,0x04,0xb1,0x05,0x45,0x00,0x16,0x00,0x23,0x00,0x52,0x40,0x30,0x06,0x04,0x16,0x04,0x02,0x01,0x1e,0x5c,0x15,0x0d,0x0d,0x11,0x07,0x5c,0x10,0x17,0x70,0x17,0x80,0x17,0x03,0x17,0x17,0x25,0x14,0x10,0x5c,0x4f,0x11,0x5f,0x11,0x02,0x11,0x1d,0x0f,0x60,0x01,0x14,0x14,0x00,0x1e,0x60, +0x11,0x0d,0x12,0x12,0x00,0x03,0x00,0x3f,0x32,0x3f,0x33,0xed,0x11,0x39,0x2f,0x33,0xed,0x32,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x31,0x30,0x00,0x5d,0x01,0x11,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x21,0x11,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x11,0x01,0x34,0x2e,0x02,0x2b, +0x01,0x11,0x33,0x32,0x3e,0x02,0x02,0xdc,0x5c,0x57,0x8c,0x62,0x34,0x33,0x5f,0x87,0x54,0xfe,0xed,0xfe,0xb7,0xa1,0xa1,0x01,0x49,0x01,0xde,0x20,0x38,0x4c,0x2c,0x63,0x6b,0x2d,0x49,0x35,0x1d,0x05,0x45,0xfd,0xc0,0x37,0x63,0x8c,0x56,0x52,0x90,0x6a,0x3d,0x02,0x79,0xfd,0x87,0x05,0x45,0xfd,0xc0,0x02,0x40,0xfc,0x42,0x38,0x59,0x3f, +0x22,0xfe,0x14,0x23,0x41,0x5d,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0x8a,0x05,0x45,0x00,0x1b,0x00,0x54,0xb9,0x00,0x17,0xff,0xe8,0x40,0x2e,0x09,0x0c,0x48,0x0e,0x0e,0x00,0x10,0x08,0x5a,0x09,0x09,0x0b,0x1b,0x5a,0x10,0x00,0x20,0x00,0x90,0x00,0xa0,0x00,0x04,0x00,0x00,0x1d,0x0b,0x04,0x5f,0xb0,0x15,0x01,0x30,0x15,0x01, +0x15,0x15,0x00,0x0f,0x0b,0x5f,0x0c,0x03,0x09,0x00,0x12,0x00,0x3f,0x32,0x3f,0xed,0x32,0x12,0x39,0x2f,0x5d,0x71,0xed,0x01,0x2f,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0xed,0x32,0x11,0x39,0x2f,0x31,0x30,0x00,0x2b,0x21,0x11,0x34,0x26,0x23,0x22,0x06,0x07,0x11,0x23,0x11,0x21,0x35,0x21,0x15,0x21,0x11,0x3e,0x03,0x33,0x32,0x1e, +0x02,0x15,0x11,0x03,0xcc,0x50,0x60,0x4d,0xa4,0x47,0xbe,0xfe,0xda,0x03,0x37,0xfe,0xad,0x24,0x4e,0x52,0x53,0x29,0x60,0x87,0x57,0x28,0x02,0x21,0x7a,0x6d,0x20,0x12,0xfd,0x2a,0x04,0xa9,0x9c,0x9c,0xfe,0xbe,0x0a,0x15,0x11,0x0b,0x2f,0x5c,0x89,0x59,0xfd,0xcb,0x00,0x00,0xff,0xff,0x00,0xa8,0x00,0x00,0x04,0x9d,0x06,0xa9,0x12,0x26, +0x01,0xb6,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x57,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x1a,0x05,0x26,0x01,0x1a,0x1a,0x1d,0x00,0x10,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x06,0xa9,0x10,0x27,0x00,0x43,0xff,0xc0,0x00,0xf5,0x10,0x06,0x01,0xb4,0x00,0x00,0xff,0xff,0x00,0x14, +0xff,0xec,0x04,0xb6,0x06,0xa9,0x12,0x26,0x01,0xbf,0x00,0x00,0x11,0x07,0x02,0x96,0x00,0x00,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x1a,0x05,0x26,0x01,0x0f,0x1f,0x2b,0x15,0x19,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0x00,0x01,0x00,0x9c,0xfe,0x57,0x04,0x30,0x05,0x45,0x00,0x0b,0x00,0x59,0x40,0x3d,0x0b,0x5c,0x00,0x00, +0x02,0x09,0x5a,0x40,0x06,0x01,0xd0,0x06,0xe0,0x06,0x02,0x1f,0x06,0x2f,0x06,0x3f,0x06,0x6f,0x06,0x7f,0x06,0x05,0x6f,0x06,0x7f,0x06,0x8f,0x06,0xbf,0x06,0x04,0x06,0x06,0x0d,0x05,0x5a,0x4f,0x02,0x01,0x00,0x02,0x10,0x02,0xb0,0x02,0x03,0x02,0x07,0x03,0x03,0x0a,0x05,0x5f,0x02,0x12,0x00,0x1b,0x00,0x3f,0x3f,0xed,0x33,0x3f,0x33, +0x01,0x2f,0x5d,0x72,0xed,0x12,0x39,0x2f,0x5d,0x71,0x71,0x72,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x01,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x02,0x0c,0xfe,0x90,0xbf,0x02,0x16,0xbf,0xfe,0x90,0xfe,0x57,0x01,0xa9,0x05,0x45,0xfb,0x5b,0x04,0xa5,0xfa,0xbb,0xfe,0x57,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc, +0x05,0x45,0x12,0x06,0x00,0x24,0x00,0x00,0x00,0x02,0x00,0xa2,0x00,0x00,0x04,0x94,0x05,0x45,0x00,0x10,0x00,0x19,0x00,0x79,0x40,0x21,0x65,0x19,0x01,0x6a,0x12,0x01,0x06,0x0e,0x01,0x08,0x40,0x0d,0x14,0x48,0x08,0x08,0x16,0x77,0x00,0x87,0x00,0x02,0x00,0x5a,0x40,0x11,0x01,0x90,0x11,0xa0,0x11,0x02,0x11,0xb8,0xff,0xc0,0xb3,0x29, +0x2d,0x48,0x11,0xb8,0xff,0xc0,0x40,0x26,0x09,0x0c,0x48,0x11,0x11,0x1b,0x0b,0x16,0x5a,0x70,0x06,0x01,0x00,0x06,0x10,0x06,0xa0,0x06,0xb0,0x06,0x04,0x06,0x15,0x5f,0x50,0x0b,0x01,0x0b,0x0b,0x16,0x0a,0x5f,0x07,0x03,0x16,0x5f,0x06,0x12,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0x71,0xed,0x01,0x2f,0x5d,0x71,0xed,0x32,0x12,0x39, +0x2f,0x2b,0x2b,0x5d,0x71,0xed,0x5d,0x11,0x39,0x2f,0x2b,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x21,0x11,0x21,0x15,0x21,0x11,0x21,0x32,0x1e,0x02,0x07,0x34,0x26,0x23,0x21,0x11,0x21,0x32,0x36,0x04,0x94,0x3d,0x79,0xb6,0x79,0xfd,0xf3,0x03,0x96,0xfd,0x29,0x01,0x42,0x7d,0xba,0x7c,0x3e,0xc0,0xa4,0xa4,0xfe,0xd5, +0x01,0x33,0xa4,0x9c,0x01,0x89,0x57,0x90,0x68,0x3a,0x05,0x45,0x9c,0xfe,0x66,0x36,0x66,0x90,0x60,0x79,0x73,0xfe,0x28,0x70,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x80,0x05,0x45,0x12,0x06,0x00,0x25,0x00,0x00,0xff,0xff,0x00,0xe0,0x00,0x00,0x04,0x5b,0x05,0x45,0x12,0x06,0x01,0x61,0x00,0x00,0x00,0x02,0x00,0x05,0xfe,0x68,0x04,0xaf, +0x05,0x45,0x00,0x10,0x00,0x19,0x00,0x6f,0x40,0x45,0x6b,0x0e,0x7b,0x0e,0x8b,0x0e,0x03,0xb0,0x12,0xc0,0x12,0x02,0x12,0x0f,0x18,0x5a,0x09,0x40,0x0f,0x50,0x0f,0x02,0x0f,0x09,0x0f,0x09,0x19,0x07,0x02,0x5c,0x03,0x03,0x00,0x5c,0x40,0x19,0x50,0x19,0x02,0x19,0x40,0x19,0x1c,0x48,0x10,0x19,0x90,0x19,0xa0,0x19,0x03,0x19,0x19,0x1b, +0x06,0x5c,0x07,0x12,0x5f,0x0f,0x03,0x18,0x00,0x08,0x5f,0x05,0x12,0x07,0x02,0xb8,0x01,0x08,0x00,0x3f,0x33,0x3f,0xed,0x32,0x32,0x3f,0xed,0x01,0x2f,0xed,0x12,0x39,0x2f,0x5d,0x2b,0x71,0xed,0x32,0x2f,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x71,0x10,0xed,0x10,0xcd,0x71,0x31,0x30,0x5d,0x25,0x33,0x11,0x23,0x11,0x21,0x11,0x23,0x11, +0x33,0x3e,0x03,0x37,0x13,0x21,0x07,0x21,0x03,0x0e,0x03,0x07,0x21,0x04,0x00,0xaf,0xa0,0xfc,0x96,0xa0,0x77,0x29,0x44,0x38,0x2e,0x12,0x43,0x02,0x5c,0xa6,0xfe,0xd9,0x31,0x12,0x29,0x30,0x38,0x20,0x02,0x1b,0x96,0xfd,0xd2,0x01,0x98,0xfe,0x68,0x02,0x2e,0x33,0x7a,0xa3,0xd4,0x8d,0x01,0xfe,0x96,0xfe,0x86,0x86,0xcd,0x9f,0x7a,0x33, +0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x62,0x05,0x45,0x12,0x06,0x00,0x28,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0xcc,0x05,0x45,0x00,0x2b,0x00,0xdc,0x40,0x98,0x6b,0x1d,0x7b,0x1d,0x8b,0x1d,0x03,0x64,0x0e,0x74,0x0e,0x84,0x0e,0x03,0x6b,0x24,0x7b,0x24,0x8b,0x24,0x03,0x64,0x07,0x74,0x07,0x84,0x07,0x03,0x16,0x10,0x01,0x19, +0x1b,0x01,0x0b,0x25,0x1b,0x25,0x02,0x0d,0x1f,0x1d,0x1f,0x02,0x04,0x06,0x14,0x06,0x02,0x02,0x0c,0x12,0x0c,0x02,0x22,0x25,0x23,0x2b,0x06,0x09,0x08,0x17,0x2b,0x5c,0x14,0xe0,0x00,0x01,0x00,0x00,0x08,0x23,0x1d,0x1e,0x1e,0x24,0x10,0x23,0x01,0x23,0x23,0x2d,0x0e,0x0d,0x0d,0x07,0x0f,0x08,0x1f,0x08,0x02,0x0f,0x08,0x3f,0x08,0x5f, +0x08,0x8f,0x08,0x9f,0x08,0x05,0x4f,0x08,0x5f,0x08,0xcf,0x08,0xdf,0x08,0x04,0x08,0x40,0x24,0x27,0x48,0x08,0x40,0x10,0x13,0x48,0x08,0x22,0x09,0x25,0x06,0x09,0x06,0x17,0x66,0x14,0x76,0x14,0x86,0x14,0x03,0x2a,0x01,0x60,0x3f,0x14,0x01,0x14,0x14,0x1d,0x15,0x0d,0x03,0x24,0x08,0x00,0x12,0x00,0x3f,0x32,0x32,0x3f,0x33,0x33,0x39, +0x2f,0x5d,0xed,0x32,0x5d,0x33,0x39,0x39,0x11,0x33,0x11,0x33,0x01,0x2f,0x2b,0x2b,0x5d,0x71,0x72,0x33,0x33,0x2f,0x33,0x11,0x33,0x2f,0x5d,0x33,0x33,0x2f,0x33,0x11,0x12,0x39,0x2f,0x71,0x33,0xed,0x32,0x12,0x39,0x39,0x11,0x12,0x39,0x39,0x31,0x30,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x21,0x11,0x2e,0x03,0x27,0x03, +0x23,0x01,0x2e,0x01,0x27,0x03,0x33,0x13,0x1e,0x03,0x17,0x11,0x33,0x11,0x3e,0x03,0x37,0x13,0x33,0x03,0x0e,0x01,0x07,0x01,0x23,0x03,0x0e,0x03,0x07,0x11,0x02,0x16,0x0a,0x1f,0x20,0x19,0x04,0xf7,0xb9,0x01,0x3a,0x1d,0x34,0x17,0xc9,0xad,0x94,0x16,0x2e,0x33,0x37,0x1e,0xa0,0x1e,0x37,0x33,0x2e,0x16,0x94,0xad,0xc9,0x17,0x35,0x1d, +0x01,0x3b,0xb9,0xf7,0x04,0x19,0x20,0x1f,0x0a,0x02,0x5f,0x02,0x07,0x08,0x08,0x01,0xfd,0x87,0x02,0xcf,0x1d,0x4d,0x34,0x01,0xd8,0xfe,0x7e,0x38,0x4d,0x31,0x1c,0x07,0x02,0x5b,0xfd,0xa5,0x07,0x1c,0x31,0x4d,0x38,0x01,0x82,0xfe,0x28,0x35,0x4b,0x1d,0xfd,0x30,0x02,0x79,0x01,0x08,0x08,0x07,0x02,0xfd,0xa1,0x00,0x00,0x01,0x00,0x43, +0xff,0xec,0x04,0x70,0x05,0x59,0x00,0x3c,0x00,0xf3,0xb5,0x45,0x1c,0x55,0x1c,0x02,0x36,0xb8,0xff,0xe8,0x40,0x44,0x0d,0x11,0x48,0x43,0x26,0x53,0x26,0x02,0x4a,0x03,0x5a,0x03,0x02,0x33,0x14,0x45,0x2e,0x55,0x2e,0x65,0x2e,0x03,0x2e,0x5a,0x19,0x64,0x23,0x74,0x23,0x84,0x23,0x03,0x46,0x23,0x56,0x23,0x02,0x23,0x24,0x19,0x14,0x14, +0x19,0x24,0x03,0x05,0x45,0x38,0x55,0x38,0x65,0x38,0x03,0x38,0x5a,0x1f,0x10,0x2f,0x10,0x3f,0x10,0x03,0x90,0x10,0xa0,0x10,0x02,0x10,0xb8,0xff,0xc0,0x40,0x1a,0x09,0x0c,0x48,0x10,0x10,0x3e,0x64,0x06,0x74,0x06,0x84,0x06,0x03,0x46,0x06,0x56,0x06,0x02,0x06,0x05,0x40,0x0b,0x0f,0x48,0x05,0x33,0xb8,0xff,0xf0,0x40,0x20,0x0d,0x11, +0x48,0x33,0x14,0x10,0x0d,0x11,0x48,0x14,0x60,0x0f,0x15,0x3f,0x15,0x02,0x6f,0x15,0x8f,0x15,0x9f,0x15,0xbf,0x15,0xdf,0x15,0x05,0x15,0x15,0x0b,0x29,0x29,0xb8,0xff,0xf0,0x40,0x1f,0x0d,0x11,0x48,0xef,0x23,0x01,0x23,0x23,0x1e,0x5f,0x29,0x04,0x00,0x10,0x0d,0x11,0x48,0x0b,0x5f,0x00,0x80,0x06,0xd0,0x06,0xe0,0x06,0x03,0x06,0x06, +0x00,0x13,0x00,0x3f,0x32,0x2f,0x5d,0x10,0xed,0x2b,0x3f,0xed,0x33,0x2f,0x5d,0x2b,0x11,0x12,0x39,0x2f,0x71,0x72,0xed,0x2b,0x39,0x2b,0x01,0x2f,0x2b,0x33,0x5d,0x5d,0x12,0x39,0x2f,0x2b,0x5d,0x71,0xed,0x5d,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x33,0x5d,0x5d,0x10,0xed,0x5d,0x11,0x39,0x31,0x30,0x00,0x5d,0x5d,0x2b,0x5d,0x05,0x22,0x2e, +0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x2b,0x01,0x35,0x33,0x32,0x36,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x1e,0x03,0x15,0x14,0x0e,0x02,0x02,0x6d,0x76,0xaf,0x83,0x5e,0x24,0xa5,0x18,0x42,0x5b,0x79,0x50,0x4d,0x7a,0x55,0x2d,0xc0,0xca, +0x47,0x47,0xb4,0xae,0x27,0x48,0x68,0x41,0x4c,0x74,0x54,0x39,0x13,0xaf,0x21,0x60,0x84,0xa8,0x69,0x6c,0xac,0x78,0x40,0x28,0x49,0x68,0x3f,0x43,0x75,0x57,0x33,0x45,0x84,0xc0,0x14,0x32,0x5b,0x80,0x4f,0x4d,0x37,0x62,0x4b,0x2c,0x24,0x43,0x5e,0x3a,0x7a,0x72,0x94,0x7a,0x69,0x32,0x50,0x37,0x1e,0x28,0x44,0x5a,0x31,0x3d,0x52,0x7f, +0x57,0x2d,0x34,0x5e,0x82,0x4d,0x3f,0x65,0x4d,0x36,0x0f,0x0a,0x32,0x4f,0x6c,0x44,0x59,0x97,0x6d,0x3e,0x00,0x01,0x00,0xa2,0x00,0x00,0x04,0x2a,0x05,0x45,0x00,0x13,0x00,0x94,0x40,0x6d,0x0b,0x5c,0x7b,0x09,0x8b,0x09,0x02,0x4a,0x09,0x5a,0x09,0x6a,0x09,0x03,0x29,0x09,0x39,0x09,0x02,0x09,0x80,0x0c,0x90,0x0c,0xd0,0x0c,0xe0,0x0c, +0x04,0x3f,0x0c,0x01,0xc0,0x0c,0xd0,0x0c,0x02,0x7f,0x0c,0x8f,0x0c,0x02,0x0c,0x0c,0x15,0x74,0x13,0x84,0x13,0x02,0x45,0x13,0x55,0x13,0x65,0x13,0x03,0x16,0x13,0x26,0x13,0x36,0x13,0x03,0x05,0x13,0x01,0x13,0x02,0x5c,0x70,0x01,0x01,0x00,0x01,0x10,0x01,0xa0,0x01,0xb0,0x01,0x04,0x01,0x8c,0x12,0x01,0x7a,0x12,0x01,0x69,0x12,0x01, +0x12,0x09,0x01,0x03,0x83,0x08,0x01,0x75,0x08,0x01,0x66,0x08,0x01,0x0c,0x08,0x00,0x12,0x00,0x3f,0x32,0x32,0x5d,0x5d,0x5d,0x3f,0x33,0x33,0x5d,0x5d,0x5d,0x01,0x2f,0x5d,0x71,0xed,0x32,0x5d,0x5d,0x5d,0x5d,0x12,0x39,0x2f,0x5d,0x5d,0x71,0x71,0x33,0x5d,0x5d,0x5d,0xed,0x31,0x30,0x33,0x11,0x33,0x11,0x14,0x06,0x07,0x06,0x07,0x01, +0x33,0x11,0x23,0x11,0x34,0x36,0x37,0x36,0x37,0x01,0xa2,0xac,0x05,0x04,0x04,0x05,0x02,0x10,0xde,0xaa,0x05,0x03,0x04,0x04,0xfd,0xf8,0x05,0x45,0xfc,0xa0,0x33,0x62,0x27,0x2e,0x28,0x04,0x72,0xfa,0xbb,0x03,0x6c,0x27,0x59,0x26,0x2d,0x2b,0xfb,0x96,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x06,0xa9,0x12,0x26,0x01,0xb4,0x00,0x00, +0x11,0x07,0x02,0x96,0xff,0xee,0x00,0xf5,0x00,0x15,0xb4,0x01,0x14,0x05,0x26,0x01,0xb8,0xff,0xfc,0xb4,0x19,0x25,0x00,0x0a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x01,0x00,0xa8,0x00,0x00,0x04,0x9d,0x05,0x45,0x00,0x19,0x00,0x7f,0x40,0x55,0x79,0x12,0x89,0x12,0x02,0x7f,0x11,0x8f,0x11,0x02,0x6c,0x11,0x01,0x11,0x20,0x0b, +0x0e,0x48,0x08,0x20,0x0b,0x11,0x48,0x16,0x0f,0x26,0x0f,0x36,0x0f,0x03,0x72,0x0f,0x82,0x0f,0x02,0x44,0x0f,0x54,0x0f,0x64,0x0f,0x03,0x16,0x0f,0x26,0x0f,0x36,0x0f,0x03,0x0f,0x12,0x10,0x08,0x09,0x09,0x11,0x00,0x10,0x10,0x10,0x02,0x10,0x10,0x1b,0x02,0x18,0x5a,0x00,0x19,0x10,0x19,0x02,0x19,0x0f,0x12,0x17,0x5f,0x02,0x02,0x19, +0x10,0x12,0x08,0x00,0x03,0x00,0x3f,0x32,0x3f,0x33,0x39,0x2f,0xed,0x39,0x39,0x01,0x2f,0x5d,0xed,0x32,0x11,0x33,0x2f,0x5d,0x33,0x33,0x2f,0x33,0x11,0x39,0x39,0x5d,0x5d,0x5d,0x00,0x5d,0x31,0x30,0x01,0x2b,0x2b,0x5d,0x5d,0x00,0x5d,0x13,0x33,0x11,0x32,0x3e,0x02,0x37,0x13,0x33,0x01,0x0e,0x03,0x07,0x01,0x23,0x01,0x0e,0x03,0x23, +0x11,0x23,0xa8,0xbf,0x2a,0x53,0x51,0x4f,0x27,0xfb,0xca,0xfe,0xd8,0x21,0x33,0x29,0x1f,0x0c,0x01,0xfd,0xde,0xfe,0x55,0x11,0x2e,0x30,0x2d,0x11,0xbf,0x05,0x45,0xfd,0xb3,0x16,0x31,0x51,0x3a,0x01,0x7b,0xfe,0x52,0x30,0x3e,0x29,0x18,0x09,0xfd,0x21,0x02,0x87,0x07,0x0e,0x0b,0x06,0xfd,0x9f,0x00,0x01,0xff,0xfe,0xff,0xf0,0x04,0x5d, +0x05,0x45,0x00,0x1b,0x00,0x66,0x40,0x0c,0x9d,0x01,0x01,0x01,0x69,0x18,0x79,0x18,0x89,0x18,0x03,0x18,0xb8,0xff,0xc8,0x40,0x0e,0x0a,0x0e,0x48,0x18,0x18,0x0c,0x1a,0x5a,0x40,0x1b,0x50,0x1b,0x02,0x1b,0xb8,0xff,0xc0,0xb3,0x21,0x28,0x48,0x1b,0xb8,0xff,0xc0,0xb3,0x15,0x18,0x48,0x1b,0xb8,0xff,0xc0,0x40,0x16,0x09,0x0c,0x48,0x1b, +0x1b,0x1d,0x2f,0x0c,0x3f,0x0c,0x02,0x0c,0x1a,0x12,0x01,0x5f,0x18,0x03,0x10,0x5f,0x09,0x13,0x00,0x3f,0xed,0x3f,0xed,0x3f,0x01,0x2f,0x5d,0x12,0x39,0x2f,0x2b,0x2b,0x2b,0x71,0xed,0x12,0x39,0x2f,0x2b,0x5d,0xcd,0x5d,0x31,0x30,0x01,0x21,0x03,0x06,0x02,0x0e,0x03,0x23,0x22,0x26,0x27,0x35,0x1e,0x01,0x33,0x32,0x3e,0x04,0x37,0x13, +0x21,0x11,0x23,0x03,0xa3,0xfe,0x86,0x2b,0x16,0x2b,0x33,0x3d,0x50,0x66,0x43,0x19,0x2f,0x0e,0x0b,0x23,0x0a,0x1e,0x35,0x30,0x2b,0x29,0x28,0x14,0x3d,0x02,0xd7,0xba,0x04,0xa5,0xfe,0xae,0xac,0xfe,0xf9,0xc1,0x81,0x4d,0x21,0x05,0x05,0x98,0x04,0x03,0x13,0x37,0x63,0xa3,0xe9,0xa1,0x01,0xe0,0xfa,0xbb,0x00,0x00,0xff,0xff,0x00,0x81, +0x00,0x00,0x04,0x4b,0x05,0x45,0x12,0x06,0x00,0x30,0x00,0x00,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x2a,0x05,0x45,0x12,0x06,0x00,0x2b,0x00,0x00,0xff,0xff,0x00,0x66,0xff,0xec,0x04,0x66,0x05,0x5a,0x12,0x06,0x00,0x32,0x00,0x00,0x00,0x01,0x00,0xa2,0x00,0x00,0x04,0x2a,0x05,0x45,0x00,0x07,0x00,0x43,0x40,0x2f,0x07,0x5a,0x1f,0x00, +0x2f,0x00,0x3f,0x00,0x6f,0x00,0x7f,0x00,0x05,0x6f,0x00,0x7f,0x00,0x8f,0x00,0xbf,0x00,0x04,0x00,0x00,0x09,0x03,0x5a,0x70,0x04,0x01,0x00,0x04,0x10,0x04,0xa0,0x04,0xb0,0x04,0x04,0x04,0x02,0x5f,0x05,0x03,0x04,0x00,0x12,0x00,0x3f,0x32,0x3f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x31,0x30,0x21,0x11,0x21, +0x11,0x23,0x11,0x21,0x11,0x03,0x6b,0xfd,0xf6,0xbf,0x03,0x88,0x04,0xa5,0xfb,0x5b,0x05,0x45,0xfa,0xbb,0xff,0xff,0x00,0xa2,0x00,0x00,0x04,0x5f,0x05,0x45,0x12,0x06,0x00,0x33,0x00,0x00,0xff,0xff,0x00,0x71,0xff,0xec,0x04,0x76,0x05,0x5a,0x12,0x06,0x00,0x26,0x00,0x00,0xff,0xff,0x00,0x4c,0x00,0x00,0x04,0x80,0x05,0x45,0x12,0x06, +0x00,0x37,0x00,0x00,0x00,0x01,0x00,0x14,0xff,0xec,0x04,0xb6,0x05,0x45,0x00,0x19,0x00,0x79,0x40,0x54,0x7b,0x12,0x8b,0x12,0x02,0x7b,0x13,0x8b,0x13,0x02,0x69,0x14,0x01,0x8c,0x18,0x01,0x18,0x20,0x0d,0x10,0x48,0x82,0x16,0x01,0x63,0x16,0x73,0x16,0x02,0x44,0x16,0x54,0x16,0x02,0x14,0x17,0x17,0x15,0x18,0x10,0x19,0x20,0x19,0x30, +0x19,0x90,0x19,0xa0,0x19,0xb0,0x19,0x06,0x19,0x19,0x1b,0x0a,0x0a,0x16,0x15,0x40,0x0b,0x14,0x48,0x15,0x70,0x17,0x80,0x17,0x02,0x54,0x17,0x64,0x17,0x02,0x17,0x14,0x14,0x18,0x15,0x03,0x0e,0x5f,0x05,0x13,0x00,0x3f,0xed,0x3f,0x33,0x39,0x2f,0x33,0x5d,0x5d,0x01,0x2f,0x2b,0x33,0x33,0x2f,0x11,0x33,0x2f,0x5d,0x33,0x12,0x39,0x11, +0x33,0x31,0x30,0x5d,0x5d,0x5d,0x2b,0x5d,0x5d,0x5d,0x5d,0x01,0x0e,0x03,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x01,0x33,0x32,0x3e,0x02,0x3f,0x01,0x01,0x33,0x09,0x01,0x33,0x02,0xa2,0x2e,0x51,0x5a,0x6e,0x4b,0x1f,0x43,0x40,0x3a,0x17,0x51,0x23,0x53,0x30,0x26,0x3a,0x36,0x39,0x24,0x27,0xfd,0xe6,0xd7,0x01,0xa1,0x01,0x5d,0xcd,0x01, +0x3e,0x59,0x80,0x52,0x27,0x0a,0x12,0x1a,0x10,0x90,0x16,0x25,0x14,0x35,0x59,0x45,0x4a,0x03,0x8d,0xfd,0x1d,0x02,0xe3,0x00,0xff,0xff,0x00,0x08,0xff,0xf5,0x04,0xc5,0x05,0x4f,0x12,0x06,0x01,0x73,0x00,0x00,0xff,0xff,0x00,0x24,0x00,0x00,0x04,0xa9,0x05,0x45,0x12,0x06,0x00,0x3b,0x00,0x00,0x00,0x01,0x00,0x80,0xfe,0x57,0x04,0xb7, +0x05,0x45,0x00,0x0b,0x00,0x4d,0x40,0x33,0x01,0x5a,0x02,0x02,0x0b,0x5a,0x6f,0x08,0x7f,0x08,0x8f,0x08,0x03,0x08,0x40,0x1e,0x25,0x48,0x08,0x40,0x19,0x1c,0x48,0x08,0x08,0x0d,0x07,0x5a,0xcf,0x04,0xdf,0x04,0xef,0x04,0x03,0x00,0x04,0x10,0x04,0x02,0x04,0x09,0x05,0x03,0x0b,0x07,0x5f,0x04,0x12,0x01,0x1b,0x00,0x3f,0x3f,0xed,0x32, +0x3f,0x33,0x01,0x2f,0x5d,0x5d,0xed,0x12,0x39,0x2f,0x2b,0x2b,0x5d,0xed,0x32,0x2f,0xed,0x31,0x30,0x25,0x11,0x23,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x04,0xb7,0xb4,0xfc,0x7d,0xbf,0x02,0x0a,0xbf,0xa0,0xfd,0xb7,0x01,0xa9,0x05,0x45,0xfb,0x5b,0x04,0xa5,0xfb,0x5b,0x00,0x00,0x00,0x00,0x01,0x00,0x5f,0x00,0x00,0x04,0x31, +0x05,0x45,0x00,0x17,0x00,0x4e,0x40,0x33,0x7a,0x07,0x8a,0x07,0x02,0x0a,0x06,0x01,0x16,0x5a,0x13,0x80,0x17,0x90,0x17,0xd0,0x17,0x03,0x1f,0x17,0x2f,0x17,0x3f,0x17,0x03,0x7f,0x17,0x8f,0x17,0x02,0x17,0x17,0x19,0x0b,0x5a,0x08,0x79,0x05,0x89,0x05,0x02,0x05,0x5f,0x0e,0x0e,0x09,0x16,0x12,0x14,0x09,0x03,0x00,0x3f,0x33,0x3f,0x12, +0x39,0x2f,0xed,0x5d,0x01,0x2f,0xed,0x12,0x39,0x2f,0x5d,0x71,0x71,0x33,0xed,0x31,0x30,0x00,0x5d,0x5d,0x01,0x0e,0x03,0x23,0x22,0x26,0x35,0x11,0x33,0x11,0x14,0x16,0x33,0x32,0x3e,0x02,0x37,0x11,0x33,0x11,0x23,0x03,0x73,0x24,0x5a,0x64,0x68,0x30,0xce,0xcc,0xbe,0x7b,0x6f,0x2e,0x63,0x60,0x58,0x23,0xbe,0xbe,0x01,0xde,0x08,0x14, +0x12,0x0c,0xbb,0xb2,0x02,0x34,0xfd,0xe0,0x7a,0x6d,0x0a,0x0f,0x11,0x07,0x02,0xd6,0xfa,0xbb,0x00,0x00,0x00,0x01,0x00,0x59,0x00,0x00,0x04,0x73,0x05,0x45,0x00,0x0b,0x00,0x6c,0x40,0x14,0x07,0x5c,0x04,0x04,0x00,0x0b,0x5c,0x20,0x08,0x30,0x08,0x40,0x08,0x03,0xa0,0x08,0xf0,0x08,0x02,0x08,0xb8,0xff,0xc0,0x40,0x35,0x12,0x16,0x48, +0x4f,0x08,0x5f,0x08,0x02,0x10,0x08,0x20,0x08,0x30,0x08,0x03,0x08,0x08,0x0d,0x03,0x5c,0x0f,0x00,0x3f,0x00,0x5f,0x00,0x8f,0x00,0x9f,0x00,0x05,0x2f,0x00,0xcf,0x00,0xdf,0x00,0x03,0x00,0x40,0x10,0x13,0x48,0x00,0x09,0x05,0x01,0x03,0x07,0x03,0x60,0x00,0x12,0x00,0x3f,0xed,0x32,0x3f,0x33,0x33,0x01,0x2f,0x2b,0x5d,0x71,0xed,0x12, +0x39,0x2f,0x5d,0x5d,0x2b,0x71,0x72,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x33,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x59,0xa2,0x01,0x1a,0xa2,0x01,0x1a,0xa2,0x05,0x45,0xfb,0x47,0x04,0xb9,0xfb,0x47,0x04,0xb9,0xfa,0xbb,0x00,0x00,0x00,0x01,0x00,0x56,0xfe,0x57,0x04,0xcc,0x05,0x45,0x00,0x0f,0x00,0x8e,0x40,0x20, +0x09,0x5c,0x06,0x06,0x0a,0x02,0x0f,0x5c,0x40,0x00,0x50,0x00,0x02,0x00,0x00,0x0d,0x5c,0x20,0x0a,0x30,0x0a,0x50,0x0a,0x60,0x0a,0x04,0x80,0x0a,0x90,0x0a,0x02,0x0a,0xb8,0xff,0xc0,0x40,0x41,0x24,0x28,0x48,0x1f,0x0a,0x2f,0x0a,0x3f,0x0a,0x03,0x90,0x0a,0xa0,0x0a,0x02,0x4f,0x0a,0x5f,0x0a,0x02,0x0a,0x0a,0x11,0x05,0x5c,0x0f,0x02, +0x3f,0x02,0x02,0x2f,0x02,0xcf,0x02,0xdf,0x02,0x03,0x02,0x40,0x28,0x2d,0x48,0x02,0x40,0x1e,0x23,0x48,0x02,0x40,0x10,0x13,0x48,0x02,0x0b,0x07,0x03,0x03,0x0d,0x09,0x05,0x60,0x02,0x12,0x00,0x1b,0x00,0x3f,0x3f,0xed,0x32,0x32,0x3f,0x33,0x33,0x01,0x2f,0x2b,0x2b,0x2b,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x5d,0x71,0x2b,0x71,0x72, +0xed,0x32,0x2f,0x71,0xed,0x11,0x12,0x39,0x2f,0xed,0x31,0x30,0x01,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x04,0x3e,0xfc,0x18,0xa2,0x01,0x01,0xa2,0x01,0x01,0xa2,0x8e,0xfe,0x57,0x01,0xa9,0x05,0x45,0xfb,0x47,0x04,0xb9,0xfb,0x47,0x04,0xb9,0xfb,0x47,0xfd,0xcb,0x00,0x00,0x00,0x02,0x00,0x00, +0x00,0x00,0x04,0x83,0x05,0x45,0x00,0x10,0x00,0x19,0x00,0x62,0x40,0x41,0x65,0x19,0x01,0x6a,0x12,0x01,0x08,0x09,0x01,0x06,0x03,0x01,0x00,0x16,0x5a,0x0c,0x0c,0x0e,0x75,0x06,0x85,0x06,0x02,0x06,0x5a,0x00,0x11,0x10,0x11,0x02,0x3f,0x11,0xaf,0x11,0xbf,0x11,0xcf,0x11,0x04,0x00,0x11,0x10,0x11,0x90,0x11,0xa0,0x11,0x04,0x11,0x11, +0x1b,0x0e,0x15,0x5f,0x00,0x00,0x16,0x0e,0x5f,0x0f,0x03,0x16,0x5f,0x0c,0x12,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x01,0x2f,0x12,0x39,0x2f,0x5d,0x71,0x72,0xed,0x5d,0x12,0x39,0x2f,0xed,0x32,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x21,0x11,0x21,0x35,0x21,0x01,0x34,0x26, +0x2b,0x01,0x11,0x33,0x32,0x36,0x02,0x0e,0x84,0x7d,0xba,0x7c,0x3e,0x3d,0x79,0xb6,0x79,0xfe,0xb1,0xfe,0xb1,0x02,0x0e,0x01,0xb5,0xa4,0xa4,0x6d,0x75,0xa4,0x9c,0x03,0x0f,0x36,0x66,0x90,0x5a,0x57,0x90,0x68,0x3a,0x04,0xa9,0x9c,0xfc,0x42,0x79,0x6f,0xfe,0x28,0x74,0x00,0x00,0x03,0x00,0x69,0x00,0x00,0x04,0x63,0x05,0x45,0x00,0x0c, +0x00,0x14,0x00,0x18,0x00,0x88,0x40,0x2e,0x65,0x14,0x01,0x6a,0x0e,0x01,0x07,0x0b,0x17,0x0b,0x27,0x0b,0x03,0x77,0x00,0x87,0x00,0x02,0x00,0x5c,0x40,0x0d,0x01,0x10,0x0d,0x20,0x0d,0x30,0x0d,0x03,0x0d,0x0d,0x06,0x18,0x5c,0x10,0x15,0x20,0x15,0x02,0x90,0x15,0xa0,0x15,0x02,0x15,0xb8,0xff,0xc0,0xb3,0x26,0x29,0x48,0x15,0xb8,0xff, +0xc0,0xb3,0x1d,0x22,0x48,0x15,0xb8,0xff,0xc0,0x40,0x1e,0x09,0x0c,0x48,0x15,0x15,0x1a,0x09,0x11,0x5c,0x06,0x40,0x1a,0x1d,0x48,0x10,0x06,0x01,0x06,0x10,0x60,0x09,0x09,0x16,0x07,0x03,0x11,0x60,0x15,0x06,0x12,0x00,0x3f,0x33,0xed,0x3f,0x33,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x2b,0xed,0x32,0x12,0x39,0x2f,0x2b,0x2b,0x2b,0x5d,0x71, +0xed,0x12,0x39,0x2f,0x5d,0x71,0xed,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x2b,0x01,0x11,0x33,0x11,0x33,0x32,0x16,0x07,0x34,0x21,0x23,0x11,0x33,0x32,0x36,0x01,0x11,0x33,0x11,0x03,0x43,0x3e,0x7a,0xb6,0x77,0xf5,0xab,0x3e,0xf6,0xfb,0xa2,0xfe,0xb8,0x45,0x4d,0xa5,0x9b,0x01,0x17,0xab,0x01,0x89,0x57,0x90,0x68, +0x3a,0x05,0x45,0xfd,0xc0,0xc8,0xb6,0xf2,0xfe,0x14,0x7d,0xfe,0xf6,0x05,0x45,0xfa,0xbb,0x00,0x00,0x00,0x00,0x02,0x00,0xa2,0x00,0x00,0x04,0x94,0x05,0x45,0x00,0x0e,0x00,0x17,0x00,0x64,0x40,0x19,0x65,0x17,0x01,0x6a,0x10,0x01,0x06,0x0c,0x01,0x77,0x00,0x87,0x00,0x02,0x00,0x5a,0x40,0x0f,0x01,0x90,0x0f,0xa0,0x0f,0x02,0x0f,0xb8, +0xff,0xc0,0xb3,0x29,0x2d,0x48,0x0f,0xb8,0xff,0xc0,0x40,0x20,0x09,0x0c,0x48,0x0f,0x0f,0x19,0x09,0x14,0x5a,0x70,0x06,0x01,0x00,0x06,0x10,0x06,0xa0,0x06,0xb0,0x06,0x04,0x06,0x13,0x5f,0x09,0x09,0x07,0x03,0x14,0x5f,0x06,0x12,0x00,0x3f,0xed,0x3f,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x32,0x12,0x39,0x2f,0x2b,0x2b,0x5d,0x71, +0xed,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x21,0x11,0x33,0x11,0x21,0x32,0x1e,0x02,0x07,0x34,0x26,0x23,0x21,0x11,0x21,0x32,0x36,0x04,0x94,0x3d,0x79,0xb6,0x79,0xfd,0xf3,0xbf,0x01,0x42,0x7d,0xba,0x7c,0x3e,0xc0,0xa4,0xa4,0xfe,0xd5,0x01,0x33,0xa4,0x9c,0x01,0x89,0x57,0x90,0x68,0x3a,0x05,0x45,0xfd,0xca, +0x36,0x66,0x90,0x60,0x79,0x73,0xfe,0x28,0x70,0x00,0x00,0x00,0x00,0x01,0x00,0x57,0xff,0xec,0x04,0x5c,0x05,0x5a,0x00,0x2a,0x00,0xaf,0x40,0x7d,0x45,0x0d,0x55,0x0d,0x02,0x33,0x28,0x01,0x74,0x0a,0x84,0x0a,0x02,0x0a,0x0b,0x00,0x0b,0x00,0x1f,0x15,0x5b,0x02,0xaf,0x2a,0x01,0x40,0x2a,0x01,0x2a,0x40,0x17,0x1b,0x48,0x79,0x2a,0x89, +0x2a,0x02,0x00,0x2a,0x01,0x2a,0x2a,0x2c,0x74,0x20,0x84,0x20,0x02,0x20,0x2f,0x1f,0x01,0x1f,0x00,0x60,0x0f,0x01,0x3f,0x01,0x02,0x6f,0x01,0x8f,0x01,0x9f,0x01,0xbf,0x01,0xdf,0x01,0x05,0x6f,0x01,0x01,0x01,0x01,0x10,0x49,0x1a,0x59,0x1a,0x69,0x1a,0x03,0x25,0x5f,0x1a,0x10,0x20,0x20,0x20,0x30,0x20,0x60,0x20,0x70,0x20,0x05,0x30, +0x20,0x80,0x20,0xd0,0x20,0xe0,0x20,0x04,0x20,0x20,0x1a,0x13,0x46,0x10,0x56,0x10,0x66,0x10,0x03,0x0a,0x0a,0x05,0x5f,0x10,0x04,0x00,0x3f,0xed,0x33,0x2f,0x5d,0x3f,0x33,0x2f,0x5d,0x71,0x10,0xed,0x5d,0x11,0x39,0x2f,0x5d,0x71,0x72,0xed,0x01,0x2f,0x5d,0x33,0x5d,0x12,0x39,0x2f,0x5d,0x5d,0x2b,0x71,0x71,0x33,0xed,0x12,0x39,0x39, +0x2f,0x2f,0x33,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x01,0x35,0x21,0x2e,0x01,0x23,0x22,0x0e,0x02,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x01,0x12,0x15,0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x01,0xe7,0x01,0xaa,0x0a,0x9f,0xa5,0x3c,0x61,0x49,0x34,0x0f,0xa8,0x1a,0x4c,0x6f,0x98,0x65,0x8a, +0xca,0x84,0x40,0x41,0x87,0xcd,0x8d,0x66,0x9b,0x74,0x51,0x1d,0x9f,0x15,0x3a,0x4f,0x65,0x3f,0x55,0x7e,0x54,0x2d,0x05,0x02,0x61,0x91,0xe2,0xea,0x2a,0x44,0x58,0x2e,0x41,0x42,0x79,0x5d,0x37,0x5b,0xaf,0xfe,0xff,0xa6,0x9e,0xfe,0xfe,0xb8,0x65,0x40,0x69,0x85,0x46,0x41,0x36,0x66,0x4e,0x30,0x3f,0x78,0xb1,0x72,0x00,0x02,0x00,0x56, +0xff,0xec,0x04,0x97,0x05,0x5a,0x00,0x16,0x00,0x22,0x00,0x8a,0x40,0x2d,0x76,0x15,0x86,0x15,0x02,0x60,0x1e,0x01,0x60,0x22,0x01,0x6f,0x1c,0x01,0x6f,0x18,0x01,0x1d,0x5c,0x11,0x9f,0x0a,0xaf,0x0a,0x02,0x0a,0x40,0x09,0x0c,0x48,0x0a,0x0a,0x0d,0x00,0x5c,0x40,0x17,0x50,0x17,0xd0,0x17,0xe0,0x17,0x04,0x17,0xb8,0xff,0xc0,0xb3,0x12, +0x16,0x48,0x17,0xb8,0xff,0xc0,0x40,0x0a,0x0a,0x0e,0x48,0x17,0x17,0x24,0x10,0x0c,0x5c,0x0d,0xb8,0xff,0xc0,0x40,0x18,0x24,0x2b,0x48,0x2f,0x0d,0x01,0x0d,0x0b,0x60,0x10,0x10,0x20,0x1a,0x60,0x14,0x04,0x0e,0x03,0x0d,0x12,0x20,0x60,0x05,0x13,0x00,0x3f,0xed,0x3f,0x3f,0x3f,0xed,0x12,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x2b,0xed,0x32, +0x12,0x39,0x2f,0x2b,0x2b,0x71,0xed,0x12,0x39,0x2f,0x2b,0x5d,0x33,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x02,0x0e,0x01,0x23,0x22,0x2e,0x02,0x27,0x23,0x11,0x23,0x11,0x33,0x11,0x33,0x1a,0x01,0x33,0x32,0x12,0x03,0x10,0x02,0x23,0x22,0x02,0x11,0x10,0x12,0x33,0x32,0x12,0x04,0x97,0x31,0x62,0x92,0x61,0x5a,0x8c, +0x60,0x36,0x05,0x99,0xa1,0xa1,0x99,0x0b,0xc6,0xb2,0xbc,0xc8,0xac,0x6a,0x6f,0x6d,0x6a,0x6b,0x6c,0x6d,0x6c,0x02,0xa9,0xa7,0xfe,0xfb,0xb3,0x5e,0x54,0xa0,0xeb,0x96,0xfd,0x9f,0x05,0x45,0xfd,0xad,0x01,0x34,0x01,0x34,0xfe,0xa8,0xfe,0xa7,0x01,0x16,0x01,0x09,0xfe,0xf7,0xfe,0xea,0xfe,0xea,0xfe,0xea,0x01,0x16,0x00,0x02,0x00,0x34, +0x00,0x00,0x04,0x2b,0x05,0x45,0x00,0x11,0x00,0x1b,0x00,0x9c,0x40,0x41,0x77,0x09,0x87,0x09,0x02,0x74,0x08,0x84,0x08,0x02,0x6a,0x04,0x01,0x0a,0x03,0x01,0x82,0x10,0x01,0x74,0x10,0x01,0x66,0x10,0x01,0x10,0x01,0x01,0x00,0x18,0x0d,0x5a,0x3f,0x0e,0x01,0xc0,0x0e,0xd0,0x0e,0x02,0x6f,0x0e,0x7f,0x0e,0x8f,0x0e,0x03,0x0e,0x0e,0x1d, +0x12,0x5a,0x06,0x82,0x11,0x01,0x54,0x11,0x64,0x11,0x74,0x11,0x03,0x11,0x00,0xb8,0xff,0xf0,0x40,0x26,0x00,0x00,0x06,0x40,0x15,0x1c,0x48,0x10,0x06,0x01,0x06,0x01,0x10,0x5f,0x1f,0x17,0x7f,0x17,0x02,0x3f,0x17,0x6f,0x17,0x9f,0x17,0xef,0x17,0x04,0x17,0x17,0x00,0x1a,0x5f,0x0b,0x03,0x0e,0x00,0x12,0x00,0x3f,0x32,0x3f,0xed,0x12, +0x39,0x2f,0x5d,0x71,0xed,0x32,0x01,0x2f,0x5d,0x2b,0x33,0x2f,0x38,0x33,0x5d,0x5d,0x10,0xed,0x12,0x39,0x2f,0x5d,0x5d,0x71,0xed,0x33,0x12,0x39,0x2f,0x33,0x5d,0x5d,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x33,0x01,0x2e,0x03,0x35,0x34,0x3e,0x02,0x33,0x21,0x11,0x23,0x11,0x23,0x01,0x13,0x14,0x1e,0x02,0x33,0x21,0x11,0x21,0x20, +0x34,0x01,0x90,0x5b,0x82,0x54,0x27,0x3b,0x77,0xb3,0x78,0x01,0xe2,0xbf,0xee,0xfe,0x92,0x1c,0x1f,0x45,0x72,0x52,0x01,0x18,0xfe,0xf0,0xfe,0xd0,0x02,0x55,0x0f,0x4c,0x67,0x7b,0x3e,0x57,0x8a,0x61,0x33,0xfa,0xbb,0x02,0x3f,0xfd,0xc1,0x03,0xcd,0x32,0x5a,0x43,0x28,0x01,0xd6,0x00,0x00,0x00,0xff,0xff,0x00,0x80,0xff,0xec,0x04,0x88, +0x04,0x4e,0x12,0x06,0x00,0x44,0x00,0x00,0x00,0x02,0x00,0x8c,0xff,0xec,0x04,0x53,0x05,0xde,0x00,0x13,0x00,0x38,0x00,0x8c,0x40,0x4e,0x79,0x2f,0x89,0x2f,0x02,0x4a,0x08,0x5a,0x08,0x02,0x6d,0x02,0x01,0x4a,0x02,0x5a,0x02,0x02,0x62,0x12,0x01,0x45,0x12,0x55,0x12,0x02,0x62,0x0c,0x01,0x45,0x0c,0x55,0x0c,0x02,0x06,0x15,0x76,0x15, +0x86,0x15,0x03,0x2a,0x2a,0x0a,0x17,0x47,0xa0,0x00,0x01,0x00,0x00,0x10,0x00,0x60,0x00,0xe0,0x00,0x04,0x00,0x00,0x3a,0x34,0x0a,0x47,0xc0,0x1f,0xe0,0x1f,0x02,0x00,0x1f,0x01,0x1f,0x34,0x05,0x50,0x14,0x2d,0xb8,0x01,0x0a,0x40,0x0d,0x24,0x14,0x24,0x14,0x24,0x0f,0x2a,0x52,0x29,0x0f,0x50,0x1a,0x16,0x00,0x3f,0xed,0x2f,0xed,0x12, +0x39,0x39,0x2f,0x2f,0x10,0xed,0x10,0xed,0x33,0x01,0x2f,0x5d,0x71,0xed,0x32,0x12,0x39,0x2f,0x5d,0x71,0xed,0x11,0x39,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x03,0x32,0x12,0x11,0x10,0x02,0x23,0x22,0x2e,0x02,0x35,0x34, +0x12,0x3e,0x01,0x37,0x3e,0x03,0x37,0x15,0x0e,0x01,0x07,0x0e,0x05,0x07,0x3e,0x03,0x03,0x96,0x27,0x49,0x68,0x41,0x45,0x72,0x51,0x2c,0x2c,0x4d,0x6a,0x3d,0x45,0x70,0x4e,0x2a,0xf3,0xde,0xd2,0xfa,0xee,0x71,0xb2,0x7b,0x41,0x3a,0x80,0xce,0x93,0x39,0x64,0x5b,0x56,0x2b,0x56,0xa1,0x5b,0x4e,0x7c,0x5e,0x43,0x2c,0x16,0x03,0x14,0x42, +0x61,0x7f,0x01,0xf6,0x72,0x97,0x5b,0x25,0x27,0x5b,0x97,0x70,0x72,0x96,0x59,0x24,0x24,0x58,0x97,0x02,0x7f,0xfe,0xfb,0xfe,0xfa,0xfe,0xf7,0xfe,0xfd,0x46,0x9c,0xfa,0xb4,0xc0,0x01,0x16,0xc1,0x73,0x1c,0x0b,0x11,0x0e,0x0c,0x06,0xa1,0x0b,0x17,0x11,0x0e,0x21,0x32,0x49,0x6c,0x95,0x65,0x38,0x60,0x48,0x29,0x00,0x00,0x03,0x00,0xb9, +0x00,0x00,0x04,0x3a,0x04,0x3a,0x00,0x17,0x00,0x24,0x00,0x2f,0x00,0x55,0x40,0x34,0x76,0x2a,0x86,0x2a,0x02,0x0a,0x13,0x1a,0x13,0x02,0x05,0x03,0x15,0x03,0x25,0x03,0x03,0x0a,0x18,0x05,0x47,0x2c,0x2c,0x16,0x10,0x47,0x1e,0x1e,0x31,0x26,0x18,0x46,0x00,0x16,0x80,0x16,0x02,0x16,0x0a,0x24,0x51,0x26,0x26,0x18,0x25,0x50,0x17,0x0f, +0x18,0x50,0x16,0x15,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x39,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0xed,0x11,0x39,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x15,0x1e,0x03,0x15,0x14,0x0e,0x02,0x23,0x21,0x11,0x13,0x21,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23, +0x21,0x19,0x01,0x21,0x32,0x3e,0x02,0x35,0x34,0x26,0x23,0x02,0x87,0x4c,0x90,0x70,0x44,0x23,0x3c,0x51,0x2f,0x36,0x5f,0x45,0x28,0x3d,0x6d,0x97,0x5b,0xfe,0x1b,0xb4,0x01,0x14,0x45,0x5f,0x3b,0x1b,0x1c,0x3f,0x64,0x47,0xfe,0xf8,0x01,0x00,0x44,0x5b,0x37,0x17,0x66,0x79,0x04,0x3a,0x18,0x3e,0x68,0x51,0x34,0x52,0x3a,0x25,0x09,0x07, +0x07,0x23,0x3d,0x59,0x3e,0x4e,0x75,0x4e,0x27,0x04,0x3a,0xfc,0x4b,0x14,0x2c,0x43,0x2f,0x32,0x46,0x2c,0x14,0x01,0xc2,0xfe,0xc0,0x13,0x27,0x3d,0x2b,0x52,0x4c,0x00,0x00,0x01,0x01,0x09,0x00,0x00,0x04,0x1a,0x04,0x3a,0x00,0x05,0x00,0x2c,0x40,0x1b,0x0f,0x00,0x1f,0x00,0x02,0x5f,0x00,0xff,0x00,0x02,0x9f,0x00,0xaf,0x00,0x02,0x00, +0x00,0x07,0x03,0x46,0x04,0x02,0x50,0x05,0x0f,0x03,0x15,0x00,0x3f,0x3f,0xed,0x01,0x2f,0xed,0x12,0x39,0x2f,0x5d,0x71,0x72,0x31,0x30,0x01,0x15,0x21,0x11,0x23,0x11,0x04,0x1a,0xfd,0xa3,0xb4,0x04,0x3a,0x8e,0xfc,0x54,0x04,0x3a,0x00,0x02,0x00,0x16,0xfe,0x68,0x04,0x76,0x04,0x3a,0x00,0x07,0x00,0x19,0x00,0x81,0x40,0x1d,0x74,0x14, +0x84,0x14,0x02,0x24,0x13,0x01,0x06,0x46,0x0f,0x01,0x16,0x60,0x16,0x70,0x16,0x80,0x16,0x03,0x0f,0x16,0x0f,0x16,0x0d,0x07,0x08,0x49,0x09,0xb8,0xff,0xc0,0xb3,0x26,0x2a,0x48,0x09,0xb8,0xff,0xc0,0x40,0x2b,0x1d,0x20,0x48,0x09,0x09,0x18,0x49,0x90,0x07,0xa0,0x07,0xc0,0x07,0xd0,0x07,0x04,0x07,0x07,0x1b,0x0c,0x49,0x9f,0x0d,0xaf, +0x0d,0xbf,0x0d,0xff,0x0d,0x04,0x0d,0x01,0x50,0x16,0x0f,0x18,0x06,0x0e,0x50,0x0b,0x15,0x0d,0x08,0xb8,0x01,0x08,0x00,0x3f,0x33,0x3f,0xed,0x32,0x32,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0xed,0x32,0x2f,0x2b,0x2b,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x10,0xcd,0x10,0xed,0x31,0x30,0x00,0x5d,0x5d,0x01,0x21,0x06, +0x02,0x0e,0x01,0x07,0x21,0x01,0x23,0x11,0x21,0x11,0x23,0x11,0x33,0x3e,0x05,0x37,0x21,0x11,0x33,0x03,0x3f,0xfe,0xc4,0x18,0x31,0x30,0x2f,0x17,0x01,0xfb,0x01,0x37,0xa3,0xfc,0xe6,0xa3,0x77,0x14,0x27,0x27,0x27,0x26,0x26,0x12,0x02,0x70,0x92,0x03,0xac,0xb1,0xff,0x00,0xba,0x81,0x32,0xfd,0xda,0x01,0x98,0xfe,0x68,0x02,0x26,0x21, +0x53,0x6e,0x8f,0xba,0xed,0x94,0xfc,0x54,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x04,0x4e,0x12,0x06,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x04,0xcb,0x04,0x3a,0x00,0x2a,0x00,0xee,0x40,0x38,0x0b,0x24,0x1b,0x24,0x02,0x04,0x06,0x14,0x06,0x02,0x0b,0x1b,0x1b,0x1b,0x02,0x0b,0x1a,0x1b,0x1a,0x02,0x04,0x11,0x14,0x11, +0x02,0x04,0x10,0x14,0x10,0x02,0x66,0x21,0x76,0x21,0x86,0x21,0x03,0x21,0x24,0x22,0x2a,0x69,0x09,0x79,0x09,0x89,0x09,0x03,0x06,0x09,0x08,0x17,0x2a,0x49,0x14,0x00,0xb8,0xff,0xc0,0x40,0x5b,0x26,0x2a,0x48,0x00,0x00,0x08,0x22,0x6b,0x1d,0x7b,0x1d,0x8b,0x1d,0x03,0x1d,0x1e,0x6b,0x23,0x7b,0x23,0x8b,0x23,0x03,0x1e,0x23,0x10,0x22, +0x70,0x22,0x80,0x22,0x03,0x22,0x22,0x2c,0x64,0x0e,0x74,0x0e,0x84,0x0e,0x03,0x0e,0x0d,0x64,0x07,0x74,0x07,0x84,0x07,0x03,0x0d,0x07,0x0f,0x08,0x3f,0x08,0x5f,0x08,0x8f,0x08,0x9f,0x08,0x05,0x4f,0x08,0x5f,0x08,0x9f,0x08,0xaf,0x08,0xcf,0x08,0xdf,0x08,0x06,0x08,0x40,0x24,0x2a,0x48,0x08,0x21,0x09,0x24,0x06,0x09,0x06,0x29,0x01, +0xb8,0x01,0x0a,0x40,0x0e,0x17,0x2f,0x14,0x01,0x14,0x14,0x1e,0x0d,0x15,0x0f,0x22,0x08,0x00,0x15,0x00,0x3f,0x32,0x32,0x3f,0x33,0x33,0x39,0x2f,0x5d,0x33,0xed,0x32,0x39,0x39,0x11,0x33,0x11,0x33,0x01,0x2f,0x2b,0x5d,0x71,0x33,0x33,0x5d,0x2f,0x33,0x5d,0x11,0x33,0x2f,0x5d,0x33,0x33,0x5d,0x2f,0x33,0x5d,0x11,0x12,0x39,0x2f,0x2b, +0x33,0xed,0x32,0x12,0x39,0x39,0x5d,0x11,0x12,0x39,0x39,0x5d,0x31,0x30,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x21,0x11,0x2e,0x03,0x27,0x03,0x23,0x01,0x2e,0x01,0x27,0x03,0x33,0x17,0x1e,0x03,0x17,0x11,0x33,0x11,0x3e,0x03,0x3f,0x01,0x33,0x03,0x06,0x07,0x01,0x23,0x03,0x0e,0x03,0x07,0x11,0x02,0x19,0x0f,0x20,0x1b,0x14,0x04,0xfd,0xb9, +0x01,0x4f,0x13,0x38,0x23,0xd8,0xb2,0x94,0x20,0x35,0x2f,0x2d,0x18,0x9a,0x18,0x2d,0x2f,0x35,0x20,0x94,0xb2,0xd8,0x47,0x28,0x01,0x50,0xb9,0xfd,0x04,0x14,0x1b,0x20,0x0f,0x01,0xe0,0x02,0x09,0x0c,0x0b,0x03,0xfd,0xfb,0x02,0x60,0x15,0x4b,0x35,0x01,0x45,0xef,0x33,0x4a,0x33,0x20,0x09,0x01,0xc8,0xfe,0x38,0x09,0x20,0x33,0x4a,0x33, +0xef,0xfe,0xbb,0x6a,0x2b,0xfd,0xa0,0x02,0x05,0x03,0x0b,0x0c,0x09,0x02,0xfe,0x20,0x00,0x01,0x00,0x8a,0xff,0xec,0x04,0x25,0x04,0x4e,0x00,0x39,0x00,0xa6,0x40,0x70,0x73,0x33,0x83,0x33,0x02,0x7a,0x2c,0x8a,0x2c,0x02,0x6a,0x10,0x01,0x0a,0x38,0x1a,0x38,0x02,0x05,0x27,0x15,0x27,0x25,0x27,0x03,0x2f,0x13,0x2a,0x46,0x19,0x13,0x19, +0x13,0x19,0x05,0x35,0x47,0x2f,0x0e,0x3f,0x0e,0x02,0x0e,0x0e,0x05,0x3b,0x74,0x21,0x84,0x21,0x02,0x21,0x49,0x40,0x22,0x50,0x22,0x02,0x22,0x74,0x06,0x84,0x06,0x02,0x06,0x49,0x22,0x05,0x40,0x12,0x16,0x48,0x00,0x05,0x01,0x05,0x2f,0x13,0x50,0x14,0x14,0x25,0x0b,0x00,0x21,0x60,0x21,0x70,0x21,0x80,0x21,0x04,0x20,0x21,0x90,0x21, +0xf0,0x21,0x03,0x21,0x21,0x1c,0x50,0x25,0x10,0x0b,0x50,0x00,0x06,0x06,0x00,0x16,0x00,0x3f,0x32,0x2f,0x10,0xed,0x3f,0xed,0x33,0x2f,0x5d,0x71,0x11,0x12,0x39,0x2f,0xed,0x39,0x01,0x2f,0x5d,0x2b,0x33,0xed,0x5d,0x2f,0x71,0xed,0x5d,0x11,0x12,0x39,0x2f,0x71,0xed,0x12,0x39,0x39,0x2f,0x2f,0x10,0xed,0x11,0x39,0x31,0x30,0x00,0x5d, +0x5d,0x5d,0x5d,0x5d,0x05,0x22,0x2e,0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x36,0x35,0x34,0x2e,0x02,0x23,0x35,0x32,0x3e,0x02,0x35,0x34,0x26,0x23,0x22,0x0e,0x02,0x07,0x27,0x3e,0x01,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x15,0x1e,0x03,0x15,0x14,0x0e,0x02,0x02,0x5a,0x66,0x9a,0x6f,0x4a,0x17,0x9f,0x0c,0x2f,0x4b,0x69,0x46, +0x86,0x82,0x4b,0x75,0x8b,0x41,0x41,0x86,0x6d,0x46,0x75,0x82,0x36,0x5c,0x47,0x2d,0x07,0xa2,0x18,0xd7,0xc1,0x68,0x9f,0x6e,0x38,0x34,0x50,0x60,0x2d,0x38,0x6c,0x54,0x33,0x35,0x6f,0xae,0x14,0x1f,0x3f,0x60,0x40,0x2c,0x27,0x3d,0x2a,0x16,0x5e,0x5b,0x3b,0x4e,0x2d,0x12,0x89,0x0f,0x26,0x43,0x34,0x4a,0x56,0x0d,0x21,0x38,0x2a,0x14, +0x89,0x79,0x2a,0x4c,0x68,0x3f,0x39,0x58,0x3d,0x23,0x05,0x02,0x06,0x29,0x43,0x5d,0x3a,0x45,0x77,0x57,0x31,0x00,0x00,0x00,0x00,0x01,0x00,0xb9,0x00,0x00,0x04,0x15,0x04,0x3a,0x00,0x13,0x00,0x58,0x40,0x3c,0x09,0x48,0x07,0x18,0x0e,0x11,0x48,0x49,0x07,0x01,0x07,0x20,0x0a,0x30,0x0a,0x02,0x60,0x0a,0x70,0x0a,0xb0,0x0a,0xc0,0x0a, +0xe0,0x0a,0x05,0x0a,0x0a,0x15,0x65,0x11,0x75,0x11,0x85,0x11,0x03,0x11,0x00,0x48,0x00,0x13,0x80,0x13,0x02,0x13,0x8a,0x10,0x01,0x10,0x07,0x13,0x0f,0x85,0x06,0x01,0x0a,0x06,0x12,0x15,0x00,0x3f,0x33,0x33,0x5d,0x3f,0x33,0x33,0x5d,0x01,0x2f,0x5d,0xed,0x32,0x5d,0x12,0x39,0x2f,0x71,0x72,0x33,0x5d,0x2b,0xed,0x31,0x30,0x01,0x11, +0x14,0x0e,0x02,0x07,0x01,0x33,0x11,0x23,0x11,0x34,0x3e,0x02,0x37,0x01,0x23,0x11,0x01,0x67,0x03,0x03,0x03,0x01,0x01,0xf3,0xc5,0xac,0x02,0x03,0x04,0x01,0xfe,0x06,0xc0,0x04,0x3a,0xfd,0xb0,0x17,0x4d,0x52,0x4a,0x15,0x03,0x65,0xfb,0xc6,0x02,0x94,0x13,0x39,0x3c,0x39,0x14,0xfc,0x97,0x04,0x3a,0x00,0x00,0x00,0xff,0xff,0x00,0xb9, +0x00,0x00,0x04,0x15,0x05,0xb4,0x12,0x26,0x01,0xd4,0x00,0x00,0x11,0x06,0x02,0x96,0xf3,0x00,0x00,0x13,0x40,0x0b,0x01,0x14,0x11,0x26,0x01,0x00,0x19,0x25,0x12,0x08,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x01,0x00,0xda,0x00,0x00,0x04,0x5c,0x04,0x3a,0x00,0x17,0x00,0xa6,0x40,0x35,0x72,0x0b,0x82,0x0b,0x02,0x74,0x0a,0x84, +0x0a,0x02,0x66,0x0a,0x01,0x7d,0x0f,0x8d,0x0f,0x02,0x4a,0x0f,0x5a,0x0f,0x6a,0x0f,0x03,0x8d,0x08,0x01,0x6b,0x08,0x7b,0x08,0x02,0x4a,0x08,0x5a,0x08,0x02,0x35,0x0d,0x65,0x0d,0x75,0x0d,0x85,0x0d,0x04,0x05,0x0d,0x15,0x0d,0x02,0x0d,0xb8,0xff,0xe8,0x40,0x3c,0x0c,0x11,0x48,0x29,0x07,0x79,0x07,0x89,0x07,0x03,0x0a,0x07,0x0d,0x10, +0x07,0x03,0x0e,0x08,0x72,0x09,0x82,0x09,0x02,0x09,0x09,0x0f,0x00,0x0e,0x01,0x0e,0x0e,0x19,0x02,0x16,0x46,0x00,0x17,0x60,0x17,0x70,0x17,0x80,0x17,0x04,0x17,0x0d,0x10,0x15,0x50,0x2f,0x02,0x01,0x02,0x02,0x17,0x0e,0x15,0x09,0x00,0x0f,0x00,0x3f,0x32,0x3f,0x33,0x39,0x2f,0x5d,0xed,0x39,0x39,0x01,0x2f,0x5d,0xed,0x32,0x11,0x33, +0x2f,0x5d,0x33,0x33,0x2f,0x5d,0x33,0x11,0x17,0x39,0x11,0x33,0x5d,0x31,0x30,0x00,0x2b,0x5d,0x01,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x13,0x33,0x11,0x32,0x3e,0x02,0x37,0x13,0x33,0x03,0x0e,0x01,0x07,0x01,0x23,0x01,0x0e,0x03,0x23,0x11,0x23,0xda,0xb4,0x32,0x55,0x50,0x4e,0x2a,0xb4,0xc2,0xe2,0x35,0x4c,0x15,0x01,0x81, +0xcc,0xfe,0xc3,0x12,0x30,0x35,0x36,0x18,0xb4,0x04,0x3a,0xfe,0x26,0x11,0x2d,0x50,0x3f,0x01,0x0d,0xfe,0xbb,0x4c,0x48,0x0f,0xfd,0xae,0x01,0xfd,0x08,0x0d,0x09,0x05,0xfe,0x26,0x00,0x00,0x00,0x01,0x00,0x06,0xff,0xec,0x04,0x18,0x04,0x3a,0x00,0x19,0x00,0x59,0x40,0x3a,0x07,0x20,0x0b,0x11,0x48,0x14,0x18,0x0b,0x0f,0x48,0x14,0x15, +0x01,0x17,0x10,0x0b,0x11,0x48,0x9f,0x02,0xaf,0x02,0xbf,0x02,0x03,0x02,0x10,0x17,0x70,0x17,0x80,0x17,0x03,0x17,0x17,0x0c,0x19,0x46,0xbf,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x1b,0x0c,0x02,0x50,0x17,0x0f,0x10,0x50,0x09,0x16,0x00,0x15,0x00,0x3f,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x12,0x39,0x2f,0x5d,0x5d,0xed,0x12,0x39,0x2f,0x5d, +0xcd,0x5d,0x2b,0x31,0x30,0x00,0x5d,0x01,0x2b,0x00,0x2b,0x21,0x11,0x21,0x06,0x02,0x0e,0x03,0x23,0x22,0x26,0x27,0x35,0x1e,0x01,0x33,0x32,0x3e,0x03,0x12,0x37,0x21,0x11,0x03,0x63,0xfe,0x83,0x1a,0x28,0x2b,0x32,0x44,0x5e,0x41,0x1d,0x30,0x11,0x0b,0x26,0x13,0x1f,0x32,0x29,0x26,0x25,0x2a,0x19,0x02,0xc6,0x03,0xac,0xb8,0xfe,0xe3, +0xd6,0x92,0x5b,0x28,0x08,0x05,0x81,0x04,0x05,0x2a,0x5e,0x95,0xd8,0x01,0x1d,0xb7,0xfb,0xc6,0x00,0x00,0x00,0x01,0x00,0x66,0x00,0x00,0x04,0x67,0x04,0x3a,0x00,0x20,0x00,0x96,0x40,0x1a,0x76,0x07,0x86,0x07,0x02,0x7b,0x08,0x8b,0x08,0x02,0x1e,0x20,0x0d,0x11,0x48,0x29,0x1e,0x39,0x1e,0x02,0x0b,0x1e,0x1b,0x1e,0x02,0x12,0xb8,0xff, +0xe0,0x40,0x4d,0x0d,0x11,0x48,0x36,0x12,0x01,0x04,0x12,0x14,0x12,0x24,0x12,0x03,0x08,0x07,0x18,0x77,0x18,0x87,0x18,0x02,0x18,0x10,0x1e,0x20,0x49,0xaf,0x00,0x01,0x10,0x00,0x20,0x00,0x02,0x20,0x00,0x30,0x00,0x70,0x00,0x80,0x00,0x04,0x00,0x00,0x22,0x12,0x0f,0x49,0x60,0x10,0x70,0x10,0xa0,0x10,0x03,0x10,0x06,0x09,0x09,0x1e, +0x11,0x0f,0x40,0x18,0x50,0x18,0x02,0x3f,0x18,0x01,0x00,0x08,0x18,0x03,0x10,0x15,0x00,0x3f,0x17,0x33,0x5d,0x5d,0x3f,0x33,0x33,0x11,0x33,0x01,0x2f,0x71,0xed,0x32,0x12,0x39,0x2f,0x5d,0x71,0x71,0xed,0x33,0x11,0x39,0x5d,0x11,0x33,0x33,0x31,0x30,0x5d,0x5d,0x2b,0x5d,0x5d,0x2b,0x5d,0x5d,0x21,0x11,0x34,0x3e,0x02,0x37,0x01,0x23, +0x01,0x1e,0x03,0x15,0x11,0x23,0x11,0x33,0x13,0x1e,0x03,0x17,0x3e,0x03,0x37,0x13,0x33,0x11,0x03,0xce,0x01,0x03,0x03,0x01,0xfe,0xe3,0x99,0xfe,0xda,0x02,0x02,0x01,0x01,0x9a,0xfa,0xc8,0x0a,0x15,0x12,0x0f,0x04,0x05,0x0f,0x12,0x14,0x0a,0xc8,0xef,0x02,0xd4,0x16,0x3c,0x40,0x3d,0x16,0xfc,0x47,0x03,0xb7,0x19,0x3d,0x3d,0x39,0x17, +0xfd,0x2c,0x04,0x3a,0xfd,0x7f,0x20,0x4d,0x51,0x50,0x24,0x24,0x51,0x51,0x4c,0x20,0x02,0x81,0xfb,0xc6,0x00,0x01,0x00,0xb5,0x00,0x00,0x04,0x18,0x04,0x3a,0x00,0x0b,0x00,0x3d,0x40,0x24,0x05,0x46,0x02,0x06,0x06,0x0d,0x01,0x09,0x46,0x9f,0x0a,0x01,0x3f,0x0a,0xef,0x0a,0x02,0x00,0x0a,0x80,0x0a,0x02,0x0a,0x08,0x51,0x2f,0x01,0x01, +0x01,0x01,0x0a,0x05,0x15,0x03,0x00,0x0f,0x00,0x3f,0x32,0x3f,0x33,0x39,0x2f,0x5d,0xed,0x01,0x2f,0x5d,0x71,0x72,0xed,0x32,0x12,0x39,0x2f,0x33,0xed,0x31,0x30,0x01,0x11,0x21,0x11,0x33,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x01,0x69,0x01,0xfb,0xb4,0xb4,0xfe,0x05,0xb4,0x04,0x3a,0xfe,0x36,0x01,0xca,0xfb,0xc6,0x01,0xed,0xfe,0x13, +0x04,0x3a,0x00,0x00,0xff,0xff,0x00,0x82,0xff,0xec,0x04,0x49,0x04,0x4e,0x12,0x06,0x00,0x52,0x00,0x00,0x00,0x01,0x00,0xb5,0x00,0x00,0x04,0x18,0x04,0x3a,0x00,0x07,0x00,0x2f,0x40,0x1c,0x01,0x46,0x02,0x02,0x09,0x05,0x46,0x9f,0x06,0x01,0x3f,0x06,0xef,0x06,0x02,0x00,0x06,0x80,0x06,0x02,0x06,0x04,0x50,0x07,0x0f,0x06,0x01,0x15, +0x00,0x3f,0x33,0x3f,0xed,0x01,0x2f,0x5d,0x71,0x72,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x01,0x11,0x23,0x11,0x21,0x11,0x23,0x11,0x04,0x18,0xb4,0xfe,0x05,0xb4,0x04,0x3a,0xfb,0xc6,0x03,0xac,0xfc,0x54,0x04,0x3a,0x00,0x00,0x00,0xff,0xff,0x00,0xb3,0xfe,0x57,0x04,0x42,0x04,0x50,0x12,0x06,0x00,0x53,0x00,0x00,0xff,0xff,0x00,0x82, +0xff,0xec,0x04,0x38,0x04,0x4e,0x12,0x06,0x00,0x46,0x00,0x00,0x00,0x01,0x00,0x82,0x00,0x00,0x04,0x4a,0x04,0x3a,0x00,0x07,0x00,0x38,0x40,0x1f,0x02,0x0e,0x04,0x07,0x05,0x0e,0x0f,0x07,0x01,0x07,0x04,0x46,0x4f,0x05,0x5f,0x05,0x02,0x00,0x05,0x01,0x05,0x05,0x08,0x09,0x04,0x15,0x03,0x07,0x50,0x00,0x0f,0x00,0x3f,0xed,0x32,0x3f, +0x11,0x12,0x01,0x39,0x2f,0x5d,0x5d,0xed,0xc6,0x5d,0x2b,0x01,0x18,0x10,0x4d,0xe6,0x31,0x30,0x13,0x21,0x15,0x21,0x11,0x23,0x11,0x21,0x82,0x03,0xc8,0xfe,0x76,0xb4,0xfe,0x76,0x04,0x3a,0x8e,0xfc,0x54,0x03,0xac,0x00,0x00,0x00,0xff,0xff,0x00,0x42,0xfe,0x57,0x04,0x89,0x04,0x3a,0x12,0x06,0x00,0x5c,0x00,0x00,0x00,0x03,0x00,0x46, +0xfe,0x57,0x04,0x85,0x05,0xcc,0x00,0x17,0x00,0x22,0x00,0x2d,0x00,0x8b,0xb3,0x44,0x2b,0x01,0x2c,0xb8,0xff,0xe0,0x40,0x17,0x0c,0x0f,0x48,0x02,0x2c,0x01,0x25,0x20,0x0c,0x0f,0x48,0x0d,0x25,0x01,0x21,0x20,0x0c,0x0f,0x48,0x0d,0x21,0x01,0x1a,0xb8,0xff,0xe0,0x40,0x35,0x0c,0x0f,0x48,0x02,0x1a,0x01,0x0b,0x0d,0x23,0x01,0x02,0x18, +0x01,0x0f,0x04,0x23,0x47,0x40,0x00,0x0e,0x06,0x0d,0x07,0x0e,0x18,0x47,0x0d,0x29,0x15,0x06,0x49,0x1d,0x12,0x07,0x07,0x2e,0x2f,0x13,0x00,0x28,0x1e,0x50,0x15,0x12,0x10,0x29,0x1d,0x50,0x05,0x08,0x16,0x06,0x1b,0x00,0x3f,0x3f,0x33,0xed,0x32,0x3f,0x33,0xed,0x32,0x3f,0x11,0x12,0x01,0x39,0x2f,0x33,0x33,0xed,0x32,0x32,0xd4,0xed, +0x2b,0x01,0x18,0x10,0x4d,0xf4,0x1a,0xed,0x5f,0x5e,0x5d,0x5d,0x31,0x30,0x00,0x5e,0x5d,0x2b,0x5d,0x2b,0x5d,0x2b,0x5d,0x2b,0x5d,0x01,0x14,0x0e,0x02,0x07,0x11,0x23,0x11,0x2e,0x03,0x35,0x34,0x3e,0x02,0x37,0x11,0x33,0x11,0x16,0x12,0x01,0x14,0x1e,0x02,0x17,0x11,0x0e,0x03,0x05,0x34,0x2e,0x02,0x27,0x11,0x3e,0x03,0x04,0x85,0x3f, +0x77,0xac,0x6e,0x9b,0x6b,0xad,0x7a,0x42,0x3e,0x78,0xae,0x70,0x9b,0xeb,0xe5,0xfc,0x7e,0x2c,0x4c,0x65,0x3a,0x3f,0x66,0x4a,0x28,0x02,0xc5,0x28,0x48,0x65,0x3e,0x3d,0x65,0x49,0x28,0x02,0x1e,0x82,0xc7,0x8b,0x50,0x0a,0xfe,0x67,0x01,0x98,0x09,0x4e,0x8b,0xc9,0x84,0x81,0xc6,0x8c,0x50,0x0a,0x01,0x81,0xfe,0x7f,0x13,0xfe,0xeb,0xfe, +0xfb,0x6e,0x9a,0x64,0x34,0x09,0x03,0x4e,0x09,0x36,0x64,0x97,0x6b,0x6e,0x99,0x63,0x34,0x08,0xfc,0xb3,0x09,0x36,0x64,0x98,0xff,0xff,0x00,0x5e,0x00,0x00,0x04,0x6d,0x04,0x3a,0x12,0x06,0x00,0x5b,0x00,0x00,0x00,0x01,0x00,0xb0,0xfe,0x68,0x04,0xa6,0x04,0x3a,0x00,0x0b,0x00,0x64,0x40,0x14,0x07,0x49,0xa0,0x08,0xb0,0x08,0x02,0x40, +0x08,0x50,0x08,0x02,0x90,0x08,0xa0,0x08,0xb0,0x08,0x03,0x08,0xb8,0xff,0xc0,0x40,0x27,0x26,0x2a,0x48,0x08,0x08,0x05,0x46,0x0f,0x02,0x01,0x02,0x02,0x0d,0x01,0x46,0x9f,0x0a,0xaf,0x0a,0xbf,0x0a,0x03,0x3f,0x0a,0xef,0x0a,0xff,0x0a,0x03,0x00,0x0a,0x01,0x0a,0x05,0x01,0x51,0x0a,0x15,0x08,0xb8,0x01,0x08,0xb2,0x03,0x00,0x0f,0x00, +0x3f,0x32,0x3f,0x3f,0xed,0x32,0x01,0x2f,0x5d,0x71,0x72,0xed,0x12,0x39,0x2f,0x71,0xed,0x32,0x2f,0x2b,0x5d,0x71,0x72,0xed,0x31,0x30,0x01,0x11,0x21,0x11,0x33,0x11,0x33,0x11,0x23,0x11,0x21,0x11,0x01,0x64,0x01,0xfb,0xb4,0x93,0xa3,0xfc,0xad,0x04,0x3a,0xfc,0x49,0x03,0xb7,0xfc,0x49,0xfd,0xe5,0x01,0x98,0x04,0x3a,0x00,0x00,0x00, +0x00,0x01,0x00,0x9a,0x00,0x00,0x03,0xfd,0x04,0x3a,0x00,0x19,0x00,0x54,0x40,0x38,0x0a,0x20,0x0d,0x11,0x48,0x11,0x20,0x0d,0x11,0x48,0x16,0x28,0x09,0x0e,0x48,0x0e,0x46,0x0b,0x0f,0x0f,0x01,0x4f,0x0f,0x5f,0x0f,0xbf,0x0f,0x03,0x0f,0x0f,0x1b,0x01,0x46,0x9f,0x18,0xaf,0x18,0x02,0x18,0x40,0x1c,0x21,0x48,0x00,0x18,0x01,0x18,0x06, +0x50,0x15,0x15,0x0e,0x15,0x0c,0x00,0x0f,0x00,0x3f,0x32,0x3f,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x2b,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x71,0x33,0xed,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x01,0x11,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x11,0x33,0x11,0x23,0x11,0x0e,0x03,0x23,0x22,0x26,0x35,0x11,0x01,0x4e,0x15,0x2f,0x4b,0x37,0x23,0x4e, +0x50,0x4f,0x25,0xb4,0xb4,0x26,0x5b,0x66,0x6c,0x36,0x92,0x94,0x04,0x3a,0xfe,0x6e,0x22,0x3b,0x2c,0x19,0x08,0x0f,0x13,0x0a,0x02,0x00,0xfb,0xc6,0x01,0xd2,0x0f,0x20,0x1b,0x11,0x9e,0x8a,0x01,0x9b,0x00,0x00,0x00,0x01,0x00,0x66,0x00,0x00,0x04,0x67,0x04,0x3a,0x00,0x0b,0x00,0x60,0x40,0x1a,0x07,0x49,0x04,0x04,0x00,0x0b,0x49,0x60, +0x08,0x70,0x08,0xa0,0x08,0xb0,0x08,0xc0,0x08,0xf0,0x08,0x06,0x70,0x08,0x80,0x08,0x02,0x08,0xb8,0xff,0xc0,0x40,0x24,0x30,0x34,0x48,0x4f,0x08,0x5f,0x08,0x02,0x20,0x08,0x30,0x08,0x02,0x08,0x08,0x0d,0x03,0x49,0x0f,0x00,0x01,0xcf,0x00,0xdf,0x00,0x02,0x00,0x09,0x05,0x01,0x0f,0x07,0x03,0x51,0x00,0x15,0x00,0x3f,0xed,0x32,0x3f, +0x33,0x33,0x01,0x2f,0x5d,0x71,0xed,0x12,0x39,0x2f,0x5d,0x5d,0x2b,0x5d,0x71,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x33,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x66,0xa0,0x01,0x10,0xa0,0x01,0x11,0xa0,0x04,0x3a,0xfc,0x49,0x03,0xb7,0xfc,0x49,0x03,0xb7,0xfb,0xc6,0x00,0x00,0x00,0x01,0x00,0x5c,0xfe,0x68,0x04,0xbd, +0x04,0x3a,0x00,0x0f,0x00,0x9c,0x40,0x22,0x07,0x49,0x04,0x04,0x00,0x08,0x0d,0x49,0x50,0x0e,0x60,0x0e,0x02,0x40,0x0e,0x50,0x0e,0x80,0x0e,0x90,0x0e,0x04,0x90,0x0e,0xa0,0x0e,0xb0,0x0e,0xe0,0x0e,0xf0,0x0e,0x05,0x0e,0xb8,0xff,0xc0,0x40,0x3e,0x26,0x2c,0x48,0x0e,0x0e,0x0b,0x49,0x8f,0x08,0x9f,0x08,0xdf,0x08,0xef,0x08,0x04,0x4f, +0x08,0x5f,0x08,0x9f,0x08,0xaf,0x08,0x04,0x08,0x40,0x2e,0x31,0x48,0x08,0x40,0x29,0x2c,0x48,0x08,0x40,0x17,0x1b,0x48,0x08,0x08,0x11,0x03,0x49,0x0f,0x00,0x01,0x1f,0x00,0xcf,0x00,0xdf,0x00,0x03,0x00,0x40,0x1e,0x21,0x48,0x00,0x0e,0xb8,0x01,0x08,0x40,0x0a,0x09,0x05,0x01,0x0f,0x0b,0x07,0x03,0x51,0x00,0x15,0x00,0x3f,0xed,0x32, +0x32,0x3f,0x33,0x33,0x3f,0x01,0x2f,0x2b,0x5d,0x71,0xed,0x12,0x39,0x2f,0x2b,0x2b,0x2b,0x5d,0x71,0xed,0x32,0x2f,0x2b,0x5d,0x71,0x72,0xed,0x11,0x12,0x39,0x2f,0xed,0x31,0x30,0x33,0x11,0x33,0x11,0x33,0x11,0x33,0x11,0x33,0x11,0x33,0x11,0x33,0x11,0x23,0x11,0x5c,0xa0,0xf9,0xa0,0xf9,0xa0,0x8f,0x8f,0x04,0x3a,0xfc,0x49,0x03,0xb7, +0xfc,0x49,0x03,0xb7,0xfc,0x49,0xfd,0xe5,0x01,0x98,0x00,0x00,0x00,0x02,0xff,0xff,0x00,0x00,0x04,0x7e,0x04,0x3a,0x00,0x0e,0x00,0x19,0x00,0x4b,0xb5,0x0b,0x06,0x1b,0x06,0x02,0x01,0xb8,0xff,0xe0,0x40,0x25,0x09,0x0c,0x48,0x0e,0x0f,0x46,0x09,0x09,0x0b,0x03,0x47,0x00,0x15,0x10,0x15,0x90,0x15,0xa0,0x15,0x04,0x15,0x15,0x1b,0x0b, +0x19,0x51,0x0e,0x0e,0x0f,0x0b,0x50,0x0c,0x0f,0x0f,0x51,0x09,0x15,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x01,0x2f,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0xed,0x32,0x31,0x30,0x00,0x2b,0x5d,0x01,0x32,0x16,0x15,0x14,0x0e,0x02,0x23,0x21,0x11,0x21,0x35,0x21,0x19,0x01,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x2b,0x01,0x02, +0xdf,0xcd,0xd2,0x34,0x68,0x9b,0x67,0xfe,0x67,0xfe,0xb8,0x01,0xfc,0xca,0x45,0x60,0x3b,0x1a,0x74,0x85,0xcb,0x02,0x70,0x93,0x9f,0x4a,0x76,0x52,0x2c,0x03,0xac,0x8e,0xfe,0x36,0xfe,0x0f,0x19,0x31,0x47,0x2e,0x5e,0x57,0x00,0x00,0x00,0x03,0x00,0x6a,0x00,0x00,0x04,0x62,0x04,0x3a,0x00,0x0c,0x00,0x17,0x00,0x1b,0x00,0x83,0xb7,0x0b, +0x06,0x1b,0x06,0x2b,0x06,0x03,0x01,0xb8,0xff,0xe0,0x40,0x16,0x09,0x0c,0x48,0x03,0x48,0xd0,0x13,0xe0,0x13,0x02,0x00,0x13,0x10,0x13,0x20,0x13,0x90,0x13,0xa0,0x13,0x05,0x13,0xb8,0xff,0xc0,0x40,0x17,0x1e,0x22,0x48,0x13,0x13,0x09,0x1b,0x49,0xb0,0x18,0xd0,0x18,0x02,0x10,0x18,0x20,0x18,0x90,0x18,0xa0,0x18,0x04,0x18,0xb8,0xff, +0xc0,0x40,0x1c,0x1f,0x22,0x48,0x18,0x18,0x1d,0x0c,0x0d,0x49,0x3f,0x09,0x01,0x10,0x09,0x01,0x09,0x17,0x51,0x0c,0x0c,0x19,0x0a,0x0f,0x0d,0x51,0x18,0x09,0x15,0x00,0x3f,0x33,0xed,0x3f,0x33,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x32,0x12,0x39,0x2f,0x2b,0x5d,0x71,0xed,0x12,0x39,0x2f,0x2b,0x5d,0x71,0xed,0x31,0x30,0x00,0x2b, +0x5d,0x01,0x32,0x16,0x15,0x14,0x0e,0x02,0x23,0x21,0x11,0x33,0x19,0x01,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x2b,0x01,0x01,0x11,0x33,0x11,0x01,0xa9,0xcd,0xd2,0x34,0x68,0x9b,0x67,0xfe,0xc0,0xa4,0x9b,0x42,0x5b,0x39,0x1a,0x71,0x7e,0x9c,0x02,0xb0,0xa4,0x02,0x70,0x93,0x9f,0x4a,0x76,0x52,0x2c,0x04,0x3a,0xfe,0x36,0xfe,0x0f,0x19, +0x31,0x47,0x2e,0x5e,0x57,0xfe,0x0d,0x04,0x3a,0xfb,0xc6,0x00,0x00,0x02,0x00,0xcc,0x00,0x00,0x04,0x29,0x04,0x3a,0x00,0x0c,0x00,0x17,0x00,0x45,0x40,0x2c,0x0b,0x06,0x1b,0x06,0x02,0x04,0x01,0x14,0x01,0x02,0x03,0x47,0x00,0x13,0x01,0x13,0x13,0x19,0x0c,0x0d,0x46,0x10,0x09,0x20,0x09,0x02,0x60,0x09,0x70,0x09,0x80,0x09,0x03,0x09, +0x17,0x51,0x0c,0x0c,0x0a,0x0f,0x0d,0x51,0x09,0x15,0x00,0x3f,0xed,0x3f,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x71,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x31,0x30,0x00,0x5d,0x5d,0x01,0x32,0x16,0x15,0x14,0x0e,0x02,0x23,0x21,0x11,0x33,0x19,0x01,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x2b,0x01,0x02,0x8a,0xcd,0xd2,0x34,0x68,0x9b,0x67,0xfe, +0x41,0xb4,0xf0,0x45,0x60,0x3b,0x1a,0x74,0x85,0xf1,0x02,0x70,0x93,0x9f,0x4a,0x76,0x52,0x2c,0x04,0x3a,0xfe,0x36,0xfe,0x0f,0x19,0x31,0x47,0x2e,0x5e,0x57,0x00,0x00,0x00,0x01,0x00,0x7c,0xff,0xec,0x04,0x3c,0x04,0x4e,0x00,0x2a,0x00,0xa5,0x40,0x73,0x78,0x08,0x88,0x08,0x02,0x77,0x24,0x87,0x24,0x02,0x65,0x0d,0x01,0x62,0x13,0x01, +0x45,0x13,0x55,0x13,0x02,0x4a,0x1a,0x5a,0x1a,0x6a,0x1a,0x03,0x00,0x17,0x10,0x17,0x40,0x17,0x50,0x17,0x04,0x17,0x17,0x0a,0x18,0x00,0x47,0x3f,0x15,0x4f,0x15,0xaf,0x15,0x03,0xcf,0x15,0xdf,0x15,0xff,0x15,0x03,0x60,0x15,0x01,0x15,0x15,0x0a,0x2c,0x20,0x47,0x21,0x21,0x0b,0x47,0xff,0x0a,0x01,0x00,0x0a,0x01,0x0a,0x16,0x51,0x17, +0x17,0x10,0x26,0x1f,0x20,0x01,0x20,0x20,0x1d,0x50,0x26,0x10,0x10,0x50,0x05,0x20,0x0b,0x70,0x0b,0x80,0x0b,0x03,0x00,0x0b,0x10,0x0b,0x60,0x0b,0xc0,0x0b,0x04,0x0b,0x0b,0x05,0x16,0x00,0x3f,0x33,0x2f,0x5d,0x71,0x10,0xed,0x3f,0xed,0x33,0x2f,0x5d,0x11,0x12,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x5d,0xed,0x33,0x2f,0xed,0x11,0x12,0x39, +0x2f,0x5d,0x5d,0x71,0xed,0x33,0x12,0x39,0x2f,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x21,0x35,0x21,0x2e,0x03,0x23,0x22,0x06,0x07,0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x04,0x3c,0x36,0x77,0xbf,0x89,0x64,0xa2,0x75,0x47,0x09,0xbe, +0x08,0x31,0x49,0x5d,0x36,0x4e,0x6f,0x48,0x25,0x04,0xfe,0x82,0x01,0x7e,0x04,0x26,0x48,0x6f,0x4e,0x76,0x8a,0x10,0xc0,0x0e,0x48,0x73,0x9d,0x62,0x5f,0xb4,0x8d,0x56,0x02,0x1e,0x78,0xcd,0x97,0x56,0x39,0x5e,0x7c,0x43,0x0c,0x36,0x51,0x35,0x1b,0x31,0x5d,0x87,0x56,0x83,0x54,0x82,0x58,0x2e,0x69,0x5b,0x0e,0x44,0x76,0x57,0x32,0x35, +0x80,0xd8,0x00,0x00,0x00,0x02,0x00,0x46,0xff,0xec,0x04,0x98,0x04,0x4e,0x00,0x1a,0x00,0x2e,0x00,0x8f,0x40,0x63,0x63,0x23,0x01,0x45,0x23,0x55,0x23,0x02,0x63,0x1d,0x01,0x45,0x1d,0x55,0x1d,0x02,0x6c,0x2d,0x01,0x4a,0x2d,0x5a,0x2d,0x02,0x6d,0x27,0x01,0x3a,0x27,0x4a,0x27,0x5a,0x27,0x03,0x09,0x13,0x01,0x08,0x0e,0x01,0x07,0x04, +0x01,0x1b,0x48,0x15,0x15,0x70,0x01,0x80,0x01,0xb0,0x01,0xc0,0x01,0xd0,0x01,0x05,0x01,0x01,0x17,0x0b,0x48,0x4f,0x25,0x5f,0x25,0x02,0x25,0x25,0x30,0x00,0x17,0x49,0x60,0x18,0x70,0x18,0x80,0x18,0x03,0x18,0x19,0x0f,0x18,0x15,0x16,0x51,0x00,0x00,0x06,0x20,0x50,0x10,0x16,0x2a,0x50,0x06,0x10,0x00,0x3f,0xed,0x3f,0xed,0x11,0x39, +0x2f,0xed,0x3f,0x3f,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x33,0x10,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x13,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x23,0x11,0x23,0x11,0x33,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e, +0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0xea,0xa9,0x09,0x42,0x67,0x87,0x4d,0x4f,0x8b,0x68,0x3d,0x38,0x65,0x8d,0x56,0x55,0x8e,0x66,0x3b,0x03,0xa7,0xa4,0xa4,0x01,0x54,0x26,0x3d,0x4d,0x27,0x29,0x4d,0x3c,0x24,0x28,0x3e,0x49,0x21,0x29,0x4f,0x3f,0x26,0x02,0x70,0x79,0xb3,0x77,0x3b,0x44,0x8c,0xd3,0x8f,0x8b,0xd2,0x8d,0x46, +0x43,0x83,0xbf,0x7c,0xfe,0x13,0x04,0x3a,0xfd,0xe2,0x7e,0xa4,0x62,0x27,0x29,0x63,0xa4,0x7b,0x7e,0xa5,0x62,0x28,0x27,0x62,0xa6,0x00,0x00,0x00,0x00,0x02,0x00,0x45,0x00,0x00,0x03,0xfb,0x04,0x3a,0x00,0x0d,0x00,0x16,0x00,0x7a,0x40,0x2f,0x04,0x18,0x09,0x0c,0x48,0x05,0x08,0x15,0x08,0x02,0x00,0x3f,0x03,0x01,0x03,0x03,0x06,0x16, +0x0b,0x46,0x0f,0x0c,0x5f,0x0c,0xaf,0x0c,0xff,0x0c,0x04,0x4f,0x0c,0x5f,0x0c,0x02,0x0c,0x0c,0x06,0x18,0x65,0x01,0x75,0x01,0x85,0x01,0x03,0x01,0x02,0xb8,0xff,0xf0,0x40,0x1d,0x02,0x40,0x0c,0x0f,0x48,0x02,0x02,0x12,0x47,0x9f,0x06,0x01,0x00,0x06,0x01,0x06,0x03,0x00,0x51,0x15,0x15,0x01,0x0f,0x51,0x09,0x0f,0x0c,0x01,0x15,0x00, +0x3f,0x33,0x3f,0xed,0x12,0x39,0x2f,0xed,0x32,0x01,0x2f,0x5d,0x5d,0xed,0x33,0x2f,0x2b,0x38,0x33,0x5d,0x11,0x12,0x39,0x2f,0x5d,0x71,0xed,0x33,0x12,0x39,0x2f,0x5d,0x33,0x31,0x30,0x00,0x5d,0x2b,0x09,0x01,0x23,0x01,0x2e,0x01,0x35,0x34,0x36,0x33,0x21,0x11,0x23,0x19,0x01,0x23,0x22,0x06,0x15,0x14,0x16,0x3b,0x01,0x02,0x4b,0xfe, +0xc5,0xcb,0x01,0x58,0x82,0x77,0xd8,0xcf,0x01,0xb0,0xb4,0xea,0x82,0x78,0x6b,0x7c,0xfd,0x01,0xca,0xfe,0x36,0x01,0xd7,0x1b,0xa3,0x7a,0x95,0x96,0xfb,0xc6,0x01,0xca,0x01,0xf1,0x5c,0x5d,0x5e,0x5d,0x00,0x00,0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0xc1,0x10,0x26,0x00,0x43,0x9e,0x0d,0x12,0x06,0x00,0x48,0x00,0x00,0x00,0x00, +0xff,0xff,0x00,0x85,0xff,0xec,0x04,0x46,0x05,0x7b,0x12,0x26,0x00,0x48,0x00,0x00,0x11,0x06,0x00,0x69,0x08,0x00,0x00,0x17,0x40,0x0d,0x03,0x02,0x2c,0x11,0x26,0x03,0x02,0x08,0x30,0x2e,0x15,0x1f,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x01,0x00,0x35,0xfe,0x57,0x04,0x19,0x05,0xcc,0x00,0x37,0x00,0x81,0x40,0x40, +0x74,0x12,0x84,0x12,0x02,0x35,0x0c,0x01,0x18,0x28,0x09,0x0f,0x48,0x05,0x11,0x15,0x11,0x25,0x11,0x75,0x11,0x85,0x11,0x05,0x9f,0x03,0xaf,0x03,0x02,0x1d,0x03,0x1d,0x03,0x32,0x15,0x46,0x26,0x26,0x39,0x05,0x02,0x32,0x46,0x33,0x36,0x36,0x37,0x00,0x33,0x80,0x33,0x02,0x33,0x05,0x35,0x51,0x02,0x36,0x36,0x00,0x2c,0x50,0x09,0x0f, +0xb8,0xff,0xc0,0x40,0x0e,0x09,0x0c,0x48,0x0f,0x0f,0x00,0x33,0x15,0x21,0x50,0x1a,0x1b,0x00,0x00,0x00,0x3f,0x3f,0xed,0x3f,0x12,0x39,0x2f,0x2b,0x33,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x01,0x2f,0x5d,0x33,0x33,0x2f,0x10,0xed,0x32,0x32,0x12,0x39,0x2f,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x31,0x30,0x00,0x5d,0x2b,0x5d,0x5d,0x13, +0x33,0x15,0x21,0x15,0x21,0x15,0x14,0x06,0x07,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x11,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x35,0x1e,0x01,0x33,0x32,0x3e,0x02,0x35,0x11,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x23,0x35,0x33,0xb9,0xb5,0x01,0x2b,0xfe,0xd5,0x06,0x03,0x03,0x18,0x40,0x52,0x69,0x40,0x53,0x82, +0x5a,0x2f,0x15,0x36,0x5d,0x48,0x22,0x41,0x1c,0x0d,0x24,0x0d,0x26,0x31,0x1b,0x0a,0x21,0x3b,0x50,0x30,0x3b,0x67,0x4d,0x2c,0xb4,0x84,0x84,0x05,0xcc,0x9d,0x83,0x84,0x32,0x65,0x2e,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfc,0xc7,0x3e,0x6a,0x4e,0x2d,0x04,0x05,0x8b,0x02,0x04,0x14,0x2b,0x43,0x2e,0x03,0x04,0x50,0x67,0x3d,0x18, +0x2d,0x55,0x7d,0x51,0xfd,0xab,0x04,0xac,0x83,0x00,0x00,0x00,0xff,0xff,0x01,0x09,0x00,0x00,0x04,0x1a,0x05,0xb4,0x12,0x26,0x01,0xcf,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x93,0x00,0x00,0x00,0x13,0x40,0x0b,0x01,0x06,0x11,0x26,0x01,0x67,0x06,0x09,0x04,0x00,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0x00,0x01,0x00,0x91, +0xff,0xec,0x04,0x51,0x04,0x4e,0x00,0x2a,0x00,0x8f,0x40,0x62,0x79,0x23,0x89,0x23,0x02,0x76,0x08,0x86,0x08,0x02,0x65,0x1e,0x01,0x63,0x18,0x01,0x45,0x18,0x55,0x18,0x02,0x4a,0x11,0x5a,0x11,0x6a,0x11,0x03,0x0f,0x14,0x1f,0x14,0x02,0x14,0x14,0x20,0x00,0x0a,0x47,0x0b,0x0b,0x21,0x47,0x00,0x20,0x10,0x20,0x60,0x20,0x03,0x20,0x20, +0x2c,0x13,0x16,0x47,0x00,0x00,0xd0,0x00,0x02,0x00,0x16,0x51,0x13,0x13,0x05,0x20,0x20,0x70,0x20,0x80,0x20,0x03,0x00,0x20,0x10,0x20,0x60,0x20,0xc0,0x20,0x04,0x20,0x20,0x1b,0x50,0x26,0x16,0x1f,0x0b,0x01,0x0b,0x0b,0x0e,0x50,0x05,0x10,0x00,0x3f,0xed,0x33,0x2f,0x5d,0x3f,0xed,0x33,0x2f,0x5d,0x71,0x11,0x39,0x2f,0xed,0x01,0x2f, +0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x13,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x01,0x23,0x22,0x0e,0x02,0x07,0x21,0x15,0x21,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x91,0x56,0x8d,0xb4,0x5f, +0x62,0x9d,0x73,0x49,0x0d,0xc0,0x10,0x8a,0x76,0x4e,0x6f,0x48,0x25,0x05,0x01,0x7e,0xfe,0x82,0x05,0x24,0x48,0x6f,0x4e,0x36,0x5d,0x49,0x31,0x08,0xbe,0x09,0x47,0x75,0xa2,0x64,0x89,0xbf,0x77,0x36,0x02,0x1e,0xa3,0xd8,0x80,0x35,0x32,0x57,0x76,0x44,0x0e,0x5b,0x69,0x2e,0x58,0x82,0x54,0x83,0x56,0x87,0x5d,0x31,0x1b,0x35,0x51,0x36, +0x0c,0x43,0x7c,0x5e,0x39,0x56,0x97,0xcd,0xff,0xff,0x00,0xa7,0xff,0xec,0x04,0x24,0x04,0x4b,0x12,0x06,0x00,0x56,0x00,0x00,0xff,0xff,0x00,0x8f,0x00,0x00,0x04,0x65,0x05,0xcc,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x01,0x4f,0x29,0x00,0x00,0x0b,0xb6,0x01,0x00,0x0a,0x0d,0x06,0x09,0x25,0x01,0x2b,0x35,0x00,0xff,0xff,0x00,0x8f, +0x00,0x00,0x04,0x65,0x05,0x7b,0x12,0x26,0x00,0xf1,0x00,0x00,0x11,0x06,0x00,0x69,0x29,0x00,0x00,0x17,0x40,0x0d,0x02,0x01,0x0a,0x11,0x26,0x02,0x01,0x14,0x0e,0x0c,0x03,0x01,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0xff,0xff,0x00,0x75,0xfe,0x57,0x03,0x44,0x05,0xcc,0x12,0x06,0x00,0x4d,0x00,0x00,0x00,0x02,0x00,0x19, +0xff,0xec,0x04,0xa7,0x04,0x3a,0x00,0x1f,0x00,0x2a,0x00,0x78,0x40,0x0b,0x0a,0x06,0x1a,0x06,0x02,0x04,0x01,0x14,0x01,0x02,0x0b,0xb8,0xff,0xe8,0x40,0x0d,0x17,0x1c,0x48,0x0b,0x28,0x12,0x16,0x48,0x0b,0xe0,0x1d,0x01,0x1d,0xb8,0xff,0xc0,0x40,0x2e,0x0d,0x11,0x48,0x1d,0x1d,0x14,0x1f,0x20,0x49,0x70,0x09,0x80,0x09,0x02,0x09,0x09, +0x14,0x03,0x49,0xe0,0x26,0x01,0x26,0x26,0x2c,0x00,0x14,0x01,0x14,0x2a,0x51,0x1f,0x1f,0x20,0x0b,0x51,0x1d,0x0f,0x17,0x50,0x11,0x16,0x20,0x51,0x09,0x15,0x00,0x3f,0xed,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x2b,0x5d,0xcd,0x2b,0x2b,0x31, +0x30,0x00,0x5d,0x5d,0x01,0x32,0x16,0x15,0x14,0x0e,0x02,0x2b,0x01,0x11,0x23,0x03,0x0e,0x03,0x23,0x22,0x26,0x27,0x35,0x16,0x33,0x32,0x3e,0x02,0x37,0x13,0x21,0x19,0x01,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x2b,0x01,0x03,0x1c,0xbd,0xce,0x34,0x64,0x93,0x5f,0xcf,0xa5,0x28,0x0f,0x2a,0x3f,0x5b,0x41,0x1d,0x26,0x11,0x15,0x25,0x23, +0x30,0x21,0x19,0x0c,0x35,0x01,0xc8,0x33,0x3e,0x57,0x38,0x19,0x6f,0x76,0x34,0x02,0x70,0x94,0x9e,0x4a,0x76,0x52,0x2c,0x03,0xc1,0xfe,0x45,0xa1,0xd0,0x7a,0x2f,0x06,0x05,0x81,0x07,0x26,0x60,0xa6,0x80,0x02,0x1d,0xfe,0x36,0xfe,0x05,0x1c,0x35,0x4a,0x2e,0x5e,0x61,0x00,0x00,0x02,0x00,0x5c,0x00,0x00,0x04,0xb0,0x04,0x3a,0x00,0x14, +0x00,0x1f,0x00,0x5e,0x40,0x3a,0x0a,0x0c,0x1a,0x0c,0x02,0x04,0x07,0x14,0x07,0x02,0x05,0x15,0x49,0x02,0x20,0x0f,0x30,0x0f,0x70,0x0f,0x80,0x0f,0x04,0x0f,0x0f,0x13,0x09,0x49,0x60,0x1b,0xe0,0x1b,0x02,0x1b,0x1b,0x21,0x01,0x12,0x49,0x1f,0x13,0x01,0x13,0x1f,0x11,0x51,0x05,0x01,0x01,0x00,0x15,0x51,0x13,0x0f,0x15,0x03,0x00,0x0f, +0x00,0x3f,0x32,0x3f,0x33,0xed,0x11,0x39,0x2f,0x33,0xed,0x32,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x33,0xed,0x32,0x31,0x30,0x00,0x5d,0x5d,0x13,0x11,0x21,0x11,0x33,0x11,0x33,0x32,0x16,0x15,0x14,0x0e,0x02,0x2b,0x01,0x11,0x21,0x11,0x23,0x11,0x01,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x2b,0x01, +0xf6,0x01,0x4b,0x9a,0x36,0xcd,0xd2,0x34,0x68,0x9b,0x67,0xd1,0xfe,0xb5,0x9a,0x02,0x7f,0x36,0x45,0x60,0x3b,0x1a,0x74,0x85,0x37,0x04,0x3a,0xfe,0x36,0x01,0xca,0xfe,0x36,0x93,0x9f,0x4a,0x76,0x52,0x2c,0x01,0xf7,0xfe,0x09,0x04,0x3a,0xfc,0x3b,0x1c,0x35,0x4a,0x2e,0x5e,0x61,0x00,0x00,0x00,0x00,0x01,0x00,0x35,0x00,0x00,0x04,0x19, +0x05,0xcc,0x00,0x27,0x00,0x73,0x40,0x3a,0x74,0x12,0x84,0x12,0x02,0x35,0x0c,0x01,0x05,0x11,0x15,0x11,0x25,0x11,0x75,0x11,0x85,0x11,0x05,0x9f,0x03,0xaf,0x03,0x02,0x03,0x03,0x22,0x15,0x46,0x16,0x16,0x29,0x05,0x02,0x22,0x46,0x23,0x27,0x23,0x26,0x26,0x00,0x23,0x80,0x23,0x02,0x23,0x05,0x25,0x51,0x02,0x26,0x26,0x00,0x1c,0x50, +0x09,0x0f,0xb8,0xff,0xc0,0x40,0x0a,0x09,0x0c,0x48,0x0f,0x0f,0x15,0x23,0x15,0x00,0x00,0x00,0x3f,0x3f,0x33,0x39,0x2f,0x2b,0x33,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x01,0x2f,0x5d,0x33,0x2f,0x11,0x33,0x10,0xed,0x32,0x32,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0x5d,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x13,0x33,0x15,0x21,0x15,0x21,0x15, +0x14,0x06,0x07,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x23,0x11,0x23,0x35,0x33,0xb9,0xb5,0x01,0x2b,0xfe,0xd5,0x06,0x03,0x03,0x18,0x40,0x52,0x69,0x40,0x53,0x82,0x5a,0x2f,0xb5,0x21,0x3b,0x50,0x30,0x3b,0x67,0x4d,0x2c,0xb4,0x84,0x84,0x05,0xcc,0x9d,0x83,0x84,0x32, +0x65,0x2e,0x2f,0x4c,0x35,0x1d,0x2c,0x5c,0x90,0x65,0xfd,0x4d,0x02,0x99,0x50,0x67,0x3d,0x18,0x2d,0x55,0x7d,0x51,0xfd,0xab,0x04,0xac,0x83,0x00,0xff,0xff,0x00,0xda,0x00,0x00,0x04,0x5c,0x05,0xb4,0x12,0x26,0x01,0xd6,0x00,0x00,0x11,0x06,0x00,0x74,0x6a,0x00,0x00,0x13,0x40,0x0b,0x01,0x18,0x11,0x26,0x01,0x35,0x18,0x1b,0x00,0x0e, +0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0xb9,0x00,0x00,0x04,0x15,0x05,0xc1,0x10,0x26,0x00,0x43,0x9e,0x0d,0x10,0x06,0x01,0xd4,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x42,0xfe,0x57,0x04,0x89,0x05,0xb4,0x12,0x26,0x00,0x5c,0x00,0x00,0x11,0x06,0x02,0x96,0xf1,0x00,0x00,0x13,0x40,0x0b,0x01,0x20,0x11,0x26,0x01,0x00, +0x25,0x31,0x11,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x01,0x00,0xb5,0xfe,0x57,0x04,0x18,0x04,0x3a,0x00,0x0b,0x00,0x3d,0x40,0x24,0x09,0x49,0x0a,0x0a,0x00,0x07,0x46,0x04,0x04,0x0d,0x03,0x46,0x9f,0x00,0x01,0x3f,0x00,0xef,0x00,0x02,0x00,0x00,0x80,0x00,0x02,0x00,0x09,0x1b,0x05,0x01,0x0f,0x08,0x03,0x51,0x00,0x15, +0x00,0x3f,0xed,0x33,0x3f,0x33,0x3f,0x01,0x2f,0x5d,0x71,0x72,0xed,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x33,0x11,0x33,0x11,0x21,0x11,0x33,0x11,0x21,0x11,0x23,0x11,0xb5,0xb4,0x01,0xfb,0xb4,0xfe,0xa0,0xa3,0x04,0x3a,0xfc,0x49,0x03,0xb7,0xfb,0xc6,0xfe,0x57,0x01,0xa9,0x00,0x00,0x01,0x00,0xe2,0x00,0x01,0x04,0x76, +0x06,0xa9,0x00,0x07,0x00,0x4b,0x40,0x14,0x03,0x5c,0x10,0x00,0x01,0xd0,0x00,0xe0,0x00,0xf0,0x00,0x03,0x00,0x00,0x90,0x00,0xa0,0x00,0x03,0x00,0xb8,0xff,0xc0,0x40,0x1a,0x1d,0x22,0x48,0x00,0x00,0x09,0x05,0x5a,0x00,0x06,0x01,0x00,0x06,0x10,0x06,0x02,0x06,0x04,0x5f,0x07,0x01,0x01,0x07,0x03,0x05,0x12,0x00,0x3f,0x3f,0x33,0x2f, +0x10,0xed,0x01,0x2f,0x5d,0x72,0xed,0x12,0x39,0x2f,0x2b,0x5d,0x71,0x72,0xed,0x31,0x30,0x01,0x11,0x33,0x11,0x21,0x11,0x23,0x11,0x03,0xc2,0xb4,0xfd,0x2b,0xbf,0x05,0x45,0x01,0x64,0xfe,0x00,0xfb,0x58,0x05,0x44,0x00,0x00,0x00,0x00,0x01,0x00,0xf4,0x00,0x00,0x04,0x06,0x05,0xcc,0x00,0x07,0x00,0x50,0x40,0x39,0x06,0x49,0x1f,0x03, +0x3f,0x03,0x02,0xb0,0x03,0x01,0x6f,0x03,0x7f,0x03,0x8f,0x03,0x03,0x00,0x03,0x01,0x03,0x03,0x09,0x00,0x46,0x2f,0x01,0x3f,0x01,0x4f,0x01,0xaf,0x01,0xbf,0x01,0xcf,0x01,0x06,0x3f,0x01,0xbf,0x01,0x02,0x01,0x40,0x2b,0x2e,0x48,0x01,0x04,0x00,0x07,0x50,0x02,0x0f,0x00,0x15,0x00,0x3f,0x3f,0xed,0x3f,0x01,0x2f,0x2b,0x5d,0x71,0xed, +0x12,0x39,0x2f,0x5d,0x5d,0x5d,0x71,0xed,0x31,0x30,0x21,0x23,0x11,0x21,0x11,0x33,0x11,0x21,0x01,0xa8,0xb4,0x02,0x6f,0xa3,0xfd,0xa2,0x04,0x3a,0x01,0x92,0xfd,0xe0,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa9,0x12,0x26,0x00,0x3a,0x00,0x00,0x11,0x07,0x00,0x43,0xff,0xc5,0x00,0xf5,0x00,0x15,0xb4,0x01,0x33,0x05,0x26,0x01, +0xb8,0xff,0xc5,0xb4,0x34,0x37,0x13,0x32,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x15,0x00,0x00,0x04,0xb8,0x05,0xb4,0x12,0x26,0x00,0x5a,0x00,0x00,0x11,0x06,0x00,0x43,0x88,0x00,0x00,0x15,0xb4,0x01,0x2b,0x11,0x26,0x01,0xb8,0xff,0x88,0xb4,0x2c,0x2f,0x0f,0x2a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00, +0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0xa9,0x12,0x26,0x00,0x3a,0x00,0x00,0x11,0x07,0x00,0x74,0x00,0x67,0x00,0xf5,0x00,0x13,0x40,0x0b,0x01,0x33,0x05,0x26,0x01,0x67,0x33,0x36,0x13,0x32,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x15,0x00,0x00,0x04,0xb8,0x05,0xb4,0x12,0x26,0x00,0x5a,0x00,0x00, +0x11,0x06,0x00,0x74,0x5e,0x00,0x00,0x13,0x40,0x0b,0x01,0x2b,0x11,0x26,0x01,0x5d,0x2b,0x2e,0x0f,0x2a,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x04,0xcc,0x06,0x5e,0x12,0x26,0x00,0x3a,0x00,0x00,0x11,0x07,0x00,0x69,0x00,0x01,0x00,0xe3,0x00,0x17,0x40,0x0d,0x02,0x01,0x33,0x05,0x26,0x02,0x01,0x00, +0x37,0x35,0x13,0x32,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00,0x00,0x00,0xff,0xff,0x00,0x15,0x00,0x00,0x04,0xb8,0x05,0x7b,0x12,0x26,0x00,0x5a,0x00,0x00,0x11,0x06,0x00,0x69,0x01,0x00,0x00,0x17,0x40,0x0d,0x02,0x01,0x2b,0x11,0x26,0x02,0x01,0x00,0x2f,0x2d,0x0f,0x2a,0x25,0x01,0x2b,0x35,0x35,0x00,0x2b,0x35,0x35,0x00, +0xff,0xff,0x00,0x24,0x00,0x00,0x04,0xa8,0x06,0xa9,0x12,0x26,0x00,0x3c,0x00,0x00,0x11,0x07,0x00,0x43,0xff,0xba,0x00,0xf5,0x00,0x15,0xb4,0x01,0x09,0x05,0x26,0x01,0xb8,0xff,0xba,0xb4,0x0a,0x0d,0x04,0x08,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0xff,0xff,0x00,0x42,0xfe,0x57,0x04,0x89,0x05,0xb4,0x12,0x26,0x00,0x5c,0x00,0x00, +0x11,0x06,0x00,0x43,0xc5,0x00,0x00,0x15,0xb4,0x01,0x20,0x11,0x26,0x01,0xb8,0xff,0xc6,0xb4,0x21,0x24,0x11,0x1f,0x25,0x01,0x2b,0x35,0x00,0x2b,0x35,0x00,0x00,0x00,0x00,0x01,0x01,0x4e,0x01,0xd0,0x03,0x7e,0x02,0x70,0x00,0x03,0x00,0x1d,0x00,0xb0,0x00,0x2f,0xb0,0x01,0xcd,0xb0,0x01,0xcd,0x01,0xb0,0x04,0x2f,0xb0,0x00,0xdc,0xb0, +0x03,0xcd,0xb0,0x03,0x10,0xb0,0x05,0xd6,0x00,0x30,0x31,0x01,0x35,0x21,0x15,0x01,0x4e,0x02,0x30,0x01,0xd0,0xa0,0xa0,0x00,0x00,0x01,0x01,0x4e,0x01,0xd0,0x03,0x7e,0x02,0x70,0x00,0x03,0x00,0x1d,0x00,0xb0,0x00,0x2f,0xb0,0x01,0xcd,0xb0,0x01,0xcd,0x01,0xb0,0x04,0x2f,0xb0,0x00,0xdc,0xb0,0x03,0xcd,0xb0,0x03,0x10,0xb0,0x05,0xd6, +0x00,0x30,0x31,0x01,0x35,0x21,0x15,0x01,0x4e,0x02,0x30,0x01,0xd0,0xa0,0xa0,0x00,0x00,0x01,0x00,0xaa,0x01,0xc3,0x04,0x22,0x02,0x4c,0x00,0x03,0x00,0x0f,0xb5,0x02,0x00,0x00,0xb9,0x01,0xbc,0x00,0x3f,0xed,0x01,0x2f,0x2f,0x31,0x30,0x13,0x35,0x21,0x15,0xaa,0x03,0x78,0x01,0xc3,0x89,0x89,0x00,0x01,0xff,0xf6,0x01,0xc3,0x04,0xd6, +0x02,0x4c,0x00,0x03,0x00,0x0f,0xb5,0x02,0x00,0x00,0xb9,0x01,0xbc,0x00,0x3f,0xed,0x01,0x2f,0x2f,0x31,0x30,0x03,0x35,0x21,0x15,0x0a,0x04,0xe0,0x01,0xc3,0x89,0x89,0x00,0x01,0xff,0xf6,0x01,0xc3,0x04,0xd6,0x02,0x4c,0x00,0x03,0x00,0x0e,0xb4,0x00,0x02,0x00,0xb9,0x01,0x00,0x2f,0xed,0x01,0x2f,0x2f,0x31,0x30,0x03,0x35,0x21,0x15, +0x0a,0x04,0xe0,0x01,0xc3,0x89,0x89,0x00,0x00,0x02,0xff,0xfb,0xfe,0x57,0x04,0xd1,0xff,0x84,0x00,0x03,0x00,0x07,0x00,0x27,0xb6,0x07,0x02,0x04,0x01,0x05,0xbb,0x04,0xb8,0xff,0xc0,0x40,0x0c,0x09,0x10,0x48,0x04,0x00,0xbb,0x01,0x40,0x09,0x0c,0x48,0x01,0x00,0x2f,0x2b,0xed,0x2f,0x2b,0xed,0x01,0x2f,0x33,0x2f,0x33,0x31,0x30,0x07, +0x35,0x21,0x15,0x05,0x35,0x21,0x15,0x05,0x04,0xd6,0xfb,0x2a,0x04,0xd6,0xdc,0x60,0x60,0xcd,0x60,0x60,0x00,0x01,0x01,0x8d,0x03,0x5e,0x03,0x3f,0x05,0xcc,0x00,0x03,0x00,0x2a,0xb5,0x06,0x01,0x16,0x01,0x02,0x01,0xb8,0xff,0xf0,0x40,0x11,0x0e,0x11,0x48,0x03,0x9a,0x00,0x97,0x01,0x99,0x00,0x02,0x01,0x02,0x01,0x9c,0x00,0x00,0x00, +0x3f,0xed,0x01,0x2f,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x01,0x03,0x21,0x01,0x03,0x3f,0xa9,0xfe,0xf7,0x01,0x37,0x05,0xcc,0xfd,0x92,0x02,0x6e,0x00,0x00,0x00,0x00,0x01,0x01,0x8f,0x03,0x5e,0x03,0x41,0x05,0xcc,0x00,0x03,0x00,0x33,0x40,0x22,0x00,0x18,0x0e,0x11,0x48,0x09,0x00,0x19,0x00,0x02,0x09,0x02,0x19,0x02,0x02,0x02, +0x10,0x0e,0x11,0x48,0x01,0x99,0x02,0x97,0x03,0x9a,0x00,0x00,0x01,0x00,0x03,0x9c,0x01,0x00,0x00,0x3f,0xed,0x01,0x2f,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x5d,0x2b,0x01,0x13,0x21,0x01,0x01,0x8f,0xa9,0x01,0x09,0xfe,0xc9,0x03,0x5e,0x02,0x6e,0xfd,0x92,0x00,0x00,0x00,0x01,0x01,0x5d,0xfe,0x95,0x03,0x0f,0x01,0x03,0x00,0x03, +0x00,0x3b,0x40,0x28,0x00,0x18,0x0e,0x11,0x48,0x09,0x00,0x19,0x00,0x02,0x09,0x02,0x19,0x02,0x02,0x02,0x10,0x0e,0x11,0x48,0x01,0x99,0x02,0x97,0x03,0x9a,0x2f,0x00,0x01,0x00,0x00,0x10,0x00,0x02,0x00,0x00,0x9c,0x01,0x9b,0x04,0x00,0x10,0xf6,0xed,0x01,0x2f,0x5d,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x5d,0x2b,0x01,0x13,0x21, +0x01,0x01,0x5d,0xa9,0x01,0x09,0xfe,0xc9,0xfe,0x95,0x02,0x6e,0xfd,0x92,0x00,0x00,0x00,0x01,0x01,0x8e,0x03,0x5e,0x03,0x40,0x05,0xcc,0x00,0x03,0x00,0x37,0x40,0x10,0x00,0x18,0x0e,0x11,0x48,0x09,0x00,0x19,0x00,0x02,0x06,0x02,0x16,0x02,0x02,0x02,0xb8,0xff,0xf0,0x40,0x11,0x0e,0x11,0x48,0x00,0x9a,0x03,0x97,0x02,0x99,0x00,0x01, +0x01,0x01,0x00,0x9c,0x02,0x00,0x00,0x3f,0xed,0x01,0x2f,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x5d,0x2b,0x09,0x01,0x21,0x13,0x02,0xc5,0xfe,0xc9,0x01,0x09,0xa9,0x03,0x5e,0x02,0x6e,0xfd,0x92,0x00,0x00,0x00,0x02,0x00,0xb1,0x03,0x5e,0x04,0x1a,0x05,0xcc,0x00,0x03,0x00,0x07,0x00,0x57,0xb5,0x06,0x05,0x16,0x05,0x02,0x05,0xb8, +0xff,0xf0,0x40,0x09,0x0e,0x11,0x48,0x06,0x01,0x16,0x01,0x02,0x01,0xb8,0xff,0xf0,0x40,0x26,0x0e,0x11,0x48,0x07,0x9a,0x04,0x97,0x05,0x99,0x2f,0x06,0x9f,0x06,0x02,0x00,0x06,0x10,0x06,0x02,0x06,0x03,0x9a,0x00,0x97,0x01,0x99,0x00,0x02,0x10,0x02,0x02,0x02,0x05,0x07,0x01,0x9c,0x03,0x00,0x00,0x3f,0xed,0x33,0x32,0x01,0x2f,0x5d, +0xed,0xfd,0xed,0x2f,0x5d,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x2b,0x5d,0x01,0x03,0x21,0x01,0x21,0x03,0x21,0x01,0x02,0x63,0xa9,0xfe,0xf7,0x01,0x37,0x02,0x32,0xa9,0xfe,0xf7,0x01,0x37,0x05,0xcc,0xfd,0x92,0x02,0x6e,0xfd,0x92,0x02,0x6e,0x00,0x00,0x02,0x00,0xb2,0x03,0x5e,0x04,0x1b,0x05,0xcc,0x00,0x03,0x00,0x07,0x00,0x68, +0x40,0x4b,0x04,0x18,0x0e,0x11,0x48,0x09,0x04,0x19,0x04,0x02,0x09,0x06,0x19,0x06,0x02,0x06,0x10,0x0e,0x11,0x48,0x00,0x18,0x0e,0x11,0x48,0x09,0x00,0x19,0x00,0x02,0x09,0x02,0x19,0x02,0x02,0x02,0x10,0x0e,0x11,0x48,0x05,0x99,0x06,0x97,0x07,0x9a,0x00,0x04,0x10,0x04,0x90,0x04,0x03,0x04,0x01,0x99,0x02,0x97,0x03,0x9a,0x2f,0x00, +0x01,0x00,0x00,0x10,0x00,0x02,0x00,0x07,0x05,0x03,0x9c,0x01,0x00,0x00,0x3f,0xed,0x33,0x32,0x01,0x2f,0x5d,0x5d,0xed,0xfd,0xed,0x2f,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x5d,0x2b,0x2b,0x5d,0x5d,0x2b,0x01,0x13,0x21,0x01,0x21,0x13,0x21,0x01,0x02,0x69,0xa9,0x01,0x09,0xfe,0xc9,0xfd,0xce,0xa9,0x01,0x09,0xfe,0xc9,0x03,0x5e, +0x02,0x6e,0xfd,0x92,0x02,0x6e,0xfd,0x92,0x00,0x02,0x00,0xb2,0xfe,0x94,0x04,0x1b,0x01,0x02,0x00,0x03,0x00,0x07,0x00,0x6a,0x40,0x4c,0x04,0x18,0x0e,0x11,0x48,0x09,0x04,0x19,0x04,0x02,0x09,0x06,0x19,0x06,0x02,0x06,0x10,0x0e,0x11,0x48,0x00,0x18,0x0e,0x11,0x48,0x09,0x00,0x19,0x00,0x02,0x09,0x02,0x19,0x02,0x02,0x02,0x10,0x0e, +0x11,0x48,0x05,0x99,0x06,0x97,0x07,0x9a,0x00,0x04,0x10,0x04,0x90,0x04,0x03,0x04,0x01,0x99,0x02,0x97,0x03,0x9a,0x2f,0x00,0x01,0x00,0x00,0x10,0x00,0x02,0x00,0x04,0x00,0x9c,0x05,0x01,0x9b,0x08,0x00,0x10,0xf4,0x32,0xed,0x32,0x01,0x2f,0x5d,0x5d,0xed,0xfd,0xed,0x2f,0x5d,0xed,0xfd,0xed,0x31,0x30,0x2b,0x5d,0x5d,0x2b,0x2b,0x5d, +0x5d,0x2b,0x01,0x13,0x21,0x01,0x21,0x13,0x21,0x01,0x02,0x69,0xa9,0x01,0x09,0xfe,0xc9,0xfd,0xce,0xa9,0x01,0x09,0xfe,0xc9,0xfe,0x94,0x02,0x6e,0xfd,0x92,0x02,0x6e,0xfd,0x92,0x00,0x00,0x00,0x01,0x00,0xb6,0xff,0x2b,0x04,0x16,0x05,0xcb,0x00,0x0b,0x00,0x2c,0x40,0x18,0x0a,0xc0,0x08,0xbe,0x05,0xc0,0x00,0x07,0x10,0x07,0x02,0x07, +0x07,0x0c,0x0d,0x0b,0x04,0xc1,0x0a,0x05,0xc2,0x07,0x00,0x02,0x00,0x2f,0x3f,0xf6,0x32,0xed,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0xe6,0xfd,0xe6,0x31,0x30,0x01,0x03,0x23,0x03,0x05,0x35,0x05,0x03,0x33,0x03,0x25,0x15,0x02,0xad,0x0e,0x73,0x0e,0xfe,0x98,0x01,0x68,0x1a,0xc3,0x1a,0x01,0x69,0x03,0xdd,0xfb,0x4e,0x04,0xb2,0x11,0xa4, +0x13,0x01,0x6e,0xfe,0x92,0x13,0xa4,0x00,0x00,0x01,0x00,0xb6,0xff,0x2b,0x04,0x16,0x05,0xcb,0x00,0x15,0x00,0x42,0x40,0x24,0x00,0x11,0xc0,0x14,0x03,0x0f,0xbe,0x07,0x0c,0xc0,0x09,0x04,0x00,0x0e,0x10,0x0e,0x02,0x0e,0x0e,0x16,0x17,0x12,0x0b,0xc1,0x11,0x0c,0xc2,0x0e,0x00,0x00,0x07,0xc1,0x01,0x06,0xc2,0x04,0x00,0x2f,0xf6,0x32, +0xed,0x32,0x3f,0xf6,0x32,0xed,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0x33,0x33,0xe6,0x32,0xfd,0x32,0x32,0xe6,0x32,0x31,0x30,0x01,0x15,0x25,0x13,0x23,0x13,0x05,0x35,0x05,0x13,0x03,0x05,0x35,0x05,0x03,0x33,0x03,0x25,0x15,0x25,0x03,0x13,0x04,0x16,0xfe,0x97,0x1a,0xc3,0x1a,0xfe,0x98,0x01,0x68,0x22,0x22,0xfe,0x98,0x01,0x68,0x1a, +0xc3,0x1a,0x01,0x69,0xfe,0x97,0x22,0x22,0x01,0x2a,0xa4,0x13,0xfe,0x92,0x01,0x6e,0x13,0xa4,0x11,0x01,0x62,0x01,0x62,0x11,0xa4,0x13,0x01,0x6e,0xfe,0x92,0x13,0xa4,0x11,0xfe,0x9e,0xfe,0x9e,0x00,0x00,0x00,0x00,0x01,0x01,0x50,0x01,0x91,0x03,0x7b,0x03,0xbc,0x00,0x13,0x00,0x37,0x40,0x25,0x15,0x11,0x25,0x11,0x35,0x11,0x03,0x15, +0x0d,0x25,0x0d,0x35,0x0d,0x03,0x1a,0x07,0x2a,0x07,0x3a,0x07,0x03,0x1a,0x03,0x2a,0x03,0x3a,0x03,0x03,0x00,0x00,0x10,0x0a,0x01,0x0a,0x05,0x05,0x0f,0x00,0x2f,0x33,0x2f,0x01,0x2f,0x5d,0x33,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x03,0x7b,0x2c, +0x4d,0x66,0x3a,0x39,0x63,0x4b,0x2b,0x2b,0x4b,0x63,0x39,0x3a,0x66,0x4d,0x2c,0x02,0xaa,0x3a,0x66,0x4c,0x2d,0x2d,0x4c,0x66,0x3a,0x39,0x64,0x4a,0x2b,0x2b,0x4a,0x64,0x00,0x03,0x00,0x75,0x00,0x00,0x04,0x58,0x00,0xdb,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x3c,0x40,0x24,0x0b,0x98,0x08,0x04,0x03,0x98,0x00,0x07,0x98,0x10,0x04,0x50, +0x04,0x02,0x10,0x04,0x90,0x04,0xa0,0x04,0xc0,0x04,0xd0,0x04,0x05,0x04,0x04,0x0c,0x0d,0x09,0x05,0x01,0x9b,0x08,0x04,0x00,0x00,0x2f,0x32,0x32,0xed,0x32,0x32,0x11,0x12,0x01,0x39,0x2f,0x5d,0x71,0xed,0xd4,0xed,0x10,0xd4,0xed,0x31,0x30,0x21,0x35,0x33,0x15,0x21,0x35,0x33,0x15,0x21,0x35,0x33,0x15,0x03,0xaa,0xae,0xfd,0xb9,0xac, +0xfd,0xb8,0xaf,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x04,0xcc,0x05,0x83,0x00,0x03,0x00,0x17,0x00,0x2b,0x00,0x3f,0x00,0x53,0x00,0x67,0x00,0x7b,0x00,0xed,0xb9,0x00,0x66,0xff,0xd8,0x40,0x0e,0x09,0x0e,0x48,0x60,0x28,0x09,0x0c,0x48,0x5c,0x28,0x09,0x0c,0x48,0x56,0xb8,0xff,0xd8,0xb3,0x09, +0x0e,0x48,0x3e,0xb8,0xff,0xd8,0x40,0x0e,0x09,0x0e,0x48,0x38,0x28,0x09,0x0c,0x48,0x34,0x28,0x09,0x0c,0x48,0x2e,0xb8,0xff,0xd8,0xb3,0x09,0x0e,0x48,0x16,0xb8,0xff,0xd8,0x40,0x0e,0x09,0x0e,0x48,0x10,0x28,0x09,0x0c,0x48,0x0c,0x28,0x09,0x0c,0x48,0x06,0xb8,0xff,0xd8,0x40,0x11,0x09,0x0e,0x48,0x4b,0x02,0x5b,0x02,0x6b,0x02,0x03, +0x02,0x03,0x00,0x01,0x03,0x10,0x01,0xb8,0xff,0xf0,0x40,0x44,0x03,0x40,0x09,0x0f,0x48,0x03,0x01,0x03,0x01,0x31,0x13,0x4a,0xb4,0x3b,0xb5,0x40,0xb4,0x31,0x31,0x68,0x13,0x72,0xb4,0x63,0xb5,0x59,0xb4,0x68,0x68,0x13,0x7d,0x18,0xb4,0x09,0xb5,0x22,0xb4,0x13,0x02,0x00,0x02,0x00,0x04,0x36,0x6d,0xb6,0x54,0xb7,0x77,0xb6,0x5e,0x19, +0x45,0xb6,0x2c,0xb7,0x4f,0xb6,0x36,0x19,0x27,0xb6,0x0e,0xb7,0x1d,0xb6,0x04,0x07,0x00,0x3f,0xed,0xf4,0xed,0x3f,0xed,0xf4,0xed,0x3f,0xed,0xf4,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x01,0x2f,0xed,0xf4,0xed,0x11,0x12,0x39,0x2f,0xfd,0xf4,0xed,0x11,0x12,0x39,0x2f,0xed,0xf4,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x2b,0x38,0x38,0x11, +0x33,0x11,0x33,0x5d,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x13,0x23,0x01,0x33,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x13,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x13,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23, +0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x13,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x13,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x93,0x91,0x02,0x47,0x93,0xfe,0x10,0x2f,0x53, +0x3e,0x24,0x24,0x3f,0x55,0x30,0x31,0x55,0x3e,0x24,0x24,0x3f,0x56,0x95,0x0d,0x19,0x25,0x18,0x1a,0x28,0x1a,0x0d,0x0d,0x1b,0x27,0x19,0x17,0x24,0x1b,0x0e,0xa1,0x2f,0x53,0x3f,0x24,0x24,0x3f,0x55,0x30,0x31,0x55,0x3f,0x24,0x24,0x3f,0x57,0x95,0x0d,0x1a,0x25,0x18,0x1a,0x27,0x1b,0x0d,0x0e,0x1a,0x27,0x19,0x17,0x25,0x1b,0x0e,0x01, +0x96,0x2f,0x53,0x3e,0x24,0x24,0x3f,0x55,0x30,0x31,0x54,0x3f,0x24,0x24,0x3f,0x57,0x95,0x0d,0x1a,0x25,0x18,0x1a,0x28,0x1a,0x0d,0x0d,0x1b,0x27,0x19,0x17,0x25,0x1a,0x0f,0x01,0x8b,0x02,0x7f,0x01,0x79,0x1b,0x44,0x72,0x57,0x54,0x74,0x46,0x1f,0x1f,0x46,0x74,0x54,0x57,0x72,0x44,0x1b,0xfe,0xd8,0x37,0x48,0x2b,0x12,0x12,0x2c,0x48, +0x36,0x35,0x48,0x2c,0x13,0x13,0x2c,0x48,0xfe,0x2f,0x1b,0x44,0x72,0x57,0x54,0x74,0x46,0x1f,0x1f,0x46,0x74,0x54,0x57,0x72,0x44,0x1b,0xfe,0xd8,0x37,0x48,0x2b,0x12,0x12,0x2c,0x48,0x36,0x35,0x48,0x2c,0x13,0x13,0x2c,0x48,0x01,0x5d,0x1b,0x44,0x72,0x57,0x54,0x74,0x46,0x1f,0x1f,0x46,0x74,0x54,0x57,0x72,0x44,0x1b,0xfe,0xd8,0x37, +0x48,0x2b,0x12,0x12,0x2c,0x48,0x36,0x35,0x48,0x2c,0x13,0x13,0x2c,0x48,0x00,0x00,0x00,0x01,0x01,0xf6,0x03,0x4d,0x02,0xd6,0x05,0xcc,0x00,0x03,0x00,0x1c,0x40,0x0d,0x03,0x96,0x00,0x02,0x01,0x02,0x02,0x04,0x05,0x00,0x00,0x02,0x00,0x00,0x3f,0x33,0x2f,0x11,0x12,0x01,0x39,0x2f,0x5d,0xed,0x31,0x30,0x01,0x23,0x03,0x33,0x02,0xac, +0x8d,0x29,0xe0,0x03,0x4d,0x02,0x7f,0x00,0x00,0x02,0x01,0x15,0x03,0x4d,0x03,0xb6,0x05,0xcc,0x00,0x03,0x00,0x07,0x00,0x27,0x40,0x14,0x03,0x96,0x02,0x02,0x09,0x07,0x96,0x2f,0x06,0x01,0x00,0x06,0x01,0x06,0x05,0x00,0x00,0x06,0x02,0x00,0x00,0x3f,0x33,0x33,0x2f,0x32,0x01,0x2f,0x5d,0x5d,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x01, +0x23,0x03,0x33,0x01,0x23,0x03,0x33,0x03,0x8c,0x8e,0x28,0xe0,0xfe,0x15,0x8d,0x29,0xe0,0x03,0x4d,0x02,0x7f,0xfd,0x81,0x02,0x7f,0x00,0x00,0x00,0x00,0x01,0x01,0x5a,0x00,0x8d,0x03,0x5d,0x03,0xac,0x00,0x08,0x00,0x2e,0x40,0x18,0x00,0xeb,0x08,0x03,0xeb,0x04,0xec,0x06,0xeb,0x4f,0x01,0x01,0x00,0x01,0x01,0x01,0x02,0x01,0x06,0x06, +0x03,0xef,0x00,0xee,0x00,0x3f,0xe4,0x39,0x3d,0x2f,0x33,0x33,0x01,0x18,0x2f,0x5d,0x5d,0xed,0xfd,0xed,0xd4,0xed,0x31,0x30,0x25,0x01,0x35,0x01,0x33,0x15,0x09,0x01,0x15,0x02,0xaa,0xfe,0xb0,0x01,0x50,0xb1,0xfe,0xb1,0x01,0x51,0x8d,0x01,0x6d,0x3f,0x01,0x73,0x1f,0xfe,0x8c,0xfe,0x91,0x1d,0x00,0x01,0x01,0x6e,0x00,0x8d,0x03,0x71, +0x03,0xac,0x00,0x08,0x00,0x30,0x40,0x1a,0x03,0xeb,0x08,0xec,0x01,0x06,0xeb,0x05,0x00,0xeb,0x00,0x01,0x60,0x01,0xd0,0x01,0x03,0x01,0x08,0x07,0x03,0x03,0x06,0xef,0x00,0xee,0x00,0x3f,0xe4,0x39,0x3d,0x2f,0x33,0x33,0x01,0x18,0x2f,0x5d,0xed,0xd4,0xed,0x10,0xfd,0xed,0x31,0x30,0x25,0x23,0x35,0x09,0x01,0x35,0x33,0x01,0x15,0x02, +0x20,0xb2,0x01,0x52,0xfe,0xb0,0xb0,0x01,0x51,0x8d,0x1d,0x01,0x6f,0x01,0x74,0x1f,0xfe,0x8d,0x3f,0x00,0x00,0x04,0x00,0xed,0x00,0x00,0x03,0xe0,0x05,0x44,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x0f,0x00,0x3c,0x40,0x20,0x0b,0x0a,0x0f,0x98,0x00,0x0c,0x01,0x0c,0x0c,0x11,0x03,0x07,0x98,0x02,0x00,0x04,0x10,0x04,0x02,0x04,0x09,0x01, +0x01,0x02,0x0d,0x05,0x9d,0x0c,0x04,0x0a,0x02,0x03,0x00,0x3f,0x33,0x2f,0x33,0xed,0x32,0x11,0x39,0x2f,0x33,0x01,0x2f,0x5d,0x33,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x33,0x32,0x31,0x30,0x01,0x23,0x03,0x33,0x03,0x35,0x33,0x15,0x01,0x23,0x03,0x33,0x03,0x35,0x33,0x15,0x01,0x9b,0x94,0x18,0xc4,0xc6,0xc2,0x02,0x19,0x94,0x18,0xc4, +0xc6,0xc2,0x01,0x8d,0x03,0xb7,0xfa,0xbc,0xc9,0xc9,0x01,0x8d,0x03,0xb7,0xfa,0xbc,0xc9,0xc9,0x00,0x00,0xff,0xff,0xff,0xfb,0x05,0xac,0x04,0xd1,0x06,0x0c,0x12,0x07,0x00,0x42,0x00,0x00,0x06,0x88,0x00,0x00,0x00,0x01,0x00,0xcc,0x00,0x00,0x03,0xfe,0x05,0x45,0x00,0x03,0x00,0x27,0xb7,0x02,0x03,0x10,0x03,0x03,0x05,0x00,0x01,0xb8, +0xff,0xf0,0x40,0x0a,0x00,0x01,0x10,0x01,0x02,0x01,0x02,0x06,0x00,0x18,0x00,0x3f,0x3f,0x01,0x2f,0x5d,0x38,0x33,0x12,0x39,0x2f,0x38,0x33,0x31,0x30,0x21,0x23,0x01,0x33,0x01,0x42,0x76,0x02,0xbf,0x73,0x05,0x45,0x00,0x00,0x00,0x00,0x01,0x01,0x65,0x02,0x07,0x03,0x83,0x04,0x9d,0x00,0x21,0x00,0x41,0xb9,0x00,0x1e,0xff,0xd8,0x40, +0x22,0x09,0x11,0x48,0x21,0xe0,0x00,0x00,0x23,0x17,0x0a,0xe0,0x00,0x0b,0x01,0x0b,0x17,0x06,0xe4,0x1d,0x1d,0x0f,0x11,0x01,0x11,0x40,0x0b,0x12,0x48,0x11,0x0b,0x10,0x00,0x01,0x00,0x00,0x2f,0x5d,0x32,0x2f,0x2b,0x5d,0x33,0x2f,0xed,0x33,0x01,0x2f,0x5d,0xed,0x32,0x12,0x39,0x2f,0xed,0x31,0x30,0x00,0x2b,0x01,0x11,0x34,0x2e,0x02, +0x23,0x22,0x06,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x35,0x33,0x14,0x1e,0x02,0x15,0x33,0x3e,0x03,0x33,0x32,0x16,0x15,0x11,0x03,0x02,0x0d,0x1d,0x2f,0x23,0x48,0x55,0x80,0x01,0x01,0x02,0x77,0x02,0x02,0x02,0x02,0x0f,0x26,0x31,0x40,0x2a,0x6e,0x61,0x02,0x07,0x01,0x8e,0x2e,0x3d,0x25,0x10,0x64,0x5e,0xfe,0x94,0x01,0xff,0x14,0x2e, +0x28,0x1d,0x04,0x03,0x1b,0x22,0x23,0x0c,0x1c,0x2e,0x20,0x11,0x6c,0x79,0xfe,0x4f,0x00,0x01,0x00,0x22,0x00,0x00,0x04,0x4c,0x05,0x45,0x00,0x11,0x00,0x50,0x40,0x2b,0x06,0x02,0x06,0x02,0x0a,0x00,0x10,0x01,0x10,0x10,0x13,0x05,0x01,0x09,0x5a,0x0a,0x0c,0x0e,0x0c,0x0a,0x08,0x0c,0x60,0x05,0x0d,0x0d,0x09,0x04,0x5f,0x3f,0x01,0xef, +0x01,0x02,0x01,0x01,0x09,0x00,0x5f,0x0f,0x03,0x09,0x12,0x00,0x3f,0x3f,0xed,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x33,0xed,0x32,0x01,0x2f,0x33,0x33,0x2f,0x10,0xed,0x32,0x32,0x12,0x39,0x2f,0x5d,0x12,0x39,0x39,0x2f,0x2f,0x31,0x30,0x01,0x11,0x21,0x15,0x21,0x15,0x21,0x15,0x21,0x11,0x23,0x11,0x23,0x35,0x33,0x11,0x21,0x15, +0x01,0x90,0x02,0xa4,0xfd,0x5c,0x01,0x87,0xfe,0x79,0xbf,0xaf,0xaf,0x03,0x7b,0x04,0xa9,0xfe,0x44,0x9e,0xcb,0x81,0xfe,0xfd,0x01,0x03,0x81,0x03,0xc1,0x9c,0x00,0x00,0x00,0x01,0x00,0x50,0x00,0x00,0x04,0x66,0x05,0x5a,0x00,0x3a,0x00,0xcc,0xb3,0x3a,0x03,0x01,0x18,0xb8,0xff,0xf0,0x40,0x67,0x09,0x0c,0x48,0x1f,0x6f,0x2f,0x2a,0x4f, +0x20,0x5f,0x20,0x02,0x20,0x2a,0x20,0x2a,0x3a,0x29,0x30,0x2d,0x6f,0x10,0x0e,0x70,0x13,0x01,0x13,0x0d,0x14,0x13,0x03,0x7f,0x10,0x8f,0x10,0x02,0x10,0x10,0x06,0x00,0x6f,0x3a,0x40,0x10,0x13,0x48,0x3a,0x3a,0x3c,0x34,0x6e,0x00,0x06,0x10,0x06,0x02,0x06,0x30,0x0e,0x73,0x0f,0x2d,0x0f,0x2c,0x12,0x73,0x13,0x29,0x13,0x6f,0x0f,0x9f, +0x0f,0xaf,0x0f,0xbf,0x0f,0x04,0x3f,0x13,0x01,0x0f,0x13,0x0f,0x13,0x34,0x25,0x73,0x1a,0x20,0x20,0x1a,0x07,0x07,0x34,0x73,0x06,0x10,0x3a,0x20,0x3a,0x02,0x3a,0xb8,0xff,0xc0,0xb3,0x16,0x26,0x48,0x3a,0xb8,0xff,0xc0,0xb6,0x10,0x13,0x48,0x3a,0x3a,0x06,0x18,0x00,0x3f,0x33,0x2f,0x2b,0x2b,0x5d,0x10,0xed,0x32,0x3f,0x33,0x2f,0x10, +0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x11,0x33,0x10,0xed,0x32,0x11,0x33,0x10,0xed,0x32,0x01,0x7c,0x2f,0x5d,0x18,0xed,0x12,0x39,0x7d,0x2f,0x2b,0x18,0xed,0x12,0x39,0x2f,0x5d,0x17,0x33,0x2f,0x5d,0x33,0x10,0xed,0x32,0x32,0x11,0x39,0x39,0x2f,0x2f,0x5d,0x11,0x33,0xed,0x31,0x30,0x00,0x2b,0x5d,0x01,0x0e,0x03,0x23,0x21,0x35, +0x3e,0x03,0x3d,0x01,0x23,0x35,0x33,0x35,0x23,0x35,0x33,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x03,0x23,0x22,0x06,0x1d,0x01,0x21,0x15,0x21,0x15,0x21,0x15,0x21,0x15,0x14,0x06,0x07,0x21,0x32,0x3e,0x02,0x37,0x04,0x66,0x09,0x39,0x59,0x73,0x43,0xfd,0x46,0x2c,0x42,0x2c,0x15,0xba,0xba,0xba,0xba,0x30,0x63,0x98, +0x67,0x46,0x7b,0x63,0x47,0x12,0xae,0x0a,0x27,0x35,0x41,0x24,0x72,0x70,0x01,0x98,0xfe,0x68,0x01,0x98,0xfe,0x68,0x58,0x51,0x01,0xe3,0x26,0x43,0x35,0x25,0x08,0x01,0x37,0x50,0x75,0x4d,0x25,0x9a,0x17,0x31,0x41,0x57,0x3c,0x19,0x8e,0x98,0x8d,0x4c,0x5c,0x93,0x66,0x37,0x1d,0x3a,0x56,0x39,0x39,0x20,0x33,0x24,0x14,0x73,0x7d,0x54, +0x8d,0x98,0x8e,0x07,0x70,0x95,0x2a,0x13,0x2a,0x43,0x30,0x00,0x00,0x04,0x00,0x2d,0xff,0xf6,0x04,0xb4,0x05,0x45,0x00,0x0c,0x00,0x3a,0x00,0x45,0x00,0x5b,0x00,0xf3,0xb5,0x0f,0x18,0x0d,0x11,0x48,0x27,0xb8,0xff,0xe8,0xb3,0x0d,0x11,0x48,0x26,0xb8,0xff,0xe8,0x40,0x09,0x0d,0x11,0x48,0x58,0x28,0x0a,0x19,0x48,0x0b,0xb8,0xff,0xe8, +0x40,0x7c,0x09,0x0e,0x48,0x2c,0x70,0x2d,0x2d,0x1c,0x00,0x6f,0x3b,0x4b,0x4f,0x70,0x5a,0x30,0x46,0x40,0x46,0x50,0x46,0x80,0x46,0x04,0x46,0x48,0x5a,0x4d,0x4d,0x54,0x14,0x70,0x13,0x13,0x33,0x70,0x24,0x70,0x54,0x80,0x54,0x02,0x2f,0x54,0x3f,0x54,0x02,0x40,0x3b,0x50,0x3b,0x90,0x3b,0x03,0x0f,0x3b,0x01,0x3b,0x5a,0x54,0x24,0x24, +0x54,0x5a,0x3b,0x04,0x08,0x0d,0x70,0x1c,0x40,0x14,0x18,0x48,0x1c,0x1c,0x5d,0x42,0x07,0x6f,0x08,0x4e,0x46,0x74,0x47,0x33,0x1c,0x10,0x30,0x74,0x29,0x2d,0x2d,0x29,0x29,0x4b,0x47,0x49,0x49,0x47,0x06,0x73,0x42,0x47,0x42,0x47,0x42,0x09,0x51,0x19,0x74,0x10,0x57,0x10,0x14,0x14,0x10,0x19,0x41,0x73,0x09,0x06,0x08,0x15,0x00,0x3f, +0x3f,0xed,0x3f,0x33,0x2f,0x11,0x33,0x10,0xed,0x32,0x11,0x39,0x39,0x2f,0x2f,0x10,0xed,0x11,0x33,0x2f,0x11,0x33,0x33,0x2f,0x33,0x2f,0x10,0xed,0x12,0x39,0x39,0x10,0xed,0x32,0x01,0x2f,0xed,0x32,0x12,0x39,0x2f,0x2b,0xed,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x5d,0x5d,0x5d,0x5d,0x10,0xed,0x33,0x2f,0xed,0x11,0x33,0x2f,0x11,0x33, +0x2f,0x5d,0x10,0xed,0x32,0x10,0xed,0x11,0x33,0x2f,0xed,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x2b,0x01,0x14,0x0e,0x02,0x2b,0x01,0x11,0x23,0x11,0x33,0x32,0x16,0x01,0x14,0x06,0x23,0x22,0x26,0x27,0x37,0x1e,0x03,0x33,0x32,0x36,0x35,0x34,0x26,0x27,0x2e,0x03,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x07,0x2e,0x01,0x23,0x22,0x06, +0x15,0x14,0x16,0x17,0x1e,0x03,0x01,0x34,0x2e,0x02,0x2b,0x01,0x11,0x33,0x32,0x36,0x13,0x35,0x33,0x37,0x33,0x15,0x33,0x15,0x23,0x11,0x14,0x33,0x32,0x37,0x15,0x0e,0x01,0x23,0x22,0x26,0x35,0x11,0x02,0x46,0x28,0x4f,0x76,0x4e,0x3d,0xa1,0xd2,0xa1,0xa6,0x02,0x6e,0x60,0x5a,0x4a,0x62,0x0b,0x6c,0x05,0x10,0x14,0x18,0x0c,0x1a,0x22, +0x2d,0x30,0x19,0x32,0x29,0x1a,0x1b,0x31,0x42,0x27,0x46,0x58,0x08,0x6d,0x05,0x23,0x13,0x1d,0x1a,0x35,0x33,0x16,0x2e,0x26,0x19,0xfc,0xf0,0x16,0x29,0x3b,0x24,0x38,0x40,0x4b,0x4b,0x19,0x5a,0x3b,0x47,0x95,0x95,0x44,0x2d,0x1b,0x17,0x32,0x1e,0x54,0x54,0x03,0xf7,0x4c,0x84,0x61,0x38,0xfd,0x72,0x05,0x45,0xa6,0xfc,0x0e,0x53,0x64, +0x53,0x50,0x11,0x1b,0x22,0x14,0x07,0x25,0x28,0x24,0x3e,0x21,0x11,0x29,0x33,0x3e,0x26,0x2b,0x3e,0x29,0x13,0x56,0x48,0x0c,0x2c,0x23,0x26,0x23,0x25,0x39,0x23,0x0f,0x26,0x31,0x3c,0x03,0x23,0x37,0x4a,0x2d,0x14,0xfe,0x65,0x72,0xfe,0x9c,0x61,0x8e,0x8e,0x61,0xfe,0x80,0x4e,0x07,0x61,0x05,0x06,0x52,0x4f,0x01,0x92,0x00,0x00,0x00, +0x00,0x01,0x00,0x5b,0xff,0xec,0x04,0x63,0x05,0x5a,0x00,0x3c,0x00,0x96,0x40,0x55,0x69,0x31,0x01,0x37,0x03,0x47,0x03,0x57,0x03,0x03,0x2b,0x2a,0x2a,0x0c,0x35,0x00,0x00,0x39,0x0b,0x0c,0x0c,0x1c,0x3e,0x33,0x01,0x01,0x39,0x6e,0x1c,0x20,0x00,0x17,0x01,0x17,0x17,0x1c,0x22,0x16,0x16,0x1c,0x40,0x0b,0x0e,0x48,0x1c,0x01,0x17,0x73, +0x18,0x3b,0x18,0x36,0x20,0x73,0x21,0x33,0x21,0x6f,0x18,0x01,0x3f,0x21,0x01,0x18,0x21,0x18,0x21,0x06,0x2e,0x73,0x25,0x2b,0x2b,0x25,0x07,0x06,0x73,0x11,0x30,0x0b,0x01,0x0b,0x0b,0x11,0x19,0x00,0x3f,0x33,0x2f,0x5d,0x10,0xed,0x3f,0x33,0x2f,0x10,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x11,0x33,0x10,0xed,0x32,0x11,0x33,0x10, +0xed,0x32,0x01,0x2f,0x2b,0x33,0x2f,0x33,0x11,0x33,0x2f,0x5d,0x32,0x10,0xed,0x32,0x2f,0x33,0x11,0x12,0x39,0x2f,0x33,0x12,0x39,0x2f,0x33,0x11,0x33,0x11,0x33,0x31,0x30,0x00,0x5d,0x5d,0x01,0x21,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x27,0x23,0x35,0x33,0x2e,0x01,0x35,0x34,0x36,0x37,0x23,0x35, +0x33,0x3e,0x01,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x01,0x23,0x22,0x0e,0x02,0x07,0x21,0x15,0x21,0x0e,0x01,0x15,0x14,0x17,0x21,0x03,0x69,0xfe,0x35,0x08,0x2a,0x4d,0x74,0x50,0x34,0x57,0x4b,0x42,0x1e,0x4c,0x2a,0x58,0x60,0x6c,0x3e,0x78,0xb2,0x7b,0x47,0x0d,0x83,0x77,0x02,0x02,0x02,0x02,0x77,0x81,0x1d,0xfb,0xe5,0x38,0x64,0x5d, +0x57,0x2b,0x52,0x3a,0x8a,0x56,0x49,0x72,0x53,0x33,0x0b,0x01,0xcd,0xfe,0x25,0x01,0x01,0x03,0x01,0xda,0x01,0xcf,0x4f,0x7a,0x54,0x2b,0x12,0x1e,0x25,0x13,0x87,0x1c,0x2e,0x20,0x12,0x44,0x7d,0xb2,0x6d,0x90,0x17,0x22,0x12,0x1a,0x23,0x12,0x8e,0xea,0xec,0x0e,0x1c,0x2c,0x1e,0x8c,0x2a,0x3a,0x1c,0x47,0x7a,0x5f,0x8d,0x0e,0x2b,0x15, +0x2a,0x20,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0xf4,0x04,0xcd,0x05,0x50,0x00,0x13,0x00,0x27,0x00,0x4b,0x00,0x4f,0x00,0xc3,0x40,0x09,0x4a,0x34,0x01,0x38,0x28,0x09,0x0e,0x48,0x3e,0xb8,0xff,0xd8,0xb3,0x09,0x0e,0x48,0x11,0xb8,0xff,0xd8,0xb3,0x09,0x0e,0x48,0x0d,0xb8,0xff,0xd8,0x40,0x14,0x09,0x0e,0x48,0x07,0x28,0x09,0x0d,0x48, +0x03,0x28,0x09,0x0d,0x48,0x4e,0x4f,0x4c,0x4d,0x4f,0x10,0x4d,0xb8,0xff,0xf0,0x40,0x0f,0x0f,0x4f,0x01,0x00,0x4d,0x01,0x4f,0x4d,0x4f,0x4d,0x00,0x3b,0x1e,0xb4,0x0a,0xb8,0x01,0x05,0x40,0x10,0x00,0xb4,0x14,0x14,0x3b,0x51,0x45,0x31,0xb4,0x46,0x00,0x30,0x10,0x30,0x02,0x30,0xb8,0x01,0x05,0x40,0x27,0x28,0xb4,0x3b,0x4e,0x06,0x4c, +0x18,0x10,0x30,0x01,0x20,0x30,0x30,0x30,0x02,0x30,0x30,0x2d,0xb6,0x36,0xb8,0x49,0xb6,0x40,0x3f,0x46,0x01,0x46,0x46,0x40,0x07,0x19,0xb6,0x0f,0xb8,0x23,0xb6,0x05,0x19,0x00,0x3f,0xed,0xf4,0xed,0x3f,0x33,0x2f,0x5d,0x10,0xed,0xf4,0xed,0x33,0x2f,0x5d,0x71,0x3f,0x3f,0x01,0x2f,0xed,0xf4,0x5d,0x32,0xed,0x32,0x11,0x12,0x39,0x2f, +0xed,0xf4,0xed,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x38,0x38,0x11,0x33,0x11,0x33,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x5d,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x01,0x14,0x1e,0x02,0x33, +0x32,0x36,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x07,0x2e,0x01,0x23,0x22,0x06,0x13,0x23,0x01,0x33,0x04,0xcd,0x2b,0x4a,0x62,0x37,0x37,0x60,0x48,0x2a,0x29,0x49,0x62,0x39,0x36,0x61,0x49,0x2a,0x94,0x0f,0x1e,0x2c,0x1d,0x1f,0x2e,0x1e,0x0f,0x10,0x1e,0x2d,0x1d,0x1c,0x2d,0x1f,0x10, +0xfc,0x59,0x0f,0x20,0x2f,0x20,0x26,0x37,0x0b,0x8d,0x06,0x25,0x3c,0x54,0x36,0x48,0x68,0x43,0x21,0x2b,0x4a,0x65,0x39,0x35,0x50,0x3a,0x25,0x09,0x8f,0x0a,0x2b,0x2d,0x3f,0x3e,0xb0,0x76,0x02,0xbf,0x73,0x01,0x94,0x72,0x9e,0x63,0x2d,0x2c,0x63,0x9e,0x73,0x7a,0xa1,0x62,0x28,0x28,0x62,0xa1,0x7a,0x58,0x77,0x48,0x1f,0x20,0x48,0x77, +0x57,0x53,0x75,0x49,0x21,0x21,0x49,0x75,0x02,0x70,0x3f,0x71,0x54,0x31,0x52,0x57,0x09,0x36,0x63,0x4c,0x2d,0x3e,0x70,0x9a,0x5c,0x74,0x9f,0x63,0x2c,0x28,0x46,0x5e,0x37,0x0b,0x48,0x55,0x9c,0xfb,0xbd,0x05,0x45,0x00,0x00,0x00,0x00,0x02,0x01,0x1e,0xff,0xec,0x03,0x9d,0x05,0x95,0x00,0x29,0x00,0x39,0x00,0x9e,0xb9,0x00,0x1c,0xff, +0xd8,0xb3,0x09,0x0e,0x48,0x18,0xb8,0xff,0xd8,0x40,0x0c,0x09,0x0f,0x48,0x09,0x18,0x09,0x0d,0x48,0x1f,0x49,0x2a,0x04,0xb8,0x01,0x1a,0x40,0x1b,0x03,0x2a,0x03,0x2a,0x03,0x3b,0x35,0x25,0x48,0x0c,0x14,0x0c,0x10,0x10,0x00,0x0c,0x40,0x0c,0x50,0x0c,0x90,0x0c,0xa0,0x0c,0x05,0x0c,0x11,0xb8,0x01,0x18,0xb2,0x10,0x10,0x0d,0xb8,0x01, +0x18,0xb7,0x0f,0x14,0x1f,0x14,0x02,0x14,0x14,0x24,0xb8,0x01,0x18,0xb3,0x35,0x35,0x00,0x2f,0xb8,0x01,0x18,0x40,0x0d,0x0f,0x1a,0x3f,0x1a,0x4f,0x1a,0x6f,0x1a,0x7f,0x1a,0x05,0x1a,0x00,0xb8,0x01,0x19,0xb4,0x07,0x04,0x04,0x07,0x16,0x00,0x3f,0x33,0x2f,0x10,0xed,0x2f,0x5d,0xed,0x12,0x39,0x2f,0xed,0x32,0x2f,0x5d,0xed,0x32,0x2f, +0xed,0x01,0x2f,0x5d,0x33,0x2f,0x11,0x33,0x10,0xed,0x32,0x12,0x39,0x39,0x2f,0x2f,0x10,0xed,0x10,0xed,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x25,0x32,0x36,0x37,0x33,0x0e,0x01,0x23,0x22,0x2e,0x02,0x3d,0x01,0x0e,0x01,0x07,0x35,0x3e,0x01,0x37,0x11,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x15,0x14,0x1e,0x02,0x13, +0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x3e,0x03,0x02,0xc6,0x33,0x4e,0x11,0x45,0x14,0x82,0x6d,0x37,0x5b,0x42,0x24,0x20,0x42,0x22,0x23,0x42,0x1f,0x19,0x3b,0x62,0x48,0x34,0x55,0x3d,0x21,0x32,0x57,0x74,0x42,0x16,0x24,0x2d,0x7d,0x14,0x22,0x2f,0x1a,0x1f,0x28,0x16,0x08,0x31,0x54,0x3d,0x22,0x4e,0x68,0x6d,0x9a,0x9d,0x28, +0x4f,0x76,0x4d,0xaf,0x11,0x1c,0x0d,0x49,0x0e,0x1d,0x10,0x02,0x4b,0x3b,0x6d,0x52,0x31,0x2a,0x4e,0x6f,0x45,0x63,0xb4,0x98,0x76,0x26,0xf4,0x39,0x53,0x36,0x1a,0x04,0x14,0x34,0x55,0x3d,0x21,0x24,0x3d,0x51,0x2e,0xfe,0x05,0x21,0x68,0x83,0x97,0x00,0x00,0x04,0x00,0x16,0x00,0x00,0x04,0xb9,0x05,0x45,0x00,0x13,0x00,0x25,0x00,0x39, +0x00,0x3d,0x00,0x9d,0xb9,0x00,0x0a,0xff,0xe8,0x40,0x09,0x0d,0x11,0x48,0x00,0x18,0x0d,0x11,0x48,0x23,0xb8,0xff,0xe8,0xb3,0x09,0x0e,0x48,0x1f,0xb8,0xff,0xe8,0x40,0x4b,0x09,0x0e,0x48,0x1a,0x28,0x09,0x0e,0x48,0x17,0x18,0x09,0x0e,0x48,0x3d,0x3d,0x14,0x3a,0x3a,0x1c,0x00,0x11,0x5d,0x12,0x30,0xb4,0x1c,0x0f,0x12,0x01,0x12,0x40, +0x0b,0x0e,0x48,0x00,0x1c,0x01,0x12,0x1c,0x12,0x1c,0x08,0x14,0xb4,0x26,0x26,0x3f,0x0a,0x07,0x5d,0x08,0x35,0xb6,0x19,0x19,0x21,0x3b,0x60,0x3a,0x12,0x2b,0xb6,0x0f,0x21,0x01,0x21,0x0f,0x11,0x01,0x09,0x03,0x0b,0x00,0x08,0x12,0x00,0x3f,0x33,0x33,0x3f,0x33,0x33,0x3f,0x5d,0xed,0x3f,0xed,0x11,0x39,0x2f,0xed,0x01,0x2f,0xed,0x32, +0x12,0x39,0x2f,0xed,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x2b,0x5d,0x10,0xed,0x10,0xed,0x32,0x11,0x33,0x2f,0x11,0x33,0x2f,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x01,0x2b,0x2b,0x21,0x01,0x16,0x17,0x1e,0x01,0x15,0x11,0x23,0x11,0x33,0x01,0x26,0x27,0x2e,0x01,0x35,0x11,0x33,0x11,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x35,0x34,0x3e,0x02, +0x33,0x32,0x1e,0x02,0x07,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x01,0x35,0x21,0x15,0x01,0xaa,0xfe,0xf2,0x01,0x02,0x02,0x01,0x8c,0xc0,0x01,0x16,0x02,0x02,0x02,0x02,0x8d,0x02,0x48,0x19,0x3a,0x60,0x48,0x80,0x75,0x1d,0x3c,0x5e,0x42,0x46,0x5f,0x39,0x19,0x95,0x0b,0x17,0x24,0x19,0x1b,0x26, +0x18,0x0b,0x0b,0x16,0x23,0x18,0x1c,0x27,0x19,0x0b,0xfe,0xc4,0x01,0xb3,0x04,0x1a,0x2b,0x2d,0x26,0x59,0x27,0xfc,0xe4,0x05,0x45,0xfb,0xde,0x28,0x2e,0x27,0x62,0x33,0x03,0x10,0xfa,0xbb,0x02,0xb2,0x5e,0x92,0x63,0x34,0xca,0xbd,0x5c,0x90,0x65,0x35,0x35,0x64,0x91,0x5c,0x51,0x6b,0x40,0x1a,0x1b,0x40,0x6b,0x50,0x52,0x6c,0x3f,0x1a, +0x1a,0x3f,0x6c,0xfd,0xa0,0x88,0x88,0x00,0x00,0x02,0x00,0x04,0x03,0x4a,0x04,0xc8,0x05,0xcb,0x00,0x24,0x00,0x2c,0x00,0x88,0xb5,0x22,0x18,0x0e,0x11,0x48,0x14,0xb8,0xff,0xe8,0x40,0x4c,0x0e,0x11,0x48,0x09,0x08,0x1a,0x1a,0x24,0x14,0x11,0xc5,0x40,0x0f,0x12,0x1f,0x12,0x2f,0x12,0x03,0x0f,0x03,0x12,0x12,0x00,0x2c,0x0e,0x26,0x29, +0x27,0x0e,0x29,0x26,0xc4,0x00,0x27,0x01,0x27,0x22,0x00,0xc5,0x70,0x24,0x80,0x24,0x02,0x24,0x24,0x2e,0x25,0x29,0xc8,0x02,0x0f,0x13,0x22,0x0f,0x03,0x2a,0x00,0x0f,0x1a,0x1f,0x1a,0x02,0x0f,0x09,0x1f,0x09,0x02,0x00,0x09,0x12,0x1a,0x04,0x27,0xd1,0x00,0x3f,0x17,0x33,0x5d,0x5d,0x3f,0x17,0x33,0x11,0x33,0xed,0x32,0x11,0x01,0x33, +0x2f,0x5d,0xed,0x32,0x2f,0x5d,0xed,0xc6,0x2b,0x01,0x18,0x10,0x4d,0xe6,0x11,0x39,0x2f,0x5f,0x5e,0x5d,0x1a,0xed,0x32,0x12,0x39,0x11,0x33,0x33,0x31,0x30,0x2b,0x2b,0x01,0x11,0x35,0x06,0x07,0x0e,0x01,0x07,0x03,0x23,0x03,0x2e,0x01,0x27,0x26,0x27,0x15,0x11,0x23,0x11,0x33,0x13,0x1e,0x01,0x17,0x16,0x17,0x36,0x37,0x3e,0x03,0x35, +0x13,0x33,0x11,0x01,0x11,0x23,0x11,0x23,0x35,0x21,0x15,0x04,0x5f,0x02,0x04,0x03,0x05,0x02,0xbe,0x59,0x87,0x02,0x14,0x0c,0x0e,0x11,0x69,0x9c,0xb8,0x02,0x04,0x02,0x03,0x02,0x11,0x0d,0x06,0x0a,0x09,0x06,0x8b,0x98,0xfc,0x56,0x6f,0xab,0x01,0xc9,0x03,0x4a,0x01,0x60,0xa0,0x09,0x09,0x08,0x0e,0x05,0xfe,0x2d,0x01,0x56,0x04,0x36, +0x1f,0x24,0x2d,0x2b,0xfe,0x2b,0x02,0x81,0xfe,0x2f,0x03,0x0b,0x06,0x07,0x08,0x2a,0x22,0x0f,0x1c,0x16,0x10,0x01,0x01,0x56,0xfd,0x7f,0x02,0x25,0xfd,0xdb,0x02,0x25,0x5c,0x5c,0x00,0x00,0x00,0x01,0x00,0x3b,0x00,0x00,0x04,0x93,0x05,0x5a,0x00,0x39,0x00,0xda,0x40,0x78,0x79,0x15,0x89,0x15,0x02,0x76,0x25,0x86,0x25,0x02,0x6b,0x09, +0x7b,0x09,0x8b,0x09,0x03,0x6b,0x31,0x7b,0x31,0x8b,0x31,0x03,0x66,0x25,0x76,0x25,0x86,0x25,0x03,0x66,0x15,0x76,0x15,0x86,0x15,0x03,0x46,0x38,0x56,0x38,0x02,0x46,0x02,0x56,0x02,0x02,0x39,0x1b,0x01,0x39,0x1f,0x01,0x30,0x5c,0x28,0x0a,0x5c,0x12,0x20,0x12,0x30,0x12,0x50,0x12,0x60,0x12,0x70,0x12,0x05,0x4f,0x12,0x01,0xdf,0x28, +0xef,0x28,0xff,0x28,0x03,0x00,0x28,0x10,0x28,0x20,0x28,0x03,0x70,0x28,0x80,0x28,0x02,0x28,0x12,0x28,0x12,0x35,0x18,0x10,0x10,0x05,0x5a,0x80,0x18,0x90,0x18,0xd0,0x18,0xe0,0x18,0xf0,0x18,0x05,0x90,0x18,0xa0,0x18,0x02,0x18,0xb8,0xff,0xc0,0x40,0x23,0x09,0x0c,0x48,0x18,0x18,0x35,0x3b,0x2a,0x2a,0x22,0x5a,0x2f,0x35,0x3f,0x35, +0x02,0x35,0x40,0x21,0x24,0x48,0x35,0x13,0x27,0x27,0x10,0x2a,0x5f,0x12,0x29,0x12,0x1d,0x5f,0x00,0x04,0x00,0x3f,0xed,0x3f,0x33,0xed,0x32,0x32,0x2f,0x33,0x01,0x2f,0x2b,0x5d,0xed,0x33,0x2f,0x11,0x12,0x39,0x2f,0x2b,0x5d,0x71,0xed,0x32,0x2f,0x11,0x12,0x39,0x39,0x2f,0x2f,0x5d,0x71,0x71,0x71,0x72,0x10,0xed,0x10,0xed,0x31,0x30, +0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x01,0x5d,0x5d,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x36,0x37,0x3e,0x01,0x3b,0x01,0x15,0x21,0x35,0x3e,0x03,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x17,0x15,0x21,0x35,0x33,0x32,0x16,0x17,0x16,0x17,0x2e,0x03,0x35,0x34,0x3e,0x02,0x02,0x67,0x7c,0xc5, +0x8a,0x49,0x2d,0x55,0x7e,0x51,0x20,0x1e,0x1a,0x36,0x13,0xc8,0xfe,0x1d,0x4b,0x66,0x3d,0x1a,0x27,0x53,0x7f,0x57,0x58,0x80,0x52,0x28,0x1a,0x3d,0x66,0x4b,0xfe,0x1d,0xc8,0x13,0x36,0x1a,0x1e,0x20,0x51,0x7e,0x55,0x2d,0x49,0x8a,0xc5,0x05,0x5a,0x55,0x9d,0xdd,0x88,0x5f,0xb3,0xa0,0x8a,0x36,0x03,0x03,0x02,0x03,0x9c,0xe0,0x37,0x7d, +0x88,0x90,0x4a,0x69,0xa8,0x77,0x40,0x40,0x77,0xa8,0x69,0x4a,0x90,0x88,0x7d,0x37,0xe0,0x9c,0x03,0x02,0x03,0x03,0x36,0x8a,0xa0,0xb3,0x5f,0x88,0xdd,0x9d,0x55,0x00,0x00,0x02,0x00,0x5f,0xff,0xde,0x04,0x83,0x04,0x48,0x00,0x22,0x00,0x2f,0x00,0x5a,0xb6,0x1d,0x8f,0x1e,0x01,0x1e,0x1e,0x11,0xb8,0x01,0x1b,0x40,0x10,0x00,0x23,0x10, +0x23,0x60,0x23,0x70,0x23,0x80,0x23,0x05,0x23,0x23,0x31,0x12,0x2f,0xb8,0x01,0x1b,0xb7,0x1f,0x05,0x01,0x05,0x1d,0x1d,0x18,0x12,0xb8,0x01,0x18,0xb3,0x2f,0x2f,0x18,0x29,0xb8,0x01,0x18,0xb2,0x0c,0x10,0x18,0xb8,0x01,0x18,0xb1,0x00,0x16,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x11,0x39,0x2f,0x01,0x2f,0x5d,0xed,0x32,0x12, +0x39,0x2f,0x5d,0xed,0x32,0x2f,0x5d,0x33,0x31,0x30,0x05,0x22,0x2e,0x02,0x35,0x34,0x3e,0x04,0x33,0x32,0x1e,0x02,0x15,0x21,0x11,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x13,0x11,0x2e,0x03,0x23,0x22,0x0e,0x02,0x07,0x11,0x02,0x72,0x82,0xc6,0x86,0x45,0x2c,0x4c,0x66,0x76,0x80,0x3f,0x71,0xc1,0x8e,0x51,0xfc,0xc5,0x16, +0x40,0x4e,0x58,0x2e,0x4b,0x74,0x5d,0x4d,0x22,0x48,0x24,0x53,0x6e,0x8f,0xcb,0x13,0x3b,0x4c,0x5d,0x35,0x33,0x57,0x4a,0x3c,0x18,0x22,0x5d,0x9d,0xcc,0x6f,0x62,0xa0,0x7d,0x5d,0x3c,0x1d,0x4f,0x92,0xd1,0x83,0xfe,0x9c,0x18,0x2d,0x23,0x14,0x20,0x3c,0x57,0x37,0x2a,0x39,0x64,0x4c,0x2c,0x02,0x8a,0x01,0x15,0x14,0x2a,0x22,0x16,0x13, +0x20,0x2a,0x18,0xfe,0xea,0x00,0x00,0x00,0xff,0xff,0x00,0x01,0xff,0xf4,0x04,0xc3,0x05,0x45,0x10,0x27,0x02,0x9a,0xfe,0xdc,0x00,0x00,0x10,0x26,0x02,0x1e,0xeb,0x00,0x11,0x07,0x02,0xa0,0x01,0xbd,0xfd,0xb4,0x00,0x24,0x40,0x14,0x04,0x03,0x02,0x42,0x18,0x04,0x03,0x02,0x30,0x42,0x01,0x2f,0x42,0x01,0x42,0x01,0x60,0x14,0x01,0x14, +0x11,0x5d,0x35,0x11,0x5d,0x5d,0x35,0x35,0x35,0x00,0x3f,0x35,0x35,0x35,0x00,0x00,0xff,0xff,0x00,0x09,0xff,0xf4,0x04,0xc3,0x05,0x51,0x10,0x27,0x02,0x9c,0xff,0x1f,0x00,0x00,0x10,0x26,0x02,0x1e,0xfc,0x00,0x11,0x07,0x02,0xa0,0x01,0xbd,0xfd,0xb4,0x00,0x24,0x40,0x14,0x04,0x03,0x02,0x63,0x18,0x04,0x03,0x02,0x30,0x42,0x01,0x2f, +0x42,0x01,0x42,0x00,0x40,0x00,0x01,0x00,0x11,0x5d,0x35,0x11,0x5d,0x5d,0x35,0x35,0x35,0x00,0x3f,0x35,0x35,0x35,0x00,0x00,0xff,0xff,0x00,0x25,0xff,0xf4,0x04,0xc3,0x05,0x45,0x10,0x27,0x02,0x9e,0xff,0x21,0x00,0x00,0x10,0x26,0x02,0x1e,0x08,0x00,0x11,0x07,0x02,0xa0,0x01,0xbd,0xfd,0xb4,0x00,0x28,0x40,0x17,0x04,0x03,0x02,0x4f, +0x18,0x04,0x03,0x02,0x30,0x42,0x01,0x2f,0x42,0x01,0x42,0x00,0x40,0x00,0x01,0x30,0x00,0x01,0x00,0x11,0x5d,0x5d,0x35,0x11,0x5d,0x5d,0x35,0x35,0x35,0x00,0x3f,0x35,0x35,0x35,0x00,0x00,0xff,0xff,0x00,0x39,0xff,0xf4,0x04,0xa3,0x05,0x45,0x10,0x27,0x02,0x9f,0xff,0x3d,0x00,0x00,0x10,0x26,0x02,0x1e,0xb5,0x00,0x11,0x07,0x02,0xa0, +0x01,0x9d,0xfd,0xb4,0x00,0x30,0x40,0x1c,0x04,0x03,0x02,0x3e,0x18,0x04,0x03,0x02,0x2f,0x42,0x01,0x42,0x01,0x5f,0x0f,0x01,0x0f,0x00,0x60,0x00,0x01,0x50,0x00,0x01,0x40,0x00,0x01,0x00,0x11,0x5d,0x5d,0x5d,0x35,0x11,0x5d,0x35,0x11,0x5d,0x35,0x35,0x35,0x00,0x3f,0x35,0x35,0x35,0x00,0x00,0x00,0x01,0x00,0x08,0x01,0x37,0x04,0xc4, +0x03,0x17,0x00,0x11,0x00,0x1b,0x00,0xb0,0x00,0x2f,0xb0,0x0f,0xcd,0x01,0xb0,0x12,0x2f,0xb0,0x13,0xd6,0x00,0xb1,0x0f,0x00,0x11,0x12,0xb1,0x07,0x08,0x39,0x39,0x30,0x31,0x13,0x1e,0x01,0x17,0x23,0x2e,0x01,0x27,0x35,0x3e,0x01,0x37,0x33,0x0e,0x01,0x07,0x21,0x15,0xe7,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f, +0x3b,0x1d,0x03,0xdd,0x01,0xfc,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x56,0x00,0x01,0x01,0x76,0xff,0xc3,0x03,0x56,0x04,0x7f,0x00,0x11,0x00,0x1f,0x40,0x0e,0x0c,0x10,0xac,0x03,0x11,0x10,0x0f,0x00,0x0c,0x6f,0x03,0x01,0x03,0x07,0x00,0x2f,0xc4,0x5d,0x32,0x39,0x39,0x2f,0x01,0x2f,0xce,0xfd,0xce,0x31, +0x30,0x01,0x0e,0x01,0x07,0x35,0x3e,0x01,0x37,0x33,0x1e,0x01,0x17,0x15,0x2e,0x01,0x27,0x11,0x23,0x02,0x3b,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x56,0x03,0xa0,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b,0x1d,0xfc,0x23,0x00,0x00,0x00,0x00,0x01,0x00,0x08,0x01,0x35,0x04,0xc4, +0x03,0x15,0x00,0x11,0x00,0x1b,0x00,0xb0,0x10,0x2f,0xb0,0x11,0xcd,0x01,0xb0,0x12,0x2f,0xb0,0x13,0xd6,0x00,0xb1,0x11,0x10,0x11,0x12,0xb1,0x07,0x08,0x39,0x39,0x30,0x31,0x01,0x2e,0x01,0x27,0x33,0x1e,0x01,0x17,0x15,0x0e,0x01,0x07,0x23,0x3e,0x01,0x37,0x21,0x35,0x03,0xe5,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48, +0x1f,0x3b,0x1d,0xfc,0x23,0x02,0x50,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x56,0x00,0x00,0x00,0x00,0x01,0x01,0x76,0xff,0xc3,0x03,0x56,0x04,0x7f,0x00,0x11,0x00,0x1f,0x40,0x0e,0x03,0x00,0xac,0x0c,0x0f,0x10,0x0f,0x00,0x03,0x60,0x0c,0x01,0x0c,0x08,0x00,0x2f,0xc4,0x5d,0x32,0x39,0x39,0x2f,0x01,0x2f, +0xcd,0xfd,0xcd,0x31,0x30,0x25,0x3e,0x01,0x37,0x15,0x0e,0x01,0x07,0x23,0x2e,0x01,0x27,0x35,0x1e,0x01,0x17,0x11,0x33,0x02,0x91,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x56,0xa2,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b,0x1d,0x03,0xdd,0x00,0x01,0x00,0x08,0x01,0x35,0x04,0xc4, +0x03,0x15,0x00,0x1f,0x00,0x1e,0x00,0xb0,0x00,0x2f,0xb0,0x0f,0xcd,0x01,0xb0,0x20,0x2f,0xb0,0x21,0xd6,0x00,0xb1,0x0f,0x00,0x11,0x12,0xb3,0x07,0x08,0x17,0x18,0x24,0x17,0x39,0x30,0x31,0x13,0x1e,0x01,0x17,0x23,0x2e,0x01,0x27,0x35,0x3e,0x01,0x37,0x33,0x0e,0x01,0x07,0x21,0x2e,0x01,0x27,0x33,0x1e,0x01,0x17,0x15,0x0e,0x01,0x07, +0x23,0x3e,0x01,0x37,0xe7,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b,0x1d,0x02,0xfe,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b,0x1d,0x01,0xfa,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x00, +0x00,0x01,0x01,0x76,0xff,0xc3,0x03,0x56,0x04,0x7f,0x00,0x1f,0x00,0x2f,0x40,0x17,0x14,0x0b,0x10,0xac,0x1b,0x03,0x1f,0x1f,0x10,0x13,0x60,0x1c,0x01,0x1c,0x18,0x00,0x0f,0x0c,0x6f,0x03,0x01,0x03,0x07,0x00,0x2f,0xcc,0x5d,0x32,0x39,0x39,0x2f,0xcc,0x5d,0x32,0x39,0x39,0x01,0x2f,0xce,0x32,0xfd,0xcc,0x32,0x31,0x30,0x01,0x0e,0x01, +0x07,0x35,0x3e,0x01,0x37,0x33,0x1e,0x01,0x17,0x15,0x2e,0x01,0x27,0x11,0x3e,0x01,0x37,0x15,0x0e,0x01,0x07,0x23,0x2e,0x01,0x27,0x35,0x1e,0x01,0x17,0x02,0x3b,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x03,0xa0,0x1d,0x3b,0x1f,0x48,0x3a, +0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b,0x1d,0xfd,0x02,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b,0x1d,0x00,0x00,0x00,0x00,0x02,0x01,0x76,0xff,0x48,0x03,0x56,0x04,0x7f,0x00,0x03,0x00,0x23,0x00,0x3e,0x40,0x1f,0x07,0x00,0x20,0x23,0x10,0x01,0x17,0x14,0xac,0x23,0x23,0x14,0x17,0x60,0x20,0x01,0x20,0x1c, +0x03,0xaf,0x00,0x00,0x1c,0x04,0x13,0x10,0x6f,0x07,0x01,0x07,0x0b,0x00,0x2f,0xcc,0x5d,0x32,0x39,0x39,0x2f,0x33,0x2f,0xed,0x10,0xcc,0x5d,0x32,0x39,0x39,0x01,0x2f,0xfd,0xcd,0x32,0x32,0x10,0xcd,0x32,0x32,0x31,0x30,0x05,0x21,0x15,0x21,0x13,0x0e,0x01,0x07,0x35,0x3e,0x01,0x37,0x33,0x1e,0x01,0x17,0x15,0x2e,0x01,0x27,0x11,0x3e, +0x01,0x37,0x15,0x0e,0x01,0x07,0x23,0x2e,0x01,0x27,0x35,0x1e,0x01,0x17,0x01,0x76,0x01,0xe0,0xfe,0x20,0xc5,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x22,0x62,0x41,0x44,0x70,0x2a,0x24,0x2a,0x70,0x44,0x41,0x62,0x22,0x68,0x50,0x04,0x58,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b, +0x1d,0xfd,0x02,0x1d,0x3b,0x1f,0x48,0x3a,0x82,0x52,0x52,0x82,0x3a,0x48,0x1f,0x3b,0x1d,0x00,0x00,0x00,0x00,0x02,0x00,0x69,0xff,0xe5,0x04,0x63,0x05,0xc5,0x00,0x2d,0x00,0x43,0x00,0x70,0x40,0x48,0x25,0x14,0x35,0x14,0x02,0x0b,0x41,0x1b,0x41,0x02,0x09,0x0c,0x19,0x0c,0x02,0x25,0x25,0x0f,0x29,0x2e,0x01,0x2e,0x10,0x0d,0x16,0x48, +0x2e,0x19,0x00,0x46,0x00,0x1d,0x10,0x1d,0x02,0x1d,0x1d,0x45,0x3a,0x47,0x0f,0x33,0x51,0x2e,0x19,0x19,0x7f,0x16,0x8f,0x16,0x9f,0x16,0xbf,0x16,0xcf,0x16,0xdf,0x16,0x06,0x16,0x16,0x29,0x3f,0x50,0x0a,0x16,0x25,0x25,0x20,0x50,0x29,0x00,0x00,0x3f,0xed,0x33,0x2f,0x3f,0xed,0x11,0x39,0x2f,0x5d,0x33,0x11,0x33,0xed,0x01,0x2f,0xed, +0x12,0x39,0x2f,0x5d,0xed,0x33,0x33,0x2b,0x5d,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x01,0x5d,0x00,0x5d,0x01,0x14,0x0e,0x02,0x07,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x04,0x33,0x32,0x16,0x17,0x33,0x3e,0x01,0x35,0x34,0x26,0x23,0x22,0x0e,0x02,0x07,0x37,0x3e,0x01,0x33,0x32,0x1e,0x02,0x03,0x2e,0x03,0x23,0x22,0x0e,0x04, +0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x04,0x63,0x08,0x0e,0x15,0x0d,0x22,0x6e,0x93,0xb8,0x6e,0x69,0x90,0x59,0x27,0x1a,0x36,0x55,0x78,0x9a,0x61,0x64,0x9a,0x25,0x04,0x02,0x03,0x92,0x91,0x1f,0x44,0x41,0x3d,0x19,0x27,0x2e,0x7f,0x49,0x7b,0xa8,0x67,0x2c,0xd9,0x0a,0x2c,0x3f,0x4e,0x2d,0x41,0x6a,0x52,0x3c,0x27,0x13,0x1a,0x34, +0x4f,0x36,0x51,0x85,0x66,0x45,0x03,0xaa,0x2e,0x67,0x6b,0x6a,0x30,0x80,0xce,0x90,0x4d,0x3f,0x6b,0x8a,0x4b,0x3c,0x8f,0x90,0x86,0x68,0x3f,0x63,0x54,0x19,0x3a,0x22,0xc4,0xd1,0x0b,0x13,0x1c,0x11,0x93,0x17,0x27,0x58,0x95,0xc3,0xfe,0x93,0x2a,0x4a,0x37,0x20,0x33,0x54,0x6e,0x74,0x74,0x30,0x35,0x5b,0x43,0x26,0x63,0xa1,0xcd,0x00, +0x00,0x02,0x00,0x0c,0x00,0x00,0x04,0xc0,0x05,0x81,0x00,0x05,0x00,0x12,0x00,0x7b,0x40,0x4e,0x29,0x02,0x01,0x06,0x03,0x01,0x03,0x01,0x52,0x12,0x0b,0x12,0x5e,0x04,0x03,0x14,0x04,0x04,0x03,0x02,0x01,0x52,0x11,0x0b,0x11,0x5e,0x01,0x02,0x14,0x01,0x01,0x02,0x0b,0x01,0x04,0x5a,0x6f,0x12,0x7f,0x12,0x8f,0x12,0x03,0x10,0x12,0x01, +0x12,0x12,0x14,0x11,0x5a,0x7f,0x01,0x8f,0x01,0x02,0x01,0x5a,0x0b,0x01,0x4b,0x0b,0x01,0x0b,0x03,0x02,0x04,0x12,0x04,0x01,0x01,0x04,0x12,0x03,0x11,0x5f,0x00,0x12,0x00,0x3f,0xed,0x17,0x32,0x2f,0x2f,0x2f,0x3f,0x33,0x33,0x5d,0x5d,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0x5d,0xed,0x11,0x39,0x87,0x10,0x2b,0x87,0x2b,0xc4,0x87, +0x18,0x10,0x2b,0x87,0x2b,0xc4,0x31,0x30,0x01,0x5d,0x5d,0x33,0x35,0x01,0x33,0x01,0x15,0x01,0x2e,0x03,0x27,0x0e,0x03,0x07,0x01,0x21,0x0c,0x01,0xdd,0xf4,0x01,0xe3,0xfe,0x06,0x11,0x22,0x1b,0x12,0x02,0x01,0x13,0x1c,0x22,0x10,0xfe,0xca,0x03,0x34,0x91,0x04,0xf0,0xfb,0x12,0x93,0x03,0xe5,0x2e,0x5f,0x4e,0x36,0x04,0x04,0x36,0x4e, +0x5f,0x2e,0xfc,0xb7,0x00,0x01,0x00,0x69,0xfe,0x39,0x04,0x62,0x05,0x45,0x00,0x07,0x00,0x45,0x40,0x0b,0x07,0x5a,0xd0,0x00,0xe0,0x00,0x02,0x00,0x00,0x01,0x00,0xb8,0xff,0xc0,0xb3,0x1d,0x20,0x48,0x00,0xb8,0xff,0xc0,0x40,0x17,0x15,0x19,0x48,0x00,0x00,0x09,0x03,0x5a,0x04,0x40,0x15,0x1d,0x48,0x10,0x04,0x01,0x04,0x02,0x5f,0x05, +0x03,0x04,0x00,0x00,0x2f,0x32,0x3f,0xed,0x01,0x2f,0x5d,0x2b,0xed,0x12,0x39,0x2f,0x2b,0x2b,0x5d,0x71,0xed,0x31,0x30,0x01,0x11,0x21,0x11,0x23,0x11,0x21,0x11,0x03,0xaa,0xfd,0x7e,0xbf,0x03,0xf9,0xfe,0x39,0x06,0x6a,0xf9,0x96,0x07,0x0c,0xf8,0xf4,0x00,0x01,0x00,0x1b,0xfe,0x39,0x04,0xb1,0x05,0x45,0x00,0x0b,0x00,0x79,0x40,0x0d, +0x29,0x01,0x69,0x01,0x79,0x01,0x89,0x01,0x04,0x24,0x03,0x01,0x03,0xb8,0xff,0xe0,0x40,0x1d,0x0e,0x11,0x48,0x08,0x5b,0x02,0x40,0x0e,0x11,0x48,0x02,0x02,0x05,0x01,0x07,0x5b,0x9f,0x05,0xaf,0x05,0xbf,0x05,0x03,0x03,0x05,0x03,0x05,0x01,0x0a,0xb8,0xff,0xc0,0x40,0x1b,0x09,0x25,0x48,0x0a,0x0a,0x0d,0x09,0x5b,0x01,0x40,0x0b,0x25, +0x48,0x01,0x03,0x07,0x5f,0x04,0x08,0x02,0x02,0x04,0x03,0x01,0x09,0x5f,0x00,0x00,0x2f,0xed,0x32,0x3f,0x39,0x19,0x2f,0x33,0x18,0x10,0xed,0x32,0x01,0x2f,0x2b,0xed,0x12,0x39,0x2f,0x2b,0x12,0x39,0x39,0x2f,0x2f,0x5d,0xed,0x11,0x12,0x39,0x2f,0x2b,0xed,0x31,0x30,0x00,0x2b,0x5d,0x5d,0x13,0x35,0x09,0x01,0x35,0x21,0x15,0x21,0x09, +0x01,0x21,0x15,0x1b,0x02,0x7b,0xfd,0x95,0x04,0x42,0xfc,0xb2,0x02,0x48,0xfd,0xa8,0x03,0xa2,0xfe,0x39,0x6d,0x03,0x22,0x03,0x13,0x6a,0x98,0xfd,0x1d,0xfd,0x07,0x98,0x00,0x01,0x00,0x75,0x02,0x60,0x04,0x58,0x02,0xf2,0x00,0x03,0x00,0x18,0x40,0x0c,0x03,0x05,0x00,0x00,0x10,0x00,0x02,0x00,0x00,0xad,0x01,0xb3,0x00,0x3f,0xed,0x01, +0x2f,0x5d,0x10,0xce,0x31,0x30,0x13,0x35,0x21,0x15,0x75,0x03,0xe3,0x02,0x60,0x92,0x92,0x00,0x00,0x00,0x00,0x01,0x01,0xf0,0x01,0xa4,0x02,0xdb,0x02,0xcf,0x00,0x03,0x00,0x28,0x40,0x18,0x03,0x96,0x00,0x00,0x01,0x00,0x00,0x04,0x05,0x01,0x9b,0x0f,0x00,0x1f,0x00,0x3f,0x00,0x03,0x00,0x40,0x0e,0x11,0x48,0x00,0x00,0x2f,0x2b,0x5d, +0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0xed,0x31,0x30,0x01,0x11,0x33,0x11,0x01,0xf0,0xeb,0x01,0xa4,0x01,0x2b,0xfe,0xd5,0x00,0x00,0x01,0x00,0x4e,0xff,0xf2,0x04,0x7d,0x06,0x54,0x00,0x08,0x00,0x54,0x40,0x34,0x76,0x00,0x01,0x06,0x05,0x16,0x05,0x02,0x2b,0x01,0x3b,0x01,0x4b,0x01,0x03,0x09,0x01,0x01,0x01,0x00,0x06,0x29,0x06,0x59, +0x06,0x69,0x06,0x89,0x06,0x04,0x15,0x06,0x01,0x06,0x02,0x07,0x08,0x08,0x03,0x0a,0x05,0x02,0x02,0x03,0x02,0xaf,0x05,0x05,0x07,0x19,0x06,0x00,0x00,0x2f,0x32,0x3f,0x39,0x2f,0xed,0x01,0x2f,0x33,0x2f,0x32,0x11,0x12,0x39,0x2f,0x33,0x12,0x39,0x5d,0x5d,0x11,0x33,0x33,0x31,0x30,0x5d,0x5d,0x5d,0x5d,0x05,0x23,0x01,0x23,0x35,0x21, +0x13,0x01,0x33,0x02,0x89,0x6a,0xfe,0xe5,0xb6,0x01,0x0e,0xf2,0x01,0xae,0x81,0x0e,0x03,0x18,0x75,0xfd,0x4e,0x05,0x87,0x00,0x00,0x03,0x00,0x1d,0x00,0xcb,0x04,0xab,0x03,0xd7,0x00,0x23,0x00,0x33,0x00,0x43,0x00,0x95,0x40,0x0f,0x45,0x43,0x55,0x43,0x65,0x43,0x03,0x4a,0x35,0x5a,0x35,0x6a,0x35,0x03,0x21,0xb8,0xff,0xe8,0x40,0x09, +0x09,0x0c,0x48,0x03,0x18,0x09,0x0c,0x48,0x15,0xb8,0xff,0xe8,0x40,0x49,0x09,0x0c,0x48,0x0f,0x18,0x09,0x0c,0x48,0x08,0x1a,0x27,0x1a,0x34,0x03,0x12,0x2f,0xaa,0x0f,0x00,0x4f,0x00,0x5f,0x00,0x03,0x00,0x45,0x3c,0xaa,0x12,0x40,0x12,0x22,0x48,0x12,0x40,0x0b,0x0f,0x48,0x12,0x24,0x37,0xad,0x27,0x34,0x08,0x34,0x1a,0x03,0x0d,0x1f, +0x17,0x2a,0x41,0xad,0x05,0x3f,0x0d,0x5f,0x0d,0xff,0x0d,0x03,0x0d,0x40,0x1b,0x2c,0x48,0x0d,0x40,0x12,0x16,0x48,0x0d,0x00,0x2f,0x2b,0x2b,0x5d,0x33,0xed,0x32,0x2f,0x33,0x12,0x17,0x39,0x11,0x33,0xed,0x32,0x01,0x2f,0x2b,0x2b,0xed,0x10,0xde,0x5d,0xed,0x12,0x17,0x39,0x11,0x33,0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x5d,0x5d,0x01, +0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x3e,0x03,0x33,0x32,0x1e,0x02,0x25,0x22,0x06,0x07,0x1e,0x01,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x05,0x2e,0x01,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x36,0x04,0xab,0x28,0x4a,0x68,0x40,0x58,0x99,0x3f, +0x1c,0x45,0x4c,0x51,0x2a,0x3e,0x69,0x4b,0x2a,0x28,0x4b,0x69,0x40,0x55,0x99,0x3c,0x1d,0x42,0x4d,0x55,0x2f,0x3f,0x67,0x49,0x29,0xfe,0xce,0x3d,0x67,0x30,0x2d,0x66,0x42,0x26,0x3d,0x2c,0x17,0x19,0x2c,0x3d,0xfe,0x84,0x2c,0x67,0x43,0x25,0x3c,0x2b,0x17,0x15,0x2a,0x3e,0x28,0x3c,0x68,0x02,0x4e,0x4e,0x8d,0x6a,0x3e,0x85,0x95,0x3f, +0x66,0x48,0x27,0x37,0x64,0x90,0x58,0x51,0x8e,0x68,0x3c,0x87,0x94,0x3e,0x66,0x49,0x28,0x37,0x65,0x8f,0xa8,0x7e,0x82,0x80,0x80,0x28,0x46,0x5e,0x36,0x36,0x5c,0x45,0x27,0xfa,0x80,0x80,0x28,0x46,0x5e,0x36,0x33,0x5d,0x45,0x29,0x7e,0x00,0x00,0x00,0x00,0x01,0x00,0x34,0x00,0x00,0x04,0x98,0x04,0xc7,0x00,0x05,0x00,0x13,0xb7,0x02, +0xac,0x05,0x03,0x02,0xaf,0x05,0x00,0x00,0x2f,0x2f,0xed,0x01,0x2f,0x2f,0xed,0x31,0x30,0x13,0x33,0x11,0x21,0x15,0x21,0x34,0x5e,0x04,0x06,0xfb,0x9c,0x04,0xc7,0xfb,0x97,0x5e,0x00,0x00,0x00,0x01,0x00,0x9c,0xff,0xfe,0x04,0x30,0x04,0x08,0x00,0x19,0x00,0x37,0x40,0x23,0x40,0x08,0x50,0x08,0x02,0x4f,0x04,0x5f,0x04,0x02,0x0c,0xac, +0x00,0x0d,0x10,0x0d,0x20,0x0d,0x03,0x0d,0x0d,0x1b,0x19,0xac,0x00,0x00,0x10,0x00,0x02,0x00,0x13,0xaf,0x06,0x0d,0x00,0x00,0x2f,0x32,0x2f,0xed,0x01,0x2f,0x5d,0xed,0x11,0x33,0x2f,0x5d,0xed,0x31,0x30,0x5d,0x5d,0x17,0x11,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x11,0x23,0x11,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x11,0x9c, +0x44,0x7a,0xa7,0x62,0x63,0xa9,0x7b,0x46,0x67,0x35,0x5f,0x82,0x4e,0x4e,0x82,0x5e,0x34,0x02,0x02,0x00,0x74,0xc0,0x8a,0x4c,0x4c,0x8a,0xc0,0x74,0xfe,0x00,0x02,0x02,0x62,0x9b,0x6c,0x39,0x38,0x6c,0x9c,0x64,0xfe,0x00,0x00,0x00,0x00,0x01,0x00,0xeb,0xfe,0x39,0x03,0xe1,0x05,0xe3,0x00,0x23,0x00,0x3c,0x40,0x24,0x0a,0x09,0x1a,0x09, +0x2a,0x09,0x03,0x05,0x1b,0x15,0x1b,0x25,0x1b,0x03,0x20,0x20,0x06,0xab,0x17,0x0e,0x0e,0x00,0x17,0x10,0x17,0x02,0x17,0x17,0x24,0x25,0x00,0xad,0x1d,0x12,0xad,0x0b,0x00,0x2f,0xed,0x2f,0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0x33,0x2f,0x10,0xed,0x32,0x2f,0x31,0x30,0x00,0x5d,0x5d,0x01,0x22,0x0e,0x02,0x15,0x11,0x14,0x0e,0x02,0x23, +0x22,0x26,0x27,0x35,0x1e,0x01,0x33,0x32,0x3e,0x02,0x35,0x11,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x15,0x2e,0x01,0x03,0x6e,0x33,0x42,0x27,0x10,0x32,0x59,0x7c,0x4a,0x24,0x4b,0x17,0x14,0x3e,0x23,0x33,0x41,0x27,0x0f,0x32,0x5a,0x7d,0x4b,0x22,0x4b,0x16,0x12,0x3d,0x05,0x58,0x28,0x41,0x54,0x2c,0xfb,0x2d,0x5e,0x86,0x56,0x29,0x0b, +0x08,0x93,0x08,0x10,0x25,0x40,0x54,0x30,0x04,0xd1,0x5e,0x86,0x56,0x28,0x09,0x09,0x94,0x0a,0x11,0x00,0x00,0x02,0x00,0x6c,0x01,0x50,0x04,0x60,0x03,0xf4,0x00,0x22,0x00,0x44,0x00,0xb4,0x40,0x13,0x25,0x30,0x09,0x14,0x00,0x4c,0x2a,0x30,0x09,0x14,0x00,0x4c,0x29,0x30,0x09,0x14,0x00,0x4c,0x38,0xb8,0xff,0xc0,0x40,0x24,0x09,0x14, +0x00,0x4c,0x39,0x30,0x09,0x14,0x00,0x4c,0x16,0x11,0x26,0x11,0x36,0x11,0x66,0x11,0x96,0x11,0xa6,0x11,0x06,0x20,0x30,0x09,0x14,0x00,0x4c,0x21,0x30,0x09,0x14,0x00,0x4c,0x0c,0xb8,0xff,0xc0,0x40,0x46,0x09,0x14,0x00,0x4c,0x0d,0x30,0x09,0x14,0x00,0x4c,0x27,0x1e,0x46,0x37,0x10,0x0b,0x01,0x0b,0x32,0xad,0x26,0x3b,0x40,0x17,0x1c, +0x48,0x3b,0x40,0x09,0x0c,0x48,0x3b,0x37,0x23,0xad,0x6f,0x2c,0x01,0x2c,0x40,0x12,0x15,0x48,0x10,0x2c,0x20,0x2c,0x02,0x2c,0x06,0xad,0x1d,0x0f,0x40,0x17,0x1c,0x48,0x0f,0x40,0x09,0x0c,0x48,0x0f,0x0b,0x1a,0xad,0x3f,0x00,0x01,0x00,0x00,0x2f,0x5d,0xed,0x33,0xdd,0x2b,0x2b,0x32,0xed,0x2f,0x5d,0x2b,0x5d,0xed,0x33,0xdd,0x2b,0x2b, +0x32,0xed,0x01,0x2f,0x5d,0x33,0x10,0xce,0x32,0x31,0x30,0x2b,0x00,0x2b,0x2b,0x2b,0x5d,0x01,0x2b,0x00,0x2b,0x2b,0x2b,0x2b,0x01,0x22,0x26,0x27,0x2e,0x01,0x23,0x22,0x0e,0x02,0x07,0x35,0x3e,0x01,0x33,0x32,0x16,0x17,0x1e,0x01,0x17,0x1e,0x03,0x33,0x32,0x36,0x37,0x15,0x0e,0x03,0x03,0x32,0x36,0x37,0x15,0x0e,0x03,0x23,0x22,0x26, +0x27,0x2e,0x01,0x23,0x22,0x0e,0x02,0x07,0x35,0x3e,0x01,0x33,0x32,0x1e,0x02,0x17,0x1e,0x03,0x03,0x5c,0x45,0x91,0x49,0x41,0x6b,0x2d,0x26,0x41,0x3c,0x38,0x1d,0x32,0x84,0x51,0x4d,0x93,0x46,0x04,0x07,0x04,0x15,0x32,0x33,0x33,0x17,0x45,0x7b,0x34,0x1f,0x3c,0x3d,0x44,0x18,0x45,0x7b,0x34,0x1f,0x3c,0x3d,0x44,0x28,0x45,0x91,0x49, +0x41,0x6b,0x2d,0x26,0x41,0x3c,0x38,0x1d,0x32,0x84,0x51,0x29,0x4f,0x4d,0x4b,0x25,0x15,0x32,0x33,0x33,0x02,0xf6,0x2b,0x1a,0x16,0x17,0x0c,0x16,0x21,0x15,0x90,0x25,0x2f,0x2c,0x19,0x02,0x01,0x02,0x07,0x10,0x0e,0x08,0x33,0x2b,0x95,0x16,0x1f,0x13,0x08,0xfe,0xe3,0x32,0x2a,0x93,0x17,0x20,0x13,0x08,0x2c,0x1a,0x17,0x18,0x0c,0x17, +0x20,0x15,0x8d,0x26,0x2e,0x0d,0x14,0x1a,0x0d,0x07,0x10,0x0e,0x08,0x00,0x00,0x00,0x00,0x01,0x00,0x74,0x00,0x37,0x04,0x57,0x05,0x10,0x00,0x13,0x00,0x84,0x40,0x58,0x0d,0x10,0x11,0x00,0x04,0x01,0x0c,0x01,0x0a,0x07,0x06,0x03,0x04,0x02,0x0b,0x0b,0x0c,0x02,0x40,0x09,0x0c,0x48,0x02,0x0c,0x02,0x0c,0x04,0x13,0x0e,0x15,0x08,0x00, +0x04,0x10,0x04,0x02,0x04,0x10,0x08,0xad,0x0d,0x0b,0x30,0x09,0x50,0x09,0x60,0x09,0x70,0x09,0x04,0x50,0x09,0x70,0x09,0x80,0x09,0xb0,0x09,0xd0,0x09,0x05,0x0f,0x09,0x01,0x09,0x11,0x05,0xad,0x02,0x00,0x1f,0x04,0x7f,0x04,0x9f,0x04,0xaf,0x04,0xbf,0x04,0x05,0x04,0x40,0x12,0x16,0x48,0x04,0x00,0x2f,0x2b,0x71,0x33,0xc6,0xed,0x32, +0x2f,0x5d,0x5d,0x71,0xc6,0x33,0xed,0x32,0x01,0x2f,0x5d,0x33,0x10,0xce,0x32,0x11,0x39,0x39,0x2f,0x2f,0x2b,0x11,0x33,0x11,0x12,0x17,0x39,0x32,0x11,0x12,0x17,0x39,0x31,0x30,0x01,0x03,0x23,0x13,0x23,0x35,0x21,0x13,0x21,0x35,0x21,0x13,0x33,0x03,0x21,0x15,0x21,0x03,0x21,0x15,0x01,0xf3,0x98,0x91,0x97,0xed,0x01,0x37,0xbe,0xfe, +0x0b,0x02,0x3d,0x9a,0x8f,0x98,0x01,0x15,0xfe,0xa2,0xbf,0x02,0x1d,0x01,0x58,0xfe,0xdf,0x01,0x21,0x94,0x01,0x6c,0x94,0x01,0x24,0xfe,0xdc,0x94,0xfe,0x94,0x94,0x00,0x00,0x03,0x00,0x74,0x00,0xf4,0x04,0x57,0x04,0x50,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x43,0x40,0x2a,0x0b,0x07,0x02,0x0d,0x08,0x04,0x00,0x00,0x10,0x00,0x02,0x00, +0x08,0xad,0x09,0x09,0x01,0x05,0xad,0x04,0x00,0xad,0x6f,0x01,0x9f,0x01,0xaf,0x01,0xcf,0x01,0xef,0x01,0x05,0x50,0x01,0x01,0x0f,0x01,0x1f,0x01,0x02,0x01,0x00,0x2f,0x5d,0x5d,0x5d,0xed,0x2f,0xed,0x11,0x39,0x2f,0xed,0x01,0x2f,0x5d,0x33,0x33,0x10,0xce,0x32,0x32,0x31,0x30,0x13,0x35,0x21,0x15,0x01,0x35,0x21,0x15,0x01,0x35,0x21, +0x15,0x74,0x03,0xe3,0xfc,0x1d,0x03,0xe3,0xfc,0x1d,0x03,0xe3,0x03,0xbc,0x94,0x94,0xfd,0x38,0x94,0x94,0x01,0x64,0x94,0x94,0x00,0x02,0x00,0x73,0x00,0x00,0x04,0x58,0x04,0xcf,0x00,0x06,0x00,0x0a,0x00,0x89,0xb7,0x0a,0x07,0x00,0x01,0x52,0x05,0x04,0x05,0xb8,0x01,0x0d,0x40,0x10,0x06,0x00,0x14,0x06,0x00,0x05,0x06,0x01,0x02,0x01, +0x52,0x03,0x04,0x01,0x04,0x03,0xb8,0x01,0x0d,0x40,0x32,0x02,0x01,0x14,0x02,0x01,0x03,0x02,0x06,0x0c,0x04,0x00,0x00,0x10,0x00,0x02,0x00,0x08,0xad,0x07,0x01,0x00,0x04,0x04,0x02,0x05,0xd0,0x06,0x01,0x2f,0x06,0x3f,0x06,0x02,0x06,0x03,0x70,0x02,0x80,0x02,0xb0,0x02,0x03,0x0f,0x02,0x4f,0x02,0x5f,0x02,0x03,0x02,0x00,0x2f,0x5d, +0x5d,0x33,0x2f,0x5d,0x5d,0x33,0x12,0x39,0x3d,0x2f,0x33,0x33,0x18,0x2f,0xed,0x01,0x2f,0x5d,0x33,0x10,0xde,0xd4,0xc1,0x87,0x04,0x2b,0x10,0x01,0xc1,0x87,0x04,0x2b,0x10,0xc4,0x10,0x01,0xc1,0x87,0x04,0x18,0x2b,0x87,0x2b,0xc4,0x01,0x32,0x33,0x31,0x30,0x13,0x35,0x01,0x15,0x09,0x01,0x15,0x05,0x35,0x21,0x15,0x75,0x03,0xe3,0xfc, +0xa6,0x03,0x5a,0xfc,0x1b,0x03,0xe3,0x02,0x77,0xcd,0x01,0x8b,0x9a,0xfe,0xa8,0xfe,0xa8,0x99,0xec,0x91,0x91,0x00,0x00,0x00,0x00,0x02,0x00,0x74,0x00,0x00,0x04,0x57,0x04,0xcf,0x00,0x06,0x00,0x0a,0x00,0x89,0xb7,0x0a,0x07,0x06,0x01,0x52,0x01,0x02,0x01,0xb8,0x01,0x0d,0x40,0x10,0x00,0x06,0x14,0x00,0x06,0x01,0x00,0x05,0x04,0x01, +0x52,0x03,0x02,0x05,0x02,0x03,0xb8,0x01,0x0d,0x40,0x32,0x04,0x05,0x14,0x04,0x05,0x03,0x04,0x02,0x06,0x0c,0x04,0x00,0x00,0x10,0x00,0x02,0x00,0x08,0xad,0x07,0x06,0x05,0x02,0x02,0x03,0x70,0x04,0x80,0x04,0xb0,0x04,0x03,0x0f,0x04,0x4f,0x04,0x5f,0x04,0x03,0x04,0x01,0xd0,0x00,0x01,0x2f,0x00,0x3f,0x00,0x02,0x00,0x00,0x2f,0x5d, +0x5d,0x32,0x2f,0x5d,0x5d,0x33,0x39,0x3d,0x2f,0x33,0x33,0x18,0x2f,0xed,0x01,0x2f,0x5d,0xc4,0x10,0xce,0x32,0x10,0xc1,0x87,0x04,0x2b,0x10,0x01,0xc1,0x87,0x04,0x2b,0x10,0xc4,0x10,0x01,0xc1,0x87,0x04,0x18,0x2b,0x87,0x2b,0xc4,0x01,0x33,0x32,0x31,0x30,0x37,0x35,0x09,0x01,0x35,0x01,0x15,0x01,0x35,0x21,0x15,0x74,0x03,0x5a,0xfc, +0xa6,0x03,0xe3,0xfc,0x1d,0x03,0xe3,0xec,0x99,0x01,0x58,0x01,0x58,0x9a,0xfe,0x75,0xcd,0xfd,0x89,0x91,0x91,0x00,0x00,0x00,0x00,0x02,0x00,0x8a,0x00,0x00,0x04,0x42,0x04,0x3b,0x00,0x04,0x00,0x09,0x00,0x2c,0x40,0x19,0x04,0xac,0x40,0x06,0x0b,0x80,0x05,0xac,0x00,0x00,0x10,0x00,0x02,0x00,0x49,0x08,0x59,0x08,0x02,0x08,0xaf,0x02, +0x05,0xaf,0x00,0x00,0x2f,0xed,0x2f,0xed,0x5d,0x01,0x2f,0x5d,0xed,0x1a,0x10,0xdc,0x1a,0xed,0x31,0x30,0x33,0x11,0x09,0x01,0x11,0x25,0x21,0x11,0x09,0x01,0x8a,0x01,0xdc,0x01,0xdc,0xfc,0x9b,0x03,0x12,0xfe,0x77,0xfe,0x77,0x02,0x7b,0x01,0xc0,0xfe,0x40,0xfd,0x85,0x55,0x02,0x00,0x01,0x72,0xfe,0x8e,0x00,0x00,0x00,0x01,0x00,0x73, +0x00,0xb4,0x04,0x57,0x02,0xf2,0x00,0x05,0x00,0x28,0x40,0x18,0x04,0x07,0x01,0xaa,0x00,0x02,0x10,0x02,0x02,0x02,0x00,0xad,0x0f,0x03,0x3f,0x03,0xef,0x03,0x03,0x03,0x3f,0x01,0x01,0x01,0x00,0x2f,0x5d,0x2f,0x5d,0xed,0x01,0x2f,0x5d,0xed,0x10,0xce,0x31,0x30,0x01,0x11,0x23,0x13,0x21,0x15,0x01,0x06,0x93,0x01,0x03,0xe3,0x02,0x60, +0xfe,0x54,0x02,0x3e,0x92,0x00,0x00,0x00,0x00,0x01,0x02,0x1e,0xfd,0x99,0x04,0x02,0x06,0xa9,0x00,0x19,0x00,0x2b,0x40,0x1a,0x6b,0x12,0x7b,0x12,0x8b,0x12,0x03,0x64,0x0a,0x74,0x0a,0x84,0x0a,0x03,0x6f,0x0c,0x01,0x0c,0x80,0x00,0x49,0x01,0x14,0x0f,0x07,0x00,0x00,0x2f,0x2f,0xcd,0xcd,0x01,0x2f,0xfd,0x1a,0xcc,0x5d,0x31,0x30,0x5d, +0x5d,0x01,0x23,0x11,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x06,0x23,0x22,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x02,0xaf,0x91,0x25,0x4c,0x76,0x52,0x20,0x3e,0x30,0x1d,0x32,0x23,0x27,0x2b,0x1d,0x1b,0x16,0x19,0x23,0x17,0x0b,0xfd,0x99,0x07,0x1e,0x69,0xb6,0x86,0x4d,0x12,0x21,0x30,0x1e,0x27,0x31,0x24,0x2b,0x24,0x21,0x4b, +0x79,0x59,0x00,0x00,0x00,0x01,0x00,0xcb,0xfd,0x99,0x02,0xaf,0x06,0xa9,0x00,0x19,0x00,0x2b,0x40,0x1a,0x64,0x12,0x74,0x12,0x84,0x12,0x03,0x6b,0x0a,0x7b,0x0a,0x8b,0x0a,0x03,0x60,0x0c,0x01,0x0c,0x80,0x02,0x49,0x19,0x14,0x0f,0x07,0x00,0x00,0x2f,0x2f,0xcd,0xcd,0x01,0x2f,0xed,0x1a,0xcc,0x5d,0x31,0x30,0x5d,0x5d,0x01,0x33,0x11, +0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x36,0x33,0x32,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x02,0x1e,0x91,0x24,0x4d,0x76,0x52,0x20,0x3e,0x30,0x1d,0x32,0x23,0x27,0x2b,0x1d,0x1b,0x16,0x19,0x23,0x17,0x0b,0x06,0xa9,0xf8,0xe2,0x69,0xb6,0x86,0x4d,0x12,0x21,0x30,0x1e,0x27,0x31,0x24,0x2b,0x24,0x21,0x4b,0x79,0x59,0x00,0x00, +0x00,0x01,0xff,0xf6,0x02,0x2b,0x04,0xd7,0x02,0xbc,0x00,0x03,0x00,0x16,0xb4,0x02,0x02,0x05,0x00,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed,0x01,0x2f,0x11,0x33,0x2f,0x31,0x30,0x03,0x35,0x21,0x15,0x0a,0x04,0xe1,0x02,0x2b,0x91,0x91,0x00,0x00,0x01,0x02,0x1e,0xfd,0x99,0x02,0xaf,0x06,0xa9,0x00,0x03,0x00,0x10,0xb6,0x02, +0xff,0x03,0x02,0xfe,0x00,0xfa,0x00,0x3f,0x3f,0x01,0x2f,0xed,0x31,0x30,0x01,0x33,0x11,0x23,0x02,0x1e,0x91,0x91,0x06,0xa9,0xf6,0xf0,0x00,0x00,0x00,0x01,0x02,0x1e,0xfd,0x99,0x04,0xd7,0x02,0xbc,0x00,0x05,0x00,0x1d,0x40,0x09,0x01,0x01,0x07,0x04,0xff,0x05,0x04,0xfe,0x03,0xb8,0x01,0x00,0xb1,0x00,0xfc,0x00,0x3f,0xed,0x3f,0x01, +0x2f,0xed,0x11,0x33,0x2f,0x31,0x30,0x01,0x21,0x15,0x21,0x11,0x23,0x02,0x1e,0x02,0xb9,0xfd,0xd8,0x91,0x02,0xbc,0x91,0xfb,0x6e,0x00,0x00,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x02,0xaf,0x02,0xbc,0x00,0x05,0x00,0x18,0xb6,0x00,0x03,0xff,0x04,0x03,0xfe,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed,0x3f,0x01,0x2f,0xed,0x2f, +0x31,0x30,0x03,0x35,0x21,0x11,0x23,0x11,0x0a,0x02,0xb9,0x91,0x02,0x2b,0x91,0xfa,0xdd,0x04,0x92,0x00,0x00,0x01,0x02,0x1e,0x02,0x2b,0x04,0xd7,0x06,0xa9,0x00,0x05,0x00,0x1c,0xb6,0x03,0x03,0x07,0x02,0xff,0x05,0x05,0xb8,0x01,0x00,0xb3,0x02,0xfc,0x00,0xfa,0x00,0x3f,0x3f,0xed,0x01,0x2f,0xed,0x11,0x33,0x2f,0x31,0x30,0x01,0x33, +0x11,0x21,0x15,0x21,0x02,0x1e,0x91,0x02,0x28,0xfd,0x47,0x06,0xa9,0xfc,0x13,0x91,0x00,0x01,0xff,0xf6,0x02,0x2b,0x02,0xaf,0x06,0xa9,0x00,0x05,0x00,0x18,0xb6,0x05,0xff,0x02,0x00,0x03,0xfa,0x05,0xb8,0x01,0x00,0xb1,0x02,0xfc,0x00,0x3f,0xed,0x3f,0x01,0x2f,0x2f,0xed,0x31,0x30,0x03,0x35,0x21,0x11,0x33,0x11,0x0a,0x02,0x28,0x91, +0x02,0x2b,0x91,0x03,0xed,0xfb,0x82,0x00,0x00,0x01,0x02,0x1e,0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x07,0x00,0x22,0x40,0x0a,0x03,0x03,0x09,0x02,0x06,0xff,0x07,0x06,0xfe,0x05,0xb8,0x01,0x00,0xb3,0x02,0xfc,0x00,0xfa,0x00,0x3f,0x3f,0xed,0x3f,0x01,0x2f,0xed,0x32,0x11,0x33,0x2f,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x11,0x23, +0x02,0x1e,0x91,0x02,0x28,0xfd,0xd8,0x91,0x06,0xa9,0xfc,0x13,0x91,0xfb,0x6e,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x02,0xaf,0x06,0xa9,0x00,0x07,0x00,0x1e,0x40,0x0a,0x05,0xff,0x02,0x06,0x00,0x05,0xfe,0x03,0xfa,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed,0x3f,0x3f,0x01,0x2f,0x2f,0x33,0xed,0x31,0x30,0x03,0x35,0x21,0x11, +0x33,0x11,0x23,0x11,0x0a,0x02,0x28,0x91,0x91,0x02,0x2b,0x91,0x03,0xed,0xf6,0xf0,0x04,0x92,0x00,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x02,0xbc,0x00,0x07,0x00,0x21,0x40,0x0b,0x02,0x02,0x09,0x05,0xff,0x06,0x01,0x05,0xfe,0x04,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed,0x32,0x3f,0x01,0x2f,0x2f,0xed,0x11,0x33, +0x2f,0x31,0x30,0x03,0x35,0x21,0x15,0x21,0x11,0x23,0x11,0x0a,0x04,0xe1,0xfd,0xd8,0x91,0x02,0x2b,0x91,0x91,0xfb,0x6e,0x04,0x92,0x00,0x00,0x00,0x00,0x01,0xff,0xf6,0x02,0x2b,0x04,0xd7,0x06,0xa9,0x00,0x07,0x00,0x21,0x40,0x0b,0x06,0x06,0x09,0x05,0xff,0x02,0x01,0x03,0xfa,0x05,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed, +0x33,0x3f,0x01,0x2f,0x2f,0xed,0x11,0x33,0x2f,0x31,0x30,0x03,0x35,0x21,0x11,0x33,0x11,0x21,0x15,0x0a,0x02,0x28,0x91,0x02,0x28,0x02,0x2b,0x91,0x03,0xed,0xfc,0x13,0x91,0x00,0x00,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x0b,0x00,0x2a,0x40,0x0f,0x06,0x06,0x0d,0x05,0x09,0xff,0x02,0x0a,0x01,0x09,0xfe,0x03, +0xfa,0x08,0x00,0xb8,0x01,0x00,0xb2,0x05,0x01,0xfc,0x00,0x3f,0x33,0xed,0x32,0x3f,0x3f,0x01,0x2f,0x2f,0x33,0xed,0x32,0x11,0x33,0x2f,0x31,0x30,0x03,0x35,0x21,0x11,0x33,0x11,0x21,0x15,0x21,0x11,0x23,0x11,0x0a,0x02,0x28,0x91,0x02,0x28,0xfd,0xd8,0x91,0x02,0x2b,0x91,0x03,0xed,0xfc,0x13,0x91,0xfb,0x6e,0x04,0x92,0x00,0x00,0x00, +0x00,0x02,0xff,0xf6,0x01,0x77,0x04,0xd7,0x03,0x70,0x00,0x03,0x00,0x07,0x00,0x23,0xb6,0x07,0x02,0x02,0x09,0x04,0x00,0x04,0xb8,0x01,0x00,0xb2,0x05,0xfd,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfb,0x00,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x33,0x11,0x33,0x2f,0x33,0x31,0x30,0x03,0x35,0x21,0x15,0x01,0x35,0x21,0x15,0x0a,0x04,0xe1,0xfb,0x1f, +0x04,0xe1,0x02,0xdf,0x91,0x91,0xfe,0x98,0x91,0x91,0x00,0x00,0x00,0x02,0x01,0x6a,0xfd,0x99,0x03,0x63,0x06,0xa9,0x00,0x03,0x00,0x07,0x00,0x1e,0x40,0x0f,0x06,0xff,0x07,0x02,0xff,0x00,0x03,0x01,0x03,0x07,0x02,0xfe,0x04,0x00,0xfa,0x00,0x3f,0x32,0x3f,0x33,0x01,0x2f,0x5d,0xed,0x2f,0xed,0x31,0x30,0x01,0x33,0x11,0x23,0x01,0x33, +0x11,0x23,0x01,0x6a,0x91,0x91,0x01,0x68,0x91,0x91,0x06,0xa9,0xf6,0xf0,0x09,0x10,0xf6,0xf0,0x00,0x00,0x00,0x01,0x02,0x1e,0xfd,0x99,0x04,0xd7,0x03,0x70,0x00,0x09,0x00,0x2a,0x40,0x0b,0x06,0x01,0x01,0x0b,0x04,0x08,0xff,0x09,0x08,0xfe,0x07,0xb8,0x01,0x00,0xb2,0x04,0xfd,0x03,0xb8,0x01,0x00,0xb1,0x00,0xfb,0x00,0x3f,0xed,0x3f, +0xed,0x3f,0x01,0x2f,0xed,0x32,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x21,0x15,0x21,0x15,0x21,0x15,0x21,0x11,0x23,0x02,0x1e,0x02,0xb9,0xfd,0xd8,0x02,0x28,0xfd,0xd8,0x91,0x03,0x70,0x91,0xd7,0x91,0xfc,0x22,0x00,0x01,0x01,0x6a,0xfd,0x99,0x04,0xd7,0x02,0xbc,0x00,0x09,0x00,0x2a,0x40,0x0e,0x00,0x00,0x0b,0x07,0xff,0x00,0x08,0x01, +0x08,0x03,0xff,0x04,0x02,0x06,0xb8,0x01,0x00,0xb4,0x09,0xfc,0x08,0x03,0xfe,0x00,0x3f,0x33,0x3f,0xed,0x32,0x01,0x2f,0xed,0x2f,0x5d,0xed,0x11,0x33,0x2f,0x31,0x30,0x01,0x15,0x21,0x11,0x23,0x11,0x23,0x11,0x23,0x11,0x04,0xd7,0xfe,0x8c,0x91,0xd7,0x91,0x02,0xbc,0x91,0xfb,0x6e,0x04,0x92,0xfb,0x6e,0x05,0x23,0x00,0x02,0x01,0x6a, +0xfd,0x99,0x04,0xd7,0x03,0x70,0x00,0x05,0x00,0x0b,0x00,0x33,0x40,0x0e,0x08,0x01,0x01,0x0d,0x0a,0xff,0x0b,0x04,0xff,0x00,0x05,0x01,0x05,0x09,0xb8,0x01,0x00,0xb5,0x06,0xfd,0x0b,0x04,0xfe,0x03,0xb8,0x01,0x00,0xb1,0x00,0xfb,0x00,0x3f,0xed,0x3f,0x33,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x2f,0xed,0x11,0x33,0x2f,0x33,0x31,0x30,0x01, +0x21,0x15,0x21,0x11,0x23,0x01,0x21,0x15,0x21,0x11,0x23,0x01,0x6a,0x03,0x6d,0xfd,0x24,0x91,0x01,0x68,0x02,0x05,0xfe,0x8c,0x91,0x03,0x70,0x91,0xfa,0xba,0x04,0x6f,0x91,0xfc,0x22,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x02,0xaf,0x03,0x70,0x00,0x09,0x00,0x26,0x40,0x09,0x07,0xff,0x02,0x08,0x04,0x00,0x07,0xfe,0x04,0xb8,0x01,0x00, +0xb2,0x05,0xfb,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfd,0x00,0x3f,0xed,0x3f,0xed,0x3f,0x01,0x2f,0x33,0x2f,0x33,0xed,0x31,0x30,0x03,0x35,0x21,0x35,0x21,0x35,0x21,0x11,0x23,0x11,0x0a,0x02,0x28,0xfd,0xd8,0x02,0xb9,0x91,0x01,0x77,0x91,0xd7,0x91,0xfa,0x29,0x03,0xde,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x03,0x63,0x02,0xbc,0x00,0x09, +0x00,0x26,0x40,0x0f,0x07,0xff,0x00,0x08,0x01,0x08,0x03,0xff,0x04,0x00,0x08,0x03,0xfe,0x06,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed,0x32,0x3f,0x33,0x01,0x2f,0x2f,0xed,0x2f,0x5d,0xed,0x31,0x30,0x03,0x35,0x21,0x11,0x23,0x11,0x23,0x11,0x23,0x11,0x0a,0x03,0x6d,0x91,0xd7,0x91,0x02,0x2b,0x91,0xfa,0xdd,0x04,0x92,0xfb, +0x6e,0x04,0x92,0x00,0x00,0x02,0xff,0xf6,0xfd,0x99,0x03,0x63,0x03,0x70,0x00,0x05,0x00,0x0b,0x00,0x2f,0x40,0x0c,0x06,0xff,0x00,0x07,0x01,0x07,0x09,0x04,0x01,0xff,0x02,0x09,0xb8,0x01,0x00,0xb2,0x0a,0xfd,0x04,0xb8,0x01,0x00,0xb4,0x05,0xfb,0x07,0x01,0xfe,0x00,0x3f,0x33,0x3f,0xed,0x3f,0xed,0x01,0x2f,0xed,0x2f,0x33,0x2f,0x5d, +0xed,0x31,0x30,0x01,0x11,0x23,0x11,0x21,0x35,0x01,0x23,0x11,0x21,0x35,0x21,0x03,0x63,0x91,0xfd,0x24,0x02,0x05,0x91,0xfe,0x8c,0x02,0x05,0x03,0x70,0xfa,0x29,0x05,0x46,0x91,0xfa,0x29,0x03,0xde,0x91,0x00,0x00,0x01,0x02,0x1e,0x01,0x77,0x04,0xd7,0x06,0xa9,0x00,0x09,0x00,0x2a,0x40,0x09,0x08,0x03,0x03,0x0b,0x02,0x06,0xff,0x09, +0x09,0xb8,0x01,0x00,0xb2,0x06,0xfd,0x05,0xb8,0x01,0x00,0xb3,0x02,0xfb,0x00,0xfa,0x00,0x3f,0x3f,0xed,0x3f,0xed,0x01,0x2f,0xed,0x32,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x15,0x21,0x15,0x21,0x02,0x1e,0x91,0x02,0x28,0xfd,0xd8,0x02,0x28,0xfd,0x47,0x06,0xa9,0xfc,0xc7,0x91,0xd7,0x91,0x00,0x01,0x01,0x6a, +0x02,0x2b,0x04,0xd7,0x06,0xa9,0x00,0x09,0x00,0x2a,0x40,0x0d,0x03,0x03,0x0b,0x02,0xff,0x09,0x08,0xff,0x00,0x05,0x01,0x05,0x05,0xb8,0x01,0x00,0xb5,0x02,0x08,0xfc,0x06,0x00,0xfa,0x00,0x3f,0x32,0x3f,0x33,0xed,0x01,0x2f,0x5d,0xed,0x2f,0xed,0x11,0x33,0x2f,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x11,0x33,0x11,0x33,0x02,0xd2, +0x91,0x01,0x74,0xfc,0x93,0x91,0xd7,0x06,0xa9,0xfc,0x13,0x91,0x04,0x7e,0xfc,0x13,0x00,0x02,0x01,0x6a,0x01,0x77,0x04,0xd7,0x06,0xa9,0x00,0x05,0x00,0x0b,0x00,0x33,0x40,0x0e,0x0a,0x03,0x03,0x0d,0x08,0xff,0x0b,0x02,0xff,0x00,0x05,0x01,0x05,0x0b,0xb8,0x01,0x00,0xb2,0x08,0xfb,0x05,0xb8,0x01,0x00,0xb4,0x02,0xfd,0x06,0x00,0xfa, +0x00,0x3f,0x32,0x3f,0xed,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x2f,0xed,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x01,0x33,0x11,0x21,0x15,0x21,0x01,0x6a,0x91,0x02,0xdc,0xfc,0x93,0x01,0x68,0x91,0x01,0x74,0xfd,0xfb,0x06,0xa9,0xfb,0x5f,0x91,0x05,0x32,0xfc,0xc7,0x91,0x00,0x00,0x01,0xff,0xf6,0x01,0x77,0x02,0xaf, +0x06,0xa9,0x00,0x09,0x00,0x26,0x40,0x09,0x09,0xff,0x06,0x02,0x04,0x00,0x07,0xfa,0x04,0xb8,0x01,0x00,0xb2,0x05,0xfb,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfd,0x00,0x3f,0xed,0x3f,0xed,0x3f,0x01,0x2f,0x33,0x2f,0x33,0xed,0x31,0x30,0x03,0x35,0x21,0x35,0x21,0x35,0x21,0x11,0x33,0x11,0x0a,0x02,0x28,0xfd,0xd8,0x02,0x28,0x91,0x01,0x77, +0x91,0xd7,0x91,0x03,0x39,0xfa,0xce,0x00,0x00,0x01,0xff,0xf6,0x02,0x2b,0x03,0x63,0x06,0xa9,0x00,0x09,0x00,0x26,0x40,0x0f,0x00,0xff,0x07,0x06,0xff,0x00,0x03,0x01,0x03,0x01,0x08,0x04,0xfa,0x06,0x01,0xb8,0x01,0x00,0xb1,0x02,0xfc,0x00,0x3f,0xed,0x33,0x3f,0x33,0x01,0x2f,0x2f,0x5d,0xed,0x2f,0xed,0x31,0x30,0x01,0x21,0x35,0x21, +0x11,0x33,0x11,0x33,0x11,0x33,0x03,0x63,0xfc,0x93,0x01,0x74,0x91,0xd7,0x91,0x02,0x2b,0x91,0x03,0xed,0xfc,0x13,0x03,0xed,0x00,0x02,0xff,0xf6,0x01,0x77,0x03,0x63,0x06,0xa9,0x00,0x05,0x00,0x0b,0x00,0x2f,0x40,0x0c,0x08,0xff,0x00,0x0b,0x01,0x0b,0x00,0xff,0x03,0x09,0x01,0x09,0xb8,0x01,0x00,0xb5,0x0a,0xfb,0x06,0x04,0xfa,0x01, +0xb8,0x01,0x00,0xb1,0x02,0xfd,0x00,0x3f,0xed,0x3f,0x33,0x3f,0xed,0x01,0x2f,0x33,0x2f,0xed,0x2f,0x5d,0xed,0x31,0x30,0x01,0x21,0x35,0x21,0x11,0x33,0x21,0x33,0x11,0x21,0x35,0x21,0x03,0x63,0xfc,0x93,0x02,0xdc,0x91,0xfe,0x07,0x91,0xfd,0xfb,0x01,0x74,0x01,0x77,0x91,0x04,0xa1,0xfc,0x36,0x91,0x00,0x00,0x00,0x00,0x01,0x02,0x1e, +0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x0b,0x00,0x2f,0x40,0x0c,0x08,0x03,0x03,0x0d,0x06,0x02,0x0a,0xff,0x0b,0x0a,0xfe,0x09,0xb8,0x01,0x00,0xb2,0x06,0xfd,0x05,0xb8,0x01,0x00,0xb3,0x02,0xfb,0x00,0xfa,0x00,0x3f,0x3f,0xed,0x3f,0xed,0x3f,0x01,0x2f,0xed,0x32,0x32,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x15, +0x21,0x15,0x21,0x11,0x23,0x02,0x1e,0x91,0x02,0x28,0xfd,0xd8,0x02,0x28,0xfd,0xd8,0x91,0x06,0xa9,0xfc,0xc7,0x91,0xd7,0x91,0xfc,0x22,0x00,0x00,0x00,0x02,0x01,0x6a,0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x07,0x00,0x0b,0x00,0x2f,0x40,0x11,0x03,0x03,0x0d,0x0a,0xff,0x00,0x0b,0x01,0x0b,0x02,0x06,0xff,0x07,0x0b,0x06,0xfe,0x05,0xb8, +0x01,0x00,0xb4,0x02,0xfc,0x08,0x00,0xfa,0x00,0x3f,0x32,0x3f,0xed,0x3f,0x33,0x01,0x2f,0xed,0x32,0x2f,0x5d,0xed,0x11,0x33,0x2f,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x11,0x23,0x01,0x33,0x11,0x23,0x02,0xd2,0x91,0x01,0x74,0xfe,0x8c,0x91,0xfe,0x98,0x91,0x91,0x06,0xa9,0xfc,0x13,0x91,0xfb,0x6e,0x09,0x10,0xf6,0xf0,0x00,0x00, +0x00,0x03,0x01,0x6a,0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x03,0x00,0x09,0x00,0x0f,0x00,0x3c,0x40,0x10,0x0e,0x05,0x05,0x11,0x0c,0x08,0xff,0x0f,0x09,0x00,0xff,0x00,0x01,0x01,0x01,0x0f,0xb8,0x01,0x00,0xb2,0x0c,0xfb,0x07,0xb8,0x01,0x00,0xb7,0x04,0xfd,0x0a,0x02,0xfa,0x09,0x00,0xfe,0x00,0x3f,0x32,0x3f,0x33,0x3f,0xed,0x3f,0xed, +0x01,0x2f,0x5d,0xed,0x2f,0x33,0xed,0x32,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x23,0x11,0x33,0x13,0x21,0x15,0x21,0x11,0x23,0x11,0x33,0x11,0x21,0x15,0x21,0x01,0xfb,0x91,0x91,0xd7,0x02,0x05,0xfe,0x8c,0x91,0x91,0x01,0x74,0xfd,0xfb,0xfd,0x99,0x09,0x10,0xfb,0x5f,0x91,0xfc,0x22,0x09,0x10,0xfc,0xc7,0x91,0x00,0x00,0x01,0xff,0xf6, +0xfd,0x99,0x02,0xaf,0x06,0xa9,0x00,0x0b,0x00,0x2b,0x40,0x0c,0x09,0xff,0x06,0x02,0x0a,0x04,0x00,0x09,0xfe,0x07,0xfa,0x04,0xb8,0x01,0x00,0xb2,0x05,0xfb,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfd,0x00,0x3f,0xed,0x3f,0xed,0x3f,0x3f,0x01,0x2f,0x33,0x2f,0x33,0x33,0xed,0x31,0x30,0x03,0x35,0x21,0x35,0x21,0x35,0x21,0x11,0x33,0x11,0x23, +0x11,0x0a,0x02,0x28,0xfd,0xd8,0x02,0x28,0x91,0x91,0x01,0x77,0x91,0xd7,0x91,0x03,0x39,0xf6,0xf0,0x03,0xde,0x00,0x00,0x00,0x00,0x02,0xff,0xf6,0xfd,0x99,0x03,0x63,0x06,0xa9,0x00,0x07,0x00,0x0b,0x00,0x2b,0x40,0x12,0x0a,0xff,0x0b,0x05,0xff,0x02,0x00,0x06,0x01,0x06,0x00,0x0b,0x05,0xfe,0x08,0x03,0xfa,0x00,0xb8,0x01,0x00,0xb1, +0x01,0xfc,0x00,0x3f,0xed,0x3f,0x33,0x3f,0x33,0x01,0x2f,0x2f,0x5d,0x33,0xed,0x2f,0xed,0x31,0x30,0x03,0x35,0x21,0x11,0x33,0x11,0x23,0x11,0x01,0x33,0x11,0x23,0x0a,0x01,0x74,0x91,0x91,0x01,0x68,0x91,0x91,0x02,0x2b,0x91,0x03,0xed,0xf6,0xf0,0x04,0x92,0x04,0x7e,0xf6,0xf0,0x00,0x00,0x00,0x00,0x03,0xff,0xf6,0xfd,0x99,0x03,0x63, +0x06,0xa9,0x00,0x03,0x00,0x09,0x00,0x0f,0x00,0x38,0x40,0x0e,0x06,0x0a,0xff,0x09,0x00,0x0b,0x01,0x0b,0x0d,0x07,0x02,0xff,0x03,0x0d,0xb8,0x01,0x00,0xb2,0x0e,0xfd,0x07,0xb8,0x01,0x00,0xb7,0x08,0xfb,0x0b,0x02,0xfe,0x04,0x00,0xfa,0x00,0x3f,0x32,0x3f,0x33,0x3f,0xed,0x3f,0xed,0x01,0x2f,0xed,0x2f,0x33,0x2f,0x5d,0x33,0xed,0x32, +0x31,0x30,0x01,0x33,0x11,0x23,0x01,0x33,0x11,0x21,0x35,0x21,0x13,0x23,0x11,0x21,0x35,0x21,0x02,0xd2,0x91,0x91,0xfe,0x98,0x91,0xfd,0xfb,0x01,0x74,0x91,0x91,0xfe,0x8c,0x02,0x05,0x06,0xa9,0xf6,0xf0,0x09,0x10,0xfc,0x36,0x91,0xfa,0x29,0x03,0xde,0x91,0x00,0x00,0x00,0x00,0x02,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x03,0x70,0x00,0x07, +0x00,0x0b,0x00,0x2e,0x40,0x0a,0x0b,0x02,0x02,0x0d,0x05,0xff,0x06,0x08,0x00,0x08,0xb8,0x01,0x00,0xb5,0x09,0xfb,0x05,0xfe,0x04,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfd,0x00,0x3f,0xed,0x32,0x3f,0x3f,0xed,0x01,0x2f,0x33,0x2f,0xed,0x11,0x33,0x2f,0x33,0x31,0x30,0x03,0x35,0x21,0x15,0x21,0x11,0x23,0x11,0x01,0x35,0x21,0x15,0x0a,0x04, +0xe1,0xfd,0xd8,0x91,0xfd,0xd8,0x04,0xe1,0x01,0x77,0x91,0x91,0xfc,0x22,0x03,0xde,0x01,0x68,0x91,0x91,0x00,0x01,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x02,0xbc,0x00,0x0b,0x00,0x2e,0x40,0x13,0x02,0x02,0x0d,0x09,0xff,0x00,0x0a,0x01,0x0a,0x05,0xff,0x06,0x00,0x0a,0x05,0xfe,0x08,0x04,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed, +0x32,0x32,0x3f,0x33,0x01,0x2f,0x2f,0xed,0x2f,0x5d,0xed,0x11,0x33,0x2f,0x31,0x30,0x03,0x35,0x21,0x15,0x21,0x11,0x23,0x11,0x23,0x11,0x23,0x11,0x0a,0x04,0xe1,0xfe,0x8c,0x91,0xd7,0x91,0x02,0x2b,0x91,0x91,0xfb,0x6e,0x04,0x92,0xfb,0x6e,0x04,0x92,0x00,0x03,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x03,0x70,0x00,0x05,0x00,0x0b,0x00,0x0f, +0x00,0x3b,0x40,0x10,0x0d,0x07,0x07,0x11,0x0a,0xff,0x0b,0x0e,0x03,0x00,0xff,0x00,0x01,0x01,0x01,0x0e,0xb8,0x01,0x00,0xb3,0x0f,0xfb,0x09,0x03,0xb8,0x01,0x00,0xb5,0x06,0x04,0xfd,0x0b,0x00,0xfe,0x00,0x3f,0x32,0x3f,0x33,0xed,0x32,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x2f,0x33,0x2f,0xed,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x23,0x11, +0x21,0x35,0x21,0x33,0x21,0x15,0x21,0x11,0x23,0x01,0x15,0x21,0x35,0x01,0xfb,0x91,0xfe,0x8c,0x02,0x05,0xd7,0x02,0x05,0xfe,0x8c,0x91,0x02,0x05,0xfb,0x1f,0xfd,0x99,0x03,0xde,0x91,0x91,0xfc,0x22,0x05,0xd7,0x91,0x91,0x00,0x00,0x00,0x02,0xff,0xf6,0x01,0x77,0x04,0xd7,0x06,0xa9,0x00,0x07,0x00,0x0b,0x00,0x2e,0x40,0x0a,0x0b,0x06, +0x06,0x0d,0x05,0xff,0x02,0x08,0x00,0x08,0xb8,0x01,0x00,0xb5,0x09,0xfd,0x03,0xfa,0x05,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfb,0x00,0x3f,0xed,0x33,0x3f,0x3f,0xed,0x01,0x2f,0x33,0x2f,0xed,0x11,0x33,0x2f,0x33,0x31,0x30,0x03,0x35,0x21,0x11,0x33,0x11,0x21,0x15,0x01,0x35,0x21,0x15,0x0a,0x02,0x28,0x91,0x02,0x28,0xfb,0x1f,0x04,0xe1, +0x02,0xdf,0x91,0x03,0x39,0xfc,0xc7,0x91,0xfe,0x98,0x91,0x91,0x00,0x01,0xff,0xf6,0x02,0x2b,0x04,0xd7,0x06,0xa9,0x00,0x0b,0x00,0x2e,0x40,0x13,0x0a,0x0a,0x0d,0x09,0xff,0x06,0x05,0xff,0x00,0x02,0x01,0x02,0x00,0x07,0x03,0xfa,0x09,0x05,0x00,0xb8,0x01,0x00,0xb1,0x01,0xfc,0x00,0x3f,0xed,0x33,0x33,0x3f,0x33,0x01,0x2f,0x2f,0x5d, +0xed,0x2f,0xed,0x11,0x33,0x2f,0x31,0x30,0x03,0x35,0x21,0x11,0x33,0x11,0x33,0x11,0x33,0x11,0x21,0x15,0x0a,0x01,0x74,0x91,0xd7,0x91,0x01,0x74,0x02,0x2b,0x91,0x03,0xed,0xfc,0x13,0x03,0xed,0xfc,0x13,0x91,0x00,0x03,0xff,0xf6,0x01,0x77,0x04,0xd7,0x06,0xa9,0x00,0x05,0x00,0x0b,0x00,0x0f,0x00,0x3b,0x40,0x10,0x0f,0x03,0x03,0x11, +0x08,0xff,0x00,0x0b,0x01,0x0b,0x0c,0x09,0x02,0xff,0x05,0x0c,0xb8,0x01,0x00,0xb3,0x0d,0xfd,0x05,0x09,0xb8,0x01,0x00,0xb5,0x02,0x0a,0xfb,0x06,0x00,0xfa,0x00,0x3f,0x32,0x3f,0x33,0xed,0x32,0x3f,0xed,0x01,0x2f,0xed,0x2f,0x33,0x2f,0x5d,0xed,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x01,0x33,0x11,0x21,0x35, +0x21,0x01,0x35,0x21,0x15,0x02,0xd2,0x91,0x01,0x74,0xfd,0xfb,0xfe,0x98,0x91,0xfd,0xfb,0x01,0x74,0xfe,0x8c,0x04,0xe1,0x06,0xa9,0xfc,0xc7,0x91,0x03,0xca,0xfc,0x36,0x91,0xfe,0x07,0x91,0x91,0x00,0x00,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x13,0x00,0x3f,0x40,0x13,0x0f,0x0a,0x0a,0x15,0x0d,0x09,0x11,0xff, +0x06,0x02,0x12,0x04,0x00,0x11,0xfe,0x07,0xfa,0x0c,0x04,0xb8,0x01,0x00,0xb4,0x09,0x05,0xfb,0x10,0x00,0xb8,0x01,0x00,0xb2,0x0d,0x01,0xfd,0x00,0x3f,0x33,0xed,0x32,0x3f,0x33,0xed,0x32,0x3f,0x3f,0x01,0x2f,0x33,0x2f,0x33,0x33,0xed,0x32,0x32,0x11,0x33,0x2f,0x33,0x31,0x30,0x03,0x35,0x21,0x35,0x21,0x35,0x21,0x11,0x33,0x11,0x21, +0x15,0x21,0x15,0x21,0x15,0x21,0x11,0x23,0x11,0x0a,0x02,0x28,0xfd,0xd8,0x02,0x28,0x91,0x02,0x28,0xfd,0xd8,0x02,0x28,0xfd,0xd8,0x91,0x01,0x77,0x91,0xd7,0x91,0x03,0x39,0xfc,0xc7,0x91,0xd7,0x91,0xfc,0x22,0x03,0xde,0x00,0x00,0x00,0x01,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x13,0x00,0x40,0x40,0x14,0x03,0x03,0x15,0x0d, +0x12,0x0a,0xff,0x0f,0x00,0x0b,0x01,0x0b,0x02,0x06,0xff,0x13,0x07,0x09,0x05,0x0d,0xb8,0x01,0x00,0x40,0x0a,0x12,0x02,0x0e,0xfc,0x0b,0x06,0xfe,0x10,0x00,0xfa,0x00,0x3f,0x32,0x3f,0x33,0x3f,0x33,0x33,0xed,0x32,0x32,0x01,0x2f,0x33,0xed,0x32,0x2f,0x5d,0x33,0xed,0x32,0x2f,0x11,0x33,0x2f,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21, +0x11,0x23,0x11,0x23,0x11,0x23,0x11,0x21,0x35,0x21,0x11,0x33,0x11,0x33,0x02,0xd2,0x91,0x01,0x74,0xfe,0x8c,0x91,0xd7,0x91,0xfe,0x8c,0x01,0x74,0x91,0xd7,0x06,0xa9,0xfc,0x13,0x91,0xfb,0x6e,0x04,0x92,0xfb,0x6e,0x04,0x92,0x91,0x03,0xed,0xfc,0x13,0x00,0x04,0xff,0xf6,0xfd,0x99,0x04,0xd7,0x06,0xa9,0x00,0x05,0x00,0x0b,0x00,0x11, +0x00,0x17,0x00,0x4d,0x40,0x15,0x0e,0x03,0x03,0x19,0x02,0x10,0xff,0x05,0x11,0x15,0x09,0x14,0x06,0xff,0x17,0x00,0x07,0x01,0x07,0x05,0x15,0xb8,0x01,0x00,0xb4,0x02,0x16,0xfb,0x0f,0x09,0xb8,0x01,0x00,0x40,0x09,0x0c,0x0a,0xfd,0x11,0x06,0xfe,0x12,0x00,0xfa,0x00,0x3f,0x32,0x3f,0x33,0x3f,0x33,0xed,0x32,0x3f,0x33,0xed,0x32,0x01, +0x2f,0x5d,0x33,0xed,0x32,0x2f,0x33,0x2f,0x33,0xed,0x32,0x11,0x33,0x2f,0x33,0x31,0x30,0x01,0x33,0x11,0x21,0x15,0x21,0x03,0x23,0x11,0x21,0x35,0x21,0x33,0x21,0x15,0x21,0x11,0x23,0x01,0x33,0x11,0x21,0x35,0x21,0x02,0xd2,0x91,0x01,0x74,0xfd,0xfb,0xd7,0x91,0xfe,0x8c,0x02,0x05,0xd7,0x02,0x05,0xfe,0x8c,0x91,0xfe,0x98,0x91,0xfd, +0xfb,0x01,0x74,0x06,0xa9,0xfc,0xc7,0x91,0xfa,0xba,0x03,0xde,0x91,0x91,0xfc,0x22,0x09,0x10,0xfc,0x36,0x91,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x73,0x04,0xcd,0x06,0xa9,0x00,0x03,0x00,0x0e,0xb4,0x01,0x00,0x00,0x02,0xfa,0x00,0x3f,0x2f,0x01,0x2f,0x2f,0x31,0x30,0x01,0x21,0x11,0x21,0x04,0xcd,0xfb,0x33,0x04,0xcd,0x02,0x73, +0x04,0x36,0x00,0x00,0x00,0x01,0x00,0x00,0xfd,0x99,0x04,0xcd,0x02,0x73,0x00,0x03,0x00,0x0e,0xb4,0x01,0x00,0x00,0xfe,0x02,0x00,0x2f,0x3f,0x01,0x2f,0x2f,0x31,0x30,0x01,0x21,0x11,0x21,0x04,0xcd,0xfb,0x33,0x04,0xcd,0xfd,0x99,0x04,0xda,0x00,0x00,0x00,0x01,0x00,0x00,0xfd,0x99,0x04,0xcd,0x06,0xa9,0x00,0x03,0x00,0x0f,0xb5,0x01, +0x00,0x00,0xfe,0x02,0xfa,0x00,0x3f,0x3f,0x01,0x2f,0x2f,0x31,0x30,0x01,0x21,0x11,0x21,0x04,0xcd,0xfb,0x33,0x04,0xcd,0xfd,0x99,0x09,0x10,0x00,0x00,0x01,0x00,0x00,0xfd,0x99,0x02,0x67,0x06,0xa9,0x00,0x03,0x00,0x0f,0xb5,0x01,0x00,0x00,0xfe,0x02,0xfa,0x00,0x3f,0x3f,0x01,0x2f,0x2f,0x31,0x30,0x01,0x21,0x11,0x21,0x02,0x67,0xfd, +0x99,0x02,0x67,0xfd,0x99,0x09,0x10,0x00,0x00,0x01,0x02,0x66,0xfd,0x99,0x04,0xcd,0x06,0xa9,0x00,0x03,0x00,0x0f,0xb5,0x01,0x00,0x00,0xfe,0x02,0xfa,0x00,0x3f,0x3f,0x01,0x2f,0x2f,0x31,0x30,0x01,0x21,0x11,0x21,0x04,0xcd,0xfd,0x99,0x02,0x67,0xfd,0x99,0x09,0x10,0x00,0x00,0x24,0x00,0x00,0xfd,0xfb,0x04,0x67,0x06,0xa9,0x00,0x03, +0x00,0x07,0x00,0x0b,0x00,0x0f,0x00,0x13,0x00,0x17,0x00,0x1b,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x2b,0x00,0x2f,0x00,0x33,0x00,0x37,0x00,0x3b,0x00,0x3f,0x00,0x43,0x00,0x47,0x00,0x4b,0x00,0x4f,0x00,0x53,0x00,0x57,0x00,0x5b,0x00,0x5f,0x00,0x63,0x00,0x67,0x00,0x6b,0x00,0x6f,0x00,0x73,0x00,0x77,0x00,0x7b,0x00,0x7f,0x00,0x83, +0x00,0x87,0x00,0x8b,0x00,0x8f,0x01,0xad,0xb6,0x0e,0x26,0x46,0x56,0x7a,0x05,0x6e,0xb8,0x01,0x03,0x40,0x0f,0x6f,0x0f,0x27,0x47,0x57,0x7b,0x05,0x6f,0x06,0x1e,0x36,0x4e,0x8a,0x05,0x66,0xb8,0x01,0x03,0x40,0x0f,0x67,0x07,0x1f,0x37,0x4f,0x8b,0x05,0x67,0x12,0x2a,0x3e,0x5a,0x7e,0x05,0x72,0xb8,0x01,0x03,0x40,0x0f,0x73,0x13,0x2b, +0x3f,0x5b,0x7f,0x05,0x73,0x0a,0x22,0x3a,0x4a,0x8e,0x05,0x62,0xb8,0x01,0x03,0x40,0x19,0x63,0x0b,0x23,0x3b,0x4b,0x8f,0x05,0x63,0x6f,0x67,0x73,0x63,0x63,0x73,0x67,0x6f,0x04,0x77,0x02,0x1a,0x32,0x52,0x86,0x05,0x6a,0xb8,0x01,0x03,0x40,0x0e,0x03,0x1b,0x33,0x53,0x87,0x05,0x6b,0x16,0x2e,0x42,0x5e,0x82,0x05,0x76,0xb8,0x01,0x03, +0x40,0x0a,0x17,0x2f,0x43,0x5f,0x83,0x05,0x77,0x67,0x63,0x6b,0xb8,0x01,0x04,0xb6,0x68,0x64,0x60,0x68,0x5f,0x5b,0x57,0xb8,0x01,0x04,0xb6,0x54,0x5c,0x58,0x54,0x4f,0x4b,0x53,0xb8,0x01,0x04,0xb6,0x50,0x4c,0x48,0x50,0x43,0x3f,0x47,0xb8,0x01,0x04,0xb6,0x44,0x40,0x3c,0x44,0x3b,0x37,0x33,0xb8,0x01,0x04,0xb6,0x30,0x38,0x34,0x30, +0x2f,0x2b,0x27,0xb8,0x01,0x04,0xb6,0x24,0x2c,0x28,0x24,0x23,0x1f,0x1b,0xb8,0x01,0x04,0xb6,0x18,0x20,0x1c,0x18,0x17,0x13,0x0f,0xb8,0x01,0x04,0xb6,0x0c,0x14,0x10,0x0c,0x0b,0x07,0x03,0xb8,0x01,0x04,0xb6,0x00,0x08,0x04,0x00,0x83,0x7f,0x7b,0xb8,0x01,0x04,0x40,0x1d,0x78,0x80,0x7c,0x78,0x68,0x54,0x50,0x44,0x30,0x24,0x18,0x0c, +0x00,0x78,0x78,0x00,0x0c,0x18,0x24,0x30,0x44,0x50,0x54,0x68,0x0a,0x84,0x74,0x70,0x6c,0xb8,0x01,0x04,0xb5,0x77,0x73,0x6f,0x8f,0x8b,0x87,0xb8,0x01,0x04,0xb3,0x8c,0x88,0x84,0xfa,0x00,0x3f,0x33,0x33,0xed,0x32,0x32,0x2f,0x33,0x33,0xed,0x32,0x32,0x11,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x11,0x33,0x33, +0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10,0xed,0x32,0x32,0x11,0x33,0x33,0x10, +0xed,0x32,0x32,0x01,0x2f,0x17,0x33,0xed,0x17,0x32,0x2f,0x17,0x33,0xed,0x17,0x32,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x31,0x30,0x11,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15, +0x23,0x05,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x07,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x05,0x33,0x15, +0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x17,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x07,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x17,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x01,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x01,0x33,0x15,0x23,0x25,0x33,0x15, +0x23,0x25,0x33,0x15,0x23,0x67,0x67,0x01,0x9a,0x67,0x67,0x01,0x9a,0x67,0x67,0xfd,0x99,0x66,0x66,0x01,0x9a,0x66,0x66,0x01,0x9a,0x66,0x66,0xfb,0xff,0x67,0x67,0x01,0x9a,0x67,0x67,0x01,0x9a,0x67,0x67,0xfd,0x99,0x66,0x66,0x01,0x9a,0x66,0x66,0x01,0x9a,0x66,0x66,0xfb,0xff,0x67,0x67,0x01,0x9a,0x67,0x67,0x01,0x9a,0x67,0x67,0xcd, +0x66,0x66,0x01,0x9a,0x66,0x66,0xfc,0xcc,0x66,0x66,0x02,0x67,0x67,0x67,0xfe,0x66,0x67,0x67,0xfe,0x66,0x67,0x67,0xcd,0x66,0x66,0x01,0x9a,0x66,0x66,0x01,0x9a,0x66,0x66,0xcd,0x67,0x67,0xfe,0x66,0x67,0x67,0xfe,0x66,0x67,0x67,0xcd,0x66,0x66,0x01,0x9a,0x66,0x66,0x01,0x9a,0x66,0x66,0xfc,0xcc,0x66,0x66,0x01,0x9a,0x66,0x66,0x01, +0x9a,0x66,0x66,0xfb,0xff,0x67,0x67,0x01,0x9a,0x67,0x67,0x01,0x9a,0x67,0x67,0x05,0x28,0x62,0x62,0x62,0x62,0x62,0x61,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x63,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x63,0x60,0x60,0x60,0x60,0x60,0x60,0x61,0x61,0x61,0x61,0x61,0x62,0x5e,0x5e,0x5e,0x5e,0x5e, +0x62,0x61,0x61,0x61,0x61,0x61,0x60,0x60,0x60,0x60,0x60,0x60,0x07,0xed,0x62,0x62,0x62,0x62,0x62,0x01,0x23,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x48,0x00,0x00,0xfd,0xfb,0x04,0xce,0x06,0xa9,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x0f,0x00,0x13,0x00,0x17,0x00,0x1b,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x2b,0x00,0x2f,0x00,0x33, +0x00,0x37,0x00,0x3b,0x00,0x3f,0x00,0x43,0x00,0x47,0x00,0x4b,0x00,0x4f,0x00,0x53,0x00,0x57,0x00,0x5b,0x00,0x5f,0x00,0x63,0x00,0x67,0x00,0x6b,0x00,0x6f,0x00,0x73,0x00,0x77,0x00,0x7b,0x00,0x7f,0x00,0x83,0x00,0x87,0x00,0x8b,0x00,0x8f,0x00,0x93,0x00,0x97,0x00,0x9b,0x00,0x9f,0x00,0xa3,0x00,0xa7,0x00,0xab,0x00,0xaf,0x00,0xb3, +0x00,0xb7,0x00,0xbb,0x00,0xbf,0x00,0xc3,0x00,0xc7,0x00,0xcb,0x00,0xcf,0x00,0xd3,0x00,0xd7,0x00,0xdb,0x00,0xdf,0x00,0xe3,0x00,0xe7,0x00,0xeb,0x00,0xef,0x00,0xf3,0x00,0xf7,0x00,0xfb,0x00,0xff,0x01,0x03,0x01,0x07,0x01,0x0b,0x01,0x0f,0x01,0x13,0x01,0x17,0x01,0x1b,0x01,0x1f,0x03,0x11,0xb3,0x02,0x32,0x62,0xa6,0xbb,0x01,0x0a, +0x00,0x05,0x00,0xd6,0x01,0x03,0xb4,0xd7,0x03,0x33,0x63,0xa7,0xb8,0x01,0x0b,0x40,0x09,0x05,0xd7,0x1e,0x4e,0x8e,0xae,0xf6,0x05,0xde,0xb8,0x01,0x03,0x40,0x0c,0xdf,0x1f,0x4f,0x8f,0xaf,0xf7,0x05,0xdf,0x06,0x36,0x66,0xa2,0xbb,0x01,0x0e,0x00,0x05,0x00,0xd2,0x01,0x03,0xb4,0xd3,0x07,0x37,0x67,0xa3,0xb8,0x01,0x0f,0x40,0x09,0x05, +0xd3,0x22,0x52,0x7e,0xb2,0xfa,0x05,0xe2,0xb8,0x01,0x03,0x40,0x0c,0xe3,0x23,0x53,0x7f,0xb3,0xfb,0x05,0xe3,0x0a,0x3a,0x6a,0x9e,0xbb,0x01,0x12,0x00,0x05,0x00,0xce,0x01,0x03,0xb4,0xcf,0x0b,0x3b,0x6b,0x9f,0xb8,0x01,0x13,0x40,0x09,0x05,0xcf,0x26,0x56,0x82,0xb6,0xfe,0x05,0xe6,0xb8,0x01,0x03,0x40,0x0c,0xe7,0x27,0x57,0x83,0xb7, +0xff,0x05,0xe7,0x0e,0x3e,0x6e,0x9a,0xbb,0x01,0x16,0x00,0x05,0x00,0xca,0x01,0x03,0xb4,0xcb,0x0f,0x3f,0x6f,0x9b,0xb8,0x01,0x17,0xb5,0x05,0xcb,0x2a,0x5a,0x86,0xba,0xbb,0x01,0x02,0x00,0x05,0x00,0xea,0x01,0x03,0xb4,0xeb,0x2b,0x5b,0x87,0xbb,0xb8,0x01,0x03,0xb5,0x05,0xeb,0x12,0x42,0x72,0x96,0xbb,0x01,0x1a,0x00,0x05,0x00,0xc6, +0x01,0x03,0xb4,0xc7,0x13,0x43,0x73,0x97,0xb8,0x01,0x1b,0xb5,0x05,0xc7,0x2e,0x5e,0x8a,0xbe,0xbb,0x01,0x06,0x00,0x05,0x00,0xee,0x01,0x03,0xb4,0xef,0x2f,0x5f,0x8b,0xbf,0xb8,0x01,0x07,0x40,0x1f,0x05,0xef,0xd7,0xdf,0xd3,0xe3,0xcf,0xe7,0xcb,0xeb,0xc7,0xef,0xef,0xc7,0xeb,0xcb,0xe7,0xcf,0xe3,0xd3,0xdf,0xd7,0x0a,0xc3,0x1a,0x4a, +0x7a,0xaa,0xf2,0x05,0xda,0xb8,0x01,0x03,0x40,0x0b,0x1b,0x4b,0x7b,0xab,0xf3,0x05,0xdb,0x16,0x46,0x76,0x92,0xbb,0x01,0x1e,0x00,0x05,0x00,0xc2,0x01,0x03,0xb3,0x17,0x47,0x77,0x93,0xb8,0x01,0x1f,0x40,0x09,0x05,0xc3,0xc3,0xc7,0xcb,0xcf,0xd3,0x05,0xd7,0xb8,0x01,0x04,0x40,0x0f,0xd4,0xc0,0xc4,0xc8,0xcc,0xd0,0x05,0xd4,0xaf,0xb3, +0xb7,0xbb,0xbf,0x05,0xab,0xb8,0x01,0x04,0x40,0x0f,0xa8,0xac,0xb0,0xb4,0xb8,0xbc,0x05,0xa8,0x93,0x97,0x9b,0x9f,0xa3,0x05,0xa7,0xb8,0x01,0x04,0x40,0x0f,0xa4,0x90,0x94,0x98,0x9c,0xa0,0x05,0xa4,0x7f,0x83,0x87,0x8b,0x8f,0x05,0x7b,0xb8,0x01,0x04,0x40,0x0f,0x78,0x7c,0x80,0x84,0x88,0x8c,0x05,0x78,0x67,0x6b,0x6f,0x73,0x77,0x05, +0x63,0xb8,0x01,0x04,0x40,0x0f,0x60,0x64,0x68,0x6c,0x70,0x74,0x05,0x60,0x4f,0x53,0x57,0x5b,0x5f,0x05,0x4b,0xb8,0x01,0x04,0x40,0x0f,0x48,0x4c,0x50,0x54,0x58,0x5c,0x05,0x48,0x37,0x3b,0x3f,0x43,0x47,0x05,0x33,0xb8,0x01,0x04,0x40,0x0f,0x30,0x34,0x38,0x3c,0x40,0x44,0x05,0x30,0x1f,0x23,0x27,0x2b,0x2f,0x05,0x1b,0xb8,0x01,0x04, +0x40,0x0f,0x18,0x1c,0x20,0x24,0x28,0x2c,0x05,0x18,0x07,0x0b,0x0f,0x13,0x17,0x05,0x03,0xb8,0x01,0x04,0x40,0x0b,0x00,0x04,0x08,0x0c,0x10,0x14,0x05,0x00,0xf7,0xfb,0xff,0xbc,0x01,0x03,0x01,0x07,0x00,0x05,0x00,0xf3,0x01,0x04,0xb3,0xf0,0xf4,0xf8,0xfc,0xb9,0x01,0x00,0x01,0x04,0x40,0x17,0x05,0xf0,0xd4,0xa8,0xa4,0x78,0x60,0x48, +0x30,0x18,0x00,0xf0,0xf0,0x00,0x18,0x30,0x48,0x60,0x78,0xa4,0xa8,0xd4,0x0a,0xb8,0x01,0x08,0xb6,0xdc,0xe0,0xe4,0xe8,0xec,0x05,0xd8,0xb8,0x01,0x04,0xb6,0xdf,0xe3,0xe7,0xeb,0xef,0x05,0xdb,0x41,0x10,0x01,0x0f,0x01,0x13,0x01,0x17,0x01,0x1b,0x01,0x1f,0x00,0x05,0x01,0x0b,0x01,0x04,0x01,0x0c,0x01,0x10,0x01,0x14,0x01,0x18,0x01, +0x1c,0x00,0x05,0x01,0x08,0x00,0xfa,0x00,0x3f,0x17,0x33,0xed,0x17,0x32,0x2f,0x17,0x33,0xed,0x17,0x32,0x11,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33, +0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x01,0x2f,0x17,0x33,0xed,0x17,0x32,0x2f,0x17,0x33,0xed,0x17,0x32,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f, +0x2f,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32, +0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x31,0x30,0x13,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x37,0x33,0x15, +0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15, +0x23,0x05,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x25,0x33,0x15,0x23,0x05,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x07,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15, +0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x17,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x27,0x33,0x15,0x23,0x07,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x01,0x33,0x15,0x23,0x37,0x33,0x15, +0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x01,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x37,0x33,0x15,0x23,0x66,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xfb,0x99,0x66,0x66,0xcd, +0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xfc,0x65,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xfb,0x99,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xfc,0x65,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67, +0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xfb,0x99,0x66,0x66,0x01,0x9a,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xfc,0xcc,0x66,0x66,0x03,0x9a,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0x66,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66, +0x66,0x66,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0x66,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xfb,0xff,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xfc,0x65,0x67,0x67,0xcd,0x67,0x67,0xcd, +0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0x05,0x28,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x61,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x63,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, +0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x63,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x62,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x62,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, +0x60,0x60,0x60,0x60,0x07,0xed,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x01,0x23,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x38,0x00,0x00,0xfd,0x99,0x04,0xce,0x06,0xa9,0x00,0x45,0x00,0x49,0x00,0x4d,0x00,0x51,0x00,0x55,0x00,0x59,0x00,0x5d,0x00,0x61,0x00,0x65,0x00,0x69,0x00,0x6d, +0x00,0x71,0x00,0x75,0x00,0x79,0x00,0x7d,0x00,0x81,0x00,0x85,0x00,0x89,0x00,0x8d,0x00,0x91,0x00,0x95,0x00,0x99,0x00,0x9d,0x00,0xa1,0x00,0xa5,0x00,0xa9,0x00,0xad,0x00,0xb1,0x00,0xb5,0x00,0xb9,0x00,0xbd,0x00,0xc1,0x00,0xc5,0x00,0xc9,0x00,0xcd,0x00,0xd1,0x00,0xd5,0x00,0xd9,0x00,0xdd,0x00,0xe1,0x00,0xe5,0x00,0xe9,0x00,0xed, +0x00,0xf1,0x00,0xf5,0x00,0xf9,0x00,0xfd,0x01,0x01,0x01,0x05,0x01,0x09,0x01,0x0d,0x01,0x11,0x01,0x15,0x01,0x19,0x01,0x1d,0x01,0x21,0x03,0x17,0xb6,0x1a,0x64,0x78,0xa5,0xe4,0x05,0xc5,0xb8,0x01,0x03,0x40,0x0f,0x03,0x07,0x0b,0x0f,0x13,0x17,0x05,0x03,0x4b,0x6b,0x91,0xab,0xf0,0x05,0xcb,0xb8,0x01,0x03,0x40,0x0f,0xc8,0x48,0x68, +0x88,0xa8,0xf5,0x05,0xc8,0x1e,0x60,0x7b,0xa1,0xe0,0x05,0xc1,0xb8,0x01,0x03,0x40,0x0f,0xc2,0x1b,0x65,0x79,0xa2,0xe5,0x05,0xc2,0x4f,0x6f,0x8b,0xaf,0xec,0x05,0xcf,0xb8,0x01,0x03,0x40,0x0f,0xcc,0x4c,0x6c,0x8e,0xac,0xf1,0x05,0xcc,0x22,0x5c,0x7f,0x9d,0xdc,0x05,0xbd,0xb8,0x01,0x03,0x40,0x0f,0xbe,0x1f,0x61,0x7c,0x9e,0xe1,0x05, +0xbe,0x53,0x73,0x93,0xb3,0xe8,0x05,0xd3,0xb8,0x01,0x03,0x40,0x0f,0xd0,0x50,0x70,0x8c,0xb0,0xed,0x05,0xd0,0x26,0x58,0x83,0x99,0xd8,0x05,0xb9,0xb8,0x01,0x03,0x40,0x0a,0xba,0x23,0x5d,0x80,0x9a,0xdd,0x05,0xba,0xf7,0xff,0xbd,0x01,0x07,0x01,0x0f,0x01,0x20,0x00,0x05,0x01,0x17,0x01,0x03,0x40,0x0a,0xd4,0x54,0x74,0x94,0xb4,0xe9, +0x05,0xd4,0x2a,0xfc,0xbd,0x01,0x03,0x01,0x0d,0x01,0x1c,0x00,0x05,0x01,0x15,0x01,0x03,0x40,0x0f,0xb6,0x27,0x59,0x84,0x96,0xd9,0x05,0xb6,0x30,0x34,0x38,0x3c,0x40,0x05,0x44,0x41,0x09,0x01,0x03,0x01,0x18,0x00,0xf8,0x01,0x00,0x01,0x08,0x01,0x10,0x01,0x21,0x00,0x05,0x01,0x18,0x40,0x09,0x03,0xc8,0xc2,0xcc,0xbe,0xd0,0xba,0xd4, +0xb6,0xb9,0x01,0x18,0x01,0x18,0x40,0x0a,0xb6,0xd4,0xba,0xd0,0xbe,0xcc,0xc2,0xc8,0x03,0x0a,0xb8,0x01,0x12,0xb6,0x47,0x67,0x87,0xa7,0xf4,0x05,0xc7,0xb8,0x01,0x03,0x40,0x11,0x05,0x09,0x0d,0x11,0x15,0x05,0x01,0x2e,0x32,0x36,0x3a,0x3e,0x42,0x06,0x00,0x2b,0xfd,0xbc,0x01,0x04,0x01,0x0a,0x01,0x1d,0x00,0x05,0x01,0x12,0x40,0x0c, +0x1c,0x20,0x24,0x28,0x2c,0x05,0x18,0x16,0x43,0xca,0xce,0xd2,0xbb,0x01,0x16,0x00,0x05,0x00,0xc6,0x01,0x04,0xb4,0x02,0xb9,0xbd,0xc1,0xc5,0xb8,0x01,0x15,0xb5,0x05,0x02,0xb8,0xbc,0xc0,0xc4,0xbb,0x01,0x14,0x00,0x05,0x00,0x05,0x01,0x04,0xb4,0xa7,0x40,0xab,0xaf,0xb3,0xb8,0x01,0x0f,0xb5,0x05,0xa7,0x3f,0xaa,0xae,0xb2,0xbb,0x01, +0x0e,0x00,0x05,0x00,0xa6,0x01,0x04,0xb4,0x06,0x99,0x9d,0xa1,0xa5,0xb8,0x01,0x0d,0xb5,0x05,0x06,0x98,0x9c,0xa0,0xa4,0xbb,0x01,0x0c,0x00,0x05,0x00,0x09,0x01,0x04,0xb4,0x87,0x3c,0x8b,0x91,0x93,0xb8,0x01,0x07,0xb5,0x05,0x87,0x3b,0x8a,0x90,0x92,0xbb,0x01,0x06,0x00,0x05,0x00,0x86,0x01,0x04,0xb4,0x0a,0x78,0x7b,0x7f,0x83,0xb8, +0x01,0x03,0xb5,0x05,0x0a,0x77,0x7a,0x7e,0x82,0xbb,0x01,0x02,0x00,0x05,0x00,0x0d,0x01,0x04,0x40,0x0f,0x67,0x38,0x6b,0x6f,0x73,0xff,0x05,0x67,0x37,0x6a,0x6e,0x72,0xfe,0x05,0x66,0xb8,0x01,0x04,0x40,0x0f,0x0e,0x58,0x5c,0x60,0x64,0xfc,0x05,0x0e,0x57,0x5b,0x5f,0x63,0xfb,0x05,0x11,0xb8,0x01,0x04,0x40,0x0f,0x47,0x34,0x4b,0x4f, +0x53,0xf7,0x05,0x47,0x33,0x4a,0x4e,0x52,0xf6,0x05,0x46,0xb8,0x01,0x04,0xb4,0x12,0xd8,0xdc,0xe0,0xe4,0xb8,0x01,0x1c,0xb5,0x05,0x12,0xd7,0xdb,0xdf,0xe3,0xbb,0x01,0x1b,0x00,0x05,0x00,0x15,0x01,0x04,0xb4,0xf4,0x30,0xe8,0xec,0xf0,0xb8,0x01,0x20,0x40,0x1c,0x05,0xf4,0x02,0xa7,0x06,0x87,0x0a,0x67,0x0e,0x47,0x12,0xf4,0xf4,0x12, +0x47,0x0e,0x67,0x0a,0x87,0x06,0xa7,0x02,0x0a,0x16,0x44,0xcb,0xcf,0xd3,0xbb,0x01,0x17,0x00,0x05,0x00,0xc7,0x01,0x04,0xb5,0x01,0xfe,0x2f,0xe7,0xeb,0xef,0xbb,0x01,0x1f,0x00,0x05,0x00,0xf3,0x01,0x04,0xb6,0x1a,0x1e,0x22,0x26,0x2a,0x05,0x16,0x00,0x2f,0x17,0x33,0xed,0x17,0x32,0x3f,0xed,0x17,0x32,0x11,0x17,0x39,0x2f,0x2f,0x2f, +0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11, +0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x10,0xc6,0x17,0x32,0x01,0x2f,0x17,0x33,0xc4,0x17,0x32,0x2f,0x17,0x33,0xed,0x17,0x32,0x12,0x17,0x39,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32, +0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x11,0x17,0x33,0x10,0xed,0x17,0x32,0x31,0x30,0x01,0x21,0x11,0x33,0x35,0x23,0x11,0x33,0x35,0x23,0x11,0x33,0x35, +0x23,0x11,0x33,0x35,0x23,0x11,0x33,0x35,0x23,0x11,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x23,0x15,0x33,0x11,0x23,0x15,0x33,0x11,0x23,0x15,0x33,0x11,0x23,0x15,0x33,0x11,0x23,0x15,0x33,0x11,0x23,0x15,0x33,0x01,0x15,0x33,0x35,0x33,0x15,0x33, +0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x17,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x07,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x05,0x23,0x15,0x33,0x37,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x05,0x15,0x33,0x35,0x21,0x15,0x33, +0x35,0x07,0x35,0x23,0x15,0x25,0x15,0x33,0x35,0x13,0x35,0x23,0x15,0x23,0x35,0x23,0x15,0x23,0x35,0x23,0x15,0x23,0x35,0x23,0x15,0x07,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x13,0x35,0x23,0x15,0x23,0x35,0x23,0x15,0x23,0x35,0x23,0x15,0x23,0x35,0x23,0x15,0x07,0x15,0x33,0x35,0x33,0x15,0x33, +0x35,0x33,0x15,0x33,0x35,0x33,0x15,0x33,0x35,0x13,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x01,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x27,0x23,0x15,0x33,0x01,0x15,0x33,0x35,0x17,0x23,0x15,0x33,0x07,0x15,0x33,0x35,0x1d,0x01,0x33,0x35,0x07,0x15,0x33,0x35,0x13,0x35,0x23, +0x15,0x07,0x15,0x33,0x35,0x13,0x35,0x23,0x15,0x07,0x15,0x33,0x35,0x13,0x23,0x15,0x33,0x03,0x23,0x15,0x33,0x04,0xce,0xfb,0x32,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x67,0x66,0x67,0x66,0x67,0x66,0x67,0x66,0x67,0x66,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0xfb,0x98,0x67,0x66,0x67, +0x66,0x67,0x66,0x67,0x66,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x67,0x66,0x67,0x66,0x67,0x66,0x67,0xfd,0xff,0x66,0x66,0x67,0x66,0x67,0x66,0x67,0x66,0xfc,0xcc,0x67,0x01,0x33,0x67,0xcd,0x67,0x01,0x9a,0x67,0x66,0x66,0x67,0x66,0x67,0x66,0x67,0x66,0x67,0x67,0x66,0x67,0x66,0x67,0x66,0x67,0x66,0x66,0x67, +0x66,0x67,0x66,0x67,0x66,0x67,0x67,0x66,0x67,0x66,0x67,0x66,0x67,0x66,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0xcd,0x66,0x66,0x02,0x01,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0xcd,0x67,0x67,0x02,0xcd,0x67,0x66,0x66,0x66,0xcd,0x67,0x66,0xcd,0x67,0x66,0x66,0x67,0x67,0x66,0x66,0x67,0x67,0x66,0x66,0x66,0x66,0x67,0x67,0xfd, +0x99,0x01,0x22,0x61,0x01,0x22,0x61,0x01,0x23,0x60,0x01,0x21,0x62,0x01,0x21,0x62,0x01,0x21,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xc1,0x62,0xfe,0xdf,0x60,0xfe,0xdd,0x60,0xfe,0xdd,0x60,0xfe,0xdd,0x5e,0xfe,0xdd,0x60,0x06,0x6a,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xc0,0x62,0x62,0x62,0x62,0x62,0x62,0x62, +0x61,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xc0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xc3,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xfe,0xdf,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x62,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0xfe,0xdf,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x60,0x60,0x60,0x60,0x60,0x60, +0x60,0x60,0x60,0x06,0xcd,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x01,0x22,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0xfe,0xdf,0x60,0x60,0xc0,0x62,0x61,0x60,0x60,0xc0,0x60,0x60,0xc3,0x60,0x60,0xfe,0xdf,0x61,0x61,0x62,0x5e,0x5e,0xfe,0xdf,0x61,0x61,0x60,0x60,0x60,0x06,0xcd,0x62,0x01,0x22,0x62,0x00,0x01,0x00,0x77,0x00,0x75,0x04,0x56, +0x04,0x54,0x00,0x03,0x00,0x0d,0xb3,0x00,0x01,0x02,0x00,0x00,0x2f,0x2f,0x01,0x2f,0x2f,0x31,0x30,0x13,0x21,0x11,0x21,0x77,0x03,0xdf,0xfc,0x21,0x04,0x54,0xfc,0x21,0x00,0x02,0x00,0x02,0x00,0x00,0x04,0xcb,0x04,0xc9,0x00,0x03,0x00,0x07,0x00,0x26,0x41,0x0c,0x00,0x05,0x01,0x01,0x00,0x03,0x00,0x06,0x01,0x01,0x00,0x02,0x00,0x05, +0x01,0x02,0x00,0x03,0x00,0x04,0x01,0x02,0x00,0x00,0x00,0x2f,0xed,0x2f,0xed,0x01,0x2f,0xed,0x2f,0xed,0x31,0x30,0x13,0x21,0x11,0x21,0x13,0x11,0x21,0x11,0x02,0x04,0xc9,0xfb,0x37,0x4c,0x04,0x31,0x04,0xc9,0xfb,0x37,0x04,0x7d,0xfb,0xcf,0x04,0x31,0x00,0x01,0x01,0x68,0x01,0x7f,0x03,0x64,0x03,0x7b,0x00,0x03,0x00,0x14,0x40,0x09, +0x00,0x00,0x01,0x60,0x01,0x02,0x01,0x00,0x02,0x00,0x2f,0xcd,0x01,0x2f,0x5d,0xcd,0x31,0x30,0x01,0x21,0x11,0x21,0x03,0x64,0xfe,0x04,0x01,0xfc,0x01,0x7f,0x01,0xfc,0x00,0x02,0x01,0x68,0x01,0x7f,0x03,0x64,0x03,0x7b,0x00,0x03,0x00,0x07,0x00,0x2b,0xbc,0x00,0x04,0x01,0x01,0x00,0x00,0x00,0x07,0x01,0x01,0xb6,0x00,0x01,0x60,0x01, +0x02,0x01,0x07,0xbc,0x01,0x02,0x00,0x00,0x00,0x06,0x01,0x02,0x00,0x02,0x00,0x2f,0xed,0xdc,0xed,0x01,0x2f,0x5d,0xed,0xdd,0xed,0x31,0x30,0x01,0x21,0x11,0x21,0x03,0x11,0x21,0x11,0x03,0x64,0xfe,0x04,0x01,0xfc,0x4c,0xfe,0x9c,0x01,0x7f,0x01,0xfc,0xfe,0x50,0x01,0x62,0xfe,0x9e,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x46,0x04,0xc5, +0x02,0x22,0x00,0x03,0x00,0x0d,0xb3,0x00,0x01,0x02,0x00,0x00,0x2f,0x2f,0x01,0x2f,0x2f,0x31,0x30,0x13,0x21,0x11,0x21,0x08,0x04,0xbd,0xfb,0x43,0x02,0x22,0xfe,0x24,0x00,0x01,0x00,0x0f,0x00,0x32,0x04,0xbd,0x04,0xae,0x00,0x02,0x00,0x0d,0xb3,0x00,0x02,0x00,0x01,0x00,0x2f,0x2f,0x01,0x2f,0x2f,0x31,0x30,0x37,0x09,0x01,0x0f,0x02, +0x58,0x02,0x56,0x32,0x04,0x7c,0xfb,0x84,0x00,0x01,0x00,0x34,0xff,0xe5,0x04,0xcb,0x04,0xac,0x00,0x02,0x00,0x0d,0xb3,0x00,0x01,0x02,0x00,0x00,0x2f,0x2f,0x01,0x2f,0x2f,0x31,0x30,0x13,0x09,0x01,0x34,0x04,0x97,0xfb,0x69,0x04,0xac,0xfd,0x9e,0xfd,0x9b,0x00,0x00,0x00,0x00,0x01,0x00,0x0f,0xff,0xe5,0x04,0xbd,0x04,0x61,0x00,0x02, +0x00,0x0d,0xb3,0x02,0x00,0x01,0x00,0x00,0x2f,0x2f,0x01,0x2f,0x2f,0x31,0x30,0x09,0x02,0x04,0xbd,0xfd,0xaa,0xfd,0xa8,0x04,0x61,0xfb,0x84,0x04,0x7c,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0xff,0xe5,0x04,0x99,0x04,0xac,0x00,0x02,0x00,0x0d,0xb3,0x02,0x00,0x01,0x00,0x00,0x2f,0x2f,0x01,0x2f,0x2f,0x31,0x30,0x01,0x11,0x01,0x04,0x99, +0xfb,0x69,0x04,0xac,0xfb,0x39,0x02,0x65,0x00,0x02,0x00,0x73,0x00,0x00,0x04,0x59,0x05,0xa0,0x00,0x05,0x00,0x09,0x00,0x55,0x40,0x32,0x04,0x03,0x06,0x00,0x01,0x06,0x03,0x08,0x08,0x02,0x05,0xaa,0x10,0x09,0x20,0x09,0x30,0x09,0x70,0x09,0x80,0x09,0x05,0x09,0x09,0x0b,0x07,0xaa,0x00,0x02,0x10,0x02,0x02,0x02,0x02,0x05,0x09,0x03, +0x07,0x07,0x08,0x06,0xb0,0x0f,0x03,0x01,0x03,0x08,0xb0,0x01,0x00,0x2f,0xed,0x2f,0x5d,0xed,0x12,0x39,0x3d,0x2f,0x17,0x33,0x01,0x18,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x5d,0xed,0x11,0x39,0x3d,0x2f,0x17,0x33,0x11,0x33,0x33,0x31,0x30,0x21,0x23,0x09,0x01,0x33,0x09,0x04,0x02,0x8e,0x52,0xfe,0x37,0x01,0xc9,0x52,0x01,0xcb,0xfe,0x0e, +0xfe,0x9e,0x01,0x62,0x01,0x60,0x02,0xcf,0x02,0xd1,0xfd,0x31,0x02,0x35,0xfd,0xcb,0xfd,0xc2,0x02,0x3e,0x00,0x02,0x00,0xa3,0x00,0xa2,0x04,0x2a,0x04,0x29,0x00,0x13,0x00,0x27,0x00,0x47,0x40,0x15,0x4b,0x26,0x5b,0x26,0x02,0x4b,0x20,0x5b,0x20,0x02,0x44,0x1c,0x54,0x1c,0x02,0x44,0x16,0x54,0x16,0x02,0x1e,0xb8,0x01,0x01,0xb2,0x0a, +0x0a,0x14,0xb8,0x01,0x01,0xb4,0x00,0x00,0x01,0x00,0x19,0xb8,0x01,0x02,0xb2,0x0f,0x0f,0x23,0xb9,0x01,0x02,0x00,0x05,0x00,0x2f,0xed,0x33,0x2f,0xed,0x01,0x2f,0x5d,0xed,0x33,0x2f,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x13,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x37,0x14,0x1e,0x02,0x33, +0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0xa3,0x46,0x7a,0xa4,0x5e,0x5e,0xa5,0x7b,0x47,0x47,0x7b,0xa5,0x5e,0x5e,0xa4,0x7a,0x46,0x56,0x39,0x62,0x85,0x4c,0x4c,0x86,0x63,0x3a,0x3a,0x63,0x86,0x4c,0x4c,0x85,0x62,0x39,0x02,0x64,0x5e,0xa5,0x7b,0x47,0x47,0x7b,0xa5,0x5e,0x5e,0xa4,0x7a,0x46,0x46,0x7a,0xa4,0x5e,0x4c, +0x84,0x63,0x39,0x39,0x63,0x84,0x4c,0x4c,0x86,0x63,0x3a,0x3a,0x63,0x86,0x00,0x00,0x00,0x01,0x00,0xae,0x00,0x89,0x04,0x1f,0x03,0xfa,0x00,0x17,0x00,0x18,0x40,0x0d,0x08,0x00,0x10,0x90,0x10,0xa0,0x10,0xb0,0x10,0x04,0x10,0x0c,0x00,0x00,0x2f,0xcd,0x01,0x2f,0x5d,0xcd,0x31,0x30,0x01,0x32,0x17,0x1e,0x01,0x17,0x1e,0x01,0x15,0x14, +0x07,0x06,0x23,0x22,0x27,0x26,0x35,0x34,0x36,0x37,0x3e,0x01,0x37,0x36,0x02,0x66,0x6e,0x6b,0x35,0x52,0x1d,0x1d,0x1f,0x81,0x81,0xb7,0xb6,0x81,0x81,0x1e,0x1d,0x1d,0x53,0x34,0x6c,0x03,0xfa,0x39,0x1c,0x52,0x34,0x36,0x6e,0x39,0xb7,0x81,0x81,0x81,0x81,0xb7,0x3a,0x6d,0x36,0x34,0x52,0x1c,0x39,0x00,0x00,0x00,0x00,0x02,0x00,0x25, +0x00,0x00,0x04,0xa8,0x04,0x83,0x00,0x03,0x00,0x17,0x00,0x1e,0x40,0x0e,0xcf,0x0e,0x01,0xdf,0x0e,0x01,0x0e,0x03,0x04,0x00,0x13,0x01,0x09,0x00,0x00,0x2f,0xcd,0x2f,0xcd,0x01,0x2f,0xcd,0xdd,0xcd,0x5d,0x71,0x31,0x30,0x33,0x11,0x21,0x11,0x01,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x25,0x04, +0x83,0xfc,0x04,0x45,0x78,0xa0,0x5b,0x5b,0xa1,0x78,0x45,0x45,0x78,0xa1,0x5b,0x5b,0xa0,0x78,0x45,0x04,0x83,0xfb,0x7d,0x02,0x41,0x5b,0xa0,0x78,0x45,0x45,0x78,0xa0,0x5b,0x5b,0xa1,0x78,0x45,0x45,0x78,0xa1,0x00,0x03,0x00,0x25,0x00,0x00,0x04,0xa8,0x04,0x83,0x00,0x03,0x00,0x17,0x00,0x2b,0x00,0x30,0x40,0x19,0xf0,0x04,0x01,0x04, +0x18,0x00,0x00,0x0e,0x01,0x0e,0xcf,0x22,0x01,0xdf,0x22,0x01,0x22,0x03,0x00,0x09,0x27,0x01,0x13,0x1d,0x00,0x00,0x2f,0xdd,0xce,0x2f,0xdd,0xce,0x01,0x2f,0xdd,0xdd,0x5d,0x71,0xce,0x72,0x10,0xdd,0xce,0x71,0x31,0x30,0x33,0x11,0x21,0x11,0x01,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x14, +0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x25,0x04,0x83,0xfc,0x51,0x3a,0x63,0x85,0x4b,0x4b,0x85,0x63,0x3a,0x3a,0x63,0x85,0x4b,0x4b,0x85,0x63,0x3a,0x4d,0x45,0x78,0xa0,0x5b,0x5b,0xa1,0x78,0x45,0x45,0x78,0xa1,0x5b,0x5b,0xa0,0x78,0x45,0x04,0x83,0xfb,0x7d,0x02,0x41,0x4b,0x85,0x63,0x3a,0x3a,0x63, +0x85,0x4b,0x4b,0x85,0x63,0x3a,0x3a,0x63,0x85,0x4b,0x5b,0xa0,0x78,0x45,0x45,0x78,0xa0,0x5b,0x5b,0xa1,0x78,0x45,0x45,0x78,0xa1,0x00,0x00,0x00,0x00,0x02,0x01,0x6e,0x01,0x85,0x03,0x5e,0x03,0x75,0x00,0x12,0x00,0x22,0x00,0x30,0xbc,0x00,0x13,0x01,0x01,0x00,0x00,0x00,0x1b,0x01,0x01,0x40,0x0b,0x00,0x0b,0x50,0x0b,0x60,0x0b,0xb0, +0x0b,0x04,0x0b,0x1f,0xbc,0x01,0x02,0x00,0x06,0x00,0x17,0x01,0x02,0x00,0x0f,0x00,0x2f,0xed,0xdc,0xed,0x01,0x2f,0x5d,0xed,0xd4,0xed,0x31,0x30,0x01,0x14,0x06,0x07,0x0e,0x01,0x23,0x22,0x27,0x2e,0x01,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x07,0x34,0x27,0x26,0x23,0x22,0x07,0x06,0x15,0x14,0x17,0x16,0x33,0x32,0x37,0x36,0x03, +0x5e,0x25,0x25,0x25,0x56,0x33,0x65,0x4b,0x23,0x25,0x48,0x4a,0x66,0x67,0x47,0x4a,0x4c,0x33,0x33,0x46,0x46,0x33,0x33,0x33,0x31,0x48,0x48,0x31,0x33,0x02,0x7d,0x35,0x56,0x25,0x23,0x25,0x48,0x25,0x56,0x35,0x66,0x48,0x4a,0x4a,0x47,0x67,0x46,0x33,0x33,0x33,0x33,0x46,0x45,0x36,0x31,0x31,0x36,0x00,0x00,0x00,0x00,0x05,0x00,0x1b, +0x00,0x02,0x04,0xb1,0x04,0x98,0x00,0x19,0x00,0x2d,0x00,0x39,0x00,0x45,0x00,0x5b,0x00,0xbf,0x40,0x4a,0x1b,0x2c,0x2b,0x2c,0x6b,0x2c,0x7b,0x2c,0x04,0x69,0x2b,0x79,0x2b,0x02,0x69,0x27,0x79,0x27,0x02,0x1b,0x26,0x2b,0x26,0x6b,0x26,0x7b,0x26,0x04,0x14,0x22,0x24,0x22,0x64,0x22,0x74,0x22,0x04,0x66,0x21,0x76,0x21,0x02,0x66,0x1d, +0x76,0x1d,0x02,0x14,0x1c,0x24,0x1c,0x64,0x1c,0x74,0x1c,0x04,0x34,0xff,0x2e,0x3a,0xff,0x40,0x5b,0x00,0x2e,0x51,0x40,0x0c,0x2e,0x40,0x2e,0x40,0x00,0x24,0xbb,0x01,0x01,0x00,0x0c,0x00,0x1a,0x01,0x01,0xb2,0x00,0x50,0x46,0xb8,0xff,0xc0,0xb5,0x09,0x0d,0x48,0x46,0x46,0x56,0xb8,0x01,0x04,0xb2,0x4b,0x43,0x37,0xb8,0x01,0x00,0x40, +0x0e,0x31,0x3d,0x31,0x3f,0x4b,0x4f,0x4b,0x02,0x4b,0x31,0x4b,0x31,0x07,0x1f,0xbb,0x01,0x02,0x00,0x13,0x00,0x29,0x01,0x02,0xb1,0x07,0x13,0x00,0x2f,0xdc,0xed,0x10,0xed,0x11,0x39,0x39,0x2f,0x2f,0x5d,0x11,0x33,0x10,0xed,0x32,0x10,0xed,0x33,0x2f,0x2b,0x33,0x01,0x2f,0xed,0xd4,0xed,0x12,0x39,0x39,0x2f,0x2f,0x11,0x12,0x39,0x11, +0x12,0x39,0x10,0xed,0x10,0xed,0x31,0x30,0x00,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x13,0x34,0x3e,0x04,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x04,0x23,0x22,0x2e,0x04,0x37,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x37,0x34,0x36,0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x25,0x34,0x36, +0x33,0x32,0x16,0x15,0x14,0x06,0x23,0x22,0x26,0x01,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x17,0x0e,0x03,0x23,0x22,0x2e,0x02,0x27,0x1b,0x2a,0x4c,0x6c,0x82,0x96,0x51,0x7a,0xd5,0xa0,0x5c,0x2a,0x4c,0x6c,0x82,0x96,0x51,0x51,0x96,0x82,0x6c,0x4c,0x2a,0x3f,0x52,0x8f,0xbf,0x6c,0x6c,0xbe,0x8f,0x52,0x52,0x8f,0xbe,0x6c,0x6c,0xbf,0x8f, +0x52,0xec,0x29,0x1d,0x1d,0x2a,0x2a,0x1d,0x1d,0x29,0x01,0xb3,0x29,0x1d,0x1d,0x2a,0x2a,0x1d,0x1d,0x29,0xfe,0x68,0x12,0x2c,0x3d,0x52,0x38,0x38,0x52,0x3d,0x2c,0x12,0x3a,0x13,0x36,0x4d,0x65,0x44,0x43,0x66,0x4d,0x35,0x14,0x02,0x4d,0x51,0x96,0x82,0x6c,0x4c,0x2a,0x5c,0xa0,0xd5,0x7a,0x51,0x96,0x82,0x6c,0x4c,0x2a,0x2a,0x4c,0x6c, +0x82,0x96,0x51,0x6c,0xbf,0x8f,0x52,0x52,0x8f,0xbf,0x6c,0x6c,0xbe,0x8f,0x52,0x52,0x8f,0xbe,0x2c,0x1d,0x2a,0x2a,0x1d,0x1d,0x29,0x29,0x1d,0x1d,0x2a,0x2a,0x1d,0x1d,0x29,0x29,0xfe,0xf2,0x18,0x30,0x27,0x19,0x19,0x27,0x30,0x18,0x31,0x1e,0x3f,0x33,0x21,0x21,0x33,0x3f,0x1e,0x00,0x00,0x00,0x00,0x04,0x00,0x1b,0x00,0x02,0x04,0xb1, +0x04,0x98,0x00,0x19,0x00,0x25,0x00,0x31,0x00,0x47,0x00,0x6d,0x40,0x1e,0x26,0xff,0x2c,0x20,0xff,0x1a,0x3c,0x0c,0x2c,0x32,0x1a,0x00,0x1f,0x2c,0x2f,0x2c,0x02,0x10,0x1a,0x20,0x1a,0x02,0x2c,0x1a,0x2c,0x1a,0x0c,0x00,0x29,0x1d,0xb8,0x01,0x00,0xb6,0x23,0x2f,0x23,0x3d,0x47,0x47,0x37,0xb8,0x01,0x04,0x40,0x15,0x42,0x0f,0x23,0x01, +0x0f,0x42,0x3f,0x42,0x4f,0x42,0x6f,0x42,0x7f,0x42,0x05,0x23,0x42,0x23,0x42,0x07,0x13,0x00,0x2f,0xc4,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x10,0xee,0x33,0x2f,0x33,0x11,0x33,0x10,0xe6,0x32,0x01,0x2f,0xcd,0x39,0x39,0x2f,0x2f,0x5d,0x5d,0x11,0x12,0x39,0x11,0x12,0x39,0x10,0xe6,0x10,0xe6,0x31,0x30,0x13,0x34,0x3e,0x04,0x33,0x32,0x1e, +0x02,0x15,0x14,0x0e,0x04,0x23,0x22,0x2e,0x04,0x25,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x05,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x01,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x27,0x0e,0x03,0x23,0x22,0x2e,0x02,0x27,0x1b,0x2a,0x4c,0x6c,0x82,0x96,0x51,0x7a,0xd5,0xa0,0x5c,0x2a,0x4c,0x6c,0x82, +0x96,0x51,0x51,0x96,0x82,0x6c,0x4c,0x2a,0x01,0x2b,0x29,0x1d,0x1d,0x2a,0x2a,0x1d,0x1d,0x29,0x01,0xb3,0x29,0x1d,0x1d,0x2a,0x2a,0x1d,0x1d,0x29,0xfe,0x2e,0x14,0x35,0x4d,0x66,0x43,0x44,0x65,0x4d,0x36,0x13,0x3a,0x12,0x2c,0x3d,0x52,0x38,0x38,0x52,0x3d,0x2c,0x12,0x02,0x4d,0x51,0x96,0x82,0x6c,0x4c,0x2a,0x5c,0xa0,0xd5,0x7a,0x51, +0x96,0x82,0x6c,0x4c,0x2a,0x2a,0x4c,0x6c,0x82,0x96,0xe9,0x1d,0x29,0x29,0x1d,0x1d,0x2a,0x2a,0x1d,0x1d,0x29,0x29,0x1d,0x1d,0x2a,0x2a,0xfe,0x87,0x1e,0x3f,0x33,0x21,0x21,0x33,0x3f,0x1e,0x31,0x18,0x30,0x27,0x19,0x19,0x27,0x30,0x18,0x00,0x00,0x00,0x00,0x02,0x00,0x1a,0xff,0x86,0x04,0xb2,0x04,0x1e,0x00,0x2f,0x00,0x43,0x00,0x8f, +0xb7,0x59,0x2f,0x69,0x2f,0x79,0x2f,0x03,0x24,0xb8,0xff,0xf0,0xb3,0x0e,0x11,0x48,0x17,0xb8,0xff,0xf0,0x40,0x0b,0x0e,0x11,0x48,0x59,0x0c,0x69,0x0c,0x79,0x0c,0x03,0x30,0xb8,0x01,0x01,0xb4,0x2b,0x28,0x28,0x04,0x3a,0xb8,0x01,0x01,0xb7,0x10,0x70,0x13,0x01,0x13,0x13,0x1c,0x07,0xb8,0x01,0x01,0x40,0x0e,0x1f,0x00,0x04,0x10,0x04, +0x40,0x04,0x50,0x04,0x70,0x04,0x05,0x04,0x35,0xb8,0x01,0x02,0xb4,0x1f,0x1c,0x1c,0x13,0x28,0xbb,0x01,0x02,0x00,0x2b,0x00,0x3f,0x01,0x02,0x40,0x0b,0x04,0x70,0x07,0x01,0x07,0x07,0x10,0x1f,0x2b,0x01,0x2b,0x00,0x2f,0x5d,0x33,0x33,0x2f,0x5d,0x33,0xed,0x10,0xed,0x32,0x32,0x2f,0x33,0xed,0x01,0x2f,0x5d,0x33,0xed,0x32,0x32,0x2f, +0x5d,0x33,0xed,0x11,0x33,0x2f,0x33,0xed,0x31,0x30,0x00,0x5d,0x2b,0x2b,0x5d,0x13,0x17,0x3e,0x01,0x37,0x35,0x33,0x15,0x1e,0x01,0x17,0x37,0x17,0x07,0x1e,0x01,0x17,0x33,0x15,0x23,0x0e,0x01,0x07,0x17,0x07,0x27,0x0e,0x01,0x07,0x15,0x23,0x35,0x2e,0x01,0x27,0x07,0x27,0x37,0x2e,0x01,0x27,0x23,0x35,0x33,0x3e,0x01,0x37,0x27,0x13, +0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0xe0,0xa4,0x28,0x60,0x36,0x48,0x36,0x5f,0x28,0xa5,0x33,0xa5,0x20,0x2a,0x05,0xe9,0xe9,0x05,0x2a,0x20,0xa5,0x33,0xa5,0x28,0x5f,0x36,0x48,0x36,0x60,0x28,0xa4,0x33,0xa4,0x20,0x2a,0x05,0xe8,0xe8,0x05,0x2a,0x20,0xa4,0x9c,0x2d,0x4d,0x68,0x3b,0x3b,0x68, +0x4d,0x2d,0x2d,0x4d,0x68,0x3b,0x3b,0x68,0x4d,0x2d,0x03,0x8b,0xa5,0x20,0x2a,0x05,0xe9,0xe9,0x05,0x2a,0x20,0xa5,0x33,0xa5,0x28,0x5f,0x36,0x48,0x36,0x60,0x28,0xa4,0x33,0xa4,0x20,0x2a,0x05,0xe8,0xe8,0x05,0x2a,0x20,0xa4,0x33,0xa4,0x28,0x60,0x36,0x48,0x36,0x5f,0x28,0xa5,0xfe,0x7a,0x3c,0x68,0x4d,0x2c,0x2c,0x4d,0x68,0x3c,0x3b, +0x68,0x4d,0x2d,0x2d,0x4d,0x68,0x00,0x00,0x00,0x02,0x01,0x3c,0x00,0x46,0x03,0x90,0x04,0x94,0x00,0x1e,0x00,0x32,0x00,0x56,0xb6,0x14,0x20,0x0c,0x0f,0x48,0x17,0x1b,0xb8,0x01,0x01,0xb4,0x01,0x1c,0x1c,0x07,0x29,0xb8,0x01,0x01,0xb2,0x19,0x11,0x1f,0xb8,0x01,0x01,0xb4,0x1e,0x07,0x1c,0x1a,0x1e,0xb8,0x01,0x02,0xb3,0x17,0x00,0x00, +0x24,0xb8,0x01,0x02,0xb5,0x16,0x30,0x02,0x01,0x02,0x2e,0xb9,0x01,0x02,0x00,0x0c,0x00,0x2f,0xed,0xd4,0x5d,0x32,0xed,0x33,0x2f,0x33,0xed,0x32,0x32,0x01,0x2f,0x33,0xed,0xd4,0x32,0xed,0x11,0x39,0x2f,0x33,0xed,0x32,0x31,0x30,0x00,0x2b,0x01,0x33,0x35,0x2e,0x03,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07, +0x15,0x33,0x15,0x23,0x15,0x23,0x35,0x23,0x13,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x01,0x58,0xea,0x37,0x60,0x46,0x29,0x2f,0x51,0x6d,0x3d,0x3e,0x6c,0x51,0x2f,0x29,0x46,0x60,0x37,0xea,0xea,0x48,0xea,0x2c,0x23,0x3e,0x52,0x2f,0x2f,0x52,0x3d,0x24,0x24,0x3d,0x52,0x2f,0x2f,0x52,0x3e,0x23, +0x01,0x78,0xca,0x07,0x33,0x4f,0x66,0x39,0x3e,0x6c,0x51,0x2f,0x2f,0x51,0x6c,0x3e,0x39,0x66,0x4f,0x33,0x07,0xca,0x48,0xea,0xea,0x02,0x3a,0x2f,0x52,0x3e,0x23,0x23,0x3e,0x52,0x2f,0x2f,0x52,0x3d,0x24,0x24,0x3d,0x52,0x00,0x00,0x00,0x02,0x00,0xa4,0x00,0x72,0x04,0x04,0x03,0xd2,0x00,0x1d,0x00,0x31,0x00,0x67,0xb3,0x10,0x09,0x0b, +0x0f,0xb8,0x01,0x01,0x40,0x0c,0x0f,0x0e,0x1f,0x0e,0x2f,0x0e,0x03,0x0e,0x11,0x08,0x00,0x28,0xbb,0x01,0x01,0x00,0x14,0x00,0x1e,0x01,0x01,0xb7,0x00,0x00,0x01,0x00,0x08,0x11,0x05,0x23,0xb8,0x01,0x02,0x40,0x13,0x30,0x19,0x01,0x19,0x05,0x09,0x10,0x0e,0x0a,0x0f,0x0b,0x1f,0x0b,0x2f,0x0b,0x03,0x0b,0x0b,0x2d,0xb9,0x01,0x02,0x00, +0x05,0x00,0x2f,0xed,0x33,0x2f,0x5d,0xcd,0xcc,0x39,0x39,0x10,0xd4,0x5d,0xed,0x12,0x39,0x39,0x01,0x2f,0x5d,0xed,0xd4,0xed,0x12,0x39,0x39,0xd6,0x5d,0xed,0xc4,0x39,0x39,0x31,0x30,0x13,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x01,0x2f,0x01,0x21,0x17,0x11,0x2f,0x01,0x01,0x1e,0x01,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x37,0x14, +0x1e,0x02,0x33,0x32,0x3e,0x02,0x35,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0xa4,0x2f,0x51,0x6d,0x3d,0x34,0x5d,0x26,0x01,0x01,0xe2,0x02,0x01,0x4b,0x17,0x37,0x14,0xfe,0xff,0x1e,0x22,0x2f,0x51,0x6c,0x3e,0x3d,0x6d,0x51,0x2f,0x48,0x23,0x3e,0x52,0x2f,0x2f,0x52,0x3d,0x24,0x24,0x3d,0x52,0x2f,0x2f,0x52,0x3e,0x23,0x01,0x9c,0x3e,0x6c, +0x51,0x2f,0x22,0x1e,0x01,0x01,0x14,0x37,0x17,0xfe,0xb5,0x02,0xe2,0xfe,0xff,0x26,0x5d,0x34,0x3d,0x6d,0x51,0x2f,0x2f,0x51,0x6d,0x3d,0x2f,0x52,0x3e,0x23,0x23,0x3e,0x52,0x2f,0x2f,0x52,0x3d,0x24,0x24,0x3d,0x52,0x00,0x00,0x00,0x00,0x01,0x00,0x66,0x00,0x00,0x04,0x66,0x04,0xab,0x00,0x35,0x00,0x46,0x40,0x2e,0x47,0x30,0x57,0x30, +0x02,0x20,0x0a,0x30,0x0a,0x70,0x0a,0x03,0x0a,0x14,0x3f,0x2b,0x7f,0x2b,0x02,0x2b,0x10,0x21,0x40,0x21,0x50,0x21,0x80,0x21,0x04,0x21,0x0f,0x26,0x14,0x21,0x21,0x1f,0x26,0x2f,0x26,0x3f,0x26,0x03,0x26,0x26,0x1a,0x00,0x00,0x2f,0x2f,0x39,0x2f,0x5d,0x39,0x11,0x33,0x11,0x33,0x01,0x2f,0x5d,0xcd,0x5d,0xdd,0xcd,0x5d,0x31,0x30,0x5d, +0x01,0x14,0x1e,0x02,0x17,0x1e,0x03,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x14,0x1e,0x02,0x33,0x15,0x21,0x35,0x32,0x3e,0x02,0x35,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x37,0x3e,0x03,0x35,0x02,0x80,0x29,0x45,0x5b,0x32,0x38,0x57,0x3c,0x20,0x27,0x42,0x55,0x2d,0x24,0x46,0x3d,0x30,0x0e,0x2f,0x55,0x76,0x46, +0xfd,0x20,0x47,0x75,0x55,0x2f,0x0e,0x30,0x3d,0x46,0x24,0x2d,0x55,0x42,0x27,0x20,0x3c,0x58,0x37,0x32,0x5b,0x45,0x29,0x04,0xab,0x2e,0x67,0x65,0x60,0x27,0x2c,0x51,0x4f,0x53,0x2d,0x3a,0x59,0x3c,0x1f,0x13,0x1d,0x24,0x10,0x44,0x6a,0x48,0x26,0x38,0x38,0x26,0x48,0x6a,0x44,0x10,0x24,0x1d,0x13,0x1f,0x3c,0x59,0x3a,0x2d,0x53,0x4f, +0x51,0x2c,0x27,0x60,0x65,0x67,0x2e,0x00,0x00,0x01,0x00,0x61,0x00,0x00,0x04,0x6b,0x04,0xab,0x00,0x3e,0x00,0x54,0x40,0x34,0x35,0x26,0x3a,0x3a,0x2f,0x30,0x3f,0x30,0x7f,0x30,0x03,0x30,0x26,0x0a,0x19,0x05,0x05,0x20,0x0f,0x30,0x0f,0x70,0x0f,0x03,0x0f,0x19,0x10,0x26,0x40,0x26,0x50,0x26,0x80,0x26,0x04,0x26,0x14,0x2b,0x19,0x26, +0x26,0x1f,0x2b,0x2f,0x2b,0x3f,0x2b,0x03,0x2b,0x2b,0x1f,0x00,0x00,0x2f,0x2f,0x39,0x2f,0x5d,0x39,0x11,0x33,0x11,0x33,0x01,0x2f,0x5d,0xdd,0xcd,0x5d,0x39,0x2f,0x12,0x39,0x10,0xcd,0x5d,0x39,0x2f,0x12,0x39,0x31,0x30,0x01,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x36,0x1e,0x02,0x15,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x14, +0x1e,0x02,0x33,0x15,0x21,0x35,0x32,0x3e,0x02,0x35,0x0e,0x03,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x17,0x2e,0x03,0x35,0x34,0x3e,0x02,0x02,0x66,0x4b,0x6a,0x42,0x1e,0x13,0x20,0x2b,0x18,0x53,0x85,0x5d,0x31,0x27,0x42,0x55,0x2d,0x24,0x47,0x3f,0x32,0x0e,0x2f,0x55,0x76,0x46,0xfd,0x20,0x47,0x75,0x55,0x2f,0x0e,0x32,0x3f,0x47, +0x24,0x2d,0x55,0x42,0x27,0x31,0x5d,0x85,0x53,0x18,0x2b,0x20,0x13,0x1e,0x42,0x6a,0x04,0xab,0x2c,0x45,0x53,0x26,0x23,0x46,0x3e,0x34,0x11,0x08,0x1f,0x43,0x61,0x3c,0x3a,0x59,0x3c,0x1f,0x13,0x1d,0x24,0x10,0x44,0x6a,0x48,0x26,0x38,0x38,0x26,0x48,0x6a,0x44,0x10,0x24,0x1d,0x13,0x1f,0x3c,0x59,0x3a,0x3c,0x61,0x43,0x1f,0x08,0x11, +0x34,0x3e,0x46,0x23,0x26,0x53,0x45,0x2c,0x00,0x01,0x00,0x66,0xff,0xff,0x04,0x66,0x04,0x68,0x00,0x29,0x00,0x2a,0x40,0x1a,0x09,0x26,0x01,0x06,0x03,0x01,0x10,0x1f,0x01,0x1f,0x1f,0x2b,0x10,0x0a,0x40,0x0a,0x50,0x0a,0x70,0x0a,0x80,0x0a,0x05,0x0a,0x0f,0x00,0x00,0x2f,0x2f,0x01,0x2f,0x5d,0x11,0x33,0x2f,0x5d,0x31,0x30,0x5d,0x5d, +0x05,0x34,0x2e,0x02,0x27,0x2e,0x03,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x17,0x33,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x14,0x0e,0x02,0x07,0x0e,0x03,0x15,0x02,0x4c,0x30,0x4a,0x58,0x29,0x34,0x56,0x3e,0x23,0x2b,0x45,0x58,0x2d,0x2f,0x54,0x44,0x33,0x0e,0x06,0x0e,0x33,0x44,0x54,0x2f,0x2d,0x58,0x45,0x2b,0x23,0x3e,0x56,0x34, +0x28,0x59,0x4a,0x30,0x01,0x2f,0x6e,0x74,0x71,0x31,0x3f,0x79,0x71,0x68,0x2d,0x3a,0x5c,0x40,0x22,0x25,0x3f,0x53,0x2f,0x2f,0x53,0x3f,0x25,0x22,0x40,0x5c,0x3a,0x2d,0x68,0x71,0x79,0x3f,0x31,0x71,0x74,0x6e,0x2f,0x00,0x00,0x00,0x00,0x01,0x00,0x84,0xff,0xff,0x04,0x48,0x04,0xae,0x00,0x17,0x00,0x2c,0x40,0x1c,0x70,0x10,0x80,0x10, +0x02,0x4f,0x10,0x01,0x30,0x10,0x01,0x0f,0x10,0x01,0x10,0x10,0x00,0x04,0x10,0x04,0x40,0x04,0x50,0x04,0x04,0x04,0x16,0x0a,0x00,0x2f,0x2f,0x01,0x2f,0x5d,0x33,0x2f,0x5d,0x5d,0x5d,0x5d,0x31,0x30,0x24,0x2e,0x02,0x27,0x35,0x3e,0x03,0x37,0x33,0x1e,0x03,0x17,0x15,0x0e,0x03,0x07,0x23,0x02,0x31,0x70,0x7b,0x82,0x40,0x40,0x82,0x7b, +0x70,0x2f,0x0c,0x2f,0x70,0x7b,0x82,0x40,0x40,0x82,0x7b,0x70,0x2f,0x0c,0x40,0x95,0x9b,0x9c,0x49,0x03,0x49,0x9c,0x9b,0x95,0x41,0x41,0x95,0x9b,0x9c,0x49,0x03,0x49,0x9c,0x9b,0x95,0x41,0x00,0x01,0x01,0x1a,0x00,0x18,0x03,0xa9,0x04,0x66,0x00,0x2a,0x00,0x2c,0x40,0x17,0x03,0x40,0x25,0x80,0x1d,0x09,0x1f,0x13,0x01,0x13,0x00,0x1b, +0x10,0x1b,0x30,0x1b,0x03,0x1b,0x08,0x1c,0x0d,0x00,0x18,0x00,0x2f,0x33,0xcd,0x2f,0x33,0x01,0x2f,0x5d,0xcd,0x5d,0xcd,0x32,0x1a,0xdc,0x1a,0xcd,0x31,0x30,0x01,0x3e,0x01,0x35,0x34,0x2e,0x02,0x27,0x11,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x11,0x33,0x1e,0x01,0x17,0x1e,0x03,0x15,0x14,0x0e, +0x02,0x07,0x03,0x14,0x23,0x29,0x21,0x37,0x48,0x28,0x29,0x40,0x4f,0x26,0x21,0x3a,0x2c,0x19,0x27,0x3f,0x4e,0x28,0x1a,0x34,0x16,0x26,0x05,0x3b,0x45,0x2b,0x3e,0x28,0x13,0x14,0x1f,0x24,0x10,0x01,0x10,0x26,0x73,0x41,0x3a,0x62,0x4d,0x35,0x0d,0xfd,0xaa,0x25,0x3e,0x2c,0x18,0x11,0x20,0x2e,0x1d,0x22,0x3c,0x2d,0x1a,0x0b,0x0c,0x03, +0x44,0x31,0x78,0x46,0x2c,0x54,0x56,0x5b,0x33,0x2e,0x50,0x41,0x33,0x11,0x00,0x00,0x00,0x02,0x00,0x70,0xff,0xd2,0x04,0x3c,0x04,0x83,0x00,0x29,0x00,0x2d,0x00,0x86,0x40,0x53,0x2a,0x10,0x22,0x2b,0x25,0x1f,0x05,0x01,0x05,0x0d,0x0d,0x1f,0x1a,0x01,0x1a,0x00,0x22,0x10,0x22,0x02,0x22,0x89,0x0f,0x01,0x0f,0x2a,0x88,0x2a,0x01,0x67, +0x2a,0x01,0x54,0x2a,0x01,0x2a,0x89,0x0e,0x01,0x0e,0x2b,0x27,0x2b,0x01,0x15,0x2b,0x01,0x04,0x2b,0x01,0x2b,0x24,0x79,0x2d,0x89,0x2d,0x02,0x2d,0x23,0x77,0x23,0x87,0x23,0x02,0x56,0x23,0x01,0x23,0x24,0x00,0x0a,0x0a,0x1f,0x89,0x2c,0x01,0x2c,0x24,0x15,0x3f,0x1f,0x01,0x1f,0x00,0x2f,0x5d,0xcd,0x2f,0x33,0x5d,0x12,0x39,0x2f,0xcd, +0x11,0x33,0x5d,0x5d,0x11,0x33,0x5d,0x11,0x33,0x5d,0x5d,0x5d,0x11,0x33,0x5d,0x33,0x5d,0x5d,0x5d,0x11,0x33,0x5d,0x01,0x2f,0x5d,0xcd,0x5d,0x33,0x2f,0xcd,0x5d,0xcd,0x33,0x10,0xcd,0x32,0x31,0x30,0x25,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x11,0x05,0x11,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x3e,0x02, +0x33,0x32,0x16,0x17,0x11,0x25,0x11,0x14,0x0e,0x02,0x01,0x25,0x35,0x05,0x03,0x5e,0x21,0x3a,0x2c,0x19,0x27,0x3f,0x4e,0x28,0x1a,0x34,0x16,0xfd,0xf0,0x29,0x40,0x4f,0x26,0x21,0x3a,0x2c,0x19,0x27,0x3f,0x4e,0x28,0x1a,0x34,0x16,0x02,0x8c,0x29,0x40,0x4f,0xfe,0x6a,0x02,0x10,0xfd,0xf0,0x2c,0x11,0x20,0x2e,0x1d,0x22,0x3c,0x2d,0x1a, +0x0b,0x0c,0x01,0xb3,0x51,0xfd,0xe1,0x25,0x3e,0x2c,0x18,0x11,0x20,0x2e,0x1d,0x22,0x3c,0x2d,0x1a,0x0b,0x0c,0x03,0x43,0x64,0xfc,0x50,0x25,0x3e,0x2c,0x18,0x02,0xf8,0x51,0x78,0x51,0x00,0x00,0x03,0x00,0x54,0x00,0x00,0x04,0x25,0x05,0xcc,0x00,0x1b,0x00,0x1f,0x00,0x23,0x00,0x7e,0xb5,0x45,0x0a,0x55,0x0a,0x02,0x0a,0xb8,0xff,0xe0, +0x40,0x46,0x09,0x0c,0x48,0x1a,0x1a,0x0f,0x40,0x1d,0x22,0x48,0x0f,0x40,0x0b,0x18,0x48,0x0f,0x0f,0x20,0x02,0x1c,0x46,0x1f,0x1f,0x23,0x46,0x60,0x20,0xd0,0x20,0x02,0x20,0x20,0x25,0x19,0x01,0x46,0x02,0x05,0x05,0x06,0x00,0x02,0x01,0x02,0x30,0x1c,0x60,0x1c,0x02,0x80,0x1c,0x90,0x1c,0x02,0x1c,0x1d,0x13,0x50,0x0c,0x00,0x00,0x04, +0x51,0x21,0x19,0x05,0x0f,0x20,0x01,0x15,0x00,0x3f,0x33,0x3f,0x33,0x33,0xed,0x32,0x3f,0xed,0x2f,0x2f,0x5d,0x71,0x01,0x2f,0x5d,0x33,0x33,0x2f,0x10,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x32,0x2f,0xed,0x11,0x12,0x39,0x2f,0x2b,0x2b,0x33,0x2f,0x31,0x30,0x00,0x2b,0x5d,0x01,0x11,0x23,0x11,0x23,0x35,0x33,0x35,0x34,0x3e,0x02,0x33, +0x32,0x16,0x17,0x15,0x2e,0x01,0x23,0x22,0x0e,0x02,0x1d,0x01,0x33,0x15,0x13,0x35,0x33,0x15,0x03,0x11,0x33,0x11,0x01,0xa0,0xb4,0x98,0x98,0x16,0x3b,0x66,0x51,0x20,0x45,0x1a,0x11,0x2d,0x12,0x28,0x33,0x1d,0x0b,0xd3,0xfe,0xb4,0xb4,0xb4,0x03,0xb7,0xfc,0x49,0x03,0xb7,0x83,0x7a,0x3b,0x65,0x4b,0x2b,0x06,0x06,0x89,0x03,0x05,0x16, +0x29,0x3c,0x27,0x61,0x83,0x01,0x69,0xac,0xac,0xfa,0xe0,0x04,0x3a,0xfb,0xc6,0x00,0x00,0x02,0x00,0x54,0x00,0x00,0x04,0x25,0x05,0xcc,0x00,0x1b,0x00,0x1f,0x00,0x66,0xb5,0x45,0x0a,0x55,0x0a,0x02,0x0a,0xb8,0xff,0xe0,0x40,0x36,0x09,0x0c,0x48,0x1a,0x1a,0x0f,0x40,0x1d,0x22,0x48,0x0f,0x40,0x0b,0x18,0x48,0x0f,0x0f,0x02,0x1f,0x46, +0x60,0x1c,0xd0,0x1c,0x02,0x1c,0x1c,0x21,0x19,0x01,0x46,0x02,0x05,0x05,0x06,0x00,0x02,0x01,0x02,0x1d,0x00,0x13,0x50,0x0c,0x00,0x00,0x04,0x51,0x19,0x05,0x0f,0x1c,0x01,0x15,0x00,0x3f,0x33,0x3f,0x33,0xed,0x32,0x3f,0xed,0x3f,0x01,0x2f,0x5d,0x33,0x33,0x2f,0x10,0xed,0x32,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x2b,0x2b,0x33, +0x2f,0x31,0x30,0x00,0x2b,0x5d,0x01,0x11,0x23,0x11,0x23,0x35,0x33,0x35,0x34,0x3e,0x02,0x33,0x32,0x16,0x17,0x15,0x2e,0x01,0x23,0x22,0x0e,0x02,0x1d,0x01,0x33,0x15,0x13,0x11,0x33,0x11,0x01,0xa0,0xb4,0x98,0x98,0x16,0x3b,0x66,0x51,0x20,0x45,0x1a,0x11,0x2d,0x12,0x28,0x33,0x1d,0x0b,0xd3,0xfe,0xb4,0x03,0xb7,0xfc,0x49,0x03,0xb7, +0x83,0x7a,0x3b,0x65,0x4b,0x2b,0x06,0x06,0x89,0x03,0x05,0x16,0x29,0x3c,0x27,0x61,0x83,0xfc,0x49,0x05,0xcc,0xfa,0x34,0x00,0x00,0x01,0x01,0xdb,0xfe,0x59,0x02,0xef,0xff,0x9e,0x00,0x05,0x00,0x20,0x40,0x09,0x02,0x18,0x09,0x11,0x48,0x03,0x80,0x00,0x05,0xb8,0x01,0x0c,0xb5,0x00,0x02,0x10,0x02,0x02,0x02,0x00,0x2f,0x5d,0xed,0x01, +0x2f,0x1a,0xcd,0x31,0x30,0x2b,0x01,0x35,0x13,0x33,0x15,0x03,0x01,0xdb,0x4f,0xc5,0xab,0xfe,0x59,0x21,0x01,0x24,0x25,0xfe,0xe0,0x00,0x00,0x00,0x00,0x01,0x01,0x05,0x04,0xb0,0x03,0xe3,0x05,0xb4,0x00,0x15,0x00,0x25,0x40,0x14,0x10,0x85,0x0f,0x11,0x01,0x11,0x11,0x06,0x85,0x00,0x05,0x01,0x05,0x10,0x06,0x8c,0x0b,0x8e,0x00,0x93, +0x00,0x3f,0xed,0xe4,0x32,0x01,0x2f,0x5d,0xed,0x33,0x2f,0x5d,0xed,0x31,0x30,0x01,0x22,0x2e,0x02,0x27,0x33,0x1e,0x03,0x33,0x32,0x3e,0x02,0x37,0x33,0x0e,0x03,0x02,0x74,0x64,0x8a,0x57,0x28,0x02,0xa4,0x03,0x1e,0x33,0x49,0x2e,0x2e,0x49,0x33,0x1e,0x03,0xa4,0x02,0x28,0x57,0x8a,0x04,0xb0,0x26,0x45,0x60,0x39,0x2b,0x3a,0x22,0x0e, +0x0e,0x22,0x3a,0x2b,0x39,0x60,0x45,0x26,0x00,0x01,0x01,0xdb,0x04,0x87,0x02,0xef,0x05,0xcc,0x00,0x05,0x00,0x29,0xb2,0x02,0x86,0x03,0xb8,0x01,0x0b,0x40,0x0e,0x66,0x05,0x76,0x05,0x86,0x05,0x03,0x05,0x83,0x00,0x00,0x01,0x00,0x02,0xb8,0x01,0x0c,0xb1,0x05,0x93,0x00,0x3f,0xed,0x01,0x2f,0x5d,0xed,0x5d,0xfd,0xed,0x31,0x30,0x01, +0x35,0x13,0x33,0x15,0x03,0x01,0xdb,0x4f,0xc5,0xab,0x04,0x87,0x21,0x01,0x24,0x25,0xfe,0xe0,0x00,0x00,0x00,0x01,0x01,0xdb,0x04,0xbb,0x02,0xef,0x06,0x00,0x00,0x05,0x00,0x1d,0xb9,0x00,0x02,0xff,0xe8,0xb6,0x09,0x11,0x48,0x00,0x80,0x03,0x05,0xb8,0x01,0x0c,0xb1,0x02,0x94,0x00,0x3f,0xed,0x01,0x2f,0x1a,0xcd,0x31,0x30,0x2b,0x01, +0x15,0x03,0x23,0x35,0x13,0x02,0xef,0x4f,0xc5,0xab,0x06,0x00,0x21,0xfe,0xdc,0x25,0x01,0x20,0x00,0x00,0x00,0x01,0x00,0xd5,0xfe,0x57,0x03,0xa4,0x04,0x3a,0x00,0x19,0x00,0x30,0x40,0x1a,0x0a,0x03,0x1a,0x03,0x02,0x18,0x18,0x0a,0x00,0x46,0x00,0x15,0x01,0x15,0x15,0x1b,0x1a,0x0a,0x17,0x50,0x18,0x0f,0x10,0x50,0x05,0x1b,0x00,0x3f, +0xed,0x3f,0xed,0x01,0x2f,0x11,0x12,0x39,0x2f,0x5d,0xed,0x12,0x39,0x2f,0x31,0x30,0x00,0x5d,0x05,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x35,0x1e,0x03,0x33,0x32,0x3e,0x02,0x35,0x11,0x21,0x35,0x21,0x03,0xa4,0x47,0x76,0x9c,0x56,0x29,0x52,0x4c,0x41,0x18,0x16,0x3c,0x48,0x4f,0x28,0x38,0x61,0x48,0x29,0xfe,0x69,0x02,0x4b,0x1c, +0x6d,0x97,0x5f,0x2a,0x07,0x0c,0x0f,0x09,0x8c,0x05,0x0c,0x0a,0x07,0x1c,0x3d,0x5f,0x43,0x03,0xc5,0x8e,0x00,0x01,0x01,0x25,0x02,0x4d,0x02,0xc7,0x05,0x45,0x00,0x12,0x00,0x44,0x40,0x1c,0x11,0x11,0x10,0xe0,0x02,0x08,0x08,0x01,0x01,0x0e,0x00,0x02,0x10,0x02,0x02,0x02,0x02,0x13,0x14,0x08,0xe4,0x00,0x09,0x01,0x09,0x09,0x03,0x0e, +0xb8,0x01,0x11,0xb3,0x10,0x01,0xe4,0x00,0xb8,0x01,0x12,0x00,0x3f,0xed,0x32,0x3f,0x33,0x33,0x2f,0x5d,0xed,0x11,0x12,0x01,0x39,0x2f,0x5d,0x33,0x33,0x2f,0x33,0x2f,0x10,0xed,0x32,0x2f,0x31,0x30,0x01,0x35,0x33,0x11,0x0e,0x03,0x23,0x35,0x32,0x3e,0x02,0x37,0x33,0x11,0x33,0x15,0x01,0x49,0x87,0x0d,0x2f,0x33,0x2f,0x0d,0x12,0x30, +0x33,0x2f,0x11,0x79,0x74,0x02,0x4d,0x6b,0x02,0x01,0x1a,0x24,0x17,0x0a,0x77,0x0c,0x1b,0x2c,0x21,0xfd,0x73,0x6b,0x00,0x00,0x00,0x01,0x00,0xfa,0x02,0x4d,0x03,0x04,0x05,0x51,0x00,0x20,0x00,0x4f,0xb9,0x00,0x15,0xff,0xd8,0x40,0x20,0x09,0x11,0x48,0x1f,0x1f,0x17,0xe1,0x08,0x08,0x00,0x22,0x0e,0xe0,0x0f,0x0f,0x00,0x1e,0x1e,0x00, +0x00,0x10,0x00,0x02,0x00,0x5f,0x0e,0x01,0x0e,0x0e,0x0b,0xe4,0x14,0xb8,0x01,0x13,0xb3,0x01,0x1e,0xe4,0x00,0xb8,0x01,0x12,0x00,0x3f,0xed,0x32,0x3f,0xed,0x33,0x2f,0x5d,0x01,0x2f,0x5d,0x33,0x2f,0x11,0x33,0x2f,0xed,0x11,0x12,0x39,0x2f,0xed,0x32,0x2f,0x31,0x30,0x00,0x2b,0x13,0x35,0x3e,0x05,0x35,0x34,0x26,0x23,0x22,0x06,0x07, +0x27,0x3e,0x03,0x33,0x32,0x16,0x15,0x14,0x0e,0x04,0x07,0x21,0x15,0xfa,0x18,0x4a,0x54,0x54,0x44,0x2a,0x33,0x3c,0x3d,0x3b,0x08,0x82,0x06,0x27,0x41,0x5c,0x3d,0x78,0x79,0x2e,0x47,0x56,0x52,0x44,0x10,0x01,0x7c,0x02,0x4d,0x61,0x37,0x55,0x48,0x3f,0x40,0x47,0x2c,0x39,0x40,0x3e,0x3d,0x05,0x2f,0x50,0x3a,0x21,0x70,0x67,0x37,0x59, +0x4b,0x41,0x3f,0x41,0x26,0x6b,0x00,0x00,0x00,0x01,0x00,0xea,0x02,0x3b,0x02,0xed,0x05,0x51,0x00,0x33,0x00,0x8a,0xb9,0x00,0x2a,0xff,0xd8,0x40,0x40,0x09,0x11,0x48,0x03,0x28,0x09,0x11,0x48,0x00,0x1c,0x10,0x1c,0x20,0x1c,0x03,0x7b,0x30,0x01,0x22,0xe1,0x23,0x23,0x0a,0x2d,0xe1,0x1c,0x18,0x1c,0x18,0x1c,0x0a,0x00,0xe1,0x11,0x0b, +0xe1,0x0a,0x11,0x11,0x35,0x4f,0x0a,0x01,0x00,0x0a,0x10,0x0a,0x02,0x0a,0x30,0x18,0x17,0x16,0x16,0x0e,0x28,0x5f,0x22,0x01,0x22,0x22,0x1f,0xe4,0x28,0xb8,0x01,0x13,0x40,0x09,0x0e,0xe4,0x05,0x50,0x0b,0x01,0x0b,0x0b,0x05,0xb8,0x01,0x14,0x00,0x3f,0x33,0x2f,0x5d,0x10,0xed,0x3f,0xed,0x33,0x2f,0x5d,0x11,0x12,0x39,0x2f,0xc4,0x11, +0x39,0x01,0x2f,0x5d,0x5d,0x12,0x39,0x2f,0x10,0xed,0x10,0xed,0x12,0x39,0x39,0x2f,0x2f,0x10,0xed,0x11,0x33,0x2f,0xed,0x00,0x5d,0x01,0x5d,0x31,0x30,0x00,0x2b,0x2b,0x01,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x27,0x37,0x1e,0x01,0x33,0x32,0x36,0x35,0x34,0x2e,0x02,0x2b,0x01,0x35,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x06,0x07, +0x27,0x3e,0x03,0x33,0x32,0x1e,0x02,0x15,0x14,0x06,0x07,0x15,0x1e,0x01,0x02,0xed,0x27,0x44,0x5e,0x38,0x40,0x5c,0x3e,0x22,0x06,0x88,0x09,0x41,0x30,0x36,0x42,0x19,0x29,0x36,0x1d,0x29,0x25,0x44,0x40,0x36,0x29,0x2d,0x42,0x06,0x87,0x07,0x2c,0x44,0x55,0x30,0x3a,0x57,0x3a,0x1d,0x43,0x45,0x52,0x4b,0x03,0x1a,0x36,0x53,0x39,0x1d, +0x25,0x3c,0x4c,0x27,0x0d,0x3c,0x3d,0x3c,0x41,0x25,0x2f,0x1a,0x0a,0x6d,0x39,0x42,0x35,0x32,0x3f,0x39,0x0c,0x36,0x50,0x36,0x1a,0x1f,0x37,0x4a,0x2a,0x42,0x55,0x1a,0x02,0x12,0x64,0x00,0x00,0x02,0x00,0xc5,0x02,0x4b,0x03,0x35,0x05,0x45,0x00,0x0a,0x00,0x17,0x00,0x5d,0x40,0x12,0x09,0x09,0x08,0x01,0xe0,0x12,0x06,0x60,0x02,0x70, +0x02,0x80,0x02,0x03,0x02,0x02,0x19,0x11,0xb8,0x01,0x17,0x40,0x20,0x04,0x40,0x0d,0x11,0x48,0x00,0x04,0x10,0x04,0x02,0x04,0x00,0x04,0xe4,0x08,0x05,0x0f,0x11,0x1f,0x11,0x2f,0x11,0x9f,0x11,0xbf,0x11,0x05,0x11,0x11,0x01,0x0b,0x06,0xba,0x01,0x11,0x00,0x01,0x01,0x12,0x00,0x3f,0x3f,0x33,0x12,0x39,0x2f,0x5d,0x33,0x33,0xed,0x32, +0x01,0x2f,0x5d,0x2b,0xed,0x12,0x39,0x2f,0x5d,0x33,0x33,0xed,0x32,0x32,0x2f,0x31,0x30,0x01,0x15,0x23,0x35,0x21,0x35,0x01,0x33,0x11,0x33,0x15,0x03,0x0e,0x03,0x07,0x03,0x21,0x11,0x3c,0x02,0x36,0x02,0xbb,0x7f,0xfe,0x89,0x01,0x69,0x8d,0x7a,0xf8,0x06,0x15,0x18,0x17,0x07,0xb9,0x01,0x09,0x01,0x02,0xec,0xa1,0xa1,0x63,0x01,0xf6, +0xfe,0x0c,0x65,0x01,0xd9,0x09,0x1f,0x22,0x20,0x0a,0xff,0x00,0x01,0x04,0x0d,0x20,0x1f,0x1b,0x00,0x00,0x00,0x01,0x01,0x04,0x02,0x46,0x02,0xfb,0x05,0x45,0x00,0x1f,0x00,0x66,0xb9,0x00,0x1e,0xff,0xd8,0x40,0x2c,0x09,0x11,0x48,0x02,0x28,0x09,0x0e,0x48,0x19,0x1a,0x16,0x14,0xe0,0x15,0x15,0x05,0x0e,0x17,0x17,0x00,0xe1,0x0e,0x0e, +0x21,0x06,0xe0,0x00,0x05,0x10,0x05,0x02,0x05,0x1a,0xe5,0x15,0x15,0x11,0xe4,0x1d,0x1d,0x09,0x19,0xe5,0x16,0xb8,0x01,0x11,0xb5,0x09,0xe4,0x03,0x06,0x06,0x03,0xb8,0x01,0x14,0x00,0x3f,0x33,0x2f,0x10,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x33,0x2f,0xed,0x01,0x2f,0x5d,0xed,0x12,0x39,0x2f,0xed,0x32,0x2f,0x11,0x12,0x39,0x2f,0xed, +0x33,0x32,0x32,0x31,0x30,0x00,0x2b,0x2b,0x01,0x14,0x06,0x23,0x22,0x27,0x37,0x1e,0x01,0x33,0x32,0x3e,0x02,0x35,0x34,0x26,0x23,0x22,0x06,0x07,0x23,0x13,0x21,0x15,0x21,0x07,0x3e,0x01,0x33,0x32,0x16,0x02,0xfb,0x83,0x76,0xdb,0x23,0x85,0x0b,0x39,0x32,0x18,0x2b,0x20,0x12,0x3f,0x35,0x28,0x32,0x15,0x81,0x21,0x01,0xaa,0xfe,0xc2, +0x13,0x1c,0x43,0x27,0x70,0x7b,0x03,0x43,0x7a,0x83,0xbf,0x0f,0x36,0x2f,0x0e,0x22,0x39,0x2b,0x49,0x3f,0x1e,0x1e,0x01,0xb6,0x71,0xd7,0x20,0x1b,0x7e,0x00,0x00,0x00,0x00,0x01,0x00,0xfc,0x02,0x4d,0x03,0x03,0x05,0x45,0x00,0x0e,0x00,0x2f,0x40,0x14,0x05,0xe0,0x06,0x06,0x0c,0x00,0xe0,0x0b,0x0b,0x10,0x00,0x0c,0x10,0x0c,0x02,0x0c, +0x00,0x0c,0xe5,0x0d,0xba,0x01,0x11,0x00,0x05,0x01,0x12,0x00,0x3f,0x3f,0xed,0x32,0x01,0x2f,0x5d,0x12,0x39,0x2f,0xed,0x12,0x39,0x2f,0xed,0x31,0x30,0x01,0x0e,0x03,0x15,0x23,0x34,0x3e,0x02,0x37,0x21,0x35,0x21,0x03,0x03,0x43,0x63,0x3f,0x1f,0x85,0x22,0x43,0x63,0x40,0xfe,0x7a,0x02,0x07,0x04,0xe0,0x5d,0x9a,0x96,0xa1,0x65,0x5e, +0xa3,0x99,0x99,0x54,0x71,0x00,0x00,0x00,0x00,0x03,0x01,0x11,0x02,0x40,0x03,0x06,0x05,0x51,0x00,0x11,0x00,0x25,0x00,0x47,0x00,0x6d,0xb9,0x00,0x3e,0xff,0xe8,0xb3,0x0c,0x11,0x48,0x3a,0xb8,0xff,0xe8,0x40,0x2e,0x0c,0x11,0x48,0x2d,0x18,0x09,0x0f,0x48,0x29,0x18,0x09,0x11,0x48,0x45,0x33,0x37,0x41,0xe0,0x00,0x08,0xe0,0x37,0x00, +0x37,0x00,0x37,0x30,0x26,0xe0,0x12,0x12,0x49,0x1c,0xe0,0x30,0x45,0x33,0x33,0x17,0xe4,0x0d,0x0d,0x21,0x05,0xe4,0x3c,0xb8,0x01,0x13,0xb2,0x21,0xe4,0x2b,0xb8,0x01,0x14,0x00,0x3f,0xed,0x3f,0xed,0x12,0x39,0x2f,0xed,0x39,0x11,0x33,0x01,0x2f,0xed,0x12,0x39,0x2f,0xed,0x12,0x39,0x39,0x2f,0x2f,0x10,0xed,0x10,0xed,0x11,0x39,0x39, +0x31,0x30,0x00,0x2b,0x2b,0x2b,0x2b,0x01,0x34,0x2e,0x02,0x23,0x22,0x06,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x13,0x34,0x2e,0x02,0x23,0x22,0x0e,0x02,0x15,0x14,0x1e,0x02,0x33,0x32,0x3e,0x02,0x37,0x14,0x0e,0x02,0x23,0x22,0x2e,0x02,0x35,0x34,0x36,0x37,0x35,0x2e,0x01,0x35,0x34,0x3e,0x02,0x33,0x32,0x1e,0x02,0x15,0x14,0x06, +0x07,0x15,0x1e,0x01,0x02,0x6b,0x08,0x16,0x25,0x1e,0x38,0x28,0x08,0x16,0x25,0x1e,0x21,0x26,0x14,0x05,0x15,0x0c,0x1b,0x2d,0x22,0x21,0x2d,0x1a,0x0b,0x0b,0x1b,0x2e,0x22,0x23,0x2d,0x1a,0x09,0x86,0x1d,0x3c,0x5f,0x42,0x42,0x5f,0x3d,0x1d,0x40,0x39,0x36,0x2f,0x1d,0x39,0x56,0x39,0x3c,0x58,0x38,0x1b,0x31,0x35,0x42,0x39,0x04,0x80, +0x19,0x28,0x1d,0x0f,0x3b,0x32,0x13,0x29,0x21,0x15,0x16,0x21,0x29,0xfe,0xbb,0x1c,0x2f,0x22,0x13,0x13,0x22,0x2f,0x1c,0x1c,0x30,0x24,0x14,0x14,0x23,0x31,0x13,0x32,0x53,0x3b,0x20,0x21,0x3b,0x52,0x32,0x4e,0x59,0x12,0x03,0x1a,0x57,0x3f,0x29,0x48,0x35,0x1f,0x1f,0x36,0x48,0x29,0x3e,0x58,0x18,0x03,0x13,0x5a,0x00,0x00,0x00,0x1c, +0x01,0x56,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0xc2,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x0f,0x01,0x43,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x07,0x01,0x63,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x1a,0x01,0xa1,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0f,0x01,0xdc,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x0e,0x02,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0e,0x02,0x37,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x7a,0x03,0x3c,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x14,0x03,0xe1,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x0e,0x04,0x14,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x0b,0x00,0x1c,0x04,0x5d,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x2e,0x04,0xd8,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,0x6f,0x05,0xe7,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x3e,0x06,0xd5,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x01,0x00,0x1e, +0x01,0x23,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x02,0x00,0x0e,0x01,0x53,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x03,0x00,0x34,0x01,0x6b,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x04,0x00,0x1e,0x01,0xbc,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x05,0x00,0x1c,0x01,0xec,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x06,0x00,0x1c,0x02,0x19,0x00,0x03, +0x00,0x01,0x04,0x09,0x00,0x07,0x00,0xf4,0x02,0x46,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x08,0x00,0x28,0x03,0xb7,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x09,0x00,0x1c,0x03,0xf6,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0b,0x00,0x38,0x04,0x23,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0c,0x00,0x5c,0x04,0x7a,0x00,0x03,0x00,0x01,0x04,0x09, +0x00,0x0d,0x00,0xde,0x05,0x07,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0e,0x00,0x7c,0x06,0x57,0x00,0x43,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00,0x20,0x00,0x28,0x00,0x63,0x00,0x29,0x00,0x20,0x00,0x32,0x00,0x30,0x00,0x30,0x00,0x37,0x00,0x20,0x00,0x52,0x00,0x65,0x00,0x64,0x00,0x20, +0x00,0x48,0x00,0x61,0x00,0x74,0x00,0x2c,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x20,0x00,0x41,0x00,0x6c,0x00,0x6c,0x00,0x20,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00,0x73,0x00,0x20,0x00,0x72,0x00,0x65,0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x76,0x00,0x65,0x00,0x64,0x00,0x2e,0x00,0x20,0x00,0x4c, +0x00,0x49,0x00,0x42,0x00,0x45,0x00,0x52,0x00,0x41,0x00,0x54,0x00,0x49,0x00,0x4f,0x00,0x4e,0x00,0x20,0x00,0x69,0x00,0x73,0x00,0x20,0x00,0x61,0x00,0x20,0x00,0x74,0x00,0x72,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x6d,0x00,0x61,0x00,0x72,0x00,0x6b,0x00,0x20,0x00,0x6f,0x00,0x66,0x00,0x20,0x00,0x52,0x00,0x65,0x00,0x64,0x00,0x20, +0x00,0x48,0x00,0x61,0x00,0x74,0x00,0x2c,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x00,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x63,0x29,0x20,0x32,0x30,0x30,0x37,0x20,0x52,0x65,0x64,0x20,0x48,0x61,0x74,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x20,0x41,0x6c,0x6c,0x20,0x72,0x69,0x67,0x68,0x74,0x73,0x20, +0x72,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x2e,0x20,0x4c,0x49,0x42,0x45,0x52,0x41,0x54,0x49,0x4f,0x4e,0x20,0x69,0x73,0x20,0x61,0x20,0x74,0x72,0x61,0x64,0x65,0x6d,0x61,0x72,0x6b,0x20,0x6f,0x66,0x20,0x52,0x65,0x64,0x20,0x48,0x61,0x74,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x00,0x00,0x4c,0x00,0x69,0x00,0x62,0x00,0x65,0x00,0x72,0x00, +0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x4d,0x00,0x6f,0x00,0x6e,0x00,0x6f,0x00,0x00,0x4c,0x69,0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x20,0x4d,0x6f,0x6e,0x6f,0x00,0x00,0x52,0x00,0x65,0x00,0x67,0x00,0x75,0x00,0x6c,0x00,0x61,0x00,0x72,0x00,0x00,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x00,0x00,0x41,0x00, +0x73,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x20,0x00,0x2d,0x00,0x20,0x00,0x4c,0x00,0x69,0x00,0x62,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x4d,0x00,0x6f,0x00,0x6e,0x00,0x6f,0x00,0x00,0x41,0x73,0x63,0x65,0x6e,0x64,0x65,0x72,0x20,0x2d,0x20,0x4c,0x69, +0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x20,0x4d,0x6f,0x6e,0x6f,0x00,0x00,0x4c,0x00,0x69,0x00,0x62,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x4d,0x00,0x6f,0x00,0x6e,0x00,0x6f,0x00,0x00,0x4c,0x69,0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x20,0x4d,0x6f,0x6e,0x6f,0x00,0x00,0x56, +0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x31,0x00,0x2e,0x00,0x30,0x00,0x37,0x00,0x2e,0x00,0x31,0x00,0x00,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x30,0x37,0x2e,0x31,0x00,0x00,0x4c,0x00,0x69,0x00,0x62,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00, +0x4d,0x00,0x6f,0x00,0x6e,0x00,0x6f,0x00,0x00,0x4c,0x69,0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x4d,0x6f,0x6e,0x6f,0x00,0x00,0x4c,0x00,0x69,0x00,0x62,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x69,0x00,0x73,0x00,0x20,0x00,0x61,0x00,0x20,0x00,0x74,0x00,0x72,0x00,0x61,0x00,0x64, +0x00,0x65,0x00,0x6d,0x00,0x61,0x00,0x72,0x00,0x6b,0x00,0x20,0x00,0x6f,0x00,0x66,0x00,0x20,0x00,0x52,0x00,0x65,0x00,0x64,0x00,0x20,0x00,0x48,0x00,0x61,0x00,0x74,0x00,0x2c,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x20,0x00,0x72,0x00,0x65,0x00,0x67,0x00,0x69,0x00,0x73,0x00,0x74,0x00,0x65,0x00,0x72,0x00,0x65, +0x00,0x64,0x00,0x20,0x00,0x69,0x00,0x6e,0x00,0x20,0x00,0x55,0x00,0x2e,0x00,0x53,0x00,0x2e,0x00,0x20,0x00,0x50,0x00,0x61,0x00,0x74,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x20,0x00,0x61,0x00,0x6e,0x00,0x64,0x00,0x20,0x00,0x54,0x00,0x72,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x6d,0x00,0x61,0x00,0x72,0x00,0x6b,0x00,0x20,0x00,0x4f, +0x00,0x66,0x00,0x66,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x20,0x00,0x61,0x00,0x6e,0x00,0x64,0x00,0x20,0x00,0x63,0x00,0x65,0x00,0x72,0x00,0x74,0x00,0x61,0x00,0x69,0x00,0x6e,0x00,0x20,0x00,0x6f,0x00,0x74,0x00,0x68,0x00,0x65,0x00,0x72,0x00,0x20,0x00,0x6a,0x00,0x75,0x00,0x72,0x00,0x69,0x00,0x73,0x00,0x64,0x00,0x69,0x00,0x63, +0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x73,0x00,0x2e,0x00,0x00,0x4c,0x69,0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x20,0x69,0x73,0x20,0x61,0x20,0x74,0x72,0x61,0x64,0x65,0x6d,0x61,0x72,0x6b,0x20,0x6f,0x66,0x20,0x52,0x65,0x64,0x20,0x48,0x61,0x74,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65, +0x72,0x65,0x64,0x20,0x69,0x6e,0x20,0x55,0x2e,0x53,0x2e,0x20,0x50,0x61,0x74,0x65,0x6e,0x74,0x20,0x61,0x6e,0x64,0x20,0x54,0x72,0x61,0x64,0x65,0x6d,0x61,0x72,0x6b,0x20,0x4f,0x66,0x66,0x69,0x63,0x65,0x20,0x61,0x6e,0x64,0x20,0x63,0x65,0x72,0x74,0x61,0x69,0x6e,0x20,0x6f,0x74,0x68,0x65,0x72,0x20,0x6a,0x75,0x72,0x69,0x73,0x64, +0x69,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x00,0x00,0x41,0x00,0x73,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x20,0x00,0x43,0x00,0x6f,0x00,0x72,0x00,0x70,0x00,0x6f,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x41,0x73,0x63,0x65,0x6e,0x64,0x65,0x72,0x20,0x43,0x6f,0x72,0x70, +0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x00,0x00,0x53,0x00,0x74,0x00,0x65,0x00,0x76,0x00,0x65,0x00,0x20,0x00,0x4d,0x00,0x61,0x00,0x74,0x00,0x74,0x00,0x65,0x00,0x73,0x00,0x6f,0x00,0x6e,0x00,0x00,0x53,0x74,0x65,0x76,0x65,0x20,0x4d,0x61,0x74,0x74,0x65,0x73,0x6f,0x6e,0x00,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00, +0x2f,0x00,0x2f,0x00,0x77,0x00,0x77,0x00,0x77,0x00,0x2e,0x00,0x61,0x00,0x73,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x63,0x00,0x6f,0x00,0x72,0x00,0x70,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x2f,0x00,0x00,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x61,0x73,0x63,0x65,0x6e,0x64, +0x65,0x72,0x63,0x6f,0x72,0x70,0x2e,0x63,0x6f,0x6d,0x2f,0x00,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,0x77,0x00,0x77,0x00,0x2e,0x00,0x61,0x00,0x73,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x63,0x00,0x6f,0x00,0x72,0x00,0x70,0x00,0x2e,0x00,0x63,0x00,0x6f, +0x00,0x6d,0x00,0x2f,0x00,0x74,0x00,0x79,0x00,0x70,0x00,0x65,0x00,0x64,0x00,0x65,0x00,0x73,0x00,0x69,0x00,0x67,0x00,0x6e,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x2e,0x00,0x68,0x00,0x74,0x00,0x6d,0x00,0x6c,0x00,0x00,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x61,0x73,0x63,0x65,0x6e,0x64,0x65,0x72,0x63,0x6f,0x72, +0x70,0x2e,0x63,0x6f,0x6d,0x2f,0x74,0x79,0x70,0x65,0x64,0x65,0x73,0x69,0x67,0x6e,0x65,0x72,0x73,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x4c,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x73,0x00,0x65,0x00,0x64,0x00,0x20,0x00,0x75,0x00,0x6e,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x20,0x00,0x74,0x00,0x68,0x00,0x65,0x00,0x20,0x00, +0x4c,0x00,0x69,0x00,0x62,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x46,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x73,0x00,0x20,0x00,0x6c,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x73,0x00,0x65,0x00,0x2c,0x00,0x20,0x00,0x73,0x00,0x65,0x00,0x65,0x00,0x20,0x00,0x68,0x00,0x74,0x00, +0x74,0x00,0x70,0x00,0x73,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x00,0x66,0x00,0x65,0x00,0x64,0x00,0x6f,0x00,0x72,0x00,0x61,0x00,0x70,0x00,0x72,0x00,0x6f,0x00,0x6a,0x00,0x65,0x00,0x63,0x00,0x74,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,0x6b,0x00,0x69,0x00,0x2f,0x00,0x4c,0x00,0x69,0x00,0x63,0x00, +0x65,0x00,0x6e,0x00,0x73,0x00,0x69,0x00,0x6e,0x00,0x67,0x00,0x2f,0x00,0x4c,0x00,0x69,0x00,0x62,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x46,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x4c,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x73,0x00,0x65,0x00,0x00,0x4c,0x69,0x63,0x65,0x6e,0x73,0x65, +0x64,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x65,0x20,0x4c,0x69,0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x20,0x46,0x6f,0x6e,0x74,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x2c,0x20,0x73,0x65,0x65,0x20,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x66,0x65,0x64,0x6f,0x72,0x61,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e, +0x6f,0x72,0x67,0x2f,0x77,0x69,0x6b,0x69,0x2f,0x4c,0x69,0x63,0x65,0x6e,0x73,0x69,0x6e,0x67,0x2f,0x4c,0x69,0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x46,0x6f,0x6e,0x74,0x4c,0x69,0x63,0x65,0x6e,0x73,0x65,0x00,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x73,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x00,0x66,0x00,0x65,0x00,0x64,0x00, +0x6f,0x00,0x72,0x00,0x61,0x00,0x70,0x00,0x72,0x00,0x6f,0x00,0x6a,0x00,0x65,0x00,0x63,0x00,0x74,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,0x6b,0x00,0x69,0x00,0x2f,0x00,0x4c,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x73,0x00,0x69,0x00,0x6e,0x00,0x67,0x00,0x2f,0x00,0x4c,0x00,0x69,0x00, +0x62,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x46,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x4c,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x6e,0x00,0x73,0x00,0x65,0x00,0x00,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x66,0x65,0x64,0x6f,0x72,0x61,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x6f,0x72,0x67, +0x2f,0x77,0x69,0x6b,0x69,0x2f,0x4c,0x69,0x63,0x65,0x6e,0x73,0x69,0x6e,0x67,0x2f,0x4c,0x69,0x62,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x46,0x6f,0x6e,0x74,0x4c,0x69,0x63,0x65,0x6e,0x73,0x65,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x23,0x00,0x54,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xa1,0x00,0x00,0x00,0x01,0x00,0x02,0x01,0x02,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,0x00,0x09,0x00,0x0a,0x00,0x0b,0x00,0x0c,0x00,0x0d,0x00,0x0e,0x00,0x0f,0x01,0x03,0x00,0x11,0x00,0x12,0x00,0x13,0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x18,0x00,0x19,0x00,0x1a, +0x00,0x1b,0x00,0x1c,0x00,0x1d,0x01,0x04,0x00,0x1f,0x00,0x20,0x00,0x21,0x00,0x22,0x00,0x23,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2a,0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a, +0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x3e,0x00,0x3f,0x00,0x40,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x47,0x00,0x48,0x00,0x49,0x00,0x4a,0x00,0x4b,0x00,0x4c,0x00,0x4d,0x00,0x4e,0x00,0x4f,0x00,0x50,0x00,0x51,0x00,0x52,0x00,0x53,0x00,0x54,0x00,0x55,0x00,0x56,0x00,0x57,0x00,0x58,0x00,0x59,0x00,0x5a, +0x00,0x5b,0x00,0x5c,0x00,0x5d,0x00,0x5e,0x00,0x5f,0x00,0x60,0x00,0x61,0x00,0xa3,0x00,0x84,0x00,0x85,0x00,0xbd,0x00,0x96,0x00,0xe8,0x00,0x86,0x00,0x8e,0x00,0x8b,0x00,0x9d,0x00,0xa9,0x00,0xa4,0x00,0x8a,0x00,0xda,0x00,0x83,0x00,0x93,0x01,0x05,0x01,0x06,0x00,0x8d,0x01,0x07,0x00,0x88,0x00,0xc3,0x00,0xde,0x01,0x08,0x00,0x9e, +0x00,0xaa,0x00,0xf5,0x00,0xf4,0x00,0xf6,0x00,0xa2,0x00,0xad,0x00,0xc9,0x00,0xc7,0x00,0xae,0x00,0x62,0x00,0x63,0x00,0x90,0x00,0x64,0x00,0xcb,0x00,0x65,0x00,0xc8,0x00,0xca,0x00,0xcf,0x00,0xcc,0x00,0xcd,0x00,0xce,0x00,0xe9,0x00,0x66,0x00,0xd3,0x00,0xd0,0x00,0xd1,0x00,0xaf,0x00,0x67,0x00,0xf0,0x00,0x91,0x00,0xd6,0x00,0xd4, +0x00,0xd5,0x00,0x68,0x00,0xeb,0x00,0xed,0x00,0x89,0x00,0x6a,0x00,0x69,0x00,0x6b,0x00,0x6d,0x00,0x6c,0x00,0x6e,0x00,0xa0,0x00,0x6f,0x00,0x71,0x00,0x70,0x00,0x72,0x00,0x73,0x00,0x75,0x00,0x74,0x00,0x76,0x00,0x77,0x00,0xea,0x00,0x78,0x00,0x7a,0x00,0x79,0x00,0x7b,0x00,0x7d,0x00,0x7c,0x00,0xb8,0x00,0xa1,0x00,0x7f,0x00,0x7e, +0x00,0x80,0x00,0x81,0x00,0xec,0x00,0xee,0x00,0xba,0x01,0x09,0x01,0x0a,0x01,0x0b,0x01,0x0c,0x01,0x0d,0x01,0x0e,0x00,0xfd,0x00,0xfe,0x01,0x0f,0x01,0x10,0x01,0x11,0x01,0x12,0x00,0xff,0x01,0x00,0x01,0x13,0x01,0x14,0x01,0x15,0x01,0x01,0x01,0x16,0x01,0x17,0x01,0x18,0x01,0x19,0x01,0x1a,0x01,0x1b,0x01,0x1c,0x01,0x1d,0x01,0x1e, +0x01,0x1f,0x01,0x20,0x01,0x21,0x00,0xf8,0x00,0xf9,0x01,0x22,0x01,0x23,0x01,0x24,0x01,0x25,0x01,0x26,0x01,0x27,0x01,0x28,0x01,0x29,0x01,0x2a,0x01,0x2b,0x01,0x2c,0x01,0x2d,0x01,0x2e,0x01,0x2f,0x01,0x30,0x01,0x31,0x00,0xfa,0x00,0xd7,0x01,0x32,0x01,0x33,0x01,0x34,0x01,0x35,0x01,0x36,0x01,0x37,0x01,0x38,0x01,0x39,0x01,0x3a, +0x01,0x3b,0x01,0x3c,0x01,0x3d,0x01,0x3e,0x01,0x3f,0x01,0x40,0x00,0xe2,0x00,0xe3,0x01,0x41,0x01,0x42,0x01,0x43,0x01,0x44,0x01,0x45,0x01,0x46,0x01,0x47,0x01,0x48,0x01,0x49,0x01,0x4a,0x01,0x4b,0x01,0x4c,0x01,0x4d,0x01,0x4e,0x01,0x4f,0x00,0xb0,0x00,0xb1,0x01,0x50,0x01,0x51,0x01,0x52,0x01,0x53,0x01,0x54,0x01,0x55,0x01,0x56, +0x01,0x57,0x01,0x58,0x01,0x59,0x00,0xfb,0x00,0xfc,0x00,0xe4,0x00,0xe5,0x01,0x5a,0x01,0x5b,0x01,0x5c,0x01,0x5d,0x01,0x5e,0x01,0x5f,0x01,0x60,0x01,0x61,0x01,0x62,0x01,0x63,0x01,0x64,0x01,0x65,0x01,0x66,0x01,0x67,0x01,0x68,0x01,0x69,0x01,0x6a,0x01,0x6b,0x01,0x6c,0x01,0x6d,0x01,0x6e,0x01,0x6f,0x00,0xbb,0x01,0x70,0x01,0x71, +0x01,0x72,0x01,0x73,0x00,0xe6,0x00,0xe7,0x01,0x74,0x00,0xa6,0x01,0x75,0x01,0x76,0x01,0x77,0x01,0x78,0x01,0x79,0x01,0x7a,0x01,0x7b,0x01,0x7c,0x01,0x7d,0x01,0x7e,0x00,0xd8,0x00,0xe1,0x01,0x7f,0x00,0xdb,0x00,0xdc,0x00,0xdd,0x00,0xe0,0x00,0xd9,0x00,0xdf,0x01,0x80,0x01,0x81,0x01,0x82,0x01,0x83,0x01,0x84,0x01,0x85,0x01,0x86, +0x01,0x87,0x01,0x88,0x01,0x89,0x01,0x8a,0x01,0x8b,0x01,0x8c,0x01,0x8d,0x00,0xa8,0x01,0x8e,0x01,0x8f,0x01,0x90,0x01,0x91,0x01,0x92,0x01,0x93,0x01,0x94,0x01,0x95,0x01,0x96,0x01,0x97,0x01,0x98,0x01,0x99,0x01,0x9a,0x01,0x9b,0x01,0x9c,0x01,0x9d,0x01,0x9e,0x01,0x9f,0x01,0xa0,0x00,0x9f,0x01,0xa1,0x01,0xa2,0x01,0xa3,0x01,0xa4, +0x01,0xa5,0x01,0xa6,0x01,0xa7,0x01,0xa8,0x01,0xa9,0x01,0xaa,0x01,0xab,0x01,0xac,0x01,0xad,0x01,0xae,0x01,0xaf,0x01,0xb0,0x01,0xb1,0x01,0xb2,0x00,0x97,0x01,0xb3,0x01,0xb4,0x01,0xb5,0x00,0x9b,0x01,0xb6,0x01,0xb7,0x01,0xb8,0x01,0xb9,0x01,0xba,0x01,0xbb,0x01,0xbc,0x01,0xbd,0x01,0xbe,0x01,0xbf,0x01,0xc0,0x01,0xc1,0x01,0xc2, +0x01,0xc3,0x01,0xc4,0x01,0xc5,0x01,0xc6,0x01,0xc7,0x01,0xc8,0x01,0xc9,0x01,0xca,0x01,0xcb,0x01,0xcc,0x01,0xcd,0x01,0xce,0x01,0xcf,0x01,0xd0,0x01,0xd1,0x01,0xd2,0x01,0xd3,0x01,0xd4,0x01,0xd5,0x01,0xd6,0x01,0xd7,0x01,0xd8,0x01,0xd9,0x01,0xda,0x01,0xdb,0x01,0xdc,0x01,0xdd,0x01,0xde,0x01,0xdf,0x01,0xe0,0x01,0xe1,0x01,0xe2, +0x01,0xe3,0x01,0xe4,0x01,0xe5,0x01,0xe6,0x01,0xe7,0x01,0xe8,0x01,0xe9,0x01,0xea,0x01,0xeb,0x01,0xec,0x01,0xed,0x01,0xee,0x01,0xef,0x01,0xf0,0x01,0xf1,0x01,0xf2,0x01,0xf3,0x01,0xf4,0x01,0xf5,0x01,0xf6,0x01,0xf7,0x01,0xf8,0x01,0xf9,0x01,0xfa,0x01,0xfb,0x01,0xfc,0x01,0xfd,0x01,0xfe,0x01,0xff,0x02,0x00,0x02,0x01,0x02,0x02, +0x02,0x03,0x02,0x04,0x02,0x05,0x02,0x06,0x02,0x07,0x02,0x08,0x02,0x09,0x02,0x0a,0x02,0x0b,0x02,0x0c,0x02,0x0d,0x02,0x0e,0x02,0x0f,0x02,0x10,0x02,0x11,0x02,0x12,0x02,0x13,0x02,0x14,0x02,0x15,0x02,0x16,0x02,0x17,0x02,0x18,0x02,0x19,0x02,0x1a,0x02,0x1b,0x02,0x1c,0x02,0x1d,0x02,0x1e,0x02,0x1f,0x02,0x20,0x02,0x21,0x02,0x22, +0x02,0x23,0x02,0x24,0x02,0x25,0x02,0x26,0x02,0x27,0x02,0x28,0x02,0x29,0x02,0x2a,0x02,0x2b,0x02,0x2c,0x02,0x2d,0x02,0x2e,0x02,0x2f,0x00,0xb2,0x00,0xb3,0x02,0x30,0x02,0x31,0x00,0xb6,0x00,0xb7,0x00,0xc4,0x02,0x32,0x00,0xb4,0x00,0xb5,0x00,0xc5,0x00,0x82,0x00,0xc2,0x00,0x87,0x00,0xab,0x00,0xc6,0x02,0x33,0x02,0x34,0x00,0xbe, +0x00,0xbf,0x02,0x35,0x02,0x36,0x02,0x37,0x02,0x38,0x00,0xf7,0x02,0x39,0x02,0x3a,0x02,0x3b,0x02,0x3c,0x02,0x3d,0x02,0x3e,0x00,0x8c,0x02,0x3f,0x02,0x40,0x02,0x41,0x02,0x42,0x02,0x43,0x02,0x44,0x02,0x45,0x02,0x46,0x02,0x47,0x02,0x48,0x02,0x49,0x02,0x4a,0x02,0x4b,0x00,0x98,0x02,0x4c,0x00,0x9a,0x00,0x99,0x00,0xef,0x02,0x4d, +0x00,0xa5,0x00,0x92,0x02,0x4e,0x02,0x4f,0x00,0x9c,0x00,0xa7,0x00,0x8f,0x02,0x50,0x00,0x94,0x00,0x95,0x02,0x51,0x02,0x52,0x02,0x53,0x02,0x54,0x02,0x55,0x02,0x56,0x02,0x57,0x02,0x58,0x02,0x59,0x02,0x5a,0x02,0x5b,0x02,0x5c,0x02,0x5d,0x02,0x5e,0x02,0x5f,0x02,0x60,0x02,0x61,0x02,0x62,0x02,0x63,0x02,0x64,0x02,0x65,0x02,0x66, +0x02,0x67,0x02,0x68,0x02,0x69,0x02,0x6a,0x02,0x6b,0x02,0x6c,0x02,0x6d,0x02,0x6e,0x02,0x6f,0x02,0x70,0x02,0x71,0x02,0x72,0x02,0x73,0x02,0x74,0x02,0x75,0x02,0x76,0x02,0x77,0x02,0x78,0x02,0x79,0x02,0x7a,0x02,0x7b,0x02,0x7c,0x02,0x7d,0x02,0x7e,0x02,0x7f,0x02,0x80,0x02,0x81,0x02,0x82,0x02,0x83,0x02,0x84,0x02,0x85,0x02,0x86, +0x02,0x87,0x02,0x88,0x02,0x89,0x02,0x8a,0x02,0x8b,0x02,0x8c,0x02,0x8d,0x00,0xb9,0x02,0x8e,0x02,0x8f,0x02,0x90,0x02,0x91,0x02,0x92,0x02,0x93,0x02,0x94,0x02,0x95,0x02,0x96,0x02,0x97,0x02,0x98,0x02,0x99,0x02,0x9a,0x02,0x9b,0x02,0x9c,0x02,0x9d,0x02,0x9e,0x02,0x9f,0x02,0xa0,0x02,0xa1,0x02,0xa2,0x02,0xa3,0x02,0xa4,0x02,0xa5, +0x02,0xa6,0x02,0xa7,0x02,0xa8,0x02,0xa9,0x02,0xaa,0x02,0xab,0x07,0x75,0x6e,0x69,0x30,0x30,0x41,0x30,0x07,0x75,0x6e,0x69,0x30,0x30,0x41,0x44,0x07,0x75,0x6e,0x69,0x30,0x33,0x37,0x45,0x07,0x75,0x6e,0x69,0x30,0x30,0x42,0x32,0x07,0x75,0x6e,0x69,0x30,0x30,0x42,0x33,0x07,0x75,0x6e,0x69,0x30,0x30,0x42,0x35,0x07,0x75,0x6e,0x69, +0x30,0x30,0x42,0x39,0x07,0x41,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x61,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x41,0x62,0x72,0x65,0x76,0x65,0x06,0x61,0x62,0x72,0x65,0x76,0x65,0x07,0x41,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x61,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x0b,0x43,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x63, +0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0a,0x43,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x0a,0x63,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x44,0x63,0x61,0x72,0x6f,0x6e,0x06,0x64,0x63,0x61,0x72,0x6f,0x6e,0x06,0x44,0x63,0x72,0x6f,0x61,0x74,0x07,0x45,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x65,0x6d, +0x61,0x63,0x72,0x6f,0x6e,0x06,0x45,0x62,0x72,0x65,0x76,0x65,0x06,0x65,0x62,0x72,0x65,0x76,0x65,0x0a,0x45,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x0a,0x65,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x07,0x45,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x65,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x06,0x45,0x63,0x61,0x72,0x6f,0x6e, +0x06,0x65,0x63,0x61,0x72,0x6f,0x6e,0x0b,0x47,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x67,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0a,0x47,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x0a,0x67,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x47,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65, +0x6e,0x74,0x0c,0x67,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0b,0x48,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x68,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x04,0x48,0x62,0x61,0x72,0x04,0x68,0x62,0x61,0x72,0x06,0x49,0x74,0x69,0x6c,0x64,0x65,0x06,0x69,0x74,0x69,0x6c,0x64,0x65,0x07, +0x49,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x69,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x49,0x62,0x72,0x65,0x76,0x65,0x06,0x69,0x62,0x72,0x65,0x76,0x65,0x07,0x49,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x69,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x02,0x49,0x4a,0x02,0x69,0x6a,0x0b,0x4a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b, +0x6a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0c,0x4b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6b,0x67,0x72,0x65,0x65,0x6e,0x6c,0x61,0x6e,0x64,0x69,0x63,0x06,0x4c,0x61,0x63,0x75,0x74,0x65,0x06,0x6c,0x61,0x63,0x75,0x74,0x65, +0x0c,0x4c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x4c,0x63,0x61,0x72,0x6f,0x6e,0x06,0x6c,0x63,0x61,0x72,0x6f,0x6e,0x04,0x4c,0x64,0x6f,0x74,0x04,0x6c,0x64,0x6f,0x74,0x06,0x4e,0x61,0x63,0x75,0x74,0x65,0x06,0x6e,0x61,0x63,0x75,0x74,0x65, +0x0c,0x4e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x6e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x4e,0x63,0x61,0x72,0x6f,0x6e,0x06,0x6e,0x63,0x61,0x72,0x6f,0x6e,0x0b,0x6e,0x61,0x70,0x6f,0x73,0x74,0x72,0x6f,0x70,0x68,0x65,0x03,0x45,0x6e,0x67,0x03,0x65,0x6e,0x67,0x07,0x4f,0x6d,0x61, +0x63,0x72,0x6f,0x6e,0x07,0x6f,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x4f,0x62,0x72,0x65,0x76,0x65,0x06,0x6f,0x62,0x72,0x65,0x76,0x65,0x0d,0x4f,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x0d,0x6f,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x06,0x52,0x61,0x63,0x75,0x74,0x65,0x06,0x72,0x61, +0x63,0x75,0x74,0x65,0x0c,0x52,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x72,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x52,0x63,0x61,0x72,0x6f,0x6e,0x06,0x72,0x63,0x61,0x72,0x6f,0x6e,0x06,0x53,0x61,0x63,0x75,0x74,0x65,0x06,0x73,0x61,0x63,0x75,0x74,0x65,0x0b,0x53,0x63,0x69,0x72,0x63, +0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x73,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0c,0x54,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x74,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x06,0x54,0x63,0x61,0x72,0x6f,0x6e,0x06,0x74,0x63,0x61,0x72,0x6f,0x6e,0x04,0x54,0x62,0x61,0x72,0x04, +0x74,0x62,0x61,0x72,0x06,0x55,0x74,0x69,0x6c,0x64,0x65,0x06,0x75,0x74,0x69,0x6c,0x64,0x65,0x07,0x55,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x07,0x75,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x06,0x55,0x62,0x72,0x65,0x76,0x65,0x06,0x75,0x62,0x72,0x65,0x76,0x65,0x05,0x55,0x72,0x69,0x6e,0x67,0x05,0x75,0x72,0x69,0x6e,0x67,0x0d,0x55,0x68,0x75, +0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x0d,0x75,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x07,0x55,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x07,0x75,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x0b,0x57,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x77,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78, +0x0b,0x59,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x0b,0x79,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x06,0x5a,0x61,0x63,0x75,0x74,0x65,0x06,0x7a,0x61,0x63,0x75,0x74,0x65,0x0a,0x5a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x0a,0x7a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x05,0x6c,0x6f,0x6e, +0x67,0x73,0x0a,0x41,0x72,0x69,0x6e,0x67,0x61,0x63,0x75,0x74,0x65,0x0a,0x61,0x72,0x69,0x6e,0x67,0x61,0x63,0x75,0x74,0x65,0x07,0x41,0x45,0x61,0x63,0x75,0x74,0x65,0x07,0x61,0x65,0x61,0x63,0x75,0x74,0x65,0x0b,0x4f,0x73,0x6c,0x61,0x73,0x68,0x61,0x63,0x75,0x74,0x65,0x0b,0x6f,0x73,0x6c,0x61,0x73,0x68,0x61,0x63,0x75,0x74,0x65, +0x0c,0x53,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0c,0x73,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x07,0x75,0x6e,0x69,0x30,0x32,0x31,0x41,0x07,0x75,0x6e,0x69,0x30,0x32,0x31,0x42,0x07,0x75,0x6e,0x69,0x30,0x32,0x43,0x39,0x05,0x74,0x6f,0x6e,0x6f,0x73,0x0d,0x64,0x69,0x65,0x72,0x65,0x73,0x69, +0x73,0x74,0x6f,0x6e,0x6f,0x73,0x0a,0x41,0x6c,0x70,0x68,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x09,0x61,0x6e,0x6f,0x74,0x65,0x6c,0x65,0x69,0x61,0x0c,0x45,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x08,0x45,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x09,0x49,0x6f,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x0c,0x4f,0x6d,0x69,0x63, +0x72,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0c,0x55,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0a,0x4f,0x6d,0x65,0x67,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x11,0x69,0x6f,0x74,0x61,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x74,0x6f,0x6e,0x6f,0x73,0x05,0x41,0x6c,0x70,0x68,0x61,0x04,0x42,0x65,0x74,0x61,0x05,0x47,0x61, +0x6d,0x6d,0x61,0x07,0x45,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x04,0x5a,0x65,0x74,0x61,0x03,0x45,0x74,0x61,0x05,0x54,0x68,0x65,0x74,0x61,0x04,0x49,0x6f,0x74,0x61,0x05,0x4b,0x61,0x70,0x70,0x61,0x06,0x4c,0x61,0x6d,0x62,0x64,0x61,0x02,0x4d,0x75,0x02,0x4e,0x75,0x02,0x58,0x69,0x07,0x4f,0x6d,0x69,0x63,0x72,0x6f,0x6e,0x02,0x50,0x69, +0x03,0x52,0x68,0x6f,0x05,0x53,0x69,0x67,0x6d,0x61,0x03,0x54,0x61,0x75,0x07,0x55,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x03,0x50,0x68,0x69,0x03,0x43,0x68,0x69,0x03,0x50,0x73,0x69,0x0c,0x49,0x6f,0x74,0x61,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0f,0x55,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0a, +0x61,0x6c,0x70,0x68,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x0c,0x65,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x08,0x65,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x09,0x69,0x6f,0x74,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x14,0x75,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x74,0x6f,0x6e,0x6f,0x73,0x05, +0x61,0x6c,0x70,0x68,0x61,0x04,0x62,0x65,0x74,0x61,0x05,0x67,0x61,0x6d,0x6d,0x61,0x05,0x64,0x65,0x6c,0x74,0x61,0x07,0x65,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x04,0x7a,0x65,0x74,0x61,0x03,0x65,0x74,0x61,0x05,0x74,0x68,0x65,0x74,0x61,0x04,0x69,0x6f,0x74,0x61,0x05,0x6b,0x61,0x70,0x70,0x61,0x06,0x6c,0x61,0x6d,0x62,0x64,0x61,0x02, +0x6e,0x75,0x02,0x78,0x69,0x07,0x6f,0x6d,0x69,0x63,0x72,0x6f,0x6e,0x03,0x72,0x68,0x6f,0x06,0x73,0x69,0x67,0x6d,0x61,0x31,0x05,0x73,0x69,0x67,0x6d,0x61,0x03,0x74,0x61,0x75,0x07,0x75,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x03,0x70,0x68,0x69,0x03,0x63,0x68,0x69,0x03,0x70,0x73,0x69,0x05,0x6f,0x6d,0x65,0x67,0x61,0x0c,0x69,0x6f,0x74, +0x61,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0f,0x75,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x0c,0x6f,0x6d,0x69,0x63,0x72,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0c,0x75,0x70,0x73,0x69,0x6c,0x6f,0x6e,0x74,0x6f,0x6e,0x6f,0x73,0x0a,0x6f,0x6d,0x65,0x67,0x61,0x74,0x6f,0x6e,0x6f,0x73,0x07,0x75, +0x6e,0x69,0x30,0x34,0x30,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x31,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x34,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30, +0x35,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x36,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x36,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x36,0x31,0x07,0x75, +0x6e,0x69,0x30,0x34,0x30,0x44,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x36,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x34,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x31,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x31,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x31,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30, +0x32,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x31,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x34,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x36,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x37,0x09,0x61, +0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x32,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x31,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x33,0x09,0x61,0x66,0x69,0x69,0x31, +0x30,0x30,0x33,0x34,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x36,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x33,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x30, +0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x31,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x34,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x36,0x09,0x61,0x66,0x69, +0x69,0x31,0x30,0x30,0x34,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x34,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x36,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x36,0x36,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x36,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30, +0x36,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x36,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x34,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x35,0x09,0x61, +0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x36,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x31,0x09,0x61,0x66,0x69,0x69,0x31, +0x30,0x30,0x38,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x34,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x36,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x38, +0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x38,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x31,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x34,0x09,0x61,0x66,0x69, +0x69,0x31,0x30,0x30,0x39,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x36,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x37,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x37,0x31,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x39,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x30, +0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x31,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x32,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x34,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x35,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x36,0x09,0x61,0x66,0x69, +0x69,0x31,0x30,0x31,0x30,0x37,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x38,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x30,0x39,0x07,0x75,0x6e,0x69,0x30,0x34,0x35,0x44,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x31,0x30,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x31,0x39,0x33,0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x35,0x30, +0x09,0x61,0x66,0x69,0x69,0x31,0x30,0x30,0x39,0x38,0x06,0x57,0x67,0x72,0x61,0x76,0x65,0x06,0x77,0x67,0x72,0x61,0x76,0x65,0x06,0x57,0x61,0x63,0x75,0x74,0x65,0x06,0x77,0x61,0x63,0x75,0x74,0x65,0x09,0x57,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x09,0x77,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x06,0x59,0x67,0x72,0x61,0x76, +0x65,0x06,0x79,0x67,0x72,0x61,0x76,0x65,0x07,0x75,0x6e,0x69,0x32,0x30,0x31,0x30,0x07,0x75,0x6e,0x69,0x32,0x30,0x31,0x31,0x09,0x61,0x66,0x69,0x69,0x30,0x30,0x32,0x30,0x38,0x0d,0x75,0x6e,0x64,0x65,0x72,0x73,0x63,0x6f,0x72,0x65,0x64,0x62,0x6c,0x0d,0x71,0x75,0x6f,0x74,0x65,0x72,0x65,0x76,0x65,0x72,0x73,0x65,0x64,0x06,0x6d, +0x69,0x6e,0x75,0x74,0x65,0x06,0x73,0x65,0x63,0x6f,0x6e,0x64,0x09,0x65,0x78,0x63,0x6c,0x61,0x6d,0x64,0x62,0x6c,0x07,0x75,0x6e,0x69,0x32,0x30,0x33,0x45,0x07,0x75,0x6e,0x69,0x32,0x32,0x31,0x35,0x07,0x75,0x6e,0x69,0x32,0x30,0x37,0x46,0x04,0x6c,0x69,0x72,0x61,0x06,0x70,0x65,0x73,0x65,0x74,0x61,0x04,0x45,0x75,0x72,0x6f,0x09, +0x61,0x66,0x69,0x69,0x36,0x31,0x32,0x34,0x38,0x09,0x61,0x66,0x69,0x69,0x36,0x31,0x32,0x38,0x39,0x09,0x61,0x66,0x69,0x69,0x36,0x31,0x33,0x35,0x32,0x07,0x75,0x6e,0x69,0x32,0x31,0x32,0x36,0x09,0x65,0x73,0x74,0x69,0x6d,0x61,0x74,0x65,0x64,0x09,0x6f,0x6e,0x65,0x65,0x69,0x67,0x68,0x74,0x68,0x0c,0x74,0x68,0x72,0x65,0x65,0x65, +0x69,0x67,0x68,0x74,0x68,0x73,0x0b,0x66,0x69,0x76,0x65,0x65,0x69,0x67,0x68,0x74,0x68,0x73,0x0c,0x73,0x65,0x76,0x65,0x6e,0x65,0x69,0x67,0x68,0x74,0x68,0x73,0x09,0x61,0x72,0x72,0x6f,0x77,0x6c,0x65,0x66,0x74,0x07,0x61,0x72,0x72,0x6f,0x77,0x75,0x70,0x0a,0x61,0x72,0x72,0x6f,0x77,0x72,0x69,0x67,0x68,0x74,0x09,0x61,0x72,0x72, +0x6f,0x77,0x64,0x6f,0x77,0x6e,0x09,0x61,0x72,0x72,0x6f,0x77,0x62,0x6f,0x74,0x68,0x09,0x61,0x72,0x72,0x6f,0x77,0x75,0x70,0x64,0x6e,0x0c,0x61,0x72,0x72,0x6f,0x77,0x75,0x70,0x64,0x6e,0x62,0x73,0x65,0x07,0x75,0x6e,0x69,0x32,0x32,0x30,0x36,0x07,0x75,0x6e,0x69,0x32,0x32,0x31,0x39,0x0a,0x6f,0x72,0x74,0x68,0x6f,0x67,0x6f,0x6e, +0x61,0x6c,0x0c,0x69,0x6e,0x74,0x65,0x72,0x73,0x65,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x65,0x71,0x75,0x69,0x76,0x61,0x6c,0x65,0x6e,0x63,0x65,0x05,0x68,0x6f,0x75,0x73,0x65,0x0d,0x72,0x65,0x76,0x6c,0x6f,0x67,0x69,0x63,0x61,0x6c,0x6e,0x6f,0x74,0x0a,0x69,0x6e,0x74,0x65,0x67,0x72,0x61,0x6c,0x74,0x70,0x0a,0x69,0x6e,0x74,0x65,0x67, +0x72,0x61,0x6c,0x62,0x74,0x08,0x53,0x46,0x31,0x30,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x31,0x31,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x31,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x33,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x32,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x34,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x38, +0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x39,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x36,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x37,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x30,0x35,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x33,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x34,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x35,0x31,0x30, +0x30,0x30,0x30,0x08,0x53,0x46,0x35,0x32,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x33,0x39,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x32,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x31,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x35,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x35,0x30,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x39,0x30,0x30, +0x30,0x30,0x08,0x53,0x46,0x33,0x38,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x38,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x37,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x36,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x33,0x36,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x33,0x37,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x32,0x30,0x30,0x30, +0x30,0x08,0x53,0x46,0x31,0x39,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x30,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x32,0x33,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x37,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x38,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x31,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x35,0x30,0x30,0x30,0x30, +0x08,0x53,0x46,0x34,0x36,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x30,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x35,0x34,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x35,0x33,0x30,0x30,0x30,0x30,0x08,0x53,0x46,0x34,0x34,0x30,0x30,0x30,0x30,0x07,0x75,0x70,0x62,0x6c,0x6f,0x63,0x6b,0x07,0x64,0x6e,0x62,0x6c,0x6f,0x63,0x6b,0x05,0x62,0x6c, +0x6f,0x63,0x6b,0x07,0x6c,0x66,0x62,0x6c,0x6f,0x63,0x6b,0x07,0x72,0x74,0x62,0x6c,0x6f,0x63,0x6b,0x07,0x6c,0x74,0x73,0x68,0x61,0x64,0x65,0x05,0x73,0x68,0x61,0x64,0x65,0x07,0x64,0x6b,0x73,0x68,0x61,0x64,0x65,0x09,0x66,0x69,0x6c,0x6c,0x65,0x64,0x62,0x6f,0x78,0x06,0x48,0x32,0x32,0x30,0x37,0x33,0x06,0x48,0x31,0x38,0x35,0x34, +0x33,0x06,0x48,0x31,0x38,0x35,0x35,0x31,0x0a,0x66,0x69,0x6c,0x6c,0x65,0x64,0x72,0x65,0x63,0x74,0x07,0x74,0x72,0x69,0x61,0x67,0x75,0x70,0x07,0x74,0x72,0x69,0x61,0x67,0x72,0x74,0x07,0x74,0x72,0x69,0x61,0x67,0x64,0x6e,0x07,0x74,0x72,0x69,0x61,0x67,0x6c,0x66,0x06,0x63,0x69,0x72,0x63,0x6c,0x65,0x06,0x48,0x31,0x38,0x35,0x33, +0x33,0x09,0x69,0x6e,0x76,0x62,0x75,0x6c,0x6c,0x65,0x74,0x09,0x69,0x6e,0x76,0x63,0x69,0x72,0x63,0x6c,0x65,0x0a,0x6f,0x70,0x65,0x6e,0x62,0x75,0x6c,0x6c,0x65,0x74,0x09,0x73,0x6d,0x69,0x6c,0x65,0x66,0x61,0x63,0x65,0x0c,0x69,0x6e,0x76,0x73,0x6d,0x69,0x6c,0x65,0x66,0x61,0x63,0x65,0x03,0x73,0x75,0x6e,0x06,0x66,0x65,0x6d,0x61, +0x6c,0x65,0x04,0x6d,0x61,0x6c,0x65,0x05,0x73,0x70,0x61,0x64,0x65,0x04,0x63,0x6c,0x75,0x62,0x05,0x68,0x65,0x61,0x72,0x74,0x07,0x64,0x69,0x61,0x6d,0x6f,0x6e,0x64,0x0b,0x6d,0x75,0x73,0x69,0x63,0x61,0x6c,0x6e,0x6f,0x74,0x65,0x0e,0x6d,0x75,0x73,0x69,0x63,0x61,0x6c,0x6e,0x6f,0x74,0x65,0x64,0x62,0x6c,0x07,0x75,0x6e,0x69,0x46, +0x42,0x30,0x31,0x07,0x75,0x6e,0x69,0x46,0x42,0x30,0x32,0x10,0x75,0x6e,0x64,0x65,0x72,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x0d,0x63,0x79,0x72,0x69,0x6c,0x6c,0x69,0x63,0x62,0x72,0x65,0x76,0x65,0x10,0x63,0x61,0x72,0x6f,0x6e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x11,0x63,0x6f,0x6d,0x6d, +0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x72,0x6f,0x74,0x61,0x74,0x65,0x08,0x64,0x6f,0x74,0x6c,0x65,0x73,0x73,0x6a,0x0b,0x6f,0x6e,0x65,0x66,0x72,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0b,0x74,0x77,0x6f,0x66,0x72,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0d,0x74,0x68,0x72,0x65,0x65,0x66,0x72,0x61,0x63,0x69,0x74,0x6f,0x6e,0x0c,0x66,0x6f,0x75, +0x72,0x66,0x72,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0c,0x66,0x69,0x76,0x65,0x66,0x72,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0d,0x73,0x65,0x76,0x65,0x6e,0x66,0x72,0x61,0x63,0x74,0x69,0x6f,0x6e,0x0d,0x65,0x69,0x67,0x68,0x74,0x66,0x72,0x61,0x63,0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x08,0x00,0x02,0x00,0x11,0x00,0x01, +0xff,0xff,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x18,0x00,0x20,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x01,0x02,0xa0,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0xc9,0x89,0x6f,0x31,0x00,0x00,0x00,0x00,0xbd,0x76,0x89,0x24, +0x00,0x00,0x00,0x00,0xca,0x9f,0x1d,0x63, +}; + +read_only global String8 df_g_default_code_font_bytes = {df_g_default_code_font_bytes__data, sizeof(df_g_default_code_font_bytes__data)}; + +#endif // DF_GFX_META_H diff --git a/src/draw/draw.c b/src/draw/draw.c new file mode 100644 index 00000000..fb389b7f --- /dev/null +++ b/src/draw/draw.c @@ -0,0 +1,679 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Generated Code + +#define D_StackPushImpl(name_upper, name_lower, type, val) \ +D_Bucket *bucket = d_top_bucket();\ +type old_val = bucket->top_##name_lower->v;\ +D_##name_upper##Node *node = push_array(d_thread_ctx->arena, D_##name_upper##Node, 1);\ +node->v = (val);\ +SLLStackPush(bucket->top_##name_lower, node);\ +bucket->stack_gen += 1;\ +return old_val + +#define D_StackPopImpl(name_upper, name_lower, type) \ +D_Bucket *bucket = d_top_bucket();\ +type popped_val = bucket->top_##name_lower->v;\ +SLLStackPop(bucket->top_##name_lower);\ +bucket->stack_gen += 1;\ +return popped_val + +#define D_StackTopImpl(name_upper, name_lower, type) \ +D_Bucket *bucket = d_top_bucket();\ +type top_val = bucket->top_##name_lower->v;\ +return top_val + +#include "generated/draw.meta.c" + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +d_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +//////////////////////////////// +//~ rjf: Fancy String Type Functions + +internal void +d_fancy_string_list_push(Arena *arena, D_FancyStringList *list, D_FancyString *str) +{ + D_FancyStringNode *n = push_array_no_zero(arena, D_FancyStringNode, 1); + MemoryCopyStruct(&n->v, str); + SLLQueuePush(list->first, list->last, n); + list->node_count += 1; + list->total_size += str->string.size; +} + +internal String8 +d_string_from_fancy_string_list(Arena *arena, D_FancyStringList *list) +{ + String8 result = {0}; + result.size = list->total_size; + result.str = push_array_no_zero(arena, U8, result.size); + U64 idx = 0; + for(D_FancyStringNode *n = list->first; n != 0; n = n->next) + { + MemoryCopy(result.str+idx, n->v.string.str, n->v.string.size); + idx += n->v.string.size; + } + return result; +} + +internal D_FancyRunList +d_fancy_run_list_from_fancy_string_list(Arena *arena, D_FancyStringList *strs) +{ + ProfBeginFunction(); + D_FancyRunList run_list = {0}; + for(D_FancyStringNode *n = strs->first; n != 0; n = n->next) + { + D_FancyRunNode *dst_n = push_array(arena, D_FancyRunNode, 1); + dst_n->v.run = f_push_run_from_string(arena, n->v.font, n->v.size, 0, n->v.string); + dst_n->v.color = n->v.color; + dst_n->v.underline_thickness = n->v.underline_thickness; + dst_n->v.strikethrough_thickness = n->v.strikethrough_thickness; + SLLQueuePush(run_list.first, run_list.last, dst_n); + run_list.node_count += 1; + run_list.dim.x += dst_n->v.run.dim.x; + run_list.dim.y = Max(run_list.dim.y, dst_n->v.run.dim.y); + } + ProfEnd(); + return run_list; +} + +//////////////////////////////// +//~ rjf: Top-Level API +// +// (Frame boundaries) + +internal void +d_begin_frame(void) +{ + if(d_thread_ctx == 0) + { + Arena *arena = arena_alloc__sized(GB(64), MB(8)); + d_thread_ctx = push_array(arena, D_ThreadCtx, 1); + d_thread_ctx->arena = arena; + d_thread_ctx->arena_frame_start_pos = arena_pos(arena); + } + arena_pop_to(d_thread_ctx->arena, d_thread_ctx->arena_frame_start_pos); + d_thread_ctx->free_bucket_selection = 0; + d_thread_ctx->top_bucket = 0; +} + +internal void +d_submit_bucket(OS_Handle os_window, R_Handle r_window, D_Bucket *bucket) +{ + r_window_submit(os_window, r_window, &bucket->passes); +} + +//////////////////////////////// +//~ rjf: Bucket Construction & Selection API +// +// (Bucket: Handle to sequence of many render passes, constructed by this layer) + +internal D_Bucket * +d_bucket_make(void) +{ + D_Bucket *bucket = push_array(d_thread_ctx->arena, D_Bucket, 1); + D_BucketStackInits(bucket); + return bucket; +} + +internal void +d_push_bucket(D_Bucket *bucket) +{ + D_BucketSelectionNode *node = d_thread_ctx->free_bucket_selection; + if(node) + { + SLLStackPop(d_thread_ctx->free_bucket_selection); + } + else + { + node = push_array(d_thread_ctx->arena, D_BucketSelectionNode, 1); + } + SLLStackPush(d_thread_ctx->top_bucket, node); + node->bucket = bucket; +} + +internal void +d_pop_bucket(void) +{ + D_BucketSelectionNode *node = d_thread_ctx->top_bucket; + SLLStackPop(d_thread_ctx->top_bucket); + SLLStackPush(d_thread_ctx->free_bucket_selection, node); +} + +internal D_Bucket * +d_top_bucket(void) +{ + D_Bucket *bucket = 0; + if(d_thread_ctx->top_bucket != 0) + { + bucket = d_thread_ctx->top_bucket->bucket; + } + return bucket; +} + +//////////////////////////////// +//~ rjf: Bucket Stacks +// +// (Pushing/popping implicit draw parameters) + +// NOTE(rjf): (The implementation of the push/pop/top functions is auto-generated) + +//////////////////////////////// +//~ rjf: Draw Calls +// +// (Apply to the calling thread's currently selected bucket) + +//- rjf: rectangles + +internal inline R_Rect2DInst * +d_rect(Rng2F32 dst, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness) +{ + Arena *arena = d_thread_ctx->arena; + D_Bucket *bucket = d_top_bucket(); + R_Pass *pass = r_pass_from_kind(arena, &bucket->passes, R_PassKind_UI); + R_PassParams_UI *params = pass->params_ui; + R_BatchGroup2DList *rects = ¶ms->rects; + R_BatchGroup2DNode *node = rects->last; + if(node == 0 || bucket->stack_gen != bucket->last_cmd_stack_gen) + { + node = push_array(arena, R_BatchGroup2DNode, 1); + SLLQueuePush(rects->first, rects->last, node); + rects->count += 1; + node->batches = r_batch_list_make(sizeof(R_Rect2DInst)); + node->params.tex = r_handle_zero(); + node->params.tex_sample_kind = bucket->top_tex2d_sample_kind->v; + node->params.xform = bucket->top_xform2d->v; + node->params.clip = bucket->top_clip->v; + node->params.transparency = bucket->top_transparency->v; + } + R_Rect2DInst *inst = (R_Rect2DInst *)r_batch_list_push_inst(arena, &node->batches, 256); + inst->dst = dst; + inst->src = r2f32p(0, 0, 0, 0); + inst->colors[Corner_00] = color; + inst->colors[Corner_01] = color; + inst->colors[Corner_10] = color; + inst->colors[Corner_11] = color; + inst->corner_radii[Corner_00] = corner_radius; + inst->corner_radii[Corner_01] = corner_radius; + inst->corner_radii[Corner_10] = corner_radius; + inst->corner_radii[Corner_11] = corner_radius; + inst->border_thickness = border_thickness; + inst->edge_softness = edge_softness; + inst->white_texture_override = 1.f; + bucket->last_cmd_stack_gen = bucket->stack_gen; + return inst; +} + +//- rjf: images + +internal inline R_Rect2DInst * +d_img(Rng2F32 dst, Rng2F32 src, R_Handle texture, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness) +{ + Arena *arena = d_thread_ctx->arena; + D_Bucket *bucket = d_top_bucket(); + R_Pass *pass = r_pass_from_kind(arena, &bucket->passes, R_PassKind_UI); + R_PassParams_UI *params = pass->params_ui; + R_BatchGroup2DList *rects = ¶ms->rects; + R_BatchGroup2DNode *node = rects->last; + if(node != 0 && bucket->stack_gen == bucket->last_cmd_stack_gen && r_handle_match(node->params.tex, r_handle_zero())) + { + node->params.tex = texture; + } + else if(node == 0 || bucket->stack_gen != bucket->last_cmd_stack_gen || !r_handle_match(texture, node->params.tex)) + { + node = push_array(arena, R_BatchGroup2DNode, 1); + SLLQueuePush(rects->first, rects->last, node); + rects->count += 1; + node->batches = r_batch_list_make(sizeof(R_Rect2DInst)); + node->params.tex = texture; + node->params.tex_sample_kind = bucket->top_tex2d_sample_kind->v; + node->params.xform = bucket->top_xform2d->v; + node->params.clip = bucket->top_clip->v; + node->params.transparency = bucket->top_transparency->v; + } + R_Rect2DInst *inst = (R_Rect2DInst *)r_batch_list_push_inst(arena, &node->batches, 256); + inst->dst = dst; + inst->src = src; + inst->colors[Corner_00] = color; + inst->colors[Corner_01] = color; + inst->colors[Corner_10] = color; + inst->colors[Corner_11] = color; + inst->corner_radii[Corner_00] = corner_radius; + inst->corner_radii[Corner_01] = corner_radius; + inst->corner_radii[Corner_10] = corner_radius; + inst->corner_radii[Corner_11] = corner_radius; + inst->border_thickness = border_thickness; + inst->edge_softness = edge_softness; + inst->white_texture_override = 0.f; + bucket->last_cmd_stack_gen = bucket->stack_gen; + return inst; +} + +//- rjf: blurs + +internal R_PassParams_Blur * +d_blur(Rng2F32 rect, F32 blur_size, F32 corner_radius) +{ + Arena *arena = d_thread_ctx->arena; + D_Bucket *bucket = d_top_bucket(); + R_Pass *pass = r_pass_from_kind(arena, &bucket->passes, R_PassKind_Blur); + R_PassParams_Blur *params = pass->params_blur; + params->rect = rect; + params->blur_size = blur_size; + params->corner_radii[Corner_00] = corner_radius; + params->corner_radii[Corner_01] = corner_radius; + params->corner_radii[Corner_10] = corner_radius; + params->corner_radii[Corner_11] = corner_radius; + return params; +} + +//- rjf: 3d rendering pass params + +internal R_PassParams_Geo3D * +d_geo3d_begin(Rng2F32 viewport, Mat4x4F32 view, Mat4x4F32 projection) +{ + Arena *arena = d_thread_ctx->arena; + D_Bucket *bucket = d_top_bucket(); + R_Pass *pass = r_pass_from_kind(arena, &bucket->passes, R_PassKind_Geo3D); + R_PassParams_Geo3D *params = pass->params_geo3d; + params->viewport = viewport; + params->view = view; + params->projection = projection; + return params; +} + +//- rjf: meshes + +internal R_Mesh3DInst * +d_mesh(R_Handle mesh_vertices, R_Handle mesh_indices, R_GeoTopologyKind mesh_geo_topology, R_GeoVertexFlags mesh_geo_vertex_flags, R_Handle albedo_tex, Mat4x4F32 inst_xform) +{ + Arena *arena = d_thread_ctx->arena; + D_Bucket *bucket = d_top_bucket(); + R_Pass *pass = r_pass_from_kind(arena, &bucket->passes, R_PassKind_Geo3D); + R_PassParams_Geo3D *params = pass->params_geo3d; + + // rjf: mesh batch map not made yet -> make + if(params->mesh_batches.slots_count == 0) + { + params->mesh_batches.slots_count = 64; + params->mesh_batches.slots = push_array(arena, R_BatchGroup3DMapNode *, params->mesh_batches.slots_count); + } + + // rjf: hash batch group 3d params + U64 hash = 0; + U64 slot_idx = 0; + { + U64 buffer[] = + { + mesh_vertices.u64[0], + mesh_vertices.u64[1], + mesh_indices.u64[0], + mesh_indices.u64[1], + (U64)mesh_geo_topology, + (U64)mesh_geo_vertex_flags, + albedo_tex.u64[0], + albedo_tex.u64[1], + (U64)d_top_tex2d_sample_kind(), + }; + hash = d_hash_from_string(str8((U8 *)buffer, sizeof(buffer))); + slot_idx = hash%params->mesh_batches.slots_count; + } + + // rjf: map hash -> existing batch group node + R_BatchGroup3DMapNode *node = 0; + { + for(R_BatchGroup3DMapNode *n = params->mesh_batches.slots[slot_idx]; n != 0; n = n->next) + { + if(n->hash == hash) + { + node = n; + break; + } + } + } + + // rjf: no batch group node? -> make one + if(node == 0) + { + node = push_array(arena, R_BatchGroup3DMapNode, 1); + SLLStackPush(params->mesh_batches.slots[slot_idx], node); + node->hash = hash; + node->batches = r_batch_list_make(sizeof(R_Mesh3DInst)); + node->params.mesh_vertices = mesh_vertices; + node->params.mesh_indices = mesh_indices; + node->params.mesh_geo_topology = mesh_geo_topology; + node->params.mesh_geo_vertex_flags = mesh_geo_vertex_flags; + node->params.albedo_tex = albedo_tex; + node->params.albedo_tex_sample_kind = d_top_tex2d_sample_kind(); + node->params.xform = mat_4x4f32(1.f); + } + + // rjf: push new instance to batch group + R_Mesh3DInst *inst = (R_Mesh3DInst *)r_batch_list_push_inst(arena, &node->batches, 256); + inst->xform = inst_xform; + return inst; +} + +//- rjf: collating one pre-prepped bucket into parent bucket + +internal void +d_sub_bucket(D_Bucket *bucket) +{ + Arena *arena = d_thread_ctx->arena; + D_Bucket *src = bucket; + D_Bucket *dst = d_top_bucket(); + Rng2F32 dst_clip = d_top_clip(); + B32 dst_clip_is_set = !(dst_clip.x0 == 0 && dst_clip.x1 == 0 && + dst_clip.y0 == 0 && dst_clip.y1 == 0); + for(R_PassNode *n = src->passes.first; n != 0; n = n->next) + { + R_Pass *src_pass = &n->v; + R_Pass *dst_pass = r_pass_from_kind(arena, &dst->passes, src_pass->kind); + switch(dst_pass->kind) + { + default:{dst_pass->params = src_pass->params;}break; + case R_PassKind_UI: + { + R_PassParams_UI *src_ui = src_pass->params_ui; + R_PassParams_UI *dst_ui = dst_pass->params_ui; + for(R_BatchGroup2DNode *src_group_n = src_ui->rects.first; + src_group_n != 0; + src_group_n = src_group_n->next) + { + R_BatchGroup2DNode *dst_group_n = push_array(arena, R_BatchGroup2DNode, 1); + SLLQueuePush(dst_ui->rects.first, dst_ui->rects.last, dst_group_n); + dst_ui->rects.count += 1; + MemoryCopyStruct(&dst_group_n->params, &src_group_n->params); + dst_group_n->batches = src_group_n->batches; + dst_group_n->params.xform = d_top_xform2d(); + if(dst_clip_is_set) + { + B32 clip_is_set = !(dst_group_n->params.clip.x0 == 0 && + dst_group_n->params.clip.y0 == 0 && + dst_group_n->params.clip.x1 == 0 && + dst_group_n->params.clip.y1 == 0); + dst_group_n->params.clip = clip_is_set ? intersect_2f32(dst_clip, dst_group_n->params.clip) : dst_clip; + } + } + }break; + } + } +} + +//////////////////////////////// +//~ rjf: Draw Call Helpers + +//- rjf: text + +internal void +d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run trailer_run) +{ + ProfBeginFunction(); + + // rjf: grab total advance + F32 run_list_total_advance = list->dim.x; + + // rjf: total advance > max? -> enable trailer + B32 trailer_enabled = (run_list_total_advance >= max_x && trailer_run.dim.x < max_x); + + // rjf: draw runs + F32 advance = 0; + B32 trailer_found = 0; + Vec4F32 last_color = {0}; + for(D_FancyRunNode *n = list->first; n != 0; n = n->next) + { + D_FancyRun *fr = &n->v; + F_Piece *piece_first = fr->run.pieces.v; + F_Piece *piece_opl = piece_first + fr->run.pieces.count; + F32 pre_advance = advance; + last_color = fr->color; + for(F_Piece *piece = piece_first; + piece < piece_opl; + piece += 1) + { + if(trailer_enabled && advance + piece->advance >= (max_x - trailer_run.dim.x)) + { + trailer_found = 1; + break; + } + if(!trailer_enabled && advance + piece->advance >= max_x) + { + goto end_draw; + } + R_Handle texture = piece->texture; + Rng2F32 src = r2f32p((F32)piece->subrect.x0, (F32)piece->subrect.y0, (F32)piece->subrect.x1, (F32)piece->subrect.y1); + Vec2F32 size = dim_2f32(src); + Rng2F32 dst = r2f32p(p.x + piece->offset.x + advance, + p.y + piece->offset.y, + p.x + piece->offset.x + advance + size.x, + p.y + piece->offset.y + size.y); + if(!r_handle_match(texture, r_handle_zero())) + { + d_img(dst, src, texture, fr->color, 0, 0, 0); + } + advance += piece->advance; + } + if(fr->underline_thickness > 0) + { + d_rect(r2f32p(p.x+pre_advance, p.y+fr->run.descent-fr->underline_thickness/2, p.x+advance, p.y+fr->run.descent+fr->underline_thickness/2), fr->color, 0, 0, 1.f); + } + if(fr->strikethrough_thickness > 0) + { + d_rect(r2f32p(p.x+pre_advance, p.y+fr->run.descent - fr->run.ascent/2, p.x+advance, p.y+fr->run.descent - fr->run.ascent/2 + fr->strikethrough_thickness), fr->color, 0, 0, 1.f); + } + if(trailer_found) + { + break; + } + } + end_draw:; + + // rjf: draw trailer + if(trailer_found) + { + F_Piece *piece_first = trailer_run.pieces.v; + F_Piece *piece_opl = piece_first + trailer_run.pieces.count; + F32 pre_advance = advance; + Vec4F32 trailer_piece_color = last_color; + for(F_Piece *piece = piece_first; + piece < piece_opl; + piece += 1) + { + R_Handle texture = piece->texture; + Rng2F32 src = r2f32p((F32)piece->subrect.x0, (F32)piece->subrect.y0, (F32)piece->subrect.x1, (F32)piece->subrect.y1); + Vec2F32 size = dim_2f32(src); + Rng2F32 dst = r2f32p(p.x + piece->offset.x + advance, + p.y + piece->offset.y, + p.x + piece->offset.x + advance + size.x, + p.y + piece->offset.y + size.y); + if(!r_handle_match(texture, r_handle_zero())) + { + d_img(dst, src, texture, trailer_piece_color, 0, 0, 0); + trailer_piece_color.w *= 0.5f; + } + advance += piece->advance; + } + } + + ProfEnd(); +} + +internal void +d_text_run(Vec2F32 p, Vec4F32 color, F_Run run) +{ + F32 advance = 0; + F_Piece *piece_first = run.pieces.v; + F_Piece *piece_opl = piece_first + run.pieces.count; + for(F_Piece *piece = piece_first; + piece < piece_opl; + piece += 1) + { + R_Handle texture = piece->texture; + Rng2F32 src = r2f32p((F32)piece->subrect.x0, (F32)piece->subrect.y0, (F32)piece->subrect.x1, (F32)piece->subrect.y1); + Vec2F32 size = dim_2f32(src); + Rng2F32 dst = r2f32p(p.x + piece->offset.x + advance, + p.y + piece->offset.y, + p.x + piece->offset.x + advance + size.x, + p.y + piece->offset.y + size.y); + if(!r_handle_match(texture, r_handle_zero())) + { + d_img(dst, src, texture, color, 0, 0, 0); + } + advance += piece->advance; + } +} + +internal void +d_truncated_text_run(Vec2F32 p, Vec4F32 color, F32 max_x, F_Run text_run, F_Run trailer_run) +{ + B32 truncated = 0; + B32 set_truncation = 0; + F32 truncation_p = p.x; + F32 max_x_minus_ellipses = max_x - trailer_run.dim.x; + F32 available_space = max_x - p.x; + + // rjf: find last piece before truncation + B32 truncation_needed = 0; + F_Piece *last_piece_before_truncation = 0; + F32 truncation_offset = 0; + if(available_space > text_run.dim.x || available_space > trailer_run.dim.x) + { + F32 advance = 0; + F_Piece *text_run_first = text_run.pieces.v; + F_Piece *text_run_opl = text_run_first + text_run.pieces.count; + for(F_Piece *piece = text_run_first; + piece < text_run_opl; + piece += 1) + { + Rng2F32 src = r2f32p((F32)piece->subrect.x0, (F32)piece->subrect.y0, (F32)piece->subrect.x1, (F32)piece->subrect.y1); + Vec2F32 size = dim_2f32(src); + Rng2F32 dst = r2f32p(p.x + piece->offset.x + advance, + p.y + piece->offset.y, + p.x + piece->offset.x + advance + size.x, + p.y + piece->offset.y + size.y); + advance += piece->advance; + if(last_piece_before_truncation == 0 && p.x + advance > max_x_minus_ellipses) + { + truncation_offset = advance - piece->advance; + last_piece_before_truncation = piece; + } + if(p.x + advance > max_x) + { + truncation_needed = 1; + } + } + } + + // rjf: draw pieces + if(available_space > text_run.dim.x || available_space > trailer_run.dim.x) + { + F32 advance = 0; + F_Piece *text_run_first = text_run.pieces.v; + F_Piece *text_run_opl = text_run_first + text_run.pieces.count; + for(F_Piece *piece = text_run_first; + piece < text_run_opl; + piece += 1) + { + if(truncation_needed && piece == last_piece_before_truncation) + { + break; + } + R_Handle texture = piece->texture; + Rng2F32 src = r2f32p((F32)piece->subrect.x0, (F32)piece->subrect.y0, (F32)piece->subrect.x1, (F32)piece->subrect.y1); + Vec2F32 size = dim_2f32(src); + Rng2F32 dst = r2f32p(p.x + piece->offset.x + advance, + p.y + piece->offset.y, + p.x + piece->offset.x + advance + size.x, + p.y + piece->offset.y + size.y); + if(!r_handle_match(texture, r_handle_zero())) + { + d_img(dst, src, texture, color, 0, 0, 0); + } + advance += piece->advance; + } + } + + // rjf: draw truncation ellipses + if(truncation_needed && last_piece_before_truncation != 0) + { + Vec2F32 ellipses_p = {p.x + truncation_offset, p.y}; + Vec4F32 ellipses_color = color; + F32 advance = 0; + F_Piece *trailer_run_first = trailer_run.pieces.v; + F_Piece *trailer_run_opl = trailer_run_first + trailer_run.pieces.count; + for(F_Piece *piece = trailer_run_first; + piece < trailer_run_opl; + piece += 1) + { + R_Handle texture = piece->texture; + Rng2F32 src = r2f32p((F32)piece->subrect.x0, (F32)piece->subrect.y0, (F32)piece->subrect.x1, (F32)piece->subrect.y1); + Vec2F32 size = dim_2f32(src); + Rng2F32 dst = r2f32p(ellipses_p.x + piece->offset.x + advance, + ellipses_p.y + piece->offset.y, + ellipses_p.x + piece->offset.x + advance + size.x, + ellipses_p.y + piece->offset.y + size.y); + if(!r_handle_match(texture, r_handle_zero())) + { + d_img(dst, src, texture, ellipses_color, 0, 0, 0); + } + ellipses_color.w *= 0.5f; + advance += piece->advance; + } + } +} + +internal void +d_text(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, String8 string) +{ + Temp scratch = scratch_begin(0, 0); + F_Run run = f_push_run_from_string(scratch.arena, font, size, 0, string); + d_text_run(p, color, run); + scratch_end(scratch); +} + +internal void +d_textf(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + d_text(font, size, p, color, string); + scratch_end(scratch); +} + +internal void +d_truncated_text(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, F32 max_x, String8 string) +{ + Temp scratch = scratch_begin(0, 0); + F_Run run = f_push_run_from_string(scratch.arena, font, size, 0, string); + F_Run ellipses_run = f_push_run_from_string(scratch.arena, font, size, 0, str8_lit("...")); + d_truncated_text_run(p, color, max_x, run, ellipses_run); + scratch_end(scratch); +} + +internal void +d_truncated_textf(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, F32 max_x, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8f(scratch.arena, fmt, args); + d_truncated_text(font, size, p, color, max_x, string); + va_end(args); + scratch_end(scratch); +} diff --git a/src/draw/draw.h b/src/draw/draw.h new file mode 100644 index 00000000..06178bab --- /dev/null +++ b/src/draw/draw.h @@ -0,0 +1,192 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DRAW_H +#define DRAW_H + +//////////////////////////////// +//~ rjf: Fancy String Types + +typedef struct D_FancyString D_FancyString; +struct D_FancyString +{ + F_Tag font; + String8 string; + Vec4F32 color; + F32 size; + F32 underline_thickness; + F32 strikethrough_thickness; +}; + +typedef struct D_FancyStringNode D_FancyStringNode; +struct D_FancyStringNode +{ + D_FancyStringNode *next; + D_FancyString v; +}; + +typedef struct D_FancyStringList D_FancyStringList; +struct D_FancyStringList +{ + D_FancyStringNode *first; + D_FancyStringNode *last; + U64 node_count; + U64 total_size; +}; + +typedef struct D_FancyRun D_FancyRun; +struct D_FancyRun +{ + F_Run run; + Vec4F32 color; + F32 underline_thickness; + F32 strikethrough_thickness; +}; + +typedef struct D_FancyRunNode D_FancyRunNode; +struct D_FancyRunNode +{ + D_FancyRunNode *next; + D_FancyRun v; +}; + +typedef struct D_FancyRunList D_FancyRunList; +struct D_FancyRunList +{ + D_FancyRunNode *first; + D_FancyRunNode *last; + U64 node_count; + Vec2F32 dim; +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/draw.meta.h" + +//////////////////////////////// +//~ rjf: Draw Bucket Types + +typedef struct D_Bucket D_Bucket; +struct D_Bucket +{ + R_PassList passes; + U64 stack_gen; + U64 last_cmd_stack_gen; + D_BucketStackDecls; +}; + +//////////////////////////////// +//~ rjf: Thread Context + +typedef struct D_BucketSelectionNode D_BucketSelectionNode; +struct D_BucketSelectionNode +{ + D_BucketSelectionNode *next; + D_Bucket *bucket; +}; + +typedef struct D_ThreadCtx D_ThreadCtx; +struct D_ThreadCtx +{ + Arena *arena; + U64 arena_frame_start_pos; + D_BucketSelectionNode *top_bucket; + D_BucketSelectionNode *free_bucket_selection; +}; + +//////////////////////////////// +//~ rjf: Globals + +thread_static D_ThreadCtx *d_thread_ctx = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 d_hash_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Fancy String Type Functions + +internal void d_fancy_string_list_push(Arena *arena, D_FancyStringList *list, D_FancyString *str); +internal String8 d_string_from_fancy_string_list(Arena *arena, D_FancyStringList *list); +internal D_FancyRunList d_fancy_run_list_from_fancy_string_list(Arena *arena, D_FancyStringList *strs); + +//////////////////////////////// +//~ rjf: Top-Level API +// +// (Frame boundaries & bucket submission) + +internal void d_begin_frame(void); +internal void d_submit_bucket(OS_Handle os_window, R_Handle r_window, D_Bucket *bucket); + +//////////////////////////////// +//~ rjf: Bucket Construction & Selection API +// +// (Bucket: Handle to sequence of many render passes, constructed by this layer) + +internal D_Bucket *d_bucket_make(void); +internal void d_push_bucket(D_Bucket *bucket); +internal void d_pop_bucket(void); +internal D_Bucket *d_top_bucket(void); +#define D_BucketScope(b) DeferLoop(d_push_bucket(b), d_pop_bucket()) + +//////////////////////////////// +//~ rjf: Bucket Stacks +// +// (Pushing/popping implicit draw parameters) + +internal R_Tex2DSampleKind d_push_tex2d_sample_kind(R_Tex2DSampleKind v); +internal Mat3x3F32 d_push_xform2d(Mat3x3F32 v); +internal Rng2F32 d_push_clip(Rng2F32 v); +internal F32 d_push_transparency(F32 v); +internal R_Tex2DSampleKind d_pop_tex2d_sample_kind(void); +internal Mat3x3F32 d_pop_xform2d(void); +internal Rng2F32 d_pop_clip(void); +internal F32 d_pop_transparency(void); +internal R_Tex2DSampleKind d_top_tex2d_sample_kind(void); +internal Mat3x3F32 d_top_xform2d(void); +internal Rng2F32 d_top_clip(void); +internal F32 d_top_transparency(void); + +#define D_Tex2DSampleKindScope(v) DeferLoop(d_push_tex2d_sample_kind(v), d_pop_tex2d_sample_kind()) +#define D_XForm2DScope(v) DeferLoop(d_push_xform2d(v), d_pop_xform2d()) +#define D_ClipScope(v) DeferLoop(d_push_clip(v), d_pop_clip()) +#define D_TransparencyScope(v) DeferLoop(d_push_transparency(v), d_pop_transparency()) + +//////////////////////////////// +//~ rjf: Core Draw Calls +// +// (Apply to the calling thread's currently selected bucket) + +//- rjf: rectangles +internal inline R_Rect2DInst *d_rect(Rng2F32 dst, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness); + +//- rjf: images +internal inline R_Rect2DInst *d_img(Rng2F32 dst, Rng2F32 src, R_Handle texture, Vec4F32 color, F32 corner_radius, F32 border_thickness, F32 edge_softness); + +//- rjf: blurs +internal R_PassParams_Blur *d_blur(Rng2F32 rect, F32 blur_size, F32 corner_radius); + +//- rjf: 3d rendering pass params +internal R_PassParams_Geo3D *d_geo3d_begin(Rng2F32 viewport, Mat4x4F32 view, Mat4x4F32 projection); + +//- rjf: meshes +internal R_Mesh3DInst *d_mesh(R_Handle mesh_vertices, R_Handle mesh_indices, R_GeoTopologyKind mesh_geo_topology, R_GeoVertexFlags mesh_geo_vertex_flags, R_Handle albedo_tex, Mat4x4F32 inst_xform); + +//- rjf: collating one pre-prepped bucket into parent bucket +internal void d_sub_bucket(D_Bucket *bucket); + +//////////////////////////////// +//~ rjf: Draw Call Helpers + +//- rjf: text +internal void d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run trailer_run); +internal void d_text_run(Vec2F32 p, Vec4F32 color, F_Run run); +internal void d_truncated_text_run(Vec2F32 p, Vec4F32 color, F32 max_x, F_Run text_run, F_Run trailer_run); +internal void d_text(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, String8 string); +internal void d_textf(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, char *fmt, ...); +internal void d_truncated_text(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, F32 max_x, String8 string); +internal void d_truncated_textf(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, F32 max_x, char *fmt, ...); + +#endif // DRAW_H diff --git a/src/draw/draw.mc b/src/draw/draw.mc new file mode 100644 index 00000000..bba9861e --- /dev/null +++ b/src/draw/draw.mc @@ -0,0 +1,58 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +@table(name, name_lower, type, default_init) +D_StackTable: +{ + {Tex2DSampleKind tex2d_sample_kind R_Tex2DSampleKind `R_Tex2DSampleKind_Nearest` } + {XForm2D xform2d Mat3x3F32 `{1, 0, 0, 0, 1, 0, 0, 0, 1}` } + {Clip clip Rng2F32 `{0}` } + {Transparency transparency F32 `0` } +} + +@table_gen +{ + @expand(D_StackTable a) `typedef struct D_$(a.name)Node D_$(a.name)Node; struct D_$(a.name)Node {D_$(a.name)Node *next; $(a.type) v;};`; +} + +@table_gen +{ + `#define D_BucketStackDecls struct{\\`; + @expand(D_StackTable a) `D_$(a.name)Node *top_$(a.name_lower);\\`; + `}`; +} + +@table_gen +{ + @expand(D_StackTable a) `read_only global D_$(a.name)Node d_nil_$(a.name_lower) = {0, $(a.default_init)};`; +} + +@table_gen +{ + `#define D_BucketStackInits(b) do{\\`; + @expand(D_StackTable a) `(b)->top_$(a.name_lower) = &d_nil_$(a.name_lower);\\`; + `}while(0)`; +} + +@table_gen +{ + `#if 0`; + @expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v);`; + @expand(D_StackTable a) `internal $(a.type) $(=>35) d_pop_$(a.name_lower)(void);`; + @expand(D_StackTable a) `internal $(a.type) $(=>35) d_top_$(a.name_lower)(void);`; + `#endif`; +} + +@table_gen @c_file +{ + @expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v) {D_StackPushImpl($(a.name), $(a.name_lower), $(a.type), v);}`; + @expand(D_StackTable a) `internal $(a.type) $(=>35) d_pop_$(a.name_lower)(void) {D_StackPopImpl($(a.name), $(a.name_lower), $(a.type));}`; + @expand(D_StackTable a) `internal $(a.type) $(=>35) d_top_$(a.name_lower)(void) {D_StackTopImpl($(a.name), $(a.name_lower), $(a.type));}`; +} + +@table_gen +{ + `#if 0`; + @expand(D_StackTable a) `#define D_$(a.name)Scope(v) $(=>35) DeferLoop(d_push_$(a.name_lower)(v), d_pop_$(a.name_lower)())`; + `#endif`; +} diff --git a/src/draw/generated/draw.meta.c b/src/draw/generated/draw.meta.c new file mode 100644 index 00000000..50ed1be1 --- /dev/null +++ b/src/draw/generated/draw.meta.c @@ -0,0 +1,17 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +internal R_Tex2DSampleKind d_push_tex2d_sample_kind(R_Tex2DSampleKind v) {D_StackPushImpl(Tex2DSampleKind, tex2d_sample_kind, R_Tex2DSampleKind, v);} +internal Mat3x3F32 d_push_xform2d(Mat3x3F32 v) {D_StackPushImpl(XForm2D, xform2d, Mat3x3F32, v);} +internal Rng2F32 d_push_clip(Rng2F32 v) {D_StackPushImpl(Clip, clip, Rng2F32, v);} +internal F32 d_push_transparency(F32 v) {D_StackPushImpl(Transparency, transparency, F32, v);} +internal R_Tex2DSampleKind d_pop_tex2d_sample_kind(void) {D_StackPopImpl(Tex2DSampleKind, tex2d_sample_kind, R_Tex2DSampleKind);} +internal Mat3x3F32 d_pop_xform2d(void) {D_StackPopImpl(XForm2D, xform2d, Mat3x3F32);} +internal Rng2F32 d_pop_clip(void) {D_StackPopImpl(Clip, clip, Rng2F32);} +internal F32 d_pop_transparency(void) {D_StackPopImpl(Transparency, transparency, F32);} +internal R_Tex2DSampleKind d_top_tex2d_sample_kind(void) {D_StackTopImpl(Tex2DSampleKind, tex2d_sample_kind, R_Tex2DSampleKind);} +internal Mat3x3F32 d_top_xform2d(void) {D_StackTopImpl(XForm2D, xform2d, Mat3x3F32);} +internal Rng2F32 d_top_clip(void) {D_StackTopImpl(Clip, clip, Rng2F32);} +internal F32 d_top_transparency(void) {D_StackTopImpl(Transparency, transparency, F32);} diff --git a/src/draw/generated/draw.meta.h b/src/draw/generated/draw.meta.h new file mode 100644 index 00000000..0cf4f6d9 --- /dev/null +++ b/src/draw/generated/draw.meta.h @@ -0,0 +1,50 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef DRAW_META_H +#define DRAW_META_H + +typedef struct D_Tex2DSampleKindNode D_Tex2DSampleKindNode; struct D_Tex2DSampleKindNode {D_Tex2DSampleKindNode *next; R_Tex2DSampleKind v;}; +typedef struct D_XForm2DNode D_XForm2DNode; struct D_XForm2DNode {D_XForm2DNode *next; Mat3x3F32 v;}; +typedef struct D_ClipNode D_ClipNode; struct D_ClipNode {D_ClipNode *next; Rng2F32 v;}; +typedef struct D_TransparencyNode D_TransparencyNode; struct D_TransparencyNode {D_TransparencyNode *next; F32 v;}; +#define D_BucketStackDecls struct{\ +D_Tex2DSampleKindNode *top_tex2d_sample_kind;\ +D_XForm2DNode *top_xform2d;\ +D_ClipNode *top_clip;\ +D_TransparencyNode *top_transparency;\ +} +read_only global D_Tex2DSampleKindNode d_nil_tex2d_sample_kind = {0, R_Tex2DSampleKind_Nearest}; +read_only global D_XForm2DNode d_nil_xform2d = {0, {1, 0, 0, 0, 1, 0, 0, 0, 1}}; +read_only global D_ClipNode d_nil_clip = {0, {0}}; +read_only global D_TransparencyNode d_nil_transparency = {0, 0}; +#define D_BucketStackInits(b) do{\ +(b)->top_tex2d_sample_kind = &d_nil_tex2d_sample_kind;\ +(b)->top_xform2d = &d_nil_xform2d;\ +(b)->top_clip = &d_nil_clip;\ +(b)->top_transparency = &d_nil_transparency;\ +}while(0) +#if 0 +internal R_Tex2DSampleKind d_push_tex2d_sample_kind(R_Tex2DSampleKind v); +internal Mat3x3F32 d_push_xform2d(Mat3x3F32 v); +internal Rng2F32 d_push_clip(Rng2F32 v); +internal F32 d_push_transparency(F32 v); +internal R_Tex2DSampleKind d_pop_tex2d_sample_kind(void); +internal Mat3x3F32 d_pop_xform2d(void); +internal Rng2F32 d_pop_clip(void); +internal F32 d_pop_transparency(void); +internal R_Tex2DSampleKind d_top_tex2d_sample_kind(void); +internal Mat3x3F32 d_top_xform2d(void); +internal Rng2F32 d_top_clip(void); +internal F32 d_top_transparency(void); +#endif +#if 0 +#define D_Tex2DSampleKindScope(v) DeferLoop(d_push_tex2d_sample_kind(v), d_pop_tex2d_sample_kind()) +#define D_XForm2DScope(v) DeferLoop(d_push_xform2d(v), d_pop_xform2d()) +#define D_ClipScope(v) DeferLoop(d_push_clip(v), d_pop_clip()) +#define D_TransparencyScope(v) DeferLoop(d_push_transparency(v), d_pop_transparency()) +#endif + +#endif // DRAW_META_H diff --git a/src/eval/eval.mc b/src/eval/eval.mc new file mode 100644 index 00000000..9bd5dda9 --- /dev/null +++ b/src/eval/eval.mc @@ -0,0 +1,81 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +@table(name num_children op_string) +// num_children - # of children packed after this node kind +// op_string - string for quick display of the operator +EVAL_ExprKindTable: +{ + { ArrayIndex 2 "[]" } + { MemberAccess 2 "." } + { Deref 1 "*" } + { Address 1 "&" } + + { Cast 2 "cast" } + { Sizeof 1 "sizeof" } + + { Neg 1 "-" } + { LogNot 1 "!" } + { BitNot 1 "~" } + { Mul 2 "*" } + { Div 2 "/" } + { Mod 2 "%" } + { Add 2 "+" } + { Sub 2 "-" } + { LShift 2 "<<" } + { RShift 2 ">>" } + { Less 2 "<" } + { LsEq 2 "<=" } + { Grtr 2 ">" } + { GrEq 2 ">=" } + { EqEq 2 "==" } + { NtEq 2 "!=" } + + { BitAnd 2 "&" } + { BitXor 2 "^" } + { BitOr 2 "|" } + { LogAnd 2 "&&" } + { LogOr 2 "||" } + + { Ternary 3 "? " } + + { LeafBytecode 0 "bytecode" } + { LeafMember 0 "member" } + { LeafU64 0 "U64" } + { LeafF64 0 "F64" } + { LeafF32 0 "F32" } + + { TypeIdent 0 "type_ident" } + { Ptr 1 "ptr" } + { Array 2 "array" } + { Func 1 "function" } +} + +@table_gen +{ + `typedef U32 EVAL_ExprKind;`; + `enum`; + `{`; + @expand(EVAL_ExprKindTable a) `EVAL_ExprKind_$(a.name),`; + `EVAL_ExprKind_COUNT`; + `};`; + ``; +} + +@table_gen_data(type:U8, fallback:0) +eval_expr_kind_child_counts: +{ + @expand(EVAL_ExprKindTable a) `$(a.num_children),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +eval_expr_kind_strings: +{ + @expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.name)"),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +eval_expr_op_strings: +{ + @expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.op_string)"),`; +} diff --git a/src/eval/eval_compiler.c b/src/eval/eval_compiler.c new file mode 100644 index 00000000..983cecc4 --- /dev/null +++ b/src/eval/eval_compiler.c @@ -0,0 +1,1624 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ allen: Eval Errors + +internal void +eval_error(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, String8 text){ + EVAL_Error *error = push_array_no_zero(arena, EVAL_Error, 1); + SLLQueuePush(list->first, list->last, error); + list->count += 1; + list->max_kind = Max(kind, list->max_kind); + error->kind = kind; + error->location = location; + error->text = text; +} + +internal void +eval_errorf(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, char *fmt, ...){ + va_list args; + va_start(args, fmt); + String8 text = push_str8fv(arena, fmt, args); + va_end(args); + eval_error(arena, list, kind, location, text); +} + +internal void +eval_error_list_concat_in_place(EVAL_ErrorList *dst, EVAL_ErrorList *to_push){ + if (dst->last != 0){ + if (to_push->last != 0){ + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->count += to_push->count; + } + } + else{ + *dst = *to_push; + } + MemoryZeroStruct(to_push); +} + +//////////////////////////////// +//~ allen: EVAL Bytecode Helpers + +internal String8 +eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list){ + // allocate output + U64 size = list->encoded_size; + U8 *str = push_array_no_zero(arena, U8, size); + + // iterate loose op nodes + U8 *ptr = str; + U8 *opl = str + size; + for (EVAL_Op *op = list->first_op; + op != 0; + op = op->next){ + U32 opcode = op->opcode; + + switch (opcode){ + default: + { + // compute bytecode advance + U8 ctrlbits = raddbg_eval_opcode_ctrlbits[opcode]; + U64 extra_byte_count = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); + + U8 *next_ptr = ptr + 1 + extra_byte_count; + Assert(next_ptr <= opl); + + // fill bytecode + ptr[0] = opcode; + MemoryCopy(ptr + 1, &op->p, extra_byte_count); + + // advance output pointer + ptr = next_ptr; + }break; + + case EVAL_IRExtKind_Bytecode: + { + // compute bytecode advance + U64 size = op->bytecode.size; + U8 *next_ptr = ptr + size; + Assert(next_ptr <= opl); + + // fill bytecode + MemoryCopy(ptr, op->bytecode.str, size); + + // advance output pointer + ptr = next_ptr; + }break; + } + } + + // fill result + String8 result = {0}; + result.size = size; + result.str = str; + return(result); +} + +internal void +eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RADDBG_EvalOp opcode, U64 p){ + U8 ctrlbits = raddbg_eval_opcode_ctrlbits[opcode]; + U32 p_size = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); + + EVAL_Op *node = push_array_no_zero(arena, EVAL_Op, 1); + node->opcode = opcode; + node->p = p; + + SLLQueuePush(list->first_op, list->last_op, node); + list->op_count += 1; + list->encoded_size += 1 + p_size; +} + +internal void +eval_oplist_push_uconst(Arena *arena, EVAL_OpList *list, U64 x){ + if (x <= 0xFF){ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU8, x); + } + else if (x <= 0xFFFF){ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU16, x); + } + else if (x <= 0xFFFFFFFF){ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU32, x); + } + else{ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU64, x); + } +} + +internal void +eval_oplist_push_sconst(Arena *arena, EVAL_OpList *list, S64 x){ + if (-0x80 <= x && x <= 0x7F){ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU8, (U64)x); + eval_oplist_push_op(arena, list, RADDBG_EvalOp_TruncSigned, 8); + } + else if (-0x8000 <= x && x <= 0x7FFF){ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU16, (U64)x); + eval_oplist_push_op(arena, list, RADDBG_EvalOp_TruncSigned, 16); + } + else if (-0x80000000ll <= x && x <= 0x7FFFFFFFll){ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU32, (U64)x); + eval_oplist_push_op(arena, list, RADDBG_EvalOp_TruncSigned, 32); + } + else{ + eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU64, (U64)x); + } +} + +internal void +eval_oplist_push_bytecode(Arena *arena, EVAL_OpList *list, String8 bytecode){ + EVAL_Op *node = push_array_no_zero(arena, EVAL_Op, 1); + node->opcode = EVAL_IRExtKind_Bytecode; + node->bytecode = bytecode; + SLLQueuePush(list->first_op, list->last_op, node); + list->op_count += 1; + list->encoded_size += bytecode.size; +} + +internal void +eval_oplist_concat_in_place(EVAL_OpList *left_dst, EVAL_OpList *right_destroyed){ + if (right_destroyed->first_op != 0){ + if (left_dst->first_op == 0){ + MemoryCopyStruct(left_dst, right_destroyed); + } + else{ + left_dst->last_op = right_destroyed->last_op; + left_dst->op_count += right_destroyed->op_count; + left_dst->encoded_size += right_destroyed->encoded_size; + } + MemoryZeroStruct(right_destroyed); + } +} + +//////////////////////////////// +//~ allen: EVAL Expression Info Functions + +internal RADDBG_EvalOp +eval_opcode_from_expr_kind(EVAL_ExprKind kind){ + RADDBG_EvalOp result = RADDBG_EvalOp_Stop; + switch (kind){ + case EVAL_ExprKind_Neg: result = RADDBG_EvalOp_Neg; break; + case EVAL_ExprKind_LogNot: result = RADDBG_EvalOp_LogNot; break; + case EVAL_ExprKind_BitNot: result = RADDBG_EvalOp_BitNot; break; + case EVAL_ExprKind_Mul: result = RADDBG_EvalOp_Mul; break; + case EVAL_ExprKind_Div: result = RADDBG_EvalOp_Div; break; + case EVAL_ExprKind_Mod: result = RADDBG_EvalOp_Mod; break; + case EVAL_ExprKind_Add: result = RADDBG_EvalOp_Add; break; + case EVAL_ExprKind_Sub: result = RADDBG_EvalOp_Sub; break; + case EVAL_ExprKind_LShift: result = RADDBG_EvalOp_LShift; break; + case EVAL_ExprKind_RShift: result = RADDBG_EvalOp_RShift; break; + case EVAL_ExprKind_Less: result = RADDBG_EvalOp_Less; break; + case EVAL_ExprKind_LsEq: result = RADDBG_EvalOp_LsEq; break; + case EVAL_ExprKind_Grtr: result = RADDBG_EvalOp_Grtr; break; + case EVAL_ExprKind_GrEq: result = RADDBG_EvalOp_GrEq; break; + case EVAL_ExprKind_EqEq: result = RADDBG_EvalOp_EqEq; break; + case EVAL_ExprKind_NtEq: result = RADDBG_EvalOp_NtEq; break; + case EVAL_ExprKind_BitAnd: result = RADDBG_EvalOp_BitAnd; break; + case EVAL_ExprKind_BitXor: result = RADDBG_EvalOp_BitXor; break; + case EVAL_ExprKind_BitOr: result = RADDBG_EvalOp_BitOr; break; + case EVAL_ExprKind_LogAnd: result = RADDBG_EvalOp_LogAnd; break; + case EVAL_ExprKind_LogOr: result = RADDBG_EvalOp_LogOr; break; + } + return(result); +} + +internal B32 +eval_expr_kind_is_comparison(EVAL_ExprKind kind){ + B32 result = 0; + switch (kind){ + case EVAL_ExprKind_EqEq: + case EVAL_ExprKind_NtEq: + case EVAL_ExprKind_Less: + case EVAL_ExprKind_Grtr: + case EVAL_ExprKind_LsEq: + case EVAL_ExprKind_GrEq: + { + result = 1; + }break; + } + return(result); +} + +//////////////////////////////// +//~ allen: EVAL Expression Constructors + +internal EVAL_Expr* +eval_expr(Arena *arena, EVAL_ExprKind kind, void *location, + EVAL_Expr *c0, EVAL_Expr *c1, EVAL_Expr *c2){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->kind = kind; + result->location = location; + result->children[0] = c0; + result->children[1] = c1; + result->children[2] = c2; + return(result); +} + +internal EVAL_Expr* +eval_expr_u64(Arena *arena, void *location, U64 u64){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->kind = EVAL_ExprKind_LeafU64; + result->location = location; + result->u64 = u64; + return(result); +} + +internal EVAL_Expr* +eval_expr_f64(Arena *arena, void *location, F64 f64){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->kind = EVAL_ExprKind_LeafF64; + result->location = location; + result->f64 = f64; + return(result); +} + +internal EVAL_Expr* +eval_expr_f32(Arena *arena, void *location, F32 f32){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->kind = EVAL_ExprKind_LeafF32; + result->location = location; + result->f32 = f32; + return(result); +} + +internal EVAL_Expr* +eval_expr_child_and_u64(Arena *arena, EVAL_ExprKind kind, void *location, + EVAL_Expr *child, U64 u64){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->kind = kind; + result->location = location; + result->child_and_constant.child = child; + result->child_and_constant.u64 = u64; + return(result); +} + +internal EVAL_Expr* +eval_expr_leaf_member(Arena *arena, void *location, String8 name){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->location = location; + result->kind = EVAL_ExprKind_LeafMember; + result->name = name; + return(result); +} + +internal EVAL_Expr* +eval_expr_leaf_bytecode(Arena *arena, void *location, TG_Key type_key, String8 bytecode, EVAL_EvalMode mode){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->location = location; + result->kind = EVAL_ExprKind_LeafBytecode; + result->type_key = type_key; + result->bytecode = bytecode; + result->mode = mode; + return(result); +} + +internal EVAL_Expr* +eval_expr_leaf_op_list(Arena *arena, void *location, TG_Key type_key, EVAL_OpList *ops, EVAL_EvalMode mode){ + String8 bytecode = eval_bytecode_from_oplist(arena, ops); + EVAL_Expr *result = eval_expr_leaf_bytecode(arena, location, type_key, bytecode, mode); + return(result); +} + +internal EVAL_Expr* +eval_expr_leaf_type(Arena *arena, void *location, TG_Key type_key){ + EVAL_Expr *result = push_array(arena, EVAL_Expr, 1); + result->location = location; + result->kind = EVAL_ExprKind_TypeIdent; + result->type_key = type_key; + return(result); +} + +//////////////////////////////// +//~ allen: EVAL Type Information Transformers + +internal RADDBG_EvalTypeGroup +eval_type_group_from_kind(TG_Kind kind){ + RADDBG_EvalTypeGroup result = 0; + switch (kind){ + default:{}break; + + case TG_Kind_Null: case TG_Kind_Void: + case TG_Kind_F16: case TG_Kind_F32PP: case TG_Kind_F48: + case TG_Kind_F80: case TG_Kind_F128: + case TG_Kind_ComplexF32: case TG_Kind_ComplexF64: + case TG_Kind_ComplexF80: case TG_Kind_ComplexF128: + case TG_Kind_Modifier: case TG_Kind_Array: + case TG_Kind_Struct: case TG_Kind_Class: case TG_Kind_Union: + case TG_Kind_Enum: case TG_Kind_Alias: + case TG_Kind_IncompleteStruct: case TG_Kind_IncompleteClass: + case TG_Kind_IncompleteUnion: case TG_Kind_IncompleteEnum: + case TG_Kind_Bitfield: case TG_Kind_Variadic: + result = RADDBG_EvalTypeGroup_Other; break; + + case TG_Kind_Handle: + case TG_Kind_UChar8: case TG_Kind_UChar16: case TG_Kind_UChar32: + case TG_Kind_U8: case TG_Kind_U16: case TG_Kind_U32: + case TG_Kind_U64: case TG_Kind_U128: case TG_Kind_U256: + case TG_Kind_U512: + case TG_Kind_Ptr: case TG_Kind_LRef: case TG_Kind_RRef: + case TG_Kind_Function: case TG_Kind_Method: case TG_Kind_MemberPtr: + result = RADDBG_EvalTypeGroup_U; break; + + case TG_Kind_Char8: case TG_Kind_Char16: case TG_Kind_Char32: + case TG_Kind_S8: case TG_Kind_S16: case TG_Kind_S32: + case TG_Kind_S64: case TG_Kind_S128: case TG_Kind_S256: + case TG_Kind_S512: + case TG_Kind_Bool: + result = RADDBG_EvalTypeGroup_S; break; + + case TG_Kind_F32: + result = RADDBG_EvalTypeGroup_F32; break; + + case TG_Kind_F64: + result = RADDBG_EvalTypeGroup_F64; break; + } + return(result); +} + +internal TG_Key +eval_type_unwrap(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_Key result = key; + for(B32 good = 1; good;) + { + TG_Kind kind = tg_kind_from_key(result); + if((TG_Kind_FirstIncomplete <= kind && kind <= TG_Kind_LastIncomplete) || + kind == TG_Kind_Modifier || + kind == TG_Kind_Alias) + { + result = tg_direct_from_graph_raddbg_key(graph, rdbg, result); + } + else + { + good = 0; + } + } + return result; +} + +internal TG_Key +eval_type_unwrap_enum(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_Key result = key; + for(B32 good = 1; good;) + { + TG_Kind kind = tg_kind_from_key(key); + if(kind == TG_Kind_Enum) + { + result = tg_direct_from_graph_raddbg_key(graph, rdbg, result); + } + else + { + good = 0; + } + } + return result; +} + +internal TG_Key +eval_type_promote(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key){ + TG_Key result = key; + TG_Kind kind = tg_kind_from_key(key); + if(kind == TG_Kind_Bool || + kind == TG_Kind_S8 || + kind == TG_Kind_S16 || + kind == TG_Kind_U8 || + kind == TG_Kind_U16) + { + result = tg_key_basic(TG_Kind_S32); + } + return result; +} + +internal TG_Key +eval_type_coerce(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ + Assert(eval_kind_is_basic_or_enum(tg_kind_from_key(l)) && + eval_kind_is_basic_or_enum(tg_kind_from_key(r))); + + // replace enums with corresponding ints + TG_Key lt = eval_type_unwrap_enum(graph, rdbg, l); + TG_Key rt = eval_type_unwrap_enum(graph, rdbg, r); + + // first promote each + TG_Key lp = eval_type_promote(graph, rdbg, lt); + TG_Key rp = eval_type_promote(graph, rdbg, rt); + TG_Kind lk = tg_kind_from_key(lp); + TG_Kind rk = tg_kind_from_key(rp); + + TG_Key result = l; + return(result); +} + +internal B32 +eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ + B32 result = 0; + + // unwrap + TG_Key lu = eval_type_unwrap(graph, rdbg, l); + TG_Key ru = eval_type_unwrap(graph, rdbg, r); + + if (tg_key_match(lu, ru)){ + result = 1; + } + else{ + TG_Kind luk = tg_kind_from_key(lu); + TG_Kind ruk = tg_kind_from_key(ru); + if (luk == ruk){ + switch (luk){ + default: + { + result = 1; + }break; + + case TG_Kind_Ptr: + case TG_Kind_LRef: + case TG_Kind_RRef: + { + TG_Key lud = tg_direct_from_graph_raddbg_key(graph, rdbg, lu); + TG_Key rud = tg_direct_from_graph_raddbg_key(graph, rdbg, ru); + if (eval_type_match(graph, rdbg, lud, rud)){ + result = 1; + } + }break; + + case TG_Kind_MemberPtr: + { + TG_Key lud = tg_direct_from_graph_raddbg_key(graph, rdbg, lu); + TG_Key rud = tg_direct_from_graph_raddbg_key(graph, rdbg, ru); + TG_Key luo = tg_owner_from_graph_raddbg_key(graph, rdbg, lu); + TG_Key ruo = tg_owner_from_graph_raddbg_key(graph, rdbg, ru); + if (eval_type_match(graph, rdbg, lud, rud) && + eval_type_match(graph, rdbg, luo, ruo)){ + result = 1; + } + }break; + + case TG_Kind_Array: + { + Temp scratch = scratch_begin(0, 0); + TG_Type *lt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, l); + TG_Type *rt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, r); + if(lt->count == rt->count && eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key)) + { + result = 1; + } + scratch_end(scratch); + }break; + + case TG_Kind_Function: + { + Temp scratch = scratch_begin(0, 0); + TG_Type *lt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, l); + TG_Type *rt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, r); + if (lt->count == rt->count && eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key)) + { + B32 params_match = 1; + TG_Key *lp = lt->param_type_keys; + TG_Key *rp = rt->param_type_keys; + U64 count = lt->count; + for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) + { + if(!eval_type_match(graph, rdbg, *lp, *rp)) + { + params_match = 0; + break; + } + } + result = params_match; + } + scratch_end(scratch); + }break; + + case TG_Kind_Method: + { + Temp scratch = scratch_begin(0, 0); + TG_Type *lt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, l); + TG_Type *rt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, r); + if (lt->count == rt->count && + eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key) && + eval_type_match(graph, rdbg, lt->owner_type_key, rt->owner_type_key)) + { + B32 params_match = 1; + TG_Key *lp = lt->param_type_keys; + TG_Key *rp = rt->param_type_keys; + U64 count = lt->count; + for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) + { + if(!eval_type_match(graph, rdbg, *lp, *rp)) + { + params_match = 0; + break; + } + } + result = params_match; + } + scratch_end(scratch); + }break; + } + } + } + + return(result); +} + +internal B32 +eval_kind_is_integer(TG_Kind kind){ + B32 result = (TG_Kind_FirstInteger <= kind && kind <= TG_Kind_LastInteger); + return(result); +} + +internal B32 +eval_kind_is_signed(TG_Kind kind){ + B32 result = ((TG_Kind_FirstSigned1 <= kind && kind <= TG_Kind_LastSigned1) || + (TG_Kind_FirstSigned2 <= kind && kind <= TG_Kind_LastSigned2)); + return(result); +} + +internal B32 +eval_kind_is_basic_or_enum(TG_Kind kind){ + B32 result = ((TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) || + kind == TG_Kind_Enum); + return(result); +} + + +//////////////////////////////// +//~ allen: EVAL IR-Tree Constructors + +internal EVAL_IRTree* +eval_irtree_const_u(Arena *arena, U64 v){ + // choose encoding op + RADDBG_EvalOp op = RADDBG_EvalOp_ConstU64; + if (v < 0x100){ + op = RADDBG_EvalOp_ConstU8; + } + else if (v < 0x10000){ + op = RADDBG_EvalOp_ConstU16; + } + else if (v < 0x100000000){ + op = RADDBG_EvalOp_ConstU32; + } + + // make the tree node + EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); + result->op = op; + result->p = v; + return(result); +} + +internal EVAL_IRTree* +eval_irtree_unary_op(Arena *arena, RADDBG_EvalOp op, + RADDBG_EvalTypeGroup group, EVAL_IRTree *c){ + EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); + result->op = op; + result->p = group; + result->children[0] = c; + return(result); +} + +internal EVAL_IRTree* +eval_irtree_binary_op(Arena *arena, RADDBG_EvalOp op, RADDBG_EvalTypeGroup group, + EVAL_IRTree *l, EVAL_IRTree *r){ + EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); + result->op = op; + result->p = group; + result->children[0] = l; + result->children[1] = r; + return(result); +} + +internal EVAL_IRTree* +eval_irtree_binary_op_u(Arena *arena, RADDBG_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r){ + EVAL_IRTree *result = eval_irtree_binary_op(arena, op, RADDBG_EvalTypeGroup_U, l, r); + return(result); +} + +internal EVAL_IRTree* +eval_irtree_conditional(Arena *arena, EVAL_IRTree *c, EVAL_IRTree *l, EVAL_IRTree *r){ + EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); + result->op = RADDBG_EvalOp_Cond; + result->children[0] = c; + result->children[1] = l; + result->children[2] = r; + return(result); +} + +internal EVAL_IRTree* +eval_irtree_bytecode_no_copy(Arena *arena, String8 bytecode){ + EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); + result->op = EVAL_IRExtKind_Bytecode; + result->bytecode = bytecode; + return(result); +} + +//////////////////////////////// +//~ allen: EVAL IR-Tree High Level Helpers + +internal EVAL_IRTree* +eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key){ + U64 byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + EVAL_IRTree *result = &eval_irtree_nil; + if (0 < byte_size && byte_size <= 8){ + // build the read node + EVAL_IRTree *read_node = push_array(arena, EVAL_IRTree, 1); + read_node->op = RADDBG_EvalOp_MemRead; + read_node->p = byte_size; + read_node->children[0] = c; + + // build a signed trunc node if needed + U64 bit_size = byte_size << 3; + EVAL_IRTree *with_trunc = read_node; + TG_Kind kind = tg_kind_from_key(type_key); + if (bit_size < 64 && eval_kind_is_signed(kind)){ + with_trunc = push_array(arena, EVAL_IRTree, 1); + with_trunc->op = RADDBG_EvalOp_TruncSigned; + with_trunc->p = bit_size; + with_trunc->children[0] = read_node; + } + + // set result + result = with_trunc; + } + else{ + // TODO: unexpected path + } + return(result); +} + +internal EVAL_IRTree* +eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RADDBG_EvalTypeGroup out, RADDBG_EvalTypeGroup in){ + EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); + result->op = RADDBG_EvalOp_Convert; + result->p = in | (out << 8); + result->children[0] = c; + return(result); +} + +internal EVAL_IRTree* +eval_irtree_trunc(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key){ + EVAL_IRTree *result = c; + U64 byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + if (byte_size < 64){ + RADDBG_EvalOp op = RADDBG_EvalOp_Trunc; + TG_Kind kind = tg_kind_from_key(type_key); + if (eval_kind_is_signed(kind)){ + op = RADDBG_EvalOp_TruncSigned; + } + U64 bit_size = byte_size << 3; + result = push_array(arena, EVAL_IRTree, 1); + result->op = op; + result->p = bit_size; + result->children[0] = c; + } + return(result); +} + +internal EVAL_IRTree* +eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key out, TG_Key in){ + EVAL_IRTree *result = c; + TG_Kind in_kind = tg_kind_from_key(in); + TG_Kind out_kind = tg_kind_from_key(out); + U8 in_group = eval_type_group_from_kind(in_kind); + U8 out_group = eval_type_group_from_kind(out_kind); + U32 conversion_rule = raddbg_eval_conversion_rule(in_group, out_group); + if(conversion_rule == RADDBG_EvalConversionKind_Legal) + { + result = eval_irtree_convert_lo(arena, result, out_group, in_group); + } + U64 in_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, in); + U64 out_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, out); + if(out_byte_size < in_byte_size && eval_kind_is_integer(out_kind)) + { + result = eval_irtree_trunc(arena, graph, rdbg, result, out); + } + return(result); +} + +internal EVAL_IRTree* +eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_EvalMode from_mode, + EVAL_IRTree *tree, TG_Key type_key){ + EVAL_IRTree *result = tree; + switch (from_mode){ + default:{}break; + case EVAL_EvalMode_Addr: + { + result = eval_irtree_mem_read_type(arena, graph, rdbg, tree, type_key); + }break; + case EVAL_EvalMode_Reg: + { + result = eval_irtree_unary_op(arena, RADDBG_EvalOp_RegReadDyn, RADDBG_EvalTypeGroup_U, tree); + }break; + } + return(result); +} + +//////////////////////////////// +//~ allen: EVAL Compiler Phases + +internal TG_Key +eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_Expr *expr, EVAL_ErrorList *eout){ + TG_Key result = zero_struct; + + EVAL_ExprKind kind = expr->kind; + switch (kind){ + default: + { + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Expected type expression."); + }break; + + case EVAL_ExprKind_TypeIdent: + { + result = expr->type_key; + }break; + + case EVAL_ExprKind_Ptr: + { + TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdbg, expr->children[0], eout); + result = tg_cons_type_make(graph, TG_Kind_Ptr, direct_type_key, 0); + }break; + + case EVAL_ExprKind_Array: + { + EVAL_Expr *child_expr = expr->child_and_constant.child; + TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdbg, child_expr, eout); + result = tg_cons_type_make(graph, TG_Kind_Array, direct_type_key, expr->child_and_constant.u64); + }break; + + case EVAL_ExprKind_Func: + { + // TODO(rjf): old type graph code is below: +#if 0 + TG_Type *ret_type = eval_type_from_type_expr(arena, graph, expr->children[0], eout); + // TODO(allen): decision: do we do the extra work to preserve full function type info? + result = tg_type_func(graph, ret_type, 0, 0); +#endif + }break; + } + + return(result); +} + +internal EVAL_IRTreeAndType +eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_Expr *expr, EVAL_ErrorList *eout) +{ + EVAL_IRTreeAndType result = {0}; + result.tree = &eval_irtree_nil; + + EVAL_ExprKind kind = expr->kind; + switch(kind) + { + default: + { + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "(internal) Undefined expression kind (%u).", kind); + }break; + + case EVAL_ExprKind_ArrayIndex: + { + EVAL_Expr *exprl = expr->children[0]; + EVAL_Expr *exprr = expr->children[1]; + + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprl, eout); + EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprr, eout); + + if (l.tree->op != 0 && r.tree->op != 0){ + TG_Key l_restype = eval_type_unwrap(graph, rdbg, l.type_key); + TG_Key r_restype = eval_type_unwrap(graph, rdbg, r.type_key); + TG_Kind l_restype_kind = tg_kind_from_key(l_restype); + TG_Kind r_restype_kind = tg_kind_from_key(r_restype); + + // analyze situation + B32 can_generate = 0; + B32 l_resolve = 0; + TG_Key direct_type = zero_struct; + U64 direct_type_size = 0; + if (!eval_kind_is_integer(r_restype_kind)){ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Cannot index with this type."); + } + else{ + direct_type = tg_direct_from_graph_raddbg_key(graph, rdbg, l_restype); + direct_type_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct_type); + if (l_restype_kind == TG_Kind_Ptr){ + if (direct_type_size == 0){ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Cannot index into pointers of zero-sized types."); + } + else{ + can_generate = 1; + if (l.mode != EVAL_EvalMode_Value){ + l_resolve = 1; + } + } + } + else if (l_restype_kind == TG_Kind_Array){ + if (l.mode == EVAL_EvalMode_Addr){ + if (direct_type_size == 0){ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "Cannot index into arrays of zero-sized types."); + } + else{ + can_generate = 1; + } + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "(Not supported) Cannot index into array without base address."); + } + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "Cannot index into this type."); + } + } + + // generate ir tree + if (can_generate){ + // how to compute the index + EVAL_IRTree *index_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); + if (direct_type_size > 1){ + EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size); + index_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Mul, index_tree, const_tree); + } + + // how to compute the base address + EVAL_IRTree *base_tree = l.tree; + if (l_resolve){ + base_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, base_tree, l_restype); + } + + // how to compute the final address + EVAL_IRTree *new_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Add, index_tree, base_tree); + + // fill result + result.tree = new_tree; + result.type_key = direct_type; + result.mode = EVAL_EvalMode_Addr; + } + } + }break; + + case EVAL_ExprKind_MemberAccess: + { + EVAL_Expr *exprl = expr->children[0]; + EVAL_Expr *exprr = expr->children[1]; + + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprl, eout); + + if (l.tree->op != 0 && !tg_key_match(tg_key_zero(), l.type_key)){ + TG_Key l_restype = eval_type_unwrap(graph, rdbg, l.type_key); + TG_Kind l_restype_kind = tg_kind_from_key(l_restype); + + // determine which type to use + TG_Key check_type_key = l_restype; + TG_Kind check_type_kind = l_restype_kind; + if (l_restype_kind == TG_Kind_Ptr){ + check_type_key = tg_direct_from_graph_raddbg_key(graph, rdbg, l_restype); + check_type_kind = tg_kind_from_key(check_type_key); + } + + // switch to handle + switch(check_type_kind) + { + default: + { + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "Cannot perform member access on this type."); + }break; + + case TG_Kind_Struct: + case TG_Kind_Class: + case TG_Kind_Union: + { + // analyze situation + B32 can_generate = 0; + TG_Key r_type = zero_struct; + U32 r_off = 0; + B32 l_resolve = 0; + + // determine how to treat left + B32 l_good = 0; + if (l_restype_kind == TG_Kind_Ptr){ + l_good = 1; + l_resolve = 1; + } + else{ + if (l.mode == EVAL_EvalMode_Addr){ + l_good = 1; + } + else if(l.mode == EVAL_EvalMode_Reg) + { + l_good = 1; + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, + "(Not supported) Cannot access member without a base address or register location."); + } + } + + // right must be identifier + B32 r_good = 0; + if (exprr->kind == EVAL_ExprKind_LeafMember){ + r_good = 1; + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, + "(internal) Expected a leaf member in member access."); + } + + if (l_good && r_good){ + Temp scratch = scratch_begin(&arena, 1); + TG_Type *check_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, check_type_key); + + // lookup member + String8 member_name = exprr->name; + TG_Member *match = 0; + for(U64 member_idx = 0; member_idx < check_type->count; member_idx += 1) + { + TG_Member *member = &check_type->members[member_idx]; + if(str8_match(member->name, member_name, 0)) + { + match = member; + break; + } + } + + // extract member info + if (match != 0){ + can_generate = 1; + r_type = match->type_key; + r_off = match->off; + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Could not find a member named '%S' in type.", member_name); + } + + scratch_end(scratch); + } + + // generate ir tree + if (can_generate){ + EVAL_IRTree *new_tree = l.tree; + if (l_resolve){ + new_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, new_tree, l_restype); + } + if (r_off != 0){ + EVAL_IRTree *const_tree = eval_irtree_const_u(arena, r_off); + new_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Add, new_tree, const_tree); + } + + // fill result + result.tree = new_tree; + result.type_key = r_type; + result.mode = l.mode; + } + }break; + } + + } + }break; + + case EVAL_ExprKind_Deref: + { + EVAL_Expr *exprc = expr->children[0]; + + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprc, eout); + + if (c.tree->op != 0){ + TG_Key c_restype = eval_type_unwrap(graph, rdbg, c.type_key); + TG_Kind c_restype_kind = tg_kind_from_key(c_restype); + TG_Key c_restype_direct = tg_direct_from_graph_raddbg_key(graph, rdbg, c_restype); + U64 c_restype_direct_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, c_restype_direct); + + // analyze situation + B32 can_generate = 0; + B32 c_resolve = 0; + if (c_restype_kind == TG_Kind_Ptr){ + if (c_restype_direct_size == 0){ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "Cannot dereference pointers of zero-sized types."); + } + else{ + can_generate = 1; + c_resolve = 1; + } + } + else if (c_restype_kind == TG_Kind_Array){ + if (c.mode == EVAL_EvalMode_Addr){ + if (c_restype_direct_size == 0){ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "Cannot dereference arrays of zero-sized types."); + } + else{ + can_generate = 1; + } + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "(Not supported) Cannot dereference array without base address."); + } + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "Cannot dereference this type."); + } + + // generate ir tree + if (can_generate){ + EVAL_IRTree *new_tree = c.tree; + if (c_resolve){ + new_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); + } + + // fill result + result.tree = new_tree; + result.type_key = c_restype_direct; + result.mode = EVAL_EvalMode_Addr; + } + } + }break; + + case EVAL_ExprKind_Address: + { + EVAL_Expr *exprc = expr->children[0]; + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprc, eout); + if(c.tree->op != 0 && !tg_key_match(c.type_key, tg_key_zero())) + { + TG_Key c_restype = eval_type_unwrap(graph, rdbg, c.type_key); + TG_Kind c_restype_kind = tg_kind_from_key(c_restype); + + // analyze situation + B32 can_generate = 0; + if(c.mode == EVAL_EvalMode_Addr) + { + can_generate = 1; + } + + // generate ir tree + if(can_generate) + { + EVAL_IRTree *new_tree = c.tree; + TG_Key ptr_type = tg_cons_type_make(graph, TG_Kind_Ptr, c_restype, 0); + + // fill result + result.tree = new_tree; + result.type_key = ptr_type; + result.mode = EVAL_EvalMode_Value; + } + } + }break; + + case EVAL_ExprKind_Cast: + { + EVAL_Expr *exprl = expr->children[0]; + EVAL_Expr *exprr = expr->children[1]; + + TG_Key cast_type_key = eval_type_from_type_expr(arena, graph, rdbg, exprl, eout); + TG_Kind cast_type_kind = tg_kind_from_key(cast_type_key); + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprr, eout); + + if(cast_type_kind != TG_Kind_Null && c.tree->op != 0) + { + TG_Key c_restype = eval_type_unwrap(graph, rdbg, c.type_key); + TG_Kind c_restype_kind = tg_kind_from_key(c_restype); + U64 c_restype_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, c_restype); + U64 cast_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, cast_type_key); + + // analyze situation + U8 in_group = eval_type_group_from_kind(c_restype_kind); + U8 out_group = eval_type_group_from_kind(cast_type_kind); + RADDBG_EvalConversionKind conversion_rule = raddbg_eval_conversion_rule(in_group, out_group); + + // generate tree + switch(conversion_rule) + { + case RADDBG_EvalConversionKind_Noop: + case RADDBG_EvalConversionKind_Legal: + { + EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); + + EVAL_IRTree *new_tree = in_tree; + if (conversion_rule == RADDBG_EvalConversionKind_Legal){ + new_tree = eval_irtree_convert_lo(arena, in_tree, out_group, in_group); + } + if (cast_type_byte_size < c_restype_byte_size && eval_kind_is_integer(cast_type_kind)){ + new_tree = eval_irtree_trunc(arena, graph, rdbg, in_tree, cast_type_key); + } + + result.tree = new_tree; + result.type_key = cast_type_key; + result.mode = EVAL_EvalMode_Value; + }break; + + default: + { + String8 text = str8_lit("(internal) unknown conversion rule"); + if (conversion_rule < RADDBG_EvalConversionKind_COUNT){ + text.str = raddbg_eval_conversion_message(conversion_rule, &text.size); + } + eval_error(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, text); + }break; + } + } + }break; + + case EVAL_ExprKind_Sizeof: + { + EVAL_Expr *exprc = expr->children[0]; + + // analyze situation + TG_Key type_key = zero_struct; + switch (exprc->kind){ + // size of type expression + case EVAL_ExprKind_TypeIdent: + case EVAL_ExprKind_Ptr: + case EVAL_ExprKind_Array: + case EVAL_ExprKind_Func: + { + type_key = eval_type_from_type_expr(arena, graph, rdbg, exprc, eout); + }break; + + // size of value expression + default: + { + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprc, eout); + type_key = c.type_key; + }break; + } + B32 can_generate = 0; + U64 size = 0; + TG_Kind type_kind = tg_kind_from_key(type_key); + if (type_kind != TG_Kind_Null){ + can_generate = 1; + size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + } + + // generate ir tree + if(can_generate) + { + EVAL_IRTree *new_tree = eval_irtree_const_u(arena, size); + result.tree = new_tree; + result.type_key = tg_key_basic(TG_Kind_U64); + result.mode = EVAL_EvalMode_Value; + } + }break; + + case EVAL_ExprKind_Neg: + case EVAL_ExprKind_LogNot: + case EVAL_ExprKind_BitNot: + { + EVAL_Expr *exprc = expr->children[0]; + + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprc, eout); + if (c.tree->op != 0){ + TG_Key c_restype = eval_type_unwrap(graph, rdbg, c.type_key); + TG_Key p_type = eval_type_promote(graph, rdbg, c_restype); + TG_Kind c_restype_kind = tg_kind_from_key(c_restype); + + // analyze situation + B32 can_generate = 0; + RADDBG_EvalOp op = eval_opcode_from_expr_kind(kind); + U8 c_group = eval_type_group_from_kind(c_restype_kind); + if (!raddbg_eval_opcode_type_compatible(op, c_group)){ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Cannot use this operator on this type."); + } + else{ + can_generate = 1; + } + + // generate ir tree + if (can_generate){ + EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); + in_tree = eval_irtree_convert_hi(arena, graph, rdbg, in_tree, p_type, c_restype); + + EVAL_IRTree *new_tree = eval_irtree_unary_op(arena, op, c_group, in_tree); + + result.tree = new_tree; + result.type_key = p_type; + result.mode = EVAL_EvalMode_Value; + } + } + }break; + + case EVAL_ExprKind_Mul: + case EVAL_ExprKind_Div: + case EVAL_ExprKind_Mod: + case EVAL_ExprKind_Add: + case EVAL_ExprKind_Sub: + case EVAL_ExprKind_LShift: + case EVAL_ExprKind_RShift: + case EVAL_ExprKind_Less: + case EVAL_ExprKind_LsEq: + case EVAL_ExprKind_Grtr: + case EVAL_ExprKind_GrEq: + case EVAL_ExprKind_EqEq: + case EVAL_ExprKind_NtEq: + case EVAL_ExprKind_BitAnd: + case EVAL_ExprKind_BitXor: + case EVAL_ExprKind_BitOr: + case EVAL_ExprKind_LogAnd: + case EVAL_ExprKind_LogOr: + { + //- setup & dispatch + EVAL_Expr *exprl = expr->children[0]; + EVAL_Expr *exprr = expr->children[1]; + + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprl, eout); + EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprr, eout); + + if (l.tree->op != 0 && r.tree->op != 0){ + TG_Key l_restype = eval_type_unwrap(graph, rdbg, l.type_key); + TG_Key r_restype = eval_type_unwrap(graph, rdbg, r.type_key); + TG_Kind l_restype_kind = tg_kind_from_key(l_restype); + TG_Kind r_restype_kind = tg_kind_from_key(r_restype); + + //- rjf: decay register types to basics + if(l_restype.kind == TG_KeyKind_Reg) + { + l_restype = tg_key_basic(TG_Kind_U64); + l_restype_kind = tg_kind_from_key(l_restype); + } + if(r_restype.kind == TG_KeyKind_Reg) + { + r_restype = tg_key_basic(TG_Kind_U64); + r_restype_kind = tg_kind_from_key(r_restype); + } + + RADDBG_EvalOp op = eval_opcode_from_expr_kind(kind); + + //- pointer decay + B32 l_is_pointer = (l_restype_kind == TG_Kind_Ptr); + B32 l_is_decay = (l_restype_kind == TG_Kind_Array && l.mode == EVAL_EvalMode_Addr); + B32 l_is_pointer_like = (l_is_pointer || l_is_decay); + + B32 r_is_pointer = (r_restype_kind == TG_Kind_Ptr); + B32 r_is_decay = (r_restype_kind == TG_Kind_Array && r.mode == EVAL_EvalMode_Addr); + B32 r_is_pointer_like = (r_is_pointer || r_is_decay); + + //- determine arithmetic path +#define EVAL_ArithPath_Normal 0 +#define EVAL_ArithPath_PtrAdd 1 +#define EVAL_ArithPath_PtrSub 2 + + B32 ptr_arithmetic_mul_rptr = 0; + U32 arith_path = EVAL_ArithPath_Normal; + if (kind == EVAL_ExprKind_Add){ + if (l_is_pointer_like && eval_kind_is_integer(r_restype_kind)){ + arith_path = EVAL_ArithPath_PtrAdd; + } + if (l_is_pointer_like && eval_kind_is_integer(l_restype_kind)){ + arith_path = EVAL_ArithPath_PtrAdd; + ptr_arithmetic_mul_rptr = 1; + } + } + else if (kind == EVAL_ExprKind_Sub){ + if (l_is_pointer_like && eval_kind_is_integer(r_restype_kind)){ + arith_path = EVAL_ArithPath_PtrAdd; + } + if (l_is_pointer_like && r_is_pointer_like){ + TG_Key l_restype_direct = tg_direct_from_graph_raddbg_key(graph, rdbg, l_restype); + TG_Key r_restype_direct = tg_direct_from_graph_raddbg_key(graph, rdbg, r_restype); + U64 l_restype_direct_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, l_restype_direct); + U64 r_restype_direct_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, r_restype_direct); + if (l_restype_direct_byte_size == r_restype_direct_byte_size){ + arith_path = EVAL_ArithPath_PtrSub; + } + } + } + + //- specific arithmetic handlers + + switch (arith_path){ + case EVAL_ArithPath_Normal: + { + // analyze situation + B32 is_comparison = eval_expr_kind_is_comparison(kind); + B32 both_basic = (eval_kind_is_basic_or_enum(l_restype_kind) && + eval_kind_is_basic_or_enum(r_restype_kind)); + + TG_Key cv_type_key = zero_struct; + if (both_basic){ + cv_type_key = eval_type_coerce(graph, rdbg, l_restype, r_restype); + } + else if (is_comparison && eval_type_match(graph, rdbg, l_restype, r_restype)){ + cv_type_key = l_restype; + } + + TG_Kind cv_type_kind = tg_kind_from_key(cv_type_key); + U8 cv_group = eval_type_group_from_kind(cv_type_kind); + + B32 can_generate = 0; + if (raddbg_eval_opcode_type_compatible(op, cv_group)){ + can_generate = 1; + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Cannot use this operator on this type."); + } + + // generate ir tree + if (can_generate){ + TG_Key final_type_key = cv_type_key; + if (is_comparison){ + final_type_key = tg_key_basic(TG_Kind_Bool); + } + + EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype); + l_tree = eval_irtree_convert_hi(arena, graph, rdbg, l_tree, cv_type_key, l_restype); + + EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); + r_tree = eval_irtree_convert_hi(arena, graph, rdbg, r_tree, cv_type_key, r_restype); + + EVAL_IRTree *new_tree = eval_irtree_binary_op(arena, op, cv_group, l_tree, r_tree); + + result.tree = new_tree; + result.type_key = final_type_key; + result.mode = EVAL_EvalMode_Value; + } + }break; + + case EVAL_ArithPath_PtrAdd: + { + // setup which side is the pointer + EVAL_IRTreeAndType *ptr = &l; + EVAL_IRTreeAndType *integer = &r; + B32 ptr_is_decay = l_is_decay; + if (ptr_arithmetic_mul_rptr){ + ptr = &r; + integer = &l; + ptr_is_decay = r_is_decay; + } + + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, ptr->type_key); + U64 direct_type_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct); + + // generate ir tree + EVAL_IRTree *ptr_tree = ptr->tree; + if (!ptr_is_decay){ + ptr_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, ptr->mode, ptr_tree, ptr->type_key); + } + + EVAL_IRTree *integer_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, integer->mode, integer->tree, integer->type_key); + if (direct_type_size > 1){ + EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size); + integer_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Mul, integer_tree, const_tree); + } + + TG_Key ptr_type = ptr->type_key; + if (ptr_is_decay){ + ptr_type = tg_cons_type_make(graph, TG_Kind_Ptr, direct, 0); + } + + EVAL_IRTree *new_tree = eval_irtree_binary_op(arena, op, RADDBG_EvalTypeGroup_U, ptr_tree, integer_tree); + + result.tree = new_tree; + result.type_key = ptr_type; + result.mode = EVAL_EvalMode_Value; + }break; + + case EVAL_ArithPath_PtrSub: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, l_restype); + U64 direct_type_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct); + + // generate ir tree + EVAL_IRTree *l_tree = l.tree; + if (!l_is_decay){ + l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype); + } + + EVAL_IRTree *r_tree = r.tree; + if (!r_is_decay){ + r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); + } + + EVAL_IRTree *op_tree = eval_irtree_binary_op(arena, op, RADDBG_EvalTypeGroup_U, l_tree, r_tree); + + EVAL_IRTree *new_tree = op_tree; + if (direct_type_size > 1){ + EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size); + new_tree = eval_irtree_binary_op(arena, RADDBG_EvalOp_Div, RADDBG_EvalTypeGroup_U, new_tree, const_tree); + } + + result.tree = new_tree; + result.type_key = tg_key_basic(TG_Kind_U64); + result.mode = EVAL_EvalMode_Value; + }break; + } + } + }break; + + case EVAL_ExprKind_Ternary: + { + EVAL_Expr *exprc = expr->children[0]; + EVAL_Expr *exprl = expr->children[1]; + EVAL_Expr *exprr = expr->children[2]; + + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprc, eout); + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprl, eout); + EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, exprr, eout); + + if (l.tree->op != 0 && r.tree->op != 0 && c.tree->op != 0){ + + TG_Key c_restype = eval_type_unwrap(graph, rdbg, c.type_key); + TG_Key l_restype = eval_type_unwrap(graph, rdbg, l.type_key); + TG_Key r_restype = eval_type_unwrap(graph, rdbg, r.type_key); + TG_Kind c_restype_kind = tg_kind_from_key(c_restype); + TG_Kind l_restype_kind = tg_kind_from_key(l_restype); + TG_Kind r_restype_kind = tg_kind_from_key(r_restype); + + // analyze situation + B32 can_generate = 0; + TG_Key final_type = zero_struct; + if (eval_kind_is_integer(c_restype_kind)){ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Conditional term must be an integer type."); + } + else{ + if (eval_kind_is_basic_or_enum(l_restype_kind) && + eval_kind_is_basic_or_enum(r_restype_kind)){ + can_generate = 1; + final_type = eval_type_coerce(graph, rdbg, l_restype, r_restype); + } + else{ + if (eval_type_match(graph, rdbg, l_restype, r_restype)){ + if (l_restype_kind == TG_Kind_Ptr){ + can_generate = 1; + final_type = l_restype; + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "(Not supported) Conditional value not basic type or pointer."); + } + } + else{ + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Left and right terms must have matching types."); + } + } + } + + // generate ir tree + if (can_generate){ + EVAL_IRTree *c_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); + + EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype); + l_tree = eval_irtree_convert_hi(arena, graph, rdbg, l_tree, final_type, l_restype); + + EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); + r_tree = eval_irtree_convert_hi(arena, graph, rdbg, r_tree, final_type, r_restype); + + EVAL_IRTree *new_tree = eval_irtree_conditional(arena, c_tree, l_tree, r_tree); + + result.tree = new_tree; + result.type_key = final_type; + result.mode = EVAL_EvalMode_Value; + } + } + }break; + + case EVAL_ExprKind_LeafBytecode: + { + EVAL_IRTree *new_tree = eval_irtree_bytecode_no_copy(arena, expr->bytecode); + TG_Key final_type_key = expr->type_key; + EVAL_EvalMode mode = expr->mode; + + result.tree = new_tree; + result.type_key = final_type_key; + result.mode = mode; + }break; + + case EVAL_ExprKind_LeafMember: + { + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "(internal) Leaf member not expected here."); + }break; + + case EVAL_ExprKind_LeafU64: + { + U64 val = expr->u64; + EVAL_IRTree *new_tree = eval_irtree_const_u(arena, val); + + TG_Key type_key = zero_struct; + if (val <= max_S32){ + type_key = tg_key_basic(TG_Kind_S32); + } + else if (val <= max_S64){ + type_key = tg_key_basic(TG_Kind_S64); + } + else{ + type_key = tg_key_basic(TG_Kind_U64); + } + + result.tree = new_tree; + result.type_key = type_key; + result.mode = EVAL_EvalMode_Value; + }break; + + case EVAL_ExprKind_LeafF64: + { + U64 val = expr->u64; + EVAL_IRTree *new_tree = eval_irtree_const_u(arena, val); + + result.tree = new_tree; + result.type_key = tg_key_basic(TG_Kind_F64); + result.mode = EVAL_EvalMode_Value; + }break; + + case EVAL_ExprKind_LeafF32: + { + U32 val = expr->u32; + EVAL_IRTree *new_tree = eval_irtree_const_u(arena, val); + + result.tree = new_tree; + result.type_key = tg_key_basic(TG_Kind_F32); + result.mode = EVAL_EvalMode_Value; + }break; + + case EVAL_ExprKind_TypeIdent: + case EVAL_ExprKind_Ptr: + case EVAL_ExprKind_Array: + case EVAL_ExprKind_Func: + { + eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Type expression not expected."); + }break; + } + + return(result); +} + +internal void +eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out){ + U32 op = tree->op; + switch (op){ + case RADDBG_EvalOp_Stop: + case RADDBG_EvalOp_Skip: + { + // TODO: error - invalid ir-tree op + }break; + + case EVAL_IRExtKind_Bytecode: + { + eval_oplist_push_bytecode(arena, out, tree->bytecode); + }break; + + case RADDBG_EvalOp_Cond: + { + // split out each of the children + EVAL_OpList prt_cond = {0}; + eval_oplist_from_irtree(arena, tree->children[0], &prt_cond); + + EVAL_OpList prt_left = {0}; + eval_oplist_from_irtree(arena, tree->children[1], &prt_left); + + EVAL_OpList prt_right = {0}; + eval_oplist_from_irtree(arena, tree->children[2], &prt_right); + + // put together like so: + // 1. , Op_Cond (sizeof(2)) + // 2. , Op_Skip (sizeof(3)) + // 3. + // 4. + + // modify prt_right in place to create step 2 + eval_oplist_push_op(arena, &prt_right, RADDBG_EvalOp_Skip, prt_left.encoded_size); + + // merge 1 into out + eval_oplist_concat_in_place(out, &prt_cond); + eval_oplist_push_op(arena, out, RADDBG_EvalOp_Cond, prt_right.encoded_size); + + // merge 2 into out + eval_oplist_concat_in_place(out, &prt_right); + + // merge 3 into out + eval_oplist_concat_in_place(out, &prt_left); + }break; + + default: + { + if (op >= RADDBG_EvalOp_COUNT){ + // TODO: error - invalid ir-tree op + } + else{ + // handle all children + U8 ctrlbits = raddbg_eval_opcode_ctrlbits[op]; + U64 child_count = RADDBG_POPN_FROM_CTRLBITS(ctrlbits); + EVAL_IRTree**child = tree->children; + for (U64 i = 0; i < child_count; i += 1, child += 1){ + eval_oplist_from_irtree(arena, *child, out); + } + + // emit op to compute this node + eval_oplist_push_op(arena, out, (RADDBG_EvalOp)tree->op, tree->p); + } + }break; + } +} + + + diff --git a/src/eval/eval_compiler.h b/src/eval/eval_compiler.h new file mode 100644 index 00000000..eff1c86e --- /dev/null +++ b/src/eval/eval_compiler.h @@ -0,0 +1,204 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef EVAL_COMPILER_H +#define EVAL_COMPILER_H + +//////////////////////////////// +//~ allen: EVAL Error Types + +typedef enum EVAL_ErrorKind +{ + EVAL_ErrorKind_Null, + EVAL_ErrorKind_MalformedInput, + EVAL_ErrorKind_MissingInfo, + EVAL_ErrorKind_ResolutionFailure, + EVAL_ErrorKind_COUNT +} +EVAL_ErrorKind; + +typedef struct EVAL_Error EVAL_Error; +struct EVAL_Error{ + EVAL_Error *next; + EVAL_ErrorKind kind; + void *location; + String8 text; +}; + +typedef struct EVAL_ErrorList EVAL_ErrorList; +struct EVAL_ErrorList{ + EVAL_Error *first; + EVAL_Error *last; + EVAL_ErrorKind max_kind; + U64 count; +}; + +//////////////////////////////// +//~ allen: EVAL Op List Types + +enum{ + EVAL_IRExtKind_Bytecode = RADDBG_EvalOp_COUNT, + EVAL_IRExtKind_COUNT +}; + +typedef struct EVAL_Op EVAL_Op; +struct EVAL_Op{ + EVAL_Op *next; + RADDBG_EvalOp opcode; + union{ + U64 p; + String8 bytecode; + }; +}; + +typedef struct EVAL_OpList EVAL_OpList; +struct EVAL_OpList{ + EVAL_Op *first_op; + EVAL_Op *last_op; + U32 op_count; + U32 encoded_size; +}; + +//////////////////////////////// +//- allen: EVAL Expression Types + +#include "eval/generated/eval.meta.h" + +typedef enum EVAL_EvalMode{ + EVAL_EvalMode_NULL, + EVAL_EvalMode_Value, + EVAL_EvalMode_Addr, + EVAL_EvalMode_Reg +} +EVAL_EvalMode; + +typedef struct EVAL_Expr EVAL_Expr; +struct EVAL_Expr{ + EVAL_ExprKind kind; + void *location; + union{ + EVAL_Expr *children[3]; + U32 u32; + U64 u64; + F32 f32; + F64 f64; + struct{ + EVAL_Expr *child; + U64 u64; + } child_and_constant; + String8 name; + struct{ + TG_Key type_key; + String8 bytecode; + EVAL_EvalMode mode; + }; + }; +}; + +global read_only EVAL_Expr eval_expr_nil = {0}; + +//////////////////////////////// +//~ allen: EVAL Compiler Types + +typedef struct EVAL_IRTree EVAL_IRTree; +struct EVAL_IRTree{ + RADDBG_EvalOp op; + EVAL_IRTree *children[3]; + union{ + U64 p; + String8 bytecode; + }; +}; + +global read_only EVAL_IRTree eval_irtree_nil = {0}; + +typedef struct EVAL_IRTreeAndType EVAL_IRTreeAndType; +struct EVAL_IRTreeAndType{ + EVAL_IRTree *tree; + TG_Key type_key; + EVAL_EvalMode mode; +}; + + +//////////////////////////////// +//~ allen: Eval Error Helpers + +internal void eval_error(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, String8 text); +internal void eval_errorf(Arena *arena, EVAL_ErrorList *list, EVAL_ErrorKind kind, void *location, char *fmt, ...); +internal void eval_error_list_concat_in_place(EVAL_ErrorList *dst, EVAL_ErrorList *to_push); + +//////////////////////////////// +//~ allen: EVAL Bytecode Helpers + +internal String8 eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list); + +internal void eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RADDBG_EvalOp op, U64 p); +internal void eval_oplist_push_uconst(Arena *arena, EVAL_OpList *list, U64 x); +internal void eval_oplist_push_sconst(Arena *arena, EVAL_OpList *list, S64 x); + +internal void eval_oplist_push_bytecode(Arena *arena, EVAL_OpList *list, String8 bytecode); + +internal void eval_oplist_concat_in_place(EVAL_OpList *left_dst, EVAL_OpList *right_destroyed); + +//////////////////////////////// +//~ allen: EVAL Expression Info Functions + +internal RADDBG_EvalOp eval_opcode_from_expr_kind(EVAL_ExprKind kind); +internal B32 eval_expr_kind_is_comparison(EVAL_ExprKind kind); + +//////////////////////////////// +//~ allen: EVAL Expression Constructors + +internal EVAL_Expr* eval_expr(Arena *arena, EVAL_ExprKind kind, void *location, EVAL_Expr *c0, EVAL_Expr *c1, EVAL_Expr *c2); +internal EVAL_Expr* eval_expr_u64(Arena *arena, void *location, U64 u64); +internal EVAL_Expr* eval_expr_f64(Arena *arena, void *location, F64 f64); +internal EVAL_Expr* eval_expr_f32(Arena *arena, void *location, F32 f32); +internal EVAL_Expr* eval_expr_child_and_u64(Arena *arena, EVAL_ExprKind kind, void *location, EVAL_Expr *child, U64 u64); +internal EVAL_Expr* eval_expr_leaf_member(Arena *arena, void *location, String8 name); +internal EVAL_Expr* eval_expr_leaf_bytecode(Arena *arena, void *location, TG_Key type_key, String8 bytecode, EVAL_EvalMode mode); +internal EVAL_Expr* eval_expr_leaf_op_list(Arena *arena, void *location, TG_Key type_key, EVAL_OpList *ops, EVAL_EvalMode mode); +internal EVAL_Expr* eval_expr_leaf_type(Arena *arena, void *location, TG_Key type_key); + +//////////////////////////////// +//~ allen: EVAL Type Information Transformers + +internal RADDBG_EvalTypeGroup eval_type_group_from_kind(TG_Kind kind); + +internal TG_Key eval_type_unwrap(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Key eval_type_unwrap_enum(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Key eval_type_promote(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Key eval_type_coerce(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r); + +internal B32 eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r); + +internal B32 eval_kind_is_integer(TG_Kind kind); +internal B32 eval_kind_is_signed(TG_Kind kind); +internal B32 eval_kind_is_basic_or_enum(TG_Kind kind); + +//////////////////////////////// +//~ allen: EVAL IR-Tree Constructors + +internal EVAL_IRTree* eval_irtree_const_u(Arena *arena, U64 v); +internal EVAL_IRTree* eval_irtree_unary_op(Arena *arena, RADDBG_EvalOp op, RADDBG_EvalTypeGroup group, EVAL_IRTree *c); +internal EVAL_IRTree* eval_irtree_binary_op(Arena *arena, RADDBG_EvalOp op, RADDBG_EvalTypeGroup group, EVAL_IRTree *l, EVAL_IRTree *r); +internal EVAL_IRTree* eval_irtree_binary_op_u(Arena *arena, RADDBG_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r); +internal EVAL_IRTree* eval_irtree_conditional(Arena *arena, EVAL_IRTree *c, EVAL_IRTree *l, EVAL_IRTree *r); +internal EVAL_IRTree* eval_irtree_bytecode_no_copy(Arena *arena, String8 bytecode); + +//////////////////////////////// +//~ allen: EVAL IR-Tree High Level Helpers + +internal EVAL_IRTree* eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key); +internal EVAL_IRTree* eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RADDBG_EvalTypeGroup out, RADDBG_EvalTypeGroup in); +internal EVAL_IRTree* eval_irtree_trunc(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key); +internal EVAL_IRTree* eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key out, TG_Key in); +internal EVAL_IRTree* eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_EvalMode from_mode, EVAL_IRTree *tree, TG_Key type_key); + +//////////////////////////////// +//~ allen: EVAL Compiler Phases + +internal TG_Key eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_Expr *expr, EVAL_ErrorList *eout); +internal EVAL_IRTreeAndType eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_Expr *expr, EVAL_ErrorList *eout); +internal void eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out); + +#endif //EVAL_COMPILER_H diff --git a/src/eval/eval_decode.c b/src/eval/eval_decode.c new file mode 100644 index 00000000..c465bef7 --- /dev/null +++ b/src/eval/eval_decode.c @@ -0,0 +1,50 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Eval Decode Function + +internal void +eval_print_decode_from_bytecode(FILE *out, String8 bytecode){ + U8 *ptr = bytecode.str; + U8 *opl = bytecode.str + bytecode.size; + + for (;ptr < opl;){ + // consume opcode + SYMS_EvalOp op = (SYMS_EvalOp)*ptr; + if (op >= SYMS_EvalOp_COUNT){ + fprintf(out, "decode error: undefined op code\n"); + goto done; + } + U8 ctrlbits = syms_eval_opcode_ctrlbits[op]; + ptr += 1; + + // decode + U64 imm = 0; + U32 decode_size = (ctrlbits >> SYMS_EvalOpCtrlBits_DecodeShft)&SYMS_EvalOpCtrlBits_DecodeMask; + { + U8 *next_ptr = ptr + decode_size; + if (next_ptr > opl){ + fprintf(out, "decode error: expected constant goes past the end of bytecode\n"); + goto done; + } + // TODO(allen): to improve this: + // gaurantee 8 bytes padding after the end of serialized bytecode + // read 8 bytes and mask + switch (decode_size){ + case 1: imm = *ptr; break; + case 2: imm = *(U16*)ptr; break; + case 4: imm = *(U32*)ptr; break; + case 8: imm = *(U64*)ptr; break; + } + ptr = next_ptr; + } + + // op string & control bits + SYMS_String8 op_string = syms_eval_opcode_strings[op]; + + // print + fprintf(out, "%.*s 0x%llx\n", str8_varg(op_string), imm); + } + done:; +} diff --git a/src/eval/eval_decode.h b/src/eval/eval_decode.h new file mode 100644 index 00000000..c6ebc743 --- /dev/null +++ b/src/eval/eval_decode.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef EVAL_DECODE_H +#define EVAL_DECODE_H + +//////////////////////////////// +// NOTE(allen): Eval Decode Function + +internal void eval_print_decode_from_bytecode(FILE *out, String8 bytecode); + +#endif //EVAL_DECODE_H diff --git a/src/eval/eval_machine.c b/src/eval/eval_machine.c new file mode 100644 index 00000000..8af94237 --- /dev/null +++ b/src/eval/eval_machine.c @@ -0,0 +1,630 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ allen: Eval Machine Functions + +internal EVAL_Result +eval_interpret(EVAL_Machine *machine, String8 bytecode){ + EVAL_Result result = {0}; + + // TODO(allen): We could scan the bytecode and figure out the + // maximum depth of the stack + Temp scratch = scratch_begin(0, 0); + U64 stack_cap = 128; + EVAL_Slot *stack = push_array_no_zero(scratch.arena, EVAL_Slot, stack_cap); + + U64 stack_count = 0; + U8 *ptr = bytecode.str; + U8 *opl = bytecode.str + bytecode.size; + + for (;ptr < opl;){ + // consume opcode + RADDBG_EvalOp op = (RADDBG_EvalOp)*ptr; + if (op >= RADDBG_EvalOp_COUNT){ + result.bad_eval = 1; + goto done; + } + U8 ctrlbits = raddbg_eval_opcode_ctrlbits[op]; + ptr += 1; + + // decode + U64 imm = 0; + { + U32 decode_size = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); + U8 *next_ptr = ptr + decode_size; + if (next_ptr > opl){ + result.bad_eval = 1; + goto done; + } + // TODO(allen): to improve this: + // gaurantee 8 bytes padding after the end of serialized bytecode + // read 8 bytes and mask + switch (decode_size){ + case 1: imm = *ptr; break; + case 2: imm = *(U16*)ptr; break; + case 4: imm = *(U32*)ptr; break; + case 8: imm = *(U64*)ptr; break; + } + ptr = next_ptr; + } + + // pop + EVAL_Slot *svals = 0; + { + U32 pop_count = RADDBG_POPN_FROM_CTRLBITS(ctrlbits); + if (pop_count > stack_count){ + result.bad_eval = 1; + goto done; + } + if (pop_count <= stack_count){ + stack_count -= pop_count; + svals = stack + stack_count; + } + } + + // interpret + EVAL_Slot nval = {0}; + switch (op){ + case RADDBG_EvalOp_Stop: + { + goto done; + }break; + + case RADDBG_EvalOp_Noop: + { + // do nothing + }break; + + case RADDBG_EvalOp_Cond: + { + if (svals[0].u64){ + ptr += imm; + } + }break; + + case RADDBG_EvalOp_Skip: + { + ptr += imm; + }break; + + case RADDBG_EvalOp_MemRead: + { + U64 addr = svals[0].u64; + U64 size = imm; + B32 good_read = 0; + if (machine->memory_read != 0 && + machine->memory_read(machine->u, &nval, addr, size)){ + good_read = 1; + } + if (!good_read){ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_RegRead: + { + U8 raddbg_reg_code = (imm&0x0000FF)>>0; + U8 byte_size = (imm&0x00FF00)>>8; + U8 byte_off = (imm&0xFF0000)>>16; + REGS_RegCode base_reg_code = regs_reg_code_from_arch_raddbg_code(machine->arch, raddbg_reg_code); + REGS_Rng rng = regs_reg_code_rng_table_from_architecture(machine->arch)[base_reg_code]; + U64 off = (U64)rng.byte_off + byte_off; + U64 size = (U64)byte_size; + if (off + size <= machine->reg_size){ + MemoryCopy(&nval, (U8*)machine->reg_data + off, size); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_RegReadDyn: + { + U64 off = svals[0].u64; + U64 size = bit_size_from_arch(machine->arch)/8; + if (off + size <= machine->reg_size){ + MemoryCopy(&nval, (U8*)machine->reg_data + off, size); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_FrameOff: + { + if (machine->frame_base != 0){ + nval.u64 = *machine->frame_base + imm; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_ModuleOff: + { + if (machine->module_base != 0){ + nval.u64 = *machine->module_base + imm; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_TLSOff: + { + if (machine->tls_base != 0){ + nval.u64 = *machine->tls_base + imm; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_ConstU8: + case RADDBG_EvalOp_ConstU16: + case RADDBG_EvalOp_ConstU32: + case RADDBG_EvalOp_ConstU64: + { + nval.u64 = imm; + }break; + + case RADDBG_EvalOp_Abs: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.f32 = svals[0].f32; + if (svals[0].f32 < 0){ + nval.f32 = -svals[0].f32; + } + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.f64 = svals[0].f64; + if (svals[0].f64 < 0){ + nval.f64 = -svals[0].f64; + } + } + else{ + nval.s64 = svals[0].s64; + if (svals[0].s64 < 0){ + nval.s64 = -svals[0].s64; + } + } + }break; + + case RADDBG_EvalOp_Neg: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.f32 = -svals[0].f32; + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.f64 = -svals[0].f64; + } + else{ + nval.u64 = (~svals[0].u64) + 1; + } + }break; + + case RADDBG_EvalOp_Add: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.f32 = svals[0].f32 + svals[1].f32; + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.f64 = svals[0].f64 + svals[1].f64; + } + else{ + nval.u64 = svals[0].u64 + svals[1].u64; + } + }break; + + case RADDBG_EvalOp_Sub: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.f32 = svals[0].f32 - svals[1].f32; + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.f64 = svals[0].f64 - svals[1].f64; + } + else{ + nval.u64 = svals[0].u64 - svals[1].u64; + } + }break; + + case RADDBG_EvalOp_Mul: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.f32 = svals[0].f32*svals[1].f32; + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.f64 = svals[0].f64*svals[1].f64; + } + else{ + nval.u64 = svals[0].u64*svals[1].u64; + } + }break; + + case RADDBG_EvalOp_Div: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + if (svals[1].f32 != 0.f){ + nval.f32 = svals[0].f32/svals[1].f32; + } + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + if (svals[1].f64 != 0.){ + nval.f64 = svals[0].f64/svals[1].f64; + } + } + else if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + if (svals[1].u64 != 0){ + nval.u64 = svals[0].u64/svals[1].u64; + } + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_Mod: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + if (svals[1].u64 != 0){ + nval.u64 = svals[0].u64%svals[1].u64; + } + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_LShift: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = svals[0].u64 << svals[1].u64; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_RShift: + { + if (imm == RADDBG_EvalTypeGroup_U){ + nval.u64 = svals[0].u64 >> svals[1].u64; + } + else if (imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = svals[0].s64 >> svals[1].u64; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_BitAnd: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = svals[0].u64&svals[1].u64; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_BitOr: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = svals[0].u64|svals[1].u64; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_BitXor: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = svals[0].u64^svals[1].u64; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_BitNot: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = ~svals[0].u64; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_LogAnd: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = (svals[0].u64 && svals[1].u64); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_LogOr: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = (svals[0].u64 || svals[1].u64); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_LogNot: + { + if (imm == RADDBG_EvalTypeGroup_U || + imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = (!svals[0].u64); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_EqEq: + { + nval.u64 = (svals[0].u64 == svals[1].u64); + }break; + + case RADDBG_EvalOp_NtEq: + { + nval.u64 = (svals[0].u64 != svals[1].u64); + }break; + + case RADDBG_EvalOp_LsEq: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.u64 = (svals[0].f32 <= svals[1].f32); + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.u64 = (svals[0].f64 <= svals[1].f64); + } + else if (imm == RADDBG_EvalTypeGroup_U){ + nval.u64 = (svals[0].u64 <= svals[1].u64); + } + else if (imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = (svals[0].s64 <= svals[1].s64); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_GrEq: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.u64 = (svals[0].f32 >= svals[1].f32); + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.u64 = (svals[0].f64 >= svals[1].f64); + } + else if (imm == RADDBG_EvalTypeGroup_U){ + nval.u64 = (svals[0].u64 >= svals[1].u64); + } + else if (imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = (svals[0].s64 >= svals[1].s64); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_Less: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.u64 = (svals[0].f32 < svals[1].f32); + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.u64 = (svals[0].f64 < svals[1].f64); + } + else if (imm == RADDBG_EvalTypeGroup_U){ + nval.u64 = (svals[0].u64 < svals[1].u64); + } + else if (imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = (svals[0].s64 < svals[1].s64); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_Grtr: + { + if (imm == RADDBG_EvalTypeGroup_F32){ + nval.u64 = (svals[0].f32 > svals[1].f32); + } + else if (imm == RADDBG_EvalTypeGroup_F64){ + nval.u64 = (svals[0].f64 > svals[1].f64); + } + else if (imm == RADDBG_EvalTypeGroup_U){ + nval.u64 = (svals[0].u64 > svals[1].u64); + } + else if (imm == RADDBG_EvalTypeGroup_S){ + nval.u64 = (svals[0].s64 > svals[1].s64); + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_Trunc: + { + if (0 < imm){ + U64 mask = 0; + if (imm < 64){ + mask = max_U64 >> (64 - imm); + } + nval.u64 = svals[0].u64&mask; + } + }break; + + case RADDBG_EvalOp_TruncSigned: + { + if (0 < imm){ + U64 mask = 0; + if (imm < 64){ + mask = max_U64 >> (64 - imm); + } + U64 high = 0; + if (svals[0].u64 & (1 << (imm - 1))){ + high = ~mask; + } + nval.u64 = high|(svals[0].u64&mask); + } + }break; + + case RADDBG_EvalOp_Convert: + { + U32 in = imm&0xFF; + U32 out = (imm >> 8)&0xFF; + if (in != out){ + switch (in + out*RADDBG_EvalTypeGroup_COUNT){ + case RADDBG_EvalTypeGroup_F32 + RADDBG_EvalTypeGroup_U*RADDBG_EvalTypeGroup_COUNT: + { + nval.u64 = (U64)svals[0].f32; + }break; + case RADDBG_EvalTypeGroup_F64 + RADDBG_EvalTypeGroup_U*RADDBG_EvalTypeGroup_COUNT: + { + nval.u64 = (U64)svals[0].f64; + }break; + + case RADDBG_EvalTypeGroup_F32 + RADDBG_EvalTypeGroup_S*RADDBG_EvalTypeGroup_COUNT: + { + nval.s64 = (S64)svals[0].f32; + }break; + case RADDBG_EvalTypeGroup_F64 + RADDBG_EvalTypeGroup_S*RADDBG_EvalTypeGroup_COUNT: + { + nval.s64 = (S64)svals[0].f64; + }break; + + case RADDBG_EvalTypeGroup_U + RADDBG_EvalTypeGroup_F32*RADDBG_EvalTypeGroup_COUNT: + { + nval.f32 = (F32)svals[0].u64; + }break; + case RADDBG_EvalTypeGroup_S + RADDBG_EvalTypeGroup_F32*RADDBG_EvalTypeGroup_COUNT: + { + nval.f32 = (F32)svals[0].s64; + }break; + case RADDBG_EvalTypeGroup_F64 + RADDBG_EvalTypeGroup_F32*RADDBG_EvalTypeGroup_COUNT: + { + nval.f32 = (F32)svals[0].f64; + }break; + + case RADDBG_EvalTypeGroup_U + RADDBG_EvalTypeGroup_F64*RADDBG_EvalTypeGroup_COUNT: + { + nval.f64 = (F64)svals[0].u64; + }break; + case RADDBG_EvalTypeGroup_S + RADDBG_EvalTypeGroup_F64*RADDBG_EvalTypeGroup_COUNT: + { + nval.f64 = (F64)svals[0].s64; + }break; + case RADDBG_EvalTypeGroup_F32 + RADDBG_EvalTypeGroup_F64*RADDBG_EvalTypeGroup_COUNT: + { + nval.f64 = (F64)svals[0].f32; + }break; + } + } + }break; + + case RADDBG_EvalOp_Pick: + { + if (stack_count > imm){ + nval = stack[stack_count - imm - 1]; + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + + case RADDBG_EvalOp_Pop: + { + // do nothing - the pop is handled by the control bits + }break; + + case RADDBG_EvalOp_Insert: + { + if (stack_count > imm){ + if (imm > 0){ + EVAL_Slot tval = stack[stack_count - 1]; + EVAL_Slot *dst = stack + stack_count - 1 - imm; + EVAL_Slot *shift = dst + 1; + MemoryCopy(shift, dst, imm*sizeof(EVAL_Slot)); + *dst = tval; + } + } + else{ + result.bad_eval = 1; + goto done; + } + }break; + } + + // push + { + U64 push_count = RADDBG_PUSHN_FROM_CTRLBITS(ctrlbits); + if (push_count == 1){ + if (stack_count < stack_cap){ + stack[stack_count] = nval; + stack_count += 1; + } + else{ + result.bad_eval = 1; + goto done; + } + } + } + + } + done:; + + if (stack_count == 1){ + result.value = stack[0]; + } + else{ + result.bad_eval = 1; + } + + scratch_end(scratch); + return(result); +} \ No newline at end of file diff --git a/src/eval/eval_machine.h b/src/eval/eval_machine.h new file mode 100644 index 00000000..b520629e --- /dev/null +++ b/src/eval/eval_machine.h @@ -0,0 +1,45 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef EVAL2_MACHINE_H +#define EVAL2_MACHINE_H + +//////////////////////////////// +//~ allen: Eval Machine Types + +typedef B32 EVAL_MemoryRead(void *u, void *out, U64 addr, U64 size); + +typedef struct EVAL_Machine EVAL_Machine; +struct EVAL_Machine{ + void *u; + Architecture arch; + EVAL_MemoryRead *memory_read; + void *reg_data; + U64 reg_size; + U64 *module_base; + U64 *frame_base; + U64 *tls_base; +}; + +typedef union EVAL_Slot EVAL_Slot; +union EVAL_Slot{ + U64 u256[4]; + U64 u128[2]; + U64 u64; + S64 s64; + F64 f64; + F32 f32; +}; + +typedef struct EVAL_Result EVAL_Result; +struct EVAL_Result{ + EVAL_Slot value; + B32 bad_eval; +}; + +//////////////////////////////// +//~ allen: Eval Machine Functions + +internal EVAL_Result eval_interpret(EVAL_Machine *machine, String8 bytecode); + +#endif //EVAL2_MACHINE_H diff --git a/src/eval/eval_parser.c b/src/eval/eval_parser.c new file mode 100644 index 00000000..58e80acf --- /dev/null +++ b/src/eval/eval_parser.c @@ -0,0 +1,1372 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Tables + +global read_only String8 eval_g_multichar_symbol_strings[] = +{ + str8_lit_comp("<<"), + str8_lit_comp(">>"), + str8_lit_comp("->"), + str8_lit_comp("<="), + str8_lit_comp(">="), + str8_lit_comp("=="), + str8_lit_comp("!="), + str8_lit_comp("&&"), + str8_lit_comp("||"), +}; + +global read_only struct {EVAL_ExprKind kind; String8 string; S64 precedence;} eval_g_unary_prefix_op_table[] = +{ + // { EVAL_ExprKind_???, str8_lit_comp("+"), 2 }, + { EVAL_ExprKind_Neg, str8_lit_comp("-"), 2 }, + { EVAL_ExprKind_LogNot, str8_lit_comp("!"), 2 }, + { EVAL_ExprKind_Deref, str8_lit_comp("*"), 2 }, + { EVAL_ExprKind_Address,str8_lit_comp("&"), 2 }, + { EVAL_ExprKind_Sizeof, str8_lit_comp("sizeof"), 2 }, + // { EVAL_ExprKind_Alignof, str8_lit_comp("_Alignof"), 2 }, +}; + +global read_only struct {EVAL_ExprKind kind; String8 string; S64 precedence;} eval_g_binary_op_table[] = +{ + { EVAL_ExprKind_Mul, str8_lit_comp("*"), 3 }, + { EVAL_ExprKind_Div, str8_lit_comp("/"), 3 }, + { EVAL_ExprKind_Mod, str8_lit_comp("%"), 3 }, + { EVAL_ExprKind_Add, str8_lit_comp("+"), 4 }, + { EVAL_ExprKind_Sub, str8_lit_comp("-"), 4 }, + { EVAL_ExprKind_LShift, str8_lit_comp("<<"), 5 }, + { EVAL_ExprKind_RShift, str8_lit_comp(">>"), 5 }, + { EVAL_ExprKind_Less, str8_lit_comp("<"), 6 }, + { EVAL_ExprKind_LsEq, str8_lit_comp("<="), 6 }, + { EVAL_ExprKind_Grtr, str8_lit_comp(">"), 6 }, + { EVAL_ExprKind_GrEq, str8_lit_comp(">="), 6 }, + { EVAL_ExprKind_EqEq, str8_lit_comp("=="), 7 }, + { EVAL_ExprKind_NtEq, str8_lit_comp("!="), 7 }, + { EVAL_ExprKind_BitAnd, str8_lit_comp("&"), 8 }, + { EVAL_ExprKind_BitXor, str8_lit_comp("^"), 9 }, + { EVAL_ExprKind_BitOr, str8_lit_comp("|"), 10 }, + { EVAL_ExprKind_LogAnd, str8_lit_comp("&&"), 11 }, + { EVAL_ExprKind_LogOr, str8_lit_comp("||"), 12 }, +}; + +global read_only S64 eval_g_max_precedence = 15; + +//////////////////////////////// +//~ rjf: Basic Functions + +internal U64 +eval_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +//////////////////////////////// +//~ rjf: Map Functions + +internal EVAL_String2NumMap +eval_string2num_map_make(Arena *arena, U64 slot_count) +{ + EVAL_String2NumMap map = {0}; + map.slots_count = slot_count; + map.slots = push_array(arena, EVAL_String2NumMapSlot, map.slots_count); + return map; +} + +internal void +eval_string2num_map_insert(Arena *arena, EVAL_String2NumMap *map, String8 string, U64 num) +{ + U64 hash = eval_hash_from_string(string); + U64 slot_idx = hash%map->slots_count; + EVAL_String2NumMapNode *existing_node = 0; + for(EVAL_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->next) + { + if(str8_match(node->string, string, 0) && node->num == num) + { + existing_node = node; + break; + } + } + if(existing_node == 0) + { + EVAL_String2NumMapNode *node = push_array(arena, EVAL_String2NumMapNode, 1); + SLLQueuePush(map->slots[slot_idx].first, map->slots[slot_idx].last, node); + node->string = string; + node->num = num; + } +} + +internal U64 +eval_num_from_string(EVAL_String2NumMap *map, String8 string) +{ + U64 num = 0; + if(map->slots_count != 0) + { + U64 hash = eval_hash_from_string(string); + U64 slot_idx = hash%map->slots_count; + EVAL_String2NumMapNode *existing_node = 0; + for(EVAL_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->next) + { + if(str8_match(node->string, string, 0)) + { + existing_node = node; + break; + } + } + if(existing_node != 0) + { + num = existing_node->num; + } + } + return num; +} + +//////////////////////////////// +//~ rjf: Map Building Fast Paths + +internal EVAL_String2NumMap * +eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff) +{ + //- rjf: voff -> tightest scope + RADDBG_Scope *tightest_scope = 0; + if(rdbg->scope_vmap != 0 && rdbg->scopes != 0) + { + U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff); + tightest_scope = &rdbg->scopes[scope_idx]; + } + + //- rjf: build blank map + EVAL_String2NumMap *map = push_array(arena, EVAL_String2NumMap, 1); + *map = eval_string2num_map_make(arena, 1024); + + //- rjf: tightest scope -> walk up the tree & accumulate all locals + for(RADDBG_Scope *scope = tightest_scope; + scope != 0 && scope != &rdbg->scopes[0]; + scope = &rdbg->scopes[scope->parent_scope_idx]) + { + U32 local_opl_idx = scope->local_first + scope->local_count; + for(U32 local_idx = scope->local_first; local_idx < local_opl_idx; local_idx += 1) + { + RADDBG_Local *local_var = &rdbg->locals[local_idx]; + U64 local_name_size = 0; + U8 *local_name_str = raddbg_string_from_idx(rdbg, local_var->name_string_idx, &local_name_size); + String8 name = push_str8_copy(arena, str8(local_name_str, local_name_size)); + eval_string2num_map_insert(arena, map, name, (U64)local_idx+1); + } + } + + return map; +} + +internal EVAL_String2NumMap * +eval_push_member_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff) +{ + //- rjf: voff -> tightest scope + RADDBG_Scope *tightest_scope = 0; + if(rdbg->scope_vmap != 0 && rdbg->scopes != 0) + { + U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff); + tightest_scope = &rdbg->scopes[scope_idx]; + } + + //- rjf: tightest scope -> procedure + RADDBG_Procedure *procedure = 0; + if(tightest_scope != 0 && rdbg->procedures != 0) + { + U32 proc_idx = tightest_scope->proc_idx; + if(0 < proc_idx && proc_idx < rdbg->procedure_count) + { + procedure = &rdbg->procedures[proc_idx]; + } + } + + //- rjf: procedure -> udt + RADDBG_UDT *udt = 0; + if(procedure != 0 && rdbg->udts != 0 && procedure->link_flags & RADDBG_LinkFlag_TypeScoped) + { + U32 udt_idx = procedure->container_idx; + if(0 < udt_idx && udt_idx < rdbg->udt_count) + { + udt = &rdbg->udts[udt_idx]; + } + } + + //- rjf: build blank map + EVAL_String2NumMap *map = push_array(arena, EVAL_String2NumMap, 1); + *map = eval_string2num_map_make(arena, 64); + + //- rjf: udt -> fill member map + if(udt != 0 && !(udt->flags & RADDBG_UserDefinedTypeFlag_EnumMembers) && rdbg->members != 0) + { + U64 data_member_num = 1; + for(U32 member_idx = udt->member_first; + member_idx < udt->member_first+udt->member_count; + member_idx += 1) + { + if(member_idx < 1 || rdbg->member_count <= member_idx) + { + break; + } + RADDBG_Member *m = &rdbg->members[member_idx]; + if(m->kind == RADDBG_MemberKind_DataField) + { + String8 name = {0}; + name.str = raddbg_string_from_idx(rdbg, m->name_string_idx, &name.size); + eval_string2num_map_insert(arena, map, name, data_member_num); + data_member_num += 1; + } + } + } + + return map; +} + +//////////////////////////////// +//~ rjf: Tokenization Functions + +internal EVAL_Token +eval_token_zero(void) +{ + EVAL_Token token = zero_struct; + return token; +} + +internal void +eval_token_chunk_list_push(Arena *arena, EVAL_TokenChunkList *list, U64 chunk_size, EVAL_Token *token) +{ + EVAL_TokenChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, EVAL_TokenChunkNode, 1); + SLLQueuePush(list->first, list->last, node); + node->cap = chunk_size; + node->v = push_array_no_zero(arena, EVAL_Token, node->cap); + list->node_count += 1; + } + MemoryCopyStruct(&node->v[node->count], token); + node->count += 1; + list->total_count += 1; +} + +internal EVAL_TokenArray +eval_token_array_from_chunk_list(Arena *arena, EVAL_TokenChunkList *list) +{ + EVAL_TokenArray array = {0}; + array.count = list->total_count; + array.v = push_array_no_zero(arena, EVAL_Token, array.count); + U64 idx = 0; + for(EVAL_TokenChunkNode *node = list->first; node != 0; node = node->next) + { + MemoryCopy(array.v+idx, node->v, sizeof(EVAL_Token)*node->count); + } + return array; +} + +internal EVAL_TokenArray +eval_token_array_from_text(Arena *arena, String8 text) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: lex loop + EVAL_TokenChunkList tokens = {0}; + U64 active_token_start_idx = 0; + EVAL_TokenKind active_token_kind = EVAL_TokenKind_Null; + B32 escaped = 0; + for(U64 idx = 0, advance = 0; idx <= text.size; idx += advance) + { + U8 byte = (idx+0 < text.size) ? text.str[idx+0] : 0; + U8 byte_next = (idx+1 < text.size) ? text.str[idx+1] : 0; + U8 byte_next2= (idx+2 < text.size) ? text.str[idx+2] : 0; + advance = 1; + B32 token_formed = 0; + U64 token_end_idx_pad = 0; + switch(active_token_kind) + { + //- rjf: no active token -> seek token starter + default: + { + if(char_is_alpha(byte) || byte == '_') + { + active_token_kind = EVAL_TokenKind_Identifier; + active_token_start_idx = idx; + } + else if(char_is_digit(byte, 10) || (byte == '.' && char_is_digit(byte_next, 10))) + { + active_token_kind = EVAL_TokenKind_Numeric; + active_token_start_idx = idx; + } + else if(byte == '"') + { + active_token_kind = EVAL_TokenKind_StringLiteral; + active_token_start_idx = idx; + } + else if(byte == '\'') + { + active_token_kind = EVAL_TokenKind_CharLiteral; + active_token_start_idx = idx; + } + else if(byte == '~' || byte == '!' || byte == '%' || byte == '^' || + byte == '&' || byte == '*' || byte == '(' || byte == ')' || + byte == '-' || byte == '=' || byte == '+' || byte == '[' || + byte == ']' || byte == '{' || byte == '}' || byte == ':' || + byte == ';' || byte == ',' || byte == '.' || byte == '<' || + byte == '>' || byte == '/' || byte == '?' || byte == '|') + { + active_token_kind = EVAL_TokenKind_Symbol; + active_token_start_idx = idx; + } + }break; + + //- rjf: active tokens -> seek enders + case EVAL_TokenKind_Identifier: + { + if(byte == ':' && byte_next == ':' && (char_is_alpha(byte_next2) || byte_next2 == '_')) + { + // NOTE(rjf): encountering C++-style namespaces - skip over scope resolution symbol + // & keep going. + advance = 2; + } + else if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_') + { + advance = 0; + token_formed = 1; + } + }break; + case EVAL_TokenKind_Numeric: + { + if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.') + { + advance = 0; + token_formed = 1; + } + }break; + case EVAL_TokenKind_StringLiteral: + { + if(escaped == 0 && byte == '\\') + { + escaped = 1; + } + else if(escaped) + { + escaped = 0; + } + else if(escaped == 0 && byte == '"') + { + advance = 1; + token_formed = 1; + token_end_idx_pad = 1; + } + }break; + case EVAL_TokenKind_CharLiteral: + { + if(escaped == 0 && byte == '\\') + { + escaped = 1; + } + else if(escaped) + { + escaped = 0; + } + else if(escaped == 0 && byte == '\'') + { + advance = 1; + token_formed = 1; + token_end_idx_pad = 1; + } + }break; + case EVAL_TokenKind_Symbol: + { + if(byte != '~' && byte != '!' && byte != '%' && byte != '^' && + byte != '&' && byte != '*' && byte != '(' && byte != ')' && + byte != '-' && byte != '=' && byte != '+' && byte != '[' && + byte != ']' && byte != '{' && byte != '}' && byte != ':' && + byte != ';' && byte != ',' && byte != '.' && byte != '<' && + byte != '>' && byte != '/' && byte != '?' && byte != '|') + { + advance = 0; + token_formed = 1; + } + }break; + } + + //- rjf: token formed -> push new formed token(s) + if(token_formed) + { + // rjf: non-symbols *or* symbols of only 1-length can be immediately + // pushed as a token + if(active_token_kind != EVAL_TokenKind_Symbol || idx==active_token_start_idx+1) + { + EVAL_Token token = {active_token_kind, r1u64(active_token_start_idx, idx+token_end_idx_pad)}; + eval_token_chunk_list_push(scratch.arena, &tokens, 256, &token); + } + + // rjf: if we got a symbol string of N>1 characters, then we need to + // apply the maximum-munch rule, and produce M<=N tokens, where each + // formed token is the maximum size possible, given the legal + // >1-length symbol strings. + else + { + U64 advance2 = 0; + for(U64 idx2 = active_token_start_idx; idx2 < idx; idx2 += advance2) + { + advance2 = 1; + for(U64 multichar_symbol_idx = 0; + multichar_symbol_idx < ArrayCount(eval_g_multichar_symbol_strings); + multichar_symbol_idx += 1) + { + String8 multichar_symbol_string = eval_g_multichar_symbol_strings[multichar_symbol_idx]; + String8 part_of_token = str8_substr(text, r1u64(idx2, idx2+multichar_symbol_string.size)); + if(str8_match(part_of_token, multichar_symbol_string, 0)) + { + advance2 = multichar_symbol_string.size; + break; + } + } + EVAL_Token token = {active_token_kind, r1u64(idx2, idx2+advance2)}; + eval_token_chunk_list_push(scratch.arena, &tokens, 256, &token); + } + } + + // rjf: reset for subsequent tokens. + active_token_kind = EVAL_TokenKind_Null; + } + } + + //- rjf: chunk list -> array & return + EVAL_TokenArray array = eval_token_array_from_chunk_list(arena, &tokens); + scratch_end(scratch); + return array; +} + +internal EVAL_TokenArray +eval_token_array_make_first_opl(EVAL_Token *first, EVAL_Token *opl) +{ + EVAL_TokenArray array = {first, (U64)(opl-first)}; + return array; +} + +//////////////////////////////// +//~ rjf: Parser Functions + +internal TG_Key +eval_leaf_type_from_name(RADDBG_Parsed *rdbg, String8 name) +{ + TG_Key key = zero_struct; + B32 found = 0; + if(rdbg->type_nodes != 0) + { + RADDBG_NameMap *name_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Types); + RADDBG_ParsedNameMap parsed_name_map = {0}; + raddbg_name_map_parse(rdbg, name_map, &parsed_name_map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &parsed_name_map, name.str, name.size); + if(node != 0) + { + U32 match_count = 0; + U32 *matches = raddbg_matches_from_map_node(rdbg, node, &match_count); + if(match_count != 0) + { + U32 type_node_idx = matches[0]; + if(type_node_idx < rdbg->type_node_count) + { + RADDBG_TypeNode *type_node = &rdbg->type_nodes[type_node_idx]; + key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_node_idx); + found = 1; + } + } + } + } + if(!found) + { +#define Case(str) (str8_match(name, str8_lit(str), 0)) + if(Case("u8") || Case("uint8") || Case("uint8_t") || Case("uchar8") || Case("U8")) + { + key = tg_key_basic(TG_Kind_U8); + } + else if(Case("u16") || Case("uint16") || Case("uint16_t") || Case("uchar16") || Case("U16")) + { + key = tg_key_basic(TG_Kind_U16); + } + else if(Case("u32") || Case("uint32") || Case("uint32_t") || Case("uchar32") || Case("U32") || Case("uint")) + { + key = tg_key_basic(TG_Kind_U32); + } + else if(Case("u64") || Case("uint64") || Case("uint64_t") || Case("U64")) + { + key = tg_key_basic(TG_Kind_U64); + } + else if(Case("s8") || Case("b8") || Case("B8") || Case("i8") || Case("int8") || Case("int8_t") || Case("char8") || Case("S8")) + { + key = tg_key_basic(TG_Kind_S8); + } + else if(Case("s16") ||Case("b16") || Case("B16") || Case("i16") || Case("int16") || Case("int16_t") || Case("char16") || Case("S16")) + { + key = tg_key_basic(TG_Kind_S16); + } + else if(Case("s32") || Case("b32") || Case("B32") || Case("i32") || Case("int32") || Case("int32_t") || Case("char32") || Case("S32") || Case("int")) + { + key = tg_key_basic(TG_Kind_S32); + } + else if(Case("s64") || Case("b64") || Case("B64") || Case("i64") || Case("int64") || Case("int64_t") || Case("S64")) + { + key = tg_key_basic(TG_Kind_S64); + } + else if(Case("void")) + { + key = tg_key_basic(TG_Kind_Void); + } + else if(Case("bool")) + { + key = tg_key_basic(TG_Kind_Bool); + } + else if(Case("float") || Case("f32") || Case("F32") || Case("r32") || Case("R32")) + { + key = tg_key_basic(TG_Kind_F32); + } + else if(Case("double") || Case("f64") || Case("F64") || Case("r64") || Case("R64")) + { + key = tg_key_basic(TG_Kind_F64); + } +#undef Case + } + return key; +} + +internal EVAL_ParseResult +eval_parse_type_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens) +{ + EVAL_ParseResult parse = eval_parse_result_nil; + EVAL_Token *token_it = tokens->v; + + //- rjf: parse unsigned marker + B32 unsigned_marker = 0; + { + EVAL_Token token = eval_token_at_it(token_it, tokens); + if(token.kind == EVAL_TokenKind_Identifier) + { + String8 token_string = str8_substr(text, token.range); + if(str8_match(token_string, str8_lit("unsigned"), 0)) + { + token_it += 1; + unsigned_marker = 1; + } + } + } + + //- rjf: parse base type + { + EVAL_Token token = eval_token_at_it(token_it, tokens); + if(token.kind == EVAL_TokenKind_Identifier) + { + String8 token_string = str8_substr(text, token.range); + TG_Key type_key = eval_leaf_type_from_name(ctx->rdbg, token_string); + if(!tg_key_match(tg_key_zero(), type_key)) + { + token_it += 1; + + // rjf: apply unsigned marker to base type + if(unsigned_marker) switch(tg_kind_from_key(type_key)) + { + default:{}break; + case TG_Kind_Char8: {type_key = tg_key_basic(TG_Kind_UChar8);}break; + case TG_Kind_Char16:{type_key = tg_key_basic(TG_Kind_UChar16);}break; + case TG_Kind_Char32:{type_key = tg_key_basic(TG_Kind_UChar32);}break; + case TG_Kind_S8: {type_key = tg_key_basic(TG_Kind_U8);}break; + case TG_Kind_S16: {type_key = tg_key_basic(TG_Kind_U16);}break; + case TG_Kind_S32: {type_key = tg_key_basic(TG_Kind_U32);}break; + case TG_Kind_S64: {type_key = tg_key_basic(TG_Kind_U64);}break; + case TG_Kind_S128:{type_key = tg_key_basic(TG_Kind_U128);}break; + case TG_Kind_S256:{type_key = tg_key_basic(TG_Kind_U256);}break; + case TG_Kind_S512:{type_key = tg_key_basic(TG_Kind_U512);}break; + } + + // rjf: construct leaf type + parse.expr = eval_expr_leaf_type(arena, token_string.str, type_key); + } + } + } + + //- rjf: parse extensions + if(parse.expr != &eval_expr_nil) + { + for(;;) + { + EVAL_Token token = eval_token_at_it(token_it, tokens); + if(token.kind != EVAL_TokenKind_Symbol) + { + break; + } + String8 token_string = str8_substr(text, token.range); + if(str8_match(token_string, str8_lit("*"), 0)) + { + token_it += 1; + parse.expr = eval_expr(arena, EVAL_ExprKind_Ptr, token_string.str, parse.expr, 0, 0); + } + else + { + break; + } + } + } + + //- rjf: fill parse & end + parse.last_token = token_it; + return parse; +} + +internal EVAL_ParseResult +eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens, S64 max_precedence) +{ + Temp scratch = scratch_begin(&arena, 1); + EVAL_Token *it = tokens->v; + EVAL_Token *it_opl = tokens->v + tokens->count; + EVAL_ParseResult result = eval_parse_result_nil; + + //- rjf: parse prefix unaries + typedef struct PrefixUnaryNode PrefixUnaryNode; + struct PrefixUnaryNode + { + PrefixUnaryNode *next; + EVAL_ExprKind kind; + EVAL_Expr *cast_expr; + void *location; + }; + PrefixUnaryNode *first_prefix_unary = 0; + PrefixUnaryNode *last_prefix_unary = 0; + { + for(;it < it_opl;) + { + EVAL_Token *start_it = it; + EVAL_Token token = eval_token_at_it(it, tokens); + String8 token_string = str8_substr(text, token.range); + S64 prefix_unary_precedence = 0; + EVAL_ExprKind prefix_unary_kind = 0; + EVAL_Expr *cast_expr = &eval_expr_nil; + void *location = 0; + + // rjf: try op table + for(U64 idx = 0; idx < ArrayCount(eval_g_unary_prefix_op_table); idx += 1) + { + if(str8_match(token_string, eval_g_unary_prefix_op_table[idx].string, 0)) + { + prefix_unary_precedence = eval_g_unary_prefix_op_table[idx].precedence; + prefix_unary_kind = eval_g_unary_prefix_op_table[idx].kind; + break; + } + } + + // rjf: consume valid op + if(prefix_unary_precedence != 0) + { + location = token_string.str; + it += 1; + } + + // rjf: try casting expression + if(prefix_unary_precedence == 0 && str8_match(token_string, str8_lit("("), 0)) + { + EVAL_Token some_type_identifier_maybe = eval_token_at_it(it+1, tokens); + String8 some_type_identifier_maybe_string = str8_substr(text, some_type_identifier_maybe.range); + if(some_type_identifier_maybe.kind == EVAL_TokenKind_Identifier) + { + TG_Key type_key = eval_leaf_type_from_name(ctx->rdbg, some_type_identifier_maybe_string); + if(!tg_key_match(type_key, tg_key_zero()) || str8_match(some_type_identifier_maybe_string, str8_lit("unsigned"), 0)) + { + // rjf: move past open paren + it += 1; + + // rjf: parse type expr + EVAL_TokenArray type_parse_tokens = eval_token_array_make_first_opl(it, it_opl); + EVAL_ParseResult type_parse = eval_parse_type_from_text_tokens(arena, ctx, text, &type_parse_tokens); + EVAL_Expr *type = type_parse.expr; + eval_error_list_concat_in_place(&result.errors, &type_parse.errors); + it = type_parse.last_token; + location = token_string.str; + + // rjf: expect ) + EVAL_Token close_paren_maybe = eval_token_at_it(it, tokens); + String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); + if(close_paren_maybe.kind != EVAL_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Missing )."); + } + + // rjf: consume ) + else + { + it += 1; + } + + // rjf: fill + prefix_unary_precedence = 2; + prefix_unary_kind = EVAL_ExprKind_Cast; + cast_expr = type; + } + } + } + + // rjf: break if we got no operators + if(prefix_unary_precedence == 0) + { + break; + } + + // rjf: break if the token node iterator has not changed + if(it == start_it) + { + break; + } + + // rjf: push prefix unary if we got one + { + PrefixUnaryNode *op_n = push_array(scratch.arena, PrefixUnaryNode, 1); + op_n->kind = prefix_unary_kind; + op_n->cast_expr = cast_expr; + op_n->location = location; + SLLQueuePushFront(first_prefix_unary, last_prefix_unary, op_n); + } + } + } + + //- rjf: parse atom + EVAL_Expr *atom = &eval_expr_nil; + String8 atom_implicit_member_name = {0}; + if(it < it_opl) + { + EVAL_Token token = eval_token_at_it(it, tokens); + String8 token_string = str8_substr(text, token.range); + + //- rjf: descent to nested expression + if(token.kind == EVAL_TokenKind_Symbol && str8_match(token_string, str8_lit("("), 0)) + { + // rjf: skip ( + it += 1; + + // rjf: parse () contents + EVAL_TokenArray nested_parse_tokens = eval_token_array_make_first_opl(it, it_opl); + EVAL_ParseResult nested_parse = eval_parse_expr_from_text_tokens__prec(arena, ctx, text, &nested_parse_tokens, eval_g_max_precedence); + eval_error_list_concat_in_place(&result.errors, &nested_parse.errors); + atom = nested_parse.expr; + it = nested_parse.last_token; + + // rjf: expect ) + EVAL_Token close_paren_maybe = eval_token_at_it(it, tokens); + String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); + if(close_paren_maybe.kind != EVAL_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Missing )."); + } + + // rjf: consume ) + else + { + it += 1; + } + } + + //- rjf: leaf (identifier, literal) + else if(token.kind != EVAL_TokenKind_Symbol) + { + switch(token.kind) + { + //- rjf: identifier => name resolution + default: + case EVAL_TokenKind_Identifier: + { + B32 mapped_identifier = 0; + B32 identifier_looks_like_type_expr = 0; + RADDBG_LocationKind loc_kind = RADDBG_LocationKind_NULL; + RADDBG_LocationRegister loc_reg = {0}; + RADDBG_LocationRegisterPlusU16 loc_reg_u16 = {0}; + String8 loc_bytecode = {0}; + REGS_RegCode reg_code = 0; + REGS_AliasCode alias_code = 0; + TG_Key type_key = zero_struct; + String8 local_lookup_string = token_string; + + //- rjf: try members + if(mapped_identifier == 0) + { + U64 data_member_num = eval_num_from_string(ctx->member_map, token_string); + if(data_member_num != 0) + { + atom_implicit_member_name = token_string; + local_lookup_string = str8_lit("this"); + } + } + + //- rjf: try locals + if(mapped_identifier == 0) + { + U64 local_num = eval_num_from_string(ctx->locals_map, local_lookup_string); + if(local_num != 0 && + ctx->rdbg->locals != 0 && (1 <= local_num && local_num <= ctx->rdbg->local_count) && + ctx->rdbg->type_nodes != 0) + { + mapped_identifier = 1; + RADDBG_Local *local_var = &ctx->rdbg->locals[local_num-1]; + + // rjf: grab location info + for(U32 loc_block_idx = local_var->location_first; + loc_block_idx < local_var->location_opl; + loc_block_idx += 1) + { + RADDBG_LocationBlock *block = &ctx->rdbg->location_blocks[loc_block_idx]; + if(block->scope_off_first <= ctx->ip_voff && ctx->ip_voff < block->scope_off_opl) + { + loc_kind = *((RADDBG_LocationKind *)(ctx->rdbg->location_data + block->location_data_off)); + switch(loc_kind) + { + default:{mapped_identifier = 0;}break; + case RADDBG_LocationKind_AddrBytecodeStream: + case RADDBG_LocationKind_ValBytecodeStream: + { + U8 *bytecode_base = ctx->rdbg->location_data + block->location_data_off + sizeof(RADDBG_LocationKind); + loc_bytecode = str8_cstring((char *)bytecode_base); + }break; + case RADDBG_LocationKind_AddrRegisterPlusU16: + case RADDBG_LocationKind_AddrAddrRegisterPlusU16: + { + MemoryCopy(&loc_reg_u16, (ctx->rdbg->location_data + block->location_data_off), sizeof(loc_reg_u16)); + }break; + case RADDBG_LocationKind_ValRegister: + { + MemoryCopy(&loc_reg, (ctx->rdbg->location_data + block->location_data_off), sizeof(loc_reg)); + }break; + } + } + } + + // rjf: get type + if(0 <= local_var->type_idx && local_var->type_idx < ctx->rdbg->type_node_count) + { + U32 type_idx = local_var->type_idx; + RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; + type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_idx); + } + } + } + + //- rjf: try registers + if(mapped_identifier == 0) + { + U64 reg_num = eval_num_from_string(ctx->regs_map, token_string); + if(reg_num != 0) + { + reg_code = reg_num; + mapped_identifier = 1; + type_key = tg_key_reg(ctx->arch, reg_code); + } + } + + //- rjf: try register aliases + if(mapped_identifier == 0) + { + U64 alias_num = eval_num_from_string(ctx->reg_alias_map, token_string); + if(alias_num != 0) + { + alias_code = (REGS_AliasCode)alias_num; + type_key = tg_key_reg_alias(ctx->arch, alias_code); + mapped_identifier = 1; + } + } + + //- rjf: try global variables + if(mapped_identifier == 0) + { + RADDBG_NameMap *name_map = raddbg_name_map_from_kind(ctx->rdbg, RADDBG_NameMapKind_GlobalVariables); + if(name_map != 0 && ctx->rdbg->global_variables != 0) + { + RADDBG_ParsedNameMap parsed_name_map = {0}; + raddbg_name_map_parse(ctx->rdbg, name_map, &parsed_name_map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, token_string.str, token_string.size); + U32 matches_count = 0; + U32 *matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + if(matches_count != 0) + { + U32 match_idx = matches[0]; + RADDBG_GlobalVariable *global_var = &ctx->rdbg->global_variables[match_idx]; + EVAL_OpList oplist = {0}; + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ModuleOff, global_var->voff); + loc_kind = RADDBG_LocationKind_AddrBytecodeStream; + loc_bytecode = eval_bytecode_from_oplist(arena, &oplist); + U32 type_idx = global_var->type_idx; + if(type_idx < ctx->rdbg->type_node_count) + { + RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; + type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_idx); + } + mapped_identifier = 1; + } + } + } + + //- rjf: try thread variables + if(mapped_identifier == 0) + { + RADDBG_NameMap *name_map = raddbg_name_map_from_kind(ctx->rdbg, RADDBG_NameMapKind_ThreadVariables); + if(name_map != 0 && ctx->rdbg->global_variables != 0) + { + RADDBG_ParsedNameMap parsed_name_map = {0}; + raddbg_name_map_parse(ctx->rdbg, name_map, &parsed_name_map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, token_string.str, token_string.size); + U32 matches_count = 0; + U32 *matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + if(matches_count != 0) + { + U32 match_idx = matches[0]; + RADDBG_ThreadVariable *thread_var = &ctx->rdbg->thread_variables[match_idx]; + EVAL_OpList oplist = {0}; + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_TLSOff, thread_var->tls_off); + loc_kind = RADDBG_LocationKind_AddrBytecodeStream; + loc_bytecode = eval_bytecode_from_oplist(arena, &oplist); + U32 type_idx = thread_var->type_idx; + if(type_idx < ctx->rdbg->type_node_count) + { + RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; + type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_idx); + } + mapped_identifier = 1; + } + } + } + + //- rjf: try procedures + if(mapped_identifier == 0) + { + RADDBG_NameMap *name_map = raddbg_name_map_from_kind(ctx->rdbg, RADDBG_NameMapKind_Procedures); + if(name_map != 0 && ctx->rdbg->procedures != 0 && ctx->rdbg->scopes != 0 && ctx->rdbg->scope_voffs) + { + RADDBG_ParsedNameMap parsed_name_map = {0}; + raddbg_name_map_parse(ctx->rdbg, name_map, &parsed_name_map); + RADDBG_NameMapNode *node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, token_string.str, token_string.size); + U32 matches_count = 0; + U32 *matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + if(matches_count != 0) + { + U32 match_idx = matches[0]; + RADDBG_Procedure *procedure = &ctx->rdbg->procedures[match_idx]; + RADDBG_Scope *scope = &ctx->rdbg->scopes[procedure->root_scope_idx]; + U64 voff = ctx->rdbg->scope_voffs[scope->voff_range_first]; + EVAL_OpList oplist = {0}; + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ModuleOff, voff); + loc_kind = RADDBG_LocationKind_ValBytecodeStream; + loc_bytecode = eval_bytecode_from_oplist(arena, &oplist); + U32 type_idx = procedure->type_idx; + if(type_idx < ctx->rdbg->type_node_count) + { + RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; + type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_idx); + } + mapped_identifier = 1; + } + } + } + + //- rjf: try types + if(mapped_identifier == 0) + { + type_key = eval_leaf_type_from_name(ctx->rdbg, token_string); + if(!tg_key_match(tg_key_zero(), type_key)) + { + mapped_identifier = 1; + identifier_looks_like_type_expr = 1; + } + } + + //- rjf: attach on map + if(mapped_identifier != 0) + { + it += 1; + + // rjf: build atom + switch(loc_kind) + { + default: + { + if(identifier_looks_like_type_expr) + { + EVAL_TokenArray type_parse_tokens = eval_token_array_make_first_opl(it-1, it_opl); + EVAL_ParseResult type_parse = eval_parse_type_from_text_tokens(arena, ctx, text, &type_parse_tokens); + EVAL_Expr *type = type_parse.expr; + eval_error_list_concat_in_place(&result.errors, &type_parse.errors); + it = type_parse.last_token; + atom = type; + } + else if(reg_code != 0) + { + REGS_Rng reg_rng = regs_reg_code_rng_table_from_architecture(ctx->arch)[reg_code]; + EVAL_OpList oplist = {0}; + eval_oplist_push_uconst(arena, &oplist, reg_rng.byte_off); + atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Reg); + } + else if(alias_code != 0) + { + REGS_Slice alias_slice = regs_alias_code_slice_table_from_architecture(ctx->arch)[alias_code]; + REGS_Rng alias_reg_rng = regs_reg_code_rng_table_from_architecture(ctx->arch)[alias_slice.code]; + EVAL_OpList oplist = {0}; + eval_oplist_push_uconst(arena, &oplist, alias_reg_rng.byte_off + alias_slice.byte_off); + atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Reg); + } + else + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MissingInfo, token_string.str, "Missing location information for \"%S\".", token_string); + } + }break; + case RADDBG_LocationKind_AddrBytecodeStream: + { + atom = eval_expr_leaf_bytecode(arena, token_string.str, type_key, loc_bytecode, EVAL_EvalMode_Addr); + }break; + case RADDBG_LocationKind_ValBytecodeStream: + { + atom = eval_expr_leaf_bytecode(arena, token_string.str, type_key, loc_bytecode, EVAL_EvalMode_Value); + }break; + case RADDBG_LocationKind_AddrRegisterPlusU16: + { + EVAL_OpList oplist = {0}; + U64 byte_size = bit_size_from_arch(ctx->arch)/8; + U64 regread_param = RADDBG_EncodeRegReadParam(loc_reg_u16.register_code, byte_size, 0); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_RegRead, regread_param); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ConstU16, loc_reg_u16.offset); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_Add, 0); + atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Addr); + }break; + case RADDBG_LocationKind_AddrAddrRegisterPlusU16: + { + EVAL_OpList oplist = {0}; + U64 byte_size = bit_size_from_arch(ctx->arch)/8; + U64 regread_param = RADDBG_EncodeRegReadParam(loc_reg_u16.register_code, byte_size, 0); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_RegRead, regread_param); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ConstU16, loc_reg_u16.offset); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_Add, 0); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_MemRead, bit_size_from_arch(ctx->arch)/8); + atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Addr); + }break; + case RADDBG_LocationKind_ValRegister: + { + REGS_RegCode regs_reg_code = regs_reg_code_from_arch_raddbg_code(ctx->arch, loc_reg.register_code); + REGS_Rng reg_rng = regs_reg_code_rng_table_from_architecture(ctx->arch)[regs_reg_code]; + EVAL_OpList oplist = {0}; + U64 byte_size = (U64)reg_rng.byte_size; + U64 byte_pos = 0; + U64 regread_param = RADDBG_EncodeRegReadParam(loc_reg.register_code, byte_size, byte_pos); + eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_RegRead, regread_param); + atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Value); + }break; + } + + // rjf: implicit local lookup -> attach member access node + if(atom_implicit_member_name.size != 0) + { + EVAL_Expr *member_expr = eval_expr_leaf_member(arena, atom_implicit_member_name.str, atom_implicit_member_name); + atom = eval_expr(arena, EVAL_ExprKind_MemberAccess, atom_implicit_member_name.str, atom, member_expr, 0); + } + } + + // rjf: error on map failure + if(mapped_identifier == 0) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_ResolutionFailure, token_string.str, "Unknown identifier \"%S\".", token_string); + it += 1; + } + }break; + + //- rjf: numeric => directly extract value + case EVAL_TokenKind_Numeric: + { + U64 dot_pos = str8_find_needle(token_string, 0, str8_lit("."), 0); + it += 1; + + // rjf: no . => integral + if(dot_pos == token_string.size) + { + U64 val = 0; + try_u64_from_str8_c_rules(token_string, &val); + atom = eval_expr_u64(arena, token_string.str, val); + break; + } + + // rjf: presence of . => double or float + if(dot_pos < token_string.size) + { + F64 val = f64_from_str8(token_string); + U64 f_pos = str8_find_needle(token_string, 0, str8_lit("f"), StringMatchFlag_CaseInsensitive); + + // rjf: presence of f after . => f32 + if(f_pos < token_string.size) + { + atom = eval_expr_f32(arena, token_string.str, (F32)val); + } + + // rjf: no f => f64 + else + { + atom = eval_expr_f64(arena, token_string.str, val); + } + } + }break; + + //- rjf: char => extract char value + case EVAL_TokenKind_CharLiteral: + { + it += 1; + if(token_string.size > 1 && token_string.str[0] == '\'' && token_string.str[1] != '\'') + { + U8 char_val = token_string.str[1]; + atom = eval_expr_u64(arena, token_string.str, char_val); + } + else + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Malformed character literal."); + } + }break; + + // rjf: string => invalid + case EVAL_TokenKind_StringLiteral: + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "String literals are not supported."); + it += 1; + }break; + + } + } + } + + //- rjf: upgrade atom w/ postfix unaries + if(atom != &eval_expr_nil) for(;it < it_opl;) + { + EVAL_Token token = eval_token_at_it(it, tokens); + String8 token_string = str8_substr(text, token.range); + B32 is_postfix_unary = 0; + + // rjf: dot/arrow operator + if(token.kind == EVAL_TokenKind_Symbol && + (str8_match(token_string, str8_lit("."), 0) || + str8_match(token_string, str8_lit("->"), 0))) + { + is_postfix_unary = 1; + + // rjf: advance past operator + it += 1; + + // rjf: expect member name + String8 member_name = {0}; + B32 good_member_name = 0; + { + EVAL_Token member_name_maybe = eval_token_at_it(it, tokens); + String8 member_name_maybe_string = str8_substr(text, member_name_maybe.range); + if(member_name_maybe.kind != EVAL_TokenKind_Identifier) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Expected member name after %S.", token_string); + } + else + { + member_name = member_name_maybe_string; + good_member_name = 1; + } + } + + // rjf: produce lookup member expr + if(good_member_name) + { + EVAL_Expr *member_expr = eval_expr_leaf_member(arena, member_name.str, member_name); + atom = eval_expr(arena, EVAL_ExprKind_MemberAccess, token_string.str, atom, member_expr, 0); + } + + // rjf: increment past good member names + if(good_member_name) + { + it += 1; + } + } + + // rjf: array index + if(token.kind == EVAL_TokenKind_Symbol && + str8_match(token_string, str8_lit("["), 0)) + { + is_postfix_unary = 1; + + // rjf: advance past [ + it += 1; + + // rjf: parse indexing expression + EVAL_TokenArray idx_expr_parse_tokens = eval_token_array_make_first_opl(it, it_opl); + EVAL_ParseResult idx_expr_parse = eval_parse_expr_from_text_tokens__prec(arena, ctx, text, &idx_expr_parse_tokens, eval_g_max_precedence); + eval_error_list_concat_in_place(&result.errors, &idx_expr_parse.errors); + it = idx_expr_parse.last_token; + + // rjf: valid indexing expression => produce index expr + if(idx_expr_parse.expr != &eval_expr_nil) + { + atom = eval_expr(arena, EVAL_ExprKind_ArrayIndex, token_string.str, atom, idx_expr_parse.expr, 0); + } + + // rjf: expect ] + { + EVAL_Token close_brace_maybe = eval_token_at_it(it, tokens); + String8 close_brace_maybe_string = str8_substr(text, close_brace_maybe.range); + if(close_brace_maybe.kind != EVAL_TokenKind_Symbol || !str8_match(close_brace_maybe_string, str8_lit("]"), 0)) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Unclosed [."); + } + else + { + it += 1; + } + } + } + + // rjf: quit if this doesn't look like any patterns of postfix unary we know + if(!is_postfix_unary) + { + break; + } + } + + //- rjf: upgrade atom w/ previously parsed prefix unaries + if(atom == &eval_expr_nil && first_prefix_unary != 0 && first_prefix_unary->cast_expr != 0) + { + atom = first_prefix_unary->cast_expr; + for(PrefixUnaryNode *prefix_unary = first_prefix_unary->next; + prefix_unary != 0; + prefix_unary = prefix_unary->next) + { + atom = eval_expr(arena, prefix_unary->kind, prefix_unary->location, + prefix_unary->cast_expr != &eval_expr_nil ? prefix_unary->cast_expr : atom, + prefix_unary->cast_expr != &eval_expr_nil ? atom : 0, 0); + } + } + else if(atom == 0 && first_prefix_unary != 0) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, last_prefix_unary->location, "Missing expression."); + } + else + { + for(PrefixUnaryNode *prefix_unary = first_prefix_unary; prefix_unary != 0; prefix_unary = prefix_unary->next) + { + atom = eval_expr(arena, prefix_unary->kind, prefix_unary->location, + prefix_unary->cast_expr != &eval_expr_nil ? prefix_unary->cast_expr : atom, + prefix_unary->cast_expr != &eval_expr_nil ? atom : 0, 0); + } + } + + //- rjf: parse complex operators + if(atom != &eval_expr_nil) for(;it < it_opl;) + { + EVAL_Token *start_it = it; + EVAL_Token token = eval_token_at_it(it, tokens); + String8 token_string = str8_substr(text, token.range); + + //- rjf: parse binaries + { + // rjf: first try to find a matching binary operator + S64 binary_precedence = 0; + EVAL_ExprKind binary_kind = 0; + for(U64 idx = 0; idx < ArrayCount(eval_g_binary_op_table); idx += 1) + { + if(str8_match(token_string, eval_g_binary_op_table[idx].string, 0)) + { + binary_precedence = eval_g_binary_op_table[idx].precedence; + binary_kind = eval_g_binary_op_table[idx].kind; + break; + } + } + + // rjf: if we got a valid binary precedence, and it's not to be handled by + // a caller, then we need to parse the right-hand-side with a tighter + // precedence + if(binary_precedence != 0 && binary_precedence <= max_precedence) + { + EVAL_TokenArray rhs_expr_parse_tokens = eval_token_array_make_first_opl(it+1, it_opl); + EVAL_ParseResult rhs_expr_parse = eval_parse_expr_from_text_tokens__prec(arena, ctx, text, &rhs_expr_parse_tokens, binary_precedence-1); + eval_error_list_concat_in_place(&result.errors, &rhs_expr_parse.errors); + EVAL_Expr *rhs = rhs_expr_parse.expr; + it = rhs_expr_parse.last_token; + if(rhs == &eval_expr_nil) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Missing right-hand-side of %S.", token_string); + } + else + { + atom = eval_expr(arena, binary_kind, token_string.str, atom, rhs, 0); + } + } + } + + //- rjf: parse ternaries + { + if(token.kind == EVAL_TokenKind_Symbol && str8_match(token_string, str8_lit("?"), 0) && 13 <= max_precedence) + { + // rjf: parse middle expression + EVAL_TokenArray middle_expr_tokens = eval_token_array_make_first_opl(it, it_opl); + EVAL_ParseResult middle_expr_parse = eval_parse_expr_from_text_tokens__prec(arena, ctx, text, &middle_expr_tokens, eval_g_max_precedence); + it = middle_expr_parse.last_token; + EVAL_Expr *middle_expr = middle_expr_parse.expr; + eval_error_list_concat_in_place(&result.errors, &middle_expr_parse.errors); + if(middle_expr_parse.expr == &eval_expr_nil) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Expected expression after ?."); + } + + // rjf: expect : + B32 got_colon = 0; + EVAL_Token colon_token = zero_struct; + String8 colon_token_string = {0}; + { + EVAL_Token colon_token_maybe = eval_token_at_it(it, tokens); + String8 colon_token_maybe_string = str8_substr(text, colon_token_maybe.range); + if(colon_token_maybe.kind != EVAL_TokenKind_Symbol || !str8_match(colon_token_maybe_string, str8_lit(":"), 0)) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Expected : after ?."); + } + else + { + got_colon = 1; + colon_token = colon_token_maybe; + colon_token_string = colon_token_maybe_string; + it += 1; + } + } + + // rjf: parse rhs + EVAL_TokenArray rhs_expr_parse_tokens = eval_token_array_make_first_opl(it, it_opl); + EVAL_ParseResult rhs_expr_parse = eval_parse_expr_from_text_tokens__prec(arena, ctx, text, &rhs_expr_parse_tokens, eval_g_max_precedence); + if(got_colon) + { + it = rhs_expr_parse.last_token; + eval_error_list_concat_in_place(&result.errors, &rhs_expr_parse.errors); + if(rhs_expr_parse.expr == &eval_expr_nil) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, colon_token_string.str, "Expected expression after :."); + } + } + + // rjf: build ternary + atom = eval_expr(arena, EVAL_ExprKind_Ternary, token_string.str, atom, middle_expr_parse.expr, rhs_expr_parse.expr); + } + } + + // rjf: if we parsed nothing successfully, we're done + if(it == start_it) + { + break; + } + } + + //- rjf: fill result & return + result.last_token = it; + result.expr = atom; + scratch_end(scratch); + return result; +} + +internal EVAL_ParseResult +eval_parse_expr_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens) +{ + EVAL_ParseResult result = eval_parse_expr_from_text_tokens__prec(arena, ctx, text, tokens, eval_g_max_precedence); + return result; +} diff --git a/src/eval/eval_parser.h b/src/eval/eval_parser.h new file mode 100644 index 00000000..759304f5 --- /dev/null +++ b/src/eval/eval_parser.h @@ -0,0 +1,145 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef EVAL2_PARSER_H +#define EVAL2_PARSER_H + +//////////////////////////////// +//~ rjf: Maps + +typedef struct EVAL_String2NumMapNode EVAL_String2NumMapNode; +struct EVAL_String2NumMapNode +{ + EVAL_String2NumMapNode *next; + String8 string; + U64 num; +}; + +typedef struct EVAL_String2NumMapSlot EVAL_String2NumMapSlot; +struct EVAL_String2NumMapSlot +{ + EVAL_String2NumMapNode *first; + EVAL_String2NumMapNode *last; +}; + +typedef struct EVAL_String2NumMap EVAL_String2NumMap; +struct EVAL_String2NumMap +{ + U64 slots_count; + EVAL_String2NumMapSlot *slots; +}; + +//////////////////////////////// +//~ rjf: Token Types + +typedef enum EVAL_TokenKind +{ + EVAL_TokenKind_Null, + EVAL_TokenKind_Identifier, + EVAL_TokenKind_Numeric, + EVAL_TokenKind_StringLiteral, + EVAL_TokenKind_CharLiteral, + EVAL_TokenKind_Symbol, + EVAL_TokenKind_COUNT +} +EVAL_TokenKind; + +typedef struct EVAL_Token EVAL_Token; +struct EVAL_Token +{ + EVAL_TokenKind kind; + Rng1U64 range; +}; + +typedef struct EVAL_TokenChunkNode EVAL_TokenChunkNode; +struct EVAL_TokenChunkNode +{ + EVAL_TokenChunkNode *next; + EVAL_Token *v; + U64 count; + U64 cap; +}; + +typedef struct EVAL_TokenChunkList EVAL_TokenChunkList; +struct EVAL_TokenChunkList +{ + EVAL_TokenChunkNode *first; + EVAL_TokenChunkNode *last; + U64 node_count; + U64 total_count; +}; + +typedef struct EVAL_TokenArray EVAL_TokenArray; +struct EVAL_TokenArray +{ + EVAL_Token *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Parser Types + +typedef struct EVAL_ParseResult EVAL_ParseResult; +struct EVAL_ParseResult +{ + EVAL_Token *last_token; + EVAL_Expr *expr; + EVAL_ErrorList errors; +}; + +typedef struct EVAL_ParseCtx EVAL_ParseCtx; +struct EVAL_ParseCtx +{ + Architecture arch; + U64 ip_voff; + RADDBG_Parsed *rdbg; + TG_Graph *type_graph; + EVAL_String2NumMap *regs_map; + EVAL_String2NumMap *reg_alias_map; + EVAL_String2NumMap *locals_map; + EVAL_String2NumMap *member_map; +}; + +//////////////////////////////// +//~ rjf: Globals + +read_only global EVAL_String2NumMap eval_string2num_map_nil = {0}; +global read_only EVAL_ParseResult eval_parse_result_nil = {0, &eval_expr_nil}; + +//////////////////////////////// +//~ rjf: Basic Functions + +internal U64 eval_hash_from_string(String8 string); + +//////////////////////////////// +//~ rjf: Map Functions + +internal EVAL_String2NumMap eval_string2num_map_make(Arena *arena, U64 slot_count); +internal void eval_string2num_map_insert(Arena *arena, EVAL_String2NumMap *map, String8 string, U64 num); +internal U64 eval_num_from_string(EVAL_String2NumMap *map, String8 string); + +//////////////////////////////// +//~ rjf: Debug-Info-Driven Map Building Fast Paths + +internal EVAL_String2NumMap *eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff); +internal EVAL_String2NumMap *eval_push_member_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff); + +//////////////////////////////// +//~ rjf: Tokenization Functions + +#define eval_token_at_it(it, arr) (((it) < (arr)->v+(arr)->count) ? (*(it)) : eval_token_zero()) +internal EVAL_Token eval_token_zero(void); +internal void eval_token_chunk_list_push(Arena *arena, EVAL_TokenChunkList *list, U64 chunk_size, EVAL_Token *token); +internal EVAL_TokenArray eval_token_array_from_chunk_list(Arena *arena, EVAL_TokenChunkList *list); +internal EVAL_TokenArray eval_token_array_from_text(Arena *arena, String8 text); +internal EVAL_TokenArray eval_token_array_make_first_opl(EVAL_Token *first, EVAL_Token *opl); + +//////////////////////////////// +//~ rjf: Parser Functions + +internal TG_Key eval_leaf_type_from_name(RADDBG_Parsed *rdbg, String8 name); +internal EVAL_ParseResult eval_parse_type_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens); +internal EVAL_ParseResult eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens, S64 max_precedence); +internal EVAL_ParseResult eval_parse_expr_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens); + +#endif // EVAL2_PARSER_H diff --git a/src/eval/generated/eval.meta.c b/src/eval/generated/eval.meta.c new file mode 100644 index 00000000..b9d27fe6 --- /dev/null +++ b/src/eval/generated/eval.meta.c @@ -0,0 +1,5 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + diff --git a/src/eval/generated/eval.meta.h b/src/eval/generated/eval.meta.h new file mode 100644 index 00000000..5e7d648d --- /dev/null +++ b/src/eval/generated/eval.meta.h @@ -0,0 +1,176 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef EVAL_META_H +#define EVAL_META_H + +typedef U32 EVAL_ExprKind; +enum +{ +EVAL_ExprKind_ArrayIndex, +EVAL_ExprKind_MemberAccess, +EVAL_ExprKind_Deref, +EVAL_ExprKind_Address, +EVAL_ExprKind_Cast, +EVAL_ExprKind_Sizeof, +EVAL_ExprKind_Neg, +EVAL_ExprKind_LogNot, +EVAL_ExprKind_BitNot, +EVAL_ExprKind_Mul, +EVAL_ExprKind_Div, +EVAL_ExprKind_Mod, +EVAL_ExprKind_Add, +EVAL_ExprKind_Sub, +EVAL_ExprKind_LShift, +EVAL_ExprKind_RShift, +EVAL_ExprKind_Less, +EVAL_ExprKind_LsEq, +EVAL_ExprKind_Grtr, +EVAL_ExprKind_GrEq, +EVAL_ExprKind_EqEq, +EVAL_ExprKind_NtEq, +EVAL_ExprKind_BitAnd, +EVAL_ExprKind_BitXor, +EVAL_ExprKind_BitOr, +EVAL_ExprKind_LogAnd, +EVAL_ExprKind_LogOr, +EVAL_ExprKind_Ternary, +EVAL_ExprKind_LeafBytecode, +EVAL_ExprKind_LeafMember, +EVAL_ExprKind_LeafU64, +EVAL_ExprKind_LeafF64, +EVAL_ExprKind_LeafF32, +EVAL_ExprKind_TypeIdent, +EVAL_ExprKind_Ptr, +EVAL_ExprKind_Array, +EVAL_ExprKind_Func, +EVAL_ExprKind_COUNT +}; + +U8 eval_expr_kind_child_counts[] = +{ +2, +2, +1, +1, +2, +1, +1, +1, +1, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +3, +0, +0, +0, +0, +0, +0, +1, +2, +1, +}; + +String8 eval_expr_kind_strings[] = +{ +str8_lit_comp("ArrayIndex"), +str8_lit_comp("MemberAccess"), +str8_lit_comp("Deref"), +str8_lit_comp("Address"), +str8_lit_comp("Cast"), +str8_lit_comp("Sizeof"), +str8_lit_comp("Neg"), +str8_lit_comp("LogNot"), +str8_lit_comp("BitNot"), +str8_lit_comp("Mul"), +str8_lit_comp("Div"), +str8_lit_comp("Mod"), +str8_lit_comp("Add"), +str8_lit_comp("Sub"), +str8_lit_comp("LShift"), +str8_lit_comp("RShift"), +str8_lit_comp("Less"), +str8_lit_comp("LsEq"), +str8_lit_comp("Grtr"), +str8_lit_comp("GrEq"), +str8_lit_comp("EqEq"), +str8_lit_comp("NtEq"), +str8_lit_comp("BitAnd"), +str8_lit_comp("BitXor"), +str8_lit_comp("BitOr"), +str8_lit_comp("LogAnd"), +str8_lit_comp("LogOr"), +str8_lit_comp("Ternary"), +str8_lit_comp("LeafBytecode"), +str8_lit_comp("LeafMember"), +str8_lit_comp("LeafU64"), +str8_lit_comp("LeafF64"), +str8_lit_comp("LeafF32"), +str8_lit_comp("TypeIdent"), +str8_lit_comp("Ptr"), +str8_lit_comp("Array"), +str8_lit_comp("Func"), +}; + +String8 eval_expr_op_strings[] = +{ +str8_lit_comp("[]"), +str8_lit_comp("."), +str8_lit_comp("*"), +str8_lit_comp("&"), +str8_lit_comp("cast"), +str8_lit_comp("sizeof"), +str8_lit_comp("-"), +str8_lit_comp("!"), +str8_lit_comp("~"), +str8_lit_comp("*"), +str8_lit_comp("/"), +str8_lit_comp("%"), +str8_lit_comp("+"), +str8_lit_comp("-"), +str8_lit_comp("<<"), +str8_lit_comp(">>"), +str8_lit_comp("<"), +str8_lit_comp("<="), +str8_lit_comp(">"), +str8_lit_comp(">="), +str8_lit_comp("=="), +str8_lit_comp("!="), +str8_lit_comp("&"), +str8_lit_comp("^"), +str8_lit_comp("|"), +str8_lit_comp("&&"), +str8_lit_comp("||"), +str8_lit_comp("? "), +str8_lit_comp("bytecode"), +str8_lit_comp("member"), +str8_lit_comp("U64"), +str8_lit_comp("F64"), +str8_lit_comp("F32"), +str8_lit_comp("type_ident"), +str8_lit_comp("ptr"), +str8_lit_comp("array"), +str8_lit_comp("function"), +}; + + +#endif // EVAL_META_H diff --git a/src/font_cache/font_cache.c b/src/font_cache/font_cache.c new file mode 100644 index 00000000..7d597632 --- /dev/null +++ b/src/font_cache/font_cache.c @@ -0,0 +1,1027 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Functions + +#if !defined(BLAKE2_H) +#define HAVE_SSE2 +#include "third_party/blake2/blake2.h" +#include "third_party/blake2/blake2b.c" +#endif + +internal F_Hash +f_hash_from_string(String8 string) +{ + F_Hash result = {0}; + blake2b((U8 *)&result.u64[0], sizeof(result), string.str, string.size, 0, 0); + return result; +} + +internal U64 +f_little_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal Vec2S32 +f_vertex_from_corner(Corner corner) +{ + Vec2S32 result = {0}; + switch(corner) + { + default: break; + case Corner_00:{result = v2s32(0, 0);}break; + case Corner_01:{result = v2s32(0, 1);}break; + case Corner_10:{result = v2s32(1, 0);}break; + case Corner_11:{result = v2s32(1, 1);}break; + } + return result; +} + +//////////////////////////////// +//~ rjf: Font Tags + +internal F_Tag +f_tag_zero(void) +{ + F_Tag result = {0}; + return result; +} + +internal B32 +f_tag_match(F_Tag a, F_Tag b) +{ + return a.u64[0] == b.u64[0] && a.u64[1] == b.u64[1]; +} + +internal FP_Handle +f_handle_from_tag(F_Tag tag) +{ + ProfBeginFunction(); + U64 slot_idx = tag.u64[1] % f_state->font_hash_table_size; + F_FontHashNode *existing_node = 0; + { + for(F_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + { + if(MemoryMatchStruct(&tag, &n->tag)) + { + existing_node = n; + break; + } + } + } + FP_Handle result = {0}; + if(existing_node != 0) + { + result = existing_node->handle; + } + ProfEnd(); + return result; +} + +internal FP_Metrics +f_fp_metrics_from_tag(F_Tag tag) +{ + ProfBeginFunction(); + U64 slot_idx = tag.u64[1] % f_state->font_hash_table_size; + F_FontHashNode *existing_node = 0; + { + for(F_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + { + if(MemoryMatchStruct(&tag, &n->tag)) + { + existing_node = n; + break; + } + } + } + FP_Metrics result = {0}; + if(existing_node != 0) + { + result = existing_node->metrics; + } + ProfEnd(); + return result; +} + +internal F_Tag +f_tag_from_path(String8 path) +{ + ProfBeginFunction(); + + //- rjf: produce tag from hash of path + F_Tag result = {0}; + { + F_Hash hash = f_hash_from_string(path); + MemoryCopy(&result, &hash, sizeof(result)); + result.u64[1] |= bit64; + } + + //- rjf: tag -> slot index + U64 slot_idx = result.u64[1] % f_state->font_hash_table_size; + + //- rjf: slot * tag -> existing node + F_FontHashNode *existing_node = 0; + { + for(F_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + { + if(MemoryMatchStruct(&result, &n->tag)) + { + existing_node = n; + break; + } + } + } + + //- rjf: allocate & push new node if we don't have an existing one + F_FontHashNode *new_node = 0; + if(existing_node == 0) + { + F_FontHashSlot *slot = &f_state->font_hash_table[slot_idx]; + new_node = push_array(f_state->arena, F_FontHashNode, 1); + new_node->tag = result; + new_node->handle = fp_font_open(path); + new_node->metrics = fp_metrics_from_font(new_node->handle); + new_node->path = push_str8_copy(f_state->arena, path); + SLLQueuePush_N(slot->first, slot->last, new_node, hash_next); + } + + //- rjf: return + ProfEnd(); + return result; +} + +internal F_Tag +f_tag_from_static_data_string(String8 *data_ptr) +{ + ProfBeginFunction(); + + //- rjf: produce tag hash of ptr + F_Tag result = {0}; + { + F_Hash hash = f_hash_from_string(str8((U8 *)&data_ptr, sizeof(String8 *))); + MemoryCopy(&result, &hash, sizeof(result)); + result.u64[1] &= ~bit64; + } + + //- rjf: tag -> slot index + U64 slot_idx = result.u64[1] % f_state->font_hash_table_size; + + //- rjf: slot * tag -> existing node + F_FontHashNode *existing_node = 0; + { + for(F_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + { + if(MemoryMatchStruct(&result, &n->tag)) + { + existing_node = n; + break; + } + } + } + + //- rjf: allocate & push new node if we don't have an existing one + F_FontHashNode *new_node = 0; + if(existing_node == 0) + { + F_FontHashSlot *slot = &f_state->font_hash_table[slot_idx]; + new_node = push_array(f_state->arena, F_FontHashNode, 1); + new_node->tag = result; + new_node->handle = fp_font_open_from_static_data_string(data_ptr); + new_node->metrics = fp_metrics_from_font(new_node->handle); + new_node->path = str8_lit(""); + SLLQueuePush_N(slot->first, slot->last, new_node, hash_next); + } + + //- rjf: return + ProfEnd(); + return result; +} + +internal String8 +f_path_from_tag(F_Tag tag) +{ + //- rjf: tag -> slot index + U64 slot_idx = tag.u64[1] % f_state->font_hash_table_size; + + //- rjf: slot * tag -> existing node + F_FontHashNode *existing_node = 0; + { + for(F_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + { + if(MemoryMatchStruct(&tag, &n->tag)) + { + existing_node = n; + break; + } + } + } + + //- rjf: existing node -> path + String8 result = {0}; + if(existing_node != 0) + { + result = existing_node->path; + } + + return result; +} + +//////////////////////////////// +//~ rjf: Atlas + +internal Rng2S16 +f_atlas_region_alloc(Arena *arena, F_Atlas *atlas, Vec2S16 needed_size) +{ + ProfBeginFunction(); + + //- rjf: find node with best-fit size + Vec2S16 region_p0 = {0}; + Vec2S16 region_sz = {0}; + Corner node_corner = Corner_Invalid; + F_AtlasRegionNode *node = 0; + { + Vec2S16 n_supported_size = atlas->root_dim; + for(F_AtlasRegionNode *n = atlas->root, *next = 0; n != 0; n = next, next = 0) + { + // rjf: we've traversed to a taken node. + if(n->flags & F_AtlasRegionNodeFlag_Taken) + { + break; + } + + // rjf: calculate if this node can be allocated (all children are non-allocated) + B32 n_can_be_allocated = (n->num_allocated_descendants == 0); + + // rjf: fill size + if(n_can_be_allocated) + { + region_sz = n_supported_size; + } + + // rjf: calculate size of this node's children + Vec2S16 child_size = v2s16(n_supported_size.x/2, n_supported_size.y/2); + + // rjf: find best next child + F_AtlasRegionNode *best_child = 0; + if(child_size.x >= needed_size.x && child_size.y >= needed_size.y) + { + for(Corner corner = (Corner)0; corner < Corner_COUNT; corner = (Corner)(corner+1)) + { + if(n->children[corner] == 0) + { + n->children[corner] = push_array(arena, F_AtlasRegionNode, 1); + n->children[corner]->parent = n; + n->children[corner]->max_free_size[Corner_00] = + n->children[corner]->max_free_size[Corner_01] = + n->children[corner]->max_free_size[Corner_10] = + n->children[corner]->max_free_size[Corner_11] = v2s16(child_size.x/2, child_size.y/2); + } + if(n->max_free_size[corner].x >= needed_size.x && + n->max_free_size[corner].y >= needed_size.y) + { + best_child = n->children[corner]; + node_corner = corner; + Vec2S32 side_vertex = f_vertex_from_corner(corner); + region_p0.x += side_vertex.x*child_size.x; + region_p0.y += side_vertex.y*child_size.y; + break; + } + } + } + + // rjf: resolve node to this node if it can be allocated and children + // don't fit, or keep going to the next best child + if(n_can_be_allocated && best_child == 0) + { + node = n; + } + else + { + next = best_child; + n_supported_size = child_size; + } + } + } + + //- rjf: we're taking the subtree rooted by `node`. mark up all parents + if(node != 0 && node_corner != Corner_Invalid) + { + node->flags |= F_AtlasRegionNodeFlag_Taken; + if(node->parent != 0) + { + MemoryZeroStruct(&node->parent->max_free_size[node_corner]); + } + for(F_AtlasRegionNode *p = node->parent; p != 0; p = p->parent) + { + p->num_allocated_descendants += 1; + F_AtlasRegionNode *parent = p->parent; + if(parent != 0) + { + Corner p_corner = (p == parent->children[Corner_00] ? Corner_00 : + p == parent->children[Corner_01] ? Corner_01 : + p == parent->children[Corner_10] ? Corner_10 : + p == parent->children[Corner_11] ? Corner_11 : + Corner_Invalid); + if(p_corner == Corner_Invalid) + { + InvalidPath; + } + parent->max_free_size[p_corner].x = Max(Max(p->max_free_size[Corner_00].x, + p->max_free_size[Corner_01].x), + Max(p->max_free_size[Corner_10].x, + p->max_free_size[Corner_11].x)); + parent->max_free_size[p_corner].y = Max(Max(p->max_free_size[Corner_00].y, + p->max_free_size[Corner_01].y), + Max(p->max_free_size[Corner_10].y, + p->max_free_size[Corner_11].y)); + } + } + } + + //- rjf: fill rectangular region & return + Rng2S16 result = {0}; + result.p0 = region_p0; + result.p1 = add_2s16(region_p0, region_sz); + ProfEnd(); + return result; +} + +internal void +f_atlas_region_release(F_Atlas *atlas, Rng2S16 region) +{ + ProfBeginFunction(); + + //- rjf: extract region size + Vec2S16 region_size = v2s16(region.x1 - region.x0, region.y1 - region.y0); + + //- rjf: map region to associated node + Vec2S16 calc_region_size = {0}; + F_AtlasRegionNode *node = 0; + Corner node_corner = Corner_Invalid; + { + Vec2S16 n_p0 = v2s16(0, 0); + Vec2S16 n_sz = atlas->root_dim; + for(F_AtlasRegionNode *n = atlas->root, *next = 0; n != 0; n = next) + { + // rjf: is the region within this node's boundaries? (either this node, or a descendant) + if(n_p0.x <= region.p0.x && region.p0.x < n_p0.x+n_sz.x && + n_p0.y <= region.p0.y && region.p0.y < n_p0.y+n_sz.y) + { + // rjf: check the region against this node + if(region.p0.x == n_p0.x && region.p0.y == n_p0.y && + region_size.x == n_sz.x && region_size.y == n_sz.y) + { + node = n; + calc_region_size = n_sz; + break; + } + // rjf: check the region against children & iterate + else + { + Vec2S16 r_midpoint = v2s16(region.p0.x + region_size.x/2, + region.p0.y + region_size.y/2); + Vec2S16 n_midpoint = v2s16(n_p0.x + n_sz.x/2, + n_p0.y + n_sz.y/2); + Corner next_corner = Corner_Invalid; + if(r_midpoint.x <= n_midpoint.x && r_midpoint.y <= n_midpoint.y) + { + next_corner = Corner_00; + } + else if(r_midpoint.x <= n_midpoint.x && n_midpoint.y <= r_midpoint.y) + { + next_corner = Corner_01; + } + else if(n_midpoint.x <= r_midpoint.x && r_midpoint.y <= n_midpoint.y) + { + next_corner = Corner_10; + } + else if(n_midpoint.x <= r_midpoint.x && n_midpoint.y <= r_midpoint.y) + { + next_corner = Corner_11; + } + next = n->children[next_corner]; + node_corner = next_corner; + n_sz.x /= 2; + n_sz.y /= 2; + Vec2S32 side_vertex = f_vertex_from_corner(node_corner); + n_p0.x += side_vertex.x*n_sz.x; + n_p0.y += side_vertex.y*n_sz.y; + } + } + else + { + break; + } + } + } + + //- rjf: free node + if(node != 0 && node_corner != Corner_Invalid) + { + node->flags &= ~F_AtlasRegionNodeFlag_Taken; + if(node->parent != 0) + { + node->parent->max_free_size[node_corner] = calc_region_size; + } + for(F_AtlasRegionNode *p = node->parent; p != 0; p = p->parent) + { + p->num_allocated_descendants -= 1; + F_AtlasRegionNode *parent = p->parent; + if(parent != 0) + { + Corner p_corner = (p == parent->children[Corner_00] ? Corner_00 : + p == parent->children[Corner_01] ? Corner_01 : + p == parent->children[Corner_10] ? Corner_10 : + p == parent->children[Corner_11] ? Corner_11 : + Corner_Invalid); + if(p_corner == Corner_Invalid) + { + InvalidPath; + } + parent->max_free_size[p_corner].x = Max(Max(p->max_free_size[Corner_00].x, + p->max_free_size[Corner_01].x), + Max(p->max_free_size[Corner_10].x, + p->max_free_size[Corner_11].x)); + parent->max_free_size[p_corner].y = Max(Max(p->max_free_size[Corner_00].y, + p->max_free_size[Corner_01].y), + Max(p->max_free_size[Corner_10].y, + p->max_free_size[Corner_11].y)); + } + } + } + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Piece Type Functions + +internal F_Piece * +f_piece_chunk_list_push_new(Arena *arena, F_PieceChunkList *list, U64 cap) +{ + F_PieceChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, F_PieceChunkNode, 1); + node->v = push_array_no_zero(arena, F_Piece, cap); + node->cap = cap; + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + } + F_Piece *result = node->v + node->count; + node->count += 1; + list->total_piece_count += 1; + return result; +} + +internal void +f_piece_chunk_list_push(Arena *arena, F_PieceChunkList *list, U64 cap, F_Piece *piece) +{ + F_Piece *new_piece = f_piece_chunk_list_push_new(arena, list, cap); + MemoryCopyStruct(new_piece, piece); +} + +internal F_PieceArray +f_piece_array_from_chunk_list(Arena *arena, F_PieceChunkList *list) +{ + F_PieceArray array = {0}; + array.count = list->total_piece_count; + array.v = push_array_no_zero(arena, F_Piece, array.count); + U64 write_idx = 0; + for(F_PieceChunkNode *node = list->first; node != 0; node = node->next) + { + MemoryCopy(array.v + write_idx, node->v, node->count * sizeof(F_Piece)); + write_idx += node->count; + } + return array; +} + +//////////////////////////////// +//~ rjf: Rasterization Cache + +internal F_Hash2StyleRasterCacheNode * +f_hash2style_from_tag_size(F_Tag tag, F32 size) +{ + //- rjf: tag * size -> style hash + U64 style_hash = {0}; + { + U64 buffer[] = + { + tag.u64[0], + tag.u64[1], + (U64)round_f32(size), + }; + style_hash = f_little_hash_from_string(str8((U8 *)buffer, sizeof(buffer))); + } + + //- rjf: style hash -> style node + F_Hash2StyleRasterCacheNode *hash2style_node = 0; + { + ProfBegin("style hash -> style node"); + U64 slot_idx = style_hash%f_state->hash2style_slots_count; + F_Hash2StyleRasterCacheSlot *slot = &f_state->hash2style_slots[slot_idx]; + for(F_Hash2StyleRasterCacheNode *n = slot->first; + n != 0; + n = n->hash_next) + { + if(n->style_hash == style_hash) + { + hash2style_node = n; + break; + } + } + if(Unlikely(hash2style_node == 0)) + { + F_Metrics metrics = f_metrics_from_tag_size(tag, size); + hash2style_node = push_array(f_state->arena, F_Hash2StyleRasterCacheNode, 1); + DLLPushBack_NP(slot->first, slot->last, hash2style_node, hash_next, hash_prev); + hash2style_node->style_hash = style_hash; + hash2style_node->ascent = metrics.ascent; + hash2style_node->descent= metrics.descent; + hash2style_node->utf8_class1_direct_map = push_array_no_zero(f_state->arena, F_RasterCacheInfo, 256); + hash2style_node->hash2info_slots_count = 1024; + hash2style_node->hash2info_slots = push_array(f_state->arena, F_Hash2InfoRasterCacheSlot, hash2style_node->hash2info_slots_count); + } + ProfEnd(); + } + + return hash2style_node; +} + +internal F_Run +f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F_RunFlags flags, String8 string) +{ + ProfBeginFunction(); + + //- rjf: map tag/size to style node + F_Hash2StyleRasterCacheNode *hash2style_node = f_hash2style_from_tag_size(tag, size); + + //- rjf: decode string & produce run pieces + F_PieceChunkList piece_chunks = {0}; + Vec2F32 dim = {0}; + B32 font_handle_mapped_on_miss = 0; + FP_Handle font_handle = {0}; + U64 piece_substring_start_idx = 0; + for(U64 idx = 0; idx < string.size;) + { + //- rjf: decode next codepoint & get piece substring, or continuation rule + String8 piece_substring; + B32 need_another_codepoint = 0; + switch(utf8_class[string.str[idx]>>3]) + { + case 1: + { + piece_substring.str = &string.str[idx]; + piece_substring.size = 1; + idx += 1; + }break; + default: + { + UnicodeDecode decode = utf8_decode(string.str+idx, string.size-idx); + idx += decode.inc; + if(decode.inc == 0) { break; } + piece_substring.str = string.str + piece_substring_start_idx; + piece_substring.size = decode.inc; + // NOTE(rjf): assuming 1 codepoint per piece for now. + }break; + } + + //- rjf: need another codepoint? -> continue + if(need_another_codepoint) + { + continue; + } + + //- rjf: do not need another codepoint? -> bump piece start idx + { + piece_substring_start_idx = idx; + } + + //- rjf: determine if this piece is a tab - if so, use space info to draw + B32 is_tab = (piece_substring.size == 1 && piece_substring.str[0] == '\t'); + if(is_tab) + { + piece_substring = str8_lit(" "); + } + + //- rjf: piece substring -> raster cache info + F_RasterCacheInfo *info = 0; + U64 piece_hash = 0; + { + // rjf: fast path for utf8 class 1 -> direct map + if(piece_substring.size == 1 && hash2style_node->utf8_class1_direct_map_mask[piece_substring.str[0]/64] & (1ull<<(piece_substring.str[0]%64))) + { + info = &hash2style_node->utf8_class1_direct_map[piece_substring.str[0]]; + } + + // rjf: more general, slower path for other glyphs + if(piece_substring.size > 1) + { + piece_hash = f_little_hash_from_string(piece_substring); + U64 slot_idx = piece_hash%hash2style_node->hash2info_slots_count; + F_Hash2InfoRasterCacheSlot *slot = &hash2style_node->hash2info_slots[slot_idx]; + for(F_Hash2InfoRasterCacheNode *node = slot->first; node != 0; node = node->hash_next) + { + if(node->hash == piece_hash) + { + info = &node->info; + break; + } + } + } + } + + //- rjf: no info found -> miss... fill this hash in the cache + if(info == 0) + { + ProfBegin("no info found -> miss... fill this hash in the cache"); + Temp scratch = scratch_begin(&arena, 1); + + // rjf: grab font handle for this tag if we don't have one already + if(font_handle_mapped_on_miss == 0) + { + font_handle_mapped_on_miss = 1; + + // rjf: tag -> font slot index + U64 font_slot_idx = tag.u64[1] % f_state->font_hash_table_size; + + // rjf: tag * slot -> existing node + F_FontHashNode *existing_node = 0; + { + for(F_FontHashNode *n = f_state->font_hash_table[font_slot_idx].first; n != 0 ; n = n->hash_next) + { + if(MemoryMatchStruct(&n->tag, &tag)) + { + existing_node = n; + break; + } + } + } + + // rjf: existing node -> font handle + if(existing_node != 0) + { + font_handle = existing_node->handle; + } + } + + // rjf: call into font provider to rasterize this substring + FP_RasterResult raster = fp_raster(scratch.arena, font_handle, round_f32(size), FP_RasterMode_Sharp, piece_substring); + + // rjf: allocate portion of an atlas to upload the rasterization + S16 chosen_atlas_num = 0; + F_Atlas *chosen_atlas = 0; + Rng2S16 chosen_atlas_region = {0}; + if(raster.atlas_dim.x != 0 && raster.atlas_dim.y != 0) + { + U64 num_atlases = 0; + for(F_Atlas *atlas = f_state->first_atlas;; atlas = atlas->next, num_atlases += 1) + { + // rjf: create atlas if needed + if(atlas == 0 && num_atlases < 16) + { + atlas = push_array(f_state->arena, F_Atlas, 1); + DLLPushBack(f_state->first_atlas, f_state->last_atlas, atlas); + atlas->root_dim = v2s16(1024, 1024); + atlas->root = push_array(f_state->arena, F_AtlasRegionNode, 1); + atlas->root->max_free_size[Corner_00] = + atlas->root->max_free_size[Corner_01] = + atlas->root->max_free_size[Corner_10] = + atlas->root->max_free_size[Corner_11] = v2s16(atlas->root_dim.x/2, atlas->root_dim.y/2); + atlas->texture = r_tex2d_alloc(R_Tex2DKind_Dynamic, v2s32((S32)atlas->root_dim.x, (S32)atlas->root_dim.y), R_Tex2DFormat_RGBA8, 0); + } + + // rjf: allocate from atlas + if(atlas != 0) + { + Vec2S16 needed_dimensions = v2s16(raster.atlas_dim.x + 2, raster.atlas_dim.y + 2); + chosen_atlas_region = f_atlas_region_alloc(f_state->arena, atlas, needed_dimensions); + if(chosen_atlas_region.x1 != chosen_atlas_region.x0) + { + chosen_atlas = atlas; + chosen_atlas_num = (S32)num_atlases; + break; + } + } + else + { + break; + } + } + } + + // rjf: upload rasterization to allocated region of atlas texture memory + if(chosen_atlas != 0) + { + Rng2S32 subregion = + { + chosen_atlas_region.x0 + 1, + chosen_atlas_region.y0 + 1, + chosen_atlas_region.x0 + raster.atlas_dim.x + 1, + chosen_atlas_region.y0 + raster.atlas_dim.y + 1 + }; + r_fill_tex2d_region(chosen_atlas->texture, subregion, raster.atlas); + } + + // rjf: allocate & fill & push node + { + if(piece_substring.size == 1) + { + info = &hash2style_node->utf8_class1_direct_map[piece_substring.str[0]]; + hash2style_node->utf8_class1_direct_map_mask[piece_substring.str[0]/64] |= (1ull<<(piece_substring.str[0]%64)); + } + else + { + U64 slot_idx = piece_hash%hash2style_node->hash2info_slots_count; + F_Hash2InfoRasterCacheSlot *slot = &hash2style_node->hash2info_slots[slot_idx]; + F_Hash2InfoRasterCacheNode *node = push_array_no_zero(f_state->arena, F_Hash2InfoRasterCacheNode, 1); + DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev); + node->hash = piece_hash; + info = &node->info; + } + if(info != 0) + { + info->subrect = chosen_atlas_region; + info->atlas_num = chosen_atlas_num; + info->advance = raster.advance; + } + } + + scratch_end(scratch); + ProfEnd(); + } + + //- rjf: push piece for this raster portion + if(info != 0) + { + // rjf: find atlas + F_Atlas *atlas = 0; + { + if(info->subrect.x1 != 0 && info->subrect.y1 != 0) + { + S32 num = 0; + for(F_Atlas *a = f_state->first_atlas; a != 0; a = a->next, num += 1) + { + if(info->atlas_num == num) + { + atlas = a; + break; + } + } + } + } + + // rjf: push piece + { + F_Piece *piece = f_piece_chunk_list_push_new(arena, &piece_chunks, string.size); + { + piece->texture = atlas ? atlas->texture : r_handle_zero(); + piece->subrect = r2s16p(info->subrect.x0 + 1, + info->subrect.y0 + 1, + info->subrect.x1 - 1, + info->subrect.y1 - 1); + piece->advance = info->advance; + piece->decode_size = piece_substring.size; + piece->offset = v2s16(0, -hash2style_node->ascent - 4); + } + dim.x += piece->advance; + dim.y = Max(dim.y, dim_2s16(piece->subrect).y); + } + } + } + + //- rjf: tighten & return + F_Run run = {0}; + { + if(piece_chunks.node_count == 1) + { + run.pieces.v = piece_chunks.first->v; + run.pieces.count = piece_chunks.first->count; + } + else + { + run.pieces = f_piece_array_from_chunk_list(arena, &piece_chunks); + } + run.dim = dim; + run.ascent = hash2style_node->ascent; + run.descent = hash2style_node->descent; + } + + ProfEnd(); + return run; +} + +internal String8List +f_wrapped_string_lines_from_font_size_string_max(Arena *arena, F_Tag font, F32 size, String8 string, F32 max) +{ + String8List list = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + F_Run run = f_push_run_from_string(scratch.arena, font, size, 0, string); + F32 off_px = 0; + U64 off_bytes = 0; + U64 line_start_off_bytes = 0; + U64 line_end_off_bytes = 0; + B32 seeking_word_end = 0; + F32 word_start_off_px = 0; + F_Piece *last_word_start_piece = 0; + U64 last_word_start_off_bytes = 0; + F_Piece *pieces_first = run.pieces.v; + F_Piece *pieces_opl = run.pieces.v + run.pieces.count; + for(F_Piece *piece = pieces_first, *next = 0; piece != 0 && piece <= pieces_opl; piece = next) + { + if(piece != 0) {next = piece+1;} + + // rjf: gather info + U8 byte = off_bytes < string.size ? string.str[off_bytes] : 0; + F32 advance = (piece != 0) ? piece->advance : 0; + U64 decode_size = (piece != 0) ? piece->decode_size : 0; + + // rjf: find start/end of words + B32 is_first_byte_of_word = 0; + B32 is_first_space_after_word = 0; + if(!seeking_word_end && !char_is_space(byte)) + { + seeking_word_end = 1; + is_first_byte_of_word = 1; + last_word_start_off_bytes = off_bytes; + last_word_start_piece = piece; + word_start_off_px = off_px; + } + else if(seeking_word_end && char_is_space(byte)) + { + seeking_word_end = 0; + is_first_space_after_word = 1; + } + else if(seeking_word_end && byte == 0) + { + is_first_space_after_word = 1; + } + + // rjf: determine properties of this advance + B32 is_illegal = (off_px >= max); + B32 is_next_illegal = (off_px + advance >= max); + B32 is_end = (byte == 0); + + // rjf: legal word end -> extend line + if(is_first_space_after_word && !is_illegal) + { + line_end_off_bytes = off_bytes; + } + + // rjf: illegal mid-word split -> wrap mid-word + if(is_next_illegal && word_start_off_px == 0) + { + String8 line = str8(string.str + line_start_off_bytes, off_bytes - line_start_off_bytes); + line = str8_skip_chop_whitespace(line); + if(line.size != 0) + { + str8_list_push(arena, &list, line); + } + off_px = advance; + line_start_off_bytes = off_bytes; + line_end_off_bytes = off_bytes; + word_start_off_px = 0; + last_word_start_piece = piece; + last_word_start_off_bytes = off_bytes; + off_bytes += decode_size; + } + + // rjf: illegal word end -> wrap line + else if(is_first_space_after_word && (is_illegal || is_end)) + { + String8 line = str8(string.str + line_start_off_bytes, line_end_off_bytes - line_start_off_bytes); + line = str8_skip_chop_whitespace(line); + if(line.size != 0) + { + str8_list_push(arena, &list, line); + } + line_start_off_bytes = line_end_off_bytes; + if(is_illegal) + { + off_px = 0; + word_start_off_px = 0; + off_bytes = last_word_start_off_bytes; + next = last_word_start_piece; + } + } + + // rjf: advance offsets otherwise + else + { + off_px += advance; + off_bytes += decode_size; + } + + // rjf: 0 piece and 0 next -> done + if(piece == 0 && next == 0) + { + break; + } + } + scratch_end(scratch); + } + return list; +} + +internal Vec2F32 +f_dim_from_tag_size_string(F_Tag tag, F32 size, String8 string) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + Vec2F32 result = {0}; + F_Run run = f_push_run_from_string(scratch.arena, tag, size, 0, string); + result = run.dim; + scratch_end(scratch); + ProfEnd(); + return result; +} + +internal Vec2F32 +f_dim_from_tag_size_string_list(F_Tag tag, F32 size, String8List list) +{ + ProfBeginFunction(); + Vec2F32 sum = {0}; + for(String8Node *n = list.first; n != 0; n = n->next) + { + Vec2F32 str_dim = f_dim_from_tag_size_string(tag, size, n->string); + sum.x += str_dim.x; + sum.y = Max(sum.y, str_dim.y); + } + ProfEnd(); + return sum; +} + +internal U64 +f_char_pos_from_tag_size_string_p(F_Tag tag, F32 size, String8 string, F32 p) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + U64 result = 0; + U64 best_offset = 0; + F32 best_distance = -1.f; + F32 x = 0; + for(U64 char_idx = 0; char_idx <= string.size; char_idx += 1) + { + F32 this_char_distance = fabsf(p - x); + if(this_char_distance < best_distance || best_distance < 0.f) + { + best_offset = char_idx; + best_distance = this_char_distance; + } + if(char_idx < string.size) + { + x += f_dim_from_tag_size_string(tag, size, str8_substr(string, r1u64(char_idx, char_idx+1))).x; + } + } + result = best_offset; + scratch_end(scratch); + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Metrics + +internal F_Metrics +f_metrics_from_tag_size(F_Tag tag, F32 size) +{ + ProfBeginFunction(); + FP_Metrics metrics = f_fp_metrics_from_tag(tag); + F_Metrics result = {0}; + { + result.ascent = size * metrics.ascent / metrics.design_units_per_em; + result.descent = size * metrics.descent / metrics.design_units_per_em; + result.line_gap = size * metrics.line_gap / metrics.design_units_per_em; + result.capital_height = size * metrics.capital_height / metrics.design_units_per_em; + } + ProfEnd(); + return result; +} + +internal F32 +f_line_height_from_metrics(F_Metrics *metrics) +{ + return metrics->ascent + metrics->descent + metrics->line_gap; +} + +//////////////////////////////// +//~ rjf: Main Calls + +internal void +f_init(void) +{ + Arena *arena = arena_alloc(); + f_state = push_array(arena, F_State, 1); + f_state->arena = arena; + f_state->font_hash_table_size = 64; + f_state->font_hash_table = push_array(arena, F_FontHashSlot, f_state->font_hash_table_size); + f_state->hash2style_slots_count = 1024; + f_state->hash2style_slots = push_array(arena, F_Hash2StyleRasterCacheSlot, f_state->hash2style_slots_count); +} diff --git a/src/font_cache/font_cache.h b/src/font_cache/font_cache.h new file mode 100644 index 00000000..b4ab5177 --- /dev/null +++ b/src/font_cache/font_cache.h @@ -0,0 +1,265 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef FONT_CACHE_H +#define FONT_CACHE_H + +//////////////////////////////// +//~ rjf: Rasterization Flags + +typedef U32 F_RunFlags; +enum +{ + F_RunFlag_Smooth = (1<<0), +}; + +//////////////////////////////// +//~ rjf: Handles & Tags + +typedef struct F_Hash F_Hash; +struct F_Hash +{ + U64 u64[2]; +}; + +typedef struct F_Tag F_Tag; +struct F_Tag +{ + U64 u64[2]; +}; + +//////////////////////////////// +//~ rjf: Draw Package Types (For Cache Queries) + +typedef struct F_Piece F_Piece; +struct F_Piece +{ + R_Handle texture; + Rng2S16 subrect; + Vec2S16 offset; + F32 advance; + U16 decode_size; +}; + +typedef struct F_PieceChunkNode F_PieceChunkNode; +struct F_PieceChunkNode +{ + F_PieceChunkNode *next; + F_Piece *v; + U64 count; + U64 cap; +}; + +typedef struct F_PieceChunkList F_PieceChunkList; +struct F_PieceChunkList +{ + F_PieceChunkNode *first; + F_PieceChunkNode *last; + U64 node_count; + U64 total_piece_count; +}; + +typedef struct F_PieceArray F_PieceArray; +struct F_PieceArray +{ + F_Piece *v; + U64 count; +}; + +typedef struct F_Run F_Run; +struct F_Run +{ + F_PieceArray pieces; + Vec2F32 dim; + F32 ascent; + F32 descent; +}; + +//////////////////////////////// +//~ rjf: Font Path -> Handle * Metrics * Path Cache Types + +typedef struct F_FontHashNode F_FontHashNode; +struct F_FontHashNode +{ + F_FontHashNode *hash_next; + F_Tag tag; + FP_Handle handle; + FP_Metrics metrics; + String8 path; +}; + +typedef struct F_FontHashSlot F_FontHashSlot; +struct F_FontHashSlot +{ + F_FontHashNode *first; + F_FontHashNode *last; +}; + +//////////////////////////////// +//~ rjf: Rasterization Cache Types + +typedef struct F_RasterCacheInfo F_RasterCacheInfo; +struct F_RasterCacheInfo +{ + Rng2S16 subrect; + S16 atlas_num; + F32 advance; +}; + +typedef struct F_Hash2InfoRasterCacheNode F_Hash2InfoRasterCacheNode; +struct F_Hash2InfoRasterCacheNode +{ + F_Hash2InfoRasterCacheNode *hash_next; + F_Hash2InfoRasterCacheNode *hash_prev; + U64 hash; + F_RasterCacheInfo info; +}; + +typedef struct F_Hash2InfoRasterCacheSlot F_Hash2InfoRasterCacheSlot; +struct F_Hash2InfoRasterCacheSlot +{ + F_Hash2InfoRasterCacheNode *first; + F_Hash2InfoRasterCacheNode *last; +}; + +typedef struct F_Hash2StyleRasterCacheNode F_Hash2StyleRasterCacheNode; +struct F_Hash2StyleRasterCacheNode +{ + F_Hash2StyleRasterCacheNode *hash_next; + F_Hash2StyleRasterCacheNode *hash_prev; + U64 style_hash; + F32 ascent; + F32 descent; + F_RasterCacheInfo *utf8_class1_direct_map; + U64 utf8_class1_direct_map_mask[4]; + U64 hash2info_slots_count; + F_Hash2InfoRasterCacheSlot *hash2info_slots; +}; + +typedef struct F_Hash2StyleRasterCacheSlot F_Hash2StyleRasterCacheSlot; +struct F_Hash2StyleRasterCacheSlot +{ + F_Hash2StyleRasterCacheNode *first; + F_Hash2StyleRasterCacheNode *last; +}; + +//////////////////////////////// +//~ rjf: Atlas Types + +typedef U32 F_AtlasRegionNodeFlags; +enum +{ + F_AtlasRegionNodeFlag_Taken = (1<<0), +}; + +typedef struct F_AtlasRegionNode F_AtlasRegionNode; +struct F_AtlasRegionNode +{ + F_AtlasRegionNode *parent; + F_AtlasRegionNode *children[Corner_COUNT]; + Vec2S16 max_free_size[Corner_COUNT]; + F_AtlasRegionNodeFlags flags; + U64 num_allocated_descendants; +}; + +typedef struct F_Atlas F_Atlas; +struct F_Atlas +{ + F_Atlas *next; + F_Atlas *prev; + R_Handle texture; + Vec2S16 root_dim; + F_AtlasRegionNode *root; +}; + +//////////////////////////////// +//~ rjf: Metrics + +typedef struct F_Metrics F_Metrics; +struct F_Metrics +{ + F32 ascent; + F32 descent; + F32 line_gap; + F32 capital_height; +}; + +//////////////////////////////// +//~ rjf: Main State Type + +typedef struct F_State F_State; +struct F_State +{ + Arena *arena; + + // rjf: font table + U64 font_hash_table_size; + F_FontHashSlot *font_hash_table; + + // rjf: hash -> raster cache table + U64 hash2style_slots_count; + F_Hash2StyleRasterCacheSlot *hash2style_slots; + + // rjf: atlas list + F_Atlas *first_atlas; + F_Atlas *last_atlas; +}; + +//////////////////////////////// +//~ rjf: Globals + +global F_State *f_state = 0; + +//////////////////////////////// +//~ rjf: Basic Functions + +internal F_Hash f_hash_from_string(String8 string); +internal U64 f_little_hash_from_string(String8 string); +internal Vec2S32 f_vertex_from_corner(Corner corner); + +//////////////////////////////// +//~ rjf: Font Tags + +internal F_Tag f_tag_zero(void); +internal B32 f_tag_match(F_Tag a, F_Tag b); +internal FP_Handle f_handle_from_tag(F_Tag tag); +internal FP_Metrics f_fp_metrics_from_tag(F_Tag tag); +internal F_Tag f_tag_from_path(String8 path); +internal F_Tag f_tag_from_static_data_string(String8 *data_ptr); +internal String8 f_path_from_tag(F_Tag tag); + +//////////////////////////////// +//~ rjf: Atlas + +internal Rng2S16 f_atlas_region_alloc(Arena *arena, F_Atlas *atlas, Vec2S16 needed_size); +internal void f_atlas_region_release(F_Atlas *atlas, Rng2S16 region); + +//////////////////////////////// +//~ rjf: Piece Type Functions + +internal F_Piece *f_piece_chunk_list_push_new(Arena *arena, F_PieceChunkList *list, U64 cap); +internal void f_piece_chunk_list_push(Arena *arena, F_PieceChunkList *list, U64 cap, F_Piece *piece); +internal F_PieceArray f_piece_array_from_chunk_list(Arena *arena, F_PieceChunkList *list); + +//////////////////////////////// +//~ rjf: Rasterization Cache + +internal F_Hash2StyleRasterCacheNode *f_hash2style_from_tag_size(F_Tag tag, F32 size); +internal F_Run f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F_RunFlags flags, String8 string); +internal String8List f_wrapped_string_lines_from_font_size_string_max(Arena *arena, F_Tag font, F32 size, String8 string, F32 max); +internal Vec2F32 f_dim_from_tag_size_string(F_Tag tag, F32 size, String8 string); +internal Vec2F32 f_dim_from_tag_size_string_list(F_Tag tag, F32 size, String8List list); +internal U64 f_char_pos_from_tag_size_string_p(F_Tag tag, F32 size, String8 string, F32 p); + +//////////////////////////////// +//~ rjf: Metrics + +internal F_Metrics f_metrics_from_tag_size(F_Tag tag, F32 size); +internal F32 f_line_height_from_metrics(F_Metrics *metrics); + +//////////////////////////////// +//~ rjf: Main Calls + +internal void f_init(void); + +#endif // FONT_CACHE_H diff --git a/src/font_provider/dwrite/font_provider_dwrite.cpp b/src/font_provider/dwrite/font_provider_dwrite.cpp new file mode 100644 index 00000000..5684c417 --- /dev/null +++ b/src/font_provider/dwrite/font_provider_dwrite.cpp @@ -0,0 +1,449 @@ +//////////////////////////////// +//~ rjf: Globals + +global FP_DWrite_State *fp_dwrite_state = 0; +global FP_DWrite_FontFileLoaderVTable fp_dwrite_static_data_font_file_loader__vtable = +{ + fp_dwrite_iunknown_noop__query_interface, + fp_dwrite_iunknown_noop__add_ref, + fp_dwrite_iunknown_noop__release, + fp_dwrite_static_font_file_loader__stream_from_key, +}; +global FP_DWrite_FontFileLoader fp_dwrite_static_data_font_file_loader = {&fp_dwrite_static_data_font_file_loader__vtable}; +global FP_DWrite_FontFileStreamVTable fp_dwrite_static_data_font_file_stream__vtable = +{ + fp_dwrite_iunknown_noop__query_interface, + fp_dwrite_iunknown_noop__add_ref, + fp_dwrite_iunknown_noop__release, + fp_dwrite_static_font_file_stream__read_file_fragment, + fp_dwrite_static_font_file_stream__release_file_fragment, + fp_dwrite_static_font_file_stream__get_file_size, + fp_dwrite_static_font_file_stream__get_last_write_time, +}; + +//////////////////////////////// +//~ rjf: Helpers + +//- rjf: handle conversion functions + +internal FP_DWrite_Font +fp_dwrite_font_from_handle(FP_Handle handle) +{ + FP_DWrite_Font result = {0}; + result.file = (IDWriteFontFile *)handle.u64[0]; + result.face = (IDWriteFontFace *)handle.u64[1]; + return result; +} + +internal FP_Handle +fp_dwrite_handle_from_font(FP_DWrite_Font font) +{ + FP_Handle result = {0}; + result.u64[0] = (U64)font.file; + result.u64[1] = (U64)font.face; + return result; +} + +//- rjf: file stream allocator + +internal FP_DWrite_FontFileStreamNode * +fp_dwrite_font_file_stream_node_alloc(String8 *data_ptr) +{ + FP_DWrite_FontFileStreamNode *node = 0; + for(FP_DWrite_FontFileStreamNode *n = fp_dwrite_state->first_stream_node; n != 0; n = n->next) + { + if(n->stream.data == data_ptr) + { + node = n; + break; + } + } + if(node == 0) + { + node = fp_dwrite_state->free_stream_node; + if(node != 0) + { + SLLStackPop(fp_dwrite_state->free_stream_node); + } + else + { + node = push_array_no_zero(fp_dwrite_state->arena, FP_DWrite_FontFileStreamNode, 1); + } + MemoryZeroStruct(node); + node->stream.lpVtbl = &fp_dwrite_static_data_font_file_stream__vtable; + node->stream.data = data_ptr; + DLLPushBack(fp_dwrite_state->first_stream_node, fp_dwrite_state->last_stream_node, node); + } + return node; +} + +internal void +fp_dwrite_font_file_stream_node_release(FP_DWrite_FontFileStreamNode *node) +{ + DLLPushBack(fp_dwrite_state->first_stream_node, fp_dwrite_state->last_stream_node, node); + SLLStackPush(fp_dwrite_state->free_stream_node, node); +} + +//- rjf: iunknown no-op helpers + +internal HRESULT +fp_dwrite_iunknown_noop__query_interface(void *obj, REFIID riid, void *ptr_to_object) +{ + return E_NOINTERFACE; +} + +internal ULONG +fp_dwrite_iunknown_noop__add_ref(void *obj) +{ + ULONG result = 1; + return result; +} + +internal ULONG +fp_dwrite_iunknown_noop__release(void *obj) +{ + ULONG result = 1; + return result; +} + +//- rjf: font file loader interface function implementations + +internal HRESULT +fp_dwrite_static_font_file_loader__stream_from_key(FP_DWrite_FontFileLoader *obj, void const *font_file_ref_key, UINT32 font_file_ref_key_size, IDWriteFontFileStream **stream_out) +{ + HRESULT result = S_OK; + String8 *key = *(String8 **)font_file_ref_key; + FP_DWrite_FontFileStreamNode *node = fp_dwrite_font_file_stream_node_alloc(key); + *stream_out = (IDWriteFontFileStream *)&node->stream; + return result; +} + +//- rjf: font file stream interface function implementations + +internal HRESULT +fp_dwrite_static_font_file_stream__read_file_fragment(FP_DWrite_FontFileStream *obj, void const **fragment_start, UINT64 file_offset, UINT64 fragment_size, void **fragment_context) +{ + HRESULT result = S_OK; + *fragment_start = obj->data->str + file_offset; + *fragment_context = 0; + return result; +} + +internal HRESULT +fp_dwrite_static_font_file_stream__release_file_fragment(FP_DWrite_FontFileStream *obj, void *fragment_context) +{ + HRESULT result = S_OK; + return result; +} + +internal HRESULT +fp_dwrite_static_font_file_stream__get_file_size(FP_DWrite_FontFileStream *obj, UINT64 *size_out) +{ + HRESULT result = S_OK; + *size_out = obj->data->size; + return result; +} + +internal HRESULT +fp_dwrite_static_font_file_stream__get_last_write_time(FP_DWrite_FontFileStream *obj, UINT64 *time_out) +{ + HRESULT result = S_OK; + *time_out = 0; + return result; +} + +//////////////////////////////// +//~ rjf: Backend Implementations + +fp_hook void +fp_init(void) +{ + ProfBeginFunction(); + HRESULT error = 0; + + //- rjf: initialize main state + { + Arena *arena = arena_alloc(); + fp_dwrite_state = push_array(arena, FP_DWrite_State, 1); + fp_dwrite_state->arena = arena; + } + + //- rjf: make dwrite factory + error = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown **)&fp_dwrite_state->factory); + + //- rjf: register static data font "loader" interface + error = fp_dwrite_state->factory->RegisterFontFileLoader((IDWriteFontFileLoader *)&fp_dwrite_static_data_font_file_loader); + + //- rjf: make base rendering params + error = fp_dwrite_state->factory->CreateRenderingParams(&fp_dwrite_state->base_rendering_params); + + //- rjf: make sharp rendering params + { + FLOAT gamma = 1.f; + FLOAT enhanced_contrast = fp_dwrite_state->base_rendering_params->GetEnhancedContrast(); + // FLOAT clear_type_level = fp_dwrite_state->base_rendering_params->GetClearTypeLevel(); + error = fp_dwrite_state->factory->CreateCustomRenderingParams(gamma, + enhanced_contrast, + 2.f, + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_RENDERING_MODE_GDI_NATURAL, + &fp_dwrite_state->rendering_params[FP_RasterMode_Sharp]); + } + + //- rjf: make smooth rendering params + { + FLOAT gamma = 1.f; + FLOAT enhanced_contrast = fp_dwrite_state->base_rendering_params->GetEnhancedContrast(); + // FLOAT clear_type_level = fp_dwrite_state->base_rendering_params->GetClearTypeLevel(); + error = fp_dwrite_state->factory->CreateCustomRenderingParams(gamma, + enhanced_contrast, + 2.f, + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, + &fp_dwrite_state->rendering_params[FP_RasterMode_Smooth]); + } + + //- rjf: make dwrite gdi interop + error = fp_dwrite_state->factory->GetGdiInterop(&fp_dwrite_state->gdi_interop); + + //- rjf: build render target for rasterization + fp_dwrite_state->bitmap_render_target_dim = v2s32(2048, 256); + error = fp_dwrite_state->gdi_interop->CreateBitmapRenderTarget(0, fp_dwrite_state->bitmap_render_target_dim.x, fp_dwrite_state->bitmap_render_target_dim.y, &fp_dwrite_state->bitmap_render_target); + fp_dwrite_state->bitmap_render_target->SetPixelsPerDip(1.0); + ProfEnd(); +} + +fp_hook FP_Handle +fp_font_open(String8 path) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + FP_DWrite_Font font = {0}; + HRESULT error = 0; + + //- rjf: open font file reference + error = fp_dwrite_state->factory->CreateFontFileReference((WCHAR *)path16.str, 0, &font.file); + + //- rjf: open font face + error = fp_dwrite_state->factory->CreateFontFace(DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font.file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font.face); + + //- rjf: handlify & return + FP_Handle handle = fp_dwrite_handle_from_font(font); + scratch_end(scratch); + ProfEnd(); + return handle; +} + +fp_hook FP_Handle +fp_font_open_from_static_data_string(String8 *data_ptr) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + FP_DWrite_Font font = {0}; + HRESULT error = 0; + + //- rjf: open font file reference + error = fp_dwrite_state->factory->CreateCustomFontFileReference(&data_ptr, sizeof(String8 *), (IDWriteFontFileLoader *)&fp_dwrite_static_data_font_file_loader, &font.file); + + //- rjf: open font face + error = fp_dwrite_state->factory->CreateFontFace(DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font.file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font.face); + + //- rjf: handlify & return + FP_Handle handle = fp_dwrite_handle_from_font(font); + scratch_end(scratch); + ProfEnd(); + return handle; +} + +fp_hook void +fp_font_close(FP_Handle handle) +{ + ProfBeginFunction(); + FP_DWrite_Font font = fp_dwrite_font_from_handle(handle); + if(font.face != 0) + { + font.face->Release(); + } + if(font.file != 0) + { + font.file->Release(); + } + ProfEnd(); +} + +fp_hook FP_Metrics +fp_metrics_from_font(FP_Handle handle) +{ + ProfBeginFunction(); + FP_DWrite_Font font = fp_dwrite_font_from_handle(handle); + DWRITE_FONT_METRICS metrics = {0}; + if(font.face != 0) + { + font.face->GetMetrics(&metrics); + } + FP_Metrics result = {0}; + { + result.design_units_per_em = (F32)metrics.designUnitsPerEm; + result.ascent = (F32)metrics.ascent; + result.descent = (F32)metrics.descent; + result.line_gap = (F32)metrics.lineGap; + result.capital_height = (F32)metrics.capHeight; + } + ProfEnd(); + return result; +} + +fp_hook NO_ASAN FP_RasterResult +fp_raster(Arena *arena, FP_Handle font_handle, F32 size, FP_RasterMode mode, String8 string) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + HRESULT error = 0; + String32 string32 = str32_from_8(scratch.arena, string); + FP_DWrite_Font font = fp_dwrite_font_from_handle(font_handle); + COLORREF bg_color = RGB(0, 0, 0); + COLORREF fg_color = RGB(255, 255, 255); + + //- rjf: get font metrics + DWRITE_FONT_METRICS font_metrics = {0}; + if(font.face != 0) + { + font.face->GetMetrics(&font_metrics); + } + F32 design_units_per_em = (F32)font_metrics.designUnitsPerEm; + + //- rjf: get glyph indices + U16 *glyph_indices = push_array_no_zero(scratch.arena, U16, string32.size); + if(font.face != 0) + { + error = font.face->GetGlyphIndices(string32.str, string32.size, glyph_indices); + } + + //- rjf: get metrics info + U64 glyphs_count = string32.size; + DWRITE_GLYPH_METRICS *glyphs_metrics = push_array_no_zero(scratch.arena, DWRITE_GLYPH_METRICS, glyphs_count); + if(font.face != 0) + { + error = font.face->GetGdiCompatibleGlyphMetrics((96.f/72.f)*size, 1.f, 0, 1, glyph_indices, glyphs_count, glyphs_metrics, 0); + } + + //- rjf: derive info from metrics + F32 advance = 0; + Vec2S16 atlas_dim = {0}; + if(font.face != 0) + { + atlas_dim.y = (S16)((96.f/72.f) * size * (font_metrics.ascent + font_metrics.descent) / design_units_per_em); + for(U64 idx = 0; idx < glyphs_count; idx += 1) + { + DWRITE_GLYPH_METRICS *glyph_metrics = glyphs_metrics + idx; + F32 glyph_advance_width = (96.f/72.f) * size * glyph_metrics->advanceWidth / design_units_per_em; + F32 glyph_advance_height = (96.f/72.f) * size * glyph_metrics->advanceHeight / design_units_per_em; + advance += glyph_advance_width; + atlas_dim.x = Max(atlas_dim.x, (S16)(advance+1)); + } + atlas_dim.x += 7; + atlas_dim.x -= atlas_dim.x%8; + atlas_dim.x += 4; + atlas_dim.y += 4; + } + + //- rjf: make dwrite bitmap for rendering + IDWriteBitmapRenderTarget *render_target = 0; + if(font.face != 0) + { + error = fp_dwrite_state->gdi_interop->CreateBitmapRenderTarget(0, atlas_dim.x, atlas_dim.y, &render_target); + render_target->SetPixelsPerDip(1.0); + } + + //- rjf: get bitmap & clear + HDC dc = 0; + if(font.face != 0) + { + dc = render_target->GetMemoryDC(); + HGDIOBJ original = SelectObject(dc, GetStockObject(DC_PEN)); + SetDCPenColor(dc, bg_color); + SelectObject(dc, GetStockObject(DC_BRUSH)); + SetDCBrushColor(dc, bg_color); + Rectangle(dc, 0, 0, atlas_dim.x, atlas_dim.y); + SelectObject(dc, original); + } + + //- rjf: draw glyph run + Vec2F32 draw_p = {1, (F32)atlas_dim.y - 2.f}; + if(font.face != 0) + { + F32 ascent = (96.f/72.f)*size * font_metrics.ascent / design_units_per_em; + F32 descent = (96.f/72.f)*size * font_metrics.descent / design_units_per_em; + draw_p.y -= descent; + } + DWRITE_GLYPH_RUN glyph_run = {0}; + if(font.face != 0) + { + glyph_run.fontFace = font.face; + glyph_run.fontEmSize = size * 96.f/72.f; + glyph_run.glyphCount = string32.size; + glyph_run.glyphIndices = glyph_indices; + } + RECT bounding_box = {0}; + if(font.face != 0) + { + error = render_target->DrawGlyphRun(draw_p.x, draw_p.y, + DWRITE_MEASURING_MODE_NATURAL, + &glyph_run, + fp_dwrite_state->rendering_params[mode], + fg_color, + &bounding_box); + } + + //- rjf: get bitmap + DIBSECTION dib = {0}; + if(font.face != 0) + { + HBITMAP bitmap = (HBITMAP)GetCurrentObject(dc, OBJ_BITMAP); + GetObject(bitmap, sizeof(dib), &dib); + } + + //- rjf: fill & return + FP_RasterResult result = {0}; + if(font.face != 0) + { + // rjf: fill basics + result.atlas_dim = atlas_dim; + result.atlas = push_array_no_zero(arena, U8, atlas_dim.x*atlas_dim.y*4); + result.advance = advance; + result.height = bounding_box.bottom + 1.f; + + // rjf: fill atlas + { + U8 *in_data = (U8 *)dib.dsBm.bmBits; + U64 in_pitch = (U64)dib.dsBm.bmWidthBytes; + U8 *out_data = (U8 *)result.atlas; + U64 out_pitch = atlas_dim.x * 4; + + U8 *in_line = (U8 *)in_data; + U8 *out_line = out_data; + for(U64 y = 0; y < atlas_dim.y; y += 1) + { + U8 *in_pixel = in_line; + U8 *out_pixel = out_line; + for(U64 x = 0; x < atlas_dim.x; x += 1) + { + U8 in_pixel_byte = in_pixel[0]; + out_pixel[0] = 255; + out_pixel[1] = 255; + out_pixel[2] = 255; + out_pixel[3] = in_pixel_byte; + in_pixel += 4; + out_pixel += 4; + } + in_line += in_pitch; + out_line += out_pitch; + } + } + render_target->Release(); + } + scratch_end(scratch); + ProfEnd(); + return result; +} diff --git a/src/font_provider/dwrite/font_provider_dwrite.h b/src/font_provider/dwrite/font_provider_dwrite.h new file mode 100644 index 00000000..437bef4e --- /dev/null +++ b/src/font_provider/dwrite/font_provider_dwrite.h @@ -0,0 +1,99 @@ +/* date = November 2nd 2022 11:31 am */ + +#ifndef FONT_PROVIDER_DWRITE_H +#define FONT_PROVIDER_DWRITE_H + +#include + +#pragma comment(lib, "gdi32.lib") +#pragma comment(lib, "dwrite.lib") + +//- rjf: font file loader interface types + +struct FP_DWrite_FontFileLoaderVTable +{ + HRESULT (*QueryInterface)(void *obj, REFIID riid, void *ptr_to_object); + ULONG (*AddRef)(void *obj); + ULONG (*Release)(void *obj); + HRESULT (*CreateStreamFromKey)(struct FP_DWrite_FontFileLoader *loader, void const *font_file_ref_key, UINT32 font_file_ref_key_size, IDWriteFontFileStream **stream_out); +}; + +struct FP_DWrite_FontFileLoader +{ + FP_DWrite_FontFileLoaderVTable *lpVtbl; +}; + +//- rjf: font file stream interface types + +struct FP_DWrite_FontFileStreamVTable +{ + HRESULT (*QueryInterface)(void *obj, REFIID riid, void *ptr_to_object); + ULONG (*AddRef)(void *obj); + ULONG (*Release)(void *obj); + HRESULT (*ReadFileFragment)(struct FP_DWrite_FontFileStream *obj, void const **fragment_start, UINT64 file_offset, UINT64 fragment_size, void **fragment_context); + HRESULT (*ReleaseFileFragment)(struct FP_DWrite_FontFileStream *obj, void *fragment_context); + HRESULT (*GetFileSize)(struct FP_DWrite_FontFileStream *obj, UINT64 *size_out); + HRESULT (*GetLastWriteTime)(struct FP_DWrite_FontFileStream *obj, UINT64 *time_out); +}; + +struct FP_DWrite_FontFileStream +{ + FP_DWrite_FontFileStreamVTable *lpVtbl; + String8 *data; +}; + +struct FP_DWrite_FontFileStreamNode +{ + FP_DWrite_FontFileStreamNode *next; + FP_DWrite_FontFileStreamNode *prev; + FP_DWrite_FontFileStream stream; +}; + +//- rjf: state & underlying handle types + +struct FP_DWrite_State +{ + Arena *arena; + IDWriteFactory *factory; + IDWriteRenderingParams *base_rendering_params; + IDWriteRenderingParams *rendering_params[FP_RasterMode_COUNT]; + IDWriteGdiInterop *gdi_interop; + Vec2S32 bitmap_render_target_dim; + IDWriteBitmapRenderTarget *bitmap_render_target; + FP_DWrite_FontFileStreamNode *first_stream_node; + FP_DWrite_FontFileStreamNode *last_stream_node; + FP_DWrite_FontFileStreamNode *free_stream_node; +}; + +struct FP_DWrite_Font +{ + IDWriteFontFile *file; + IDWriteFontFace *face; +}; + +//////////////////////////////// +//~ rjf: Helpers + +//- rjf: handle conversion functions +internal FP_DWrite_Font fp_dwrite_font_from_handle(FP_Handle handle); +internal FP_Handle fp_dwrite_handle_from_font(FP_DWrite_Font font); + +//- rjf: file stream allocator +internal FP_DWrite_FontFileStreamNode *fp_dwrite_font_file_stream_node_alloc(String8 *data_ptr); +internal void fp_dwrite_font_file_stream_node_release(FP_DWrite_FontFileStreamNode *node); + +//- rjf: iunknown no-op helpers +internal HRESULT fp_dwrite_iunknown_noop__query_interface(void *obj, REFIID riid, void *ptr_to_object); +internal ULONG fp_dwrite_iunknown_noop__add_ref(void *obj); +internal ULONG fp_dwrite_iunknown_noop__release(void *obj); + +//- rjf: font file loader interface function implementations +internal HRESULT fp_dwrite_static_font_file_loader__stream_from_key(FP_DWrite_FontFileLoader *obj, void const *font_file_ref_key, UINT32 font_file_ref_key_size, IDWriteFontFileStream **stream_out); + +//- rjf: font file stream interface function implementations +internal HRESULT fp_dwrite_static_font_file_stream__read_file_fragment(FP_DWrite_FontFileStream *obj, void const **fragment_start, UINT64 file_offset, UINT64 fragment_size, void **fragment_context); +internal HRESULT fp_dwrite_static_font_file_stream__release_file_fragment(FP_DWrite_FontFileStream *obj, void *fragment_context); +internal HRESULT fp_dwrite_static_font_file_stream__get_file_size(FP_DWrite_FontFileStream *obj, UINT64 *size_out); +internal HRESULT fp_dwrite_static_font_file_stream__get_last_write_time(FP_DWrite_FontFileStream *obj, UINT64 *time_out); + +#endif // FONT_PROVIDER_DWRITE_H diff --git a/src/font_provider/dwrite/font_provider_dwrite_main.cpp b/src/font_provider/dwrite/font_provider_dwrite_main.cpp new file mode 100644 index 00000000..e145de25 --- /dev/null +++ b/src/font_provider/dwrite/font_provider_dwrite_main.cpp @@ -0,0 +1,12 @@ +#define SUPPLEMENT_UNIT 1 + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "font_provider/font_provider.h" + +#include "font_provider_dwrite.h" +#include "font_provider_dwrite.cpp" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "font_provider/font_provider.c" diff --git a/src/font_provider/font_provider.c b/src/font_provider/font_provider.c new file mode 100644 index 00000000..8a500e38 --- /dev/null +++ b/src/font_provider/font_provider.c @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal FP_Handle +fp_handle_zero(void) +{ + FP_Handle result = {0}; + return result; +} + +internal B32 +fp_handle_match(FP_Handle a, FP_Handle b) +{ + return (a.u64[0] == b.u64[0] && a.u64[1] == b.u64[1]); +} diff --git a/src/font_provider/font_provider.h b/src/font_provider/font_provider.h new file mode 100644 index 00000000..9abf14c1 --- /dev/null +++ b/src/font_provider/font_provider.h @@ -0,0 +1,61 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef FONT_PROVIDER_H +#define FONT_PROVIDER_H + +#define fp_hook C_LINKAGE + +//////////////////////////////// +//~ rjf: Types + +typedef enum FP_RasterMode +{ + FP_RasterMode_Sharp, + FP_RasterMode_Smooth, + FP_RasterMode_COUNT +} +FP_RasterMode; + +typedef struct FP_Handle FP_Handle; +struct FP_Handle +{ + U64 u64[2]; +}; + +typedef struct FP_Metrics FP_Metrics; +struct FP_Metrics +{ + F32 design_units_per_em; + F32 ascent; + F32 descent; + F32 line_gap; + F32 capital_height; +}; + +typedef struct FP_RasterResult FP_RasterResult; +struct FP_RasterResult +{ + Vec2S16 atlas_dim; + void *atlas; + F32 advance; + S16 height; +}; + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal FP_Handle fp_handle_zero(void); +internal B32 fp_handle_match(FP_Handle a, FP_Handle b); + +//////////////////////////////// +//~ rjf: Backend Hooks + +fp_hook void fp_init(void); +fp_hook FP_Handle fp_font_open(String8 path); +fp_hook FP_Handle fp_font_open_from_static_data_string(String8 *data_ptr); +fp_hook void fp_font_close(FP_Handle handle); +fp_hook FP_Metrics fp_metrics_from_font(FP_Handle font); +fp_hook NO_ASAN FP_RasterResult fp_raster(Arena *arena, FP_Handle font, F32 size, FP_RasterMode mode, String8 string); + +#endif // FONT_PROVIDER_H diff --git a/src/font_provider/font_provider_inc.c b/src/font_provider/font_provider_inc.c new file mode 100644 index 00000000..92f0554c --- /dev/null +++ b/src/font_provider/font_provider_inc.c @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "font_provider.c" + +#if LANG_CPP +# if FP_BACKEND == FP_BACKEND_DWRITE +# include "dwrite/font_provider_dwrite.cpp" +# else +# error Font provider backend not specified. +# endif +#endif diff --git a/src/font_provider/font_provider_inc.h b/src/font_provider/font_provider_inc.h new file mode 100644 index 00000000..3abf829e --- /dev/null +++ b/src/font_provider/font_provider_inc.h @@ -0,0 +1,35 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef FONT_PROVIDER_INC_H +#define FONT_PROVIDER_INC_H + +//////////////////////////////// +//~ rjf: Backend Constants + +#define FP_BACKEND_DWRITE 1 + +//////////////////////////////// +//~ rjf: Decide On Backend + +#if !defined(FP_BACKEND) && OS_WINDOWS +# define FP_BACKEND FP_BACKEND_DWRITE +#endif + +//////////////////////////////// +//~ rjf: Main Includes + +#include "font_provider.h" + +//////////////////////////////// +//~ rjf: Backend Includes + +#if LANG_CPP +# if FP_BACKEND == FP_BACKEND_DWRITE +# include "dwrite/font_provider_dwrite.h" +# else +# error Font provider backend not specified. +# endif +#endif + +#endif // FONT_PROVIDER_INC_H diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c new file mode 100644 index 00000000..fd96bfdc --- /dev/null +++ b/src/geo_cache/geo_cache.c @@ -0,0 +1,445 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +geo_init(void) +{ + Arena *arena = arena_alloc(); + geo_shared = push_array(arena, GEO_Shared, 1); + geo_shared->arena = arena; + geo_shared->slots_count = 1024; + geo_shared->stripes_count = 64; + geo_shared->slots = push_array(arena, GEO_Slot, geo_shared->slots_count); + geo_shared->stripes = push_array(arena, GEO_Stripe, geo_shared->stripes_count); + geo_shared->stripes_free_nodes = push_array(arena, GEO_Node *, geo_shared->stripes_count); + for(U64 idx = 0; idx < geo_shared->stripes_count; idx += 1) + { + geo_shared->stripes[idx].arena = arena_alloc(); + geo_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + geo_shared->stripes[idx].cv = os_condition_variable_alloc(); + } + geo_shared->fallback_slots_count = 1024; + geo_shared->fallback_stripes_count = 64; + geo_shared->fallback_slots = push_array(arena, GEO_KeyFallbackSlot, geo_shared->fallback_slots_count); + geo_shared->fallback_stripes = push_array(arena, GEO_Stripe, geo_shared->fallback_stripes_count); + for(U64 idx = 0; idx < geo_shared->fallback_stripes_count; idx += 1) + { + geo_shared->fallback_stripes[idx].arena = arena_alloc(); + geo_shared->fallback_stripes[idx].rw_mutex = os_rw_mutex_alloc(); + geo_shared->fallback_stripes[idx].cv = os_condition_variable_alloc(); + } + geo_shared->u2x_ring_size = KB(64); + geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size); + geo_shared->u2x_ring_cv = os_condition_variable_alloc(); + geo_shared->u2x_ring_mutex = os_mutex_alloc(); + geo_shared->xfer_thread_count = Min(4, os_logical_core_count()-1); + geo_shared->xfer_threads = push_array(arena, OS_Handle, geo_shared->xfer_thread_count); + for(U64 idx = 0; idx < geo_shared->xfer_thread_count; idx += 1) + { + geo_shared->xfer_threads[idx] = os_launch_thread(geo_xfer_thread__entry_point, (void *)idx, 0); + } + geo_shared->evictor_thread = os_launch_thread(geo_evictor_thread__entry_point, 0, 0); +} + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void +geo_tctx_ensure_inited(void) +{ + if(geo_tctx == 0) + { + Arena *arena = arena_alloc(); + geo_tctx = push_array(arena, GEO_TCTX, 1); + geo_tctx->arena = arena; + } +} + +//////////////////////////////// +//~ rjf: User Clock + +internal void +geo_user_clock_tick(void) +{ + ins_atomic_u64_inc_eval(&geo_shared->user_clock_idx); +} + +internal U64 +geo_user_clock_idx(void) +{ + return ins_atomic_u64_eval(&geo_shared->user_clock_idx); +} + +//////////////////////////////// +//~ rjf: Scoped Access + +internal GEO_Scope * +geo_scope_open(void) +{ + geo_tctx_ensure_inited(); + GEO_Scope *scope = geo_tctx->free_scope; + if(scope) + { + SLLStackPop(geo_tctx->free_scope); + } + else + { + scope = push_array_no_zero(geo_tctx->arena, GEO_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +geo_scope_close(GEO_Scope *scope) +{ + for(GEO_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) + { + U128 hash = touch->hash; + next = touch->next; + U64 slot_idx = hash.u64[1]%geo_shared->slots_count; + U64 stripe_idx = slot_idx%geo_shared->stripes_count; + GEO_Slot *slot = &geo_shared->slots[slot_idx]; + GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(GEO_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_dec_eval(&n->scope_ref_count); + break; + } + } + } + SLLStackPush(geo_tctx->free_touch, touch); + } + SLLStackPush(geo_tctx->free_scope, scope); +} + +internal void +geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node) +{ + GEO_Touch *touch = geo_tctx->free_touch; + ins_atomic_u64_inc_eval(&node->scope_ref_count); + ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, geo_user_clock_idx()); + if(touch != 0) + { + SLLStackPop(geo_tctx->free_touch); + } + else + { + touch = push_array_no_zero(geo_tctx->arena, GEO_Touch, 1); + } + MemoryZeroStruct(touch); + touch->hash = node->hash; + SLLStackPush(scope->top_touch, touch); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal R_Handle +geo_buffer_from_key_hash(GEO_Scope *scope, U128 key, U128 hash) +{ + R_Handle handle = {0}; + if(!u128_match(hash, u128_zero())) + { + U64 slot_idx = hash.u64[1]%geo_shared->slots_count; + U64 stripe_idx = slot_idx%geo_shared->stripes_count; + GEO_Slot *slot = &geo_shared->slots[slot_idx]; + GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; + B32 found = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(GEO_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + handle = n->buffer; + found = !r_handle_match(r_handle_zero(), handle); + geo_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + B32 node_is_new = 0; + if(!found) + { + OS_MutexScopeW(stripe->rw_mutex) + { + GEO_Node *node = 0; + for(GEO_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + node = n; + break; + } + } + if(node == 0) + { + node = geo_shared->stripes_free_nodes[stripe_idx]; + if(node) + { + SLLStackPop(geo_shared->stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array_no_zero(stripe->arena, GEO_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->hash = hash; + node_is_new = 1; + } + } + } + if(node_is_new) + { + geo_u2x_enqueue_req(key, hash, max_U64); + } + if(r_handle_match(handle, r_handle_zero())) + { + U128 fallback_hash = {0}; + U64 fallback_slot_idx = key.u64[1]%geo_shared->fallback_slots_count; + U64 fallback_stripe_idx = fallback_slot_idx%geo_shared->fallback_stripes_count; + GEO_KeyFallbackSlot *fallback_slot = &geo_shared->fallback_slots[fallback_slot_idx]; + GEO_Stripe *fallback_stripe = &geo_shared->fallback_stripes[fallback_stripe_idx]; + OS_MutexScopeR(fallback_stripe->rw_mutex) for(GEO_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) + { + if(u128_match(key, n->key)) + { + fallback_hash = n->hash; + break; + } + } + if(!u128_match(fallback_hash, u128_zero())) + { + U64 retry_slot_idx = fallback_hash.u64[1]%geo_shared->slots_count; + U64 retry_stripe_idx = retry_slot_idx%geo_shared->stripes_count; + GEO_Slot *retry_slot = &geo_shared->slots[retry_slot_idx]; + GEO_Stripe *retry_stripe = &geo_shared->stripes[retry_stripe_idx]; + OS_MutexScopeR(retry_stripe->rw_mutex) + { + for(GEO_Node *n = retry_slot->first; n != 0; n = n->next) + { + if(u128_match(fallback_hash, n->hash)) + { + handle = n->buffer; + geo_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + } + } + } + return handle; +} + +//////////////////////////////// +//~ rjf: Transfer Threads + +internal B32 +geo_u2x_enqueue_req(U128 key, U128 hash, U64 endt_us) +{ + B32 good = 0; + OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) + { + U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; + U64 available_size = geo_shared->u2x_ring_size-unconsumed_size; + if(available_size >= sizeof(key)+sizeof(hash)) + { + good = 1; + geo_shared->u2x_ring_write_pos += ring_write_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_write_pos, &key); + geo_shared->u2x_ring_write_pos += ring_write_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_write_pos, &hash); + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, endt_us); + } + if(good) + { + os_condition_variable_broadcast(geo_shared->u2x_ring_cv); + } + return good; +} + +internal void +geo_u2x_dequeue_req(U128 *key_out, U128 *hash_out) +{ + OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) + { + U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; + if(unconsumed_size >= sizeof(*key_out)+sizeof(*hash_out)) + { + geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, key_out); + geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, hash_out); + break; + } + os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, max_U64); + } + os_condition_variable_broadcast(geo_shared->u2x_ring_cv); +} + +internal void +geo_xfer_thread__entry_point(void *p) +{ + TCTX tctx_ = {0}; + tctx_init_and_equip(&tctx_); + for(;;) + { + HS_Scope *scope = hs_scope_open(); + + //- rjf: decode + U128 key = {0}; + U128 hash = {0}; + geo_u2x_dequeue_req(&key, &hash); + + //- rjf: unpack hash + U64 slot_idx = hash.u64[1]%geo_shared->slots_count; + U64 stripe_idx = slot_idx%geo_shared->stripes_count; + GEO_Slot *slot = &geo_shared->slots[slot_idx]; + GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; + + //- rjf: take task + B32 got_task = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(GEO_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); + break; + } + } + } + + //- rjf: hash -> data + String8 data = {0}; + if(got_task) + { + data = hs_data_from_hash(scope, hash); + } + + //- rjf: data -> buffer + R_Handle buffer = {0}; + if(got_task && data.size != 0) + { + buffer = r_buffer_alloc(R_BufferKind_Static, data.size, data.str); + } + + //- rjf: commit results to cache + if(got_task) OS_MutexScopeW(stripe->rw_mutex) + { + for(GEO_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + n->buffer = buffer; + ins_atomic_u32_eval_assign(&n->is_working, 0); + ins_atomic_u64_inc_eval(&n->load_count); + break; + } + } + } + + //- rjf: commit this key/hash pair to fallback cache + if(got_task && !u128_match(key, u128_zero()) && !u128_match(hash, u128_zero())) + { + U64 fallback_slot_idx = key.u64[1]%geo_shared->fallback_slots_count; + U64 fallback_stripe_idx = fallback_slot_idx%geo_shared->fallback_stripes_count; + GEO_KeyFallbackSlot *fallback_slot = &geo_shared->fallback_slots[fallback_slot_idx]; + GEO_Stripe *fallback_stripe = &geo_shared->fallback_stripes[fallback_stripe_idx]; + OS_MutexScopeW(fallback_stripe->rw_mutex) + { + GEO_KeyFallbackNode *node = 0; + for(GEO_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(fallback_stripe->arena, GEO_KeyFallbackNode, 1); + SLLQueuePush(fallback_slot->first, fallback_slot->last, node); + } + node->key = key; + node->hash = hash; + } + } + + hs_scope_close(scope); + } +} + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void +geo_evictor_thread__entry_point(void *p) +{ + for(;;) + { + U64 check_time_us = os_now_microseconds(); + U64 check_time_user_clocks = geo_user_clock_idx(); + U64 evict_threshold_us = 10*1000000; + U64 evict_threshold_user_clocks = 10; + for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1) + { + U64 stripe_idx = slot_idx%geo_shared->stripes_count; + GEO_Slot *slot = &geo_shared->slots[slot_idx]; + GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; + B32 slot_has_work = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(GEO_Node *n = slot->first; n != 0; n = n->next) + { + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + n->load_count != 0 && + n->is_working == 0) + { + slot_has_work = 1; + break; + } + } + } + if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + { + for(GEO_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + n->load_count != 0 && + n->is_working == 0) + { + DLLRemove(slot->first, slot->last, n); + if(!r_handle_match(n->buffer, r_handle_zero())) + { + r_buffer_release(n->buffer); + } + SLLStackPush(geo_shared->stripes_free_nodes[stripe_idx], n); + } + } + } + os_sleep_milliseconds(5); + } + os_sleep_milliseconds(1000); + } +} diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h new file mode 100644 index 00000000..256f29ac --- /dev/null +++ b/src/geo_cache/geo_cache.h @@ -0,0 +1,168 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef GEO_CACHE_H +#define GEO_CACHE_H + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct GEO_KeyFallbackNode GEO_KeyFallbackNode; +struct GEO_KeyFallbackNode +{ + GEO_KeyFallbackNode *next; + U128 key; + U128 hash; +}; + +typedef struct GEO_KeyFallbackSlot GEO_KeyFallbackSlot; +struct GEO_KeyFallbackSlot +{ + GEO_KeyFallbackNode *first; + GEO_KeyFallbackNode *last; +}; + +typedef struct GEO_Node GEO_Node; +struct GEO_Node +{ + GEO_Node *next; + GEO_Node *prev; + U128 hash; + R_Handle buffer; + B32 is_working; + U64 scope_ref_count; + U64 last_time_touched_us; + U64 last_user_clock_idx_touched; + U64 load_count; +}; + +typedef struct GEO_Slot GEO_Slot; +struct GEO_Slot +{ + GEO_Node *first; + GEO_Node *last; +}; + +typedef struct GEO_Stripe GEO_Stripe; +struct GEO_Stripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access + +typedef struct GEO_Touch GEO_Touch; +struct GEO_Touch +{ + GEO_Touch *next; + U128 hash; +}; + +typedef struct GEO_Scope GEO_Scope; +struct GEO_Scope +{ + GEO_Scope *next; + GEO_Touch *top_touch; +}; + +//////////////////////////////// +//~ rjf: Thread Context + +typedef struct GEO_TCTX GEO_TCTX; +struct GEO_TCTX +{ + Arena *arena; + GEO_Scope *free_scope; + GEO_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State + +typedef struct GEO_Shared GEO_Shared; +struct GEO_Shared +{ + Arena *arena; + + // rjf: user clock + U64 user_clock_idx; + + // rjf: cache + U64 slots_count; + U64 stripes_count; + GEO_Slot *slots; + GEO_Stripe *stripes; + GEO_Node **stripes_free_nodes; + + // rjf: fallback cache + U64 fallback_slots_count; + U64 fallback_stripes_count; + GEO_KeyFallbackSlot *fallback_slots; + GEO_Stripe *fallback_stripes; + + // rjf: user -> xfer thread + U64 u2x_ring_size; + U8 *u2x_ring_base; + U64 u2x_ring_write_pos; + U64 u2x_ring_read_pos; + OS_Handle u2x_ring_cv; + OS_Handle u2x_ring_mutex; + + // rjf: transfer threads + U64 xfer_thread_count; + OS_Handle *xfer_threads; + + // rjf: evictor thread + OS_Handle evictor_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +thread_static GEO_TCTX *geo_tctx = 0; +global GEO_Shared *geo_shared = 0; + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void geo_init(void); + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void geo_tctx_ensure_inited(void); + +//////////////////////////////// +//~ rjf: User Clock + +internal void geo_user_clock_tick(void); +internal U64 geo_user_clock_idx(void); + +//////////////////////////////// +//~ rjf: Scoped Access + +internal GEO_Scope *geo_scope_open(void); +internal void geo_scope_close(GEO_Scope *scope); +internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal R_Handle geo_buffer_from_key_hash(GEO_Scope *scope, U128 key, U128 hash); + +//////////////////////////////// +//~ rjf: Transfer Threads + +internal B32 geo_u2x_enqueue_req(U128 key, U128 hash, U64 endt_us); +internal void geo_u2x_dequeue_req(U128 *key_out, U128 *hash_out); +internal void geo_xfer_thread__entry_point(void *p); + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void geo_evictor_thread__entry_point(void *p); + +#endif //GEO_CACHE_H diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c new file mode 100644 index 00000000..b8d89673 --- /dev/null +++ b/src/hash_store/hash_store.c @@ -0,0 +1,331 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Helpers + +#if !defined(BLAKE2_H) +#define HAVE_SSE2 +#include "third_party/blake2/blake2.h" +#include "third_party/blake2/blake2b.c" +#endif + +internal U128 +hs_hash_from_data(String8 data) +{ + U128 u128 = {0}; + blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0); + return u128; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +hs_init(void) +{ + Arena *arena = arena_alloc(); + hs_shared = push_array(arena, HS_Shared, 1); + hs_shared->arena = arena; + hs_shared->slots_count = 4096; + hs_shared->stripes_count = 64; + hs_shared->slots = push_array(arena, HS_Slot, hs_shared->slots_count); + hs_shared->stripes = push_array(arena, HS_Stripe, hs_shared->stripes_count); + hs_shared->stripes_free_nodes = push_array(arena, HS_Node *, hs_shared->stripes_count); + for(U64 idx = 0; idx < hs_shared->stripes_count; idx += 1) + { + HS_Stripe *stripe = &hs_shared->stripes[idx]; + stripe->arena = arena_alloc(); + stripe->rw_mutex = os_rw_mutex_alloc(); + stripe->cv = os_condition_variable_alloc(); + } + hs_shared->key_slots_count = 4096; + hs_shared->key_stripes_count = 64; + hs_shared->key_slots = push_array(arena, HS_KeySlot, hs_shared->key_slots_count); + hs_shared->key_stripes = push_array(arena, HS_Stripe, hs_shared->key_stripes_count); + for(U64 idx = 0; idx < hs_shared->key_stripes_count; idx += 1) + { + HS_Stripe *stripe = &hs_shared->key_stripes[idx]; + stripe->arena = arena_alloc(); + stripe->rw_mutex = os_rw_mutex_alloc(); + stripe->cv = os_condition_variable_alloc(); + } + hs_shared->evictor_thread = os_launch_thread(hs_evictor_thread__entry_point, 0, 0); +} + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void +hs_tctx_ensure_inited(void) +{ + if(hs_tctx == 0) + { + Arena *arena = arena_alloc(); + hs_tctx = push_array(arena, HS_TCTX, 1); + hs_tctx->arena = arena; + } +} + +//////////////////////////////// +//~ rjf: Cache Submission + +internal U128 +hs_submit_data(U128 key, Arena **data_arena, String8 data) +{ + U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; + HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; + HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; + U128 hash = hs_hash_from_data(data); + U64 slot_idx = hash.u64[1]%hs_shared->slots_count; + U64 stripe_idx = slot_idx%hs_shared->stripes_count; + HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; + + //- rjf: commit data to cache - if already there, just bump key refcount + OS_MutexScopeW(stripe->rw_mutex) + { + HS_Node *existing_node = 0; + for(HS_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + existing_node = n; + break; + } + } + if(existing_node == 0) + { + HS_Node *node = hs_shared->stripes_free_nodes[stripe_idx]; + if(node) + { + SLLStackPop(hs_shared->stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array(stripe->arena, HS_Node, 1); + } + node->hash = hash; + node->arena = *data_arena; + node->data = data; + node->scope_ref_count = 0; + node->key_ref_count = 1; + DLLPushBack(slot->first, slot->last, node); + } + else + { + existing_node->key_ref_count += 1; + arena_release(*data_arena); + } + *data_arena = 0; + } + + //- rjf: commit this hash to key cache + U128 key_old_hash = {0}; + OS_MutexScopeW(key_stripe->rw_mutex) + { + HS_KeyNode *key_node = 0; + for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + key_node = n; + break; + } + } + if(!key_node) + { + key_node = push_array(key_stripe->arena, HS_KeyNode, 1); + key_node->key = key; + SLLQueuePush(key_slot->first, key_slot->last, key_node); + } + if(key_node) + { + key_old_hash = key_node->hash; + key_node->hash = hash; + } + } + + //- rjf: if this key was correllated with an old hash, dec key ref count of old hash + if(!u128_match(key_old_hash, u128_zero())) + { + U64 old_hash_slot_idx = key_old_hash.u64[1]%hs_shared->slots_count; + U64 old_hash_stripe_idx = old_hash_slot_idx%hs_shared->stripes_count; + HS_Slot *old_hash_slot = &hs_shared->slots[old_hash_slot_idx]; + HS_Stripe *old_hash_stripe = &hs_shared->stripes[old_hash_stripe_idx]; + OS_MutexScopeR(old_hash_stripe->rw_mutex) + { + for(HS_Node *n = old_hash_slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, key_old_hash)) + { + ins_atomic_u64_dec_eval(&n->key_ref_count); + break; + } + } + } + } + + return hash; +} + +//////////////////////////////// +//~ rjf: Scoped Access + +internal HS_Scope * +hs_scope_open(void) +{ + hs_tctx_ensure_inited(); + HS_Scope *scope = hs_tctx->free_scope; + if(scope) + { + SLLStackPop(hs_tctx->free_scope); + } + else + { + scope = push_array_no_zero(hs_tctx->arena, HS_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +hs_scope_close(HS_Scope *scope) +{ + for(HS_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) + { + U128 hash = touch->hash; + next = touch->next; + U64 slot_idx = hash.u64[1]%hs_shared->slots_count; + U64 stripe_idx = slot_idx%hs_shared->stripes_count; + HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(HS_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_dec_eval(&n->scope_ref_count); + break; + } + } + } + SLLStackPush(hs_tctx->free_touch, touch); + } + SLLStackPush(hs_tctx->free_scope, scope); +} + +internal void +hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node) +{ + HS_Touch *touch = hs_tctx->free_touch; + ins_atomic_u64_inc_eval(&node->scope_ref_count); + if(touch != 0) + { + SLLStackPop(hs_tctx->free_touch); + } + else + { + touch = push_array_no_zero(hs_tctx->arena, HS_Touch, 1); + } + MemoryZeroStruct(touch); + touch->hash = node->hash; + SLLStackPush(scope->top_touch, touch); +} + +//////////////////////////////// +//~ rjf: Cache Lookup + +internal U128 +hs_hash_from_key(U128 key) +{ + U128 result = {0}; + U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; + HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; + HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; + OS_MutexScopeR(key_stripe->rw_mutex) + { + for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + result = n->hash; + break; + } + } + } + return result; +} + +internal String8 +hs_data_from_hash(HS_Scope *scope, U128 hash) +{ + String8 result = {0}; + U64 slot_idx = hash.u64[1]%hs_shared->slots_count; + U64 stripe_idx = slot_idx%hs_shared->stripes_count; + HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(HS_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + result = n->data; + hs_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Evictor Thread + +internal void +hs_evictor_thread__entry_point(void *p) +{ + for(;;) + { + for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1) + { + U64 stripe_idx = slot_idx%hs_shared->stripes_count; + HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; + B32 slot_has_work = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(HS_Node *n = slot->first; n != 0; n = n->next) + { + U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); + U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0) + { + slot_has_work = 1; + break; + } + } + } + if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + { + for(HS_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); + U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0) + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(hs_shared->stripes_free_nodes[stripe_idx], n); + arena_release(n->arena); + } + } + } + } + os_sleep_milliseconds(1000); + } +} diff --git a/src/hash_store/hash_store.h b/src/hash_store/hash_store.h new file mode 100644 index 00000000..10e11e3d --- /dev/null +++ b/src/hash_store/hash_store.h @@ -0,0 +1,149 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef HASH_STORE_H +#define HASH_STORE_H + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct HS_KeyNode HS_KeyNode; +struct HS_KeyNode +{ + HS_KeyNode *next; + U128 key; + U128 hash; +}; + +typedef struct HS_KeySlot HS_KeySlot; +struct HS_KeySlot +{ + HS_KeyNode *first; + HS_KeyNode *last; +}; + +typedef struct HS_Node HS_Node; +struct HS_Node +{ + HS_Node *next; + HS_Node *prev; + U128 hash; + Arena *arena; + String8 data; + U64 scope_ref_count; + U64 key_ref_count; +}; + +typedef struct HS_Slot HS_Slot; +struct HS_Slot +{ + HS_Node *first; + HS_Node *last; +}; + +typedef struct HS_Stripe HS_Stripe; +struct HS_Stripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access + +typedef struct HS_Touch HS_Touch; +struct HS_Touch +{ + HS_Touch *next; + U128 hash; +}; + +typedef struct HS_Scope HS_Scope; +struct HS_Scope +{ + HS_Scope *next; + HS_Touch *top_touch; +}; + +//////////////////////////////// +//~ rjf: Thread Context + +typedef struct HS_TCTX HS_TCTX; +struct HS_TCTX +{ + Arena *arena; + HS_Scope *free_scope; + HS_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State + +typedef struct HS_Shared HS_Shared; +struct HS_Shared +{ + Arena *arena; + + // rjf: main data cache + U64 slots_count; + U64 stripes_count; + HS_Slot *slots; + HS_Stripe *stripes; + HS_Node **stripes_free_nodes; + + // rjf: key cache + U64 key_slots_count; + U64 key_stripes_count; + HS_KeySlot *key_slots; + HS_Stripe *key_stripes; + + // rjf: evictor thread + OS_Handle evictor_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +thread_static HS_TCTX *hs_tctx = 0; +global HS_Shared *hs_shared = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U128 hs_hash_from_data(String8 data); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void hs_init(void); + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void hs_tctx_ensure_inited(void); + +//////////////////////////////// +//~ rjf: Cache Submission/Derefs + +internal U128 hs_submit_data(U128 key, Arena **data_arena, String8 data); + +//////////////////////////////// +//~ rjf: Scoped Access + +internal HS_Scope *hs_scope_open(void); +internal void hs_scope_close(HS_Scope *scope); +internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal U128 hs_hash_from_key(U128 key); +internal String8 hs_data_from_hash(HS_Scope *scope, U128 hash); + +//////////////////////////////// +//~ rjf: Evictor Thread + +internal void hs_evictor_thread__entry_point(void *p); + +#endif // HASH_STORE_H diff --git a/src/mdesk/mdesk.c b/src/mdesk/mdesk.c new file mode 100644 index 00000000..f39af878 --- /dev/null +++ b/src/mdesk/mdesk.c @@ -0,0 +1,1093 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Message Type Functions + +internal void +md_msg_list_push(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, String8 string) +{ + MD_Msg *msg = push_array(arena, MD_Msg, 1); + msg->node = node; + msg->kind = kind; + msg->string = string; + SLLQueuePush(msgs->first, msgs->last, msg); + msgs->count += 1; + msgs->worst_message_kind = Max(kind, msgs->worst_message_kind); +} + +internal void +md_msg_list_pushf(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(arena, fmt, args); + md_msg_list_push(arena, msgs, node, kind, string); + va_end(args); +} + +internal void +md_msg_list_concat_in_place(MD_MsgList *dst, MD_MsgList *to_push) +{ + if(to_push->first != 0) + { + if(dst->last) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->count += to_push->count; + dst->worst_message_kind = Max(dst->worst_message_kind, to_push->worst_message_kind); + } + else + { + MemoryCopyStruct(dst, to_push); + } + } + MemoryZeroStruct(to_push); +} + +//////////////////////////////// +//~ rjf: Token Type Functions + +internal MD_Token +md_token_make(Rng1U64 range, MD_TokenFlags flags) +{ + MD_Token token = {range, flags}; + return token; +} + +internal B32 +md_token_match(MD_Token a, MD_Token b) +{ + return (a.range.min == b.range.min && + a.range.max == b.range.max && + a.flags == b.flags); +} + +internal String8List +md_string_list_from_token_flags(Arena *arena, MD_TokenFlags flags) +{ + String8List strs = {0}; + if(flags & MD_TokenFlag_Identifier ){str8_list_push(arena, &strs, str8_lit("Identifier"));} + if(flags & MD_TokenFlag_Numeric ){str8_list_push(arena, &strs, str8_lit("Numeric"));} + if(flags & MD_TokenFlag_StringLiteral ){str8_list_push(arena, &strs, str8_lit("StringLiteral"));} + if(flags & MD_TokenFlag_Symbol ){str8_list_push(arena, &strs, str8_lit("Symbol"));} + if(flags & MD_TokenFlag_Reserved ){str8_list_push(arena, &strs, str8_lit("Reserved"));} + if(flags & MD_TokenFlag_Comment ){str8_list_push(arena, &strs, str8_lit("Comment"));} + if(flags & MD_TokenFlag_Whitespace ){str8_list_push(arena, &strs, str8_lit("Whitespace"));} + if(flags & MD_TokenFlag_Newline ){str8_list_push(arena, &strs, str8_lit("Newline"));} + if(flags & MD_TokenFlag_BrokenComment ){str8_list_push(arena, &strs, str8_lit("BrokenComment"));} + if(flags & MD_TokenFlag_BrokenStringLiteral ){str8_list_push(arena, &strs, str8_lit("BrokenStringLiteral"));} + if(flags & MD_TokenFlag_BadCharacter ){str8_list_push(arena, &strs, str8_lit("BadCharacter"));} + return strs; +} + +internal void +md_token_chunk_list_push(Arena *arena, MD_TokenChunkList *list, U64 cap, MD_Token token) +{ + MD_TokenChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, MD_TokenChunkNode, 1); + node->cap = cap; + node->v = push_array_no_zero(arena, MD_Token, cap); + SLLQueuePush(list->first, list->last, node); + list->chunk_count += 1; + } + MemoryCopyStruct(&node->v[node->count], &token); + node->count += 1; + list->total_token_count += 1; +} + +internal MD_TokenArray +md_token_array_from_chunk_list(Arena *arena, MD_TokenChunkList *chunks) +{ + MD_TokenArray result = {0}; + result.count = chunks->total_token_count; + result.v = push_array_no_zero(arena, MD_Token, result.count); + U64 write_idx = 0; + for(MD_TokenChunkNode *n = chunks->first; n != 0; n = n->next) + { + MemoryCopy(result.v+write_idx, n->v, sizeof(MD_Token)*n->count); + write_idx += n->count; + } + return result; +} + +internal String8 +md_content_string_from_token_flags_str8(MD_TokenFlags flags, String8 string) +{ + U64 num_chop = 0; + U64 num_skip = 0; + { + num_skip += 3*!!(flags & MD_TokenFlag_StringTriplet); + num_chop += 3*!!(flags & MD_TokenFlag_StringTriplet); + num_skip += 1*(!(flags & MD_TokenFlag_StringTriplet) && flags & MD_TokenFlag_StringLiteral); + num_chop += 1*(!(flags & MD_TokenFlag_StringTriplet) && flags & MD_TokenFlag_StringLiteral); + } + String8 result = string; + result = str8_chop(result, num_chop); + result = str8_skip(result, num_skip); + return result; +} + +//////////////////////////////// +//~ rjf: Node Type Functions + +//- rjf: flag conversions + +internal MD_NodeFlags +md_node_flags_from_token_flags(MD_TokenFlags flags) +{ + MD_NodeFlags result = 0; + result |= MD_NodeFlag_Identifier*!!(flags&MD_TokenFlag_Identifier); + result |= MD_NodeFlag_Numeric*!!(flags&MD_TokenFlag_Numeric); + result |= MD_NodeFlag_StringLiteral*!!(flags&MD_TokenFlag_StringLiteral); + result |= MD_NodeFlag_Symbol*!!(flags&MD_TokenFlag_Symbol); + result |= MD_NodeFlag_StringSingleQuote *!!(flags&MD_TokenFlag_StringSingleQuote); + result |= MD_NodeFlag_StringDoubleQuote *!!(flags&MD_TokenFlag_StringDoubleQuote); + result |= MD_NodeFlag_StringTick*!!(flags&MD_TokenFlag_StringTick); + result |= MD_NodeFlag_StringTriplet*!!(flags&MD_TokenFlag_StringTriplet); + return result; +} + +//- rjf: nil + +internal B32 +md_node_is_nil(MD_Node *node) +{ + return (node == 0 || node == &md_nil_node || node->kind == MD_NodeKind_Nil); +} + +//- rjf: iteration + +internal MD_NodeRec +md_node_rec_depth_first(MD_Node *node, MD_Node *subtree_root, U64 child_off, U64 sib_off) +{ + MD_NodeRec rec = {0}; + rec.next = &md_nil_node; + if(!md_node_is_nil(MemberFromOffset(MD_Node *, node, child_off))) + { + rec.next = MemberFromOffset(MD_Node *, node, child_off); + rec.push_count = 1; + } + else for(MD_Node *p = node; !md_node_is_nil(p) && p != subtree_root; p = p->parent, rec.pop_count += 1) + { + if(!md_node_is_nil(MemberFromOffset(MD_Node *, p, sib_off))) + { + rec.next = MemberFromOffset(MD_Node *, p, sib_off); + break; + } + } + return rec; +} + +//- rjf: tree building + +internal MD_Node * +md_push_node(Arena *arena, MD_NodeKind kind, MD_NodeFlags flags, String8 string, String8 raw_string, U64 src_offset) +{ + MD_Node *node = push_array(arena, MD_Node, 1); + node->first = node->last = node->parent = node->next = node->prev = node->first_tag = node->last_tag = &md_nil_node; + node->kind = kind; + node->flags = flags; + node->string = string; + node->raw_string = raw_string; + node->src_offset = src_offset; + return node; +} + +internal void +md_node_push_child(MD_Node *parent, MD_Node *node) +{ + node->parent = parent; + DLLPushBack_NPZ(&md_nil_node, parent->first, parent->last, node, next, prev); +} + +internal void +md_node_push_tag(MD_Node *parent, MD_Node *node) +{ + node->parent = parent; + DLLPushBack_NPZ(&md_nil_node, parent->first_tag, parent->last_tag, node, next, prev); +} + +//- rjf: tree introspection + +internal MD_Node * +md_node_from_chain_string(MD_Node *first, MD_Node *opl, String8 string, StringMatchFlags flags) +{ + MD_Node *result = &md_nil_node; + for(MD_Node *n = first; !md_node_is_nil(n) && n != opl; n = n->next) + { + if(str8_match(n->string, string, flags)) + { + result = n; + break; + } + } + return result; +} + +internal MD_Node * +md_node_from_chain_index(MD_Node *first, MD_Node *opl, U64 index) +{ + MD_Node *result = &md_nil_node; + S64 idx = 0; + for(MD_Node *n = first; !md_node_is_nil(n) && n != opl; n = n->next, idx += 1) + { + if(index == idx) + { + result = n; + break; + } + } + return result; +} + +internal MD_Node * +md_node_from_chain_flags(MD_Node *first, MD_Node *opl, MD_NodeFlags flags) +{ + MD_Node *result = &md_nil_node; + for(MD_Node *n = first; !md_node_is_nil(n) && n != opl; n = n->next) + { + if(n->flags & flags) + { + result = n; + break; + } + } + return result; +} + +internal U64 +md_index_from_node(MD_Node *node) +{ + U64 index = 0; + for(MD_Node *n = node->prev; !md_node_is_nil(n); n = n->prev) + { + index += 1; + } + return index; +} + +internal MD_Node * +md_root_from_node(MD_Node *node) +{ + MD_Node *result = node; + for(MD_Node *p = node->parent; (p->kind == MD_NodeKind_Main || p->kind == MD_NodeKind_Tag) && !md_node_is_nil(p); p = p->parent) + { + result = p; + } + return result; +} + +internal MD_Node * +md_child_from_string(MD_Node *node, String8 child_string, StringMatchFlags flags) +{ + return md_node_from_chain_string(node->first, &md_nil_node, child_string, flags); +} + +internal MD_Node * +md_tag_from_string(MD_Node *node, String8 tag_string, StringMatchFlags flags) +{ + return md_node_from_chain_string(node->first_tag, &md_nil_node, tag_string, flags); +} + +internal MD_Node * +md_child_from_index(MD_Node *node, U64 index) +{ + return md_node_from_chain_index(node->first, &md_nil_node, index); +} + +internal MD_Node * +md_tag_from_index(MD_Node *node, U64 index) +{ + return md_node_from_chain_index(node->first_tag, &md_nil_node, index); +} + +internal MD_Node * +md_tag_arg_from_index(MD_Node *node, String8 tag_string, StringMatchFlags flags, U64 index) +{ + MD_Node *tag = md_tag_from_string(node, tag_string, flags); + return md_child_from_index(tag, index); +} + +internal MD_Node * +md_tag_arg_from_string(MD_Node *node, String8 tag_string, StringMatchFlags tag_str_flags, String8 arg_string, StringMatchFlags arg_str_flags) +{ + MD_Node *tag = md_tag_from_string(node, tag_string, tag_str_flags); + MD_Node *arg = md_child_from_string(tag, arg_string, arg_str_flags); + return arg; +} + +internal B32 +md_node_has_child(MD_Node *node, String8 string, StringMatchFlags flags) +{ + return !md_node_is_nil(md_child_from_string(node, string, flags)); +} + +internal B32 +md_node_has_tag(MD_Node *node, String8 string, StringMatchFlags flags) +{ + return !md_node_is_nil(md_tag_from_string(node, string, flags)); +} + +internal U64 +md_child_count_from_node(MD_Node *node) +{ + U64 result = 0; + for(MD_Node *child = node->first; !md_node_is_nil(child); child = child->next) + { + result += 1; + } + return result; +} + +internal U64 +md_tag_count_from_node(MD_Node *node) +{ + U64 result = 0; + for(MD_Node *child = node->first_tag; !md_node_is_nil(child); child = child->next) + { + result += 1; + } + return result; +} + +//- rjf: tree comparison + +internal B32 +md_node_match(MD_Node *a, MD_Node *b, StringMatchFlags flags) +{ + B32 result = 0; + if(a->kind == b->kind && str8_match(a->string, b->string, flags)) + { + result = 1; + if(result) + { + result = result && a->flags == b->flags; + } + if(result && a->kind != MD_NodeKind_Tag) + { + for(MD_Node *a_tag = a->first_tag, *b_tag = b->first_tag; + !md_node_is_nil(a_tag) || !md_node_is_nil(b_tag); + a_tag = a_tag->next, b_tag = b_tag->next) + { + if(md_node_match(a_tag, b_tag, flags)) + { + for(MD_Node *a_tag_arg = a_tag->first, *b_tag_arg = b_tag->first; + !md_node_is_nil(a_tag_arg) || !md_node_is_nil(b_tag_arg); + a_tag_arg = a_tag_arg->next, b_tag_arg = b_tag_arg->next) + { + if(!md_node_deep_match(a_tag_arg, b_tag_arg, flags)) + { + result = 0; + goto end; + } + } + } + else + { + result = 0; + goto end; + } + } + } + } + end:; + return result; +} + +internal B32 +md_node_deep_match(MD_Node *a, MD_Node *b, StringMatchFlags flags) +{ + B32 result = md_node_match(a, b, flags); + if(result) + { + for(MD_Node *a_child = a->first, *b_child = b->first; + !md_node_is_nil(a_child) || !md_node_is_nil(b_child); + a_child = a_child->next, b_child = b_child->next) + { + if(!md_node_deep_match(a_child, b_child, flags)) + { + result = 0; + goto end; + } + } + } + end:; + return result; +} + +//////////////////////////////// +//~ rjf: Text -> Tokens Functions + +internal MD_TokenizeResult +md_tokenize_from_text(Arena *arena, String8 text) +{ + Temp scratch = scratch_begin(&arena, 1); + MD_TokenChunkList tokens = {0}; + MD_MsgList msgs = {0}; + U8 *byte_first = text.str; + U8 *byte_opl = byte_first + text.size; + U8 *byte = byte_first; + + //- rjf: scan string & produce tokens + for(;byte < byte_opl;) + { + MD_TokenFlags token_flags = 0; + U8 *token_start = 0; + U8 *token_opl = 0; + + //- rjf: whitespace + if(token_flags == 0 && (*byte == ' ' || *byte == '\t' || *byte == '\v' || *byte == '\r')) + { + token_flags = MD_TokenFlag_Whitespace; + token_start = byte; + token_opl = byte; + byte += 1; + for(;byte <= byte_opl; byte += 1) + { + token_opl += 1; + if(byte == byte_opl || (*byte != ' ' && *byte != '\t' && *byte != '\v' && *byte != '\r')) + { + break; + } + } + } + + //- rjf: newlines + if(token_flags == 0 && *byte == '\n') + { + token_flags = MD_TokenFlag_Newline; + token_start = byte; + token_opl = byte+1; + byte += 1; + } + + //- rjf: single-line comments + if(token_flags == 0 && (byte+1 < byte_opl && *byte == '/' && byte[1] == '/')) + { + token_flags = MD_TokenFlag_Comment; + token_start = byte; + token_opl = byte+2; + byte += 2; + B32 escaped = 0; + for(;byte <= byte_opl; byte += 1) + { + token_opl += 1; + if(byte == byte_opl) + { + break; + } + if(escaped) + { + escaped = 0; + } + else + { + if(*byte == '\n') + { + break; + } + else if(*byte == '\\') + { + escaped = 1; + } + } + } + } + + //- rjf: multi-line comments + if(token_flags == 0 && (byte+1 < byte_opl && *byte == '/' && byte[1] == '*')) + { + token_flags = MD_TokenFlag_Comment; + token_start = byte; + token_opl = byte+2; + byte += 2; + for(;byte <= byte_opl; byte += 1) + { + token_opl += 1; + if(byte == byte_opl) + { + token_flags |= MD_TokenFlag_BrokenComment; + break; + } + if(byte+1 < byte_opl && byte[0] == '*' && byte[1] == '/') + { + token_opl += 2; + break; + } + } + } + + //- rjf: identifiers + if(token_flags == 0 && (('A' <= *byte && *byte <= 'Z') || + ('a' <= *byte && *byte <= 'z') || + *byte == '_' || + utf8_class[*byte>>3] >= 2 )) + { + token_flags = MD_TokenFlag_Identifier; + token_start = byte; + token_opl = byte; + byte += 1; + for(;byte <= byte_opl; byte += 1) + { + token_opl += 1; + if(byte == byte_opl || + (!('A' <= *byte && *byte <= 'Z') && + !('a' <= *byte && *byte <= 'z') && + !('0' <= *byte && *byte <= '9') && + *byte != '_' && + utf8_class[*byte>>3] < 2)) + { + break; + } + } + } + + //- rjf: numerics + if(token_flags == 0 && (('0' <= *byte && *byte <= '9') || + (*byte == '.' && byte+1 < byte_opl && '0' <= byte[1] && byte[1] <= '9') || + (*byte == '-' && byte+1 < byte_opl && '0' <= byte[1] && byte[1] <= '9') || + *byte == '_')) + { + token_flags = MD_TokenFlag_Numeric; + token_start = byte; + token_opl = byte; + byte += 1; + for(;byte <= byte_opl; byte += 1) + { + token_opl += 1; + if(byte == byte_opl || + (!('A' <= *byte && *byte <= 'Z') && + !('a' <= *byte && *byte <= 'z') && + !('0' <= *byte && *byte <= '9') && + *byte != '_' && + *byte != '.')) + { + break; + } + } + } + + //- rjf: triplet string literals + if(token_flags == 0 && byte+2 < byte_opl && + ((byte[0] == '"' && byte[1] == '"' && byte[2] == '"') || + (byte[0] == '\''&& byte[1] == '\''&& byte[2] == '\'') || + (byte[0] == '`' && byte[1] == '`' && byte[2] == '`'))) + { + U8 literal_style = byte[0]; + token_flags = MD_TokenFlag_StringLiteral|MD_TokenFlag_StringTriplet; + token_flags |= (literal_style == '\'')*MD_TokenFlag_StringSingleQuote; + token_flags |= (literal_style == '"')*MD_TokenFlag_StringDoubleQuote; + token_flags |= (literal_style == '`')*MD_TokenFlag_StringTick; + token_start = byte; + token_opl = byte+3; + byte += 3; + for(;byte <= byte_opl; byte += 1) + { + if(byte == byte_opl) + { + token_flags |= MD_TokenFlag_BrokenStringLiteral; + token_opl = byte; + break; + } + if(byte+2 < byte_opl && (byte[0] == literal_style && byte[1] == literal_style && byte[2] == literal_style)) + { + byte += 3; + token_opl = byte; + break; + } + } + } + + //- rjf: singlet string literals + if(token_flags == 0 && (byte[0] == '"' || byte[0] == '\'' || byte[0] == '`')) + { + U8 literal_style = byte[0]; + token_flags = MD_TokenFlag_StringLiteral; + token_flags |= (literal_style == '\'')*MD_TokenFlag_StringSingleQuote; + token_flags |= (literal_style == '"')*MD_TokenFlag_StringDoubleQuote; + token_flags |= (literal_style == '`')*MD_TokenFlag_StringTick; + token_start = byte; + token_opl = byte+1; + byte += 1; + B32 escaped = 0; + for(;byte <= byte_opl; byte += 1) + { + if(byte == byte_opl || *byte == '\n') + { + token_opl = byte; + token_flags |= MD_TokenFlag_BrokenStringLiteral; + break; + } + if(!escaped && byte[0] == '\\') + { + escaped = 1; + } + else if(!escaped && byte[0] == literal_style) + { + token_opl = byte+1; + byte += 1; + break; + } + else if(escaped) + { + escaped = 0; + } + } + } + + //- rjf: non-reserved symbols + if(token_flags == 0 && (*byte == '~' || *byte == '!' || *byte == '$' || *byte == '%' || *byte == '^' || + *byte == '&' || *byte == '*' || *byte == '-' || *byte == '=' || *byte == '+' || + *byte == '<' || *byte == '.' || *byte == '>' || *byte == '/' || *byte == '?' || + *byte == '|')) + { + token_flags = MD_TokenFlag_Symbol; + token_start = byte; + token_opl = byte; + byte += 1; + for(;byte <= byte_opl; byte += 1) + { + token_opl += 1; + if(byte == byte_opl || + (*byte != '~' && *byte != '!' && *byte != '$' && *byte != '%' && *byte != '^' && + *byte != '&' && *byte != '*' && *byte != '-' && *byte != '=' && *byte != '+' && + *byte != '<' && *byte != '.' && *byte != '>' && *byte != '/' && *byte != '?' && + *byte != '|')) + { + break; + } + } + } + + //- rjf: reserved symbols + if(token_flags == 0 && (*byte == '{' || *byte == '}' || *byte == '(' || *byte == ')' || + *byte == '[' || *byte == ']' || *byte == '#' || *byte == ',' || + *byte == '\\'|| *byte == ':' || *byte == ';' || *byte == '@')) + { + token_flags = MD_TokenFlag_Reserved; + token_start = byte; + token_opl = byte+1; + byte += 1; + } + + //- rjf: bad characters in all other cases + if(token_flags == 0) + { + token_flags = MD_TokenFlag_BadCharacter; + token_start = byte; + token_opl = byte+1; + byte += 1; + } + + //- rjf; push token if formed + if(token_flags != 0 && token_start != 0 && token_opl > token_start) + { + MD_Token token = {{(U64)(token_start - byte_first), (U64)(token_opl - byte_first)}, token_flags}; + md_token_chunk_list_push(scratch.arena, &tokens, 4096, token); + } + + //- rjf: push errors on unterminated comments + if(token_flags & MD_TokenFlag_BrokenComment) + { + MD_Node *error = md_push_node(arena, MD_NodeKind_ErrorMarker, 0, str8_lit(""), str8_lit(""), token_start - byte_first); + String8 error_string = str8_lit("Unterminated comment."); + md_msg_list_push(arena, &msgs, error, MD_MsgKind_Error, error_string); + } + + //- rjf: push errors on unterminated strings + if(token_flags & MD_TokenFlag_BrokenStringLiteral) + { + MD_Node *error = md_push_node(arena, MD_NodeKind_ErrorMarker, 0, str8_lit(""), str8_lit(""), token_start - byte_first); + String8 error_string = str8_lit("Unterminated string literal."); + md_msg_list_push(arena, &msgs, error, MD_MsgKind_Error, error_string); + } + } + + //- rjf: bake, fill & return + MD_TokenizeResult result = {0}; + { + result.tokens = md_token_array_from_chunk_list(arena, &tokens); + result.msgs = msgs; + } + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Tokens -> Tree Functions + +internal MD_ParseResult +md_parse_from_text_tokens(Arena *arena, String8 filename, String8 text, MD_TokenArray tokens) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: set up outputs + MD_MsgList msgs = {0}; + MD_Node *root = md_push_node(arena, MD_NodeKind_File, 0, filename, text, 0); + + //- rjf: set up parse rule stack + typedef enum MD_ParseWorkKind + { + MD_ParseWorkKind_Main, + MD_ParseWorkKind_MainImplicit, + MD_ParseWorkKind_NodeOptionalFollowUp, + MD_ParseWorkKind_NodeChildrenStyleScan, + } + MD_ParseWorkKind; + typedef struct MD_ParseWorkNode MD_ParseWorkNode; + struct MD_ParseWorkNode + { + MD_ParseWorkNode *next; + MD_ParseWorkKind kind; + MD_Node *parent; + MD_Node *first_gathered_tag; + MD_Node *last_gathered_tag; + MD_NodeFlags gathered_node_flags; + S32 counted_newlines; + }; + MD_ParseWorkNode first_work = + { + 0, + MD_ParseWorkKind_Main, + root, + }; + MD_ParseWorkNode broken_work = { 0, MD_ParseWorkKind_Main, root,}; + MD_ParseWorkNode *work_top = &first_work; + MD_ParseWorkNode *work_free = 0; +#define MD_ParseWorkPush(work_kind, work_parent) do\ +{\ +MD_ParseWorkNode *work_node = work_free;\ +if(work_node == 0) {work_node = push_array(scratch.arena, MD_ParseWorkNode, 1);}\ +else { SLLStackPop(work_free); }\ +work_node->kind = (work_kind);\ +work_node->parent = (work_parent);\ +SLLStackPush(work_top, work_node);\ +}while(0) +#define MD_ParseWorkPop() do\ +{\ +SLLStackPop(work_top);\ +if(work_top == 0) {work_top = &broken_work;}\ +}while(0) + + //- rjf: parse + MD_Token *tokens_first = tokens.v; + MD_Token *tokens_opl = tokens_first + tokens.count; + MD_Token *token = tokens_first; + for(;token < tokens_opl;) + { + //- rjf: unpack token + String8 token_string = str8_substr(text, token[0].range); + + //- rjf: whitespace -> always no-op & inc + if(token->flags & MD_TokenFlag_Whitespace) + { + token += 1; + goto end_consume; + } + + //- rjf: comments -> always no-op & inc + if(token->flags & MD_TokenGroup_Comment) + { + token += 1; + goto end_consume; + } + + //- rjf: [node follow up] : following label -> work top parent has children. we need + // to scan for explicit delimiters, else parse an implicitly delimited set of children + if(work_top->kind == MD_ParseWorkKind_NodeOptionalFollowUp && str8_match(token_string, str8_lit(":"), 0)) + { + MD_Node *parent = work_top->parent; + MD_ParseWorkPop(); + MD_ParseWorkPush(MD_ParseWorkKind_NodeChildrenStyleScan, parent); + token += 1; + goto end_consume; + } + + //- rjf: [node follow up] anything but : following label -> node has no children. just + // pop & move on + if(work_top->kind == MD_ParseWorkKind_NodeOptionalFollowUp) + { + MD_ParseWorkPop(); + goto end_consume; + } + + //- rjf: [main] separators -> mark & inc + if(work_top->kind == MD_ParseWorkKind_Main && token->flags & MD_TokenFlag_Reserved && + (str8_match(token_string, str8_lit(","), 0) || + str8_match(token_string, str8_lit(";"), 0))) + { + MD_Node *parent = work_top->parent; + if(!md_node_is_nil(parent->last)) + { + parent->last->flags |= MD_NodeFlag_IsBeforeComma*!!str8_match(token_string, str8_lit(","), 0); + parent->last->flags |= MD_NodeFlag_IsBeforeSemicolon*!!str8_match(token_string, str8_lit(";"), 0); + work_top->gathered_node_flags |= MD_NodeFlag_IsAfterComma*!!str8_match(token_string, str8_lit(","), 0); + work_top->gathered_node_flags |= MD_NodeFlag_IsAfterSemicolon*!!str8_match(token_string, str8_lit(";"), 0); + } + token += 1; + goto end_consume; + } + + //- rjf: [main_implicit] separators -> pop + if(work_top->kind == MD_ParseWorkKind_MainImplicit && token->flags & MD_TokenFlag_Reserved && + (str8_match(token_string, str8_lit(","), 0) || + str8_match(token_string, str8_lit(";"), 0))) + { + MD_ParseWorkPop(); + goto end_consume; + } + + //- rjf: [main, main_implicit] unexpected reserved tokens + if((work_top->kind == MD_ParseWorkKind_Main || work_top->kind == MD_ParseWorkKind_MainImplicit) && + token->flags & MD_TokenFlag_Reserved && + (str8_match(token_string, str8_lit("#"), 0) || + str8_match(token_string, str8_lit("\\"), 0) || + str8_match(token_string, str8_lit(":"), 0))) + { + MD_Node *error = md_push_node(arena, MD_NodeKind_ErrorMarker, 0, token_string, token_string, token->range.min); + String8 error_string = push_str8f(arena, "Unexpected reserved symbol \"%S\".", token_string); + md_msg_list_push(arena, &msgs, error, MD_MsgKind_Error, error_string); + token += 1; + goto end_consume; + } + + //- rjf: [main, main_implicit] tag signifier -> create new tag + if((work_top->kind == MD_ParseWorkKind_Main || work_top->kind == MD_ParseWorkKind_MainImplicit) && + token[0].flags & MD_TokenFlag_Reserved && str8_match(token_string, str8_lit("@"), 0)) + { + if(token+1 >= tokens_opl || + !(token[1].flags & MD_TokenGroup_Label)) + { + MD_Node *error = md_push_node(arena, MD_NodeKind_ErrorMarker, 0, token_string, token_string, token->range.min); + String8 error_string = str8_lit("Tag label expected after @ symbol."); + md_msg_list_push(arena, &msgs, error, MD_MsgKind_Error, error_string); + token += 1; + goto end_consume; + } + else + { + String8 tag_name_raw = str8_substr(text, token[1].range); + String8 tag_name = md_content_string_from_token_flags_str8(token[1].flags, tag_name_raw); + MD_Node *node = md_push_node(arena, MD_NodeKind_Tag, md_node_flags_from_token_flags(token[1].flags), tag_name, tag_name_raw, token[0].range.min); + DLLPushBack_NPZ(&md_nil_node, work_top->first_gathered_tag, work_top->last_gathered_tag, node, next, prev); + if(token+2 < tokens_opl && token[2].flags & MD_TokenFlag_Reserved && str8_match(str8_substr(text, token[2].range), str8_lit("("), 0)) + { + token += 3; + MD_ParseWorkPush(MD_ParseWorkKind_Main, node); + } + else + { + token += 2; + } + goto end_consume; + } + } + + //- rjf: [main, main_implicit] label -> create new main + if((work_top->kind == MD_ParseWorkKind_Main || work_top->kind == MD_ParseWorkKind_MainImplicit) && + token->flags & MD_TokenGroup_Label) + { + String8 node_string_raw = token_string; + String8 node_string = md_content_string_from_token_flags_str8(token->flags, node_string_raw); + MD_NodeFlags flags = md_node_flags_from_token_flags(token->flags)|work_top->gathered_node_flags; + work_top->gathered_node_flags = 0; + MD_Node *node = md_push_node(arena, MD_NodeKind_Main, flags, node_string, node_string_raw, token[0].range.min); + node->first_tag = work_top->first_gathered_tag; + node->last_tag = work_top->last_gathered_tag; + for(MD_Node *tag = work_top->first_gathered_tag; !md_node_is_nil(tag); tag = tag->next) + { + tag->parent = node; + } + work_top->first_gathered_tag = work_top->last_gathered_tag = &md_nil_node; + md_node_push_child(work_top->parent, node); + MD_ParseWorkPush(MD_ParseWorkKind_NodeOptionalFollowUp, node); + token += 1; + goto end_consume; + } + + //- rjf: [main] {s, [s, and (s -> create new main + if(work_top->kind == MD_ParseWorkKind_Main && token->flags & MD_TokenFlag_Reserved && + (str8_match(token_string, str8_lit("{"), 0) || + str8_match(token_string, str8_lit("["), 0) || + str8_match(token_string, str8_lit("("), 0))) + { + MD_NodeFlags flags = md_node_flags_from_token_flags(token->flags)|work_top->gathered_node_flags; + flags |= MD_NodeFlag_HasBraceLeft*!!str8_match(token_string, str8_lit("{"), 0); + flags |= MD_NodeFlag_HasBracketLeft*!!str8_match(token_string, str8_lit("["), 0); + flags |= MD_NodeFlag_HasParenLeft*!!str8_match(token_string, str8_lit("("), 0); + work_top->gathered_node_flags = 0; + MD_Node *node = md_push_node(arena, MD_NodeKind_Main, flags, str8_lit(""), str8_lit(""), token[0].range.min); + node->first_tag = work_top->first_gathered_tag; + node->last_tag = work_top->last_gathered_tag; + for(MD_Node *tag = work_top->first_gathered_tag; !md_node_is_nil(tag); tag = tag->next) + { + tag->parent = node; + } + work_top->first_gathered_tag = work_top->last_gathered_tag = &md_nil_node; + md_node_push_child(work_top->parent, node); + MD_ParseWorkPush(MD_ParseWorkKind_Main, node); + token += 1; + goto end_consume; + } + + //- rjf: [node children style scan] {s, [s, and (s -> explicitly delimited children + if(work_top->kind == MD_ParseWorkKind_NodeChildrenStyleScan && token->flags & MD_TokenFlag_Reserved && + (str8_match(token_string, str8_lit("{"), 0) || + str8_match(token_string, str8_lit("["), 0) || + str8_match(token_string, str8_lit("("), 0))) + { + MD_Node *parent = work_top->parent; + parent->flags |= MD_NodeFlag_HasBraceLeft*!!str8_match(token_string, str8_lit("{"), 0); + parent->flags |= MD_NodeFlag_HasBracketLeft*!!str8_match(token_string, str8_lit("["), 0); + parent->flags |= MD_NodeFlag_HasParenLeft*!!str8_match(token_string, str8_lit("("), 0); + MD_ParseWorkPop(); + MD_ParseWorkPush(MD_ParseWorkKind_Main, parent); + token += 1; + goto end_consume; + } + + //- rjf: [node children style scan] count newlines + if(work_top->kind == MD_ParseWorkKind_NodeChildrenStyleScan && token->flags & MD_TokenFlag_Newline) + { + work_top->counted_newlines += 1; + token += 1; + goto end_consume; + } + + //- rjf: [main_implicit] newline -> pop + if(work_top->kind == MD_ParseWorkKind_MainImplicit && token->flags & MD_TokenFlag_Newline) + { + MD_ParseWorkPop(); + token += 1; + goto end_consume; + } + + //- rjf: [all but main_implicit] newline -> no-op & inc + if(work_top->kind != MD_ParseWorkKind_MainImplicit && token->flags & MD_TokenFlag_Newline) + { + token += 1; + goto end_consume; + } + + //- rjf: [node children style scan] anything causing implicit set -> <2 newlines, all good, + // >=2 newlines, houston we have a problem + if(work_top->kind == MD_ParseWorkKind_NodeChildrenStyleScan) + { + if(work_top->counted_newlines >= 2) + { + MD_Node *node = work_top->parent; + MD_Node *error = md_push_node(arena, MD_NodeKind_ErrorMarker, 0, token_string, token_string, token->range.min); + String8 error_string = push_str8f(arena, "More than two newlines following \"%S\", which has implicitly-delimited children, resulting in an empty list of children.", node->string); + md_msg_list_push(arena, &msgs, error, MD_MsgKind_Warning, error_string); + MD_ParseWorkPop(); + } + else + { + MD_Node *parent = work_top->parent; + MD_ParseWorkPop(); + MD_ParseWorkPush(MD_ParseWorkKind_MainImplicit, parent); + } + goto end_consume; + } + + //- rjf: [main] }s, ]s, and )s -> pop + if(work_top->kind == MD_ParseWorkKind_Main && token->flags & MD_TokenFlag_Reserved && + (str8_match(token_string, str8_lit("}"), 0) || + str8_match(token_string, str8_lit("]"), 0) || + str8_match(token_string, str8_lit(")"), 0))) + { + MD_Node *parent = work_top->parent; + parent->flags |= MD_NodeFlag_HasBraceRight*!!str8_match(token_string, str8_lit("}"), 0); + parent->flags |= MD_NodeFlag_HasBracketRight*!!str8_match(token_string, str8_lit("]"), 0); + parent->flags |= MD_NodeFlag_HasParenRight*!!str8_match(token_string, str8_lit(")"), 0); + MD_ParseWorkPop(); + token += 1; + goto end_consume; + } + + //- rjf: [main implicit] }s, ]s, and )s -> pop without advancing + if(work_top->kind == MD_ParseWorkKind_MainImplicit && token->flags & MD_TokenFlag_Reserved && + (str8_match(token_string, str8_lit("}"), 0) || + str8_match(token_string, str8_lit("]"), 0) || + str8_match(token_string, str8_lit(")"), 0))) + { + MD_ParseWorkPop(); + goto end_consume; + } + + //- rjf: no consumption -> unexpected token! we don't know what to do with this. + { + MD_Node *error = md_push_node(arena, MD_NodeKind_ErrorMarker, 0, token_string, token_string, token->range.min); + String8 error_string = push_str8f(arena, "Unexpected \"%S\" token.", token_string); + md_msg_list_push(arena, &msgs, error, MD_MsgKind_Error, error_string); + token += 1; + } + + end_consume:; + } + + //- rjf: fill & return + MD_ParseResult result = {0}; + result.root = root; + result.msgs = msgs; + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Tree -> Text Functions + +internal String8List +md_debug_string_list_from_tree(Arena *arena, MD_Node *root) +{ + String8List strings = {0}; + { + char *indentation = " "; + S32 depth = 0; + for(MD_Node *node = root, *next = &md_nil_node; !md_node_is_nil(node); node = next) + { + // rjf: get next recursion + MD_NodeRec rec = md_node_rec_depth_first_pre(node, root); + next = rec.next; + + // rjf: extract node info + String8 kind_string = str8_lit("Unknown"); + switch(node->kind) + { + default:{}break; + case MD_NodeKind_File: {kind_string = str8_lit("File"); }break; + case MD_NodeKind_ErrorMarker:{kind_string = str8_lit("ErrorMarker");}break; + case MD_NodeKind_Main: {kind_string = str8_lit("Main"); }break; + case MD_NodeKind_Tag: {kind_string = str8_lit("Tag"); }break; + case MD_NodeKind_List: {kind_string = str8_lit("List"); }break; + case MD_NodeKind_Reference: {kind_string = str8_lit("Reference"); }break; + } + + // rjf: push node line + str8_list_pushf(arena, &strings, "%.*s\"%S\" : %S", depth, indentation, node->string, kind_string); + + // rjf: children -> open brace + if(rec.push_count != 0) + { + str8_list_pushf(arena, &strings, "%.*s{", depth, indentation); + } + + // rjf: descend + depth += rec.push_count; + + // rjf: popping -> close braces + for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + str8_list_pushf(arena, &strings, "%.*s}", depth-1-pop_idx, indentation); + } + + // rjf: ascend + depth -= rec.pop_count; + } + } + return strings; +} diff --git a/src/mdesk/mdesk.h b/src/mdesk/mdesk.h new file mode 100644 index 00000000..3daad8e4 --- /dev/null +++ b/src/mdesk/mdesk.h @@ -0,0 +1,302 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef MDESK_H +#define MDESK_H + +//////////////////////////////// +//~ rjf: Messages + +typedef enum MD_MsgKind +{ + MD_MsgKind_Null, + MD_MsgKind_Note, + MD_MsgKind_Warning, + MD_MsgKind_Error, + MD_MsgKind_FatalError, +} +MD_MsgKind; + +typedef struct MD_Msg MD_Msg; +struct MD_Msg +{ + MD_Msg *next; + struct MD_Node *node; + MD_MsgKind kind; + String8 string; +}; + +typedef struct MD_MsgList MD_MsgList; +struct MD_MsgList +{ + MD_Msg *first; + MD_Msg *last; + U64 count; + MD_MsgKind worst_message_kind; +}; + +//////////////////////////////// +//~ rjf: Token Types + +typedef U32 MD_TokenFlags; +enum +{ + // rjf: base kind info + MD_TokenFlag_Identifier = (1<<0), + MD_TokenFlag_Numeric = (1<<1), + MD_TokenFlag_StringLiteral = (1<<2), + MD_TokenFlag_Symbol = (1<<3), + MD_TokenFlag_Reserved = (1<<4), + MD_TokenFlag_Comment = (1<<5), + MD_TokenFlag_Whitespace = (1<<6), + MD_TokenFlag_Newline = (1<<7), + + // rjf: decoration info + MD_TokenFlag_StringSingleQuote = (1<<8), + MD_TokenFlag_StringDoubleQuote = (1<<9), + MD_TokenFlag_StringTick = (1<<10), + MD_TokenFlag_StringTriplet = (1<<11), + + // rjf: error info + MD_TokenFlag_BrokenComment = (1<<12), + MD_TokenFlag_BrokenStringLiteral = (1<<13), + MD_TokenFlag_BadCharacter = (1<<14), +}; + +typedef U32 MD_TokenGroups; +enum +{ + MD_TokenGroup_Comment = MD_TokenFlag_Comment, + MD_TokenGroup_Whitespace = (MD_TokenFlag_Whitespace| + MD_TokenFlag_Newline), + MD_TokenGroup_Irregular = (MD_TokenGroup_Comment| + MD_TokenGroup_Whitespace), + MD_TokenGroup_Regular = ~MD_TokenGroup_Irregular, + MD_TokenGroup_Label = (MD_TokenFlag_Identifier| + MD_TokenFlag_Numeric| + MD_TokenFlag_StringLiteral| + MD_TokenFlag_Symbol), + MD_TokenGroup_Error = (MD_TokenFlag_BrokenComment| + MD_TokenFlag_BrokenStringLiteral| + MD_TokenFlag_BadCharacter), +}; + +typedef struct MD_Token MD_Token; +struct MD_Token +{ + Rng1U64 range; + MD_TokenFlags flags; +}; + +typedef struct MD_TokenChunkNode MD_TokenChunkNode; +struct MD_TokenChunkNode +{ + MD_TokenChunkNode *next; + MD_Token *v; + U64 count; + U64 cap; +}; + +typedef struct MD_TokenChunkList MD_TokenChunkList; +struct MD_TokenChunkList +{ + MD_TokenChunkNode *first; + MD_TokenChunkNode *last; + U64 chunk_count; + U64 total_token_count; +}; + +typedef struct MD_TokenArray MD_TokenArray; +struct MD_TokenArray +{ + MD_Token *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Node Types + +typedef enum MD_NodeKind +{ + MD_NodeKind_Nil, + MD_NodeKind_File, + MD_NodeKind_ErrorMarker, + MD_NodeKind_Main, + MD_NodeKind_Tag, + MD_NodeKind_List, + MD_NodeKind_Reference, + MD_NodeKind_COUNT +} +MD_NodeKind; + +typedef U64 MD_NodeFlags; +enum +{ + MD_NodeFlag_MaskSetDelimiters = (0x3F<<0), + MD_NodeFlag_HasParenLeft = (1<<0), + MD_NodeFlag_HasParenRight = (1<<1), + MD_NodeFlag_HasBracketLeft = (1<<2), + MD_NodeFlag_HasBracketRight = (1<<3), + MD_NodeFlag_HasBraceLeft = (1<<4), + MD_NodeFlag_HasBraceRight = (1<<5), + + MD_NodeFlag_MaskSeparators = (0xF<<6), + MD_NodeFlag_IsBeforeSemicolon = (1<<6), + MD_NodeFlag_IsAfterSemicolon = (1<<7), + MD_NodeFlag_IsBeforeComma = (1<<8), + MD_NodeFlag_IsAfterComma = (1<<9), + + MD_NodeFlag_MaskStringDelimiters = (0xF<<10), + MD_NodeFlag_StringSingleQuote = (1<<10), + MD_NodeFlag_StringDoubleQuote = (1<<11), + MD_NodeFlag_StringTick = (1<<12), + MD_NodeFlag_StringTriplet = (1<<13), + + MD_NodeFlag_MaskLabelKind = (0xF<<14), + MD_NodeFlag_Numeric = (1<<14), + MD_NodeFlag_Identifier = (1<<15), + MD_NodeFlag_StringLiteral = (1<<16), + MD_NodeFlag_Symbol = (1<<17), +}; +#define MD_NodeFlag_AfterFromBefore(f) ((f) << 1) + +typedef struct MD_Node MD_Node; +struct MD_Node +{ + // rjf: tree links + MD_Node *next; + MD_Node *prev; + MD_Node *parent; + MD_Node *first; + MD_Node *last; + + // rjf: tag links + MD_Node *first_tag; + MD_Node *last_tag; + + // rjf: node info + MD_NodeKind kind; + MD_NodeFlags flags; + String8 string; + String8 raw_string; + + // rjf: source code info + U64 src_offset; +}; + +typedef struct MD_NodeRec MD_NodeRec; +struct MD_NodeRec +{ + MD_Node *next; + S32 push_count; + S32 pop_count; +}; + +//////////////////////////////// +//~ rjf: Text -> Tokens Types + +typedef struct MD_TokenizeResult MD_TokenizeResult; +struct MD_TokenizeResult +{ + MD_TokenArray tokens; + MD_MsgList msgs; +}; + +//////////////////////////////// +//~ rjf: Tokens -> Tree Types + +typedef struct MD_ParseResult MD_ParseResult; +struct MD_ParseResult +{ + MD_Node *root; + MD_MsgList msgs; +}; + +//////////////////////////////// +//~ rjf: Globals + +global read_only MD_Node md_nil_node = +{ + &md_nil_node, + &md_nil_node, + &md_nil_node, + &md_nil_node, + &md_nil_node, + &md_nil_node, + &md_nil_node, +}; + +//////////////////////////////// +//~ rjf: Message Type Functions + +internal void md_msg_list_push(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, String8 string); +internal void md_msg_list_pushf(Arena *arena, MD_MsgList *msgs, MD_Node *node, MD_MsgKind kind, char *fmt, ...); +internal void md_msg_list_concat_in_place(MD_MsgList *dst, MD_MsgList *to_push); + +//////////////////////////////// +//~ rjf: Token Type Functions + +internal MD_Token md_token_make(Rng1U64 range, MD_TokenFlags flags); +internal B32 md_token_match(MD_Token a, MD_Token b); +internal String8List md_string_list_from_token_flags(Arena *arena, MD_TokenFlags flags); +internal void md_token_chunk_list_push(Arena *arena, MD_TokenChunkList *list, U64 cap, MD_Token token); +internal MD_TokenArray md_token_array_from_chunk_list(Arena *arena, MD_TokenChunkList *chunks); +internal String8 md_content_string_from_token_flags_str8(MD_TokenFlags flags, String8 string); + +//////////////////////////////// +//~ rjf: Node Type Functions + +//- rjf: flag conversions +internal MD_NodeFlags md_node_flags_from_token_flags(MD_TokenFlags flags); + +//- rjf: nil +internal B32 md_node_is_nil(MD_Node *node); + +//- rjf: iteration +#define MD_EachNode(it, first) MD_Node *it = first; !md_node_is_nil(it); it = it->next +internal MD_NodeRec md_node_rec_depth_first(MD_Node *node, MD_Node *subtree_root, U64 child_off, U64 sib_off); +#define md_node_rec_depth_first_pre(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, first), OffsetOf(MD_Node, next)) +#define md_node_rec_depth_first_pre_rev(node, subtree_root) md_node_rec_depth_first((node), (subtree_root), OffsetOf(MD_Node, last), OffsetOf(MD_Node, prev)) + +//- rjf: tree building +internal MD_Node *md_push_node(Arena *arena, MD_NodeKind kind, MD_NodeFlags flags, String8 string, String8 raw_string, U64 src_offset); +internal void md_node_push_child(MD_Node *parent, MD_Node *node); +internal void md_node_push_tag(MD_Node *parent, MD_Node *node); + +//- rjf: tree introspection +internal MD_Node * md_node_from_chain_string(MD_Node *first, MD_Node *opl, String8 string, StringMatchFlags flags); +internal MD_Node * md_node_from_chain_index(MD_Node *first, MD_Node *opl, U64 index); +internal MD_Node * md_node_from_chain_flags(MD_Node *first, MD_Node *opl, MD_NodeFlags flags); +internal U64 md_index_from_node(MD_Node *node); +internal MD_Node * md_root_from_node(MD_Node *node); +internal MD_Node * md_child_from_string(MD_Node *node, String8 child_string, StringMatchFlags flags); +internal MD_Node * md_tag_from_string(MD_Node *node, String8 tag_string, StringMatchFlags flags); +internal MD_Node * md_child_from_index(MD_Node *node, U64 index); +internal MD_Node * md_tag_from_index(MD_Node *node, U64 index); +internal MD_Node * md_tag_arg_from_index(MD_Node *node, String8 tag_string, StringMatchFlags flags, U64 index); +internal MD_Node * md_tag_arg_from_string(MD_Node *node, String8 tag_string, StringMatchFlags tag_str_flags, String8 arg_string, StringMatchFlags arg_str_flags); +internal B32 md_node_has_child(MD_Node *node, String8 string, StringMatchFlags flags); +internal B32 md_node_has_tag(MD_Node *node, String8 string, StringMatchFlags flags); +internal U64 md_child_count_from_node(MD_Node *node); +internal U64 md_tag_count_from_node(MD_Node *node); + +//- rjf: tree comparison +internal B32 md_node_deep_match(MD_Node *a, MD_Node *b, StringMatchFlags flags); +internal B32 md_node_match(MD_Node *a, MD_Node *b, StringMatchFlags flags); + +//////////////////////////////// +//~ rjf: Text -> Tokens Functions + +internal MD_TokenizeResult md_tokenize_from_text(Arena *arena, String8 text); + +//////////////////////////////// +//~ rjf: Tokens -> Tree Functions + +internal MD_ParseResult md_parse_from_text_tokens(Arena *arena, String8 filename, String8 text, MD_TokenArray tokens); + +//////////////////////////////// +//~ rjf: Tree -> Text Functions + +internal String8List md_debug_string_list_from_tree(Arena *arena, MD_Node *root); + +#endif // MDESK_H diff --git a/src/metagen/metagen.c b/src/metagen/metagen.c new file mode 100644 index 00000000..73fe8a35 --- /dev/null +++ b/src/metagen/metagen.c @@ -0,0 +1,1119 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: String Expression Operator Tables + +read_only global String8 mg_str_expr_op_symbol_string_table[MG_StrExprOp_COUNT] = +{ + str8_lit_comp(""), + str8_lit_comp("."), // MG_StrExprOp_Dot + str8_lit_comp("->"), // MG_StrExprOp_ExpandIfTrue + str8_lit_comp(".."), // MG_StrExprOp_Concat + str8_lit_comp("=>"), // MG_StrExprOp_BumpToColumn + str8_lit_comp("+"), // MG_StrExprOp_Add + str8_lit_comp("-"), // MG_StrExprOp_Subtract + str8_lit_comp("*"), // MG_StrExprOp_Multiply + str8_lit_comp("/"), // MG_StrExprOp_Divide + str8_lit_comp("%"), // MG_StrExprOp_Modulo + str8_lit_comp("<<"), // MG_StrExprOp_LeftShift + str8_lit_comp(">>"), // MG_StrExprOp_RightShift + str8_lit_comp("&"), // MG_StrExprOp_BitwiseAnd + str8_lit_comp("|"), // MG_StrExprOp_BitwiseOr + str8_lit_comp("^"), // MG_StrExprOp_BitwiseXor + str8_lit_comp("~"), // MG_StrExprOp_BitwiseNegate + str8_lit_comp("&&"), // MG_StrExprOp_BooleanAnd + str8_lit_comp("||"), // MG_StrExprOp_BooleanOr + str8_lit_comp("!"), // MG_StrExprOp_BooleanNot + str8_lit_comp("=="), // MG_StrExprOp_Equals + str8_lit_comp("!="), // MG_StrExprOp_DoesNotEqual +}; + +read_only global S8 mg_str_expr_op_precedence_table[MG_StrExprOp_COUNT] = +{ + 0, + 20, // MG_StrExprOp_Dot + 1, // MG_StrExprOp_ExpandIfTrue + 2, // MG_StrExprOp_Concat + 12, // MG_StrExprOp_BumpToColumn + 5, // MG_StrExprOp_Add + 5, // MG_StrExprOp_Subtract + 6, // MG_StrExprOp_Multiply + 6, // MG_StrExprOp_Divide + 6, // MG_StrExprOp_Modulo + 7, // MG_StrExprOp_LeftShift + 7, // MG_StrExprOp_RightShift + 8, // MG_StrExprOp_BitwiseAnd + 10, // MG_StrExprOp_BitwiseOr + 9, // MG_StrExprOp_BitwiseXor + 11, // MG_StrExprOp_BitwiseNegate + 3, // MG_StrExprOp_BooleanAnd + 3, // MG_StrExprOp_BooleanOr + 11, // MG_StrExprOp_BooleanNot + 4, // MG_StrExprOp_Equals + 4, // MG_StrExprOp_DoesNotEqual +}; + +read_only global MG_StrExprOpKind mg_str_expr_op_kind_table[MG_StrExprOp_COUNT] = +{ + MG_StrExprOpKind_Null, + MG_StrExprOpKind_Binary, // MG_StrExprOp_Dot + MG_StrExprOpKind_Binary, // MG_StrExprOp_ExpandIfTrue + MG_StrExprOpKind_Binary, // MG_StrExprOp_Concat + MG_StrExprOpKind_Prefix, // MG_StrExprOp_BumpToColumn + MG_StrExprOpKind_Binary, // MG_StrExprOp_Add + MG_StrExprOpKind_Binary, // MG_StrExprOp_Subtract + MG_StrExprOpKind_Binary, // MG_StrExprOp_Multiply + MG_StrExprOpKind_Binary, // MG_StrExprOp_Divide + MG_StrExprOpKind_Binary, // MG_StrExprOp_Modulo + MG_StrExprOpKind_Binary, // MG_StrExprOp_LeftShift + MG_StrExprOpKind_Binary, // MG_StrExprOp_RightShift + MG_StrExprOpKind_Binary, // MG_StrExprOp_BitwiseAnd + MG_StrExprOpKind_Binary, // MG_StrExprOp_BitwiseOr + MG_StrExprOpKind_Binary, // MG_StrExprOp_BitwiseXor + MG_StrExprOpKind_Prefix, // MG_StrExprOp_BitwiseNegate + MG_StrExprOpKind_Binary, // MG_StrExprOp_BooleanAnd + MG_StrExprOpKind_Binary, // MG_StrExprOp_BooleanOr + MG_StrExprOpKind_Prefix, // MG_StrExprOp_BooleanNot + MG_StrExprOpKind_Binary, // MG_StrExprOp_Equals + MG_StrExprOpKind_Binary, // MG_StrExprOp_DoesNotEqual +}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +mg_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal TxtPt +mg_txt_pt_from_string_off(String8 string, U64 off) +{ + TxtPt pt = txt_pt(1, 1); + for(U64 idx = 0; idx < string.size && idx < off; idx += 1) + { + if(string.str[idx] == '\n') + { + pt.line += 1; + pt.column = 1; + } + else + { + pt.column += 1; + } + } + return pt; +} + +//////////////////////////////// +//~ rjf: String Escaping + +internal String8 +mg_escaped_from_str8(Arena *arena, String8 string) +{ + // NOTE(rjf): This doesn't handle hex/octal/unicode escape sequences right + // now, just the simple stuff. + Temp scratch = scratch_begin(&arena, 1); + String8List strs = {0}; + U64 start = 0; + for(U64 idx = 0; idx <= string.size; idx += 1) + { + if(idx == string.size || string.str[idx] == '\\') + { + String8 str = str8_substr(string, r1u64(start, idx)); + if(str.size != 0) + { + str8_list_push(arena, &strs, str); + } + start = idx+1; + } + if(idx < string.size && string.str[idx] == '\\') + { + U8 next_char = string.str[idx+1]; + U8 replace_byte = 0; + switch(next_char) + { + default:{}break; + case 'a': replace_byte = 0x07; break; + case 'b': replace_byte = 0x08; break; + case 'e': replace_byte = 0x1b; break; + case 'f': replace_byte = 0x0c; break; + case 'n': replace_byte = 0x0a; break; + case 'r': replace_byte = 0x0d; break; + case 't': replace_byte = 0x09; break; + case 'v': replace_byte = 0x0b; break; + case '\\':replace_byte = '\\'; break; + case '\'':replace_byte = '\''; break; + case '"': replace_byte = '"'; break; + case '?': replace_byte = '?'; break; + } + String8 replace_string = push_str8_copy(scratch.arena, str8(&replace_byte, 1)); + str8_list_push(scratch.arena, &strs, replace_string); + if(replace_byte == '\\' || replace_byte == '"' || replace_byte == '\'') + { + idx += 1; + start += 1; + } + } + } + String8 result = str8_list_join(arena, &strs, 0); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: String Wrapping + +internal String8List +mg_wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent) +{ + String8List list = {0}; + Rng1U64 line_range = r1u64(0, 0); + U64 wrapped_indent_level = 0; + static char *spaces = " "; + for (U64 idx = 0; idx <= string.size; idx += 1){ + U8 chr = idx < string.size ? string.str[idx] : 0; + if (chr == '\n'){ + Rng1U64 candidate_line_range = line_range; + candidate_line_range.max = idx; + // NOTE(nick): when wrapping is interrupted with \n we emit a string without including \n + // because later tool_fprint_list inserts separator after each node + // except for last node, so don't strip last \n. + if (idx + 1 == string.size){ + candidate_line_range.max += 1; + } + String8 substr = str8_substr(string, candidate_line_range); + str8_list_push(arena, &list, substr); + line_range = r1u64(idx+1,idx+1); + } + else + if (char_is_space(chr) || chr == 0){ + Rng1U64 candidate_line_range = line_range; + candidate_line_range.max = idx; + String8 substr = str8_substr(string, candidate_line_range); + U64 width_this_line = max_width-wrapped_indent_level; + if (list.node_count == 0){ + width_this_line = first_line_max_width; + } + if (substr.size > width_this_line){ + String8 line = str8_substr(string, line_range); + if (wrapped_indent_level > 0){ + line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line); + } + str8_list_push(arena, &list, line); + line_range = r1u64(line_range.max+1, candidate_line_range.max); + wrapped_indent_level = ClampTop(64, wrap_indent); + } + else{ + line_range = candidate_line_range; + } + } + } + if (line_range.min < string.size && line_range.max > line_range.min){ + String8 line = str8_substr(string, line_range); + if (wrapped_indent_level > 0){ + line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line); + } + str8_list_push(arena, &list, line); + } + return list; +} + +//////////////////////////////// +//~ rjf: C-String-Izing + +internal String8 +mg_c_string_literal_from_multiline_string(String8 string) +{ + String8List strings = {0}; + { + str8_list_push(mg_arena, &strings, str8_lit("\"\"\n")); + U64 active_line_start_off = 0; + for(U64 off = 0; off <= string.size; off += 1) + { + B32 is_newline = (off < string.size && (string.str[off] == '\n' || string.str[off] == '\r')); + B32 is_ender = (off >= string.size || is_newline); + if(is_ender) + { + String8 line = str8_substr(string, r1u64(active_line_start_off, off)); + str8_list_push(mg_arena, &strings, str8_lit("\"")); + str8_list_push(mg_arena, &strings, line); + if(is_newline) + { + str8_list_push(mg_arena, &strings, str8_lit("\\n\"\n")); + } + else + { + str8_list_push(mg_arena, &strings, str8_lit("\"\n")); + } + active_line_start_off = off+1; + } + if(is_newline && string.str[off] == '\r') + { + active_line_start_off += 1; + off += 1; + } + } + } + String8 result = str8_list_join(mg_arena, &strings, 0); + return result; +} + +internal String8 +mg_c_array_literal_contents_from_data(String8 data) +{ + Temp scratch = scratch_begin(0, 0); + String8List strings = {0}; + { + for(U64 off = 0; off < data.size;) + { + U64 chunk_size = Min(data.size-off, 64); + U8 *chunk_bytes = data.str+off; + String8 chunk_text_string = {0}; + chunk_text_string.size = chunk_size*5; + chunk_text_string.str = push_array(mg_arena, U8, chunk_text_string.size); + for(U64 byte_idx = 0; byte_idx < chunk_size; byte_idx += 1) + { + String8 byte_str = push_str8f(scratch.arena, "0x%02x,", chunk_bytes[byte_idx]); + MemoryCopy(chunk_text_string.str+byte_idx*5, byte_str.str, byte_str.size); + } + off += chunk_size; + str8_list_push(mg_arena, &strings, chunk_text_string); + str8_list_push(mg_arena, &strings, str8_lit("\n")); + } + } + String8 result = str8_list_join(mg_arena, &strings, 0); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Map Functions + +internal MG_Map +mg_push_map(Arena *arena, U64 slot_count) +{ + MG_Map map = {0}; + map.slots_count = slot_count; + map.slots = push_array(arena, MG_MapSlot, map.slots_count); + return map; +} + +internal void * +mg_map_ptr_from_string(MG_Map *map, String8 string) +{ + void *result = 0; + { + U64 hash = mg_hash_from_string(string); + U64 slot_idx = hash%map->slots_count; + MG_MapSlot *slot = &map->slots[slot_idx]; + for(MG_MapNode *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->key, string, 0)) + { + result = n->val; + break; + } + } + } + return result; +} + +internal void +mg_map_insert_ptr(Arena *arena, MG_Map *map, String8 string, void *val) +{ + U64 hash = mg_hash_from_string(string); + U64 slot_idx = hash%map->slots_count; + MG_MapSlot *slot = &map->slots[slot_idx]; + MG_MapNode *n = push_array(arena, MG_MapNode, 1); + n->key = push_str8_copy(arena, string); + n->val = val; + SLLQueuePush(slot->first, slot->last, n); +} + +//////////////////////////////// +//~ rjf: String Expression Parsing + +internal MG_StrExpr * +mg_push_str_expr(Arena *arena, MG_StrExprOp op, MD_Node *node) +{ + MG_StrExpr *expr = push_array(arena, MG_StrExpr, 1); + MemoryCopyStruct(expr, &mg_str_expr_nil); + expr->op = op; + expr->node = node; + return expr; +} + +internal MG_StrExprParseResult +mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node *opl, S8 min_prec) +{ + MG_StrExprParseResult parse = {&mg_str_expr_nil}; + { + MD_Node *it = first; + + //- rjf: consume prefix operators + MG_StrExpr *leafmost_op = &mg_str_expr_nil; + for(;it < opl && !md_node_is_nil(it);) + { + MG_StrExprOp found_op = MG_StrExprOp_Null; + for(MG_StrExprOp op = (MG_StrExprOp)(MG_StrExprOp_Null+1); + op < MG_StrExprOp_COUNT; + op = (MG_StrExprOp)(op+1)) + { + if(mg_str_expr_op_kind_table[op] == MG_StrExprOpKind_Prefix && + str8_match(it->string, mg_str_expr_op_symbol_string_table[op], 0) && + mg_str_expr_op_precedence_table[op] >= min_prec) + { + found_op = op; + break; + } + } + if(found_op != MG_StrExprOp_Null) + { + MG_StrExpr *op_expr = mg_push_str_expr(arena, found_op, it); + if(leafmost_op == &mg_str_expr_nil) + { + leafmost_op = op_expr; + } + op_expr->left = parse.root; + parse.root = op_expr; + it = it->next; + } + else + { + break; + } + } + + //- rjf: parse atom + { + MG_StrExpr *atom = &mg_str_expr_nil; + if(it->flags & (MD_NodeFlag_Identifier|MD_NodeFlag_Numeric|MD_NodeFlag_StringLiteral) && + md_node_is_nil(it->first)) + { + atom = mg_push_str_expr(arena, MG_StrExprOp_Null, it); + it = it->next; + } + else if(!md_node_is_nil(it->first)) + { + MG_StrExprParseResult subparse = mg_str_expr_parse_from_first_opl__min_prec(arena, it->first, &md_nil_node, 0); + atom = subparse.root; + md_msg_list_concat_in_place(&parse.msgs, &subparse.msgs); + it = it->next; + } + if(leafmost_op != &mg_str_expr_nil) + { + leafmost_op->left = atom; + } + else + { + parse.root = atom; + } + } + + //- rjf: parse binary operator extensions at this precedence level + for(;it < opl && !md_node_is_nil(it);) + { + // rjf: find binary op kind of `it` + MG_StrExprOp found_op = MG_StrExprOp_Null; + for(MG_StrExprOp op = (MG_StrExprOp)(MG_StrExprOp_Null+1); + op < MG_StrExprOp_COUNT; + op = (MG_StrExprOp)(op+1)) + { + if(mg_str_expr_op_kind_table[op] == MG_StrExprOpKind_Binary && + str8_match(it->string, mg_str_expr_op_symbol_string_table[op], 0) && + mg_str_expr_op_precedence_table[op] >= min_prec) + { + found_op = op; + break; + } + } + + // rjf: good found_op -> build binary expr + if(found_op != MG_StrExprOp_Null) + { + MG_StrExpr *op_expr = mg_push_str_expr(arena, found_op, it); + if(leafmost_op == &mg_str_expr_nil) + { + leafmost_op = op_expr; + } + op_expr->left = parse.root; + parse.root = op_expr; + it = it->next; + } + else + { + break; + } + + // rjf: parse right hand side of binary operator + MG_StrExprParseResult subparse = mg_str_expr_parse_from_first_opl__min_prec(arena, it, opl, mg_str_expr_op_precedence_table[found_op]+1); + parse.root->right = subparse.root; + md_msg_list_concat_in_place(&parse.msgs, &subparse.msgs); + if(subparse.root == &mg_str_expr_nil) + { + md_msg_list_pushf(arena, &parse.msgs, it, MD_MsgKind_Error, "Missing right-hand-side of '%S'.", mg_str_expr_op_symbol_string_table[found_op]); + } + it = subparse.next_node; + } + + // rjf: store next node for more caller-side parsing + parse.next_node = it; + } + return parse; +} + +internal MG_StrExprParseResult +mg_str_expr_parse_from_first_opl(Arena *arena, MD_Node *first, MD_Node *opl) +{ + MG_StrExprParseResult parse = mg_str_expr_parse_from_first_opl__min_prec(arena, first, opl, 0); + return parse; +} + +internal MG_StrExprParseResult +mg_str_expr_parse_from_root(Arena *arena, MD_Node *root) +{ + MG_StrExprParseResult parse = mg_str_expr_parse_from_first_opl__min_prec(arena, root->first, &md_nil_node, 0); + return parse; +} + +//////////////////////////////// +//~ rjf: Table Generation Functions + +internal MG_NodeArray +mg_node_array_make(Arena *arena, U64 count) +{ + MG_NodeArray result = {0}; + result.count = count; + result.v = push_array(arena, MD_Node *, result.count); + for(U64 idx = 0; idx < result.count; idx += 1) + { + result.v[idx] = &md_nil_node; + } + return result; +} + +internal MG_NodeArray +mg_child_array_from_node(Arena *arena, MD_Node *node) +{ + MG_NodeArray children = mg_node_array_make(arena, md_child_count_from_node(node)); + U64 idx = 0; + for(MD_EachNode(child, node->first)) + { + children.v[idx] = child; + idx += 1; + } + return children; +} + +internal MG_NodeGrid +mg_node_grid_make_from_node(Arena *arena, MD_Node *root) +{ + MG_NodeGrid grid = {0}; + + // rjf: determine dimensions + U64 row_count = md_child_count_from_node(root); + U64 column_count = 0; + for(MD_EachNode(row, root->first)) + { + U64 cell_count_this_row = md_child_count_from_node(row); + column_count = Max(column_count, cell_count_this_row); + } + + // rjf: fill grid + grid.x_stride = 1; + grid.y_stride = column_count; + grid.cells = mg_node_array_make(arena, row_count*column_count); + grid.row_parents = mg_node_array_make(arena, row_count); + + // rjf: fill nodes + { + U64 y = 0; + for(MD_EachNode(row, root->first)) + { + U64 x = 0; + grid.row_parents.v[y] = row; + for(MD_EachNode(cell, row->first)) + { + grid.cells.v[x*grid.x_stride + y*grid.y_stride] = cell; + x += 1; + } + y += 1; + } + } + + return grid; +} + +internal MG_NodeArray +mg_row_from_index(MG_NodeGrid grid, U64 index) +{ + MG_NodeArray result = {0}; + if(0 <= index && index < grid.cells.count / grid.x_stride) + { + result.count = grid.y_stride; + result.v = &grid.cells.v[index*grid.y_stride]; + } + return result; +} + +internal MG_NodeArray +mg_column_from_index(Arena *arena, MG_NodeGrid grid, U64 index) +{ + MG_NodeArray result = {0}; + if(0 <= index && index < grid.y_stride) + { + U64 row_count = grid.cells.count / grid.y_stride; + result = mg_node_array_make(arena, row_count); + U64 idx = 0; + for(U64 row_idx = 0; row_idx < row_count; row_idx += 1, idx += 1) + { + result.v[idx] = grid.cells.v[index*grid.x_stride + row_idx*grid.y_stride]; + } + } + return result; +} + +internal MD_Node * +mg_node_from_grid_xy(MG_NodeGrid grid, U64 x, U64 y) +{ + MD_Node *result = &md_nil_node; + U64 idx = x*grid.x_stride + y*grid.y_stride; + if(0 <= idx && idx < grid.cells.count) + { + result = grid.cells.v[idx]; + } + return result; +} + +internal MG_ColumnDescArray +mg_column_desc_array_make(Arena *arena, U64 count, MG_ColumnDesc *descs) +{ + MG_ColumnDescArray result = {0}; + result.count = count; + result.v = push_array(arena, MG_ColumnDesc, result.count); + MemoryCopy(result.v, descs, sizeof(*result.v)*result.count); + return result; +} + +internal MG_ColumnDescArray +mg_column_desc_array_from_tag(Arena *arena, MD_Node *tag) +{ + MG_ColumnDescArray result = {0}; + result.count = md_child_count_from_node(tag); + result.v = push_array(arena, MG_ColumnDesc, result.count); + U64 idx = 0; + for(MD_EachNode(hdr, tag->first)) + { + result.v[idx].name = push_str8_copy(arena, hdr->string); + result.v[idx].kind = MG_ColumnKind_DirectCell; + if(md_node_has_tag(hdr, str8_lit("tag_check"), 0)) + { + result.v[idx].kind = MG_ColumnKind_CheckForTag; + } + if(md_node_has_tag(hdr, str8_lit("tag_child"), 0)) + { + String8 tag_name = md_tag_from_string(hdr, str8_lit("tag_child"), 0)->first->string; + result.v[idx].kind = MG_ColumnKind_TagChild; + result.v[idx].tag_name = tag_name; + } + idx += 1; + } + return result; +} + +internal U64 +mg_column_index_from_name(MG_ColumnDescArray descs, String8 name) +{ + U64 result = 0; + for(U64 idx = 0; idx < descs.count; idx += 1) + { + if(str8_match(descs.v[idx].name, name, 0)) + { + result = idx; + break; + } + } + return result; +} + +internal String8 +mg_string_from_row_desc_idx(MD_Node *row_parent, MG_ColumnDescArray descs, U64 idx) +{ + String8 result = {0}; + + // rjf: grab relevant column description + MG_ColumnDesc *desc = 0; + if(0 <= idx && idx < descs.count) + { + desc = descs.v + idx; + } + + // rjf: grab node + if(desc != 0) + { + switch(desc->kind) + { + default: break; + + case MG_ColumnKind_DirectCell: + { + // rjf: determine grid idx (shifted by synthetic columns) + U64 cell_idx = idx; + for(U64 col_idx = 0; col_idx < descs.count && col_idx < idx; col_idx += 1) + { + if(descs.v[col_idx].kind != MG_ColumnKind_DirectCell) + { + cell_idx -= 1; + } + } + MD_Node *node = md_child_from_index(row_parent, cell_idx); + result = node->string; + }break; + + case MG_ColumnKind_CheckForTag: + { + String8 tag_name = desc->name; + MD_Node *tag = md_tag_from_string(row_parent, tag_name, 0); + result = md_node_is_nil(tag) ? str8_lit("0") : str8_lit("1"); + }break; + + case MG_ColumnKind_TagChild: + { + String8 tag_name = desc->tag_name; + MD_Node *tag = md_tag_from_string(row_parent, tag_name, 0); + result = tag->first->string; + }break; + } + } + + return result; +} + +internal S64 +mg_eval_table_expand_expr__numeric(MG_StrExpr *expr, MG_TableExpandInfo *info) +{ + S64 result = 0; + MG_StrExprOp op = expr->op; + + switch(op) + { + default: + { + if(MG_StrExprOp_FirstString <= op && op <= MG_StrExprOp_LastString) + { + Temp scratch = scratch_begin(0, 0); + String8List result_strs = {0}; + mg_eval_table_expand_expr__string(scratch.arena, expr, info, &result_strs); + String8 result_str = str8_list_join(scratch.arena, &result_strs, 0); + try_s64_from_str8_c_rules(result_str, &result); + scratch_end(scratch); + } + }break; + + case MG_StrExprOp_Null: + { + try_s64_from_str8_c_rules(expr->node->string, &result); + }break; + + //- rjf: numeric arithmetic binary ops + case MG_StrExprOp_Add: + case MG_StrExprOp_Subtract: + case MG_StrExprOp_Multiply: + case MG_StrExprOp_Divide: + case MG_StrExprOp_Modulo: + case MG_StrExprOp_LeftShift: + case MG_StrExprOp_RightShift: + case MG_StrExprOp_BitwiseAnd: + case MG_StrExprOp_BitwiseOr: + case MG_StrExprOp_BitwiseXor: + case MG_StrExprOp_BooleanAnd: + case MG_StrExprOp_BooleanOr: + { + S64 left_val = mg_eval_table_expand_expr__numeric(expr->left, info); + S64 right_val = mg_eval_table_expand_expr__numeric(expr->right, info); + switch(op) + { + default:break; + case MG_StrExprOp_Add: result = left_val+right_val; break; + case MG_StrExprOp_Subtract: result = left_val-right_val; break; + case MG_StrExprOp_Multiply: result = left_val*right_val; break; + case MG_StrExprOp_Divide: result = left_val/right_val; break; + case MG_StrExprOp_Modulo: result = left_val%right_val; break; + case MG_StrExprOp_LeftShift: result = left_val<>right_val; break; + case MG_StrExprOp_BitwiseAnd: result = left_val&right_val; break; + case MG_StrExprOp_BitwiseOr: result = left_val|right_val; break; + case MG_StrExprOp_BitwiseXor: result = left_val^right_val; break; + case MG_StrExprOp_BooleanAnd: result = left_val&&right_val; break; + case MG_StrExprOp_BooleanOr: result = left_val||right_val; break; + } + }break; + + //- rjf: prefix unary ops + case MG_StrExprOp_BitwiseNegate: + case MG_StrExprOp_BooleanNot: + { + S64 right_val = mg_eval_table_expand_expr__numeric(expr->left, info); + switch(op) + { + default:break; + case MG_StrExprOp_BitwiseNegate: result = (S64)(~((U64)right_val)); break; + case MG_StrExprOp_BooleanNot: result = !right_val; + } + }break; + + //- rjf: comparisons + case MG_StrExprOp_Equals: + case MG_StrExprOp_DoesNotEqual: + { + Temp scratch = scratch_begin(0, 0); + String8List left_strs = {0}; + String8List right_strs = {0}; + mg_eval_table_expand_expr__string(scratch.arena, expr->left, info, &left_strs); + mg_eval_table_expand_expr__string(scratch.arena, expr->right, info, &right_strs); + String8 left_str = str8_list_join(scratch.arena, &left_strs, 0); + String8 right_str = str8_list_join(scratch.arena, &right_strs, 0); + B32 match = str8_match(left_str, right_str, 0); + result = (op == MG_StrExprOp_Equals ? match : !match); + scratch_end(scratch); + }break; + } + + return result; +} + +internal void +mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpandInfo *info, String8List *out) +{ + MG_StrExprOp op = expr->op; + + switch(op) + { + default: + { + if(MG_StrExprOp_FirstNumeric <= op && op <= MG_StrExprOp_LastNumeric) + { + S64 numeric_eval = mg_eval_table_expand_expr__numeric(expr, info); + String8 numeric_eval_stringized = {0}; + if(md_node_has_tag(md_root_from_node(expr->node), str8_lit("hex"), 0)) + { + numeric_eval_stringized = push_str8f(arena, "0x%I64x", numeric_eval); + } + else + { + numeric_eval_stringized = push_str8f(arena, "%I64d", numeric_eval); + } + str8_list_push(arena, out, numeric_eval_stringized); + } + }break; + + case MG_StrExprOp_Null: + { + str8_list_push(arena, out, expr->node->string); + }break; + + case MG_StrExprOp_Dot: + { + // rjf: grab left/right + MG_StrExpr *left_expr = expr->left; + MD_Node *left_node = left_expr->node; + MG_StrExpr *right_expr = expr->right; + MD_Node *right_node = right_expr->node; + + // rjf: grab table name (LHS of .) and column lookup string (RHS of .) + String8 expand_label = left_node->string; + String8 column_lookup = right_node->string; + + // rjf: find which task corresponds to this table + U64 row_idx = 0; + MG_NodeGrid *grid = 0; + MG_ColumnDescArray column_descs = {0}; + { + for(MG_TableExpandTask *task = info->first_expand_task; task != 0; task = task->next) + { + if(str8_match(expand_label, task->expansion_label, 0)) + { + row_idx = task->idx; + grid = task->grid; + column_descs = task->column_descs; + break; + } + } + } + + // rjf: grab row parent + MD_Node *row_parent = &md_nil_node; + if(grid && (0 <= row_idx && row_idx < grid->row_parents.count)) + { + row_parent = grid->row_parents.v[row_idx]; + } + + // rjf: get string for this table lookup + String8 lookup_string = {0}; + { + U64 column_idx = 0; + + if(str8_match(column_lookup, str8_lit("_it"), 0)) + { + lookup_string = push_str8f(arena, "%I64u", row_idx); + } + else + { + // NOTE(rjf): numeric column lookup (column index) + if(right_node->flags & MD_NodeFlag_Numeric) + { + try_u64_from_str8_c_rules(column_lookup, &column_idx); + } + + // NOTE(rjf): string column lookup (column name) + if(right_node->flags & (MD_NodeFlag_Identifier|MD_NodeFlag_StringLiteral)) + { + column_idx = mg_column_index_from_name(column_descs, column_lookup); + } + + lookup_string = mg_string_from_row_desc_idx(row_parent, column_descs, column_idx); + if(str8_match(lookup_string, str8_lit("--"), 0)) + { + lookup_string = info->missing_value_fallback; + } + } + } + + // rjf: push lookup string + { + str8_list_push(arena, out, lookup_string); + } + }break; + + case MG_StrExprOp_ExpandIfTrue: + { + S64 bool_value = mg_eval_table_expand_expr__numeric(expr->left, info); + if(bool_value) + { + mg_eval_table_expand_expr__string(arena, expr->right, info, out); + } + }break; + + case MG_StrExprOp_Concat: + { + mg_eval_table_expand_expr__string(arena, expr->left, info, out); + mg_eval_table_expand_expr__string(arena, expr->right, info, out); + }break; + + case MG_StrExprOp_BumpToColumn: + { + S64 column = mg_eval_table_expand_expr__numeric(expr->left, info); + S64 current_column = out->total_size; + S64 spaces_to_push = column - current_column; + if(spaces_to_push > 0) + { + String8 str = {0}; + str.size = spaces_to_push; + str.str = push_array(arena, U8, spaces_to_push); + for(S64 idx = 0; idx < spaces_to_push; idx += 1) + { + str.str[idx] = ' '; + } + str8_list_push(arena, out, str); + } + }break; + } +} + +internal void +mg_loop_table_column_expansion(Arena *arena, String8 strexpr, MG_TableExpandInfo *info, MG_TableExpandTask *task, String8List *out) +{ + Temp scratch = scratch_begin(&arena, 1); + for(U64 it_idx = 0; it_idx < task->count; it_idx += 1) + { + task->idx = it_idx; + + //- rjf: iterate all further dimensions, if there's left in the chain + if(task->next) + { + mg_loop_table_column_expansion(arena, strexpr, info, task->next, out); + } + + //- rjf: if this is the last task in the chain, perform expansion + else + { + String8List expansion_strs = {0}; + U64 start = 0; + for(U64 char_idx = 0; char_idx <= strexpr.size;) + { + // rjf: push plain text parts of strexpr + if(char_idx == strexpr.size || strexpr.str[char_idx] == '$') + { + String8 plain_text_substr = str8_substr(strexpr, r1u64(start, char_idx)); + start = char_idx; + if(plain_text_substr.size != 0) + { + str8_list_push(arena, &expansion_strs, plain_text_substr); + } + } + + // rjf: handle expansion expression + if(strexpr.str[char_idx] == '$') + { + String8 string = str8_skip(strexpr, char_idx+1); + Rng1U64 expr_range = {0}; + S64 paren_nest = 0; + for(U64 idx = 0; idx < string.size; idx += 1) + { + if(string.str[idx] == '(') + { + paren_nest += 1; + if(paren_nest == 1) + { + expr_range.min = idx; + } + } + if(string.str[idx] == ')') + { + paren_nest -= 1; + if(paren_nest == 0) + { + expr_range.max = idx+1; + break; + } + } + } + String8 expr_string = str8_substr(string, expr_range); + MD_TokenizeResult expr_tokenize = md_tokenize_from_text(scratch.arena, expr_string); + MD_ParseResult expr_base_parse = md_parse_from_text_tokens(scratch.arena, str8_lit(""), expr_string, expr_tokenize.tokens); + MG_StrExprParseResult expr_parse = mg_str_expr_parse_from_root(scratch.arena, expr_base_parse.root->first); + mg_eval_table_expand_expr__string(arena, expr_parse.root, info, &expansion_strs); + char_idx = start = char_idx + 1 + expr_range.max; + } + else + { + char_idx += 1; + } + } + String8 expansion_str = str8_list_join(arena, &expansion_strs, 0); + if(expansion_str.size != 0) + { + str8_list_push(arena, out, expansion_str); + } + } + } + + scratch_end(scratch); +} + +internal String8List +mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_column_desc_map, String8 fallback, MD_Node *gen) +{ + String8List result = {0}; + Temp scratch = scratch_begin(&arena, 1); + for(MD_EachNode(strexpr_node, gen->first)) + { + // rjf: build task list + MG_TableExpandTask *first_task = 0; + MG_TableExpandTask *last_task = 0; + for(MD_EachNode(tag, strexpr_node->first_tag)) + { + if(str8_match(tag->string, str8_lit("expand"), 0)) + { + // rjf: grab args for this expansion + MD_Node *table_name_node = md_child_from_index(tag, 0); + MD_Node *expand_label_node = md_child_from_index(tag, 1); + String8 table_name = table_name_node->string; + String8 expand_label = expand_label_node->string; + + // rjf: lookup table / column descriptions + MG_NodeGrid *grid = mg_map_ptr_from_string(&grid_name_map, table_name); + MG_ColumnDescArray *column_descs = mg_map_ptr_from_string(&grid_column_desc_map, table_name); + + // rjf: figure out row count + U64 grid_row_count = 0; + if(grid != 0) + { + grid_row_count = grid->cells.count / grid->y_stride; + } + + // rjf: push task for this expansion + if(grid != 0) + { + MG_TableExpandTask *task = push_array(scratch.arena, MG_TableExpandTask, 1); + task->expansion_label = expand_label; + task->grid = grid; + task->column_descs = *column_descs; + task->count = grid_row_count; + task->idx = 0; + SLLQueuePush(first_task, last_task, task); + } + } + } + + // rjf: do expansion generation, OR just push this string if we have no expansions + { + MG_TableExpandInfo info = {first_task, fallback}; + if(first_task != 0) + { + mg_loop_table_column_expansion(arena, strexpr_node->string, &info, first_task, &result); + } + else + { + str8_list_push(arena, &result, strexpr_node->string); + } + } + } + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Layer Lookup Functions + +internal String8 +mg_layer_key_from_path(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + U64 src_folder_pos = 0; + for(U64 next_src_folder_pos = 0; + next_src_folder_pos < path.size; + next_src_folder_pos = str8_find_needle(path, next_src_folder_pos+1, str8_lit("src"), 0)) + { + src_folder_pos = next_src_folder_pos; + } + String8List path_parts = str8_split_path(scratch.arena, str8_chop_last_slash(str8_skip(path, src_folder_pos+4))); + StringJoin join = {0}; + join.sep = str8_lit("/"); + String8 key = str8_list_join(mg_arena, &path_parts, &join); + scratch_end(scratch); + return key; +} + +internal MG_Layer * +mg_layer_from_key(String8 key) +{ + U64 hash = mg_hash_from_string(key); + U64 slot_idx = hash%mg_state->slots_count; + MG_LayerSlot *slot = &mg_state->slots[slot_idx]; + MG_Layer *layer = 0; + for(MG_LayerNode *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->v.key, key, 0)) + { + layer = &n->v; + break; + } + } + if(layer == 0) + { + MG_LayerNode *n = push_array(mg_arena, MG_LayerNode, 1); + SLLQueuePush(slot->first, slot->last, n); + n->v.key = push_str8_copy(mg_arena, key); + layer = &n->v; + } + return layer; +} diff --git a/src/metagen/metagen.h b/src/metagen/metagen.h new file mode 100644 index 00000000..3c86bce6 --- /dev/null +++ b/src/metagen/metagen.h @@ -0,0 +1,290 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef METAGEN_H +#define METAGEN_H + +//////////////////////////////// +//~ rjf: Parse Artifact Types + +typedef struct MG_FileParse MG_FileParse; +struct MG_FileParse +{ + MD_Node *root; +}; + +typedef struct MG_FileParseNode MG_FileParseNode; +struct MG_FileParseNode +{ + MG_FileParseNode *next; + MG_FileParse v; +}; + +typedef struct MG_FileParseList MG_FileParseList; +struct MG_FileParseList +{ + MG_FileParseNode *first; + MG_FileParseNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Map Type + +typedef struct MG_MapNode MG_MapNode; +struct MG_MapNode +{ + MG_MapNode *next; + String8 key; + void *val; +}; + +typedef struct MG_MapSlot MG_MapSlot; +struct MG_MapSlot +{ + MG_MapNode *first; + MG_MapNode *last; +}; + +typedef struct MG_Map MG_Map; +struct MG_Map +{ + MG_MapSlot *slots; + U64 slots_count; +}; + +//////////////////////////////// +//~ rjf: String Expression Types + +typedef enum MG_StrExprOpKind +{ + MG_StrExprOpKind_Null, + MG_StrExprOpKind_Prefix, + MG_StrExprOpKind_Postfix, + MG_StrExprOpKind_Binary, + MG_StrExprOpKind_COUNT +} +MG_StrExprOpKind; + +typedef enum MG_StrExprOp +{ + MG_StrExprOp_Null, + +#define MG_StrExprOp_FirstString MG_StrExprOp_Dot + MG_StrExprOp_Dot, + MG_StrExprOp_ExpandIfTrue, + MG_StrExprOp_Concat, + MG_StrExprOp_BumpToColumn, +#define MG_StrExprOp_LastString MG_StrExprOp_BumpToColumn + +#define MG_StrExprOp_FirstNumeric MG_StrExprOp_Add + MG_StrExprOp_Add, + MG_StrExprOp_Subtract, + MG_StrExprOp_Multiply, + MG_StrExprOp_Divide, + MG_StrExprOp_Modulo, + MG_StrExprOp_LeftShift, + MG_StrExprOp_RightShift, + MG_StrExprOp_BitwiseAnd, + MG_StrExprOp_BitwiseOr, + MG_StrExprOp_BitwiseXor, + MG_StrExprOp_BitwiseNegate, + MG_StrExprOp_BooleanAnd, + MG_StrExprOp_BooleanOr, + MG_StrExprOp_BooleanNot, + MG_StrExprOp_Equals, + MG_StrExprOp_DoesNotEqual, +#define MG_StrExprOp_LastNumeric MG_StrExprOp_DoesNotEqual + + MG_StrExprOp_COUNT, +} +MG_StrExprOp; + +typedef struct MG_StrExpr MG_StrExpr; +struct MG_StrExpr +{ + MG_StrExpr *parent; + MG_StrExpr *left; + MG_StrExpr *right; + MG_StrExprOp op; + MD_Node *node; +}; + +typedef struct MG_StrExprParseResult MG_StrExprParseResult; +struct MG_StrExprParseResult +{ + MG_StrExpr *root; + MD_MsgList msgs; + MD_Node *next_node; +}; + +//////////////////////////////// +//~ rjf: Table Generation Types + +typedef struct MG_NodeArray MG_NodeArray; +struct MG_NodeArray +{ + MD_Node **v; + U64 count; +}; + +typedef struct MG_NodeGrid MG_NodeGrid; +struct MG_NodeGrid +{ + U64 x_stride; + U64 y_stride; + MG_NodeArray cells; + MG_NodeArray row_parents; +}; + +typedef enum MG_ColumnKind +{ + MG_ColumnKind_DirectCell, + MG_ColumnKind_CheckForTag, + MG_ColumnKind_TagChild, + MG_ColumnKind_COUNT +} +MG_ColumnKind; + +typedef struct MG_ColumnDesc MG_ColumnDesc; +struct MG_ColumnDesc +{ + String8 name; + MG_ColumnKind kind; + String8 tag_name; +}; + +typedef struct MG_ColumnDescArray MG_ColumnDescArray; +struct MG_ColumnDescArray +{ + U64 count; + MG_ColumnDesc *v; +}; + +typedef struct MG_TableExpandTask MG_TableExpandTask; +struct MG_TableExpandTask +{ + MG_TableExpandTask *next; + String8 expansion_label; + MG_NodeGrid *grid; + MG_ColumnDescArray column_descs; + U64 count; + U64 idx; +}; + +typedef struct MG_TableExpandInfo MG_TableExpandInfo; +struct MG_TableExpandInfo +{ + MG_TableExpandTask *first_expand_task; + String8 missing_value_fallback; +}; + +//////////////////////////////// +//~ rjf: Main Output Path Types + +typedef struct MG_Layer MG_Layer; +struct MG_Layer +{ + String8 key; + String8List enums; + String8List structs; + String8List h_functions; + String8List h_tables; + String8List h_catchall; + String8List c_functions; + String8List c_tables; + String8List c_catchall; +}; + +typedef struct MG_LayerNode MG_LayerNode; +struct MG_LayerNode +{ + MG_LayerNode *next; + MG_Layer v; +}; + +typedef struct MG_LayerSlot MG_LayerSlot; +struct MG_LayerSlot +{ + MG_LayerNode *first; + MG_LayerNode *last; +}; + +typedef struct MG_State MG_State; +struct MG_State +{ + U64 slots_count; + MG_LayerSlot *slots; +}; + +//////////////////////////////// +//~ rjf: Globals + +global Arena *mg_arena = 0; +global MG_State *mg_state = 0; +read_only global MG_StrExpr mg_str_expr_nil = {&mg_str_expr_nil, &mg_str_expr_nil, &mg_str_expr_nil}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 mg_hash_from_string(String8 string); +internal TxtPt mg_txt_pt_from_string_off(String8 string, U64 off); + +//////////////////////////////// +//~ rjf: String Escaping + +internal String8 mg_escaped_from_str8(Arena *arena, String8 string); + +//////////////////////////////// +//~ rjf: String Wrapping + +internal String8List mg_wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent); + +//////////////////////////////// +//~ rjf: C-String-Izing + +internal String8 mg_c_string_literal_from_multiline_string(String8 string); +internal String8 mg_c_array_literal_contents_from_data(String8 data); + +//////////////////////////////// +//~ rjf: Map Functions + +internal MG_Map mg_push_map(Arena *arena, U64 slot_count); +internal void *mg_map_ptr_from_string(MG_Map *map, String8 string); +internal void mg_map_insert_ptr(Arena *arena, MG_Map *map, String8 string, void *val); + +//////////////////////////////// +//~ rjf: String Expression Parsing + +internal MG_StrExpr *mg_push_str_expr(Arena *arena, MG_StrExprOp op, MD_Node *node); +internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node *opl, S8 min_prec); +internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl(Arena *arena, MD_Node *first, MD_Node *opl); +internal MG_StrExprParseResult mg_str_expr_parse_from_root(Arena *arena, MD_Node *root); + +//////////////////////////////// +//~ rjf: Table Generation Functions + +internal MG_NodeArray mg_node_array_make(Arena *arena, U64 count); +internal MG_NodeArray mg_child_array_from_node(Arena *arena, MD_Node *node); +internal MG_NodeGrid mg_node_grid_make_from_node(Arena *arena, MD_Node *root); +internal MG_NodeArray mg_row_from_index(MG_NodeGrid grid, U64 index); +internal MG_NodeArray mg_column_from_index(Arena *arena, MG_NodeGrid grid, U64 index); +internal MD_Node *mg_node_from_grid_xy(MG_NodeGrid grid, U64 x, U64 y); + +internal MG_ColumnDescArray mg_column_desc_array_make(Arena *arena, U64 count, MG_ColumnDesc *descs); +internal MG_ColumnDescArray mg_column_desc_array_from_tag(Arena *arena, MD_Node *tag); +internal U64 mg_column_index_from_name(MG_ColumnDescArray descs, String8 name); +internal String8 mg_string_from_row_desc_idx(MD_Node *row_parent, MG_ColumnDescArray descs, U64 idx); + +internal S64 mg_eval_table_expand_expr__numeric(MG_StrExpr *expr, MG_TableExpandInfo *info); +internal void mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpandInfo *info, String8List *out); +internal void mg_loop_table_column_expansion(Arena *arena, String8 strexpr, MG_TableExpandInfo *info, MG_TableExpandTask *task, String8List *out); +internal String8List mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_column_desc_map, String8 fallback, MD_Node *gen); + +//////////////////////////////// +//~ rjf: Layer Lookup Functions + +internal String8 mg_layer_key_from_path(String8 path); +internal MG_Layer *mg_layer_from_key(String8 key); + +#endif //METAGEN_H diff --git a/src/metagen/metagen_base/metagen_base_arena.c b/src/metagen/metagen_base/metagen_base_arena.c new file mode 100644 index 00000000..d7297f71 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_arena.c @@ -0,0 +1,316 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// Implementation + +internal Arena * +arena_alloc__sized(U64 init_res, U64 init_cmt) +{ + ProfBeginFunction(); + Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res); + + void *memory; + U64 res; + U64 cmt; + + B32 large_pages = os_large_pages_enabled(); + if (large_pages) { + U64 page_size = os_large_page_size(); + res = AlignPow2(init_res, page_size); + +#if OS_WINDOWS + cmt = res; +#else + cmt AlignPow2(init_cmt, page_size); +#endif + + memory = os_reserve_large(res); + if (!os_commit_large(memory, cmt)) { + memory = 0; + os_release(memory, res); + } + } else { + U64 page_size = os_page_size(); + res = AlignPow2(init_res, page_size); + cmt = AlignPow2(init_cmt, page_size); + + memory = os_reserve(res); + if (!os_commit(memory, cmt)) { + memory = 0; + os_release(memory, res); + } + } + Assert(memory); + + AsanPoisonMemoryRegion(memory, cmt); + AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE); + + Arena *arena = (Arena*)memory; + if (arena) { + arena->prev = 0; + arena->current = arena; + arena->base_pos = 0; + arena->pos = ARENA_HEADER_SIZE; + arena->cmt = cmt; + arena->res = res; + arena->align = 8; +#if ENABLE_DEV + arena->dev = 0; +#endif + arena->grow = 1; + arena->large_pages = large_pages; + } + + ProfEnd(); + return arena; +} + +internal Arena * +arena_alloc(void) +{ + ProfBeginFunction(); + + U64 init_res, init_cmt; + if (os_large_pages_enabled()) { + init_res = ARENA_RESERVE_SIZE_LARGE_PAGES; + init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES; + } else { + init_res = ARENA_RESERVE_SIZE; + init_cmt = ARENA_COMMIT_SIZE; + } + + Arena *arena = arena_alloc__sized(init_res, init_cmt); + + ProfEnd(); + return arena; +} + +internal void +arena_release(Arena *arena) +{ + for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) { + prev = node->prev; + os_release(node, node->res); + } +} + +internal U64 +arena_huge_push_threshold(void) +{ + U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE; + U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1; + return threshold; +} + +internal void * +arena_push__impl(Arena *arena, U64 size) +{ + Arena *current = arena->current; + U64 pos_mem = AlignPow2(current->pos, arena->align); + U64 pos_new = pos_mem + size; + + if (current->res < pos_new && arena->grow) { + Arena *new_block; + + // normal growth path + if (size < arena_huge_push_threshold()) { + new_block = arena_alloc(); + } + // huge growth path + else { + U64 new_block_size = size + ARENA_HEADER_SIZE; + new_block = arena_alloc__sized(new_block_size, new_block_size); + } + + if (new_block) { + new_block->base_pos = current->base_pos + current->res; + SLLStackPush_N(arena->current, new_block, prev); + + current = new_block; + pos_mem = AlignPow2(current->pos, current->align); + pos_new = pos_mem + size; + } + } + + if (current->cmt < pos_new) { + U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size; + B32 is_cmt_ok; + + if (current->large_pages) { + cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES); + cmt_new_clamped = ClampTop(cmt_new_aligned, current->res); + cmt_new_size = cmt_new_clamped - current->cmt; + is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size); + } else { + cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE); + cmt_new_clamped = ClampTop(cmt_new_aligned, current->res); + cmt_new_size = cmt_new_clamped - current->cmt; + is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size); + } + Assert(is_cmt_ok); + + if (is_cmt_ok) { + current->cmt = cmt_new_clamped; + } + } + + void *memory = 0; + + if (current->cmt >= pos_new) { + memory = (U8*)current + pos_mem; + current->pos = pos_new; + AsanUnpoisonMemoryRegion(memory, size); + } + +#if OS_FEATURE_GRAPHICAL + if(Unlikely(memory == 0)) + { + os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure.")); + os_exit_process(1); + } +#endif + + return memory; +} + +internal U64 +arena_pos(Arena *arena) +{ + Arena *current = arena->current; + U64 pos = current->base_pos + current->pos; + return pos; +} + +internal void +arena_pop_to(Arena *arena, U64 big_pos_unclamped) +{ + U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped); + + // unroll the chain + Arena *current = arena->current; + for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) { + prev = current->prev; + os_release(current, current->res); + } + AssertAlways(current); + arena->current = current; + + // compute arena-relative position + U64 new_pos = big_pos - current->base_pos; + AssertAlways(new_pos <= current->pos); + + // poison popped memory block + AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos)); + + // update position + current->pos = new_pos; +} + +internal void +arena_absorb(Arena *arena, Arena *sub) +{ +#if ENABLE_DEV + arena_annotate_absorb__dev(arena, sub); +#endif + + // base adjustment + Arena *current = arena->current; + U64 base_adjust = current->base_pos + current->res; + for (Arena *node = sub->current; node != 0; node = node->prev) { + node->base_pos += base_adjust; + } + + // attach sub to arena + sub->prev = arena->current; + arena->current = sub->current; + sub->current = sub; +} + +//////////////////////////////// +// Wrappers + +internal void * +arena_push(Arena *arena, U64 size) +{ + void *memory = arena_push__impl(arena, size); +#if ENABLE_DEV + arena_annotate_push__dev(arena, size, memory); +#endif + return memory; +} + +internal void * +arena_push_contiguous(Arena *arena, U64 size) +{ + B32 restore = arena->grow; + arena->grow = 0; + void *memory = arena_push(arena, size); + arena->grow = restore; +#if ENABLE_DEV + arena_annotate_push__dev(arena, size, memory); +#endif + return memory; +} + +internal void +arena_push_align(Arena *arena, U64 align) +{ + Assert(IsPow2(align)); + U64 amt = AlignPadPow2(arena->pos, align); + void *ptr = arena_push(arena, amt); + MemoryZero(ptr, amt); +} + +internal void +arena_put_back(Arena *arena, U64 amt) +{ + U64 pos_old = arena_pos(arena); + U64 pos_new = pos_old; + if (amt < pos_old) { + pos_new = pos_old - amt; + } + arena_pop_to(arena, pos_new); +} + +internal void +arena_clear(Arena *arena) +{ + arena_pop_to(arena, 0); +} + +internal Temp +temp_begin(Arena *arena) +{ + U64 pos = arena_pos(arena); + Temp temp = {arena, pos}; + return temp; +} + +internal void +temp_end(Temp temp) +{ + arena_pop_to(temp.arena, temp.pos); +} + +//////////////////////////////// +//~ NOTE(allen): "Mini-Arena" Helper + +internal B32 +ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){ + B32 result = 0; + U8 *cmt = (U8*)*cmtptr; + if (cmt < (U8*)pos){ + U64 cmt_size_raw = (U8*)pos - cmt; + U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size); + if (os_commit(cmt, cmt_size)){ + *cmtptr = cmt + cmt_size; + result = 1; + } + } + else{ + result = 1; + } + return(result); +} + diff --git a/src/metagen/metagen_base/metagen_base_arena.h b/src/metagen/metagen_base/metagen_base_arena.h new file mode 100644 index 00000000..0a9ca92f --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_arena.h @@ -0,0 +1,94 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_ARENA_H +#define BASE_ARENA_H + +//////////////////////////////// +//~ rjf: Constants + +#define ARENA_HEADER_SIZE 128 + +#ifndef ARENA_RESERVE_SIZE +# define ARENA_RESERVE_SIZE MB(64) +#endif +#ifndef ARENA_COMMIT_SIZE +# define ARENA_COMMIT_SIZE KB(64) +#endif + +#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES +# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8) +#endif +#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES +# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2) +#endif + +//////////////////////////////// +//~ rjf: Arena Types + +typedef struct Arena Arena; +struct Arena +{ + struct Arena *prev; + struct Arena *current; + U64 base_pos; + U64 pos; + U64 cmt; + U64 res; + U64 align; + struct ArenaDev *dev; + B8 grow; + B8 large_pages; +}; + +typedef struct Temp Temp; +struct Temp +{ + Arena *arena; + U64 pos; +}; + +//////////////////////////////// +// Implementation + +internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt); + +internal Arena* arena_alloc(void); +internal void arena_release(Arena *arena); + +internal void* arena_push__impl(Arena *arena, U64 size); +internal U64 arena_pos(Arena *arena); +internal void arena_pop_to(Arena *arena, U64 pos); + +internal void arena_absorb(Arena *arena, Arena *sub); + +//////////////////////////////// +// Wrappers + +internal void* arena_push(Arena *arena, U64 size); +internal void* arena_push_contiguous(Arena *arena, U64 size); +internal void arena_clear(Arena *arena); +internal void arena_push_align(Arena *arena, U64 align); +internal void arena_put_back(Arena *arena, U64 amt); + +internal Temp temp_begin(Arena *arena); +internal void temp_end(Temp temp); + +//////////////////////////////// +//~ NOTE(allen): "Mini-Arena" Helper + +internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size); + +//////////////////////////////// +//~ NOTE(allen): Main API Macros + +#if !ENABLE_DEV +# define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) +#else +# define push_array_no_zero(a,T,c) (tctx_write_this_srcloc(), (T*)arena_push((a), sizeof(T)*(c))) +#endif +#define push_array_no_zero__no_annotation(a,T,c) (T*)arena_push__impl((a), sizeof(T)*(c)) + +#define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c)) + +#endif // BASE_ARENA_H diff --git a/src/metagen/metagen_base/metagen_base_arena_dev.c b/src/metagen/metagen_base/metagen_base_arena_dev.c new file mode 100644 index 00000000..94c334bd --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_arena_dev.c @@ -0,0 +1,197 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Dev Arena + +#if ENABLE_DEV + +internal void +arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){ + ArenaDev *dev = arena->dev; + if (dev != 0 && ptr != 0){ + //- read location + char *file_name = 0; + U64 line_number = 0; + tctx_read_srcloc(&file_name, &line_number); + tctx_write_srcloc(0, 0); + + //- profile + ArenaProf *prof = dev->prof; + if (prof != 0){ + // c string -> string + String8 file_name_str = str8_lit("(null)"); + if (file_name != 0){ + file_name_str = str8_cstring(file_name); + } + // record + arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1); + } + } +} + +internal void +arena_annotate_absorb__dev(Arena *arena, Arena *sub){ + ArenaDev *dev = arena->dev; + ArenaDev *sub_dev = sub->dev; + if (dev != 0 && sub_dev != 0){ + //- merge profiles + ArenaProf *prof = dev->prof; + ArenaProf *sub_prof = sub_dev->prof; + if (prof != 0 && sub_prof != 0){ + for (ArenaProfNode *sub_node = sub_prof->first; + sub_node != 0; + sub_node = sub_node->next){ + arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line, + sub_node->size, sub_node->count); + } + } + } + //- release the sub dev memory + if (sub_dev != 0){ + arena_release(sub_dev->arena); + } +} + +internal ArenaDev* +arena_equip__dev(Arena *arena){ + ArenaDev *result = arena->dev; + if (result == 0){ + Arena *dev_arena = arena_alloc(); + ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev)); + MemoryZeroStruct(dev); + dev->arena = dev_arena; + arena->dev = dev; + result = dev; + } + return(result); +} + +internal void +arena_equip_profile__dev(Arena *arena){ + ArenaDev *dev = arena_equip__dev(arena); + if (dev->prof == 0){ + dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf)); + MemoryZeroStruct(dev->prof); + } +} + +internal void +arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){ + Assert(arena != out_arena); + + //- get dev & disable + ArenaDev *dev = arena->dev; + arena->dev = 0; + + //- get prof + ArenaProf *prof = (dev != 0)?dev->prof:0; + + //- not equipped with prof + if (prof == 0){ + str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n")); + } + + //- print prof + if (prof != 0){ + Temp scratch = temp_begin(dev->arena); + + //- make flat array + U64 note_count = prof->count; + ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count); + { + ArenaProfNode **note_ptr = notes; + for (ArenaProfNode *node = prof->first; + node != 0; + node = node->next, note_ptr += 1){ + *note_ptr = node; + } + } + + //- file name size + U64 max_file_name_size = 0; + { + ArenaProfNode **note_ptr = notes; + for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ + max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size); + } + } + + //- sort (> size, < [address]) + for (U64 i = 0; i < note_count; i += 1){ + ArenaProfNode **i_note = notes + i; + ArenaProfNode **min_note = i_note; + for (U64 j = i + 1; j < note_count; j += 1){ + ArenaProfNode **j_note = notes + j; + if ((**j_note).size > (**min_note).size || + ((**j_note).size == (**min_note).size && *j_note < *min_note)){ + min_note = j_note; + } + } + if (min_note != i_note){ + ArenaProfNode *t = *i_note; + *i_note = *min_note; + *min_note = t; + } + } + + //- total size + U64 total_size = 0; + { + ArenaProfNode **note_ptr = notes; + for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ + ArenaProfNode *note = *note_ptr; + total_size += note->size; + } + } + + //- print + { + str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size); + + ArenaProfNode **note_ptr = notes; + for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ + ArenaProfNode *note = *note_ptr; + String8 location = push_str8f(scratch.arena, "%S:%5llu:", + note->file_name, note->line); + F32 percent = 100.f*((F32)note->size)/total_size; + str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n", + max_file_name_size + 7, str8_varg(location), + note->size, percent, note->count); + } + } + + temp_end(scratch); + } + + //- restore dev + arena->dev = dev; +} + +internal void +arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, + U64 size, U64 count){ + // find existing profile node + ArenaProfNode *prof_node = 0; + for (ArenaProfNode *node = prof->first; + node != 0; + node = node->next){ + if (node->line == line && str8_match(file_name, node->file_name, 0)){ + prof_node = node; + break; + } + } + // make new histogram node if necessary + if (prof_node == 0){ + prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node)); + SLLQueuePush(prof->first, prof->last, prof_node); + prof->count += 1; + prof_node->file_name = file_name; + prof_node->line = line; + } + // record this allocation + prof_node->size += size; + prof_node->count += count; +} + +#endif diff --git a/src/metagen/metagen_base/metagen_base_arena_dev.h b/src/metagen/metagen_base/metagen_base_arena_dev.h new file mode 100644 index 00000000..14d16b1d --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_arena_dev.h @@ -0,0 +1,47 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_ARENA_DEV_H +#define BASE_ARENA_DEV_H + +//////////////////////////////// +//~ NOTE(allen): Dev Arena Types + +typedef struct ArenaDev ArenaDev; +struct ArenaDev +{ + Arena *arena; + struct ArenaProf *prof; +}; + +typedef struct ArenaProf ArenaProf; +struct ArenaProf +{ + struct ArenaProfNode *first; + struct ArenaProfNode *last; + U64 count; +}; + +typedef struct ArenaProfNode ArenaProfNode; +struct ArenaProfNode +{ + ArenaProfNode *next; + String8 file_name; + U64 line; + U64 size; + U64 count; +}; + +//////////////////////////////// +//~ NOTE(allen): Dev Arena Functions + +#if ENABLE_DEV +internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr); +internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub); +internal ArenaDev* arena_equip__dev(Arena *arena); +internal void arena_equip_profile__dev(Arena *arena); +internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out); +internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count); +#endif + +#endif // BASE_ARENA_DEV_H diff --git a/src/metagen/metagen_base/metagen_base_bits.c b/src/metagen/metagen_base/metagen_base_bits.c new file mode 100644 index 00000000..98ae781f --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_bits.c @@ -0,0 +1,103 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS) + +internal U64 +count_bits_set16(U16 val) +{ + return __popcnt16(val); +} + +internal U64 +count_bits_set32(U32 val) +{ + return __popcnt(val); +} + +internal U64 +count_bits_set64(U64 val) +{ + return __popcnt64(val); +} + +internal U64 +ctz32(U32 mask) +{ + unsigned long idx; + _BitScanForward(&idx, mask); + return idx; +} + +internal U64 +ctz64(U64 mask) +{ + unsigned long idx; + _BitScanForward64(&idx, mask); + return idx; +} + +internal U64 +clz32(U32 mask) +{ + unsigned long idx; + _BitScanReverse(&idx, mask); + return 31 - idx; +} + +internal U64 +clz64(U64 mask) +{ + unsigned long idx; + _BitScanReverse64(&idx, mask); + return 63 - idx; +} + +#elif COMPILER_CLANG || COMPILER_GCC + +internal U64 +count_bits_set16(U16 val) +{ + NotImplemented; + return 0; +} + +internal U64 +count_bits_set32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +count_bits_set64(U64 val) +{ + NotImplemented; + return 0; +} + +internal U64 +ctz32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +clz32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +clz64(U64 val) +{ + NotImplemented; + return 0; +} + +#else +# error "bits not defined for this target" +#endif + diff --git a/src/metagen/metagen_base/metagen_base_bits.h b/src/metagen/metagen_base/metagen_base_bits.h new file mode 100644 index 00000000..ab9482d3 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_bits.h @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_BITS_H +#define BASE_BITS_H + +#define ExtractBit(word, idx) (((word) >> (idx)) & 1) + +internal U64 count_bits_set16(U16 val); +internal U64 count_bits_set32(U32 val); +internal U64 count_bits_set64(U64 val); + +internal U64 ctz32(U32 val); +internal U64 ctz64(U64 val); +internal U64 clz32(U32 val); +internal U64 clz64(U64 val); + +#endif // BASE_BITS_H diff --git a/src/metagen/metagen_base/metagen_base_command_line.c b/src/metagen/metagen_base/metagen_base_command_line.c new file mode 100644 index 00000000..2a40b5c8 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_command_line.c @@ -0,0 +1,229 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ NOTE(rjf): Command Line Option Parsing + +internal U64 +cmd_line_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal CmdLineOpt ** +cmd_line_slot_from_string(CmdLine *cmd_line, String8 string) +{ + CmdLineOpt **slot = 0; + if(cmd_line->option_table_size != 0) + { + U64 hash = cmd_line_hash_from_string(string); + U64 bucket = hash % cmd_line->option_table_size; + slot = &cmd_line->option_table[bucket]; + } + return slot; +} + +internal CmdLineOpt * +cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string) +{ + CmdLineOpt *result = 0; + for(CmdLineOpt *var = *slot; var; var = var->hash_next) + { + if(str8_match(string, var->string, 0)) + { + result = var; + break; + } + } + return result; +} + +internal void +cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var) +{ + SLLQueuePush(list->first, list->last, var); + list->count += 1; +} + +internal CmdLineOpt * +cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values) +{ + CmdLineOpt *var = 0; + CmdLineOpt **slot = cmd_line_slot_from_string(cmd_line, string); + CmdLineOpt *existing_var = cmd_line_opt_from_slot(slot, string); + if(existing_var != 0) + { + var = existing_var; + } + else + { + var = push_array(arena, CmdLineOpt, 1); + var->hash_next = *slot; + var->hash = cmd_line_hash_from_string(string); + var->string = push_str8_copy(arena, string); + var->value_strings = values; + StringJoin join = {0}; + join.pre = str8_lit(""); + join.sep = str8_lit(","); + join.post = str8_lit(""); + var->value_string = str8_list_join(arena, &var->value_strings, &join); + *slot = var; + cmd_line_push_opt(&cmd_line->options, var); + } + return var; +} + +internal CmdLine +cmd_line_from_string_list(Arena *arena, String8List command_line) +{ + CmdLine parsed = {0}; + + // NOTE(rjf): Set up config option table. + { + parsed.option_table_size = 4096; + parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size); + } + + // NOTE(rjf): Parse command line. + B32 after_passthrough_option = 0; + for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next) + { + next = node->next; + String8 option_name = node->string; + + // NOTE(rjf): Look at -- or - at the start of an argument to determine if it's + // a flag option. All arguments after a single "--" (with no trailing string + // on the command line will be considered as input files. + B32 is_option = 1; + if(after_passthrough_option == 0) + { + if(str8_match(node->string, str8_lit("--"), 0)) + { + after_passthrough_option = 1; + is_option = 0; + } + else if(str8_match(str8_prefix(node->string, 2), str8_lit("--"), 0)) + { + option_name = str8_skip(option_name, 2); + } + else if(str8_match(str8_prefix(node->string, 1), str8_lit("-"), 0)) + { + option_name = str8_skip(option_name, 1); + } + else + { + is_option = 0; + } + } + else + { + is_option = 0; + } + + // NOTE(rjf): This string is an option. + if(is_option) + { + B32 has_arguments = 0; + U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0); + U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0); + U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2); + String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1); + if(arg_signifier_position < option_name.size) + { + has_arguments = 1; + } + option_name = str8_prefix(option_name, arg_signifier_position); + + String8List arguments = {0}; + + // NOTE(rjf): Parse arguments. + if(has_arguments) + { + for(String8Node *n = node; n; n = n->next) + { + next = n->next; + + String8 string = n->string; + if(n == node) + { + string = arg_portion_this_string; + } + + U8 splits[] = { ',' }; + String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0); + for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next) + { + str8_list_push(arena, &arguments, sub_arg->string); + } + if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) && + (n != node || arg_portion_this_string.size != 0)) + { + break; + } + } + } + + // NOTE(rjf): Register config variable. + cmd_line_insert_opt(arena, &parsed, option_name, arguments); + } + + // NOTE(rjf): Default path, treat as a passthrough config option to be + // handled by tool-specific code. + else if(!str8_match(node->string, str8_lit("--"), 0)) + { + str8_list_push(arena, &parsed.inputs, node->string); + after_passthrough_option = 1; + } + } + + return parsed; +} + +internal CmdLineOpt * +cmd_line_opt_from_string(CmdLine *cmd_line, String8 name) +{ + return cmd_line_opt_from_slot(cmd_line_slot_from_string(cmd_line, name), name); +} + +internal String8List +cmd_line_strings(CmdLine *cmd_line, String8 name) +{ + String8List result = {0}; + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + if(var != 0) + { + result = var->value_strings; + } + return result; +} + +internal String8 +cmd_line_string(CmdLine *cmd_line, String8 name) +{ + String8 result = {0}; + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + if(var != 0) + { + result = var->value_string; + } + return result; +} + +internal B32 +cmd_line_has_flag(CmdLine *cmd_line, String8 name) +{ + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + return(var != 0); +} + +internal B32 +cmd_line_has_argument(CmdLine *cmd_line, String8 name) +{ + CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name); + return(var != 0 && var->value_strings.node_count > 0); +} diff --git a/src/metagen/metagen_base/metagen_base_command_line.h b/src/metagen/metagen_base/metagen_base_command_line.h new file mode 100644 index 00000000..bfbc35ef --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_command_line.h @@ -0,0 +1,53 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_COMMAND_LINE_H +#define BASE_COMMAND_LINE_H + +//////////////////////////////// +//~ rjf: Parsed Command Line Types + +typedef struct CmdLineOpt CmdLineOpt; +struct CmdLineOpt +{ + CmdLineOpt *next; + CmdLineOpt *hash_next; + U64 hash; + String8 string; + String8List value_strings; + String8 value_string; +}; + +typedef struct CmdLineOptList CmdLineOptList; +struct CmdLineOptList +{ + U64 count; + CmdLineOpt *first; + CmdLineOpt *last; +}; + +typedef struct CmdLine CmdLine; +struct CmdLine +{ + CmdLineOptList options; + String8List inputs; + U64 option_table_size; + CmdLineOpt **option_table; +}; + +//////////////////////////////// +//~ NOTE(rjf): Command Line Option Parsing + +internal U64 cmd_line_hash_from_string(String8 string); +internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string); +internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string); +internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var); +internal CmdLineOpt* cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List values); +internal CmdLine cmd_line_from_string_list(Arena *arena, String8List arguments); +internal CmdLineOpt* cmd_line_opt_from_string(CmdLine *cmd_line, String8 name); +internal String8List cmd_line_strings(CmdLine *cmd_line, String8 name); +internal String8 cmd_line_string(CmdLine *cmd_line, String8 name); +internal B32 cmd_line_has_flag(CmdLine *cmd_line, String8 name); +internal B32 cmd_line_has_argument(CmdLine *cmd_line, String8 name); + +#endif // BASE_COMMAND_LINE_H diff --git a/src/metagen/metagen_base/metagen_base_context_cracking.h b/src/metagen/metagen_base/metagen_base_context_cracking.h new file mode 100644 index 00000000..65f49e7b --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_context_cracking.h @@ -0,0 +1,144 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_CONTEXT_CRACKING_H +#define BASE_CONTEXT_CRACKING_H + +#if defined(__clang__) + +# define COMPILER_CLANG 1 + +# if defined(_WIN32) +# define OS_WINDOWS 1 +# elif defined(__gnu_linux__) || defined(__linux__) +# define OS_LINUX 1 +# elif defined(__APPLE__) && defined(__MACH__) +# define OS_MAC 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) +# define ARCH_X64 1 +# elif defined(i386) || defined(__i386) || defined(__i386__) +# define ARCH_X86 1 +# elif defined(__aarch64__) +# define ARCH_ARM64 1 +# elif defined(__arm__) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + +#elif defined(_MSC_VER) + +# define COMPILER_CL 1 + +# if defined(_WIN32) +# define OS_WINDOWS 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(_M_AMD64) +# define ARCH_X64 1 +# elif defined(_M_IX86) +# define ARCH_X86 1 +# elif defined(_M_ARM64) +# define ARCH_ARM64 1 +# elif defined(_M_ARM) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) + +# define COMPILER_GCC 1 + +# if defined(__gnu_linux__) || defined(__linux__) +# define OS_LINUX 1 +# else +# error This compiler/platform combo is not supported yet +# endif + +# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) +# define ARCH_X64 1 +# elif defined(i386) || defined(__i386) || defined(__i386__) +# define ARCH_X86 1 +# elif defined(__aarch64__) +# define ARCH_ARM64 1 +# elif defined(__arm__) +# define ARCH_ARM32 1 +# else +# error architecture not supported yet +# endif + +#else +# error This compiler is not supported yet +#endif + +#if defined(ARCH_X64) +# define ARCH_64BIT 1 +#elif defined(ARCH_X86) +# define ARCH_32BIT 1 +#endif + +#if defined(__cplusplus) +# define LANG_CPP 1 +#else +# define LANG_C 1 +#endif + +// zeroify + +#if !defined(ARCH_32BIT) +# define ARCH_32BIT 0 +#endif +#if !defined(ARCH_64BIT) +# define ARCH_64BIT 0 +#endif +#if !defined(ARCH_X64) +# define ARCH_X64 0 +#endif +#if !defined(ARCH_X86) +# define ARCH_X86 0 +#endif +#if !defined(ARCH_ARM64) +# define ARCH_ARM64 0 +#endif +#if !defined(ARCH_ARM32) +# define ARCH_ARM32 0 +#endif +#if !defined(COMPILER_CL) +# define COMPILER_CL 0 +#endif +#if !defined(COMPILER_GCC) +# define COMPILER_GCC 0 +#endif +#if !defined(COMPILER_CLANG) +# define COMPILER_CLANG 0 +#endif +#if !defined(OS_WINDOWS) +# define OS_WINDOWS 0 +#endif +#if !defined(OS_LINUX) +# define OS_LINUX 0 +#endif +#if !defined(OS_MAC) +# define OS_MAC 0 +#endif +#if !defined(LANG_CPP) +# define LANG_CPP 0 +#endif +#if !defined(LANG_C) +# define LANG_C 0 +#endif + +#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86 +# define ARCH_LITTLE_ENDIAN 1 +#else +# error Endianness of this architecture not understood by context cracker +#endif + +#endif // BASE_CONTEXT_CRACKING_H diff --git a/src/metagen/metagen_base/metagen_base_inc.c b/src/metagen/metagen_base/metagen_base_inc.c new file mode 100644 index 00000000..ba36ca9d --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_inc.c @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Base Includes + +#undef RADDBG_LAYER_COLOR +#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f + +#include "metagen_base_types.c" +#include "metagen_base_markup.c" +#include "metagen_base_arena.c" +#include "metagen_base_math.c" +#include "metagen_base_string.c" +#include "metagen_base_thread_context.c" +#include "metagen_base_command_line.c" +#include "metagen_base_arena_dev.c" +#include "metagen_base_bits.c" diff --git a/src/metagen/metagen_base/metagen_base_inc.h b/src/metagen/metagen_base/metagen_base_inc.h new file mode 100644 index 00000000..27a51e5c --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_inc.h @@ -0,0 +1,23 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_INC_H +#define BASE_INC_H + +//////////////////////////////// +//~ rjf: Base Includes + +#include "metagen_base_context_cracking.h" +#include "metagen_base_types.h" +#include "metagen_base_markup.h" +#include "metagen_base_ins.h" +#include "metagen_base_linked_lists.h" +#include "metagen_base_arena.h" +#include "metagen_base_math.h" +#include "metagen_base_string.h" +#include "metagen_base_thread_context.h" +#include "metagen_base_command_line.h" +#include "metagen_base_arena_dev.h" +#include "metagen_base_bits.h" + +#endif // BASE_INC_H diff --git a/src/metagen/metagen_base/metagen_base_ins.h b/src/metagen/metagen_base/metagen_base_ins.h new file mode 100644 index 00000000..9f8d3202 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_ins.h @@ -0,0 +1,52 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_INS_H +#define BASE_INS_H + +//////////////////////////////// +// NOTE(allen): Implementations of Intrinsics + +#if OS_WINDOWS + +# include +# include +# include +# include + +# if ARCH_X64 +# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(x), 0) +# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x)) +# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x)) +# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c)) +# define ins_atomic_u64_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c) +# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c)) +# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c)) +# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c)) +# endif + +#elif OS_LINUX + +# if ARCH_X64 +# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1) +# endif + +#else +// TODO(allen): +#endif + +//////////////////////////////// +// NOTE(allen): Intrinsic Checks + +#if ARCH_X64 + +# if !defined(ins_atomic_u64_inc_eval) +# error missing: ins_atomic_u64_inc_eval +# endif + +#else +# error the intrinsic set for this arch is not developed +#endif + + +#endif //BASE_INS_H diff --git a/src/metagen/metagen_base/metagen_base_linked_lists.h b/src/metagen/metagen_base/metagen_base_linked_lists.h new file mode 100644 index 00000000..436cedc5 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_linked_lists.h @@ -0,0 +1,73 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_LINKED_LIST_H +#define BASE_LINKED_LIST_H + +//////////////////////////////// +//~ rjf: Helpers + +#define CheckNil(nil,p) ((p) == 0 || (p) == nil) +#define SetNil(nil,p) ((p) = nil) + +//////////////////////////////// +//~ rjf: Base Macros + +//- rjf: Base Doubly-Linked-List Macros +#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \ +((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\ +CheckNil(nil,p) ? \ +((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\ +((p)==(l)) ? \ +((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\ +(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p)))) +#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev) +#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next) +#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\ +((n) == (l) ? (l) = (l)->prev : (0)),\ +(CheckNil(nil,(n)->prev) ? (0) :\ +((n)->prev->next = (n)->next)),\ +(CheckNil(nil,(n)->next) ? (0) :\ +((n)->next->prev = (n)->prev))) + +//- rjf: Base Singly-Linked-List Queue Macros +#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ +((f)=(l)=(n),SetNil(nil,(n)->next)):\ +((l)->next=(n),(l)=(n),SetNil(nil,(n)->next))) +#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ +((f)=(l)=(n),SetNil(nil,(n)->next)):\ +((n)->next=(f),(f)=(n))) +#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\ +(SetNil(nil,f),SetNil(nil,l)):\ +((f)=(f)->next)) + +//- rjf: Base Singly-Linked-List Stack Macros +#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) +#define SLLStackPop_N(f,next) ((f)=(f)->next) + +//////////////////////////////// +//~ rjf: Convenience Wrappers + +//- rjf: Doubly-Linked-List Wrappers +#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev) +#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev) +#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev) +#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev) +#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev) +#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev) + +//- rjf: Singly-Linked-List Queue Wrappers +#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next) +#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next) +#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next) +#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next) +#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next) +#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next) + +//- rjf: Singly-Linked-List Stack Wrappers +#define SLLStackPush(f,n) SLLStackPush_N(f,n,next) +#define SLLStackPop(f) SLLStackPop_N(f,next) + +#endif //BASE_LINKED_LIST_H diff --git a/src/metagen/metagen_base/metagen_base_markup.c b/src/metagen/metagen_base/metagen_base_markup.c new file mode 100644 index 00000000..7ea8904c --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_markup.c @@ -0,0 +1,2 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) diff --git a/src/metagen/metagen_base/metagen_base_markup.h b/src/metagen/metagen_base/metagen_base_markup.h new file mode 100644 index 00000000..03c1adab --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_markup.h @@ -0,0 +1,79 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_MARKUP_H +#define BASE_MARKUP_H + +//////////////////////////////// +//~ rjf: Zero Settings + +#if !defined(PROFILE_TELEMETRY) +# define PROFILE_TELEMETRY 0 +#endif + +#if !defined(MARKUP_LAYER_COLOR) +# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f +#endif + +//////////////////////////////// +//~ rjf: Third Party Includes + +#if PROFILE_TELEMETRY +# include "rad_tm.h" +# if OS_WINDOWS +# pragma comment(lib, "rad_tm_win64.lib") +# endif +#endif + +//////////////////////////////// +//~ rjf: Telemetry Profile Defines + +#if PROFILE_TELEMETRY +# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__) +# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) +# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0) +# define ProfTick(...) tmTick(0) +# define ProfIsCapturing(...) tmRunning() +# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100) +# define ProfEndCapture(...) tmClose(0) +# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0) +# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) +# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__) +# define ProfEndLockWait(...) tmEndWaitForLock(0) +# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__) +# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) +# define ProfColor(color) tmZoneColorSticky(color) +#endif + +//////////////////////////////// +//~ rjf: Zeroify Undefined Defines + +#if !defined(ProfBegin) +# define ProfBegin(...) (0) +# define ProfBeginDynamic(...) (0) +# define ProfEnd(...) (0) +# define ProfTick(...) (0) +# define ProfIsCapturing(...) (0) +# define ProfBeginCapture(...) (0) +# define ProfEndCapture(...) (0) +# define ProfThreadName(...) (0) +# define ProfMsg(...) (0) +# define ProfBeginLockWait(...) (0) +# define ProfEndLockWait(...) (0) +# define ProfLockTake(...) (0) +# define ProfLockDrop(...) (0) +# define ProfColor(...) (0) +#endif + +//////////////////////////////// +//~ rjf: Helper Wrappers + +#define ProfBeginFunction(...) ProfBegin(this_function_name) +#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd()) + +//////////////////////////////// +//~ rjf: General Markup + +#define ThreadName(...) (ProfThreadName(__VA_ARGS__)) + +#endif // BASE_MARKUP_H diff --git a/src/metagen/metagen_base/metagen_base_math.c b/src/metagen/metagen_base/metagen_base_math.c new file mode 100644 index 00000000..0ddf662f --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_math.c @@ -0,0 +1,607 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Scalar Ops + +internal F32 +mix_1f32(F32 a, F32 b, F32 t) +{ + F32 c = (a + (b-a) * Clamp(0.f, t, 1.f)); + return c; +} + +internal F64 +mix_1f64(F64 a, F64 b, F64 t) +{ + F64 c = (a + (b-a) * Clamp(0.0, t, 1.0)); + return c; +} + +//////////////////////////////// +//~ rjf: Vector Ops + +internal Vec2F32 vec_2f32(F32 x, F32 y) {Vec2F32 v = {x, y}; return v;} +internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x+b.x, a.y+b.y}; return c;} +internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x-b.x, a.y-b.y}; return c;} +internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x*b.x, a.y*b.y}; return c;} +internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b) {Vec2F32 c = {a.x/b.x, a.y/b.y}; return c;} +internal Vec2F32 scale_2f32(Vec2F32 v, F32 s) {Vec2F32 c = {v.x*s, v.y*s}; return c;} +internal F32 dot_2f32(Vec2F32 a, Vec2F32 b) {F32 c = a.x*b.x + a.y*b.y; return c;} +internal F32 length_squared_2f32(Vec2F32 v) {F32 c = v.x*v.x + v.y*v.y; return c;} +internal F32 length_2f32(Vec2F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y); return c;} +internal Vec2F32 normalize_2f32(Vec2F32 v) {v = scale_2f32(v, 1.f/length_2f32(v)); return v;} +internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t) {Vec2F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t)}; return c;} + +internal Vec2S64 vec_2s64(S64 x, S64 y) {Vec2S64 v = {x, y}; return v;} +internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x+b.x, a.y+b.y}; return c;} +internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x-b.x, a.y-b.y}; return c;} +internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x*b.x, a.y*b.y}; return c;} +internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b) {Vec2S64 c = {a.x/b.x, a.y/b.y}; return c;} +internal Vec2S64 scale_2s64(Vec2S64 v, S64 s) {Vec2S64 c = {v.x*s, v.y*s}; return c;} +internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;} +internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;} +internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;} +internal Vec2S64 normalize_2s64(Vec2S64 v) {v = scale_2s64(v, (S64)(1.f/length_2s64(v))); return v;} +internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} + +internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;} +internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x+b.x, a.y+b.y}; return c;} +internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x-b.x, a.y-b.y}; return c;} +internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x*b.x, a.y*b.y}; return c;} +internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b) {Vec2S32 c = {a.x/b.x, a.y/b.y}; return c;} +internal Vec2S32 scale_2s32(Vec2S32 v, S32 s) {Vec2S32 c = {v.x*s, v.y*s}; return c;} +internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;} +internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;} +internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;} +internal Vec2S32 normalize_2s32(Vec2S32 v) {v = scale_2s32(v, (S32)(1.f/length_2s32(v))); return v;} +internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} + +internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;} +internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x+b.x), (S16)(a.y+b.y)}; return c;} +internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x-b.x), (S16)(a.y-b.y)}; return c;} +internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x*b.x), (S16)(a.y*b.y)}; return c;} +internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b) {Vec2S16 c = {(S16)(a.x/b.x), (S16)(a.y/b.y)}; return c;} +internal Vec2S16 scale_2s16(Vec2S16 v, S16 s) {Vec2S16 c = {(S16)(v.x*s), (S16)(v.y*s)}; return c;} +internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;} +internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;} +internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;} +internal Vec2S16 normalize_2s16(Vec2S16 v) {v = scale_2s16(v, (S16)(1.f/length_2s16(v))); return v;} +internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} + +internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;} +internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;} +internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x-b.x, a.y-b.y, a.z-b.z}; return c;} +internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x*b.x, a.y*b.y, a.z*b.z}; return c;} +internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.x/b.x, a.y/b.y, a.z/b.z}; return c;} +internal Vec3F32 scale_3f32(Vec3F32 v, F32 s) {Vec3F32 c = {v.x*s, v.y*s, v.z*s}; return c;} +internal F32 dot_3f32(Vec3F32 a, Vec3F32 b) {F32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;} +internal F32 length_squared_3f32(Vec3F32 v) {F32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;} +internal F32 length_3f32(Vec3F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y + v.z*v.z); return c;} +internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;} +internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;} +internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;} + +internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;} +internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;} +internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x-b.x, a.y-b.y, a.z-b.z}; return c;} +internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x*b.x, a.y*b.y, a.z*b.z}; return c;} +internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x/b.x, a.y/b.y, a.z/b.z}; return c;} +internal Vec3S32 scale_3s32(Vec3S32 v, S32 s) {Vec3S32 c = {v.x*s, v.y*s, v.z*s}; return c;} +internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;} +internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;} +internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;} +internal Vec3S32 normalize_3s32(Vec3S32 v) {v = scale_3s32(v, (S32)(1.f/length_3s32(v))); return v;} +internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;} +internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;} + +internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w) {Vec4F32 v = {x, y, z, w}; return v;} +internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w}; return c;} +internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w}; return c;} +internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return c;} +internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b) {Vec4F32 c = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return c;} +internal Vec4F32 scale_4f32(Vec4F32 v, F32 s) {Vec4F32 c = {v.x*s, v.y*s, v.z*s, v.w*s}; return c;} +internal F32 dot_4f32(Vec4F32 a, Vec4F32 b) {F32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;} +internal F32 length_squared_4f32(Vec4F32 v) {F32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;} +internal F32 length_4f32(Vec4F32 v) {F32 c = sqrt_f32(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w); return c;} +internal Vec4F32 normalize_4f32(Vec4F32 v) {v = scale_4f32(v, 1.f/length_4f32(v)); return v;} +internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t) {Vec4F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t), mix_1f32(a.w, b.w, t)}; return c;} + +internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w) {Vec4S32 v = {x, y, z, w}; return v;} +internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w}; return c;} +internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w}; return c;} +internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w}; return c;} +internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b) {Vec4S32 c = {a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w}; return c;} +internal Vec4S32 scale_4s32(Vec4S32 v, S32 s) {Vec4S32 c = {v.x*s, v.y*s, v.z*s, v.w*s}; return c;} +internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;} +internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;} +internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;} +internal Vec4S32 normalize_4s32(Vec4S32 v) {v = scale_4s32(v, (S32)(1.f/length_4s32(v))); return v;} +internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;} + +//////////////////////////////// +//~ rjf: Matrix Ops + +internal Mat3x3F32 +mat_3x3f32(F32 diagonal) +{ + Mat3x3F32 result = {0}; + result.v[0][0] = diagonal; + result.v[1][1] = diagonal; + result.v[2][2] = diagonal; + return result; +} + +internal Mat3x3F32 +make_translate_3x3f32(Vec2F32 delta) +{ + Mat3x3F32 mat = mat_3x3f32(1.f); + mat.v[2][0] = delta.x; + mat.v[2][1] = delta.y; + return mat; +} + +internal Mat3x3F32 +mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b) +{ + Mat3x3F32 c = {0}; + for(int j = 0; j < 3; j += 1) + { + for(int i = 0; i < 3; i += 1) + { + c.v[i][j] = (a.v[0][j]*b.v[i][0] + + a.v[1][j]*b.v[i][1] + + a.v[2][j]*b.v[i][2]); + } + } + return c; +} + +internal Mat4x4F32 +mat_4x4f32(F32 diagonal) +{ + Mat4x4F32 result = {0}; + result.v[0][0] = diagonal; + result.v[1][1] = diagonal; + result.v[2][2] = diagonal; + result.v[3][3] = diagonal; + return result; +} + +internal Mat4x4F32 +make_translate_4x4f32(Vec3F32 delta) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + result.v[3][0] = delta.x; + result.v[3][1] = delta.y; + result.v[3][2] = delta.z; + return result; +} + +internal Mat4x4F32 +make_scale_4x4f32(Vec3F32 scale) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + result.v[0][0] = scale.x; + result.v[1][1] = scale.y; + result.v[2][2] = scale.z; + return result; +} + +internal Mat4x4F32 +make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + F32 tan_theta_over_2 = tan_f32(fov / 2); + result.v[0][0] = 1.f / tan_theta_over_2; + result.v[1][1] = aspect_ratio / tan_theta_over_2; + result.v[2][3] = 1.f; + result.v[2][2] = -(near_z + far_z) / (near_z - far_z); + result.v[3][2] = (2.f * near_z * far_z) / (near_z - far_z); + result.v[3][3] = 0.f; + return result; +} + +internal Mat4x4F32 +make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + + result.v[0][0] = 2.f / (right - left); + result.v[1][1] = 2.f / (top - bottom); + result.v[2][2] = 2.f / (far_z - near_z); + result.v[3][3] = 1.f; + + result.v[3][0] = (left + right) / (left - right); + result.v[3][1] = (bottom + top) / (bottom - top); + result.v[3][2] = (near_z + far_z) / (near_z - far_z); + + return result; +} + +internal Mat4x4F32 +make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up) +{ + Mat4x4F32 result; + Vec3F32 f = normalize_3f32(sub_3f32(eye, center)); + Vec3F32 s = normalize_3f32(cross_3f32(f, up)); + Vec3F32 u = cross_3f32(s, f); + result.v[0][0] = s.x; + result.v[0][1] = u.x; + result.v[0][2] = -f.x; + result.v[0][3] = 0.0f; + result.v[1][0] = s.y; + result.v[1][1] = u.y; + result.v[1][2] = -f.y; + result.v[1][3] = 0.0f; + result.v[2][0] = s.z; + result.v[2][1] = u.z; + result.v[2][2] = -f.z; + result.v[2][3] = 0.0f; + result.v[3][0] = -dot_3f32(s, eye); + result.v[3][1] = -dot_3f32(u, eye); + result.v[3][2] = dot_3f32(f, eye); + result.v[3][3] = 1.0f; + return result; +} + +internal Mat4x4F32 +make_rotate_4x4f32(Vec3F32 axis, F32 turns) +{ + Mat4x4F32 result = mat_4x4f32(1.f); + axis = normalize_3f32(axis); + F32 sin_theta = sin_f32(turns); + F32 cos_theta = cos_f32(turns); + F32 cos_value = 1.f - cos_theta; + result.v[0][0] = (axis.x * axis.x * cos_value) + cos_theta; + result.v[0][1] = (axis.x * axis.y * cos_value) + (axis.z * sin_theta); + result.v[0][2] = (axis.x * axis.z * cos_value) - (axis.y * sin_theta); + result.v[1][0] = (axis.y * axis.x * cos_value) - (axis.z * sin_theta); + result.v[1][1] = (axis.y * axis.y * cos_value) + cos_theta; + result.v[1][2] = (axis.y * axis.z * cos_value) + (axis.x * sin_theta); + result.v[2][0] = (axis.z * axis.x * cos_value) + (axis.y * sin_theta); + result.v[2][1] = (axis.z * axis.y * cos_value) - (axis.x * sin_theta); + result.v[2][2] = (axis.z * axis.z * cos_value) + cos_theta; + return result; +} + +internal Mat4x4F32 +mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b) +{ + Mat4x4F32 c = {0}; + for(int j = 0; j < 4; j += 1) + { + for(int i = 0; i < 4; i += 1) + { + c.v[i][j] = (a.v[0][j]*b.v[i][0] + + a.v[1][j]*b.v[i][1] + + a.v[2][j]*b.v[i][2] + + a.v[3][j]*b.v[i][3]); + } + } + return c; +} + +internal Mat4x4F32 +scale_4x4f32(Mat4x4F32 m, F32 scale) +{ + for(int j = 0; j < 4; j += 1) + { + for(int i = 0; i < 4; i += 1) + { + m.v[i][j] *= scale; + } + } + return m; +} + +internal Mat4x4F32 +inverse_4x4f32(Mat4x4F32 m) +{ + F32 coef00 = m.v[2][2] * m.v[3][3] - m.v[3][2] * m.v[2][3]; + F32 coef02 = m.v[1][2] * m.v[3][3] - m.v[3][2] * m.v[1][3]; + F32 coef03 = m.v[1][2] * m.v[2][3] - m.v[2][2] * m.v[1][3]; + F32 coef04 = m.v[2][1] * m.v[3][3] - m.v[3][1] * m.v[2][3]; + F32 coef06 = m.v[1][1] * m.v[3][3] - m.v[3][1] * m.v[1][3]; + F32 coef07 = m.v[1][1] * m.v[2][3] - m.v[2][1] * m.v[1][3]; + F32 coef08 = m.v[2][1] * m.v[3][2] - m.v[3][1] * m.v[2][2]; + F32 coef10 = m.v[1][1] * m.v[3][2] - m.v[3][1] * m.v[1][2]; + F32 coef11 = m.v[1][1] * m.v[2][2] - m.v[2][1] * m.v[1][2]; + F32 coef12 = m.v[2][0] * m.v[3][3] - m.v[3][0] * m.v[2][3]; + F32 coef14 = m.v[1][0] * m.v[3][3] - m.v[3][0] * m.v[1][3]; + F32 coef15 = m.v[1][0] * m.v[2][3] - m.v[2][0] * m.v[1][3]; + F32 coef16 = m.v[2][0] * m.v[3][2] - m.v[3][0] * m.v[2][2]; + F32 coef18 = m.v[1][0] * m.v[3][2] - m.v[3][0] * m.v[1][2]; + F32 coef19 = m.v[1][0] * m.v[2][2] - m.v[2][0] * m.v[1][2]; + F32 coef20 = m.v[2][0] * m.v[3][1] - m.v[3][0] * m.v[2][1]; + F32 coef22 = m.v[1][0] * m.v[3][1] - m.v[3][0] * m.v[1][1]; + F32 coef23 = m.v[1][0] * m.v[2][1] - m.v[2][0] * m.v[1][1]; + + Vec4F32 fac0 = { coef00, coef00, coef02, coef03 }; + Vec4F32 fac1 = { coef04, coef04, coef06, coef07 }; + Vec4F32 fac2 = { coef08, coef08, coef10, coef11 }; + Vec4F32 fac3 = { coef12, coef12, coef14, coef15 }; + Vec4F32 fac4 = { coef16, coef16, coef18, coef19 }; + Vec4F32 fac5 = { coef20, coef20, coef22, coef23 }; + + Vec4F32 vec0 = { m.v[1][0], m.v[0][0], m.v[0][0], m.v[0][0] }; + Vec4F32 vec1 = { m.v[1][1], m.v[0][1], m.v[0][1], m.v[0][1] }; + Vec4F32 vec2 = { m.v[1][2], m.v[0][2], m.v[0][2], m.v[0][2] }; + Vec4F32 vec3 = { m.v[1][3], m.v[0][3], m.v[0][3], m.v[0][3] }; + + Vec4F32 inv0 = add_4f32(sub_4f32(mul_4f32(vec1, fac0), mul_4f32(vec2, fac1)), mul_4f32(vec3, fac2)); + Vec4F32 inv1 = add_4f32(sub_4f32(mul_4f32(vec0, fac0), mul_4f32(vec2, fac3)), mul_4f32(vec3, fac4)); + Vec4F32 inv2 = add_4f32(sub_4f32(mul_4f32(vec0, fac1), mul_4f32(vec1, fac3)), mul_4f32(vec3, fac5)); + Vec4F32 inv3 = add_4f32(sub_4f32(mul_4f32(vec0, fac2), mul_4f32(vec1, fac4)), mul_4f32(vec2, fac5)); + + Vec4F32 sign_a = { +1, -1, +1, -1 }; + Vec4F32 sign_b = { -1, +1, -1, +1 }; + + Mat4x4F32 inverse; + for(U32 i = 0; i < 4; i += 1) + { + inverse.v[0][i] = inv0.v[i] * sign_a.v[i]; + inverse.v[1][i] = inv1.v[i] * sign_b.v[i]; + inverse.v[2][i] = inv2.v[i] * sign_a.v[i]; + inverse.v[3][i] = inv3.v[i] * sign_b.v[i]; + } + + Vec4F32 row0 = { inverse.v[0][0], inverse.v[1][0], inverse.v[2][0], inverse.v[3][0] }; + Vec4F32 m0 = { m.v[0][0], m.v[0][1], m.v[0][2], m.v[0][3] }; + Vec4F32 dot0 = mul_4f32(m0, row0); + F32 dot1 = (dot0.x + dot0.y) + (dot0.z + dot0.w); + + F32 one_over_det = 1 / dot1; + + return scale_4x4f32(inverse, one_over_det); +} + +internal Mat4x4F32 +derotate_4x4f32(Mat4x4F32 mat) +{ + Vec3F32 scale = + { + length_3f32(v3f32(mat.v[0][0], mat.v[0][1], mat.v[0][2])), + length_3f32(v3f32(mat.v[1][0], mat.v[1][1], mat.v[1][2])), + length_3f32(v3f32(mat.v[2][0], mat.v[2][1], mat.v[2][2])), + }; + mat.v[0][0] = scale.x; + mat.v[1][0] = 0.f; + mat.v[2][0] = 0.f; + mat.v[0][1] = 0.f; + mat.v[1][1] = scale.y; + mat.v[2][1] = 0.f; + mat.v[0][2] = 0.f; + mat.v[1][2] = 0.f; + mat.v[2][2] = scale.z; + return mat; +} + +//////////////////////////////// +//~ rjf: Range Ops + +internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;} +internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;} +internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;} +internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;} +internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal U32 dim_1u32(Rng1U32 r) {U32 c = r.max-r.min; return c;} +internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1S32 rng_1s32(S32 min, S32 max) {Rng1S32 r = {min, max}; if(r.min > r.max) { Swap(S32, r.min, r.max); } return r;} +internal Rng1S32 shift_1s32(Rng1S32 r, S32 x) {r.min += x; r.max += x; return r;} +internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;} +internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;} +internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal S32 dim_1s32(Rng1S32 r) {S32 c = r.max-r.min; return c;} +internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1U64 rng_1u64(U64 min, U64 max) {Rng1U64 r = {min, max}; if(r.min > r.max) { Swap(U64, r.min, r.max); } return r;} +internal Rng1U64 shift_1u64(Rng1U64 r, U64 x) {r.min += x; r.max += x; return r;} +internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;} +internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;} +internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal U64 dim_1u64(Rng1U64 r) {U64 c = r.max-r.min; return c;} +internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1S64 rng_1s64(S64 min, S64 max) {Rng1S64 r = {min, max}; if(r.min > r.max) { Swap(S64, r.min, r.max); } return r;} +internal Rng1S64 shift_1s64(Rng1S64 r, S64 x) {r.min += x; r.max += x; return r;} +internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;} +internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;} +internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal S64 dim_1s64(Rng1S64 r) {S64 c = r.max-r.min; return c;} +internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng1F32 rng_1f32(F32 min, F32 max) {Rng1F32 r = {min, max}; if(r.min > r.max) { Swap(F32, r.min, r.max); } return r;} +internal Rng1F32 shift_1f32(Rng1F32 r, F32 x) {r.min += x; r.max += x; return r;} +internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;} +internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;} +internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;} +internal F32 dim_1f32(Rng1F32 r) {F32 c = r.max-r.min; return c;} +internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} +internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} +internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;} + +internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max) {Rng2S16 r = {min, max}; return r;} +internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x) {r.min = add_2s16(r.min, x); r.max = add_2s16(r.max, x); return r;} +internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;} +internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;} +internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(r.max.x-r.min.x), (S16)(r.max.y-r.min.y)}; return dim;} +internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max) {Rng2S32 r = {min, max}; return r;} +internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x) {r.min = add_2s32(r.min, x); r.max = add_2s32(r.max, x); return r;} +internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;} +internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} +internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max) {Rng2S64 r = {min, max}; return r;} +internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x) {r.min = add_2s64(r.min, x); r.max = add_2s64(r.max, x); return r;} +internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;} +internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} +internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max) {Rng2F32 r = {min, max}; return r;} +internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x) {r.min = add_2f32(r.min, x); r.max = add_2f32(r.max, x); return r;} +internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;} +internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} +internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} +internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} +internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} +internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} + +//////////////////////////////// +//~ rjf: Miscellaneous Ops + +internal Vec3F32 +hsv_from_rgb(Vec3F32 rgb) +{ + F32 c_max = Max(rgb.x, Max(rgb.y, rgb.z)); + F32 c_min = Min(rgb.x, Min(rgb.y, rgb.z)); + F32 delta = c_max - c_min; + F32 h = ((delta == 0.f) ? 0.f : + (c_max == rgb.x) ? mod_f32((rgb.y - rgb.z)/delta + 6.f, 6.f) : + (c_max == rgb.y) ? (rgb.z - rgb.x)/delta + 2.f : + (c_max == rgb.z) ? (rgb.x - rgb.y)/delta + 4.f : + 0.f); + F32 s = (c_max == 0.f) ? 0.f : (delta/c_max); + F32 v = c_max; + Vec3F32 hsv = {h/6.f, s, v}; + return hsv; +} + +internal Vec3F32 +rgb_from_hsv(Vec3F32 hsv) +{ + F32 h = mod_f32(hsv.x * 360.f, 360.f); + F32 s = hsv.y; + F32 v = hsv.z; + + F32 c = v*s; + F32 x = c*(1.f - abs_f32(mod_f32(h/60.f, 2.f) - 1.f)); + F32 m = v - c; + + F32 r = 0; + F32 g = 0; + F32 b = 0; + + if ((h >= 0.f && h < 60.f) || (h >= 360.f && h < 420.f)){ + r = c; + g = x; + b = 0; + } + else if (h >= 60.f && h < 120.f){ + r = x; + g = c; + b = 0; + } + else if (h >= 120.f && h < 180.f){ + r = 0; + g = c; + b = x; + } + else if (h >= 180.f && h < 240.f){ + r = 0; + g = x; + b = c; + } + else if (h >= 240.f && h < 300.f){ + r = x; + g = 0; + b = c; + } + else if ((h >= 300.f && h <= 360.f) || (h >= -60.f && h <= 0.f)){ + r = c; + g = 0; + b = x; + } + + Vec3F32 rgb = {r + m, g + m, b + m}; + return(rgb); +} + +internal Vec4F32 +hsva_from_rgba(Vec4F32 rgba) +{ + Vec3F32 rgb = v3f32(rgba.x, rgba.y, rgba.z); + Vec3F32 hsv = hsv_from_rgb(rgb); + Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); + return hsva; +} + +internal Vec4F32 +rgba_from_hsva(Vec4F32 hsva) +{ + Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z); + Vec3F32 rgb = rgb_from_hsv(hsv); + Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, hsva.w); + return rgba; +} + +internal Vec4F32 +rgba_from_u32(U32 hex) +{ + Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f, + ((hex&0x00ff0000)>>16)/255.f, + ((hex&0x0000ff00)>> 8)/255.f, + ((hex&0x000000ff)>> 0)/255.f); + return result; +} + +internal U32 +u32_from_rgba(Vec4F32 rgba) +{ + U32 result = 0; + result |= ((U32)((U8)(rgba.x*255.f))) << 24; + result |= ((U32)((U8)(rgba.y*255.f))) << 16; + result |= ((U32)((U8)(rgba.z*255.f))) << 8; + result |= ((U32)((U8)(rgba.w*255.f))) << 0; + return result; +} + +//////////////////////////////// +//~ rjf: List Type Functions + +internal void +rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng) +{ + Rng1S64Node *n = push_array(arena, Rng1S64Node, 1); + MemoryCopyStruct(&n->v, &rng); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal Rng1S64Array +rng1s64_array_from_list(Arena *arena, Rng1S64List *list) +{ + Rng1S64Array arr = {0}; + arr.count = list->count; + arr.v = push_array_no_zero(arena, Rng1S64, arr.count); + U64 idx = 0; + for(Rng1S64Node *n = list->first; n != 0; n = n->next) + { + arr.v[idx] = n->v; + idx += 1; + } + return arr; +} diff --git a/src/metagen/metagen_base/metagen_base_math.h b/src/metagen/metagen_base/metagen_base_math.h new file mode 100644 index 00000000..b0c9d15d --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_math.h @@ -0,0 +1,648 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_MATH_H +#define BASE_MATH_H + +//////////////////////////////// +//~ rjf: Vector Types + +//- rjf: 2-vectors + +typedef union Vec2F32 Vec2F32; +union Vec2F32 +{ + struct + { + F32 x; + F32 y; + }; + F32 v[2]; +}; + +typedef union Vec2S64 Vec2S64; +union Vec2S64 +{ + struct + { + S64 x; + S64 y; + }; + S64 v[2]; +}; + +typedef union Vec2S32 Vec2S32; +union Vec2S32 +{ + struct + { + S32 x; + S32 y; + }; + S32 v[2]; +}; + +typedef union Vec2S16 Vec2S16; +union Vec2S16 +{ + struct + { + S16 x; + S16 y; + }; + S16 v[2]; +}; + +//- rjf: 3-vectors + +typedef union Vec3F32 Vec3F32; +union Vec3F32 +{ + struct + { + F32 x; + F32 y; + F32 z; + }; + struct + { + Vec2F32 xy; + F32 _z0; + }; + struct + { + F32 _x0; + Vec2F32 yz; + }; + F32 v[3]; +}; + +typedef union Vec3S32 Vec3S32; +union Vec3S32 +{ + struct + { + S32 x; + S32 y; + S32 z; + }; + struct + { + Vec2S32 xy; + S32 _z0; + }; + struct + { + S32 _x0; + Vec2S32 yz; + }; + S32 v[3]; +}; + +//- rjf: 4-vectors + +typedef union Vec4F32 Vec4F32; +union Vec4F32 +{ + struct + { + F32 x; + F32 y; + F32 z; + F32 w; + }; + struct + { + Vec2F32 xy; + Vec2F32 zw; + }; + struct + { + Vec3F32 xyz; + F32 _z0; + }; + struct + { + F32 _x0; + Vec3F32 yzw; + }; + F32 v[4]; +}; + +typedef union Vec4S32 Vec4S32; +union Vec4S32 +{ + struct + { + S32 x; + S32 y; + S32 z; + S32 w; + }; + struct + { + Vec2S32 xy; + Vec2S32 zw; + }; + struct + { + Vec3S32 xyz; + S32 _z0; + }; + struct + { + S32 _x0; + Vec3S32 yzw; + }; + S32 v[4]; +}; + +//////////////////////////////// +//~ rjf: Matrix Types + +typedef struct Mat3x3F32 Mat3x3F32; +struct Mat3x3F32 +{ + F32 v[3][3]; +}; + +typedef struct Mat4x4F32 Mat4x4F32; +struct Mat4x4F32 +{ + F32 v[4][4]; +}; + +//////////////////////////////// +//~ rjf: Range Types + +//- rjf: 1-range + +typedef union Rng1U32 Rng1U32; +union Rng1U32 +{ + struct + { + U32 min; + U32 max; + }; + U32 v[2]; +}; + +typedef union Rng1S32 Rng1S32; +union Rng1S32 +{ + struct + { + S32 min; + S32 max; + }; + S32 v[2]; +}; + +typedef union Rng1U64 Rng1U64; +union Rng1U64 +{ + struct + { + U64 min; + U64 max; + }; + U64 v[2]; +}; + +typedef union Rng1S64 Rng1S64; +union Rng1S64 +{ + struct + { + S64 min; + S64 max; + }; + S64 v[2]; +}; + +typedef union Rng1F32 Rng1F32; +union Rng1F32 +{ + struct + { + F32 min; + F32 max; + }; + F32 v[2]; +}; + +//- rjf: 2-range (rectangles) + +typedef union Rng2S16 Rng2S16; +union Rng2S16 +{ + struct + { + Vec2S16 min; + Vec2S16 max; + }; + struct + { + Vec2S16 p0; + Vec2S16 p1; + }; + struct + { + S16 x0; + S16 y0; + S16 x1; + S16 y1; + }; + Vec2S16 v[2]; +}; + +typedef union Rng2S32 Rng2S32; +union Rng2S32 +{ + struct + { + Vec2S32 min; + Vec2S32 max; + }; + struct + { + Vec2S32 p0; + Vec2S32 p1; + }; + struct + { + S32 x0; + S32 y0; + S32 x1; + S32 y1; + }; + Vec2S32 v[2]; +}; + +typedef union Rng2F32 Rng2F32; +union Rng2F32 +{ + struct + { + Vec2F32 min; + Vec2F32 max; + }; + struct + { + Vec2F32 p0; + Vec2F32 p1; + }; + struct + { + F32 x0; + F32 y0; + F32 x1; + F32 y1; + }; + Vec2F32 v[2]; +}; + +typedef union Rng2S64 Rng2S64; +union Rng2S64 +{ + struct + { + Vec2S64 min; + Vec2S64 max; + }; + struct + { + Vec2S64 p0; + Vec2S64 p1; + }; + struct + { + S64 x0; + S64 y0; + S64 x1; + S64 y1; + }; + Vec2S64 v[2]; +}; + +//////////////////////////////// +//~ rjf: List Types + +typedef struct Rng1S64Node Rng1S64Node; +struct Rng1S64Node +{ + Rng1S64Node *next; + Rng1S64 v; +}; + +typedef struct Rng1S64List Rng1S64List; +struct Rng1S64List +{ + Rng1S64Node *first; + Rng1S64Node *last; + U64 count; +}; + +typedef struct Rng1S64Array Rng1S64Array; +struct Rng1S64Array +{ + Rng1S64 *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Scalar Ops + +#define abs_s64(v) (S64)llabs(v) + +#define sqrt_f32(v) sqrtf(v) +#define mod_f32(a, b) fmodf((a), (b)) +#define pow_f32(b, e) powf((b), (e)) +#define ceil_f32(v) ceilf(v) +#define floor_f32(v) floorf(v) +#define round_f32(v) roundf(v) +#define abs_f32(v) fabsf(v) +#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f) +#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f) +#define degrees_from_turns_f32(v) ((v)*360.f) +#define turns_from_degrees_f32(v) ((v)/360.f) +#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v))) +#define radians_from_degrees_f32(v) (radians_from_turns_f32(turns_from_degrees_f32(v))) +#define sin_f32(v) sinf(radians_from_turns_f32(v)) +#define cos_f32(v) cosf(radians_from_turns_f32(v)) +#define tan_f32(v) tanf(radians_from_turns_f32(v)) + +#define sqrt_f64(v) sqrt(v) +#define mod_f64(a, b) fmod((a), (b)) +#define pow_f64(b, e) pow((b), (e)) +#define ceil_f64(v) ceil(v) +#define floor_f64(v) floor(v) +#define round_f64(v) round(v) +#define abs_f64(v) fabs(v) +#define radians_from_turns_f64(v) ((v)*2*3.1415926535897) +#define turns_from_radians_f64(v) ((v)/2*3.1415926535897) +#define degrees_from_turns_f64(v) ((v)*360.0) +#define turns_from_degrees_f64(v) ((v)/360.0) +#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v))) +#define radians_from_degrees_f64(v) (radians_from_turns_f64(turns_from_degrees_f64(v))) +#define sin_f64(v) sin(radians_from_turns_f64(v)) +#define cos_f64(v) cos(radians_from_turns_f64(v)) +#define tan_f64(v) tan(radians_from_turns_f64(v)) + +internal F32 mix_1f32(F32 a, F32 b, F32 t); +internal F64 mix_1f64(F64 a, F64 b, F64 t); + +//////////////////////////////// +//~ rjf: Vector Ops + +#define v2f32(x, y) vec_2f32((x), (y)) +internal Vec2F32 vec_2f32(F32 x, F32 y); +internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 scale_2f32(Vec2F32 v, F32 s); +internal F32 dot_2f32(Vec2F32 a, Vec2F32 b); +internal F32 length_squared_2f32(Vec2F32 v); +internal F32 length_2f32(Vec2F32 v); +internal Vec2F32 normalize_2f32(Vec2F32 v); +internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t); + +#define v2s64(x, y) vec_2s64((x), (y)) +internal Vec2S64 vec_2s64(S64 x, S64 y); +internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 scale_2s64(Vec2S64 v, S64 s); +internal S64 dot_2s64(Vec2S64 a, Vec2S64 b); +internal S64 length_squared_2s64(Vec2S64 v); +internal S64 length_2s64(Vec2S64 v); +internal Vec2S64 normalize_2s64(Vec2S64 v); +internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t); + +#define v2s32(x, y) vec_2s32((x), (y)) +internal Vec2S32 vec_2s32(S32 x, S32 y); +internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 scale_2s32(Vec2S32 v, S32 s); +internal S32 dot_2s32(Vec2S32 a, Vec2S32 b); +internal S32 length_squared_2s32(Vec2S32 v); +internal S32 length_2s32(Vec2S32 v); +internal Vec2S32 normalize_2s32(Vec2S32 v); +internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t); + +#define v2s16(x, y) vec_2s16((x), (y)) +internal Vec2S16 vec_2s16(S16 x, S16 y); +internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 scale_2s16(Vec2S16 v, S16 s); +internal S16 dot_2s16(Vec2S16 a, Vec2S16 b); +internal S16 length_squared_2s16(Vec2S16 v); +internal S16 length_2s16(Vec2S16 v); +internal Vec2S16 normalize_2s16(Vec2S16 v); +internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t); + +#define v3f32(x, y, z) vec_3f32((x), (y), (z)) +internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z); +internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 scale_3f32(Vec3F32 v, F32 s); +internal F32 dot_3f32(Vec3F32 a, Vec3F32 b); +internal F32 length_squared_3f32(Vec3F32 v); +internal F32 length_3f32(Vec3F32 v); +internal Vec3F32 normalize_3f32(Vec3F32 v); +internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t); +internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b); + +#define v3s32(x, y, z) vec_3s32((x), (y), (z)) +internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z); +internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 scale_3s32(Vec3S32 v, S32 s); +internal S32 dot_3s32(Vec3S32 a, Vec3S32 b); +internal S32 length_squared_3s32(Vec3S32 v); +internal S32 length_3s32(Vec3S32 v); +internal Vec3S32 normalize_3s32(Vec3S32 v); +internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t); +internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b); + +#define v4f32(x, y, z, w) vec_4f32((x), (y), (z), (w)) +internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w); +internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 scale_4f32(Vec4F32 v, F32 s); +internal F32 dot_4f32(Vec4F32 a, Vec4F32 b); +internal F32 length_squared_4f32(Vec4F32 v); +internal F32 length_4f32(Vec4F32 v); +internal Vec4F32 normalize_4f32(Vec4F32 v); +internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t); + +#define v4s32(x, y, z, w) vec_4s32((x), (y), (z), (w)) +internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w); +internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 scale_4s32(Vec4S32 v, S32 s); +internal S32 dot_4s32(Vec4S32 a, Vec4S32 b); +internal S32 length_squared_4s32(Vec4S32 v); +internal S32 length_4s32(Vec4S32 v); +internal Vec4S32 normalize_4s32(Vec4S32 v); +internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t); + +//////////////////////////////// +//~ rjf: Matrix Ops + +internal Mat3x3F32 mat_3x3f32(F32 diagonal); +internal Mat3x3F32 make_translate_3x3f32(Vec2F32 delta); +internal Mat3x3F32 mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b); + +internal Mat4x4F32 mat_4x4f32(F32 diagonal); +internal Mat4x4F32 make_translate_4x4f32(Vec3F32 delta); +internal Mat4x4F32 make_scale_4x4f32(Vec3F32 scale); +internal Mat4x4F32 make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z); +internal Mat4x4F32 make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z); +internal Mat4x4F32 make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up); +internal Mat4x4F32 make_rotate_4x4f32(Vec3F32 axis, F32 turns); +internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b); +internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale); +internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m); +internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat); + +//////////////////////////////// +//~ rjf: Range Ops + +#define r1u32(min, max) rng_1u32((min), (max)) +internal Rng1U32 rng_1u32(U32 min, U32 max); +internal Rng1U32 shift_1u32(Rng1U32 r, U32 x); +internal Rng1U32 pad_1u32(Rng1U32 r, U32 x); +internal U32 center_1u32(Rng1U32 r); +internal B32 contains_1u32(Rng1U32 r, U32 x); +internal U32 dim_1u32(Rng1U32 r); +internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b); +internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b); +internal U32 clamp_1u32(Rng1U32 r, U32 v); + +#define r1s32(min, max) rng_1s32((min), (max)) +internal Rng1S32 rng_1s32(S32 min, S32 max); +internal Rng1S32 shift_1s32(Rng1S32 r, S32 x); +internal Rng1S32 pad_1s32(Rng1S32 r, S32 x); +internal S32 center_1s32(Rng1S32 r); +internal B32 contains_1s32(Rng1S32 r, S32 x); +internal S32 dim_1s32(Rng1S32 r); +internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b); +internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b); +internal S32 clamp_1s32(Rng1S32 r, S32 v); + +#define r1u64(min, max) rng_1u64((min), (max)) +internal Rng1U64 rng_1u64(U64 min, U64 max); +internal Rng1U64 shift_1u64(Rng1U64 r, U64 x); +internal Rng1U64 pad_1u64(Rng1U64 r, U64 x); +internal U64 center_1u64(Rng1U64 r); +internal B32 contains_1u64(Rng1U64 r, U64 x); +internal U64 dim_1u64(Rng1U64 r); +internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b); +internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b); +internal U64 clamp_1u64(Rng1U64 r, U64 v); + +#define r1s64(min, max) rng_1s64((min), (max)) +internal Rng1S64 rng_1s64(S64 min, S64 max); +internal Rng1S64 shift_1s64(Rng1S64 r, S64 x); +internal Rng1S64 pad_1s64(Rng1S64 r, S64 x); +internal S64 center_1s64(Rng1S64 r); +internal B32 contains_1s64(Rng1S64 r, S64 x); +internal S64 dim_1s64(Rng1S64 r); +internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b); +internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b); +internal S64 clamp_1s64(Rng1S64 r, S64 v); + +#define r1f32(min, max) rng_1f32((min), (max)) +internal Rng1F32 rng_1f32(F32 min, F32 max); +internal Rng1F32 shift_1f32(Rng1F32 r, F32 x); +internal Rng1F32 pad_1f32(Rng1F32 r, F32 x); +internal F32 center_1f32(Rng1F32 r); +internal B32 contains_1f32(Rng1F32 r, F32 x); +internal F32 dim_1f32(Rng1F32 r); +internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b); +internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b); +internal F32 clamp_1f32(Rng1F32 r, F32 v); + +#define r2s16(min, max) rng_2s16((min), (max)) +#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w))) +internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max); +internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x); +internal Rng2S16 pad_2s16(Rng2S16 r, S16 x); +internal Vec2S16 center_2s16(Rng2S16 r); +internal B32 contains_2s16(Rng2S16 r, Vec2S16 x); +internal Vec2S16 dim_2s16(Rng2S16 r); +internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b); +internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b); +internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v); + +#define r2s32(min, max) rng_2s32((min), (max)) +#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w))) +internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max); +internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x); +internal Rng2S32 pad_2s32(Rng2S32 r, S32 x); +internal Vec2S32 center_2s32(Rng2S32 r); +internal B32 contains_2s32(Rng2S32 r, Vec2S32 x); +internal Vec2S32 dim_2s32(Rng2S32 r); +internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b); +internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b); +internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v); + +#define r2s64(min, max) rng_2s64((min), (max)) +#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w))) +internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max); +internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x); +internal Rng2S64 pad_2s64(Rng2S64 r, S64 x); +internal Vec2S64 center_2s64(Rng2S64 r); +internal B32 contains_2s64(Rng2S64 r, Vec2S64 x); +internal Vec2S64 dim_2s64(Rng2S64 r); +internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b); +internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b); +internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v); + +#define r2f32(min, max) rng_2f32((min), (max)) +#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w))) +internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max); +internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x); +internal Rng2F32 pad_2f32(Rng2F32 r, F32 x); +internal Vec2F32 center_2f32(Rng2F32 r); +internal B32 contains_2f32(Rng2F32 r, Vec2F32 x); +internal Vec2F32 dim_2f32(Rng2F32 r); +internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b); +internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b); +internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v); + +//////////////////////////////// +//~ rjf: Miscellaneous Ops + +internal Vec3F32 hsv_from_rgb(Vec3F32 rgb); +internal Vec3F32 rgb_from_hsv(Vec3F32 hsv); +internal Vec4F32 hsva_from_rgba(Vec4F32 rgba); +internal Vec4F32 rgba_from_hsva(Vec4F32 hsva); +internal Vec4F32 rgba_from_u32(U32 hex); +internal U32 u32_from_rgba(Vec4F32 rgba); + +#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f } + +//////////////////////////////// +//~ rjf: List Type Functions + +internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); +internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); + +#endif // BASE_MATH_H diff --git a/src/metagen/metagen_base/metagen_base_string.c b/src/metagen/metagen_base/metagen_base_string.c new file mode 100644 index 00000000..ac974599 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_string.c @@ -0,0 +1,1878 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Third Party Includes + +#if !SUPPLEMENT_UNIT +# define STB_SPRINTF_IMPLEMENTATION +# define STB_SPRINTF_STATIC +# include "third_party/stb/stb_sprintf.h" +#endif + +//////////////////////////////// +//~ NOTE(allen): String <-> Integer Tables + +read_only global U8 integer_symbols[16] = { + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', +}; + +// NOTE(allen): Includes reverses for uppercase and lowercase hex. +read_only global U8 integer_symbol_reverse[128] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +}; + +read_only global U8 base64[64] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '_', '$', +}; + +read_only global U8 base64_reverse[128] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32, + 0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, + 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF, +}; + +//////////////////////////////// +//~ rjf: Character Classification & Conversion Functions + +internal B32 +char_is_space(U8 c){ + return(c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'); +} + +internal B32 +char_is_upper(U8 c){ + return('A' <= c && c <= 'Z'); +} + +internal B32 +char_is_lower(U8 c){ + return('a' <= c && c <= 'z'); +} + +internal B32 +char_is_alpha(U8 c){ + return(char_is_upper(c) || char_is_lower(c)); +} + +internal B32 +char_is_slash(U8 c){ + return(c == '/' || c == '\\'); +} + +internal B32 +char_is_digit(U8 c, U32 base){ + B32 result = 0; + if (0 < base && base <= 16){ + U8 val = integer_symbol_reverse[c]; + if (val < base){ + result = 1; + } + } + return(result); +} + +internal U8 +char_to_lower(U8 c){ + if (char_is_upper(c)){ + c += ('a' - 'A'); + } + return(c); +} + +internal U8 +char_to_upper(U8 c){ + if (char_is_lower(c)){ + c += ('A' - 'a'); + } + return(c); +} + +internal U8 +char_to_correct_slash(U8 c){ + if(char_is_slash(c)){ + c = '/'; + } + return(c); +} + +//////////////////////////////// +//~ rjf: C-String Measurement + +internal U64 +cstring8_length(U8 *c){ + U8 *p = c; + for (;*p != 0; p += 1); + return(p - c); +} + +internal U64 +cstring16_length(U16 *c){ + U16 *p = c; + for (;*p != 0; p += 1); + return(p - c); +} + +internal U64 +cstring32_length(U32 *c){ + U32 *p = c; + for (;*p != 0; p += 1); + return(p - c); +} + +//////////////////////////////// +//~ rjf: String Constructors + +internal String8 +str8(U8 *str, U64 size){ + String8 result = {str, size}; + return(result); +} + +internal String8 +str8_range(U8 *first, U8 *one_past_last){ + String8 result = {first, (U64)(one_past_last - first)}; + return(result); +} + +internal String8 +str8_zero(void){ + String8 result = {0}; + return(result); +} + +internal String16 +str16(U16 *str, U64 size){ + String16 result = {str, size}; + return(result); +} + +internal String16 +str16_range(U16 *first, U16 *one_past_last){ + String16 result = {first, (U64)(one_past_last - first)}; + return(result); +} + +internal String16 +str16_zero(void){ + String16 result = {0}; + return(result); +} + +internal String32 +str32(U32 *str, U64 size){ + String32 result = {str, size}; + return(result); +} + +internal String32 +str32_range(U32 *first, U32 *one_past_last){ + String32 result = {first, (U64)(one_past_last - first)}; + return(result); +} + +internal String32 +str32_zero(void){ + String32 result = {0}; + return(result); +} + +internal String8 +str8_cstring(char *c){ + String8 result = {(U8*)c, cstring8_length((U8*)c)}; + return(result); +} + +internal String16 +str16_cstring(U16 *c){ + String16 result = {(U16*)c, cstring16_length((U16*)c)}; + return(result); +} + +internal String32 +str32_cstring(U32 *c){ + String32 result = {(U32*)c, cstring32_length((U32*)c)}; + return(result); +} + +internal String8 +str8_cstring_capped(void *cstr, void *cap) +{ + char *ptr = (char*)cstr; + char *opl = (char*)cap; + for (;ptr < opl && *ptr != 0; ptr += 1); + U64 size = (U64)(ptr - (char *)cstr); + String8 result = {(U8*)cstr, size}; + return(result); +} + +//////////////////////////////// +//~ rjf: String Stylization + +internal String8 +upper_from_str8(Arena *arena, String8 string) +{ + string = push_str8_copy(arena, string); + for(U64 idx = 0; idx < string.size; idx += 1) + { + string.str[idx] = char_to_upper(string.str[idx]); + } + return string; +} + +internal String8 +lower_from_str8(Arena *arena, String8 string) +{ + string = push_str8_copy(arena, string); + for(U64 idx = 0; idx < string.size; idx += 1) + { + string.str[idx] = char_to_lower(string.str[idx]); + } + return string; +} + +internal String8 +backslashed_from_str8(Arena *arena, String8 string) +{ + string = push_str8_copy(arena, string); + for(U64 idx = 0; idx < string.size; idx += 1) + { + string.str[idx] = char_is_slash(string.str[idx]) ? '\\' : string.str[idx]; + } + return string; +} + +//////////////////////////////// +//~ rjf: String Matching + +internal B32 +str8_match(String8 a, String8 b, StringMatchFlags flags){ + B32 result = 0; + if (a.size == b.size || (flags & StringMatchFlag_RightSideSloppy)){ + B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive); + B32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive); + U64 size = Min(a.size, b.size); + result = 1; + for (U64 i = 0; i < size; i += 1){ + U8 at = a.str[i]; + U8 bt = b.str[i]; + if (case_insensitive){ + at = char_to_upper(at); + bt = char_to_upper(bt); + } + if (slash_insensitive){ + at = char_to_correct_slash(at); + bt = char_to_correct_slash(bt); + } + if (at != bt){ + result = 0; + break; + } + } + } + return(result); +} + +internal U64 +str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags){ + U8 *p = string.str + start_pos; + U64 stop_offset = Max(string.size + 1, needle.size) - needle.size; + U8 *stop_p = string.str + stop_offset; + if (needle.size > 0){ + U8 *string_opl = string.str + string.size; + String8 needle_tail = str8_skip(needle, 1); + StringMatchFlags adjusted_flags = flags | StringMatchFlag_RightSideSloppy; + U8 needle_first_char_adjusted = needle.str[0]; + if(adjusted_flags & StringMatchFlag_CaseInsensitive){ + needle_first_char_adjusted = char_to_upper(needle_first_char_adjusted); + } + for (;p < stop_p; p += 1){ + U8 haystack_char_adjusted = *p; + if(adjusted_flags & StringMatchFlag_CaseInsensitive){ + haystack_char_adjusted = char_to_upper(haystack_char_adjusted); + } + if (haystack_char_adjusted == needle_first_char_adjusted){ + if (str8_match(str8_range(p + 1, string_opl), needle_tail, adjusted_flags)){ + break; + } + } + } + } + U64 result = string.size; + if (p < stop_p){ + result = (U64)(p - string.str); + } + return(result); +} + +internal B32 +str8_ends_with(String8 string, String8 end, StringMatchFlags flags){ + String8 postfix = str8_postfix(string, end.size); + B32 is_match = str8_match(end, postfix, flags); + return is_match; +} + +//////////////////////////////// +//~ rjf: String Slicing + +internal String8 +str8_substr(String8 str, Rng1U64 range){ + range.min = ClampTop(range.min, str.size); + range.max = ClampTop(range.max, str.size); + str.str += range.min; + str.size = dim_1u64(range); + return(str); +} + +internal String8 +str8_prefix(String8 str, U64 size){ + str.size = ClampTop(size, str.size); + return(str); +} + +internal String8 +str8_skip(String8 str, U64 amt){ + amt = ClampTop(amt, str.size); + str.str += amt; + str.size -= amt; + return(str); +} + +internal String8 +str8_postfix(String8 str, U64 size){ + size = ClampTop(size, str.size); + str.str = (str.str + str.size) - size; + str.size = size; + return(str); +} + +internal String8 +str8_chop(String8 str, U64 amt){ + amt = ClampTop(amt, str.size); + str.size -= amt; + return(str); +} + +internal String8 +str8_skip_chop_whitespace(String8 string){ + U8 *first = string.str; + U8 *opl = first + string.size; + for (;first < opl; first += 1){ + if (!char_is_space(*first)){ + break; + } + } + for (;opl > first;){ + opl -= 1; + if (!char_is_space(*opl)){ + opl += 1; + break; + } + } + String8 result = str8_range(first, opl); + return(result); +} + +//////////////////////////////// +//~ rjf: String Formatting & Copying + +internal String8 +push_str8_cat(Arena *arena, String8 s1, String8 s2){ + String8 str; + str.size = s1.size + s2.size; + str.str = push_array_no_zero(arena, U8, str.size + 1); + MemoryCopy(str.str, s1.str, s1.size); + MemoryCopy(str.str + s1.size, s2.str, s2.size); + str.str[str.size] = 0; + return(str); +} + +internal String8 +push_str8_copy(Arena *arena, String8 s){ + //ProfBeginFunction(); + String8 str; + str.size = s.size; + str.str = push_array_no_zero(arena, U8, str.size + 1); + MemoryCopy(str.str, s.str, s.size); + str.str[str.size] = 0; + //ProfEnd(); + return(str); +} + +internal String8 +push_str8fv(Arena *arena, char *fmt, va_list args){ + va_list args2; + va_copy(args2, args); + U32 needed_bytes = raddbg_vsnprintf(0, 0, fmt, args) + 1; + String8 result = {0}; + result.str = push_array_no_zero(arena, U8, needed_bytes); + result.size = raddbg_vsnprintf((char*)result.str, needed_bytes, fmt, args2); + result.str[result.size] = 0; + va_end(args2); + return(result); +} + +internal String8 +push_str8f(Arena *arena, char *fmt, ...){ + va_list args; + va_start(args, fmt); + String8 result = push_str8fv(arena, fmt, args); + va_end(args); + return(result); +} + +//////////////////////////////// +//~ rjf: String <=> Integer Conversions + +//- rjf: string -> integer + +internal S64 +sign_from_str8(String8 string, String8 *string_tail){ + // count negative signs + U64 neg_count = 0; + U64 i = 0; + for (; i < string.size; i += 1){ + if (string.str[i] == '-'){ + neg_count += 1; + } + else if (string.str[i] != '+'){ + break; + } + } + + // output part of string after signs + *string_tail = str8_skip(string, i); + + // output integer sign + S64 sign = (neg_count & 1)?-1:+1; + return(sign); +} + +internal B32 +str8_is_integer(String8 string, U32 radix){ + B32 result = 0; + if (string.size > 0){ + if (1 < radix && radix <= 16){ + result = 1; + for (U64 i = 0; i < string.size; i += 1){ + U8 c = string.str[i]; + if (!(c < 0x80) || integer_symbol_reverse[c] >= radix){ + result = 0; + break; + } + } + } + } + return(result); +} + +internal U64 +u64_from_str8(String8 string, U32 radix){ + U64 x = 0; + if (1 < radix && radix <= 16){ + for (U64 i = 0; i < string.size; i += 1){ + x *= radix; + x += integer_symbol_reverse[string.str[i]&0x7F]; + } + } + return(x); +} + +internal S64 +s64_from_str8(String8 string, U32 radix){ + S64 sign = sign_from_str8(string, &string); + S64 x = (S64)u64_from_str8(string, radix) * sign; + return(x); +} + +internal B32 +try_u64_from_str8_c_rules(String8 string, U64 *x){ + B32 is_integer = 0; + if (str8_is_integer(string, 10)){ + is_integer = 1; + *x = u64_from_str8(string, 10); + } + else{ + String8 hex_string = str8_skip(string, 2); + if (str8_match(str8_prefix(string, 2), str8_lit("0x"), 0) && + str8_is_integer(hex_string, 0x10)){ + is_integer = 1; + *x = u64_from_str8(hex_string, 0x10); + } + else if (str8_match(str8_prefix(string, 2), str8_lit("0b"), 0) && + str8_is_integer(hex_string, 2)){ + is_integer = 1; + *x = u64_from_str8(hex_string, 2); + } + else{ + String8 oct_string = str8_skip(string, 1); + if (str8_match(str8_prefix(string, 1), str8_lit("0"), 0) && + str8_is_integer(hex_string, 010)){ + is_integer = 1; + *x = u64_from_str8(oct_string, 010); + } + } + } + return(is_integer); +} + +internal B32 +try_s64_from_str8_c_rules(String8 string, S64 *x){ + String8 string_tail = {0}; + S64 sign = sign_from_str8(string, &string_tail); + U64 x_u64 = 0; + B32 is_integer = try_u64_from_str8_c_rules(string_tail, &x_u64); + *x = x_u64*sign; + return(is_integer); +} + +//- rjf: string -> integer (base64 & base16) + +internal U64 +base64_size_from_data_size(U64 size_in_bytes){ + U64 bits = size_in_bytes*8; + U64 base64_size = (bits + 5)/6; + return(base64_size); +} + +internal U64 +base64_from_data(U8 *dst, U8 *src, U64 src_size){ + U8 *dst_base = dst; + U8 *opl = src + src_size; + U32 bit_num = 0; + if (src < opl){ + U8 byte = *src; + for (;;){ + U32 x = 0; + for (U32 i = 0; i < 6; i += 1){ + x |= ((byte >> bit_num) & 1) << i; + bit_num += 1; + if (bit_num == 8){ + bit_num = 0; + src += 1; + byte = (src < opl)?(*src):0; + } + } + *dst = base64[x]; + dst += 1; + if (src >= opl){ + break; + } + } + } + return(dst - dst_base); +} + +internal U64 +base16_size_from_data_size(U64 size_in_bytes){ + U64 base16_size = size_in_bytes*2; + return(base16_size); +} + +internal U64 +base16_from_data(U8 *dst, U8 *src, U64 src_size){ + U8 *dst_base = dst; + U8 *opl = src + src_size; + for (;src < opl;){ + U8 byte = *src; + *dst = integer_symbols[byte & 0xF]; + dst += 1; + *dst = integer_symbols[byte >> 4]; + dst += 1; + src += 1; + } + return(dst - dst_base); +} + +//- rjf: integer -> string + +internal String8 +str8_from_memory_size(Arena *arena, U64 z){ + String8 result = {0}; + if (z < KB(1)){ + result = push_str8f(arena, "%llu b", z); + } + else if (z < MB(1)){ + result = push_str8f(arena, "%llu.%02llu Kb", z/KB(1), ((100*z)/KB(1))%100); + } + else if (z < GB(1)){ + result = push_str8f(arena, "%llu.%02llu Mb", z/MB(1), ((100*z)/MB(1))%100); + } + else{ + result = push_str8f(arena, "%llu.%02llu Gb", z/GB(1), ((100*z)/GB(1))%100); + } + return(result); +} + +internal String8 +str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator) +{ + String8 result = {0}; + { + // rjf: prefix + String8 prefix = {0}; + switch(radix) + { + case 16:{prefix = str8_lit("0x");}break; + case 8: {prefix = str8_lit("0o");}break; + case 2: {prefix = str8_lit("0b");}break; + } + + // rjf: determine # of chars between separators + U8 digit_group_size = 3; + switch(radix) + { + default:break; + case 2: + case 8: + case 16: + {digit_group_size = 4;}break; + } + + // rjf: prep + U64 needed_leading_0s = 0; + { + U64 needed_digits = 1; + { + U64 u64_reduce = u64; + for(;;) + { + u64_reduce /= radix; + if(u64_reduce == 0) + { + break; + } + needed_digits += 1; + } + } + needed_leading_0s = (min_digits > needed_digits) ? min_digits - needed_digits : 0; + U64 needed_separators = 0; + if(digit_group_separator != 0) + { + needed_separators = (needed_digits+needed_leading_0s)/digit_group_size; + if(needed_separators > 0 && (needed_digits+needed_leading_0s)%digit_group_size == 0) + { + needed_separators -= 1; + } + } + result.size = prefix.size + needed_leading_0s + needed_separators + needed_digits; + result.str = push_array_no_zero(arena, U8, result.size + 1); + result.str[result.size] = 0; + } + + // rjf: fill contents + { + U64 u64_reduce = u64; + U64 digits_until_separator = digit_group_size; + for(U64 idx = 0; idx < result.size; idx += 1) + { + if(digits_until_separator == 0 && digit_group_separator != 0) + { + result.str[result.size - idx - 1] = digit_group_separator; + digits_until_separator = digit_group_size+1; + } + else + { + result.str[result.size - idx - 1] = char_to_lower(integer_symbols[u64_reduce%radix]); + u64_reduce /= radix; + } + digits_until_separator -= 1; + if(u64_reduce == 0) + { + break; + } + } + for(U64 leading_0_idx = 0; leading_0_idx < needed_leading_0s; leading_0_idx += 1) + { + result.str[prefix.size + leading_0_idx] = '0'; + } + } + + // rjf: fill prefix + if(prefix.size != 0) + { + MemoryCopy(result.str, prefix.str, prefix.size); + } + } + return result; +} + +internal String8 +str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator) +{ + String8 result = {0}; + // TODO(rjf): preeeeetty sloppy... + if(s64 < 0) + { + Temp scratch = scratch_begin(&arena, 1); + String8 numeric_part = str8_from_u64(scratch.arena, (U64)(-s64), radix, min_digits, digit_group_separator); + result = push_str8f(arena, "-%S", numeric_part); + scratch_end(scratch); + } + else + { + result = str8_from_u64(arena, (U64)s64, radix, min_digits, digit_group_separator); + } + return result; +} + +//////////////////////////////// +//~ rjf: String <=> Float Conversions + +internal F64 +f64_from_str8(String8 string) +{ + // TODO(rjf): crappy implementation for now that just uses atof. + F64 result = 0; + if(string.size > 0) + { + // rjf: find starting pos of numeric string, as well as sign + F64 sign = +1.0; + //U64 first_numeric = 0; + if(string.str[0] == '-') + { + //first_numeric = 1; + sign = -1.0; + } + else if(string.str[0] == '+') + { + //first_numeric = 1; + sign = 1.0; + } + + // rjf: gather numerics + U64 num_valid_chars = 0; + char buffer[64]; + for(U64 idx = 0; idx < string.size && num_valid_chars < sizeof(buffer)-1; idx += 1) + { + if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.') + { + buffer[num_valid_chars] = string.str[idx]; + num_valid_chars += 1; + } + } + + // rjf: null-terminate (the reason for all of this!!!!!!) + buffer[num_valid_chars] = 0; + + // rjf: do final conversion + result = sign * atof(buffer); + } + return result; +} + +//////////////////////////////// +//~ rjf: String List Construction Functions + +internal String8Node* +str8_list_push_node(String8List *list, String8Node *node){ + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size += node->string.size; + return(node); +} + +internal String8Node* +str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string){ + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size += string.size; + node->string = string; + return(node); +} + +internal String8Node* +str8_list_push_node_front(String8List *list, String8Node *node){ + SLLQueuePushFront(list->first, list->last, node); + list->node_count += 1; + list->total_size += node->string.size; + return(node); +} + +internal String8Node* +str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string){ + SLLQueuePushFront(list->first, list->last, node); + list->node_count += 1; + list->total_size += string.size; + node->string = string; + return(node); +} + +internal String8Node* +str8_list_push(Arena *arena, String8List *list, String8 string){ + String8Node *node = push_array_no_zero(arena, String8Node, 1); + str8_list_push_node_set_string(list, node, string); + return(node); +} + +internal String8Node* +str8_list_push_front(Arena *arena, String8List *list, String8 string){ + String8Node *node = push_array_no_zero(arena, String8Node, 1); + str8_list_push_node_front_set_string(list, node, string); + return(node); +} + +internal void +str8_list_concat_in_place(String8List *list, String8List *to_push){ + if(to_push->node_count != 0){ + if (list->last){ + list->node_count += to_push->node_count; + list->total_size += to_push->total_size; + list->last->next = to_push->first; + list->last = to_push->last; + } + else{ + *list = *to_push; + } + MemoryZeroStruct(to_push); + } +} + +internal String8Node* +str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){ + String8Node *node = push_array_no_zero(arena, String8Node, 1); + U64 new_size = list->total_size + min; + U64 increase_size = 0; + if (align > 1){ + // NOTE(allen): assert is power of 2 + Assert(((align - 1) & align) == 0); + U64 mask = align - 1; + new_size += mask; + new_size &= (~mask); + increase_size = new_size - list->total_size; + } + local_persist const U8 zeroes_buffer[64] = {0}; + Assert(increase_size <= ArrayCount(zeroes_buffer)); + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size = new_size; + node->string.str = (U8*)zeroes_buffer; + node->string.size = increase_size; + return(node); +} + +internal String8Node* +str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...){ + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(arena, fmt, args); + String8Node *result = str8_list_push(arena, list, string); + va_end(args); + return(result); +} + +internal String8Node* +str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...){ + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(arena, fmt, args); + String8Node *result = str8_list_push_front(arena, list, string); + va_end(args); + return(result); +} + +internal String8List +str8_list_copy(Arena *arena, String8List *list){ + String8List result = {0}; + for (String8Node *node = list->first; + node != 0; + node = node->next){ + String8Node *new_node = push_array_no_zero(arena, String8Node, 1); + String8 new_string = push_str8_copy(arena, node->string); + str8_list_push_node_set_string(&result, new_node, new_string); + } + return(result); +} + +internal String8List +str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags){ + String8List list = {0}; + + B32 keep_empties = (flags & StringSplitFlag_KeepEmpties); + + U8 *ptr = string.str; + U8 *opl = string.str + string.size; + for (;ptr < opl;){ + U8 *first = ptr; + for (;ptr < opl; ptr += 1){ + U8 c = *ptr; + B32 is_split = 0; + for (U64 i = 0; i < split_char_count; i += 1){ + if (split_chars[i] == c){ + is_split = 1; + break; + } + } + if (is_split){ + break; + } + } + + String8 string = str8_range(first, ptr); + if (keep_empties || string.size > 0){ + str8_list_push(arena, &list, string); + } + ptr += 1; + } + + return(list); +} + +internal String8List +str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags){ + String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); + return list; +} + +internal String8List +str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags){ + String8List result = {0}; + for (String8Node *node = list.first; node != 0; node = node->next){ + String8List split = str8_split_by_string_chars(arena, node->string, split_chars, flags); + str8_list_concat_in_place(&result, &split); + } + return result; +} + +internal String8 +str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params){ + StringJoin join = {0}; + if (optional_params != 0){ + MemoryCopyStruct(&join, optional_params); + } + + U64 sep_count = 0; + if (list->node_count > 0){ + sep_count = list->node_count - 1; + } + + String8 result; + result.size = join.pre.size + join.post.size + sep_count*join.sep.size + list->total_size; + U8 *ptr = result.str = push_array_no_zero(arena, U8, result.size + 1); + + MemoryCopy(ptr, join.pre.str, join.pre.size); + ptr += join.pre.size; + for (String8Node *node = list->first; + node != 0; + node = node->next){ + MemoryCopy(ptr, node->string.str, node->string.size); + ptr += node->string.size; + if (node->next != 0){ + MemoryCopy(ptr, join.sep.str, join.sep.size); + ptr += join.sep.size; + } + } + MemoryCopy(ptr, join.post.str, join.post.size); + ptr += join.post.size; + + *ptr = 0; + + return(result); +} + +internal void +str8_list_from_flags(Arena *arena, String8List *list, + U32 flags, String8 *flag_string_table, U32 flag_string_count){ + for (U32 i = 0; i < flag_string_count; i += 1){ + U32 flag = (1 << i); + if (flags & flag){ + str8_list_push(arena, list, flag_string_table[i]); + } + } +} + +//////////////////////////////// +//~ rjf; String Arrays + +internal String8Array +str8_array_from_list(Arena *arena, String8List *list) +{ + String8Array array; + array.count = list->node_count; + array.strings = push_array_no_zero(arena, String8, array.count); + U64 idx = 0; + for(String8Node *n = list->first; n != 0; n = n->next, idx += 1) + { + array.strings[idx] = n->string; + } + return array; +} + +internal String8Array +str8_array_reserve(Arena *arena, U64 count) +{ + String8Array arr; + arr.count = 0; + arr.strings = push_array(arena, String8, count); + return arr; +} + +//////////////////////////////// +//~ rjf: String Path Helpers + +internal String8 +str8_chop_last_slash(String8 string){ + if (string.size > 0){ + U8 *ptr = string.str + string.size - 1; + for (;ptr >= string.str; ptr -= 1){ + if (*ptr == '/' || *ptr == '\\'){ + break; + } + } + if (ptr >= string.str){ + string.size = (U64)(ptr - string.str); + } + else{ + string.size = 0; + } + } + return(string); +} + +internal String8 +str8_skip_last_slash(String8 string){ + if (string.size > 0){ + U8 *ptr = string.str + string.size - 1; + for (;ptr >= string.str; ptr -= 1){ + if (*ptr == '/' || *ptr == '\\'){ + break; + } + } + if (ptr >= string.str){ + ptr += 1; + string.size = (U64)(string.str + string.size - ptr); + string.str = ptr; + } + } + return(string); +} + +internal String8 +str8_chop_last_dot(String8 string) +{ + String8 result = string; + U64 p = string.size; + for (;p > 0;){ + p -= 1; + if (string.str[p] == '.'){ + result = str8_prefix(string, p); + break; + } + } + return(result); +} + +internal String8 +str8_skip_last_dot(String8 string){ + String8 result = string; + U64 p = string.size; + for (;p > 0;){ + p -= 1; + if (string.str[p] == '.'){ + result = str8_skip(string, p + 1); + break; + } + } + return(result); +} + +internal PathStyle +path_style_from_str8(String8 string){ + PathStyle result = PathStyle_Relative; + if (string.size >= 1 && string.str[0] == '/'){ + result = PathStyle_UnixAbsolute; + } + else if (string.size >= 2 && + char_is_alpha(string.str[0]) && + string.str[1] == ':'){ + if (string.size == 2 || + char_is_slash(string.str[2])){ + result = PathStyle_WindowsAbsolute; + } + } + return(result); +} + +internal String8List +str8_split_path(Arena *arena, String8 string){ + String8List result = str8_split(arena, string, (U8*)"/\\", 2, 0); + return(result); +} + +internal void +str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){ + Temp scratch = scratch_begin(0, 0); + + String8MetaNode *stack = 0; + String8MetaNode *free_meta_node = 0; + String8Node *first = path->first; + + MemoryZeroStruct(path); + for (String8Node *node = first, *next = 0; + node != 0; + node = next){ + // save next now + next = node->next; + + // cases: + if (node == first && style == PathStyle_WindowsAbsolute){ + goto save_without_stack; + } + if (node->string.size == 1 && node->string.str[0] == '.'){ + goto do_nothing; + } + if (node->string.size == 2 && node->string.str[0] == '.' && node->string.str[1] == '.'){ + if (stack != 0){ + goto eliminate_stack_top; + } + else{ + goto save_without_stack; + } + } + goto save_with_stack; + + + // handlers: + save_with_stack: + { + str8_list_push_node(path, node); + + String8MetaNode *stack_node = free_meta_node; + if (stack_node != 0){ + SLLStackPop(free_meta_node); + } + else{ + stack_node = push_array_no_zero(scratch.arena, String8MetaNode, 1); + } + SLLStackPush(stack, stack_node); + stack_node->node = node; + + continue; + } + + save_without_stack: + { + str8_list_push_node(path, node); + + continue; + } + + eliminate_stack_top: + { + path->node_count -= 1; + path->total_size -= stack->node->string.size; + + SLLStackPop(stack); + + if (stack == 0){ + path->last = path->first; + } + else{ + path->last = stack->node; + } + continue; + } + + do_nothing: continue; + } + scratch_end(scratch); +} + +internal String8 +str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){ + StringJoin params = {0}; + switch (style){ + case PathStyle_Relative: + case PathStyle_WindowsAbsolute: + { + params.sep = str8_lit("/"); + }break; + + case PathStyle_UnixAbsolute: + { + params.pre = str8_lit("/"); + params.sep = str8_lit("/"); + }break; + } + + String8 result = str8_list_join(arena, path, ¶ms); + return(result); +} + +internal String8TxtPtPair +str8_txt_pt_pair_from_string(String8 string) +{ + String8TxtPtPair pair = {0}; + { + String8 file_part = {0}; + String8 line_part = {0}; + String8 col_part = {0}; + + // rjf: grab file part + for(U64 idx = 0; idx <= string.size; idx += 1) + { + U8 byte = (idx < string.size) ? (string.str[idx]) : 0; + U8 next_byte = ((idx+1 < string.size) ? (string.str[idx+1]) : 0); + if(byte == ':' && next_byte != '/' && next_byte != '\\') + { + file_part = str8_prefix(string, idx); + line_part = str8_skip(string, idx+1); + break; + } + else if(byte == 0) + { + file_part = string; + break; + } + } + + // rjf: grab line/column + { + U64 colon_pos = str8_find_needle(line_part, 0, str8_lit(":"), 0); + if(colon_pos < line_part.size) + { + col_part = str8_skip(line_part, colon_pos+1); + line_part = str8_prefix(line_part, colon_pos); + } + } + + // rjf: convert line/column strings to numerics + U64 line = 0; + U64 column = 0; + try_u64_from_str8_c_rules(line_part, &line); + try_u64_from_str8_c_rules(col_part, &column); + + // rjf: fill + pair.string = file_part; + pair.pt = txt_pt((S64)line, (S64)column); + if(pair.pt.line == 0) { pair.pt.line = 1; } + if(pair.pt.column == 0) { pair.pt.column = 1; } + } + return pair; +} + +//////////////////////////////// +//~ rjf: UTF-8 & UTF-16 Decoding/Encoding + +read_only global U8 utf8_class[32] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, +}; + +internal UnicodeDecode +utf8_decode(U8 *str, U64 max){ + UnicodeDecode result = {1, max_U32}; + U8 byte = str[0]; + U8 byte_class = utf8_class[byte >> 3]; + switch (byte_class) + { + case 1: + { + result.codepoint = byte; + }break; + case 2: + { + if (2 < max) + { + U8 cont_byte = str[1]; + if (utf8_class[cont_byte >> 3] == 0) + { + result.codepoint = (byte & bitmask5) << 6; + result.codepoint |= (cont_byte & bitmask6); + result.inc = 2; + } + } + }break; + case 3: + { + if (2 < max) + { + U8 cont_byte[2] = {str[1], str[2]}; + if (utf8_class[cont_byte[0] >> 3] == 0 && + utf8_class[cont_byte[1] >> 3] == 0) + { + result.codepoint = (byte & bitmask4) << 12; + result.codepoint |= ((cont_byte[0] & bitmask6) << 6); + result.codepoint |= (cont_byte[1] & bitmask6); + result.inc = 3; + } + } + }break; + case 4: + { + if (3 < max) + { + U8 cont_byte[3] = {str[1], str[2], str[3]}; + if (utf8_class[cont_byte[0] >> 3] == 0 && + utf8_class[cont_byte[1] >> 3] == 0 && + utf8_class[cont_byte[2] >> 3] == 0) + { + result.codepoint = (byte & bitmask3) << 18; + result.codepoint |= ((cont_byte[0] & bitmask6) << 12); + result.codepoint |= ((cont_byte[1] & bitmask6) << 6); + result.codepoint |= (cont_byte[2] & bitmask6); + result.inc = 4; + } + } + } + } + return(result); +} + +internal UnicodeDecode +utf16_decode(U16 *str, U64 max){ + UnicodeDecode result = {1, max_U32}; + result.codepoint = str[0]; + result.inc = 1; + if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000){ + result.codepoint = ((str[0] - 0xD800) << 10) | (str[1] - 0xDC00); + result.inc = 2; + } + return(result); +} + +internal U32 +utf8_encode(U8 *str, U32 codepoint){ + U32 inc = 0; + if (codepoint <= 0x7F){ + str[0] = (U8)codepoint; + inc = 1; + } + else if (codepoint <= 0x7FF){ + str[0] = (bitmask2 << 6) | ((codepoint >> 6) & bitmask5); + str[1] = bit8 | (codepoint & bitmask6); + inc = 2; + } + else if (codepoint <= 0xFFFF){ + str[0] = (bitmask3 << 5) | ((codepoint >> 12) & bitmask4); + str[1] = bit8 | ((codepoint >> 6) & bitmask6); + str[2] = bit8 | ( codepoint & bitmask6); + inc = 3; + } + else if (codepoint <= 0x10FFFF){ + str[0] = (bitmask4 << 3) | ((codepoint >> 18) & bitmask3); + str[1] = bit8 | ((codepoint >> 12) & bitmask6); + str[2] = bit8 | ((codepoint >> 6) & bitmask6); + str[3] = bit8 | ( codepoint & bitmask6); + inc = 4; + } + else{ + str[0] = '?'; + inc = 1; + } + return(inc); +} + +internal U32 +utf16_encode(U16 *str, U32 codepoint){ + U32 inc = 1; + if (codepoint == max_U32){ + str[0] = (U16)'?'; + } + else if (codepoint < 0x10000){ + str[0] = (U16)codepoint; + } + else{ + U32 v = codepoint - 0x10000; + str[0] = safe_cast_u16(0xD800 + (v >> 10)); + str[1] = safe_cast_u16(0xDC00 + (v & bitmask10)); + inc = 2; + } + return(inc); +} + +internal U32 +utf8_from_utf32_single(U8 *buffer, U32 character){ + return(utf8_encode(buffer, character)); +} + +//////////////////////////////// +//~ rjf: Unicode String Conversions + +internal String8 +str8_from_16(Arena *arena, String16 in){ + U64 cap = in.size*3; + U8 *str = push_array_no_zero(arena, U8, cap + 1); + U16 *ptr = in.str; + U16 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for (;ptr < opl; ptr += consume.inc){ + consume = utf16_decode(ptr, opl - ptr); + size += utf8_encode(str + size, consume.codepoint); + } + str[size] = 0; + arena_put_back(arena, (cap - size)); + return(str8(str, size)); +} + +internal String16 +str16_from_8(Arena *arena, String8 in){ + U64 cap = in.size*2; + U16 *str = push_array_no_zero(arena, U16, cap + 1); + U8 *ptr = in.str; + U8 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for (;ptr < opl; ptr += consume.inc){ + consume = utf8_decode(ptr, opl - ptr); + size += utf16_encode(str + size, consume.codepoint); + } + str[size] = 0; + arena_put_back(arena, (cap - size)*2); + return(str16(str, size)); +} + +internal String8 +str8_from_32(Arena *arena, String32 in){ + U64 cap = in.size*4; + U8 *str = push_array_no_zero(arena, U8, cap + 1); + U32 *ptr = in.str; + U32 *opl = ptr + in.size; + U64 size = 0; + for (;ptr < opl; ptr += 1){ + size += utf8_encode(str + size, *ptr); + } + str[size] = 0; + arena_put_back(arena, (cap - size)); + return(str8(str, size)); +} + +internal String32 +str32_from_8(Arena *arena, String8 in){ + U64 cap = in.size; + U32 *str = push_array_no_zero(arena, U32, cap + 1); + U8 *ptr = in.str; + U8 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for (;ptr < opl; ptr += consume.inc){ + consume = utf8_decode(ptr, opl - ptr); + str[size] = consume.codepoint; + size += 1; + } + str[size] = 0; + arena_put_back(arena, (cap - size)*4); + return(str32(str, size)); +} + +//////////////////////////////// +//~ rjf: Basic Types & Space Enum -> String Conversions + +internal String8 +string_from_dimension(Dimension dimension){ + local_persist String8 strings[] = { + str8_lit_comp("X"), + str8_lit_comp("Y"), + str8_lit_comp("Z"), + str8_lit_comp("W"), + }; + String8 result = str8_lit("error"); + if ((U32)dimension < 4){ + result = strings[dimension]; + } + return(result); +} + +internal String8 +string_from_side(Side side){ + local_persist String8 strings[] = { + str8_lit_comp("Min"), + str8_lit_comp("Max"), + }; + String8 result = str8_lit("error"); + if ((U32)side < 2){ + result = strings[side]; + } + return(result); +} + +internal String8 +string_from_operating_system(OperatingSystem os){ + local_persist String8 strings[] = { + str8_lit_comp("Null"), + str8_lit_comp("Windows"), + str8_lit_comp("Linux"), + str8_lit_comp("Mac"), + }; + String8 result = str8_lit("error"); + if (os < OperatingSystem_COUNT){ + result = strings[os]; + } + return(result); +} + +internal String8 +string_from_architecture(Architecture arch){ + local_persist String8 strings[] = { + str8_lit_comp("Null"), + str8_lit_comp("x64"), + str8_lit_comp("x86"), + str8_lit_comp("arm64"), + str8_lit_comp("arm32"), + }; + String8 result = str8_lit("error"); + if (arch < Architecture_COUNT){ + result = strings[arch]; + } + return(result); +} + +//////////////////////////////// +//~ rjf: Time Types -> String + +internal String8 +string_from_week_day(WeekDay week_day){ + local_persist String8 strings[] = { + str8_lit_comp("Sun"), + str8_lit_comp("Mon"), + str8_lit_comp("Tue"), + str8_lit_comp("Wed"), + str8_lit_comp("Thu"), + str8_lit_comp("Fri"), + str8_lit_comp("Sat"), + }; + String8 result = str8_lit("Err"); + if ((U32)week_day < WeekDay_COUNT){ + result = strings[week_day]; + } + return(result); +} + +internal String8 +string_from_month(Month month){ + local_persist String8 strings[] = { + str8_lit_comp("Jan"), + str8_lit_comp("Feb"), + str8_lit_comp("Mar"), + str8_lit_comp("Apr"), + str8_lit_comp("May"), + str8_lit_comp("Jun"), + str8_lit_comp("Jul"), + str8_lit_comp("Aug"), + str8_lit_comp("Sep"), + str8_lit_comp("Oct"), + str8_lit_comp("Nov"), + str8_lit_comp("Dec"), + }; + String8 result = str8_lit("Err"); + if ((U32)month < Month_COUNT){ + result = strings[month]; + } + return(result); +} + +internal String8 +push_date_time_string(Arena *arena, DateTime *date_time){ + char *mon_str = (char*)string_from_month(date_time->month).str; + U32 adjusted_hour = date_time->hour%12; + if (adjusted_hour == 0){ + adjusted_hour = 12; + } + char *ampm = "am"; + if (date_time->hour >= 12){ + ampm = "pm"; + } + String8 result = push_str8f(arena, "%d %s %d, %02d:%02d:%02d %s", + date_time->day, mon_str, date_time->year, + adjusted_hour, date_time->min, date_time->sec, ampm); + return(result); +} + +internal String8 +push_file_name_date_time_string(Arena *arena, DateTime *date_time){ + char *mon_str = (char*)string_from_month(date_time->month).str; + String8 result = push_str8f(arena, "%d-%s-%0d--%02d-%02d-%02d", + date_time->year, mon_str, date_time->day, + date_time->hour, date_time->min, date_time->sec); + return(result); +} + +internal String8 +string_from_elapsed_time(Arena *arena, DateTime dt){ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (dt.year){ + str8_list_pushf(scratch.arena, &list, "%dy", dt.year); + str8_list_pushf(scratch.arena, &list, "%um", dt.mon); + str8_list_pushf(scratch.arena, &list, "%ud", dt.day); + } else if (dt.mon){ + str8_list_pushf(scratch.arena, &list, "%um", dt.mon); + str8_list_pushf(scratch.arena, &list, "%ud", dt.day); + } else if (dt.day){ + str8_list_pushf(scratch.arena, &list, "%ud", dt.day); + } + str8_list_pushf(scratch.arena, &list, "%u:%u:%u:%u ms", dt.hour, dt.min, dt.sec, dt.msec); + StringJoin join = { str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }; + String8 result = str8_list_join(arena, &list, &join); + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: String <-> Color + +internal String8 +hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba) +{ + String8 hex_string = push_str8f(arena, "%02x%02x%02x%02x", (U8)(rgba.x*255.f), (U8)(rgba.y*255.f), (U8)(rgba.z*255.f), (U8)(rgba.w*255.f)); + return hex_string; +} + +internal Vec4F32 +rgba_from_hex_string_4f32(String8 hex_string) +{ + U8 byte_text[8] = {0}; + U64 byte_text_idx = 0; + for(U64 idx = 0; idx < hex_string.size && byte_text_idx < ArrayCount(byte_text); idx += 1) + { + if(char_is_digit(hex_string.str[idx], 16)) + { + byte_text[byte_text_idx] = char_to_lower(hex_string.str[idx]); + byte_text_idx += 1; + } + } + U8 byte_vals[4] = {0}; + for(U64 idx = 0; idx < 4; idx += 1) + { + byte_vals[idx] = (U8)u64_from_str8(str8(&byte_text[idx*2], 2), 16); + } + Vec4F32 rgba = v4f32(byte_vals[0]/255.f, byte_vals[1]/255.f, byte_vals[2]/255.f, byte_vals[3]/255.f); + return rgba; +} + +//////////////////////////////// +//~ NOTE(allen): Serialization Helpers + +internal void +str8_serial_begin(Arena *arena, String8List *srl){ + String8Node *node = push_array(arena, String8Node, 1); + node->string.str = push_array_no_zero(arena, U8, 0); + srl->first = srl->last = node; + srl->node_count = 1; + srl->total_size = 0; +} + +internal String8 +str8_serial_end(Arena *arena, String8List *srl){ + U64 size = srl->total_size; + U8 *out = push_array_no_zero(arena, U8, size); + str8_serial_write_to_dst(srl, out); + String8 result = str8(out, size); + return result; +} + +internal void +str8_serial_write_to_dst(String8List *srl, void *out){ + U8 *ptr = (U8*)out; + for (String8Node *node = srl->first; + node != 0; + node = node->next){ + U64 size = node->string.size; + MemoryCopy(ptr, node->string.str, size); + ptr += size; + } +} + +internal U64 +str8_serial_push_align(Arena *arena, String8List *srl, U64 align){ + Assert(IsPow2(align)); + + U64 pos = srl->total_size; + U64 new_pos = AlignPow2(pos, align); + U64 size = (new_pos - pos); + + if(size != 0) + { + U8 *buf = push_array(arena, U8, size); + + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += size; + srl->total_size += size; + } + else{ + str8_list_push(arena, srl, str8(buf, size)); + } + } + return size; +} + +internal void * +str8_serial_push_size(Arena *arena, String8List *srl, U64 size) +{ + void *result = 0; + if(size != 0) + { + U8 *buf = push_array_no_zero(arena, U8, size); + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += size; + srl->total_size += size; + } + else{ + str8_list_push(arena, srl, str8(buf, size)); + } + result = buf; + } + return result; +} + +internal void * +str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size){ + void *result = str8_serial_push_size(arena, srl, size); + if(result != 0) + { + MemoryCopy(result, data, size); + } + return result; +} + +internal void +str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first){ + for (String8Node *node = first; + node != 0; + node = node->next){ + str8_serial_push_data(arena, srl, node->string.str, node->string.size); + } +} + +internal void +str8_serial_push_u64(Arena *arena, String8List *srl, U64 x){ + U8 *buf = push_array_no_zero(arena, U8, 8); + MemoryCopy(buf, &x, 8); + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += 8; + srl->total_size += 8; + } + else{ + str8_list_push(arena, srl, str8(buf, 8)); + } +} + +internal void +str8_serial_push_u32(Arena *arena, String8List *srl, U32 x){ + U8 *buf = push_array_no_zero(arena, U8, 4); + MemoryCopy(buf, &x, 4); + String8 *str = &srl->last->string; + if (str->str + str->size == buf){ + srl->last->string.size += 4; + srl->total_size += 4; + } + else{ + str8_list_push(arena, srl, str8(buf, 4)); + } +} + +internal void +str8_serial_push_u16(Arena *arena, String8List *srl, U16 x){ + str8_serial_push_data(arena, srl, &x, sizeof(x)); +} + +internal void +str8_serial_push_u8(Arena *arena, String8List *srl, U8 x){ + str8_serial_push_data(arena, srl, &x, sizeof(x)); +} + +internal void +str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str){ + str8_serial_push_data(arena, srl, str.str, str.size); + str8_serial_push_u8(arena, srl, 0); +} + +internal void +str8_serial_push_string(Arena *arena, String8List *srl, String8 str){ + str8_serial_push_data(arena, srl, str.str, str.size); +} + +//////////////////////////////// +//~ rjf: Deserialization Helpers + +internal U64 +str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity) +{ + U64 bytes_left = string.size-Min(off, string.size); + U64 actually_readable_size = Min(bytes_left, read_size); + U64 legally_readable_size = actually_readable_size - actually_readable_size%granularity; + if(legally_readable_size > 0) + { + MemoryCopy(read_dst, string.str+off, legally_readable_size); + } + return legally_readable_size; +} + +internal U64 +str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val) +{ + U64 cursor = off; + for (;;) { + U16 val = 0; + str8_deserial_read_struct(string, cursor, &val); + if (val == scan_val) { + break; + } + cursor += sizeof(val); + } + return cursor; +} + +internal void * +str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size) +{ + void *raw_ptr = 0; + if (off + size <= string.size) { + raw_ptr = string.str + off; + } + return raw_ptr; +} + +internal U64 +str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out) +{ + U64 cstr_size = 0; + if (off < string.size) { + U8 *ptr = string.str + off; + U8 *cap = string.str + string.size; + *cstr_out = str8_cstring_capped(ptr, cap); + cstr_size = (cstr_out->size + 1); + } + return cstr_size; +} + +internal U64 +str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out) +{ + U64 null_off = str8_deserial_find_first_match(string, off, 0); + U64 size = null_off - off; + U16 *str = (U16 *)str8_deserial_get_raw_ptr(string, off, size); + U64 count = size / sizeof(*str); + *str_out = str16(str, count); + + U64 read_size_with_null = size + sizeof(*str); + return read_size_with_null; +} + +internal U64 +str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out) +{ + Rng1U64 range = rng_1u64(off, off + size); + *block_out = str8_substr(string, range); + return block_out->size; +} diff --git a/src/metagen/metagen_base/metagen_base_string.h b/src/metagen/metagen_base/metagen_base_string.h new file mode 100644 index 00000000..cb443c18 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_string.h @@ -0,0 +1,351 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_STRING_H +#define BASE_STRING_H + +//////////////////////////////// +//~ rjf: Third Party Includes + +#define STB_SPRINTF_DECORATE(name) raddbg_##name +#include "third_party/stb/stb_sprintf.h" + +//////////////////////////////// +//~ rjf: String Types + +typedef struct String8 String8; +struct String8 +{ + U8 *str; + U64 size; +}; + +typedef struct String16 String16; +struct String16 +{ + U16 *str; + U64 size; +}; + +typedef struct String32 String32; +struct String32 +{ + U32 *str; + U64 size; +}; + +//////////////////////////////// +//~ rjf: String List & Array Types + +typedef struct String8Node String8Node; +struct String8Node +{ + String8Node *next; + String8 string; +}; + +typedef struct String8MetaNode String8MetaNode; +struct String8MetaNode +{ + String8MetaNode *next; + String8Node *node; +}; + +typedef struct String8List String8List; +struct String8List +{ + String8Node *first; + String8Node *last; + U64 node_count; + U64 total_size; +}; + +typedef struct String8Array String8Array; +struct String8Array +{ + String8 *strings; + U64 count; +}; + +//////////////////////////////// +//~ rjf: String Matching, Splitting, & Joining Types + +typedef U32 StringMatchFlags; +enum +{ + StringMatchFlag_CaseInsensitive = (1 << 0), + StringMatchFlag_RightSideSloppy = (1 << 1), + StringMatchFlag_SlashInsensitive = (1 << 2), +}; + +typedef U32 StringSplitFlags; +enum +{ + StringSplitFlag_KeepEmpties = (1 << 0), +}; + +typedef enum PathStyle +{ + PathStyle_Relative, + PathStyle_WindowsAbsolute, + PathStyle_UnixAbsolute, + +#if OS_WINDOWS + PathStyle_SystemAbsolute = PathStyle_WindowsAbsolute +#elif OS_LINUX + PathStyle_SystemAbsolute = PathStyle_UnixAbsolute +#else +# error "absolute path style is undefined for this OS" +#endif +} +PathStyle; + +typedef struct StringJoin StringJoin; +struct StringJoin +{ + String8 pre; + String8 sep; + String8 post; +}; + +//////////////////////////////// +//~ rjf: String Pair Types + +typedef struct String8TxtPtPair String8TxtPtPair; +struct String8TxtPtPair +{ + String8 string; + TxtPt pt; +}; + +//////////////////////////////// +//~ rjf: UTF Decoding Types + +typedef struct UnicodeDecode UnicodeDecode; +struct UnicodeDecode +{ + U32 inc; + U32 codepoint; +}; + +//////////////////////////////// +//~ rjf: Character Classification & Conversion Functions + +internal B32 char_is_space(U8 c); +internal B32 char_is_upper(U8 c); +internal B32 char_is_lower(U8 c); +internal B32 char_is_alpha(U8 c); +internal B32 char_is_slash(U8 c); +internal B32 char_is_digit(U8 c, U32 base); +internal U8 char_to_lower(U8 c); +internal U8 char_to_upper(U8 c); +internal U8 char_to_correct_slash(U8 c); + +//////////////////////////////// +//~ rjf: C-String Measurement + +internal U64 cstring8_length(U8 *c); +internal U64 cstring16_length(U16 *c); +internal U64 cstring32_length(U32 *c); + +//////////////////////////////// +//~ rjf: String Constructors + +#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1) +#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,} +#define str8_varg(S) (int)((S).size), ((S).str) + +#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C)) +#define str8_array_fixed(S) str8((U8*)(S), sizeof(S)) +#define str8_struct(S) str8((U8*)(S), sizeof(*(S))) + +internal String8 str8(U8 *str, U64 size); +internal String8 str8_range(U8 *first, U8 *one_past_last); +internal String8 str8_zero(void); +internal String16 str16(U16 *str, U64 size); +internal String16 str16_range(U16 *first, U16 *one_past_last); +internal String16 str16_zero(void); +internal String32 str32(U32 *str, U64 size); +internal String32 str32_range(U32 *first, U32 *one_past_last); +internal String32 str32_zero(void); +internal String8 str8_cstring(char *c); +internal String16 str16_cstring(U16 *c); +internal String32 str32_cstring(U32 *c); +internal String8 str8_cstring_capped(void *cstr, void *cap); + +//////////////////////////////// +//~ rjf: String Stylization + +internal String8 upper_from_str8(Arena *arena, String8 string); +internal String8 lower_from_str8(Arena *arena, String8 string); +internal String8 backslashed_from_str8(Arena *arena, String8 string); + +//////////////////////////////// +//~ rjf: String Matching + +internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags); +internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); +internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags); + +//////////////////////////////// +//~ rjf: String Slicing + +internal String8 str8_substr(String8 str, Rng1U64 range); +internal String8 str8_prefix(String8 str, U64 size); +internal String8 str8_skip(String8 str, U64 amt); +internal String8 str8_postfix(String8 str, U64 size); +internal String8 str8_chop(String8 str, U64 amt); +internal String8 str8_skip_chop_whitespace(String8 string); + +//////////////////////////////// +//~ rjf: String Formatting & Copying + +internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2); +internal String8 push_str8_copy(Arena *arena, String8 s); +internal String8 push_str8fv(Arena *arena, char *fmt, va_list args); +internal String8 push_str8f(Arena *arena, char *fmt, ...); + +//////////////////////////////// +//~ rjf: String <=> Integer Conversions + +//- rjf: string -> integer +internal S64 sign_from_str8(String8 string, String8 *string_tail); +internal B32 str8_is_integer(String8 string, U32 radix); +internal U64 u64_from_str8(String8 string, U32 radix); +internal S64 s64_from_str8(String8 string, U32 radix); +internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x); +internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x); + +//- rjf: string -> integer (base64 & base16) +internal U64 base64_size_from_data_size(U64 size_in_bytes); +internal U64 base64_from_data(U8 *dst, U8 *src, U64 src_size); +internal U64 base16_size_from_data_size(U64 size_in_bytes); +internal U64 base16_from_data(U8 *dst, U8 *src, U64 src_size); + +//- rjf: integer -> string +internal String8 str8_from_memory_size(Arena *arena, U64 z); +internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); +internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator); + +//////////////////////////////// +//~ rjf: String <=> Float Conversions + +internal F64 f64_from_str8(String8 string); + +//////////////////////////////// +//~ rjf: String List Construction Functions + +internal String8Node* str8_list_push_node(String8List *list, String8Node *node); +internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string); +internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node); +internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string); +internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string); +internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string); +internal void str8_list_concat_in_place(String8List *list, String8List *to_push); +internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align); +internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...); +internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...); +internal String8List str8_list_copy(Arena *arena, String8List *list); +#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero()) + +//////////////////////////////// +//~ rjf: String Splitting & Joining + +internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags); +internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags); +internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags); +internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params); +internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count); + +//////////////////////////////// +//~ rjf; String Arrays + +internal String8Array str8_array_from_list(Arena *arena, String8List *list); +internal String8Array str8_array_reserve(Arena *arena, U64 count); + +//////////////////////////////// +//~ rjf: String Path Helpers + +internal String8 str8_chop_last_slash(String8 string); +internal String8 str8_skip_last_slash(String8 string); +internal String8 str8_chop_last_dot(String8 string); +internal String8 str8_skip_last_dot(String8 string); + +internal PathStyle path_style_from_str8(String8 string); +internal String8List str8_split_path(Arena *arena, String8 string); +internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style); +internal String8 str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style); + +internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string); + +//////////////////////////////// +//~ rjf: UTF-8 & UTF-16 Decoding/Encoding + +internal UnicodeDecode utf8_decode(U8 *str, U64 max); +internal UnicodeDecode utf16_decode(U16 *str, U64 max); +internal U32 utf8_encode(U8 *str, U32 codepoint); +internal U32 utf16_encode(U16 *str, U32 codepoint); +internal U32 utf8_from_utf32_single(U8 *buffer, U32 character); + +//////////////////////////////// +//~ rjf: Unicode String Conversions + +internal String8 str8_from_16(Arena *arena, String16 in); +internal String16 str16_from_8(Arena *arena, String8 in); +internal String8 str8_from_32(Arena *arena, String32 in); +internal String32 str32_from_8(Arena *arena, String8 in); + +//////////////////////////////// +//~ rjf: Basic Types & Space Enum -> String Conversions + +internal String8 string_from_dimension(Dimension dimension); +internal String8 string_from_side(Side side); +internal String8 string_from_operating_system(OperatingSystem os); +internal String8 string_from_architecture(Architecture arch); + +//////////////////////////////// +//~ rjf: Time Types -> String + +internal String8 string_from_week_day(WeekDay week_day); +internal String8 string_from_month(Month month); +internal String8 push_date_time_string(Arena *arena, DateTime *date_time); +internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time); +internal String8 string_from_elapsed_time(Arena *arena, DateTime dt); + +//////////////////////////////// +//~ rjf: String <-> Color + +internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba); +internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string); + +//////////////////////////////// +//~ NOTE(allen): Serialization Helpers + +internal void str8_serial_begin(Arena *arena, String8List *srl); +internal String8 str8_serial_end(Arena *arena, String8List *srl); +internal void str8_serial_write_to_dst(String8List *srl, void *out); +internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 align); +internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size); +internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size); +internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first); +internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x); +internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x); +internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x); +internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x); +internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str); +internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str); +#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count)) +#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1) + +//////////////////////////////// +//~ rjf: Deserialization Helpers + +internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity); +internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val); +internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out); +internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out); +internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out); +#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr))) +#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr))) + +#endif // BASE_STRING_H diff --git a/src/metagen/metagen_base/metagen_base_thread_context.c b/src/metagen/metagen_base/metagen_base_thread_context.c new file mode 100644 index 00000000..1efd6e60 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_thread_context.c @@ -0,0 +1,78 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Thread Context Functions + +C_LINKAGE thread_static TCTX* tctx_thread_local; +#if !SUPPLEMENT_UNIT +C_LINKAGE thread_static TCTX* tctx_thread_local = 0; +#endif + +internal void +tctx_init_and_equip(TCTX *tctx){ + MemoryZeroStruct(tctx); + Arena **arena_ptr = tctx->arenas; + for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){ + *arena_ptr = arena_alloc(); + } + tctx_thread_local = tctx; +} + +internal TCTX* +tctx_get_equipped(void){ + return(tctx_thread_local); +} + +internal Arena* +tctx_get_scratch(Arena **conflicts, U64 count){ + TCTX *tctx = tctx_get_equipped(); + + Arena *result = 0; + Arena **arena_ptr = tctx->arenas; + for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){ + Arena **conflict_ptr = conflicts; + B32 has_conflict = 0; + for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){ + if (*arena_ptr == *conflict_ptr){ + has_conflict = 1; + break; + } + } + if (!has_conflict){ + result = *arena_ptr; + break; + } + } + + return(result); +} + +internal void +tctx_set_thread_name(String8 string){ + TCTX *tctx = tctx_get_equipped(); + U64 size = ClampTop(string.size, sizeof(tctx->thread_name)); + MemoryCopy(tctx->thread_name, string.str, size); + tctx->thread_name_size = size; +} + +internal String8 +tctx_get_thread_name(void){ + TCTX *tctx = tctx_get_equipped(); + String8 result = str8(tctx->thread_name, tctx->thread_name_size); + return(result); +} + +internal void +tctx_write_srcloc(char *file_name, U64 line_number){ + TCTX *tctx = tctx_get_equipped(); + tctx->file_name = file_name; + tctx->line_number = line_number; +} + +internal void +tctx_read_srcloc(char **file_name, U64 *line_number){ + TCTX *tctx = tctx_get_equipped(); + *file_name = tctx->file_name; + *line_number = tctx->line_number; +} diff --git a/src/metagen/metagen_base/metagen_base_thread_context.h b/src/metagen/metagen_base/metagen_base_thread_context.h new file mode 100644 index 00000000..ce05d47f --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_thread_context.h @@ -0,0 +1,40 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_THREAD_CONTEXT_H +#define BASE_THREAD_CONTEXT_H + +//////////////////////////////// +// NOTE(allen): Thread Context + +typedef struct TCTX TCTX; +struct TCTX +{ + Arena *arenas[2]; + + U8 thread_name[32]; + U64 thread_name_size; + + char *file_name; + U64 line_number; +}; + +//////////////////////////////// +// NOTE(allen): Thread Context Functions + +internal void tctx_init_and_equip(TCTX *tctx); +internal TCTX* tctx_get_equipped(void); + +internal Arena* tctx_get_scratch(Arena **conflicts, U64 count); + +internal void tctx_set_thread_name(String8 name); +internal String8 tctx_get_thread_name(void); + +internal void tctx_write_srcloc(char *file_name, U64 line_number); +internal void tctx_read_srcloc(char **file_name, U64 *line_number); +#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__) + +#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count))) +#define scratch_end(scratch) temp_end(scratch) + +#endif //BASE_THREAD_CONTEXT_H diff --git a/src/metagen/metagen_base/metagen_base_types.c b/src/metagen/metagen_base/metagen_base_types.c new file mode 100644 index 00000000..9627f478 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_types.c @@ -0,0 +1,454 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ Safe Casts + +internal U16 +safe_cast_u16(U32 x) +{ + AssertAlways(x <= max_U16); + U16 result = (U16)x; + return result; +} + +internal U32 +safe_cast_u32(U64 x) +{ + AssertAlways(x <= max_U32); + U32 result = (U32)x; + return result; +} + +internal S32 +safe_cast_s32(S64 x) +{ + AssertAlways(x <= max_S32); + S32 result = (S32)x; + return result; +} + +//////////////////////////////// +//~ rjf: Large Base Type Functions + +internal U128 +u128_zero(void) +{ + U128 v = {0}; + return v; +} + +internal U128 +u128_make(U64 v0, U64 v1) +{ + U128 v = {v0, v1}; + return v; +} + +internal B32 +u128_match(U128 a, U128 b) +{ + return MemoryMatchStruct(&a, &b); +} + +//////////////////////////////// +//~ rjf: Bit Patterns + +internal U32 +u32_from_u64_saturate(U64 x){ + U32 x32 = (x > max_U32)?max_U32:(U32)x; + return(x32); +} + +internal U64 +u64_up_to_pow2(U64 x){ + if (x == 0){ + x = 1; + } + else{ + x -= 1; + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + x |= (x >> 32); + x += 1; + } + return(x); +} + +internal S32 +extend_sign32(U32 x, U32 size){ + U32 high_bit = size * 8; + U32 shift = 32 - high_bit; + S32 result = ((S32)x << shift) >> shift; + return result; +} + +internal S64 +extend_sign64(U64 x, U64 size){ + U64 high_bit = size * 8; + U64 shift = 64 - high_bit; + S64 result = ((S64)x << shift) >> shift; + return result; +} + +internal F32 +inf32(void){ + union { U32 u; F32 f; } x; + x.u = exponent32; + return(x.f); +} + +internal F32 +neg_inf32(void){ + union { U32 u; F32 f; } x; + x.u = sign32 | exponent32; + return(x.f); +} + +internal U16 +bswap_u16(U16 x) +{ + U16 result = (((x & 0xFF00) >> 8) | + ((x & 0x00FF) << 8)); + return result; +} + +internal U32 +bswap_u32(U32 x) +{ + U32 result = (((x & 0xFF000000) >> 24) | + ((x & 0x00FF0000) >> 8) | + ((x & 0x0000FF00) << 8) | + ((x & 0x000000FF) << 24)); + return result; +} + +internal U64 +bswap_u64(U64 x) +{ + // TODO(nick): naive bswap, replace with something that is faster like an intrinsic + U64 result = (((x & 0xFF00000000000000ULL) >> 56) | + ((x & 0x00FF000000000000ULL) >> 40) | + ((x & 0x0000FF0000000000ULL) >> 24) | + ((x & 0x000000FF00000000ULL) >> 8) | + ((x & 0x00000000FF000000ULL) << 8) | + ((x & 0x0000000000FF0000ULL) << 24) | + ((x & 0x000000000000FF00ULL) << 40) | + ((x & 0x00000000000000FFULL) << 56)); + return result; +} + +//////////////////////////////// +//~ rjf: Enum -> Sign + +internal S32 +sign_from_side_S32(Side side){ + return((side == Side_Min)?-1:1); +} + +internal F32 +sign_from_side_F32(Side side){ + return((side == Side_Min)?-1.f:1.f); +} + +//////////////////////////////// +//~ rjf: Memory Functions + +internal B32 +memory_is_zero(void *ptr, U64 size){ + B32 result = 1; + + // break down size + U64 extra = (size&0x7); + U64 count8 = (size >> 3); + + // check with 8-byte stride + U64 *p64 = (U64*)ptr; + if(result) + { + for (U64 i = 0; i < count8; i += 1, p64 += 1){ + if (*p64 != 0){ + result = 0; + goto done; + } + } + } + + // check extra + if(result) + { + U8 *p8 = (U8*)p64; + for (U64 i = 0; i < extra; i += 1, p8 += 1){ + if (*p8 != 0){ + result = 0; + goto done; + } + } + } + + done:; + return(result); +} + +//////////////////////////////// +//~ rjf: Text 2D Coordinate/Range Functions + +internal TxtPt +txt_pt(S64 line, S64 column) +{ + TxtPt p = {0}; + p.line = line; + p.column = column; + return p; +} + +internal B32 +txt_pt_match(TxtPt a, TxtPt b) +{ + return a.line == b.line && a.column == b.column; +} + +internal B32 +txt_pt_less_than(TxtPt a, TxtPt b) +{ + B32 result = 0; + if(a.line < b.line) + { + result = 1; + } + else if(a.line == b.line) + { + result = a.column < b.column; + } + return result; +} + +internal TxtPt +txt_pt_min(TxtPt a, TxtPt b) +{ + TxtPt result = b; + if(txt_pt_less_than(a, b)) + { + result = a; + } + return result; +} + +internal TxtPt +txt_pt_max(TxtPt a, TxtPt b) +{ + TxtPt result = a; + if(txt_pt_less_than(a, b)) + { + result = b; + } + return result; +} + +internal TxtRng +txt_rng(TxtPt min, TxtPt max) +{ + TxtRng range = {0}; + if(txt_pt_less_than(min, max)) + { + range.min = min; + range.max = max; + } + else + { + range.min = max; + range.max = min; + } + return range; +} + +internal TxtRng +txt_rng_intersect(TxtRng a, TxtRng b) +{ + TxtRng result = {0}; + result.min = txt_pt_max(a.min, b.min); + result.max = txt_pt_min(a.max, b.max); + if(txt_pt_less_than(result.max, result.min)) + { + MemoryZeroStruct(&result); + } + return result; +} + +internal TxtRng +txt_rng_union(TxtRng a, TxtRng b) +{ + TxtRng result = {0}; + result.min = txt_pt_min(a.min, b.min); + result.max = txt_pt_max(a.max, b.max); + return result; +} + +//////////////////////////////// +//~ rjf: Toolchain/Environment Enum Functions + +internal U64 +bit_size_from_arch(Architecture arch) +{ + // TODO(rjf): metacode + U64 arch_bitsize = 0; + switch(arch) + { + case Architecture_x64: arch_bitsize = 64; break; + case Architecture_x86: arch_bitsize = 32; break; + case Architecture_arm64: arch_bitsize = 64; break; + case Architecture_arm32: arch_bitsize = 32; break; + default: break; + } + return arch_bitsize; +} + +internal U64 +max_instruction_size_from_arch(Architecture arch) +{ + // TODO(rjf): make this real + return 64; +} + +internal OperatingSystem +operating_system_from_context(void){ + OperatingSystem os = OperatingSystem_Null; +#if OS_WINDOWS + os = OperatingSystem_Windows; +#elif OS_LINUX + os = OperatingSystem_Linux; +#elif OS_MAC + os = OperatingSystem_Mac; +#endif + return os; +} + +internal Architecture +architecture_from_context(void){ + Architecture arch = Architecture_Null; +#if ARCH_X64 + arch = Architecture_x64; +#elif ARCH_X86 + arch = Architecture_x86; +#elif ARCH_ARM64 + arch = Architecture_arm64; +#elif ARCH_ARM32 + arch = Architecture_arm32; +#endif + return arch; +} + +internal Compiler +compiler_from_context(void){ + Compiler compiler = Compiler_Null; +#if COMPILER_CL + compiler = Compiler_cl; +#elif COMPILER_GCC + compiler = Compiler_gcc; +#elif COMPILER_CLANG + compiler = Compiler_clang; +#endif + return compiler; +} + +//////////////////////////////// +//~ rjf: Time Functions + +internal DenseTime +dense_time_from_date_time(DateTime date_time){ + DenseTime result = 0; + result += date_time.year; + result *= 12; + result += date_time.mon; + result *= 31; + result += date_time.day; + result *= 24; + result += date_time.hour; + result *= 60; + result += date_time.min; + result *= 61; + result += date_time.sec; + result *= 1000; + result += date_time.msec; + return(result); +} + +internal DateTime +date_time_from_dense_time(DenseTime time){ + DateTime result = {0}; + result.msec = time%1000; + time /= 1000; + result.sec = time%61; + time /= 61; + result.min = time%60; + time /= 60; + result.hour = time%24; + time /= 24; + result.day = time%31; + time /= 31; + result.mon = time%12; + time /= 12; + Assert(time <= max_U32); + result.year = (U32)time; + return(result); +} + +internal DateTime +date_time_from_micro_seconds(U64 time){ + DateTime result = {0}; + result.micro_sec = time%1000; + time /= 1000; + result.msec = time%1000; + time /= 1000; + result.sec = time%60; + time /= 60; + result.min = time%60; + time /= 60; + result.hour = time%24; + time /= 24; + result.day = time%31; + time /= 31; + result.mon = time%12; + time /= 12; + Assert(time <= max_U32); + result.year = (U32)time; + return(result); +} + +//////////////////////////////// +//~ rjf: Non-Fancy Ring Buffer Reads/Writes + +internal U64 +ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size) +{ + Assert(src_data_size <= ring_size); + { + U64 ring_off = ring_pos%ring_size; + U64 bytes_before_split = ring_size-ring_off; + U64 pre_split_bytes = Min(bytes_before_split, src_data_size); + U64 pst_split_bytes = src_data_size-pre_split_bytes; + void *pre_split_data = src_data; + void *pst_split_data = ((U8 *)src_data + pre_split_bytes); + MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes); + MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes); + } + return src_data_size; +} + +internal U64 +ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size) +{ + Assert(read_size <= ring_size); + { + U64 ring_off = ring_pos%ring_size; + U64 bytes_before_split = ring_size-ring_off; + U64 pre_split_bytes = Min(bytes_before_split, read_size); + U64 pst_split_bytes = read_size-pre_split_bytes; + MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes); + MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes); + } + return read_size; +} diff --git a/src/metagen/metagen_base/metagen_base_types.h b/src/metagen/metagen_base/metagen_base_types.h new file mode 100644 index 00000000..d006a541 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_types.h @@ -0,0 +1,681 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_TYPES_H +#define BASE_TYPES_H + +//////////////////////////////// +//~ rjf: Foreign Includes + +#include +#include +#include +#include +#include + +//////////////////////////////// +//~ rjf: Build Configuration + +#if !defined(ENABLE_DEV) +# define ENABLE_DEV 0 +#endif + +#if !defined(SUPPLEMENT_UNIT) +# define SUPPLEMENT_UNIT 0 +#endif + +//////////////////////////////// +//~ rjf: Codebase Keywords + +#define internal static +#define global static +#define local_persist static + +#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS) +# pragma section(".rdata$", read) +# define read_only __declspec(allocate(".rdata$")) +#elif (COMPILER_CLANG && OS_LINUX) +# define read_only __attribute__((section(".rodata"))) +#else +// NOTE(rjf): I don't know of a useful way to do this in GCC land. +// __attribute__((section(".rodata"))) looked promising, but it introduces a +// strange warning about malformed section attributes, and it doesn't look +// like writing to that section reliably produces access violations, strangely +// enough. (It does on Clang) +# define read_only +#endif + +//////////////////////////////// +//~ rjf: Memory Operation Macros + +#define MemoryCopy(dst, src, size) memmove((dst), (src), (size)) +#define MemorySet(dst, byte, size) memset((dst), (byte), (size)) +#define MemoryCompare(a, b, size) memcmp((a), (b), (size)) +#define MemoryStrlen(ptr) strlen(ptr) + +#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d))) +#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d)) +#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c)) + +#define MemoryZero(s,z) memset((s),0,(z)) +#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s))) +#define MemoryZeroArray(a) MemoryZero((a),sizeof(a)) +#define MemoryZeroTyped(m,c) MemoryZero((m),sizeof(*(m))*(c)) + +#define MemoryMatch(a,b,z) (MemoryCompare((a),(b),(z)) == 0) +#define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a))) +#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a)) + +#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) ) +#define MemoryConsume(T,p,e) \ +( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) ) + +//////////////////////////////// +//~ rjf: Units + +#define KB(n) (((U64)(n)) << 10) +#define MB(n) (((U64)(n)) << 20) +#define GB(n) (((U64)(n)) << 30) +#define TB(n) (((U64)(n)) << 40) +#define Thousand(n) ((n)*1000) +#define Million(n) ((n)*1000000) +#define Billion(n) ((n)*1000000000) + +//////////////////////////////// +//~ rjf: Asserts + +#if COMPILER_CL +# define Trap() __debugbreak() +#elif COMPILER_CLANG || COMPILER_GCC +# define Trap() __builtin_trap() +# else +# error "undefined trap" +#endif + +#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0) +#if !defined(NDEBUG) +# define Assert(x) AssertAlways(x) +#else +# define Assert(x) (void)(x) +#endif +#define AssertImplies(a,b) Assert(!(a) || b) +#define AssertIff(a,b) Assert(!!(a) == !!(b)) +#define InvalidPath Assert(!"Invalid Path!") +#define NotImplemented Assert(!"Not Implemented!") + +#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1] + +//////////////////////////////// +//~ rjf: Branch Predictor Hints + +#if defined(__clang__) +# define Expect(expr, val) __builtin_expect((expr), (val)) +#else +# define Expect(expr, val) (expr) +#endif + +#define Likely(expr) Expect(expr,1) +#define Unlikely(expr) Expect(expr,0) + +//////////////////////////////// +//~ rjf: Misc. Helper Macros + +#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) + +#define Stmnt(S) do{ S }while(0) + +#define Stringify_(S) #S +#define Stringify(S) Stringify_(S) + +#define Glue_(A,B) A##B +#define Glue(A,B) Glue_(A,B) + +#define Min(A,B) ( ((A)<(B))?(A):(B) ) +#define Max(A,B) ( ((A)>(B))?(A):(B) ) + +#define ClampTop(A,X) Min(A,X) +#define ClampBot(X,B) Max(X,B) +#define Clamp(A,X,B) ( ((X)<(A))?(A):((X)>(B))?(B):(X) ) + +#define PtrClampTop(A,X) ClampTop(A,X) +#define PtrClampBot(X,B) ClampBot(X,B) +#define PtrClamp(A,X,B) Clamp(A,X,B) + +#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b)) + +#define Swap(T,a,b) Stmnt( T t__ = a; a = b; b = t__; ) + +#if ARCH_64BIT +# define IntFromPtr(ptr) ((U64)(ptr)) +#elif ARCH_32BIT +# define IntFromPtr(ptr) ((U32)(ptr)) +#else +# error missing ptr cast for this architecture +#endif + +#define PtrFromInt(i) (void*)((U8*)0 + (i)) + +#define Member(T,m) (((T*)0)->m) +#define OffsetOf(T,m) IntFromPtr(&Member(T,m)) +#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off))) +#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m)) + +#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b)); +#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1))) +#define AlignDownPow2(x,b) ((x)&(~((b) - 1))) +#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1)) +#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0) +#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0) + +#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end)) +#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end)) + +#define B8 S8 +#define B32 rrbool + +#if LANG_CPP +# define zero_struct {} +#else +# define zero_struct {0} +#endif + +#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015 +# define this_function_name "unknown" +#else +# define this_function_name __func__ +#endif + +#if LANG_CPP +# define C_LINKAGE_BEGIN extern "C"{ +# define C_LINKAGE_END } +# define C_LINKAGE extern "C" +#else +# define C_LINKAGE_BEGIN +# define C_LINKAGE_END +# define C_LINKAGE +#endif + +#if COMPILER_CL +# define thread_static __declspec(thread) +#elif COMPILER_CLANG || COMPILER_GCC +# define thread_static __thread +#endif + +#if OS_WINDOWS +# define shared_function C_LINKAGE __declspec(dllexport) +#else +# define shared_function C_LINKAGE +#endif + +//////////////////////////////// +//~ ASAN + +#if COMPILER_CL +# if defined(__SANITIZE_ADDRESS__) +# define ASAN_ENABLED 1 +# endif +# define NO_ASAN __declspec(no_sanitize_address) +#elif COMPILER_CLANG +# if defined(__has_feature) +# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define ASAN_ENABLED 1 +# endif +# endif +# define NO_ASAN __attribute__((no_sanitize("address"))) +#else +# error "NO_ASAN is not defined" +#endif + +#if ASAN_ENABLED + +#pragma comment(lib, "clang_rt.asan-x86_64.lib") + +C_LINKAGE_BEGIN +void __asan_poison_memory_region(void const volatile *addr, size_t size); +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +C_LINKAGE_END + +# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size)) +# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size)) +#else +# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) +# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) + +#endif + +//////////////////////////////// +//~ rjf: Base Types + +typedef uint8_t U8; +typedef uint16_t U16; +typedef uint32_t U32; +typedef uint64_t U64; +typedef int8_t S8; +typedef int16_t S16; +typedef int32_t S32; +typedef int64_t S64; +typedef S8 B8; +typedef S16 B16; +typedef S32 B32; +typedef S64 B64; +typedef float F32; +typedef double F64; + +//////////////////////////////// +//~ rjf: Large Base Types + +typedef struct U128 U128; +struct U128 +{ + U64 u64[2]; +}; + +//////////////////////////////// +//~ rjf: Basic Types & Spaces + +typedef void VoidProc(void); + +typedef enum Dimension +{ + Dimension_X, + Dimension_Y, + Dimension_Z, + Dimension_W, +} +Dimension; + +typedef enum Side +{ + Side_Invalid = -1, + Side_Min, + Side_Max, + Side_COUNT, +} +Side; +#define side_flip(s) ((Side)(!(s))) + +typedef enum Axis2 +{ + Axis2_Invalid = -1, + Axis2_X, + Axis2_Y, + Axis2_COUNT, +} +Axis2; +#define axis2_flip(a) ((Axis2)(!(a))) + +typedef enum Corner +{ + Corner_Invalid = -1, + Corner_00, + Corner_01, + Corner_10, + Corner_11, + Corner_COUNT +} +Corner; + +//////////////////////////////// +//~ rjf: Toolchain/Environment Enums + +typedef enum OperatingSystem +{ + OperatingSystem_Null, + OperatingSystem_Windows, + OperatingSystem_Linux, + OperatingSystem_Mac, + OperatingSystem_COUNT, +} +OperatingSystem; + +typedef enum Architecture +{ + Architecture_Null, + Architecture_x64, + Architecture_x86, + Architecture_arm64, + Architecture_arm32, + Architecture_COUNT, +} +Architecture; + +typedef enum Compiler +{ + Compiler_Null, + Compiler_cl, + Compiler_gcc, + Compiler_clang, + Compiler_COUNT, +} +Compiler; + +//////////////////////////////// +//~ rjf: Text 2D Coordinates & Ranges + +typedef struct TxtPt TxtPt; +struct TxtPt +{ + S64 line; + S64 column; +}; + +typedef struct TxtRng TxtRng; +struct TxtRng +{ + TxtPt min; + TxtPt max; +}; + +//////////////////////////////// +//~ NOTE(allen): Constants + +global U32 sign32 = 0x80000000; +global U32 exponent32 = 0x7F800000; +global U32 mantissa32 = 0x007FFFFF; + +global F32 big_golden32 = 1.61803398875f; +global F32 small_golden32 = 0.61803398875f; + +global F32 pi32 = 3.1415926535897f; + +global F64 machine_epsilon64 = 4.94065645841247e-324; + +global U64 max_U64 = 0xffffffffffffffffull; +global U32 max_U32 = 0xffffffff; +global U16 max_U16 = 0xffff; +global U8 max_U8 = 0xff; + +global S64 max_S64 = (S64)0x7fffffffffffffffull; +global S32 max_S32 = (S32)0x7fffffff; +global S16 max_S16 = (S16)0x7fff; +global S8 max_S8 = (S8)0x7f; + +global S64 min_S64 = (S64)0xffffffffffffffffull; +global S32 min_S32 = (S32)0xffffffff; +global S16 min_S16 = (S16)0xffff; +global S8 min_S8 = (S8)0xff; + +global const U32 bitmask1 = 0x00000001; +global const U32 bitmask2 = 0x00000003; +global const U32 bitmask3 = 0x00000007; +global const U32 bitmask4 = 0x0000000f; +global const U32 bitmask5 = 0x0000001f; +global const U32 bitmask6 = 0x0000003f; +global const U32 bitmask7 = 0x0000007f; +global const U32 bitmask8 = 0x000000ff; +global const U32 bitmask9 = 0x000001ff; +global const U32 bitmask10 = 0x000003ff; +global const U32 bitmask11 = 0x000007ff; +global const U32 bitmask12 = 0x00000fff; +global const U32 bitmask13 = 0x00001fff; +global const U32 bitmask14 = 0x00003fff; +global const U32 bitmask15 = 0x00007fff; +global const U32 bitmask16 = 0x0000ffff; +global const U32 bitmask17 = 0x0001ffff; +global const U32 bitmask18 = 0x0003ffff; +global const U32 bitmask19 = 0x0007ffff; +global const U32 bitmask20 = 0x000fffff; +global const U32 bitmask21 = 0x001fffff; +global const U32 bitmask22 = 0x003fffff; +global const U32 bitmask23 = 0x007fffff; +global const U32 bitmask24 = 0x00ffffff; +global const U32 bitmask25 = 0x01ffffff; +global const U32 bitmask26 = 0x03ffffff; +global const U32 bitmask27 = 0x07ffffff; +global const U32 bitmask28 = 0x0fffffff; +global const U32 bitmask29 = 0x1fffffff; +global const U32 bitmask30 = 0x3fffffff; +global const U32 bitmask31 = 0x7fffffff; +global const U32 bitmask32 = 0xffffffff; + +global const U64 bitmask33 = 0x00000001ffffffffull; +global const U64 bitmask34 = 0x00000003ffffffffull; +global const U64 bitmask35 = 0x00000007ffffffffull; +global const U64 bitmask36 = 0x0000000fffffffffull; +global const U64 bitmask37 = 0x0000001fffffffffull; +global const U64 bitmask38 = 0x0000003fffffffffull; +global const U64 bitmask39 = 0x0000007fffffffffull; +global const U64 bitmask40 = 0x000000ffffffffffull; +global const U64 bitmask41 = 0x000001ffffffffffull; +global const U64 bitmask42 = 0x000003ffffffffffull; +global const U64 bitmask43 = 0x000007ffffffffffull; +global const U64 bitmask44 = 0x00000fffffffffffull; +global const U64 bitmask45 = 0x00001fffffffffffull; +global const U64 bitmask46 = 0x00003fffffffffffull; +global const U64 bitmask47 = 0x00007fffffffffffull; +global const U64 bitmask48 = 0x0000ffffffffffffull; +global const U64 bitmask49 = 0x0001ffffffffffffull; +global const U64 bitmask50 = 0x0003ffffffffffffull; +global const U64 bitmask51 = 0x0007ffffffffffffull; +global const U64 bitmask52 = 0x000fffffffffffffull; +global const U64 bitmask53 = 0x001fffffffffffffull; +global const U64 bitmask54 = 0x003fffffffffffffull; +global const U64 bitmask55 = 0x007fffffffffffffull; +global const U64 bitmask56 = 0x00ffffffffffffffull; +global const U64 bitmask57 = 0x01ffffffffffffffull; +global const U64 bitmask58 = 0x03ffffffffffffffull; +global const U64 bitmask59 = 0x07ffffffffffffffull; +global const U64 bitmask60 = 0x0fffffffffffffffull; +global const U64 bitmask61 = 0x1fffffffffffffffull; +global const U64 bitmask62 = 0x3fffffffffffffffull; +global const U64 bitmask63 = 0x7fffffffffffffffull; +global const U64 bitmask64 = 0xffffffffffffffffull; + +global const U32 bit1 = (1<<0); +global const U32 bit2 = (1<<1); +global const U32 bit3 = (1<<2); +global const U32 bit4 = (1<<3); +global const U32 bit5 = (1<<4); +global const U32 bit6 = (1<<5); +global const U32 bit7 = (1<<6); +global const U32 bit8 = (1<<7); +global const U32 bit9 = (1<<8); +global const U32 bit10 = (1<<9); +global const U32 bit11 = (1<<10); +global const U32 bit12 = (1<<11); +global const U32 bit13 = (1<<12); +global const U32 bit14 = (1<<13); +global const U32 bit15 = (1<<14); +global const U32 bit16 = (1<<15); +global const U32 bit17 = (1<<16); +global const U32 bit18 = (1<<17); +global const U32 bit19 = (1<<18); +global const U32 bit20 = (1<<19); +global const U32 bit21 = (1<<20); +global const U32 bit22 = (1<<21); +global const U32 bit23 = (1<<22); +global const U32 bit24 = (1<<23); +global const U32 bit25 = (1<<24); +global const U32 bit26 = (1<<25); +global const U32 bit27 = (1<<26); +global const U32 bit28 = (1<<27); +global const U32 bit29 = (1<<28); +global const U32 bit30 = (1<<29); +global const U32 bit31 = (1<<30); +global const U32 bit32 = (1<<31); + +global const U64 bit33 = (1ull<<32); +global const U64 bit34 = (1ull<<33); +global const U64 bit35 = (1ull<<34); +global const U64 bit36 = (1ull<<35); +global const U64 bit37 = (1ull<<36); +global const U64 bit38 = (1ull<<37); +global const U64 bit39 = (1ull<<38); +global const U64 bit40 = (1ull<<39); +global const U64 bit41 = (1ull<<40); +global const U64 bit42 = (1ull<<41); +global const U64 bit43 = (1ull<<42); +global const U64 bit44 = (1ull<<43); +global const U64 bit45 = (1ull<<44); +global const U64 bit46 = (1ull<<45); +global const U64 bit47 = (1ull<<46); +global const U64 bit48 = (1ull<<47); +global const U64 bit49 = (1ull<<48); +global const U64 bit50 = (1ull<<49); +global const U64 bit51 = (1ull<<50); +global const U64 bit52 = (1ull<<51); +global const U64 bit53 = (1ull<<52); +global const U64 bit54 = (1ull<<53); +global const U64 bit55 = (1ull<<54); +global const U64 bit56 = (1ull<<55); +global const U64 bit57 = (1ull<<56); +global const U64 bit58 = (1ull<<57); +global const U64 bit59 = (1ull<<58); +global const U64 bit60 = (1ull<<59); +global const U64 bit61 = (1ull<<60); +global const U64 bit62 = (1ull<<61); +global const U64 bit63 = (1ull<<62); +global const U64 bit64 = (1ull<<63); + +//////////////////////////////// +//~ allen: Time + +typedef enum WeekDay +{ + WeekDay_Sun, + WeekDay_Mon, + WeekDay_Tue, + WeekDay_Wed, + WeekDay_Thu, + WeekDay_Fri, + WeekDay_Sat, + WeekDay_COUNT, +} +WeekDay; + +typedef enum Month +{ + Month_Jan, + Month_Feb, + Month_Mar, + Month_Apr, + Month_May, + Month_Jun, + Month_Jul, + Month_Aug, + Month_Sep, + Month_Oct, + Month_Nov, + Month_Dec, + Month_COUNT, +} +Month; + +typedef struct DateTime DateTime; +struct DateTime +{ + U16 micro_sec; // [0,999] + U16 msec; // [0,999] + U16 sec; // [0,60] + U16 min; // [0,59] + U16 hour; // [0,24] + U16 day; // [0,30] + union{ + WeekDay week_day; + U32 wday; + }; + union{ + Month month; + U32 mon; + }; + U32 year; // 1 = 1 CE, 0 = 1 BC +}; + +typedef U64 DenseTime; + +//////////////////////////////// +//~ allen: Files + +typedef U32 FilePropertyFlags; +enum +{ + FilePropertyFlag_IsFolder = (1 << 0), +}; + +typedef struct FileProperties FileProperties; +struct FileProperties +{ + U64 size; + DenseTime modified; + DenseTime created; + FilePropertyFlags flags; +}; + +//////////////////////////////// +//~ Safe Casts + +internal U16 safe_cast_u16(U32 x); +internal U32 safe_cast_u32(U64 x); +internal S32 safe_cast_s32(S64 x); + +//////////////////////////////// +//~ rjf: Large Base Type Functions + +internal U128 u128_zero(void); +internal U128 u128_make(U64 v0, U64 v1); +internal B32 u128_match(U128 a, U128 b); + +//////////////////////////////// +//~ rjf: Bit Patterns + +internal U32 u32_from_u64_saturate(U64 x); +internal U64 u64_up_to_pow2(U64 x); +internal S32 extend_sign32(U32 x, U32 size); +internal S64 extend_sign64(U64 x, U64 size); + +internal F32 inf32(void); +internal F32 neg_inf32(void); + +internal U16 bswap_u16(U16 x); +internal U32 bswap_u32(U32 x); +internal U64 bswap_u64(U64 x); + +//////////////////////////////// +//~ rjf: Enum -> Sign + +internal S32 sign_from_side_S32(Side side); +internal F32 sign_from_side_F32(Side side); + +//////////////////////////////// +//~ rjf: Memory Functions + +internal B32 memory_is_zero(void *ptr, U64 size); + +//////////////////////////////// +//~ rjf: Text 2D Coordinate/Range Functions + +internal TxtPt txt_pt(S64 line, S64 column); +internal B32 txt_pt_match(TxtPt a, TxtPt b); +internal B32 txt_pt_less_than(TxtPt a, TxtPt b); +internal TxtPt txt_pt_min(TxtPt a, TxtPt b); +internal TxtPt txt_pt_max(TxtPt a, TxtPt b); +internal TxtRng txt_rng(TxtPt min, TxtPt max); +internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b); +internal TxtRng txt_rng_union(TxtRng a, TxtRng b); + +//////////////////////////////// +//~ rjf: Toolchain/Environment Enum Functions + +internal U64 bit_size_from_arch(Architecture arch); +internal U64 max_instruction_size_from_arch(Architecture arch); + +internal OperatingSystem operating_system_from_context(void); +internal Architecture architecture_from_context(void); +internal Compiler compiler_from_context(void); + +//////////////////////////////// +//~ rjf: Time Functions + +internal DenseTime dense_time_from_date_time(DateTime date_time); +internal DateTime date_time_from_dense_time(DenseTime time); +internal DateTime date_time_from_micro_seconds(U64 time); + +//////////////////////////////// +//~ rjf: Non-Fancy Ring Buffer Reads/Writes + +internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size); +internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size); +#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr))) +#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr))) + +#endif // BASE_TYPES_H diff --git a/src/metagen/metagen_main.c b/src/metagen/metagen_main.c new file mode 100644 index 00000000..c6a501a6 --- /dev/null +++ b/src/metagen/metagen_main.c @@ -0,0 +1,412 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Includes + +//- rjf: headers +#include "metagen/metagen_base/metagen_base_inc.h" +#include "metagen/metagen_os/metagen_os_inc.h" +#include "mdesk/mdesk.h" +#include "metagen.h" + +//- rjf: impls +#include "metagen/metagen_base/metagen_base_inc.c" +#include "metagen/metagen_os/metagen_os_inc.c" +#include "mdesk/mdesk.c" +#include "metagen.c" + +//////////////////////////////// +//~ rjf: Entry Point + +int main(int argument_count, char **arguments) +{ + local_persist TCTX main_tctx = {0}; + tctx_init_and_equip(&main_tctx); + os_init(argument_count, arguments); + + ////////////////////////////// + //- rjf: set up state + // + mg_arena = arena_alloc__sized(GB(64), MB(64)); + mg_state = push_array(mg_arena, MG_State, 1); + mg_state->slots_count = 256; + mg_state->slots = push_array(mg_arena, MG_LayerSlot, mg_state->slots_count); + + ////////////////////////////// + //- rjf: extract paths + // + String8 build_dir_path = os_string_from_system_path(mg_arena, OS_SystemPath_Binary); + String8 project_dir_path = str8_chop_last_slash(build_dir_path); + String8 code_dir_path = push_str8f(mg_arena, "%S/src", project_dir_path); + + ////////////////////////////// + //- rjf: search code directories for all files to consider + // + String8List file_paths = {0}; + DeferLoop(printf("searching %.*s...", str8_varg(code_dir_path)), printf(" %i files found\n", (int)file_paths.node_count)) + { + typedef struct Task Task; + struct Task + { + Task *next; + String8 path; + }; + Task start_task = {0, code_dir_path}; + Task *first_task = &start_task; + Task *last_task = &start_task; + for(Task *task = first_task; task != 0; task = task->next) + { + OS_FileIter *it = os_file_iter_begin(mg_arena, task->path, 0); + for(OS_FileInfo info = {0}; os_file_iter_next(mg_arena, it, &info);) + { + String8 file_path = push_str8f(mg_arena, "%S/%S", task->path, info.name); + if(info.props.flags & FilePropertyFlag_IsFolder) + { + Task *next_task = push_array(mg_arena, Task, 1); + SLLQueuePush(first_task, last_task, next_task); + next_task->path = file_path; + } + else + { + str8_list_push(mg_arena, &file_paths, file_path); + } + } + os_file_iter_end(it); + } + } + + ////////////////////////////// + //- rjf: parse all metadesk files + // + MG_FileParseList parses = {0}; + DeferLoop(printf("parsing metadesk..."), printf(" %i metadesk files parsed\n", (int)parses.count)) + { + for(String8Node *n = file_paths.first; n != 0; n = n->next) + { + String8 file_path = n->string; + String8 file_ext = str8_skip_last_dot(file_path); + if(str8_match(file_ext, str8_lit("mc"), 0)) + { + String8 data = os_data_from_file_path(mg_arena, file_path); + MD_TokenizeResult tokenize = md_tokenize_from_text(mg_arena, data); + MD_ParseResult parse = md_parse_from_text_tokens(mg_arena, file_path, data, tokenize.tokens); + MG_FileParseNode *parse_n = push_array(mg_arena, MG_FileParseNode, 1); + SLLQueuePush(parses.first, parses.last, parse_n); + parse_n->v.root = parse.root; + parses.count += 1; + for(MD_Msg *msg = parse.msgs.first; msg != 0; msg = msg->next) + { + TxtPt pt = mg_txt_pt_from_string_off(data, msg->node->src_offset); + // TODO(rjf): error kind display & locations + fprintf(stderr, "%.*s:%i:%i %.*s\n", str8_varg(file_path), (int)pt.line, (int)pt.column, str8_varg(msg->string)); + } + } + } + } + + ////////////////////////////// + //- rjf: gather tables + // + MG_Map table_grid_map = mg_push_map(mg_arena, 1024); + MG_Map table_col_map = mg_push_map(mg_arena, 1024); + U64 table_count = 0; + DeferLoop(printf("gathering tables..."), printf(" %i tables found\n", (int)table_count)) + { + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + MD_Node *table_tag = md_tag_from_string(node, str8_lit("table"), 0); + if(!md_node_is_nil(table_tag)) + { + MG_NodeGrid *table = push_array(mg_arena, MG_NodeGrid, 1); + MG_ColumnDescArray *col_descs = push_array(mg_arena, MG_ColumnDescArray, 1); + *table = mg_node_grid_make_from_node(mg_arena, node); + *col_descs = mg_column_desc_array_from_tag(mg_arena, table_tag); + mg_map_insert_ptr(mg_arena, &table_grid_map, node->string, table); + mg_map_insert_ptr(mg_arena, &table_col_map, node->string, col_descs); + table_count += 1; + } + } + } + } + + ////////////////////////////// + //- rjf: generate table enums + // + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + if(md_node_has_tag(node, str8_lit("table_gen_enum"), 0)) + { + String8 layer_key = mg_layer_key_from_path(file->string); + MG_Layer *layer = mg_layer_from_key(layer_key); + String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node); + str8_list_pushf(mg_arena, &layer->enums, "typedef enum %S\n{\n", node->string); + for(String8Node *n = gen_strings.first; n != 0; n = n->next) + { + String8 escaped = mg_escaped_from_str8(mg_arena, n->string); + str8_list_push(mg_arena, &layer->enums, escaped); + str8_list_push(mg_arena, &layer->enums, str8_lit("\n")); + } + str8_list_pushf(mg_arena, &layer->enums, "} %S;\n\n", node->string); + } + } + } + + ////////////////////////////// + //- rjf: generate table structs + // + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + if(md_node_has_tag(node, str8_lit("table_gen_struct"), 0)) + { + String8 layer_key = mg_layer_key_from_path(file->string); + MG_Layer *layer = mg_layer_from_key(layer_key); + String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node); + str8_list_pushf(mg_arena, &layer->structs, "typedef struct %S %S;\n", node->string, node->string); + str8_list_pushf(mg_arena, &layer->structs, "struct %S\n{\n", node->string); + for(String8Node *n = gen_strings.first; n != 0; n = n->next) + { + String8 escaped = mg_escaped_from_str8(mg_arena, n->string); + str8_list_push(mg_arena, &layer->structs, escaped); + str8_list_push(mg_arena, &layer->structs, str8_lit("\n")); + } + str8_list_pushf(mg_arena, &layer->structs, "};\n\n"); + } + } + } + + ////////////////////////////// + //- rjf: generate table data tables + // + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + MD_Node *tag = md_tag_from_string(node, str8_lit("table_gen_data"), 0); + if(!md_node_is_nil(tag)) + { + String8 layer_key = mg_layer_key_from_path(file->string); + MG_Layer *layer = mg_layer_from_key(layer_key); + String8List *out = md_node_has_tag(node, str8_lit("c_file"), 0) ? &layer->c_tables : &layer->h_tables; + MD_Node *type = md_child_from_string(tag, str8_lit("type"), 0)->first; + MD_Node *fallback = md_child_from_string(tag, str8_lit("fallback"), 0)->first; + String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, fallback->string, node); + str8_list_pushf(mg_arena, out, "%S %S[] =\n{\n", type->string, node->string); + for(String8Node *n = gen_strings.first; n != 0; n = n->next) + { + String8 escaped = mg_escaped_from_str8(mg_arena, n->string); + str8_list_push(mg_arena, out, escaped); + str8_list_push(mg_arena, out, str8_lit("\n")); + } + str8_list_push(mg_arena, out, str8_lit("};\n\n")); + } + } + } + + ////////////////////////////// + //- rjf: generate table catch-all generations + // + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + MD_Node *tag = md_tag_from_string(node, str8_lit("table_gen"), 0); + if(!md_node_is_nil(tag)) + { + String8 layer_key = mg_layer_key_from_path(file->string); + MG_Layer *layer = mg_layer_from_key(layer_key); + String8List *out = md_node_has_tag(node, str8_lit("c_file"), 0) ? &layer->c_catchall : &layer->h_catchall; + String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node); + for(String8Node *n = gen_strings.first; n != 0; n = n->next) + { + String8 escaped = mg_escaped_from_str8(mg_arena, n->string); + str8_list_push(mg_arena, out, escaped); + str8_list_push(mg_arena, out, str8_lit("\n")); + } + } + } + } + + ////////////////////////////// + //- rjf: gather & generate all embeds + // + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + if(md_node_has_tag(node, str8_lit("embed_string"), 0)) + { + String8 layer_key = mg_layer_key_from_path(file->string); + MG_Layer *layer = mg_layer_from_key(layer_key); + String8 embed_string = mg_c_string_literal_from_multiline_string(node->first->string); + str8_list_pushf(mg_arena, &layer->h_tables, "read_only global String8 %S =\nstr8_lit_comp(\n", node->string); + str8_list_push (mg_arena, &layer->h_tables, embed_string); + str8_list_pushf(mg_arena, &layer->h_tables, ");\n\n"); + } + if(md_node_has_tag(node, str8_lit("embed_file"), 0)) + { + String8 layer_key = mg_layer_key_from_path(file->string); + MG_Layer *layer = mg_layer_from_key(layer_key); + String8 data = os_data_from_file_path(mg_arena, node->first->string); + String8 embed_string = mg_c_array_literal_contents_from_data(data); + str8_list_pushf(mg_arena, &layer->h_tables, "read_only global U8 %S__data[] =\n{\n", node->string); + str8_list_push (mg_arena, &layer->h_tables, embed_string); + str8_list_pushf(mg_arena, &layer->h_tables, "};\n\n"); + str8_list_pushf(mg_arena, &layer->h_tables, "read_only global String8 %S = {%S__data, sizeof(%S__data)};\n", + node->string, + node->string, + node->string); + } + } + } + + ////////////////////////////// + //- rjf: generate all markdown in build folder + // + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + //- rjf: generate markdown page + if(md_node_has_tag(node, str8_lit("markdown"), 0)) + { + String8List md_strs = {0}; + for(MD_Node *piece = node->first; !md_node_is_nil(piece); piece = piece->next) + { + if(md_node_has_tag(piece, str8_lit("title"), 0)) + { + str8_list_pushf(mg_arena, &md_strs, "# %S\n\n", piece->string); + } + if(md_node_has_tag(piece, str8_lit("subtitle"), 0)) + { + str8_list_pushf(mg_arena, &md_strs, "## %S\n\n", piece->string); + } + if(md_node_has_tag(piece, str8_lit("p"), 0)) + { + String8 paragraph_text = piece->string; + String8List paragraph_lines = mg_wrapped_lines_from_string(mg_arena, paragraph_text, 80, 80, 0); + for(String8Node *n = paragraph_lines.first; n != 0; n = n->next) + { + str8_list_push(mg_arena, &md_strs, n->string); + str8_list_push(mg_arena, &md_strs, str8_lit("\n")); + } + str8_list_push(mg_arena, &md_strs, str8_lit("\n")); + } + if(md_node_has_tag(piece, str8_lit("unordered_list"), 0)) + { + String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), piece); + for(String8Node *n = gen_strings.first; n != 0; n = n->next) + { + str8_list_pushf(mg_arena, &md_strs, " - "); + String8 item_text = n->string; + String8List item_lines = mg_wrapped_lines_from_string(mg_arena, item_text, 80-3, 80, 3); + for(String8Node *line_n = item_lines.first; line_n != 0; line_n = line_n->next) + { + str8_list_push(mg_arena, &md_strs, line_n->string); + str8_list_pushf(mg_arena, &md_strs, "\n"); + } + } + str8_list_pushf(mg_arena, &md_strs, "\n"); + } + } + String8 output_path = push_str8f(mg_arena, "%S/%S.md", build_dir_path, node->string); + FILE *file = fopen((char *)output_path.str, "w"); + for(String8Node *n = md_strs.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, file); + } + fclose(file); + } + } + } + + ////////////////////////////// + //- rjf: write all layer output files + // + DeferLoop(printf("generating layer code..."), printf("\n")) + { + for(U64 slot_idx = 0; slot_idx < mg_state->slots_count; slot_idx += 1) + { + MG_LayerSlot *slot = &mg_state->slots[slot_idx]; + for(MG_LayerNode *n = slot->first; n != 0; n = n->next) + { + MG_Layer *layer = &n->v; + String8 layer_generated_folder = push_str8f(mg_arena, "%S/%S/generated", code_dir_path, layer->key); + if(os_make_directory(layer_generated_folder)) + { + String8List layer_key_parts = str8_split_path(mg_arena, layer->key); + StringJoin join = {0}; + join.sep = str8_lit("_"); + String8 layer_key_filename = str8_list_join(mg_arena, &layer_key_parts, &join); + String8 layer_key_filename_upper = upper_from_str8(mg_arena, layer_key_filename); + String8 h_path = push_str8f(mg_arena, "%S/%S.meta.h", layer_generated_folder, layer_key_filename); + String8 c_path = push_str8f(mg_arena, "%S/%S.meta.c", layer_generated_folder, layer_key_filename); + { + FILE *h = fopen((char *)h_path.str, "w"); + fprintf(h, "// Copyright (c) 2024 Epic Games Tools\n"); + fprintf(h, "// Licensed under the MIT license (https://opensource.org/license/mit/)\n\n"); + fprintf(h, "//- GENERATED CODE\n\n"); + fprintf(h, "#ifndef %.*s_META_H\n", str8_varg(layer_key_filename_upper)); + fprintf(h, "#define %.*s_META_H\n\n", str8_varg(layer_key_filename_upper)); + for(String8Node *n = layer->enums.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, h); + } + for(String8Node *n = layer->structs.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, h); + } + for(String8Node *n = layer->h_catchall.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, h); + } + for(String8Node *n = layer->h_functions.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, h); + } + for(String8Node *n = layer->h_tables.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, h); + } + fprintf(h, "\n#endif // %.*s_META_H\n", str8_varg(layer_key_filename_upper)); + fclose(h); + } + { + FILE *c = fopen((char *)c_path.str, "w"); + fprintf(c, "// Copyright (c) 2024 Epic Games Tools\n"); + fprintf(c, "// Licensed under the MIT license (https://opensource.org/license/mit/)\n\n"); + fprintf(c, "//- GENERATED CODE\n\n"); + for(String8Node *n = layer->c_catchall.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, c); + } + for(String8Node *n = layer->c_functions.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, c); + } + for(String8Node *n = layer->c_tables.first; n != 0; n = n->next) + { + fwrite(n->string.str, n->string.size, 1, c); + } + fclose(c); + } + } + } + } + } + + return 0; +} diff --git a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c new file mode 100644 index 00000000..f9c2af02 --- /dev/null +++ b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c @@ -0,0 +1,1682 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include + +//////////////////////////////// +//~ rjf: Globals + +global pthread_mutex_t lnx_mutex = {0}; +global Arena *lnx_perm_arena = 0; +global String8List lnx_cmd_line_args = {0}; +global LNX_Entity lnx_entity_buffer[1024]; +global LNX_Entity *lnx_entity_free = 0; +global String8 lnx_initial_path = {0}; +thread_static LNX_SafeCallChain *lnx_safe_call_chain = 0; + +//////////////////////////////// +//~ rjf: Helpers + +internal B32 +lnx_write_list_to_file_descriptor(int fd, String8List list){ + B32 success = true; + + String8Node *node = list.first; + if (node != 0){ + U8 *ptr = node->string.str;; + U8 *opl = ptr + node->string.size; + + U64 p = 0; + for (;p < list.total_size;){ + U64 amt64 = (U64)(opl - ptr); + U32 amt = u32_from_u64_saturate(amt64); + S64 written_amt = write(fd, ptr, amt); + if (written_amt < 0){ + break; + } + p += written_amt; + ptr += written_amt; + + Assert(ptr <= opl); + if (ptr == opl){ + node = node->next; + if (node == 0){ + if (p < list.total_size){ + success = false; + } + break; + } + ptr = node->string.str; + opl = ptr + node->string.size; + } + } + } + + return(success); +} + +internal void +lnx_date_time_from_tm(DateTime *out, struct tm *in, U32 msec){ + out->msec = msec; + out->sec = in->tm_sec; + out->min = in->tm_min; + out->hour = in->tm_hour; + out->day = in->tm_mday - 1; + out->wday = in->tm_wday; + out->mon = in->tm_mon; + out->year = in->tm_year + 1900; +} + +internal void +lnx_tm_from_date_time(struct tm *out, DateTime *in){ + out->tm_sec = in->sec; + out->tm_min = in->min; + out->tm_hour = in->hour; + out->tm_mday = in->day + 1; + out->tm_mon = in->mon; + out->tm_year = in->year - 1900; +} + +internal void +lnx_dense_time_from_timespec(DenseTime *out, struct timespec *in){ + struct tm tm_time = {0}; + gmtime_r(&in->tv_sec, &tm_time); + DateTime date_time = {0}; + lnx_date_time_from_tm(&date_time, &tm_time, in->tv_nsec/Million(1)); + *out = dense_time_from_date_time(date_time); +} + +internal void +lnx_file_properties_from_stat(FileProperties *out, struct stat *in){ + MemoryZeroStruct(out); + out->size = in->st_size; + lnx_dense_time_from_timespec(&out->created, &in->st_ctim); + lnx_dense_time_from_timespec(&out->modified, &in->st_mtim); + if ((in->st_mode & S_IFDIR) != 0){ + out->flags |= FilePropertyFlag_IsFolder; + } +} + +internal String8 +lnx_string_from_signal(int signum){ + String8 result = str8_lit(""); + switch (signum){ + case SIGABRT: + { + result = str8_lit("SIGABRT"); + }break; + case SIGALRM: + { + result = str8_lit("SIGALRM"); + }break; + case SIGBUS: + { + result = str8_lit("SIGBUS"); + }break; + case SIGCHLD: + { + result = str8_lit("SIGCHLD"); + }break; + case SIGCONT: + { + result = str8_lit("SIGCONT"); + }break; + case SIGFPE: + { + result = str8_lit("SIGFPE"); + }break; + case SIGHUP: + { + result = str8_lit("SIGHUP"); + }break; + case SIGILL: + { + result = str8_lit("SIGILL"); + }break; + case SIGINT: + { + result = str8_lit("SIGINT"); + }break; + case SIGIO: + { + result = str8_lit("SIGIO"); + } + case SIGKILL: + { + result = str8_lit("SIGKILL"); + }break; + case SIGPIPE: + { + result = str8_lit("SIGPIPE"); + }break; + case SIGPROF: + { + result = str8_lit("SIGPROF"); + }break; + case SIGPWR: + { + result = str8_lit("SIGPWR"); + }break; + case SIGQUIT: + { + result = str8_lit("SIGQUIT"); + }break; + case SIGSEGV: + { + result = str8_lit("SIGSEGV"); + }break; + case SIGSTKFLT: + { + result = str8_lit("SIGSTKFLT"); + }break; + case SIGSTOP: + { + result = str8_lit("SIGSTOP"); + }break; + case SIGTSTP: + { + result = str8_lit("SIGTSTP"); + }break; + case SIGSYS: + { + result = str8_lit("SIGSYS"); + }break; + case SIGTERM: + { + result = str8_lit("SIGTERM"); + }break; + case SIGTRAP: + { + result = str8_lit("SIGTRAP"); + }break; + case SIGTTIN: + { + result = str8_lit("SIGTTIN"); + }break; + case SIGTTOU: + { + result = str8_lit("SIGTTOU"); + }break; + case SIGURG: + { + result = str8_lit("SIGURG"); + }break; + case SIGUSR1: + { + result = str8_lit("SIGUSR1"); + }break; + case SIGUSR2: + { + result = str8_lit("SIGUSR2"); + }break; + case SIGVTALRM: + { + result = str8_lit("SIGVTALRM"); + }break; + case SIGXCPU: + { + result = str8_lit("SIGXCPU"); + }break; + case SIGXFSZ: + { + result = str8_lit("SIGXFSZ"); + }break; + case SIGWINCH: + { + result = str8_lit("SIGWINCH"); + }break; + } + return(result); +} + +internal String8 +lnx_string_from_errno(int error_number){ + String8 result = str8_lit(""); + switch (error_number){ + case EPERM: + { + result = str8_lit("EPERM"); + }break; + case ENOENT: + { + result = str8_lit("ENOENT"); + }break; + case ESRCH: + { + result = str8_lit("ESRCH"); + }break; + case EINTR: + { + result = str8_lit("EINTR"); + }break; + case EIO: + { + result = str8_lit("EIO"); + }break; + case ENXIO: + { + result = str8_lit("ENXIO"); + }break; + case E2BIG: + { + result = str8_lit("E2BIG"); + }break; + case ENOEXEC: + { + result = str8_lit("ENOEXEC"); + }break; + case EBADF: + { + result = str8_lit("EBADF"); + }break; + case ECHILD: + { + result = str8_lit("ECHILD"); + }break; + case EAGAIN: + { + result = str8_lit("EAGAIN"); + }break; + case ENOMEM: + { + result = str8_lit("ENOMEM"); + }break; + case EACCES: + { + result = str8_lit("EACCES"); + }break; + case EFAULT: + { + result = str8_lit("EFAULT"); + }break; + case ENOTBLK: + { + result = str8_lit("ENOTBLK"); + }break; + case EBUSY: + { + result = str8_lit("EBUSY"); + }break; + case EEXIST: + { + result = str8_lit("EEXIST"); + }break; + case EXDEV: + { + result = str8_lit("EXDEV"); + }break; + case ENODEV: + { + result = str8_lit("ENODEV"); + }break; + case ENOTDIR: + { + result = str8_lit("ENOTDIR"); + }break; + case EISDIR: + { + result = str8_lit("EISDIR"); + }break; + case EINVAL: + { + result = str8_lit("EINVAL"); + }break; + case ENFILE: + { + result = str8_lit("ENFILE"); + }break; + case EMFILE: + { + result = str8_lit("EMFILE"); + }break; + case ENOTTY: + { + result = str8_lit("ENOTTY"); + }break; + case ETXTBSY: + { + result = str8_lit("ETXTBSY"); + }break; + case EFBIG: + { + result = str8_lit("EFBIG"); + }break; + case ENOSPC: + { + result = str8_lit("ENOSPC"); + }break; + case ESPIPE: + { + result = str8_lit("ESPIPE"); + }break; + case EROFS: + { + result = str8_lit("EROFS"); + }break; + case EMLINK: + { + result = str8_lit("EMLINK"); + }break; + case EPIPE: + { + result = str8_lit("EPIPE"); + }break; + case EDOM: + { + result = str8_lit("EDOM"); + }break; + case ERANGE: + { + result = str8_lit("ERANGE"); + }break; + case EDEADLK: + { + result = str8_lit("EDEADLK"); + }break; + case ENAMETOOLONG: + { + result = str8_lit("ENAMETOOLONG"); + }break; + case ENOLCK: + { + result = str8_lit("ENOLCK"); + }break; + case ENOSYS: + { + result = str8_lit("ENOSYS"); + }break; + case ENOTEMPTY: + { + result = str8_lit("ENOTEMPTY"); + }break; + case ELOOP: + { + result = str8_lit("ELOOP"); + }break; + case ENOMSG: + { + result = str8_lit("ENOMSG"); + }break; + case EIDRM: + { + result = str8_lit("EIDRM"); + }break; + case ECHRNG: + { + result = str8_lit("ECHRNG"); + }break; + case EL2NSYNC: + { + result = str8_lit("EL2NSYNC"); + }break; + case EL3HLT: + { + result = str8_lit("EL3HLT"); + }break; + case EL3RST: + { + result = str8_lit("EL3RST"); + }break; + case ELNRNG: + { + result = str8_lit("ELNRNG"); + }break; + case EUNATCH: + { + result = str8_lit("EUNATCH"); + }break; + case ENOCSI: + { + result = str8_lit("ENOCSI"); + }break; + case EL2HLT: + { + result = str8_lit("EL2HLT"); + }break; + case EBADE: + { + result = str8_lit("EBADE"); + }break; + case EBADR: + { + result = str8_lit("EBADR"); + }break; + case EXFULL: + { + result = str8_lit("EXFULL"); + }break; + case ENOANO: + { + result = str8_lit("ENOANO"); + }break; + case EBADRQC: + { + result = str8_lit("EBADRQC"); + }break; + case EBADSLT: + { + result = str8_lit("EBADSLT"); + }break; + case EBFONT: + { + result = str8_lit("EBFONT"); + }break; + case ENOSTR: + { + result = str8_lit("ENOSTR"); + }break; + case ENODATA: + { + result = str8_lit("ENODATA"); + }break; + case ETIME: + { + result = str8_lit("ETIME"); + }break; + case ENOSR: + { + result = str8_lit("ENOSR"); + }break; + case ENONET: + { + result = str8_lit("ENONET"); + }break; + case ENOPKG: + { + result = str8_lit("ENOPKG"); + }break; + case EREMOTE: + { + result = str8_lit("EREMOTE"); + }break; + case ENOLINK: + { + result = str8_lit("ENOLINK"); + }break; + case EADV: + { + result = str8_lit("EADV"); + }break; + case ESRMNT: + { + result = str8_lit("ESRMNT"); + }break; + case ECOMM: + { + result = str8_lit("ECOMM"); + }break; + case EPROTO: + { + result = str8_lit("EPROTO"); + }break; + case EMULTIHOP: + { + result = str8_lit("EMULTIHOP"); + }break; + case EDOTDOT: + { + result = str8_lit("EDOTDOT"); + }break; + case EBADMSG: + { + result = str8_lit("EBADMSG"); + }break; + case EOVERFLOW: + { + result = str8_lit("EOVERFLOW"); + }break; + case ENOTUNIQ: + { + result = str8_lit("ENOTUNIQ"); + }break; + case EBADFD: + { + result = str8_lit("EBADFD"); + }break; + case EREMCHG: + { + result = str8_lit("EREMCHG"); + }break; + case ELIBACC: + { + result = str8_lit("ELIBACC"); + }break; + case ELIBBAD: + { + result = str8_lit("ELIBBAD"); + }break; + case ELIBSCN: + { + result = str8_lit("ELIBSCN"); + }break; + case ELIBMAX: + { + result = str8_lit("ELIBMAX"); + }break; + case ELIBEXEC: + { + result = str8_lit("ELIBEXEC"); + }break; + case EILSEQ: + { + result = str8_lit("EILSEQ"); + }break; + case ERESTART: + { + result = str8_lit("ERESTART"); + }break; + case ESTRPIPE: + { + result = str8_lit("ESTRPIPE"); + }break; + case EUSERS: + { + result = str8_lit("EUSERS"); + }break; + case ENOTSOCK: + { + result = str8_lit("ENOTSOCK"); + }break; + case EDESTADDRREQ: + { + result = str8_lit("EDESTADDRREQ"); + }break; + case EMSGSIZE: + { + result = str8_lit("EMSGSIZE"); + }break; + case EPROTOTYPE: + { + result = str8_lit("EPROTOTYPE"); + }break; + case ENOPROTOOPT: + { + result = str8_lit("ENOPROTOOPT"); + }break; + case EPROTONOSUPPORT: + { + result = str8_lit("EPROTONOSUPPORT"); + }break; + case ESOCKTNOSUPPORT: + { + result = str8_lit("ESOCKTNOSUPPORT"); + }break; + case EOPNOTSUPP: + { + result = str8_lit("EOPNOTSUPP"); + }break; + case EPFNOSUPPORT: + { + result = str8_lit("EPFNOSUPPORT"); + }break; + case EAFNOSUPPORT: + { + result = str8_lit("EAFNOSUPPORT"); + }break; + case EADDRINUSE: + { + result = str8_lit("EADDRINUSE"); + }break; + case EADDRNOTAVAIL: + { + result = str8_lit("EADDRNOTAVAIL"); + }break; + case ENETDOWN: + { + result = str8_lit("ENETDOWN"); + }break; + case ENETUNREACH: + { + result = str8_lit("ENETUNREACH"); + }break; + case ENETRESET: + { + result = str8_lit("ENETRESET"); + }break; + case ECONNABORTED: + { + result = str8_lit("ECONNABORTED"); + }break; + case ECONNRESET: + { + result = str8_lit("ECONNRESET"); + }break; + case ENOBUFS: + { + result = str8_lit("ENOBUFS"); + }break; + case EISCONN: + { + result = str8_lit("EISCONN"); + }break; + case ENOTCONN: + { + result = str8_lit("ENOTCONN"); + }break; + case ESHUTDOWN: + { + result = str8_lit("ESHUTDOWN"); + }break; + case ETOOMANYREFS: + { + result = str8_lit("ETOOMANYREFS"); + }break; + case ETIMEDOUT: + { + result = str8_lit("ETIMEDOUT"); + }break; + case ECONNREFUSED: + { + result = str8_lit("ECONNREFUSED"); + }break; + case EHOSTDOWN: + { + result = str8_lit("EHOSTDOWN"); + }break; + case EHOSTUNREACH: + { + result = str8_lit("EHOSTUNREACH"); + }break; + case EALREADY: + { + result = str8_lit("EALREADY"); + }break; + case EINPROGRESS: + { + result = str8_lit("EINPROGRESS"); + }break; + case ESTALE: + { + result = str8_lit("ESTALE"); + }break; + case EUCLEAN: + { + result = str8_lit("EUCLEAN"); + }break; + case ENOTNAM: + { + result = str8_lit("ENOTNAM"); + }break; + case ENAVAIL: + { + result = str8_lit("ENAVAIL"); + }break; + case EISNAM: + { + result = str8_lit("EISNAM"); + }break; + case EREMOTEIO: + { + result = str8_lit("EREMOTEIO"); + }break; + case EDQUOT: + { + result = str8_lit("EDQUOT"); + }break; + case ENOMEDIUM: + { + result = str8_lit("ENOMEDIUM"); + }break; + case EMEDIUMTYPE: + { + result = str8_lit("EMEDIUMTYPE"); + }break; + case ECANCELED: + { + result = str8_lit("ECANCELED"); + }break; + case ENOKEY: + { + result = str8_lit("ENOKEY"); + }break; + case EKEYEXPIRED: + { + result = str8_lit("EKEYEXPIRED"); + }break; + case EKEYREVOKED: + { + result = str8_lit("EKEYREVOKED"); + }break; + case EKEYREJECTED: + { + result = str8_lit("EKEYREJECTED"); + }break; + case EOWNERDEAD: + { + result = str8_lit("EOWNERDEAD"); + }break; + case ENOTRECOVERABLE: + { + result = str8_lit("ENOTRECOVERABLE"); + }break; + case ERFKILL: + { + result = str8_lit("ERFKILL"); + }break; + case EHWPOISON: + { + result = str8_lit("EHWPOISON"); + }break; + } + return(result); +} + +internal LNX_Entity* +lnx_alloc_entity(LNX_EntityKind kind){ + pthread_mutex_lock(&lnx_mutex); + LNX_Entity *result = lnx_entity_free; + Assert(result != 0); + SLLStackPop(lnx_entity_free); + pthread_mutex_unlock(&lnx_mutex); + result->kind = kind; + return(result); +} + +internal void +lnx_free_entity(LNX_Entity *entity){ + entity->kind = LNX_EntityKind_Null; + pthread_mutex_lock(&lnx_mutex); + SLLStackPush(lnx_entity_free, entity); + pthread_mutex_unlock(&lnx_mutex); +} + +internal void* +lnx_thread_base(void *ptr){ + LNX_Entity *entity = (LNX_Entity*)ptr; + OS_ThreadFunctionType *func = entity->thread.func; + void *thread_ptr = entity->thread.ptr; + + TCTX tctx_; + tctx_init_and_equip(&tctx_); + + func(thread_ptr); + + // remove my bit + U32 result = __sync_fetch_and_and(&entity->reference_mask, ~0x2); + // if the other bit is also gone, free entity + if ((result & 0x1) == 0){ + lnx_free_entity(entity); + } + return(0); +} + +internal void +lnx_safe_call_sig_handler(int){ + LNX_SafeCallChain *chain = lnx_safe_call_chain; + if (chain != 0 && chain->fail_handler != 0){ + chain->fail_handler(chain->ptr); + } + abort(); +} + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void +os_init(int argc, char **argv) +{ + // NOTE(allen): Initialize linux layer mutex + { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + int pthread_result = pthread_mutex_init(&lnx_mutex, &attr); + pthread_mutexattr_destroy(&attr); + if (pthread_result == -1){ + abort(); + } + } + MemoryZeroArray(lnx_entity_buffer); + { + LNX_Entity *ptr = lnx_entity_free = lnx_entity_buffer; + for (U64 i = 1; i < ArrayCount(lnx_entity_buffer); i += 1, ptr += 1){ + ptr->next = ptr + 1; + } + ptr->next = 0; + } + + // NOTE(allen): Permanent memory allocator for this layer + Arena *perm_arena = arena_alloc(); + lnx_perm_arena = perm_arena; + + // NOTE(allen): Initialize Paths + lnx_initial_path = os_get_path(lnx_perm_arena, OS_SystemPath_Current); + + // NOTE(rjf): Setup command line args + lnx_cmd_line_args = os_string_list_from_argcv(lnx_perm_arena, argc, argv); +} + +//////////////////////////////// +//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) + +internal void* +os_reserve(U64 size){ + void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + return(result); +} + +internal B32 +os_commit(void *ptr, U64 size){ + mprotect(ptr, size, PROT_READ|PROT_WRITE); + // TODO(allen): can we test this? + return(true); +} + +internal void* +os_reserve_large(U64 size){ + NotImplemented; + return 0; +} + +internal B32 +os_commit_large(void *ptr, U64 size){ + NotImplemented; + return 0; +} + +internal void +os_decommit(void *ptr, U64 size){ + madvise(ptr, size, MADV_DONTNEED); + mprotect(ptr, size, PROT_NONE); +} + +internal void +os_release(void *ptr, U64 size){ + munmap(ptr, size); +} + +internal void +os_set_large_pages(B32 flag) +{ + NotImplemented; +} + +internal B32 +os_large_pages_enabled(void) +{ + NotImplemented; + return 0; +} + +internal U64 +os_large_page_size(void) +{ + NotImplemented; + return 0; +} + +internal void* +os_alloc_ring_buffer(U64 size, U64 *actual_size_out) +{ + NotImplemented; + return 0; +} + +internal void +os_free_ring_buffer(void *ring_buffer, U64 actual_size) +{ + NotImplemented; +} + +//////////////////////////////// +//~ rjf: @os_hooks System Info (Implemented Per-OS) + +internal String8 +os_machine_name(void){ + local_persist B32 first = true; + local_persist String8 name = {0}; + + // TODO(allen): let's just pre-compute this at init and skip the complexity + pthread_mutex_lock(&lnx_mutex); + if (first){ + Temp scratch = scratch_begin(0, 0); + first = false; + + // get name + B32 got_final_result = false; + U8 *buffer = 0; + int size = 0; + for (S64 cap = 4096, r = 0; + r < 4; + cap *= 2, r += 1){ + scratch.restore(); + buffer = push_array_no_zero(scratch.arena, U8, cap); + size = gethostname((char*)buffer, cap); + if (size < cap){ + got_final_result = true; + break; + } + } + + // save string + if (got_final_result && size > 0){ + name.size = size; + name.str = push_array_no_zero(lnx_perm_arena, U8, name.size + 1); + MemoryCopy(name.str, buffer, name.size); + name.str[name.size] = 0; + } + + scratch_end(scratch); + } + pthread_mutex_unlock(&lnx_mutex); + + return(name); +} + +internal U64 +os_page_size(void){ + int size = getpagesize(); + return((U64)size); +} + +internal U64 +os_allocation_granularity(void) +{ + // On linux there is no equivalent of "dwAllocationGranularity" + os_page_size(); +} + +internal U64 +os_logical_core_count(void) +{ + // TODO(rjf): check this + return get_nprocs(); +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Info (Implemented Per-OS) + +internal String8List +os_get_command_line_arguments(void) +{ + return lnx_cmd_line_args; +} + +internal S32 +os_get_pid(void){ + S32 result = getpid(); + return(result); +} + +internal S32 +os_get_tid(void){ + S32 result = 0; +#ifdef SYS_gettid + result = syscall(SYS_gettid); +#else + result = gettid(); +#endif + return(result); +} + +internal String8List +os_get_environment(void) +{ + NotImplemented; + String8List result = {0}; + return result; +} + +internal U64 +os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out){ + U64 result = 0; + + switch (path){ + case OS_SystemPath_Binary: + { + local_persist B32 first = true; + local_persist String8 name = {0}; + + // TODO(allen): let's just pre-compute this at init and skip the complexity + pthread_mutex_lock(&lnx_mutex); + if (first){ + Temp scratch = scratch_begin(&arena, 1); + first = false; + + // get self string + B32 got_final_result = false; + U8 *buffer = 0; + int size = 0; + for (S64 cap = PATH_MAX, r = 0; + r < 4; + cap *= 2, r += 1){ + scratch.restore(); + buffer = push_array_no_zero(scratch.arena, U8, cap); + size = readlink("/proc/self/exe", (char*)buffer, cap); + if (size < cap){ + got_final_result = true; + break; + } + } + + // save string + if (got_final_result && size > 0){ + String8 full_name = str8(buffer, size); + String8 name_chopped = string_path_chop_last_slash(full_name); + name = push_str8_copy(lnx_perm_arena, name_chopped); + } + + scratch_end(scratch); + } + pthread_mutex_unlock(&lnx_mutex); + + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_Initial: + { + Assert(lnx_initial_path.str != 0); + result = 1; + str8_list_push(arena, out, lnx_initial_path); + }break; + + case OS_SystemPath_Current: + { + char *cwdir = getcwd(0, 0); + String8 string = push_str8_copy(arena, str8_cstring(cwdir)); + free(cwdir); + result = 1; + str8_list_push(arena, out, string); + }break; + + case OS_SystemPath_UserProgramData: + { + char *home = getenv("HOME"); + String8 string = str8_cstring(home); + result = 1; + str8_list_push(arena, out, string); + }break; + + case OS_SystemPath_ModuleLoad: + { + // TODO(allen): this one is big and complicated and only needed for making + // a debugger, skipping for now. + NotImplemented; + }break; + } + + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Control (Implemented Per-OS) + +internal void +os_exit_process(S32 exit_code){ + exit(exit_code); +} + +//////////////////////////////// +//~ rjf: @os_hooks File System (Implemented Per-OS) + +//- rjf: files + +internal OS_Handle +os_file_open(OS_AccessFlags flags, String8 path) +{ + OS_Handle file = {0}; + NotImplemented; + return file; +} + +internal void +os_file_close(OS_Handle file) +{ + NotImplemented; +} + +internal U64 +os_file_read(OS_Handle file, Rng1U64 rng, void *out_data) +{ + NotImplemented; + return 0; +} + +internal void +os_file_write(OS_Handle file, Rng1U64 rng, void *data) +{ + NotImplemented; +} + +internal B32 +os_file_set_times(OS_Handle file, DateTime time) +{ + NotImplemented; +} + +internal FileProperties +os_properties_from_file(OS_Handle file) +{ + FileProperties props = {0}; + NotImplemented; + return props; +} + +internal OS_FileID +os_id_from_file(OS_Handle file) +{ + // TODO(nick): querry struct stat with fstat(2) and use st_dev and st_ino as ids + OS_FileID id = {0}; + NotImplemented; + return id; +} + +internal B32 +os_delete_file_at_path(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + B32 result = false; + String8 name_copy = push_str8_copy(scratch.arena, name); + if (remove((char*)name_copy.str) != -1){ + result = true; + } + scratch_end(scratch); + return(result); +} + +internal B32 +os_copy_file_path(String8 dst, String8 src) +{ + NotImplemented; + return 0; +} + +internal String8 +os_full_path_from_path(Arena *arena, String8 path) +{ + // TODO: realpath can be used to resolve full path + String8 result = {0}; + NotImplemented; + return result; +} + +internal B32 +os_file_path_exists(String8 path) +{ + NotImplemented; + return 0; +} + +//- rjf: file maps + +internal OS_Handle +os_file_map_open(OS_AccessFlags flags, OS_Handle file) +{ + NotImplemented; + OS_Handle handle = {0}; + return handle; +} + +internal void +os_file_map_close(OS_Handle map) +{ + NotImplemented; +} + +internal void * +os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) +{ + NotImplemented; + return 0; +} + +internal void +os_file_map_view_close(OS_Handle map, void *ptr) +{ + NotImplemented; +} + +//- rjf: directory iteration + +internal OS_FileIter * +os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) +{ + NotImplemented; + return 0; +} + +internal B32 +os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) +{ + NotImplemented; + return 0; +} + +internal void +os_file_iter_end(OS_FileIter *iter) +{ + NotImplemented; +} + +//- rjf: directory creation + +internal B32 +os_make_directory(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + B32 result = false; + String8 name_copy = push_str8_copy(scratch.arena, name); + if (mkdir((char*)name_copy.str, 0777) != -1){ + result = true; + } + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Shared Memory (Implemented Per-OS) + +internal OS_Handle +os_shared_memory_alloc(U64 size, String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal OS_Handle +os_shared_memory_open(String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_shared_memory_close(OS_Handle handle) +{ + NotImplemented; +} + +internal void * +os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) +{ + NotImplemented; + return 0; +} + +internal void +os_shared_memory_view_close(OS_Handle handle, void *ptr) +{ + NotImplemented; +} + +//////////////////////////////// +//~ rjf: @os_hooks Time (Implemented Per-OS) + +internal OS_UnixTime +os_now_unix(void) +{ + time_t t = time(0); + return (OS_UnixTime)t; +} + +internal DateTime +os_now_universal_time(void){ + time_t t = 0; + time(&t); + struct tm universal_tm = {0}; + gmtime_r(&t, &universal_tm); + DateTime result = {0}; + lnx_date_time_from_tm(&result, &universal_tm, 0); + return(result); +} + +internal DateTime +os_universal_time_from_local_time(DateTime *local_time){ + // local time -> universal time (using whatever types it takes) + struct tm local_tm = {0}; + lnx_tm_from_date_time(&local_tm, local_time); + local_tm.tm_isdst = -1; + time_t universal_t = mktime(&local_tm); + + // whatever type we ended up with -> DateTime (don't alter the space along the way) + struct tm universal_tm = {0}; + gmtime_r(&universal_t, &universal_tm); + DateTime result = {0}; + lnx_date_time_from_tm(&result, &universal_tm, 0); + return(result); +} + +internal DateTime +os_local_time_from_universal_time(DateTime *universal_time){ + // universal time -> local time (using whatever types it takes) + struct tm universal_tm = {0}; + lnx_tm_from_date_time(&universal_tm, universal_time); + universal_tm.tm_isdst = -1; + time_t universal_t = timegm(&universal_tm); + struct tm local_tm = {0}; + localtime_r(&universal_t, &local_tm); + + // whatever type we ended up with -> DateTime (don't alter the space along the way) + DateTime result = {0}; + lnx_date_time_from_tm(&result, &local_tm, 0); + return(result); +} + +internal U64 +os_now_microseconds(void){ + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + U64 result = t.tv_sec*Million(1) + (t.tv_nsec/Thousand(1)); + return(result); +} + +internal void +os_sleep_milliseconds(U32 msec){ + usleep(msec*Thousand(1)); +} + +//////////////////////////////// +//~ rjf: @os_hooks Child Processes (Implemented Per-OS) + +internal B32 +os_launch_process(OS_LaunchOptions *options){ + // TODO(allen): I want to redo this API before I bother implementing it here + NotImplemented; + return(false); +} + +//////////////////////////////// +//~ rjf: @os_hooks Threads (Implemented Per-OS) + +internal OS_Handle +os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params){ + // entity + LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_Thread); + entity->reference_mask = 0x3; + entity->thread.func = func; + entity->thread.ptr = ptr; + + // pthread + pthread_attr_t attr; + pthread_attr_init(&attr); + int pthread_result = pthread_create(&entity->thread.handle, &attr, lnx_thread_base, entity); + pthread_attr_destroy(&attr); + if (pthread_result == -1){ + lnx_free_entity(entity); + entity = 0; + } + + // cast to opaque handle + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_release_thread_handle(OS_Handle thread){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(thread.id); + // remove my bit + U32 result = __sync_fetch_and_and(&entity->reference_mask, ~0x1); + // if the other bit is also gone, free entity + if ((result & 0x2) == 0){ + lnx_free_entity(entity); + } +} + +//////////////////////////////// +//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) + +// NOTE(allen): Mutexes are recursive - support counted acquire/release nesting +// on a single thread + +//- rjf: recursive mutexes + +internal OS_Handle +os_mutex_alloc(void){ + // entity + LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_Mutex); + + // pthread + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + int pthread_result = pthread_mutex_init(&entity->mutex, &attr); + pthread_mutexattr_destroy(&attr); + if (pthread_result == -1){ + lnx_free_entity(entity); + entity = 0; + } + + // cast to opaque handle + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_mutex_release(OS_Handle mutex){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(mutex.id); + pthread_mutex_destroy(&entity->mutex); + lnx_free_entity(entity); +} + +internal void +os_mutex_take_(OS_Handle mutex){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(mutex.id); + pthread_mutex_lock(&entity->mutex); +} + +internal void +os_mutex_drop_(OS_Handle mutex){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(mutex.id); + pthread_mutex_unlock(&entity->mutex); +} + +//- rjf: reader/writer mutexes + +internal OS_Handle +os_rw_mutex_alloc(void) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_rw_mutex_release(OS_Handle rw_mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_take_r_(OS_Handle mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_drop_r_(OS_Handle mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_take_w_(OS_Handle mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_drop_w_(OS_Handle mutex) +{ + NotImplemented; +} + +//- rjf: condition variables + +internal OS_Handle +os_condition_variable_alloc(void){ + // entity + LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_ConditionVariable); + + // pthread + pthread_condattr_t attr; + pthread_condattr_init(&attr); + int pthread_result = pthread_cond_init(&entity->cond, &attr); + pthread_condattr_destroy(&attr); + if (pthread_result == -1){ + lnx_free_entity(entity); + entity = 0; + } + + // cast to opaque handle + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_condition_variable_release(OS_Handle cv){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(cv.id); + pthread_cond_destroy(&entity->cond); + lnx_free_entity(entity); +} + +internal B32 +os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us){ + B32 result = false; + LNX_Entity *entity_cond = (LNX_Entity*)PtrFromInt(cv.id); + LNX_Entity *entity_mutex = (LNX_Entity*)PtrFromInt(mutex.id); + // TODO(allen): implement the time control + pthread_cond_timedwait(&entity_cond->cond, &entity_mutex->mutex); + return(result); +} + +internal B32 +os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +{ + NotImplemented; + return 0; +} + +internal B32 +os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +{ + NotImplemented; + return 0; +} + +internal void +os_condition_variable_signal_(OS_Handle cv){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(cv.id); + pthread_cond_signal(&entity->cond); +} + +internal void +os_condition_variable_broadcast_(OS_Handle cv){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(cv.id); + DontCompile; +} + +//- rjf: cross-process semaphores + +internal OS_Handle +os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_semaphore_release(OS_Handle semaphore) +{ + NotImplemented; +} + +internal OS_Handle +os_semaphore_open(String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_semaphore_close(OS_Handle semaphore) +{ + NotImplemented; +} + +internal B32 +os_semaphore_take(OS_Handle semaphore) +{ + NotImplemented; + return 0; +} + +internal void +os_semaphore_drop(OS_Handle semaphore) +{ + NotImplemented; +} + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal OS_Handle +os_library_open(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + char *path_cstr = (char *)push_str8_copy(scratch.arena, path).str; + void *so = dlopen(path_cstr, RTLD_LAZY); + OS_Handle lib = { (U64)so }; + scratch_end(scratch); + return lib; +} + +internal VoidProc * +os_library_load_proc(OS_Handle lib, String8 name) +{ + Temp scratch = scratch_begin(0, 0); + void *so = (void *)lib.id; + char *name_cstr = (char *)push_str8_copy(scratch.arena, name).str; + VoidProc *proc = (VoidProc *)dlsym(so, name_cstr); + scratch_end(scratch); + return proc; +} + +internal void +os_library_close(OS_Handle lib) +{ + void *so = (void *)lib.id; + dlclose(so); +} + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal void +os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr){ + LNX_SafeCallChain chain = {0}; + SLLStackPush(lnx_safe_call_chain, &chain); + chain.fail_handler = fail_handler; + chain.ptr = ptr; + + struct sigaction new_act = {0}; + new_act.sa_handler = lnx_safe_call_sig_handler; + + int signals_to_handle[] = { + SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, + }; + struct sigaction og_act[ArrayCount(signals_to_handle)] = {0}; + + for (U32 i = 0; i < ArrayCount(signals_to_handle); i += 1){ + sigaction(signals_to_handle[i], &new_act, &og_act[i]); + } + + func(ptr); + + for (U32 i = 0; i < ArrayCount(signals_to_handle); i += 1){ + sigaction(signals_to_handle[i], &og_act[i], 0); + } +} + +//////////////////////////////// + +internal OS_Guid +os_make_guid(void) +{ + NotImplemented; +} + diff --git a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h new file mode 100644 index 00000000..9899f94a --- /dev/null +++ b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h @@ -0,0 +1,88 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef LINUX_H +#define LINUX_H + +//////////////////////////////// +//~ NOTE(allen): Get all these linux includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////// +//~ NOTE(allen): File Iterator + +struct LNX_FileIter{ + int fd; + DIR *dir; +}; +StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(LNX_FileIter), file_iter_memory_size); + +//////////////////////////////// +//~ NOTE(allen): Threading Entities + +enum LNX_EntityKind{ + LNX_EntityKind_Null, + LNX_EntityKind_Thread, + LNX_EntityKind_Mutex, + LNX_EntityKind_ConditionVariable, +}; + +struct LNX_Entity{ + LNX_Entity *next; + LNX_EntityKind kind; + volatile U32 reference_mask; + union{ + struct{ + OS_ThreadFunctionType *func; + void *ptr; + pthread_t handle; + } thread; + pthread_mutex_t mutex; + pthread_cond_t cond; + }; +}; + +//////////////////////////////// +//~ NOTE(allen): Safe Call Chain + +struct LNX_SafeCallChain{ + LNX_SafeCallChain *next; + OS_ThreadFunctionType *fail_handler; + void *ptr; +}; + +//////////////////////////////// +//~ NOTE(allen): Helpers + +internal B32 lnx_write_list_to_file_descriptor(int fd, String8List list); + +internal void lnx_date_time_from_tm(DateTime *out, struct tm *in, U32 msec); +internal void lnx_tm_from_date_time(struct tm *out, DateTime *in); +internal void lnx_dense_time_from_timespec(DenseTime *out, struct timespec *in); +internal void lnx_file_properties_from_stat(FileProperties *out, struct stat *in); + +internal String8 lnx_string_from_signal(int signum); +internal String8 lnx_string_from_errno(int error_number); + +internal LNX_Entity* lnx_alloc_entity(LNX_EntityKind kind); +internal void lnx_free_entity(LNX_Entity *entity); +internal void* lnx_thread_base(void *ptr); + +internal void lnx_safe_call_sig_handler(int); + +#endif //LINUX_H diff --git a/src/metagen/metagen_os/core/metagen_os_core.c b/src/metagen/metagen_os/core/metagen_os_core.c new file mode 100644 index 00000000..0323091d --- /dev/null +++ b/src/metagen/metagen_os/core/metagen_os_core.c @@ -0,0 +1,265 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Handle Type Functions (Helpers, Implemented Once) + +internal OS_Handle +os_handle_zero(void) +{ + OS_Handle handle = {0}; + return handle; +} + +internal B32 +os_handle_match(OS_Handle a, OS_Handle b) +{ + return a.u64[0] == b.u64[0]; +} + +internal void +os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle) +{ + OS_HandleNode *n = push_array(arena, OS_HandleNode, 1); + n->v = handle; + SLLQueuePush(handles->first, handles->last, n); + handles->count += 1; +} + +internal OS_HandleArray +os_handle_array_from_list(Arena *arena, OS_HandleList *list) +{ + OS_HandleArray result = {0}; + result.count = list->count; + result.v = push_array_no_zero(arena, OS_Handle, result.count); + U64 idx = 0; + for(OS_HandleNode *n = list->first; n != 0; n = n->next, idx += 1) + { + result.v[idx] = n->v; + } + return result; +} + +//////////////////////////////// +//~ rjf: System Path Helper (Helper, Implemented Once) + +internal String8 +os_string_from_system_path(Arena *arena, OS_SystemPath path) +{ + String8List strs = {0}; + os_string_list_from_system_path(arena, path, &strs); + String8 result = str8_list_first(&strs); + return result; +} + +//////////////////////////////// +//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) + +internal String8List +os_string_list_from_argcv(Arena *arena, int argc, char **argv) +{ + String8List result = {0}; + for(int i = 0; i < argc; i += 1) + { + String8 str = str8_cstring(argv[i]); + str8_list_push(arena, &result, str); + } + return result; +} + +//////////////////////////////// +//~ rjf: Process Helpers (Helper, Implemented Once) + +internal void +os_relaunch_self(void){ + Temp scratch = scratch_begin(0, 0); + OS_LaunchOptions opts = {0}; + opts.cmd_line = os_get_command_line_arguments(); + opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Initial); + os_launch_process(&opts, 0); + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: Filesystem Helpers (Helpers, Implemented Once) + +internal String8 +os_data_from_file_path(Arena *arena, String8 path) +{ + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path); + FileProperties props = os_properties_from_file(file); + String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size)); + os_file_close(file); + return data; +} + +internal B32 +os_write_data_to_file_path(String8 path, String8 data) +{ + B32 good = 0; + OS_Handle file = os_file_open(OS_AccessFlag_Write, path); + if(!os_handle_match(file, os_handle_zero())) + { + good = 1; + os_file_write(file, r1u64(0, data.size), data.str); + os_file_close(file); + } + return good; +} + +internal B32 +os_write_data_list_to_file_path(String8 path, String8List list) +{ + B32 good = 0; + OS_Handle file = os_file_open(OS_AccessFlag_Write, path); + if(!os_handle_match(file, os_handle_zero())) + { + good = 1; + U64 off = 0; + for(String8Node *n = list.first; n != 0; n = n->next) + { + os_file_write(file, r1u64(off, off+n->string.size), n->string.str); + off += n->string.size; + } + os_file_close(file); + } + return good; +} + +internal FileProperties +os_properties_from_file_path(String8 path) +{ + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path); + FileProperties props = os_properties_from_file(file); + os_file_close(file); + return props; +} + +internal OS_FileID +os_id_from_file_path(String8 path) +{ + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path); + OS_FileID id = os_id_from_file(file); + os_file_close(file); + return id; +} + +internal S64 +os_file_id_compare(OS_FileID a, OS_FileID b) +{ + S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v)); + return cmp; +} + +internal String8 +os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range) +{ + U64 pre_pos = arena_pos(arena); + String8 result; + result.size = dim_1u64(range); + result.str = push_array_no_zero(arena, U8, result.size); + U64 actual_read_size = os_file_read(file, range, result.str); + if(actual_read_size < result.size) + { + arena_pop_to(arena, pre_pos + actual_read_size); + result.size = actual_read_size; + } + return result; +} + +//////////////////////////////// +//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once) + +internal void +os_mutex_take(OS_Handle mutex){ + ProfBeginLockWait((void *)(mutex.u64[0]), "take mutex"); + os_mutex_take_(mutex); + ProfEndLockWait(); + ProfLockTake((void *)(mutex.u64[0]), "take mutex"); +} + +internal void +os_mutex_drop(OS_Handle mutex){ + os_mutex_drop_(mutex); + ProfLockDrop((void *)(mutex.u64[0])); +} + +internal void +os_rw_mutex_take_r(OS_Handle rw_mutex){ + ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take r"); + os_rw_mutex_take_r_(rw_mutex); + ProfEndLockWait(); + ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take r"); +} + +internal void +os_rw_mutex_drop_r(OS_Handle rw_mutex){ + os_rw_mutex_drop_r_(rw_mutex); + ProfLockDrop((void *)(rw_mutex.u64[0])); +} + +internal void +os_rw_mutex_take_w(OS_Handle rw_mutex){ + ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take rw"); + os_rw_mutex_take_w_(rw_mutex); + ProfEndLockWait(); + ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take rw"); +} + +internal void +os_rw_mutex_drop_w(OS_Handle rw_mutex){ + os_rw_mutex_drop_w_(rw_mutex); + ProfLockDrop((void *)(rw_mutex.u64[0])); +} + +internal B32 +os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us){ + ProfLockDrop((void *)(mutex.u64[0])); + B32 result = os_condition_variable_wait_(cv, mutex, endt_us); + ProfLockTake((void *)(mutex.u64[0]), "wait cv"); + return(result); +} + +internal B32 +os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + ProfLockDrop((void *)(mutex_rw.u64[0])); + B32 result = os_condition_variable_wait_rw_r_(cv, mutex_rw, endt_us); + ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw r"); + return(result); +} + +internal B32 +os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + ProfLockDrop((void *)(mutex_rw.u64[0])); + B32 result = os_condition_variable_wait_rw_w_(cv, mutex_rw, endt_us); + ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw w"); + return(result); +} + +internal void +os_condition_variable_signal(OS_Handle cv){ + os_condition_variable_signal_(cv); +} + +internal void +os_condition_variable_broadcast(OS_Handle cv){ + os_condition_variable_broadcast_(cv); +} + +internal String8 +os_string_from_guid(Arena *arena, OS_Guid guid) +{ + String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + guid.data1, + guid.data2, + guid.data3, + guid.data4[0], + guid.data4[1], + guid.data4[2], + guid.data4[3], + guid.data4[4], + guid.data4[5], + guid.data4[6], + guid.data4[7]); + return result; +} diff --git a/src/metagen/metagen_os/core/metagen_os_core.h b/src/metagen/metagen_os/core/metagen_os_core.h new file mode 100644 index 00000000..34d33b99 --- /dev/null +++ b/src/metagen/metagen_os/core/metagen_os_core.h @@ -0,0 +1,365 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef OS_CORE_H +#define OS_CORE_H + +//////////////////////////////// +//~ rjf: Access Flags + +typedef U32 OS_AccessFlags; +enum +{ + OS_AccessFlag_Read = (1<<0), + OS_AccessFlag_Write = (1<<1), + OS_AccessFlag_Execute = (1<<2), + OS_AccessFlag_Shared = (1<<3), +}; + +//////////////////////////////// +//~ allen: Files + +typedef U32 OS_FileIterFlags; +enum +{ + OS_FileIterFlag_SkipFolders = (1 << 0), + OS_FileIterFlag_SkipFiles = (1 << 1), + OS_FileIterFlag_SkipHiddenFiles = (1 << 2), + OS_FileIterFlag_Done = (1 << 31), +}; + +typedef struct OS_FileIter OS_FileIter; +struct OS_FileIter +{ + OS_FileIterFlags flags; + U8 memory[600]; +}; + +typedef struct OS_FileInfo OS_FileInfo; +struct OS_FileInfo +{ + String8 name; + FileProperties props; +}; + +// nick: on-disk file identifier +typedef struct OS_FileID OS_FileID; +struct OS_FileID +{ + U64 v[3]; +}; + +//////////////////////////////// +//~ rjf: System Paths + +typedef enum OS_SystemPath +{ + OS_SystemPath_Binary, + OS_SystemPath_Initial, + OS_SystemPath_Current, + OS_SystemPath_UserProgramData, + OS_SystemPath_ModuleLoad, +} +OS_SystemPath; + +typedef enum OS_PathFromUserKind +{ + OS_PathFromUserKind_Save, + OS_PathFromUserKind_Load, +} +OS_PathFromUserKind; + +typedef struct OS_PathFromUser OS_PathFromUser; +struct OS_PathFromUser +{ + OS_PathFromUserKind kind; + String8 path; + U64 filter_count; + String8 *filter_extensions; + String8 *filter_names; +}; + +//////////////////////////////// +//~ allen: Launch Input + +typedef struct OS_LaunchOptions OS_LaunchOptions; +struct OS_LaunchOptions +{ + String8List cmd_line; + String8 path; + String8List env; + B32 inherit_env; + B32 consoleless; +}; + +//////////////////////////////// +//~ rjf: Handle Type + +typedef struct OS_Handle OS_Handle; +struct OS_Handle +{ + U64 u64[1]; +}; + +typedef struct OS_HandleNode OS_HandleNode; +struct OS_HandleNode +{ + OS_HandleNode *next; + OS_Handle v; +}; + +typedef struct OS_HandleList OS_HandleList; +struct OS_HandleList +{ + OS_HandleNode *first; + OS_HandleNode *last; + U64 count; +}; + +typedef struct OS_HandleArray OS_HandleArray; +struct OS_HandleArray +{ + OS_Handle *v; + U64 count; +}; + +//////////////////////////////// +// Time + +#define OS_UNIX_TIME_MAX max_U32 +typedef U32 OS_UnixTime; + +//////////////////////////////// +// Global Unique ID + +typedef struct OS_Guid +{ + U32 data1; + U16 data2; + U16 data3; + U8 data4[8]; +} OS_Guid; +StaticAssert(sizeof(OS_Guid) == 16, os_guid_check); + +//////////////////////////////// +//~ rjf: Thread Types + +typedef void OS_ThreadFunctionType(void *ptr); + +//////////////////////////////// +//~ rjf: Handle Type Functions (Helpers, Implemented Once) + +internal OS_Handle os_handle_zero(void); +internal B32 os_handle_match(OS_Handle a, OS_Handle b); +internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle); +internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list); + +//////////////////////////////// +//~ rjf: System Path Helper (Helper, Implemented Once) + +internal String8 os_string_from_system_path(Arena *arena, OS_SystemPath path); + +//////////////////////////////// +//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) + +internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv); + +//////////////////////////////// +//~ rjf: Process Helpers (Helper, Implemented Once) + +internal void os_relaunch_self(void); + +//////////////////////////////// +//~ rjf: Filesystem Helpers (Helpers, Implemented Once) + +internal String8 os_data_from_file_path(Arena *arena, String8 path); +internal B32 os_write_data_to_file_path(String8 path, String8 data); +internal B32 os_write_data_list_to_file_path(String8 path, String8List list); +internal FileProperties os_properties_from_file_path(String8 path); +internal OS_FileID os_id_from_file_path(String8 path); +internal S64 os_file_id_compare(OS_FileID a, OS_FileID b); +internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range); + +//////////////////////////////// +//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once) + +internal void os_mutex_take(OS_Handle mutex); +internal void os_mutex_drop(OS_Handle mutex); +internal void os_rw_mutex_take_r(OS_Handle rw_mutex); +internal void os_rw_mutex_drop_r(OS_Handle rw_mutex); +internal void os_rw_mutex_take_w(OS_Handle rw_mutex); +internal void os_rw_mutex_drop_w(OS_Handle rw_mutex); +// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout +internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us); +internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us); +internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us); +internal void os_condition_variable_signal(OS_Handle cv); +internal void os_condition_variable_broadcast(OS_Handle cv); + +#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex)) +#define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex)) +#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex)) + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void os_init(int argc, char **argv); + +//////////////////////////////// +//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) + +internal void* os_reserve(U64 size); +internal B32 os_commit(void *ptr, U64 size); +internal void* os_reserve_large(U64 size); +internal B32 os_commit_large(void *ptr, U64 size); +internal void os_decommit(void *ptr, U64 size); +internal void os_release(void *ptr, U64 size); + +internal B32 os_set_large_pages(B32 flag); +internal B32 os_large_pages_enabled(void); +internal U64 os_large_page_size(void); + +internal void* os_alloc_ring_buffer(U64 size, U64 *actual_size_out); +internal void os_free_ring_buffer(void *ring_buffer, U64 actual_size); + +//////////////////////////////// +//~ rjf: @os_hooks System Info (Implemented Per-OS) + +internal String8 os_machine_name(void); +internal U64 os_page_size(void); +internal U64 os_allocation_granularity(void); +internal U64 os_logical_core_count(void); + +//////////////////////////////// +//~ rjf: @os_hooks Process Info (Implemented Per-OS) + +internal String8List os_get_command_line_arguments(void); +internal S32 os_get_pid(void); +internal S32 os_get_tid(void); +internal String8List os_get_environment(void); +internal U64 os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out); + +//////////////////////////////// +//~ rjf: @os_hooks Process Control (Implemented Per-OS) + +internal void os_exit_process(S32 exit_code); + +//////////////////////////////// +//~ rjf: @os_hooks File System (Implemented Per-OS) + +//- rjf: files +internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path); +internal void os_file_close(OS_Handle file); +internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data); +internal void os_file_write(OS_Handle file, Rng1U64 rng, void *data); +internal B32 os_file_set_times(OS_Handle file, DateTime time); +internal FileProperties os_properties_from_file(OS_Handle file); +internal OS_FileID os_id_from_file(OS_Handle file); +internal B32 os_delete_file_at_path(String8 path); +internal B32 os_copy_file_path(String8 dst, String8 src); +internal String8 os_full_path_from_path(Arena *arena, String8 path); +internal B32 os_file_path_exists(String8 path); + +//- rjf: file maps +internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file); +internal void os_file_map_close(OS_Handle map); +internal void * os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range); +internal void os_file_map_view_close(OS_Handle map, void *ptr); + +//- rjf: directory iteration +internal OS_FileIter *os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags); +internal B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out); +internal void os_file_iter_end(OS_FileIter *iter); + +//- rjf: directory creation +internal B32 os_make_directory(String8 path); + +//////////////////////////////// +//~ rjf: @os_hooks Shared Memory (Implemented Per-OS) + +internal OS_Handle os_shared_memory_alloc(U64 size, String8 name); +internal OS_Handle os_shared_memory_open(String8 name); +internal void os_shared_memory_close(OS_Handle handle); +internal void * os_shared_memory_view_open(OS_Handle handle, Rng1U64 range); +internal void os_shared_memory_view_close(OS_Handle handle, void *ptr); + +//////////////////////////////// +//~ rjf: @os_hooks Time (Implemented Per-OS) + +internal OS_UnixTime os_now_unix(void); +internal DateTime os_now_universal_time(void); +internal DateTime os_universal_time_from_local_time(DateTime *local_time); +internal DateTime os_local_time_from_universal_time(DateTime *universal_time); +internal U64 os_now_microseconds(void); +internal void os_sleep_milliseconds(U32 msec); + +//////////////////////////////// +//~ rjf: @os_hooks Child Processes (Implemented Per-OS) + +internal B32 os_launch_process(OS_LaunchOptions *options, OS_Handle *handle_out); +internal B32 os_process_wait(OS_Handle handle, U64 endt_us); +internal void os_process_release_handle(OS_Handle handle); + +//////////////////////////////// +//~ rjf: @os_hooks Threads (Implemented Per-OS) + +internal OS_Handle os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params); +internal void os_release_thread_handle(OS_Handle thread); + +//////////////////////////////// +//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) + +// NOTE(allen): Mutexes are recursive - support counted acquire/release nesting +// on a single thread + +//- rjf: recursive mutexes +internal OS_Handle os_mutex_alloc(void); +internal void os_mutex_release(OS_Handle mutex); +internal void os_mutex_take_(OS_Handle mutex); +internal void os_mutex_drop_(OS_Handle mutex); + +//- rjf: reader/writer mutexes +internal OS_Handle os_rw_mutex_alloc(void); +internal void os_rw_mutex_release(OS_Handle rw_mutex); +internal void os_rw_mutex_take_r_(OS_Handle mutex); +internal void os_rw_mutex_drop_r_(OS_Handle mutex); +internal void os_rw_mutex_take_w_(OS_Handle mutex); +internal void os_rw_mutex_drop_w_(OS_Handle mutex); + +//- rjf: condition variables +internal OS_Handle os_condition_variable_alloc(void); +internal void os_condition_variable_release(OS_Handle cv); +// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout +internal B32 os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us); +internal B32 os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); +internal B32 os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); +internal void os_condition_variable_signal_(OS_Handle cv); +internal void os_condition_variable_broadcast_(OS_Handle cv); + +//- rjf: cross-process semaphores +internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name); +internal void os_semaphore_release(OS_Handle semaphore); +internal OS_Handle os_semaphore_open(String8 name); +internal void os_semaphore_close(OS_Handle semaphore); +internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us); +internal void os_semaphore_drop(OS_Handle semaphore); + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal OS_Handle os_library_open(String8 path); +internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name); +internal void os_library_close(OS_Handle lib); + +//////////////////////////////// +//~ rjf: @os_hooks Safe Calls (Implemented Per-OS) + +internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr); + +//////////////////////////////// +//~ rjf: @os_hooks GUIDs (Implemented Per-OS) + +internal OS_Guid os_make_guid(void); +internal String8 os_string_from_guid(Arena *arena, OS_Guid guid); + +#endif // OS_CORE_H diff --git a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c new file mode 100644 index 00000000..19f5260b --- /dev/null +++ b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c @@ -0,0 +1,1474 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#pragma comment(lib, "user32") +#pragma comment(lib, "winmm") +#pragma comment(lib, "shell32") +#pragma comment(lib, "advapi32") + +//////////////////////////////// +//~ allen: Definitions For Symbols That Are Sometimes Missing in Older Windows SDKs + +#if !defined(MEM_PRESERVE_PLACEHOLDER) +#define MEM_PRESERVE_PLACEHOLDER 0x2 +#endif +#if !defined(MEM_RESERVE_PLACEHOLDER) +# define MEM_REPLACE_PLACEHOLDER 0x00004000 +#endif +#if !defined(MEM_RESERVE_PLACEHOLDER) +# define MEM_RESERVE_PLACEHOLDER 0x00040000 +#endif + +typedef PVOID W32_VirtualAlloc2_Type(HANDLE Process, + PVOID BaseAddress, + SIZE_T Size, + ULONG AllocationType, + ULONG PageProtection, + void* ExtendedParameters, + ULONG ParameterCount); +typedef PVOID W32_MapViewOfFile3_Type(HANDLE FileMapping, + HANDLE Process, + PVOID BaseAddress, + ULONG64 Offset, + SIZE_T ViewSize, + ULONG AllocationType, + ULONG PageProtection, + void* ExtendedParameters, + ULONG ParameterCount); + +global W32_VirtualAlloc2_Type *w32_VirtualAlloc2_func = 0; +global W32_MapViewOfFile3_Type *w32_MapViewOfFile3_func = 0; + +//////////////////////////////// +//~ rjf: Globals + +global Arena *w32_perm_arena = 0; +global String8List w32_cmd_line_args = {0}; +global String8List w32_environment = {0}; +global CRITICAL_SECTION w32_mutex = {0}; +global String8 w32_initial_path = {0}; +global U64 w32_microsecond_resolution = 0; +global W32_Entity *w32_entity_free = 0; +global B32 w32_large_pages_enabled = 0; + +//////////////////////////////// +//~ rjf: Helpers + +//- rjf: files + +internal FilePropertyFlags +w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes){ + FilePropertyFlags flags = 0; + if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){ + flags |= FilePropertyFlag_IsFolder; + } + return(flags); +} + +internal void +w32_file_properties_from_attributes(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes){ + properties->size = Compose64Bit(attributes->nFileSizeHigh, attributes->nFileSizeLow); + w32_dense_time_from_file_time(&properties->created, &attributes->ftCreationTime); + w32_dense_time_from_file_time(&properties->modified, &attributes->ftLastWriteTime); + properties->flags = w32_file_property_flags_from_dwFileAttributes(attributes->dwFileAttributes); +} + +//- rjf: time + +internal void +w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in){ + out->year = in->wYear; + out->mon = in->wMonth - 1; + out->wday = in->wDayOfWeek; + out->day = in->wDay; + out->hour = in->wHour; + out->min = in->wMinute; + out->sec = in->wSecond; + out->msec = in->wMilliseconds; +} + +internal void +w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in){ + out->wYear = (WORD)(in->year); + out->wMonth = in->mon + 1; + out->wDay = in->day; + out->wHour = in->hour; + out->wMinute = in->min; + out->wSecond = in->sec; + out->wMilliseconds = in->msec; +} + +internal void +w32_dense_time_from_file_time(DenseTime *out, FILETIME *in){ + SYSTEMTIME systime = {0}; + FileTimeToSystemTime(in, &systime); + DateTime date_time = {0}; + w32_date_time_from_system_time(&date_time, &systime); + *out = dense_time_from_date_time(date_time); +} + +internal U32 +w32_sleep_ms_from_endt_us(U64 endt_us){ + U32 sleep_ms = 0; + if (endt_us == max_U64){ + sleep_ms = INFINITE; + } + else{ + U64 begint = os_now_microseconds(); + if (begint < endt_us){ + U64 sleep_us = endt_us - begint; + sleep_ms = (U32)((sleep_us + 999)/1000); + } + } + return(sleep_ms); +} + +//- rjf: entities + +internal W32_Entity* +w32_alloc_entity(W32_EntityKind kind){ + EnterCriticalSection(&w32_mutex); + W32_Entity *result = w32_entity_free; + if(result != 0) + { + SLLStackPop(w32_entity_free); + } + else + { + result = push_array_no_zero(w32_perm_arena, W32_Entity, 1); + } + MemoryZeroStruct(result); + Assert(result != 0); + LeaveCriticalSection(&w32_mutex); + MemoryZeroStruct(result); + result->kind = kind; + return(result); +} + +internal void +w32_free_entity(W32_Entity *entity){ + entity->kind = W32_EntityKind_Null; + EnterCriticalSection(&w32_mutex); + SLLStackPush(w32_entity_free, entity); + LeaveCriticalSection(&w32_mutex); +} + +//- rjf: threads + +internal DWORD +w32_thread_base(void *ptr){ + W32_Entity *entity = (W32_Entity*)ptr; + OS_ThreadFunctionType *func = entity->thread.func; + void *thread_ptr = entity->thread.ptr; + + func(thread_ptr); + + // remove my bit + LONG result = InterlockedAnd((LONG*)&entity->reference_mask, ~0x2); + // if the other bit is also gone, free entity + if ((result & 0x1) == 0){ + w32_free_entity(entity); + } + return(0); +} + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void +os_init(int argc, char **argv){ + // Load Fancy Memory Functions + { + HMODULE module = LoadLibraryA("kernel32.dll"); + if (module != 0){ + w32_VirtualAlloc2_func = (W32_VirtualAlloc2_Type*)GetProcAddress(module, "VirtualAlloc2"); + w32_MapViewOfFile3_func = (W32_MapViewOfFile3_Type*)GetProcAddress(module, "MapViewOfFile3"); + FreeLibrary(module); + } + } + + // Thread handshake + InitializeCriticalSection(&w32_mutex); + + // Permanent memory allocator for this layer + w32_perm_arena = arena_alloc(); + + // Init microsecond counter resolution + LARGE_INTEGER large_int_resolution; + if (QueryPerformanceFrequency(&large_int_resolution)){ + w32_microsecond_resolution = large_int_resolution.QuadPart; + } + else{ + w32_microsecond_resolution = 1; + } + + // Setup initial path + w32_initial_path = os_string_from_system_path(w32_perm_arena, OS_SystemPath_Current); + + // Setup command line arguments + w32_cmd_line_args = os_string_list_from_argcv(w32_perm_arena, argc, argv); + + // rjf: setup environment variables + { + CHAR *this_proc_env = GetEnvironmentStrings(); + U64 start_idx = 0; + for(U64 idx = 0;; idx += 1) + { + if(this_proc_env[idx] == 0) + { + if(start_idx == idx) + { + break; + } + else + { + String8 string = str8((U8 *)this_proc_env + start_idx, idx - start_idx); + str8_list_push(w32_perm_arena, &w32_environment, string); + start_idx = idx+1; + } + } + } + } +} + +//////////////////////////////// +//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) + +internal void* +os_reserve(U64 size){ + void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); + return(result); +} + +internal B32 +os_commit(void *ptr, U64 size){ + B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); + return(result); +} + +internal void* +os_reserve_large(U64 size){ + // we commit on reserve because windows + void *result = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE); + return(result); +} + +internal B32 +os_commit_large(void *ptr, U64 size){ + return 1; +} + +internal void +os_decommit(void *ptr, U64 size){ + VirtualFree(ptr, size, MEM_DECOMMIT); +} + +internal void +os_release(void *ptr, U64 size){ + // NOTE(rjf): size not used - not necessary on Windows, but necessary for other OSes. + VirtualFree(ptr, 0, MEM_RELEASE); +} + +internal B32 +os_set_large_pages(B32 flag) +{ + B32 is_ok = 0; + HANDLE token; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { + LUID luid; + if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) { + TOKEN_PRIVILEGES priv; + priv.PrivilegeCount = 1; + priv.Privileges[0].Luid = luid; + priv.Privileges[0].Attributes = flag ? SE_PRIVILEGE_ENABLED: 0; + if (AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0)) { + w32_large_pages_enabled = flag; + is_ok = 1; + } + } + CloseHandle(token); + } + return is_ok; +} + +internal B32 +os_large_pages_enabled(void) +{ + return w32_large_pages_enabled; +} + +internal U64 +os_large_page_size(void) +{ + U64 page_size = GetLargePageMinimum(); + return page_size; +} + +internal void* +os_alloc_ring_buffer(U64 size, U64 *actual_size_out){ + void *result = 0; + +#define W32_MAX_RING_SIZE GB(1) + + Assert(IsPow2(size)); + Assert(size <= W32_MAX_RING_SIZE); + + // get allocation granularity + SYSTEM_INFO info = {0}; + GetSystemInfo(&info); + Assert(IsPow2(info.dwAllocationGranularity)); + + // align size + U64 aligned_size = AlignPow2(size, (U64)(info.dwAllocationGranularity)); + + // split size + U32 lo_size = (U32)(aligned_size & 0xFFFFFFFF); + U32 hi_size = (U32)(aligned_size >> 32); + + // create pagefile-backed section + HANDLE section = CreateFileMappingA(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, hi_size, lo_size, 0); + + if (section != 0){ + if (w32_VirtualAlloc2_func != 0 && w32_MapViewOfFile3_func != 0){ + void *ptr1 = 0; + void *ptr2 = 0; + void *view1 = 0; + void *view2 = 0; + + // reserve virtual space placeholder + ptr1 = w32_VirtualAlloc2_func(0, 0, aligned_size*2, + MEM_RESERVE|MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, 0, 0); + if (ptr1 != 0){ + + // split off the first part of placeholder + VirtualFree(ptr1, aligned_size, MEM_RELEASE|MEM_PRESERVE_PLACEHOLDER); + ptr2 = ((U8*)ptr1 + aligned_size); + + // create views + view1 = w32_MapViewOfFile3_func(section, 0, ptr1, 0, aligned_size, + MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, 0, 0); + view2 = w32_MapViewOfFile3_func(section, 0, ptr2, 0, aligned_size, + MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, 0, 0); + if (view1 != 0 && view2 != 0){ + result = ptr1; + *actual_size_out = aligned_size; + } + } + + // cleanup + if (result == 0){ + if (ptr1 != 0){ + VirtualFree(ptr1, 0, MEM_RELEASE); + } + if (ptr2 != 0){ + VirtualFree(ptr2, 0, MEM_RELEASE); + } + if (view1 != 0){ + UnmapViewOfFileEx(view1, 0); + } + if (view2 != 0){ + UnmapViewOfFileEx(view2, 0); + } + } + } + + // no fancy memory functions available + else{ + for (U64 addr = GB(16); + addr < GB(272); + addr += W32_MAX_RING_SIZE){ + + // create the first view + void *view1 = MapViewOfFileEx(section, FILE_MAP_ALL_ACCESS, 0, 0, aligned_size, (void*)addr); + if (view1 != 0){ + + // create the second view + void *view2 = MapViewOfFileEx(section, FILE_MAP_ALL_ACCESS, 0, 0, aligned_size, (U8*)view1 + aligned_size); + + // on success make this the result + if (view2 != 0){ + result = view1; + *actual_size_out = aligned_size; + break; + } + + // cleanup view1 on failure + UnmapViewOfFile(view1); + } + } + } + } + + // cleanup + if (section != 0){ + CloseHandle(section); + } + + return(result); +} + +internal void +os_free_ring_buffer(void *ring_buffer, U64 actual_size){ + void *ptr1 = ring_buffer; + void *ptr2 = ((U8*)ptr1 + actual_size); + VirtualFree(ptr1, 0, MEM_RELEASE); + VirtualFree(ptr2, 0, MEM_RELEASE); + UnmapViewOfFileEx(ptr1, 0); + UnmapViewOfFileEx(ptr2, 0); +} + +//////////////////////////////// +//~ rjf: @os_hooks System Info (Implemented Per-OS) + +internal String8 +os_machine_name(void){ + local_persist U8 buffer[MAX_COMPUTERNAME_LENGTH + 1]; + local_persist String8 string = {0}; + local_persist B32 first = 1; + if (first){ + first = 0; + DWORD size = MAX_COMPUTERNAME_LENGTH + 1; + if (GetComputerNameA((char*)buffer, &size)){ + string = str8(buffer, size); + } + } + return(string); +} + +internal U64 +os_page_size(void){ + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + return(sysinfo.dwPageSize); +} + +internal U64 +os_allocation_granularity(void) +{ + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + return sysinfo.dwAllocationGranularity; +} + +internal U64 +os_logical_core_count(void) +{ + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Info (Implemented Per-OS) + +internal String8List +os_get_command_line_arguments(void) +{ + return w32_cmd_line_args; +} + +internal S32 +os_get_pid(void){ + DWORD id = GetCurrentProcessId(); + return((S32)id); +} + +internal S32 +os_get_tid(void){ + DWORD id = GetCurrentThreadId(); + return((S32)id); +} + +internal String8List +os_get_environment(void) +{ + return w32_environment; +} + +internal U64 +os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out){ + Temp scratch = scratch_begin(&arena, 1); + + U64 result = 0; + + switch (path){ + case OS_SystemPath_Binary: + { + local_persist B32 first = 1; + local_persist String8 name = {0}; + + // TODO(allen): let's just pre-compute this at init and skip the complexity + EnterCriticalSection(&w32_mutex); + if (first){ + first = 0; + DWORD size = KB(32); + U16 *buffer = push_array_no_zero(scratch.arena, U16, size); + DWORD length = GetModuleFileNameW(0, (WCHAR*)buffer, size); + String8 name8 = str8_from_16(scratch.arena, str16(buffer, length)); + String8 name_chopped = str8_chop_last_slash(name8); + name = push_str8_copy(w32_perm_arena, name_chopped); + } + LeaveCriticalSection(&w32_mutex); + + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_Initial: + { + Assert(w32_initial_path.str != 0); + result = 1; + str8_list_push(arena, out, w32_initial_path); + }break; + + case OS_SystemPath_Current: + { + DWORD length = GetCurrentDirectoryW(0, 0); + U16 *memory = push_array_no_zero(scratch.arena, U16, length + 1); + length = GetCurrentDirectoryW(length + 1, (WCHAR*)memory); + String8 name = str8_from_16(arena, str16(memory, length)); + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_UserProgramData: + { + local_persist B32 first = 1; + local_persist String8 name = {0}; + if (first){ + first = 0; + U64 size = KB(32); + U16 *buffer = push_array_no_zero(scratch.arena, U16, size); + if (SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, (WCHAR*)buffer))){ + name = str8_from_16(scratch.arena, str16_cstring(buffer)); + EnterCriticalSection(&w32_mutex); + U8 *buffer8 = push_array_no_zero(w32_perm_arena, U8, name.size); + LeaveCriticalSection(&w32_mutex); + MemoryCopy(buffer8, name.str, name.size); + name.str = buffer8; + } + } + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_ModuleLoad: + { + U64 og_count = out->node_count; + + { + UINT cap = GetSystemDirectoryW(0, 0); + if (cap > 0){ + U16 *buffer = push_array_no_zero(scratch.arena, U16, cap); + UINT size = GetSystemDirectoryW((WCHAR*)buffer, cap); + if (size > 0){ + str8_list_push(arena, out, str8_from_16(arena, str16(buffer, size))); + } + } + } + + { + UINT cap = GetWindowsDirectoryW(0, 0); + if (cap > 0){ + U16 *buffer = push_array_no_zero(scratch.arena, U16, cap); + UINT size = GetWindowsDirectoryW((WCHAR*)buffer, cap); + if (size > 0){ + str8_list_push(arena, out, str8_from_16(arena, str16(buffer, size))); + } + } + } + + result = out->node_count - og_count; + }break; + } + + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Control (Implemented Per-OS) + +internal void +os_exit_process(S32 exit_code){ + ExitProcess(exit_code); +} + +//////////////////////////////// +//~ rjf: @os_hooks File System (Implemented Per-OS) + +//- rjf: files + +internal OS_Handle +os_file_open(OS_AccessFlags flags, String8 path) +{ + OS_Handle result = {0}; + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + DWORD access_flags = 0; + DWORD share_mode = 0; + DWORD creation_disposition = OPEN_EXISTING; + if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} + if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} + if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} + if(flags & OS_AccessFlag_Shared) {share_mode = (!!(flags & OS_AccessFlag_Write)*FILE_SHARE_WRITE)|FILE_SHARE_READ;} + if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} + HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); + if(file != INVALID_HANDLE_VALUE) + { + result.u64[0] = (U64)file; + } + scratch_end(scratch); + return result; +} + +internal void +os_file_close(OS_Handle file) +{ + if(os_handle_match(file, os_handle_zero())) { return; } + HANDLE handle = (HANDLE)file.u64[0]; + CloseHandle(handle); +} + +internal U64 +os_file_read(OS_Handle file, Rng1U64 rng, void *out_data) +{ + if(os_handle_match(file, os_handle_zero())) { return 0; } + HANDLE handle = (HANDLE)file.u64[0]; + + // rjf: clamp range by file size + U64 size = 0; + GetFileSizeEx(handle, (LARGE_INTEGER *)&size); + Rng1U64 rng_clamped = r1u64(ClampTop(rng.min, size), ClampTop(rng.max, size)); + U64 total_read_size = 0; + + // rjf: read loop + { + U64 to_read = dim_1u64(rng_clamped); + for(U64 off = rng.min; total_read_size < to_read;) + { + U64 amt64 = to_read - total_read_size; + U32 amt32 = u32_from_u64_saturate(amt64); + DWORD read_size = 0; + OVERLAPPED overlapped = {0}; + overlapped.Offset = (off&0x00000000ffffffffull); + overlapped.OffsetHigh = (off&0xffffffff00000000ull) >> 32; + ReadFile(handle, (U8 *)out_data + total_read_size, amt32, &read_size, &overlapped); + off += read_size; + total_read_size += read_size; + if(read_size != amt32) + { + break; + } + } + } + + return total_read_size; +} + +internal void +os_file_write(OS_Handle file, Rng1U64 rng, void *data) +{ + if(os_handle_match(file, os_handle_zero())) { return; } + HANDLE win_handle = (HANDLE)file.u64[0]; + U64 src_off = 0; + U64 dst_off = rng.min; + U64 bytes_to_write_total = rng.max-rng.min; + for(;src_off < bytes_to_write_total;) + { + void *bytes_src = (void *)((U8 *)data + src_off); + U64 bytes_to_write_64 = (bytes_to_write_total-src_off); + U32 bytes_to_write_32 = u32_from_u64_saturate(bytes_to_write_64); + U32 bytes_written = 0; + OVERLAPPED overlapped = {0}; + overlapped.Offset = (dst_off&0x00000000ffffffffull); + overlapped.OffsetHigh = (dst_off&0xffffffff00000000ull) >> 32; + BOOL success = WriteFile(win_handle, bytes_src, bytes_to_write_32, (DWORD *)&bytes_written, &overlapped); + if(success == 0) + { + break; + } + src_off += bytes_written; + dst_off += bytes_written; + } +} + +internal B32 +os_file_set_times(OS_Handle file, DateTime time) +{ + if(os_handle_match(file, os_handle_zero())) { return 0; } + B32 result = 0; + HANDLE handle = (HANDLE)file.u64[0]; + SYSTEMTIME system_time = {0}; + w32_system_time_from_date_time(&system_time, &time); + FILETIME file_time = {0}; + result = (SystemTimeToFileTime(&system_time, &file_time) && + SetFileTime(handle, &file_time, &file_time, &file_time)); + return result; +} + +internal FileProperties +os_properties_from_file(OS_Handle file) +{ + if(os_handle_match(file, os_handle_zero())) { FileProperties r = {0}; return r; } + FileProperties props = {0}; + HANDLE handle = (HANDLE)file.u64[0]; + BY_HANDLE_FILE_INFORMATION info; + BOOL info_good = GetFileInformationByHandle(handle, &info); + if(info_good) + { + U32 size_lo = info.nFileSizeLow; + U32 size_hi = info.nFileSizeHigh; + props.size = (U64)size_lo | (((U64)size_hi)<<32); + w32_dense_time_from_file_time(&props.modified, &info.ftLastWriteTime); + w32_dense_time_from_file_time(&props.created, &info.ftCreationTime); + props.flags = w32_file_property_flags_from_dwFileAttributes(info.dwFileAttributes); + } + return props; +} + +internal OS_FileID +os_id_from_file(OS_Handle file) +{ + if(os_handle_match(file, os_handle_zero())) { OS_FileID r = {0}; return r; } + OS_FileID result = {0}; + HANDLE handle = (HANDLE)file.u64[0]; + BY_HANDLE_FILE_INFORMATION info; + BOOL is_ok = GetFileInformationByHandle(handle, &info); + if(is_ok) + { + result.v[0] = info.dwVolumeSerialNumber; + result.v[1] = info.nFileIndexLow; + result.v[2] = info.nFileIndexHigh; + } + return result; +} + +internal B32 +os_delete_file_at_path(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + B32 result = DeleteFileW((WCHAR*)path16.str); + scratch_end(scratch); + return result; +} + +internal B32 +os_copy_file_path(String8 dst, String8 src) +{ + Temp scratch = scratch_begin(0, 0); + String16 dst16 = str16_from_8(scratch.arena, dst); + String16 src16 = str16_from_8(scratch.arena, src); + B32 result = CopyFileW((WCHAR*)src16.str, (WCHAR*)dst16.str, 0); + scratch_end(scratch); + return result; +} + +internal String8 +os_full_path_from_path(Arena *arena, String8 path) +{ + Temp scratch = scratch_begin(&arena, 1); + DWORD buffer_size = MAX_PATH + 1; + U16 *buffer = push_array_no_zero(scratch.arena, U16, buffer_size); + String16 path16 = str16_from_8(scratch.arena, path); + DWORD path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, (WCHAR*)buffer, NULL); + String8 full_path = str8_from_16(arena, str16(buffer, path16_size)); + scratch_end(scratch); + return full_path; +} + +internal B32 +os_file_path_exists(String8 path) +{ + Temp scratch = scratch_begin(0,0); + String16 path16 = str16_from_8(scratch.arena, path); + DWORD attributes = GetFileAttributesW((WCHAR *)path16.str); + B32 exists = (attributes != INVALID_FILE_ATTRIBUTES) && !!(~attributes & FILE_ATTRIBUTE_DIRECTORY); + scratch_end(scratch); + return exists; +} + +//- rjf: file maps + +internal OS_Handle +os_file_map_open(OS_AccessFlags flags, OS_Handle file) +{ + OS_Handle map = {0}; + { + HANDLE file_handle = (HANDLE)file.u64[0]; + DWORD protect_flags = 0; + { + switch(flags) + { + default:{}break; + case OS_AccessFlag_Read: + {protect_flags = PAGE_READONLY;}break; + case OS_AccessFlag_Write: + case OS_AccessFlag_Read|OS_AccessFlag_Write: + {protect_flags = PAGE_READWRITE;}break; + case OS_AccessFlag_Execute: + case OS_AccessFlag_Read|OS_AccessFlag_Execute: + {protect_flags = PAGE_EXECUTE_READ;}break; + case OS_AccessFlag_Execute|OS_AccessFlag_Write|OS_AccessFlag_Read: + case OS_AccessFlag_Execute|OS_AccessFlag_Write: + {protect_flags = PAGE_EXECUTE_READWRITE;}break; + } + } + HANDLE map_handle = CreateFileMappingA(file_handle, 0, protect_flags, 0, 0, 0); + map.u64[0] = (U64)map_handle; + } + return map; +} + +internal void +os_file_map_close(OS_Handle map) +{ + HANDLE handle = (HANDLE)map.u64[0]; + CloseHandle(handle); +} + +internal void * +os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) +{ + HANDLE handle = (HANDLE)map.u64[0]; + U32 off_lo = (U32)((range.min&0x00000000ffffffffull)>>0); + U32 off_hi = (U32)((range.min&0xffffffff00000000ull)>>32); + U64 size = dim_1u64(range); + DWORD access_flags = 0; + { + switch(flags) + { + default:{}break; + case OS_AccessFlag_Read: + { + access_flags = FILE_MAP_READ; + }break; + case OS_AccessFlag_Write: + { + access_flags = FILE_MAP_WRITE; + }break; + case OS_AccessFlag_Read|OS_AccessFlag_Write: + { + access_flags = FILE_MAP_ALL_ACCESS; + }break; + case OS_AccessFlag_Execute: + case OS_AccessFlag_Read|OS_AccessFlag_Execute: + case OS_AccessFlag_Write|OS_AccessFlag_Execute: + case OS_AccessFlag_Read|OS_AccessFlag_Write|OS_AccessFlag_Execute: + { + access_flags = FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE; + }break; + } + } + void *result = MapViewOfFile(handle, access_flags, off_hi, off_lo, size); + return result; +} + +internal void +os_file_map_view_close(OS_Handle map, void *ptr) +{ + UnmapViewOfFile(ptr); +} + +//- rjf: directory iteration + +internal OS_FileIter * +os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 path_with_wildcard = push_str8_cat(scratch.arena, path, str8_lit("\\*")); + String16 path16 = str16_from_8(scratch.arena, path_with_wildcard); + OS_FileIter *iter = push_array(arena, OS_FileIter, 1); + iter->flags = flags; + W32_FileIter *w32_iter = (W32_FileIter*)iter->memory; + w32_iter->handle = FindFirstFileW((WCHAR*)path16.str, &w32_iter->find_data); + scratch_end(scratch); + return iter; +} + +internal B32 +os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) +{ + B32 result = 0; + OS_FileIterFlags flags = iter->flags; + W32_FileIter *w32_iter = (W32_FileIter*)iter->memory; + if (!(flags & OS_FileIterFlag_Done) && w32_iter->handle != INVALID_HANDLE_VALUE) + { + do + { + // check is usable + B32 usable_file = 1; + + WCHAR *file_name = w32_iter->find_data.cFileName; + DWORD attributes = w32_iter->find_data.dwFileAttributes; + if (file_name[0] == '.'){ + if (flags & OS_FileIterFlag_SkipHiddenFiles){ + usable_file = 0; + } + else if (file_name[1] == 0){ + usable_file = 0; + } + else if (file_name[1] == '.' && file_name[2] == 0){ + usable_file = 0; + } + } + if (attributes & FILE_ATTRIBUTE_DIRECTORY){ + if (flags & OS_FileIterFlag_SkipFolders){ + usable_file = 0; + } + } + else{ + if (flags & OS_FileIterFlag_SkipFiles){ + usable_file = 0; + } + } + + // emit if usable + if (usable_file){ + info_out->name = str8_from_16(arena, str16_cstring((U16*)file_name)); + info_out->props.size = (U64)w32_iter->find_data.nFileSizeLow | (((U64)w32_iter->find_data.nFileSizeHigh)<<32); + w32_dense_time_from_file_time(&info_out->props.created, &w32_iter->find_data.ftCreationTime); + w32_dense_time_from_file_time(&info_out->props.modified, &w32_iter->find_data.ftLastWriteTime); + info_out->props.flags = w32_file_property_flags_from_dwFileAttributes(attributes); + result = 1; + if (!FindNextFileW(w32_iter->handle, &w32_iter->find_data)){ + iter->flags |= OS_FileIterFlag_Done; + } + break; + } + }while(FindNextFileW(w32_iter->handle, &w32_iter->find_data)); + + if (!result){ + iter->flags |= OS_FileIterFlag_Done; + } + } + return result; +} + +internal void +os_file_iter_end(OS_FileIter *iter) +{ + W32_FileIter *w32_iter = (W32_FileIter*)iter->memory; + FindClose(w32_iter->handle); +} + +//- rjf: directory creation + +internal B32 +os_make_directory(String8 path) +{ + B32 result = 0; + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, path); + WIN32_FILE_ATTRIBUTE_DATA attributes = {0}; + GetFileAttributesExW((WCHAR*)name16.str, GetFileExInfoStandard, &attributes); + if(attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + result = 1; + } + else if(CreateDirectoryW((WCHAR*)name16.str, 0)) + { + result = 1; + } + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Shared Memory (Implemented Per-OS) + +internal OS_Handle +os_shared_memory_alloc(U64 size, String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE file = CreateFileMappingW(INVALID_HANDLE_VALUE, + 0, + PAGE_READWRITE, + (U32)((size & 0xffffffff00000000) >> 32), + (U32)((size & 0x00000000ffffffff)), + (WCHAR *)name16.str); + OS_Handle result = {(U64)file}; + scratch_end(scratch); + return result; +} + +internal OS_Handle +os_shared_memory_open(String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE file = OpenFileMappingW(FILE_MAP_ALL_ACCESS, 0, (WCHAR *)name16.str); + OS_Handle result = {(U64)file}; + scratch_end(scratch); + return result; +} + +internal void +os_shared_memory_close(OS_Handle handle) +{ + HANDLE file = (HANDLE)(handle.u64[0]); + CloseHandle(file); +} + +internal void * +os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) +{ + HANDLE file = (HANDLE)(handle.u64[0]); + U64 offset = range.min; + U64 size = range.max-range.min; + void *ptr = MapViewOfFile(file, FILE_MAP_ALL_ACCESS, + (U32)((offset & 0xffffffff00000000) >> 32), + (U32)((offset & 0x00000000ffffffff)), + size); + return ptr; +} + +internal void +os_shared_memory_view_close(OS_Handle handle, void *ptr) +{ + UnmapViewOfFile(ptr); +} + +//////////////////////////////// +//~ rjf: @os_hooks Time (Implemented Per-OS) + +internal OS_UnixTime +os_now_unix(void) +{ + FILETIME file_time; + GetSystemTimeAsFileTime(&file_time); + + U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime; + U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000); + + Assert(unix_time64 <= OS_UNIX_TIME_MAX); + OS_UnixTime unix_time32 = (OS_UnixTime)unix_time64; + + return unix_time32; +} + +internal DateTime +os_now_universal_time(void){ + SYSTEMTIME systime = {0}; + GetSystemTime(&systime); + DateTime result = {0}; + w32_date_time_from_system_time(&result, &systime); + return(result); +} + +internal DateTime +os_universal_time_from_local_time(DateTime *date_time){ + SYSTEMTIME systime = {0}; + w32_system_time_from_date_time(&systime, date_time); + FILETIME ftime = {0}; + SystemTimeToFileTime(&systime, &ftime); + FILETIME ftime_local = {0}; + LocalFileTimeToFileTime(&ftime, &ftime_local); + FileTimeToSystemTime(&ftime_local, &systime); + DateTime result = {0}; + w32_date_time_from_system_time(&result, &systime); + return(result); +} + +internal DateTime +os_local_time_from_universal_time(DateTime *date_time){ + SYSTEMTIME systime = {0}; + w32_system_time_from_date_time(&systime, date_time); + FILETIME ftime = {0}; + SystemTimeToFileTime(&systime, &ftime); + FILETIME ftime_local = {0}; + FileTimeToLocalFileTime(&ftime, &ftime_local); + FileTimeToSystemTime(&ftime_local, &systime); + DateTime result = {0}; + w32_date_time_from_system_time(&result, &systime); + return(result); +} + +internal U64 +os_now_microseconds(void){ + U64 result = 0; + LARGE_INTEGER large_int_counter; + if (QueryPerformanceCounter(&large_int_counter)){ + result = (large_int_counter.QuadPart*Million(1))/w32_microsecond_resolution; + } + return(result); +} + +internal void +os_sleep_milliseconds(U32 msec){ + Sleep(msec); +} + +//////////////////////////////// +//~ rjf: @os_hooks Child Processes (Implemented Per-OS) + +internal B32 +os_launch_process(OS_LaunchOptions *options, OS_Handle *handle_out){ + B32 result = 0; + Temp scratch = scratch_begin(0, 0); + + StringJoin join_params = {0}; + join_params.pre = str8_lit("\""); + join_params.sep = str8_lit("\" \""); + join_params.post = str8_lit("\""); + String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); + + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + B32 use_null_env_arg = 0; + String8List all_opts = options->env; + if(options->inherit_env != 0) + { + if(all_opts.node_count != 0) + { + MemoryZeroStruct(&all_opts); + for(String8Node *n = options->env.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for(String8Node *n = w32_environment.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + else + { + use_null_env_arg = 1; + } + } + String8 env = {0}; + if(use_null_env_arg == 0) + { + env = str8_list_join(scratch.arena, &all_opts, &join_params2); + } + + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = {0}; + if(use_null_env_arg == 0) + { + env16 = str16_from_8(scratch.arena, env); + } + + DWORD creation_flags = 0; + if(options->consoleless) + { + creation_flags |= CREATE_NO_WINDOW; + } + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, creation_flags, use_null_env_arg ? 0 : (WCHAR*)env16.str, (WCHAR*)dir16.str, + &startup_info, &process_info)){ + if (handle_out == 0){ + CloseHandle(process_info.hProcess); + } + CloseHandle(process_info.hThread); + + if (handle_out != 0){ + OS_Handle handle_result = {(U64)process_info.hProcess}; + *handle_out = handle_result; + } + result = 1; + } + + scratch_end(scratch); + return(result); +} + +internal B32 +os_process_wait(OS_Handle handle, U64 endt_us){ + HANDLE process = (HANDLE)(handle.u64[0]); + DWORD sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + DWORD result = WaitForSingleObject(process, sleep_ms); + return (result == WAIT_OBJECT_0); +} + +internal void +os_process_release_handle(OS_Handle handle){ + HANDLE process = (HANDLE)(handle.u64[0]); + CloseHandle(process); +} + +//////////////////////////////// +//~ rjf: @os_hooks Threads (Implemented Per-OS) + +internal OS_Handle +os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_Thread); + entity->reference_mask = 0x3; + entity->thread.func = func; + entity->thread.ptr = ptr; + entity->thread.handle = CreateThread(0, 0, w32_thread_base, entity, 0, &entity->thread.tid); + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_release_thread_handle(OS_Handle thread){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(thread.u64[0]); + // remove my bit + LONG result = InterlockedAnd((LONG*)&entity->reference_mask, ~0x1); + // if the other bit is also gone, free entity + if ((result & 0x2) == 0){ + w32_free_entity(entity); + } +} + +//////////////////////////////// +//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) + +//- rjf: mutexes + +internal OS_Handle +os_mutex_alloc(void){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_Mutex); + InitializeCriticalSection(&entity->mutex); + + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_mutex_release(OS_Handle mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + w32_free_entity(entity); +} + +internal void +os_mutex_take_(OS_Handle mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + EnterCriticalSection(&entity->mutex); +} + +internal void +os_mutex_drop_(OS_Handle mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + LeaveCriticalSection(&entity->mutex); +} + +//- rjf: reader/writer mutexes + +internal OS_Handle +os_rw_mutex_alloc(void){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_RWMutex); + InitializeSRWLock(&entity->rw_mutex); + + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_rw_mutex_release(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + w32_free_entity(entity); +} + +internal void +os_rw_mutex_take_r_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + AcquireSRWLockShared(&entity->rw_mutex); +} + +internal void +os_rw_mutex_drop_r_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + ReleaseSRWLockShared(&entity->rw_mutex); +} + +internal void +os_rw_mutex_take_w_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + AcquireSRWLockExclusive(&entity->rw_mutex); +} + +internal void +os_rw_mutex_drop_w_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + ReleaseSRWLockExclusive(&entity->rw_mutex); +} + +//- rjf: condition variables + +internal OS_Handle +os_condition_variable_alloc(void){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_ConditionVariable); + InitializeConditionVariable(&entity->cv); + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_condition_variable_release(OS_Handle cv){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + w32_free_entity(entity); +} + +internal B32 +os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us){ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + W32_Entity *mutex_entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + result = SleepConditionVariableCS(&entity->cv, &mutex_entity->mutex, sleep_ms); + } + return(result); +} + +internal B32 +os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + W32_Entity *mutex_entity = (W32_Entity*)PtrFromInt(mutex_rw.u64[0]); + result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, + CONDITION_VARIABLE_LOCKMODE_SHARED); + } + return(result); +} + +internal B32 +os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + W32_Entity *mutex_entity = (W32_Entity*)PtrFromInt(mutex_rw.u64[0]); + result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, 0); + } + return(result); +} + +internal void +os_condition_variable_signal_(OS_Handle cv){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + WakeConditionVariable(&entity->cv); +} + +internal void +os_condition_variable_broadcast_(OS_Handle cv){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + WakeAllConditionVariable(&entity->cv); +} + +//- rjf: cross-process semaphores + +internal OS_Handle +os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE handle = CreateSemaphoreW(0, initial_count, max_count, (WCHAR *)name16.str); + OS_Handle result = {(U64)handle}; + scratch_end(scratch); + return result; +} + +internal void +os_semaphore_release(OS_Handle semaphore) +{ + HANDLE handle = (HANDLE)semaphore.u64[0]; + CloseHandle(handle); +} + +internal OS_Handle +os_semaphore_open(String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE handle = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS , 0, (WCHAR *)name16.str); + OS_Handle result = {(U64)handle}; + scratch_end(scratch); + return result; +} + +internal void +os_semaphore_close(OS_Handle semaphore) +{ + HANDLE handle = (HANDLE)semaphore.u64[0]; + CloseHandle(handle); +} + +internal B32 +os_semaphore_take(OS_Handle semaphore, U64 endt_us) +{ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + HANDLE handle = (HANDLE)semaphore.u64[0]; + DWORD wait_result = WaitForSingleObject(handle, sleep_ms); + B32 result = (wait_result == WAIT_OBJECT_0); + return result; +} + +internal void +os_semaphore_drop(OS_Handle semaphore) +{ + HANDLE handle = (HANDLE)semaphore.u64[0]; + ReleaseSemaphore(handle, 1, 0); +} + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal OS_Handle +os_library_open(String8 path){ + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + HMODULE mod = LoadLibraryW((LPCWSTR)path16.str); + OS_Handle result = { (U64)mod }; + scratch_end(scratch); + return(result); +} + +internal VoidProc* +os_library_load_proc(OS_Handle lib, String8 name){ + Temp scratch = scratch_begin(0, 0); + HMODULE mod = (HMODULE)lib.u64[0]; + name = push_str8_copy(scratch.arena, name); + VoidProc *result = (VoidProc*)GetProcAddress(mod, (LPCSTR)name.str); + scratch_end(scratch); + return(result); +} + +internal void +os_library_close(OS_Handle lib){ + HMODULE mod = (HMODULE)lib.u64[0]; + FreeLibrary(mod); +} + +//////////////////////////////// +//~ rjf: @os_hooks Safe Calls (Implemented Per-OS) + +internal void +os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr){ + __try{ + func(ptr); + } + __except (EXCEPTION_EXECUTE_HANDLER){ + if (fail_handler != 0){ + fail_handler(ptr); + } + ExitProcess(1); + } +} + +//////////////////////////////// + +internal OS_Guid +os_make_guid(void) +{ + OS_Guid result; MemoryZeroStruct(&result); + UUID uuid; + RPC_STATUS rpc_status = UuidCreate(&uuid); + if (rpc_status == RPC_S_OK) { + result.data1 = uuid.Data1; + result.data2 = uuid.Data2; + result.data3 = uuid.Data3; + MemoryCopyArray(result.data4, uuid.Data4); + } + return result; +} + diff --git a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h new file mode 100644 index 00000000..3ce6aac4 --- /dev/null +++ b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h @@ -0,0 +1,91 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef WIN32_H +#define WIN32_H + +//////////////////////////////// +//~ NOTE(allen): Negotiate the windows header include order + +#if OS_FEATURE_SOCKET +#include +#endif + +#include +#include + +#if OS_FEATURE_GRAPHICAL +#include +#endif + +#if OS_FEATURE_SOCKET +#include +#include +#endif + +#include + +//////////////////////////////// +//~ NOTE(allen): File Iterator + +typedef struct W32_FileIter W32_FileIter; +struct W32_FileIter +{ + HANDLE handle; + WIN32_FIND_DATAW find_data; +}; +StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(W32_FileIter), file_iter_memory_size); + +//////////////////////////////// +//~ NOTE(allen): Threading Entities + +typedef enum W32_EntityKind +{ + W32_EntityKind_Null, + W32_EntityKind_Thread, + W32_EntityKind_Mutex, + W32_EntityKind_RWMutex, + W32_EntityKind_ConditionVariable, +} +W32_EntityKind; + +typedef struct W32_Entity W32_Entity; +struct W32_Entity +{ + W32_Entity *next; + W32_EntityKind kind; + volatile U32 reference_mask; + union{ + struct{ + OS_ThreadFunctionType *func; + void *ptr; + HANDLE handle; + DWORD tid; + } thread; + CRITICAL_SECTION mutex; + SRWLOCK rw_mutex; + CONDITION_VARIABLE cv; + }; +}; + +//////////////////////////////// +//~ rjf: Helpers + +//- rjf: files +internal FilePropertyFlags w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes); +internal void w32_file_properties_from_attributes(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes); + +//- rjf: time +internal void w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in); +internal void w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in); +internal void w32_dense_time_from_file_time(DenseTime *out, FILETIME *in); +internal U32 w32_sleep_ms_from_endt_us(U64 endt_us); + +//- rjf: entities +internal W32_Entity* w32_alloc_entity(W32_EntityKind kind); +internal void w32_free_entity(W32_Entity *entity); + +//- rjf: threads +internal DWORD w32_thread_base(void *ptr); + +#endif //WIN32_H diff --git a/src/metagen/metagen_os/metagen_os_inc.c b/src/metagen/metagen_os/metagen_os_inc.c new file mode 100644 index 00000000..ffa847ef --- /dev/null +++ b/src/metagen/metagen_os/metagen_os_inc.c @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Include OS features for extra features and target OS + +#include "core/metagen_os_core.c" + +#if OS_FEATURE_SOCKET +#include "socket/metagen_os_socket.c" +#endif + +#if OS_FEATURE_GRAPHICAL +#include "gfx/metagen_os_gfx.c" +#endif + +#if OS_WINDOWS +# include "core/win32/metagen_os_core_win32.c" +# if OS_FEATURE_SOCKET +# include "socket/win32/metagen_os_socket_win32.c" +# endif +# if OS_FEATURE_GRAPHICAL +# include "gfx/win32/metagen_os_gfx_win32.c" +# endif +#elif OS_LINUX +# include "core/linux/metagen_os_core_linux.c" +#else +# error no OS layer setup +#endif diff --git a/src/metagen/metagen_os/metagen_os_inc.h b/src/metagen/metagen_os/metagen_os_inc.h new file mode 100644 index 00000000..73b04029 --- /dev/null +++ b/src/metagen/metagen_os/metagen_os_inc.h @@ -0,0 +1,39 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef OS_INC_H +#define OS_INC_H + +#if !defined(OS_FEATURE_SOCKET) +# define OS_FEATURE_SOCKET 0 +#endif + +#if !defined(OS_FEATURE_GRAPHICAL) +# define OS_FEATURE_GRAPHICAL 0 +#endif + +#include "core/metagen_os_core.h" + +#if OS_FEATURE_SOCKET +#include "socket/metagen_os_socket.h" +#endif + +#if OS_FEATURE_GRAPHICAL +#include "gfx/metagen_os_gfx.h" +#endif + +#if OS_WINDOWS +# include "core/win32/metagen_os_core_win32.h" +# if OS_FEATURE_SOCKET +# include "socket/win32/metagen_os_socket_win32.h" +# endif +# if OS_FEATURE_GRAPHICAL +# include "gfx/win32/metagen_os_gfx_win32.h" +# endif +#elif OS_LINUX +# include "core/linux/metagen_os_core_linux.h" +#else +# error no OS layer setup +#endif + +#endif //OS_SWITCH_H diff --git a/src/mule/inline_body.cpp b/src/mule/inline_body.cpp new file mode 100644 index 00000000..a813d05f --- /dev/null +++ b/src/mule/inline_body.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +bias = (bias^x)&7; +x -= bias; +x *= 2; +x *= x; +x += bias; \ No newline at end of file diff --git a/src/mule/mule_c.c b/src/mule/mule_c.c new file mode 100644 index 00000000..e307760e --- /dev/null +++ b/src/mule/mule_c.c @@ -0,0 +1,106 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/* +* Program to run in debugger organized to provide tests for +* single threaded stepping, breakpoints, evaluation. +*/ + +//////////////////////////////// +// NOTE(allen): Complex Types + +#include + +void +c_type_coverage_eval_tests(void){ +#if _WIN32 + _Fcomplex x = _FCbuild(0.f, 1.f); + _Dcomplex y = _Cbuild(0.f, -1.f); + +#else + float complex x = 0.f + 1.f*I; + double complex y = 0.0 - 1.0*I; + +#endif +} + +//////////////////////////////// +// NOTE(allen): Reuse Type Names From Another Module + +#include + +typedef struct Basics{ + double a; + float b; + unsigned long long c; + long long d; + unsigned int e; + int f; + unsigned short g; + short h; + unsigned char i; + char j; + + int z; +} Basics; + +typedef struct Basics_Stdint{ + double x1; + float x2; + uint64_t x3; + int64_t x4; + uint32_t x5; + int32_t x6; + uint16_t x7; + int16_t x8; + uint8_t x9; + int8_t x0; +} Basics_Stdint; + +typedef struct Pair{ + int i; + float f; +} Pair; + +void +c_versions_of_same_types(void){ + Basics basics = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, }; + Basics_Stdint basics_stdint = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, }; + Pair memory_[] = { + {100, 1.f}, + {101, 2.f}, + {102, 4.f}, + {103, 8.f}, + {104, 16.f}, + {105, 32.f}, + }; + + int x = memory_[3].i + basics.f; +} + +//////////////////////////////// +//~ NOTE(rjf): Bitfields + +typedef struct TypeWithBitfield TypeWithBitfield; +struct TypeWithBitfield +{ + int v : 14; + int w : 4; + int x : 32; + int y : 4; + int z : 10; +}; + +void +c_type_with_bitfield_usage(void) +{ + TypeWithBitfield b = {0}; + b.v = 100; + b.w = 6; + b.x = 434512; + b.y = 7; + b.z = 12; + int x = (b.v + b.x); + int y = (b.y - b.z); + int z = (b.w) + 5; +} diff --git a/src/mule/mule_c.h b/src/mule/mule_c.h new file mode 100644 index 00000000..792972c0 --- /dev/null +++ b/src/mule/mule_c.h @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/* +* Program to run in debugger organized to provide tests for +* single threaded stepping, breakpoints, evaluation. +*/ + +void c_type_coverage_eval_tests(void); +void c_type_with_bitfield_usage(void); \ No newline at end of file diff --git a/src/mule/mule_inline.cpp b/src/mule/mule_inline.cpp new file mode 100644 index 00000000..76f18016 --- /dev/null +++ b/src/mule/mule_inline.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/* +** Make sure we have an inlined function +*/ + +#if defined(_MSC_VER) +# define FORCE_INLINE __forceinline +#elif defined(__clang__) +# define FORCE_INLINE __attribute__((always_inline)) +#else +# error need force inline for this compiler +#endif + +//////////////////////////////// +// NOTE(allen): Inline Stepping + +extern unsigned int fixed_frac_bits = 5; +static unsigned int bias = 7; + +static FORCE_INLINE unsigned int +fixed_mul(unsigned int a, unsigned int b){ + unsigned int c = (((a - bias)*(b - bias)) >> fixed_frac_bits) + bias; + return(c); +} + +static FORCE_INLINE unsigned int +multi_file_inlinesite(unsigned int x){ + // force compiler to generate annotations for code that's inside another file +#include "inline_body.cpp" + return x >> fixed_frac_bits; +} + +static unsigned int test_value = 0; + +unsigned int +inline_stepping_tests(void){ + bias = 15; + + // NOTE(nick): Interesting that CL does not generate inline site symbols in order of apperance here unlike clang. + + // CL: + // BinaryAnnotations: CodeLengthAndCodeOffset d 0 + // BinaryAnnotation Length: 4 bytes (1 bytes padding) + // + // Clang: + // BinaryAnnotations: LineOffset 1 CodeLength d + // BinaryAnnotation Length: 4 bytes (0 bytes padding) + unsigned int x = fixed_mul(5001, 7121); + + // CL: + // BinaryAnnotations: CodeOffsetAndLineOffset d File 0 CodeOffsetAndLineOffset 22 LineOffset 1e + // CodeLengthAndCodeOffset 2 3 + // BinaryAnnotation Length: 12 bytes (1 bytes padding) + // + // Clang: + // BinaryAnnotations: File 18 LineOffset ffffffe6 CodeOffset d CodeOffsetAndLineOffset 22 + // File 0 LineOffset 1e CodeOffset 3 CodeLength 2 + // BinaryAnnotation Length: 16 bytes (0 bytes padding) + unsigned int z = multi_file_inlinesite(x); + return(z); +} + diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp new file mode 100644 index 00000000..6d43a217 --- /dev/null +++ b/src/mule/mule_main.cpp @@ -0,0 +1,2379 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/* +** Program to run in debugger organized to provide tests for +** stepping, breakpoints, evaluation, cross-module calls. +*/ + +#include "raddbg_markup/raddbg_markup.h" + +//////////////////////////////// +// NOTE(allen): System For DLL Testing + +typedef void TestFunction(void); + +static void mule_init(void); +static TestFunction* mule_get_module_function(char *name); + +#if _WIN32 + +#include + +HMODULE mule_dll = 0; + +static void +mule_init(void){ + mule_dll = LoadLibraryA("mule_module.dll"); +} + +static TestFunction* +mule_get_module_function(char *name){ + TestFunction *result = (TestFunction*)GetProcAddress(mule_dll, name); + return(result); +} + +#else + +static void +mule_init(void){ + // TODO(allen): implement +} + +static TestFunction* +mule_get_module_function(char *name){ + // TODO(allen): implement + return(0); +} + +#endif + + +//////////////////////////////// +// NOTE(nick): Entry Point + +int +mule_main(int argc, char **argv); + +#if _WIN32 +#include +#include +int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){ + int argc = __argc; + char **argv = __argv; + int result = mule_main(argc, argv); + return(result); +} +#else +int main(int argc, char **argv){ + return(mule_main(argc, argv)); +} +#endif + +//////////////////////////////// +// NOTE(nick): BSS section test + +#if defined(__clang__) +# pragma clang section bss="muleBSS" +#elif defined(_MSC_VER) +// NOTE(nick): clang-cl is borken it allocates memory and sets Initialized Flag on the seciton. +// This is was reported by Jeff => https://bugs.llvm.org/show_bug.cgi?id=47939 +// +// This is still unresolved, last checked Sep 11, 2023. +# pragma bss_seg("muleBSS") +#else +# error "bss not defined" +#endif +char global_variable_in_bss[4096*10000]; + +//////////////////////////////// +// NOTE(allen): Inline Stepping (Built In Separate Unit) + +extern unsigned int fixed_frac_bits; +unsigned int inline_stepping_tests(void); + + +//////////////////////////////// +// NOTE(rjf): -O2 Optimized Code (Built In Separate Unit) + +void optimized_build_eval_tests(void); +void optimized_struct_parameters_eval_tests(void); + +//////////////////////////////// +// NOTE(allen): Type Coverage Eval + +#include + +struct Basics{ + char a; + unsigned char b; + short c; + unsigned short d; + int e; + unsigned int f; + long long g; + unsigned long long h; + float i; + double j; + + int z; +}; + +struct Basics_Stdint{ + int8_t a; + uint8_t b; + int16_t c; + uint16_t d; + int32_t e; + uint32_t f; + int64_t g; + uint64_t h; + float i; + double j; +}; + +struct Pair{ + int x; + float y; +}; + +struct Fixed_Array{ + Pair pairs[10]; + int count; +}; + +struct Dynamic_Array{ + Pair *pairs; + int count; +}; + +struct Struct_With_Embedded_Arrays{ + int x; + float y; + Pair pairs[10]; + char z; +}; + +typedef unsigned int Custom_Index_Type; + +typedef void Function_No_Params_Type(void); +typedef void Function_Few_Params_Type(Pair *pairs, int count, Function_No_Params_Type *no_params_type); + +static Function_No_Params_Type *ty_no_params = 0; +static Function_Few_Params_Type *ty_few_params = 0; + +struct Callback{ + Function_Few_Params_Type *few_params; + Function_No_Params_Type *no_params; + Pair pair; +}; + +union Vector_R2{ + struct{ + float x; + float y; + }; + float v[2]; +}; + +enum Kind{ + Kind_None, + Kind_First, + Kind_Second, + Kind_Third, + Kind_Fourth, + Kind_COUNT, +}; + +enum Flag{ + Flag_None = 0, + Flag_First = 1, + Flag_Second = 2, + Flag_Third = 4, + Flag_Fourth = 8, + Flag_AllMoreNarrow = 0xFF, + Flag_AllNarrow = 0xFFFF, + Flag_All = 0xFFFFFFFF, +}; + +struct Has_Enums{ + Kind kind; + Flag flags; +}; + +struct Discriminated_Union{ + Kind kind; + union{ + struct{ + int x; + int y; + Vector_R2 vector; + } first; + Pair second; + struct{ + Function_Few_Params_Type *few_params; + Pair pairs[4]; + } third; + struct{ + Kind sub_kind; + Flag flags; + } fourth; + }; +}; + +struct Linked_List{ + Linked_List *next; + Linked_List *prev; + int x; +}; + +enum{ + Anonymous_A, + Anonymous_B, + Anonymous_C, + Anonymous_D, +}; + +typedef Kind Alias1; +typedef Flag Alias2; +typedef Has_Enums Alias3; +typedef Discriminated_Union Alias4; + +struct Has_A_Pre_Forward_Reference{ + struct Gets_Referenced_Forwardly *pointer; +}; + +struct Gets_Referenced_Forwardly{ + int x; + int y; +}; + +struct Has_A_Post_Forward_Reference{ + struct Gets_Referenced_Forwardly value; +}; + +static void +no_params1(void){ + +} + +static void +few_params1(Pair *pairs, int count, Function_No_Params_Type *no_params_type){ + +} + +static void +type_coverage_eval_tests(void){ + + Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + Basics_Stdint basics_stdint = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + + char string[] = "Hello World!"; + char longer_text[] = + "Suppose there was some text\n" + "With multiple lines in it\r\n" + "\t> What ways might it be rendered?\n" + "\t> How would it deal with line endings?\r\n"; + + void *pointer = &basics; + Basics *pointer_to_basics = &basics; + Basics **pointer_to_pointer_to_basics = &pointer_to_basics; + + Fixed_Array fixed = { + { + { 3, 4.f}, + { 5, 6.f}, + { 7, 8.f}, + { 9, 10.f}, + {11, 12.f}, + {13, 14.f}, + {15, 16.f}, + {17, 18.f}, + {19, 20.f}, + }, + 9 + }; + Pair memory_[] = { + {100, 1.f}, + {101, 2.f}, + {102, 4.f}, + {103, 8.f}, + {104, 16.f}, + {105, 32.f}, + }; + Dynamic_Array dynamic = { + memory_, + 6 + }; + + raddbg_pin(basics); + raddbg_pin(fixed); + raddbg_pin(pointer); + + Struct_With_Embedded_Arrays swea = {0}; + { + swea.x = 4; + swea.y = 23.5f; + swea.pairs[0].x = 100; + swea.pairs[0].y = 123.f; + swea.pairs[2].x = 300; + swea.pairs[2].y = 323.f; + swea.pairs[5].x = 600; + swea.pairs[5].y = 623.f; + swea.z = 'z'; + } + + Custom_Index_Type custom_index = 42; + Custom_Index_Type more_custom_indices[] = { + 04,13,22,31,40 + }; + + Function_No_Params_Type *ptr_no_params = no_params1; + Function_No_Params_Type **ptr_ptr_no_params = &ptr_no_params; + Function_Few_Params_Type *ptr_few_params = few_params1; + Function_Few_Params_Type **ptr_ptr_few_params = &ptr_few_params; + Callback callback = {few_params1, no_params1, {1, 2.f}}; + + Vector_R2 vector = {1.f, 2.f}; + + Has_Enums has_enums = {(Kind)4, (Flag)7}; + + Discriminated_Union discriminated_union = {Kind_First}; + discriminated_union.first.x = 16; + discriminated_union.first.y = 8; + discriminated_union.first.vector.x = 4.f; + discriminated_union.first.vector.y = 2.f; + + Linked_List list = {&list, &list, 0}; + + Alias1 a1 = has_enums.kind; + Alias2 a2 = has_enums.flags; + Alias3 a3 = has_enums; + Alias4 a4 = discriminated_union; + + Has_A_Pre_Forward_Reference r1 = {0}; + Has_A_Post_Forward_Reference r2 = {0}; + + Basics &basics_ref = basics; + + union + { + int x; + char y[4]; + } integer_slicing = {123456789}; + + typedef struct stks + { + void *left; + size_t len; + } stks; + stks stks_test[256] = {0}; + stks *stks_first = &stks_test[0]; + stks *stks_ptr = stks_first + 8; + + int x = (int)(Anonymous_D); +} + +//////////////////////////////// +// NOTE(allen): Mutating Variables Eval + +static const int con_some_constant = 4; +static const float con_some_constant_f = 0.04f; + +static int mut_x = 0; +static int mut_y; +static int mut_xarray[4] = {0, 1, 2, 3}; +static int *mut_xptr; + +static float mut_f = 0; +static float mut_g; +static float mut_farray[4] = {0.5f, 1.5f, 2.5f, 3.5f}; +static float *mut_fptr; + +static float mut_arrayarray[3][3]; + +static Linked_List mut_link; + +static void +mutate_in_function(int *array, int count){ + for (int i = 0; i < count; i += 1){ + array[i] += 1; + } + + for (int i = 0; i < 4; i += 1){ + mut_farray[i] += 1.f; + } +} + +static void +mutating_variables_eval_tests(void){ + //////////////////////////////// + // NOTE(allen): Basics + + int array_literal[10] = { + 10, 20, 30, 40, 50, 60, 70, 80, 90, + }; + + Basics struct_literal = { + -1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001, + }; + + array_literal[0] = struct_literal.e = 9; + + int x = mut_x; + int y = x + 10 + con_some_constant; + mut_y = y; + mut_xarray[0] += 0; + mut_xarray[1] += x; + mut_xarray[2] += y; + mut_xarray[3] += x + y; + + mut_xptr = &mut_xarray[2]; + + *mut_xptr -= (y - x)/2; + *(mut_xptr - 1) += 11; + + float f = mut_f + .333f + con_some_constant_f; + float g = f + 10.1f; + mut_g = g; + mut_farray[0] += 0.000001f; + mut_farray[1] += f; + mut_farray[2] += g; + mut_farray[3] += f + g; + + mut_fptr = &mut_farray[3]; + + *mut_fptr -= (g - f)*0.5f; + *(mut_fptr - 1) += 1.f; + + float a = 0.777f; + for (int i = 0; i < 3; i += 1){ + float b = a*a - 1.f; + for (int j = 0; j < 3; j += 1){ + mut_arrayarray[i][j] = b; + b += 0.111f; + } + a += 0.333f; + } + + //////////////////////////////// + // NOTE(allen): Changes in functions + + mutate_in_function(array_literal, 10); + + mutate_in_function(array_literal, 10); + + //////////////////////////////// + // NOTE(allen): Changes through pointers + + Basics basic = struct_literal; + Basics advanced = struct_literal; + + Basics *struct_pointer = &basic; + + basic.a += 1; + advanced.a += 1; + struct_pointer->a += 1; + + struct_pointer = &advanced; + + basic.b += 1; + advanced.b += 1; + struct_pointer->b += 1; + + Linked_List links[5]; + for (int i = 0; i < 5; i += 1){ + links[i].next = &links[i + 1]; + links[i].prev = &links[i - 1]; + links[i].x = i; + } + links[0].prev = 0; + links[4].next = &mut_link; + mut_link.prev = &links[4]; + mut_link.next = 0; + mut_link.x = 1000; + + Linked_List *link_ptr = links; + + link_ptr = link_ptr->next; + + link_ptr = &links[4]; + link_ptr = &mut_link; + + Linked_List sentinel = {0}; + sentinel.x = -1; + sentinel.next = &links[0]; + links[0].prev = &sentinel; + sentinel.prev = &mut_link; + mut_link.next = &sentinel; + + link_ptr = &sentinel; +} + +//////////////////////////////// +// NOTE(allen): Global Eval + +struct NestedNodeInner{ + unsigned int small0; + unsigned int small1; + unsigned int big0; + unsigned int big1; +}; + +struct NestedNodeOuter{ + NestedNodeOuter *next; + NestedNodeInner *inner_nodes; + unsigned int inner_node_count; +}; + +static void +nested_types_eval_tests(void){ + // doing some setup + NestedNodeOuter *outer1 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + NestedNodeOuter *outer2 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + NestedNodeOuter *outer3 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + + outer1->next = outer2; + outer2->next = outer3; + outer3->next = 0; + + outer1->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer1->inner_node_count = 10; + + outer2->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer2->inner_node_count = 10; + + outer3->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer3->inner_node_count = 10; + + for (unsigned int i = 0; i < 10; i += 1){ + outer1->inner_nodes[i].small0 = i; + outer1->inner_nodes[i].small1 = 2*i; + outer1->inner_nodes[i].big0 = 0xFFFFFF + 0xF*i; + outer1->inner_nodes[i].big1 = 0xFFFFFF + 0xFF*i; + + outer2->inner_nodes[i].small0 = 1 + i; + outer2->inner_nodes[i].small1 = 3*i; + outer2->inner_nodes[i].big0 = 0x1000000 + 0x10*i; + outer2->inner_nodes[i].big1 = 0x1000000 + 0x101*i; + + outer3->inner_nodes[i].small0 = 2 + i; + outer3->inner_nodes[i].small1 = 4*i; + outer3->inner_nodes[i].big0 = 0x8000000 + 0xF0*i; + outer3->inner_nodes[i].big1 = 0x8000000 + 0xF0F*i; + } + + // okay eval it here + int x = 0; +} + +//////////////////////////////// +// NOTE(rjf): Struct Parameters Eval + +static void +struct_parameter_helper(Basics basics) +{ + basics.a += 1; + basics.a += 1; + basics.a += 1; +} + +static void +struct_parameters_eval_tests(void) +{ + Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + struct_parameter_helper(basics); +} + +//////////////////////////////// +// NOTE(allen): Global Eval + +static int g_abc = 100; +static float g_xyz = 21.f; +static Alias1 g_kind = Kind_First; + +// TODO(allen): more global test types + +static void +complicated_global_mutation(int *x){ + *x = (int)g_xyz; +} + +static void +cross_unit_global_mutation(void){ + fixed_frac_bits = 10; +} + +static void +global_eval_tests(void){ + g_abc = 11*11; + g_xyz = (float)g_abc - 21.f; + + int z = g_abc; + complicated_global_mutation(&z); + + complicated_global_mutation(&g_abc); + + if (g_kind == Kind_First){ + g_abc -= 1; + g_kind = Kind_None; + } + + cross_unit_global_mutation(); + + static int l_abc = 200; + static float l_xyz = 42.f; + static Alias1 l_kind = Kind_Second; + + l_abc = g_abc*2; + l_xyz = g_xyz*2; + l_kind = (Alias1)(g_kind + 1); +} + +//////////////////////////////// +// NOTE(allen): Return Eval + +static int +complicated_return_expression(void){ + int x = 171717; + return((x % 13) <= 5?(x % 19)*11:(x - 500)%200); +} + +static void +return_eval_tests(void){ + complicated_return_expression(); +} + +//////////////////////////////// +// NOTE(allen): TLS Eval + +#if _WIN32 +# define thread_var __declspec(thread) +#else +# define thread_var __thread +#endif + +thread_var int tls_a = 100; +thread_var int tls_b = 999; + +static void +tls_eval_tests(void){ + tls_a = (tls_a + tls_b)/2; + tls_b = tls_b - tls_a; + + TestFunction *dll_tls_eval_test = mule_get_module_function("dll_tls_eval_test"); + if (dll_tls_eval_test != 0){ + dll_tls_eval_test(); + } +} + +//////////////////////////////// +// NOTE(allen): Complicated Type Coverage Eval + +struct Complicated_Type_Members{ + int x600[2][2][2][2]; + int *x601[2][2][2][2]; + int (*x602)[2][2][2][2]; + int (*x603[2])[2][2][2]; + int (*(*x604[2])[2])[2][2]; + int (*(*(*x605[2])[2])[2])[2]; + + int (*x33[2])(void); + int (*x34[3])(void); + int (*x35[2][2])(void); + + int (*(*z33)(void))[2]; + int (*(*z34)(void))[3]; + int (*(*z35)(void))[2][2]; + + int (*(*f2)(void))(void); + int (*(*(*f3)(void))(void))(void); + int (*(*f4)(int))(void); + int (*(*f5)(void))(int); + int (*(*f6)(int))(int); + int (*(*(*f7_growing)(char))(short))(int); + int (*(*(*f7_shrinking)(int))(short))(char); +}; + +static void +complicated_type_coverage_tests(void){ + Complicated_Type_Members m = {0}; + + int x1 = {0}; + int *x2 = {0}; + int **x3 = {0}; + + int x4a[2] = {0}; + int *x4[2] = {0}; + int x5a[3] = {0}; + int *x5[3] = {0}; + int *x6[2][2] = {0}; + int (*x7)[2] = {0}; + int (*x8)[3] = {0}; + int (*x9)[2][2] = {0}; + + int x600[2][2][2][2] = {0}; + int *x601[2][2][2][2] = {0}; + int (*x602)[2][2][2][2] = {0}; + int (*x603[2])[2][2][2] = {0}; + int (*(*x604[2])[2])[2][2] = {0}; + int (*(*(*x605[2])[2])[2])[2] = {0}; + + int x606_growing [2][3][4][5] = {0}; + int x606_shrinking[5][4][3][2] = {0}; + + int (*(*(*x607_growing [2])[3])[4])[5] = {0}; + int (*(*(*x607_shrinking[5])[4])[3])[2] = {0}; + + int **x10[2] = {0}; + int **x11[3] = {0}; + int **x12[2][2] = {0}; + int *(*x13)[2] = {0}; + int *(*x14)[3] = {0}; + int *(*x15)[2][2] = {0}; + int **x16[2] = {0}; + int **x17[3] = {0}; + int **x18[2][2] = {0}; + + int (*y1[2])[2] = {0}; + int (*y2[3])[2] = {0}; + int (*y3[2][2])[2] = {0}; + int (*y4[2])[3] = {0}; + int (*y5[3])[3] = {0}; + int (*y6[2][2])[3] = {0}; + int (*y7[2])[2][2] = {0}; + int (*y8[3])[2][2] = {0}; + int (*y9[2][2])[2][2] = {0}; + + int (*x19)(void) = {0}; + int (*x20)(int) = {0}; + int (*x21)(int, int) = {0}; + int (*x22)(int*, int) = {0}; + int (*x23)(int**, int) = {0}; + int (*x24)(int**, int*) = {0}; + int (*x25)(int**, int**) = {0}; + + int *(*x26)(void) = {0}; + int *(*x27)(int) = {0}; + int *(*x28)(int, int) = {0}; + int *(*x29)(int*, int) = {0}; + int *(*x30)(int**, int) = {0}; + int *(*x31)(int**, int*) = {0}; + int *(*x32)(int**, int**) = {0}; + + int (*x33[2])(void) = {0}; + int (*x34[3])(void) = {0}; + int (*x35[2][2])(void) = {0}; + + int (*x36[2])(int) = {0}; + int (*x37[3])(int) = {0}; + int (*x38[2][2])(int) = {0}; + + int (*x39[2])(int, int) = {0}; + int (*x40[3])(int, int) = {0}; + int (*x41[2][2])(int, int) = {0}; + + int (*x42[2])(int*, int) = {0}; + int (*x43[3])(int*, int) = {0}; + int (*x44[2][2])(int*, int) = {0}; + + int (*x45[2])(int**, int) = {0}; + int (*x46[3])(int**, int) = {0}; + int (*x47[2][2])(int**, int) = {0}; + + int (*x48[2])(int**, int*) = {0}; + int (*x49[3])(int**, int*) = {0}; + int (*x50[2][2])(int**, int*) = {0}; + + int (*x51[2])(int**, int**) = {0}; + int (*x52[3])(int**, int**) = {0}; + int (*x53[2][2])(int**, int**) = {0}; + + int (*(*z33)(void))[2] = {0}; + int (*(*z34)(void))[3] = {0}; + int (*(*z35)(void))[2][2] = {0}; + + int (*(*z36)(int))[2] = {0}; + int (*(*z37)(int))[3] = {0}; + int (*(*z38)(int))[2][2] = {0}; + + int (*(*z39)(int, int))[2] = {0}; + int (*(*z40)(int, int))[3] = {0}; + int (*(*z41)(int, int))[2][2] = {0}; + + int (*(*z42)(int*, int))[2] = {0}; + int (*(*z43)(int*, int))[3] = {0}; + int (*(*z44)(int*, int))[2][2] = {0}; + + int (*(*z45)(int**, int))[2] = {0}; + int (*(*z46)(int**, int))[3] = {0}; + int (*(*z47)(int**, int))[2][2] = {0}; + + int (*(*z48)(int**, int*))[2] = {0}; + int (*(*z49)(int**, int*))[3] = {0}; + int (*(*z50)(int**, int*))[2][2] = {0}; + + int (*(*z51)(int**, int**))[2] = {0}; + int (*(*z52)(int**, int**))[3] = {0}; + int (*(*z53)(int**, int**))[2][2] = {0}; + + int (*(*z303[2])(void)) = {0}; + int (*(*z304[3])(void)) = {0}; + int (*(*z305[2][2])(void)) = {0}; + + int (*(*z306[2])(int)) = {0}; + int (*(*z307[3])(int)) = {0}; + int (*(*z308[2][2])(int)) = {0}; + + int (*(*z309[2])(int, int)) = {0}; + int (*(*z400[3])(int, int)) = {0}; + int (*(*z401[2][2])(int, int)) = {0}; + + int (*(*z402[2])(int*, int)) = {0}; + int (*(*z403[3])(int*, int)) = {0}; + int (*(*z404[2][2])(int*, int)) = {0}; + + int (*(*z405[2])(int**, int)) = {0}; + int (*(*z406[3])(int**, int)) = {0}; + int (*(*z407[2][2])(int**, int)) = {0}; + + int (*(*z408[2])(int**, int*)) = {0}; + int (*(*z409[3])(int**, int*)) = {0}; + int (*(*z500[2][2])(int**, int*)) = {0}; + + int (*(*z501[2])(int**, int**)) = {0}; + int (*(*z502[3])(int**, int**)) = {0}; + int (*(*z503[2][2])(int**, int**)) = {0}; + + int (*(*f2)(void))(void) = {0}; + int (*(*(*f3)(void))(void))(void) = {0}; + int (*(*f4)(int))(void) = {0}; + int (*(*f5)(void))(int) = {0}; + int (*(*f6)(int))(int) = {0}; + int (*(*(*f7_growing)(char))(short))(int) = {0}; + int (*(*(*f7_shrinking)(int))(short))(char) = {0}; + + int (*f8)(int (*)(void)) = {0}; + int (*f9)(void (*)(int)) = {0}; + void (*f10)(int (*)(int)) = {0}; + int (*f11)(int, int (*)(void)) = {0}; + int (*f12)(int (*)(void), int) = {0}; + int (*f13)(int (*)(void), int (*)(void)) = {0}; + + int (*f14)(int (*)(void)) = {0}; + int (*f15)(int (*)(int (*)(void))) = {0}; + int (*f16)(int (*)(int (*)(int (*)(void)))) = {0}; + int (*f17)(int (*)(int (*)(int (*)(int (*)(void))))) = {0}; + + int (*f18)(int (*)(void)) = {0}; + int (*f19)(int (*(*)(void))(void)) = {0}; + int (*f20)(int (*(*(*)(void))(void))(void)) = {0}; + int (*f21)(int (*(*(*(*)(void))(void))(void))(void)) = {0}; + + int (*(*(*(*f22)(void))(void))(void))(void) = {0}; + int (*(*(*(*f23)(int [2]))(void))(void))(void) = {0}; + int (*(*(*(*f24)(int *[2]))(int [3]))(void))(void) = {0}; + int (*(*(*(*f25)(int (*)[2]))(int *[3]))(int [4]))(void) = {0}; + int (*(*(*(*f26)(int **(**)[2]))(int (*)[3]))(int *[4]))(int [5]) = {0}; + + int x = 0; +} + +//////////////////////////////// +// NOTE(allen): Extended Type Coverage Eval + +template +struct Template_Example{ + X x; + int y; +}; + +template +struct Template_Example2{ + X x; + Y y; +}; + +template +struct Template_Example3{ + X x; + Y y; + Template_Example3(X x, Y y) + { + this->x = x; + this->y = y; + } + ~Template_Example3() + { + int x = 2; + int y = 5; + int z = x + y; + } +}; + +struct Has_Members{ + int a; + int b; + uint64_t c; + uint64_t d; + Basics bas; + + int w(void){ return a; } + int x(void){ return b; } + uint64_t y(void){ return c; } + uint64_t z(void){ return d; } + Basics bas_f(void){ return bas; } +}; + +struct Has_Static_Members{ + int a; + int b; + static uint64_t c; + static uint64_t d; + + int w(void){ return a; } + int x(void){ return b; } + static uint64_t y(void){ return c; } + static uint64_t z(void){ return d; } +}; + +uint64_t Has_Static_Members::c = 0; +uint64_t Has_Static_Members::d = 0; + +struct Pointer_To_Member{ + int Has_Members::*member_ptr_int; + uint64_t Has_Members::*member_ptr_u64; + Basics Has_Members::*member_ptr_bas; + + int (Has_Members::*method_ptr_int)(void); + uint64_t (Has_Members::*method_ptr_u64)(void); + Basics (Has_Members::*method_ptr_bas)(void); +}; + +struct Has_Sub_Types{ + struct Sub_Type1{ + int x; + int y; + }; + + struct Sub_Type2{ + float x; + float y; + }; + + Sub_Type1 a; + Sub_Type2 b; +}; + +struct Conflicting_Type_Names{ + struct Sub_Type1{ + uint64_t z; + }; + + struct Sub_Type2{ + int64_t z; + }; + + Sub_Type1 a; + Sub_Type2 b; +}; + +struct Has_Private_Sub_Types{ + Has_Private_Sub_Types(char x1, char y1, + float x2, int y2, + int x3, float y3){ + this->a.x = x1; + this->a.y = y1; + this->b.x = x2; + this->b.y = y2; + this->c.x = x3; + this->c.y = y3; + } + + struct Public_Sub_Type{ + char x; + char y; + }; + Public_Sub_Type a; + + protected: + struct Protected_Sub_Type{ + float x; + int y; + }; + Protected_Sub_Type b; + + private: + struct Private_Sub_Type{ + int x; + float y; + }; + Private_Sub_Type c; +}; + +struct Vtable_Parent{ + virtual void a_virtual_function(void) = 0; + virtual void b_virtual_function(void) = 0; + virtual void c_virtual_function(void) = 0; + + void a_virtual_function(int r){ + for (int i = 0; i < r; i += 1){ + a_virtual_function(); + } + } +}; + +struct Vtable_Child : Vtable_Parent{ + int x; + int y; + + Vtable_Child(int a, int b){ + x = a; + y = b; + } + virtual void a_virtual_function(void){ + x = 0; + }; + virtual void b_virtual_function(void){ + y = 0; + }; + virtual void c_virtual_function(void){ + x = y; + }; +}; + +struct Vinheritance_Base{ + int x; + int y; + + virtual void a_virtual_function(void){ + x = 0; + }; + virtual void b_virtual_function(void){ + y = 0; + }; + virtual void x_virtual_function(void){ + y = x; + }; +}; + +struct Vinheritance_MidLeft : virtual Vinheritance_Base{ + float left; + + virtual void c1_virtual_function(void){ + left = 0; + }; + virtual void c2_virtual_function(void){ + left = 0; + }; +}; + +struct Vinheritance_MidRight : virtual Vinheritance_Base{ + float right; + + virtual void d_virtual_function(void){ + right = 0; + }; +}; + +struct Vinheritance_Child : Vinheritance_MidLeft, Vinheritance_MidRight{ + char *name; + + virtual void a_virtual_function(void){ + x = 1; + }; + virtual void c1_virtual_function(void){ + left = 1; + }; +}; + +struct OverloadedMethods{ + int x; + int cool_method(void){ + return(x); + } + int cool_method(int z){ + int r = x; + x = z; + return(r); + } + void cool_method(int y, int z){ + if (x < z){ + x = y; + } + else{ + x = z; + } + } +}; + +struct HasStaticConstMembers +{ + int a; + int b; + static int c; + static int d; + static const int e = 789; + static const int f = 101112; +}; + +int HasStaticConstMembers::c = 123; +int HasStaticConstMembers::d = 456; + +struct Has_A_Constructor{ + int n; + int d; + Has_A_Constructor(int a, int b){ + int gcd = 1; + { + int x = a; + int y = b; + if (x < y){ + y = a; + x = b; + } + for (;y > 0;){ + int z = x%y; + x = y; + y = z; + } + gcd = x; + } + n = a/gcd; + d = b/gcd; + } + + static int N; + static int D; + ~Has_A_Constructor(){ + int m = N*d + n*D; + int e = d*D; + N = m; + D = d; + } +}; + +int Has_A_Constructor::N = 0; +int Has_A_Constructor::D = 1; + +struct Constructor_Gotcha_Test{ + int x; + int y; + void Constructor_Gotcha(void){ + x = y = 0; + } +}; + +struct Has_A_Friend{ + friend struct Modifies_Other; + int get_x(void){ return x; } + int get_y(void){ return y; } + + private: + int x; + int y; +}; + +struct Modifies_Other{ + int x; + int y; + + void talk_to_friend(Has_A_Friend *other){ + other->x = y; + other->y = x; + } +}; + +namespace UserNamespace{ + namespace SubA{ + struct Foo{ + int x; + int y; + }; + }; + namespace SubB{ + struct Foo{ + float u; + float v; + }; + }; + + SubA::Foo foo_a = {10, 20}; + SubB::Foo foo_b = {0.1f, 0.05f}; + + static void namespaced_function(void){ + foo_a.x = (int)(foo_a.y*foo_b.u); + foo_b.v = (float)(foo_a.x*foo_b.v); + } +}; + +static void +call_with_pass_by_reference(int &x){ + x += 1; +} + +static void +call_with_pass_by_const_reference(const int &x){ + int y = x; +} + +static void +extended_type_coverage_eval_tests(void){ + //////////////////////////////// + // NOTE(allen): Extensions to base type system. + { + int x = 0; + const int *x_ptr = &x; + int *const x_cptr = &x; + + call_with_pass_by_reference(x); + + call_with_pass_by_const_reference(x); + } + + //////////////////////////////// + // NOTE(allen): Extensions to user defined types + { + Template_Example temp_f = {1.f, 2}; + Template_Example temp_v = {(void*)&temp_f, 2}; + Template_Example > temp_tf = {temp_f, 2}; + Template_Example2 temp_if = {2, 1.f}; + Template_Example3 temp3_if(2, 1.f); + Template_Example3 temp3_vi((void *)&temp3_if, 1.f); + Template_Example3> temp3_itif(123, temp_if); + + Pointer_To_Member pointer_to_member = { + &Has_Members::a, &Has_Members::c, &Has_Members::bas, + &Has_Members::x, &Has_Members::z, &Has_Members::bas_f, + }; + + Has_Static_Members has_static_members = { 10, 20 }; + Has_Static_Members::c = 100; + Has_Static_Members::d = 110; + has_static_members.x(); + has_static_members.y(); + has_static_members.z(); + has_static_members.w(); + + Has_Sub_Types has_sub_types = { + {100, 200}, + {.1f, .2f}, + }; + + Conflicting_Type_Names conflicting_type_names = { + {10}, {-20}, + }; + + Has_Private_Sub_Types has_private_sub_types(1, 2, 4, 8, 16, 32); + + Vtable_Child vtable_child(1, 2); + vtable_child.a_virtual_function(); + + Vinheritance_Child vinheritance_child; + vinheritance_child.name = "foobar"; + vinheritance_child.left = 10.5f; + vinheritance_child.right = 13.0f; + vinheritance_child.x = -1; + vinheritance_child.y = -1; + + OverloadedMethods overloaded_methods; + { + overloaded_methods.x = 0; + int a = overloaded_methods.cool_method(); + overloaded_methods.cool_method(-10, 100); + int b = overloaded_methods.cool_method(100); + overloaded_methods.cool_method(b*2, a*2); + int c = overloaded_methods.cool_method(a + b); + int z = c; + } + + Has_A_Constructor construct_me(360, 25); + + Has_A_Friend has_a_friend; + + Modifies_Other modifies_other; + modifies_other.x = 57; + modifies_other.y = 66; + + modifies_other.talk_to_friend(&has_a_friend); + + int x = has_a_friend.get_x(); + int y = has_a_friend.get_y(); + int z = x; + + HasStaticConstMembers static_const_members = {0}; + static_const_members.a = 123 + HasStaticConstMembers::c * HasStaticConstMembers::e; + static_const_members.b = 456 + HasStaticConstMembers::d * HasStaticConstMembers::f; + } + + //////////////////////////////// + // NOTE(allen): Namespaces + { + UserNamespace::namespaced_function(); + } +} + +//////////////////////////////// +// NOTE(allen): C Type Coverage + +extern "C"{ +#include "mule_c.h" +} + +//////////////////////////////// +//~ rjf: Fancy Visualization Eval Tests + +static unsigned int +mule_bswap_u32(unsigned int x) +{ + unsigned int result = (((x & 0xFF000000) >> 24) | + ((x & 0x00FF0000) >> 8) | + ((x & 0x0000FF00) << 8) | + ((x & 0x000000FF) << 24)); + return result; +} + +static void +fancy_viz_eval_tests(void) +{ + //- rjf: colors + float example_color_4f32[4] = {1.00f, 0.85f, 0.25f, 1.00f}; + unsigned int example_color_u32 = 0xff6f30ff; + struct {float r, g, b, a;} example_color_struct = {0.50f, 0.95f, 0.75f, 1.00f}; + int x0 = 0; + + //- rjf: multiline text + char *long_string = ("This is an example of some very long text with line breaks\n" + "in it. This is a very common kind of data which is inspected\n" + "in the debugger while programming, and it is often a pain\n" + "when it is poorly supported.\n"); + char *code_string = ("#include \n" + "\n" + "int main(int argc, char**argv)\n" + "{\n" + " printf(\"Hello, World!\\n\");\n" + " return 0;\n" + "}\n\n"); + int x1 = 0; + raddbg_pin(long_string, "text"); + raddbg_pin(code_string, "text: (lang:c)"); + raddbg_pin(fancy_viz_eval_tests, "disasm: (arch:x64)"); + + //- rjf: bitmaps + unsigned int background_color = 0x00000000; + unsigned int main_color = 0xff2424ff; + unsigned int shine_color = 0xff5693ff; + unsigned int shadow_color = 0xff238faf; + unsigned int bg = mule_bswap_u32(background_color); + unsigned int cl = mule_bswap_u32(main_color); + unsigned int sn = mule_bswap_u32(shine_color); + unsigned int sh = mule_bswap_u32(shadow_color); + unsigned int bitmap[] = + { + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, cl, cl, bg, cl, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, cl, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, cl, sn, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, sh, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, sh, cl, cl, cl, sh, sh, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, sh, sh, sh, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + }; + raddbg_pin(bitmap, "bitmap:(w:18, h:18)"); + for(int i = 0; i < sizeof(bitmap)/sizeof(bitmap[0]); i += 1) + { + unsigned int r = bitmap[i]&0x000000ff; + unsigned int a = bitmap[i]&0xff000000; + bitmap[i] = bitmap[i]>>8; + bitmap[i] &= ~0xffff0000; + bitmap[i] |= (r<<16); + bitmap[i] |= (a); + } + for(int i = 0; i < sizeof(bitmap)/sizeof(bitmap[0]); i += 1) + { + unsigned int r = bitmap[i]&0x000000ff; + unsigned int a = bitmap[i]&0xff000000; + bitmap[i] = bitmap[i]>>8; + bitmap[i] &= ~0xffff0000; + bitmap[i] |= (r<<16); + bitmap[i] |= (a); + } + for(int i = 0; i < sizeof(bitmap)/sizeof(bitmap[0]); i += 1) + { + unsigned int r = bitmap[i]&0x000000ff; + unsigned int a = bitmap[i]&0xff000000; + bitmap[i] = bitmap[i]>>8; + bitmap[i] &= ~0xffff0000; + bitmap[i] |= (r<<16); + bitmap[i] |= (a); + } + int x2 = 0; + + //- rjf: 3D geometry + float vertex_data[] = // pos.x, pos.y, pos.z, nor.x, nor.y, nor.z, tex.u, tex.v, col.r, col.g, col.b, ... + { + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 2.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 2.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 8.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 8.0f, 0.973f, 0.480f, 0.002f, + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 2.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 2.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 8.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 8.0f, 0.612f, 0.000f, 0.069f, + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 2.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 2.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 8.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 8.0f, 0.000f, 0.254f, 0.637f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 2.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 2.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 8.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 8.0f, 0.001f, 0.447f, 0.067f, + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + }; + unsigned int index_data[] = + { + 0, 1, 9, 9, 8, 0, 1, 2, 5, 5, 4, 1, 6, 7, 10, 10, 9, 6, 2, 3, 11, 11, 10, 2, + 12, 13, 21, 21, 20, 12, 13, 14, 17, 17, 16, 13, 18, 19, 22, 22, 21, 18, 14, 15, 23, 23, 22, 14, + 24, 25, 33, 33, 32, 24, 25, 26, 29, 29, 28, 25, 30, 31, 34, 34, 33, 30, 26, 27, 35, 35, 34, 26, + 36, 37, 45, 45, 44, 36, 37, 38, 41, 41, 40, 37, 42, 43, 46, 46, 45, 42, 38, 39, 47, 47, 46, 38, + 48, 49, 57, 57, 56, 48, 49, 50, 53, 53, 52, 49, 54, 55, 58, 58, 57, 54, 50, 51, 59, 59, 58, 50, + 60, 61, 69, 69, 68, 60, 61, 62, 65, 65, 64, 61, 66, 67, 70, 70, 69, 66, 62, 63, 71, 71, 70, 62, + 72, 73, 74, 74, 75, 72, 76, 77, 78, 78, 79, 76, 80, 81, 82, 82, 83, 80, 84, 85, 86, 86, 87, 84, + 88, 89, 90, 90, 91, 88, 92, 93, 94, 94, 95, 92, 96, 97, 98, 98, 99, 96, 100, 101, 102, 102, 103, 100, + 104, 105, 106, 106, 107, 104, 108, 109, 110, 110, 111, 108, 112, 113, 114, 114, 115, 112, 116, 117, 118, 118, 119, 116, + 120, 121, 122, 122, 123, 120, 124, 125, 126, 126, 127, 124, 128, 129, 130, 130, 131, 128, 132, 133, 134, 134, 135, 132, + 136, 137, 138, 138, 139, 136, 140, 141, 142, 142, 143, 140, 144, 145, 146, 146, 147, 144, 148, 149, 150, 150, 151, 148, + 152, 153, 154, 154, 155, 152, 156, 157, 158, 158, 159, 156, 160, 161, 162, 162, 163, 160, 164, 165, 166, 166, 167, 164, + }; + raddbg_pin(index_data, "geo: { count:(sizeof index_data / 4), vertices_base:(vertex_data), vertices_size:(sizeof vertex_data) }"); + int x3 = 0; +} + +//////////////////////////////// +// NOTE(allen): Function Overload Resolution + +static int +overloaded_function(float y){ + int r = (int)(y + 0.5f); + return(r); +} + +static int +overloaded_function(float y, int x){ + int r = overloaded_function(y) + x; + return(r); +} + +static int +overloaded_function(int x){ + float y = (float)x; + int r = overloaded_function(y, 1); + return(r); +} + +//////////////////////////////// +// NOTE(allen): Control Flow Stepping + +static void +control_flow_stepping_tests(void){ + { + int a = 1; + if (a < 1){ + a += 1; + } + if (a < 2){ + a += 2; + } + } + + { + int a = 1; + if (a < 1) + { + a += 1; + } + if (a < 2) + { + a += 2; + } + } + + { + int a = 1; + if (a < 1) + a += 1; + if (a < 2) + a += 2; + } + + { + int a = 1; + int b = 2; + if (a <= b){ + if (a == b){ + b += 1; + } + else{ + a += 1; + } + } + else{ + if (a%2){ + a = b; + } + else{ + a = b - 1; + } + } + } + + { + int a = 1; + int b = 2; + if (a <= b) + { + if (a == b) + { + b += 1; + } + else + { + a += 1; + } + } + else + { + if (a%2) + { + a = b; + } + else + { + a = b - 1; + } + } + } + + { + int a = 1; + int b = 2; + if (a <= b) + if (a == b) + b += 1; + else + a += 1; + else + if (a%2) + a = b; + else + a = b - 1; + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1){ + x += i; + } + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) + { + x += i; + } + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) + x += i; + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) x += i; + } + + { + int a = 1; + for (;a < 10;){ + switch (a){ + case 0: case 1: case 2: + { + a += 2; + }break; + + default: + case 4: + case 5: + { + a += 1; + }break; + + case 6: a += 1; break; + case 7: a += 1; + case 8: + case 9: a += 1; + } + } + } + + { + int i = 0; + while (i < 5){ + i += 1; + } + + while (i < 10) + { + i += 1; + } + + while (i < 15) + i += 1; + + while (i < 20) i += 1; + } + + { + int i = 0; + do + { + i += 1; + } while (i < 10); + } + + { + int i = 17; + + check_again: + if (i <= 1) goto done; + if ((i&1) == 0) goto even_case; + + odd_case: + i = 3*i + 1; + + even_case: + i /= 2; + goto check_again; + + done:; + } + + { + int x = 15; + label_same_line:; x -= 1; if(x > 0) { goto label_same_line; } else { goto end_label_same_line; } + } + end_label_same_line:; +} + +//////////////////////////////// +// NOTE(allen): Indirect Call/Jump Stepping Tests + +typedef int FunctionType(int); + +static int +function_foo(int a){ + if (a < 1){ + a += 1; + } + if (a < 2){ + a += 2; + } + return(a); +} + +static int +function_bar(int x){ + for (int i = 0; i < 10; i += 1){ + x += i; + } + return(x); +} + + +static void +indirect_call_jump_stepping_tests(void){ + int z = 1; + FunctionType *ptr = function_foo; + z = ptr(z); + if ((z & 1) == 0){ + ptr = function_bar; + } + z = ptr(z); + + switch (z&7){ + case 0: + { + z += 2; + ptr = function_bar; + }break; + + case 1: + { + z += 1; + ptr = function_bar; + }break; + + case 2: + { + z *= 2; + ptr = function_bar; + }break; + + case 3: + { + z -= 10; + ptr = function_foo; + }break; + + case 4: + { + z -= 5; + ptr = function_foo; + }break; + + case 5: + { + z = z ^ 0x10; + ptr = function_foo; + }break; + + case 6: + { + z = z & ~0x10; + ptr = function_foo; + }break; + + case 7: + { + z = z | 0x10; + ptr = function_foo; + }break; + } + + z = ptr(z); +} + +//////////////////////////////// +// NOTE(rjf): alloca (Variable-Width Stack Changes) Stepping Tests + +static void +alloca_stepping_tests(void) +{ + int x = 1; + int y = 3; + int z = 5; + +#if _WIN32 + int *mem = (int *)_alloca((x+y+z)*sizeof(int)); + mem[0] = x; + mem[1] = y; + mem[2] = z; +#else + int *mem = (int *)__builtin_alloca((x+y+z)*sizeof(int)); + mem[0] = x; + mem[1] = y; + mem[2] = z; +#endif +} + +//////////////////////////////// +// NOTE(allen): Overloaded Line Stepping + +static int +function_get_integer(void){ + return(1); +} + +static void +function_with_multiple_parameters(int x, int y){ + x += y; +} + +static int +recursive_single_line(int x){ return(x <= 1?0:x + recursive_single_line(x/2)); } + +static int shared_1(int x) { return(x); } static int shared_2(int x) { return(1 + shared_1(x)); } + +static void +overloaded_line_stepping_tests(void){ + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + + recursive_single_line(50); + recursive_single_line(50); + recursive_single_line(50); + + shared_2(5); + shared_2(5); + shared_2(5); + + function_get_integer(); shared_1(1); shared_1(2); + + if ((shared_2(10) && shared_2(-1)) || + shared_2(function_get_integer())){ + int x = 0; + } + else{ + int y = 0; + } +} + +//////////////////////////////// +// NOTE(allen): Long Jump Stepping + +#include + +static jmp_buf global_jump_buffer; +static int global_jump_x; + +static void +long_jump_from_function(void){ + int spin = 0; + for (; spin < 5; spin += 1); + longjmp(global_jump_buffer, 2); + global_jump_x = spin; +} + +static void +long_jump_wrapped_in_function(void){ + global_jump_x = 0; + int val = setjmp(global_jump_buffer); + if (val == 0){ + global_jump_x = 1; + longjmp(global_jump_buffer, 1); + } + else if (val == 1){ + if (global_jump_x == 1){ + global_jump_x = 2; + long_jump_from_function(); + } + } + else if (val == 2){ + global_jump_x = 3; + } +} + +static void +long_jump_stepping_tests(void){ + + long_jump_wrapped_in_function(); + + long_jump_wrapped_in_function(); + + long_jump_wrapped_in_function(); + +} + +//////////////////////////////// +// NOTE(allen): Recursion Stepping + +static int +recursive_call(int x){ + if (x <= 1){ + return(x); + } + + int r1 = recursive_call(x - 1); + int r2 = recursive_call(x - 2); + return(r1 + r2); +} + +static int +tail_recursive_call(int x, int m){ + if (x <= 1){ + return(m); + } + return(tail_recursive_call(x - 1, x*m)); +} + +static void +recursion_stepping_tests(void){ + + recursive_call(4); + + recursive_call(4); + + tail_recursive_call(5, 1); + + tail_recursive_call(5, 1); + +} + +//////////////////////////////// +// NOTE(rjf): Debug Strings + +static void +debug_string_tests(void) +{ +#if _WIN32 + for(int i = 0; i < 100; i += 1) + { + OutputDebugStringA("Hello, World!\n"); + } +#endif +} + +//////////////////////////////// +// NOTE(allen): Exception Stepping + +int *global_null_read_pointer = 0; +static void +trip(void){ + *global_null_read_pointer = 0; +} + +static void +cpp_exception_in_function(void){ + int v = 0; + try{ + throw 1; + } + catch (...){ + v = 1; + } +} + +static void +cpp_throw_in_function(void){ + throw 1; +} + +static void +win32_exception_in_function(void){ +#if _WIN32 + int v = 0; + __try{ + trip(); + v = 1; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + v = 2; + } + + v = 3; + __try{ + trip(); + v = 4; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + v = 5; + } +#endif +} + +static void +cpp_recursive_exception(int x){ + try{ + if (x > 1){ + throw 1; + } + } + catch (...){ + x -= 1; + cpp_recursive_exception(x); + x += 1; + } +} + +static void +win32_recursive_exception(int x){ +#if _WIN32 + __try{ + if (x > 1){ + throw 1; + } + } + __except (EXCEPTION_EXECUTE_HANDLER){ + x -= 1; + win32_recursive_exception(x); + x += 1; + } +#endif +} + +static void +exception_stepping_tests(void){ + { + int v = 0; + try{ + throw 1; + } + catch (...){ + v = 1; + } + } + + { + int v = 0; + try{ + cpp_throw_in_function(); + } + catch (...){ + v = 1; + } + } + + cpp_exception_in_function(); + cpp_exception_in_function(); + +#if _WIN32 + win32_exception_in_function(); + win32_exception_in_function(); +#endif + + // NOTE(allen): Exception in catch tests + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + try{ + v = 2; + throw 2; + } + catch (...){ + v = 3; + } + } + } + + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + cpp_exception_in_function(); + } + } + +#if _WIN32 + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + win32_exception_in_function(); + } + } +#endif + + cpp_recursive_exception(4); + cpp_recursive_exception(4); + cpp_recursive_exception(4); + +#if _WIN32 + win32_recursive_exception(4); + win32_recursive_exception(4); + win32_recursive_exception(4); +#endif + + // NOTE(allen): Try in try tests + { + int v = 0; + try{ + try{ + v = 1; + throw 1; + } + catch (...){ + v = 2; + } + throw 2; + } + catch (...){ + v = 3; + } + } + + { + int v = 0; + try{ + try{ + v = 1; + cpp_throw_in_function(); + } + catch (...){ + v = 2; + } + throw 2; + } + catch (...){ + v = 3; + } + } + + { + int v = 0; + try{ + cpp_exception_in_function(); + throw 2; + } + catch (...){ + v = 3; + } + } + +#if _WIN32 + { + int v = 0; + try{ + win32_exception_in_function(); + throw 2; + } + catch (...){ + v = 3; + } + } +#endif + +} + +typedef void (*callback_t)(int a); +static void +dynamic_step_test(void){ +#if _WIN32 +#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( _M_AMD64 ) + void *page = VirtualAlloc(0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); + char *ptr = (char*)page; + *ptr++ = 0x51; // push rcx + *ptr++ = 0x59; // pop rcx + *ptr++ = 0xC3; // ret + callback_t cb = (callback_t)page; + cb(1); +#endif +#endif +} + +//////////////////////////////// + +int +mule_main(int argc, char** argv){ + mule_init(); + + // NOTE(allen): Eval Tests + type_coverage_eval_tests(); + + mutating_variables_eval_tests(); + + nested_types_eval_tests(); + + struct_parameters_eval_tests(); + + global_eval_tests(); + + return_eval_tests(); + + tls_eval_tests(); + + complicated_type_coverage_tests(); + + extended_type_coverage_eval_tests(); + + c_type_coverage_eval_tests(); + + c_type_with_bitfield_usage(); + + optimized_build_eval_tests(); + + optimized_struct_parameters_eval_tests(); + + fancy_viz_eval_tests(); + + // NOTE(allen): Stepping Tests + control_flow_stepping_tests(); + + indirect_call_jump_stepping_tests(); + + alloca_stepping_tests(); + + inline_stepping_tests(); + + overloaded_line_stepping_tests(); + + overloaded_function(100); + + dynamic_step_test(); + + long_jump_stepping_tests(); + + recursion_stepping_tests(); + + debug_string_tests(); + + exception_stepping_tests(); + + return(0); +} + + diff --git a/src/mule/mule_module.cpp b/src/mule/mule_module.cpp new file mode 100644 index 00000000..10d728ba --- /dev/null +++ b/src/mule/mule_module.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/* +** Program to run in debugger organized to provide tests for +** stepping, breakpoints, evaluation, cross-module calls. +*/ + +//////////////////////////////// +// NOTE(allen): Setup + + +#if _WIN32 +#define export_function extern "C" __declspec(dllexport) +#else +#define export_function extern "C" +#endif + + +//////////////////////////////// +// NOTE(allen): TLS Eval + +#if _WIN32 +# define thread_var __declspec(thread) +#else +# define thread_var __thread +#endif + +thread_var float tls_a = 1.015625f; +thread_var int tls_b = -100; + +export_function void +dll_tls_eval_test(void){ + tls_a *= 1.5f; + tls_b *= -2; +} + + diff --git a/src/mule/mule_o2.cpp b/src/mule/mule_o2.cpp new file mode 100644 index 00000000..618a642f --- /dev/null +++ b/src/mule/mule_o2.cpp @@ -0,0 +1,119 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +static int important_s32 = 0; +static float important_f32 = 0; + +#if _WIN32 +#include +#endif + +static void +do_something_with_intermediate_values(void) +{ + static int another_important_s32 = 0; + static float another_important_f32 = 0; + + another_important_s32 = (int)important_f32; + another_important_f32 = (float)important_s32; + +#if _WIN32 + char buffer[256] = "Hello, World!\n"; + buffer[0] += important_s32 + another_important_s32; + buffer[1] += (int)another_important_f32 * important_f32; + OutputDebugStringA(buffer); +#endif +} + +static void +store_important_s32(int *ptr) +{ + important_s32 = *ptr; +} + +static void +store_important_f32(float *ptr) +{ + important_f32 = *ptr; +} + +void +optimized_build_eval_tests(void) +{ + int simple_sum = 0; + for(int i = 0; i < 10000; i += 1) + { + simple_sum += i; + } + store_important_s32(&simple_sum); + + do_something_with_intermediate_values(); + + static struct {float x, y;} vec2s[] = + { + { 10.f, 76.f }, + { 40.f, 50.f }, + { -230.f, 20.f }, + { 27.f, 27.f }, + { 57.f, -57.f }, + { -37.f, 97.f }, + { 99.f, 67.f }, + { 99.f, 37.f }, + { 99.f, 57.f }, + }; + { + struct{float x, y;}sum = {0}; + int count = sizeof(vec2s)/sizeof(vec2s[0]); + for(int i = 0; i < count; i += 1) + { + sum.x += vec2s[i].x; + sum.y += vec2s[i].y; + } + struct{float x, y;}avg = {sum.x/count, sum.y/count}; + float f32 = avg.x * avg.y; + store_important_f32(&f32); + } + + do_something_with_intermediate_values(); + + int factorial = 1; + for(int i = 10; i > 0; i -= 1) + { + factorial *= i; + } + store_important_s32(&factorial); + + do_something_with_intermediate_values(); +} + +//////////////////////////////// +// NOTE(allen): Struct Parameters Eval + +struct OptimizedBasics{ + char a; + unsigned char b; + short c; + unsigned short d; + int e; + unsigned int f; + long long g; + unsigned long long h; + float i; + double j; +}; + +static void +optimized_struct_parameter_helper(int *ptr, OptimizedBasics basics) +{ + basics.a += *ptr; + basics.a += 1; + basics.a += 1; +} + +void +optimized_struct_parameters_eval_tests(void) +{ + int x = 10; + OptimizedBasics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + optimized_struct_parameter_helper(&x, basics); +} diff --git a/src/natvis/base.natvis b/src/natvis/base.natvis new file mode 100644 index 00000000..c606aad1 --- /dev/null +++ b/src/natvis/base.natvis @@ -0,0 +1,161 @@ + + + + {size,str} + size,str + + + + {{ string={string.size,string.str} next={next} }} + + + + empty + {{node count={node_count} total size={total_size} first={first->string} last={last->string} }} + + node_count + total_size + + node_count + first + next + string + + + + + + {{ count={count} pointer={strings} }} + + count + + count + strings + + + + + + + x + y + x*x + y*y + + + + + + x + y + x*x + y*y + + + + + + x + y + x*x + y*y + + + + + + x + y + z + x*x + y*y + z*z + + + + + + x + y + z + x*x + y*y + z*z + + + + + + x + y + z + w + x*x + y*y + z*z + w*w + + + + + + x + y + z + w + x*x + y*y + z*z + w*w + + + + + {{ min={min} max={max} [dim]={max - min} }} + + min + max + max - min + + + + + {{ min={min} max={max} [dim]={max - min} }} + + min + max + max - min + + + + + {{ min={min} max={max} [dim]={max - min} }} + + min + max + max - min + + + + + {{ min={min} max={max} [dim]={max - min} }} + + min + max + max - min + + + + + {{ min={min} max={max} [dim]={max - min} }} + + min + max + max - min + + + + + {{ name={string} hash={hash} value_string={value_string} value_stirngs={value_strings} }} + + + + {{ count={count} first={first} }} + + count + + count + first + next + this + + + + diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c new file mode 100644 index 00000000..f9c2af02 --- /dev/null +++ b/src/os/core/linux/os_core_linux.c @@ -0,0 +1,1682 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include + +//////////////////////////////// +//~ rjf: Globals + +global pthread_mutex_t lnx_mutex = {0}; +global Arena *lnx_perm_arena = 0; +global String8List lnx_cmd_line_args = {0}; +global LNX_Entity lnx_entity_buffer[1024]; +global LNX_Entity *lnx_entity_free = 0; +global String8 lnx_initial_path = {0}; +thread_static LNX_SafeCallChain *lnx_safe_call_chain = 0; + +//////////////////////////////// +//~ rjf: Helpers + +internal B32 +lnx_write_list_to_file_descriptor(int fd, String8List list){ + B32 success = true; + + String8Node *node = list.first; + if (node != 0){ + U8 *ptr = node->string.str;; + U8 *opl = ptr + node->string.size; + + U64 p = 0; + for (;p < list.total_size;){ + U64 amt64 = (U64)(opl - ptr); + U32 amt = u32_from_u64_saturate(amt64); + S64 written_amt = write(fd, ptr, amt); + if (written_amt < 0){ + break; + } + p += written_amt; + ptr += written_amt; + + Assert(ptr <= opl); + if (ptr == opl){ + node = node->next; + if (node == 0){ + if (p < list.total_size){ + success = false; + } + break; + } + ptr = node->string.str; + opl = ptr + node->string.size; + } + } + } + + return(success); +} + +internal void +lnx_date_time_from_tm(DateTime *out, struct tm *in, U32 msec){ + out->msec = msec; + out->sec = in->tm_sec; + out->min = in->tm_min; + out->hour = in->tm_hour; + out->day = in->tm_mday - 1; + out->wday = in->tm_wday; + out->mon = in->tm_mon; + out->year = in->tm_year + 1900; +} + +internal void +lnx_tm_from_date_time(struct tm *out, DateTime *in){ + out->tm_sec = in->sec; + out->tm_min = in->min; + out->tm_hour = in->hour; + out->tm_mday = in->day + 1; + out->tm_mon = in->mon; + out->tm_year = in->year - 1900; +} + +internal void +lnx_dense_time_from_timespec(DenseTime *out, struct timespec *in){ + struct tm tm_time = {0}; + gmtime_r(&in->tv_sec, &tm_time); + DateTime date_time = {0}; + lnx_date_time_from_tm(&date_time, &tm_time, in->tv_nsec/Million(1)); + *out = dense_time_from_date_time(date_time); +} + +internal void +lnx_file_properties_from_stat(FileProperties *out, struct stat *in){ + MemoryZeroStruct(out); + out->size = in->st_size; + lnx_dense_time_from_timespec(&out->created, &in->st_ctim); + lnx_dense_time_from_timespec(&out->modified, &in->st_mtim); + if ((in->st_mode & S_IFDIR) != 0){ + out->flags |= FilePropertyFlag_IsFolder; + } +} + +internal String8 +lnx_string_from_signal(int signum){ + String8 result = str8_lit(""); + switch (signum){ + case SIGABRT: + { + result = str8_lit("SIGABRT"); + }break; + case SIGALRM: + { + result = str8_lit("SIGALRM"); + }break; + case SIGBUS: + { + result = str8_lit("SIGBUS"); + }break; + case SIGCHLD: + { + result = str8_lit("SIGCHLD"); + }break; + case SIGCONT: + { + result = str8_lit("SIGCONT"); + }break; + case SIGFPE: + { + result = str8_lit("SIGFPE"); + }break; + case SIGHUP: + { + result = str8_lit("SIGHUP"); + }break; + case SIGILL: + { + result = str8_lit("SIGILL"); + }break; + case SIGINT: + { + result = str8_lit("SIGINT"); + }break; + case SIGIO: + { + result = str8_lit("SIGIO"); + } + case SIGKILL: + { + result = str8_lit("SIGKILL"); + }break; + case SIGPIPE: + { + result = str8_lit("SIGPIPE"); + }break; + case SIGPROF: + { + result = str8_lit("SIGPROF"); + }break; + case SIGPWR: + { + result = str8_lit("SIGPWR"); + }break; + case SIGQUIT: + { + result = str8_lit("SIGQUIT"); + }break; + case SIGSEGV: + { + result = str8_lit("SIGSEGV"); + }break; + case SIGSTKFLT: + { + result = str8_lit("SIGSTKFLT"); + }break; + case SIGSTOP: + { + result = str8_lit("SIGSTOP"); + }break; + case SIGTSTP: + { + result = str8_lit("SIGTSTP"); + }break; + case SIGSYS: + { + result = str8_lit("SIGSYS"); + }break; + case SIGTERM: + { + result = str8_lit("SIGTERM"); + }break; + case SIGTRAP: + { + result = str8_lit("SIGTRAP"); + }break; + case SIGTTIN: + { + result = str8_lit("SIGTTIN"); + }break; + case SIGTTOU: + { + result = str8_lit("SIGTTOU"); + }break; + case SIGURG: + { + result = str8_lit("SIGURG"); + }break; + case SIGUSR1: + { + result = str8_lit("SIGUSR1"); + }break; + case SIGUSR2: + { + result = str8_lit("SIGUSR2"); + }break; + case SIGVTALRM: + { + result = str8_lit("SIGVTALRM"); + }break; + case SIGXCPU: + { + result = str8_lit("SIGXCPU"); + }break; + case SIGXFSZ: + { + result = str8_lit("SIGXFSZ"); + }break; + case SIGWINCH: + { + result = str8_lit("SIGWINCH"); + }break; + } + return(result); +} + +internal String8 +lnx_string_from_errno(int error_number){ + String8 result = str8_lit(""); + switch (error_number){ + case EPERM: + { + result = str8_lit("EPERM"); + }break; + case ENOENT: + { + result = str8_lit("ENOENT"); + }break; + case ESRCH: + { + result = str8_lit("ESRCH"); + }break; + case EINTR: + { + result = str8_lit("EINTR"); + }break; + case EIO: + { + result = str8_lit("EIO"); + }break; + case ENXIO: + { + result = str8_lit("ENXIO"); + }break; + case E2BIG: + { + result = str8_lit("E2BIG"); + }break; + case ENOEXEC: + { + result = str8_lit("ENOEXEC"); + }break; + case EBADF: + { + result = str8_lit("EBADF"); + }break; + case ECHILD: + { + result = str8_lit("ECHILD"); + }break; + case EAGAIN: + { + result = str8_lit("EAGAIN"); + }break; + case ENOMEM: + { + result = str8_lit("ENOMEM"); + }break; + case EACCES: + { + result = str8_lit("EACCES"); + }break; + case EFAULT: + { + result = str8_lit("EFAULT"); + }break; + case ENOTBLK: + { + result = str8_lit("ENOTBLK"); + }break; + case EBUSY: + { + result = str8_lit("EBUSY"); + }break; + case EEXIST: + { + result = str8_lit("EEXIST"); + }break; + case EXDEV: + { + result = str8_lit("EXDEV"); + }break; + case ENODEV: + { + result = str8_lit("ENODEV"); + }break; + case ENOTDIR: + { + result = str8_lit("ENOTDIR"); + }break; + case EISDIR: + { + result = str8_lit("EISDIR"); + }break; + case EINVAL: + { + result = str8_lit("EINVAL"); + }break; + case ENFILE: + { + result = str8_lit("ENFILE"); + }break; + case EMFILE: + { + result = str8_lit("EMFILE"); + }break; + case ENOTTY: + { + result = str8_lit("ENOTTY"); + }break; + case ETXTBSY: + { + result = str8_lit("ETXTBSY"); + }break; + case EFBIG: + { + result = str8_lit("EFBIG"); + }break; + case ENOSPC: + { + result = str8_lit("ENOSPC"); + }break; + case ESPIPE: + { + result = str8_lit("ESPIPE"); + }break; + case EROFS: + { + result = str8_lit("EROFS"); + }break; + case EMLINK: + { + result = str8_lit("EMLINK"); + }break; + case EPIPE: + { + result = str8_lit("EPIPE"); + }break; + case EDOM: + { + result = str8_lit("EDOM"); + }break; + case ERANGE: + { + result = str8_lit("ERANGE"); + }break; + case EDEADLK: + { + result = str8_lit("EDEADLK"); + }break; + case ENAMETOOLONG: + { + result = str8_lit("ENAMETOOLONG"); + }break; + case ENOLCK: + { + result = str8_lit("ENOLCK"); + }break; + case ENOSYS: + { + result = str8_lit("ENOSYS"); + }break; + case ENOTEMPTY: + { + result = str8_lit("ENOTEMPTY"); + }break; + case ELOOP: + { + result = str8_lit("ELOOP"); + }break; + case ENOMSG: + { + result = str8_lit("ENOMSG"); + }break; + case EIDRM: + { + result = str8_lit("EIDRM"); + }break; + case ECHRNG: + { + result = str8_lit("ECHRNG"); + }break; + case EL2NSYNC: + { + result = str8_lit("EL2NSYNC"); + }break; + case EL3HLT: + { + result = str8_lit("EL3HLT"); + }break; + case EL3RST: + { + result = str8_lit("EL3RST"); + }break; + case ELNRNG: + { + result = str8_lit("ELNRNG"); + }break; + case EUNATCH: + { + result = str8_lit("EUNATCH"); + }break; + case ENOCSI: + { + result = str8_lit("ENOCSI"); + }break; + case EL2HLT: + { + result = str8_lit("EL2HLT"); + }break; + case EBADE: + { + result = str8_lit("EBADE"); + }break; + case EBADR: + { + result = str8_lit("EBADR"); + }break; + case EXFULL: + { + result = str8_lit("EXFULL"); + }break; + case ENOANO: + { + result = str8_lit("ENOANO"); + }break; + case EBADRQC: + { + result = str8_lit("EBADRQC"); + }break; + case EBADSLT: + { + result = str8_lit("EBADSLT"); + }break; + case EBFONT: + { + result = str8_lit("EBFONT"); + }break; + case ENOSTR: + { + result = str8_lit("ENOSTR"); + }break; + case ENODATA: + { + result = str8_lit("ENODATA"); + }break; + case ETIME: + { + result = str8_lit("ETIME"); + }break; + case ENOSR: + { + result = str8_lit("ENOSR"); + }break; + case ENONET: + { + result = str8_lit("ENONET"); + }break; + case ENOPKG: + { + result = str8_lit("ENOPKG"); + }break; + case EREMOTE: + { + result = str8_lit("EREMOTE"); + }break; + case ENOLINK: + { + result = str8_lit("ENOLINK"); + }break; + case EADV: + { + result = str8_lit("EADV"); + }break; + case ESRMNT: + { + result = str8_lit("ESRMNT"); + }break; + case ECOMM: + { + result = str8_lit("ECOMM"); + }break; + case EPROTO: + { + result = str8_lit("EPROTO"); + }break; + case EMULTIHOP: + { + result = str8_lit("EMULTIHOP"); + }break; + case EDOTDOT: + { + result = str8_lit("EDOTDOT"); + }break; + case EBADMSG: + { + result = str8_lit("EBADMSG"); + }break; + case EOVERFLOW: + { + result = str8_lit("EOVERFLOW"); + }break; + case ENOTUNIQ: + { + result = str8_lit("ENOTUNIQ"); + }break; + case EBADFD: + { + result = str8_lit("EBADFD"); + }break; + case EREMCHG: + { + result = str8_lit("EREMCHG"); + }break; + case ELIBACC: + { + result = str8_lit("ELIBACC"); + }break; + case ELIBBAD: + { + result = str8_lit("ELIBBAD"); + }break; + case ELIBSCN: + { + result = str8_lit("ELIBSCN"); + }break; + case ELIBMAX: + { + result = str8_lit("ELIBMAX"); + }break; + case ELIBEXEC: + { + result = str8_lit("ELIBEXEC"); + }break; + case EILSEQ: + { + result = str8_lit("EILSEQ"); + }break; + case ERESTART: + { + result = str8_lit("ERESTART"); + }break; + case ESTRPIPE: + { + result = str8_lit("ESTRPIPE"); + }break; + case EUSERS: + { + result = str8_lit("EUSERS"); + }break; + case ENOTSOCK: + { + result = str8_lit("ENOTSOCK"); + }break; + case EDESTADDRREQ: + { + result = str8_lit("EDESTADDRREQ"); + }break; + case EMSGSIZE: + { + result = str8_lit("EMSGSIZE"); + }break; + case EPROTOTYPE: + { + result = str8_lit("EPROTOTYPE"); + }break; + case ENOPROTOOPT: + { + result = str8_lit("ENOPROTOOPT"); + }break; + case EPROTONOSUPPORT: + { + result = str8_lit("EPROTONOSUPPORT"); + }break; + case ESOCKTNOSUPPORT: + { + result = str8_lit("ESOCKTNOSUPPORT"); + }break; + case EOPNOTSUPP: + { + result = str8_lit("EOPNOTSUPP"); + }break; + case EPFNOSUPPORT: + { + result = str8_lit("EPFNOSUPPORT"); + }break; + case EAFNOSUPPORT: + { + result = str8_lit("EAFNOSUPPORT"); + }break; + case EADDRINUSE: + { + result = str8_lit("EADDRINUSE"); + }break; + case EADDRNOTAVAIL: + { + result = str8_lit("EADDRNOTAVAIL"); + }break; + case ENETDOWN: + { + result = str8_lit("ENETDOWN"); + }break; + case ENETUNREACH: + { + result = str8_lit("ENETUNREACH"); + }break; + case ENETRESET: + { + result = str8_lit("ENETRESET"); + }break; + case ECONNABORTED: + { + result = str8_lit("ECONNABORTED"); + }break; + case ECONNRESET: + { + result = str8_lit("ECONNRESET"); + }break; + case ENOBUFS: + { + result = str8_lit("ENOBUFS"); + }break; + case EISCONN: + { + result = str8_lit("EISCONN"); + }break; + case ENOTCONN: + { + result = str8_lit("ENOTCONN"); + }break; + case ESHUTDOWN: + { + result = str8_lit("ESHUTDOWN"); + }break; + case ETOOMANYREFS: + { + result = str8_lit("ETOOMANYREFS"); + }break; + case ETIMEDOUT: + { + result = str8_lit("ETIMEDOUT"); + }break; + case ECONNREFUSED: + { + result = str8_lit("ECONNREFUSED"); + }break; + case EHOSTDOWN: + { + result = str8_lit("EHOSTDOWN"); + }break; + case EHOSTUNREACH: + { + result = str8_lit("EHOSTUNREACH"); + }break; + case EALREADY: + { + result = str8_lit("EALREADY"); + }break; + case EINPROGRESS: + { + result = str8_lit("EINPROGRESS"); + }break; + case ESTALE: + { + result = str8_lit("ESTALE"); + }break; + case EUCLEAN: + { + result = str8_lit("EUCLEAN"); + }break; + case ENOTNAM: + { + result = str8_lit("ENOTNAM"); + }break; + case ENAVAIL: + { + result = str8_lit("ENAVAIL"); + }break; + case EISNAM: + { + result = str8_lit("EISNAM"); + }break; + case EREMOTEIO: + { + result = str8_lit("EREMOTEIO"); + }break; + case EDQUOT: + { + result = str8_lit("EDQUOT"); + }break; + case ENOMEDIUM: + { + result = str8_lit("ENOMEDIUM"); + }break; + case EMEDIUMTYPE: + { + result = str8_lit("EMEDIUMTYPE"); + }break; + case ECANCELED: + { + result = str8_lit("ECANCELED"); + }break; + case ENOKEY: + { + result = str8_lit("ENOKEY"); + }break; + case EKEYEXPIRED: + { + result = str8_lit("EKEYEXPIRED"); + }break; + case EKEYREVOKED: + { + result = str8_lit("EKEYREVOKED"); + }break; + case EKEYREJECTED: + { + result = str8_lit("EKEYREJECTED"); + }break; + case EOWNERDEAD: + { + result = str8_lit("EOWNERDEAD"); + }break; + case ENOTRECOVERABLE: + { + result = str8_lit("ENOTRECOVERABLE"); + }break; + case ERFKILL: + { + result = str8_lit("ERFKILL"); + }break; + case EHWPOISON: + { + result = str8_lit("EHWPOISON"); + }break; + } + return(result); +} + +internal LNX_Entity* +lnx_alloc_entity(LNX_EntityKind kind){ + pthread_mutex_lock(&lnx_mutex); + LNX_Entity *result = lnx_entity_free; + Assert(result != 0); + SLLStackPop(lnx_entity_free); + pthread_mutex_unlock(&lnx_mutex); + result->kind = kind; + return(result); +} + +internal void +lnx_free_entity(LNX_Entity *entity){ + entity->kind = LNX_EntityKind_Null; + pthread_mutex_lock(&lnx_mutex); + SLLStackPush(lnx_entity_free, entity); + pthread_mutex_unlock(&lnx_mutex); +} + +internal void* +lnx_thread_base(void *ptr){ + LNX_Entity *entity = (LNX_Entity*)ptr; + OS_ThreadFunctionType *func = entity->thread.func; + void *thread_ptr = entity->thread.ptr; + + TCTX tctx_; + tctx_init_and_equip(&tctx_); + + func(thread_ptr); + + // remove my bit + U32 result = __sync_fetch_and_and(&entity->reference_mask, ~0x2); + // if the other bit is also gone, free entity + if ((result & 0x1) == 0){ + lnx_free_entity(entity); + } + return(0); +} + +internal void +lnx_safe_call_sig_handler(int){ + LNX_SafeCallChain *chain = lnx_safe_call_chain; + if (chain != 0 && chain->fail_handler != 0){ + chain->fail_handler(chain->ptr); + } + abort(); +} + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void +os_init(int argc, char **argv) +{ + // NOTE(allen): Initialize linux layer mutex + { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + int pthread_result = pthread_mutex_init(&lnx_mutex, &attr); + pthread_mutexattr_destroy(&attr); + if (pthread_result == -1){ + abort(); + } + } + MemoryZeroArray(lnx_entity_buffer); + { + LNX_Entity *ptr = lnx_entity_free = lnx_entity_buffer; + for (U64 i = 1; i < ArrayCount(lnx_entity_buffer); i += 1, ptr += 1){ + ptr->next = ptr + 1; + } + ptr->next = 0; + } + + // NOTE(allen): Permanent memory allocator for this layer + Arena *perm_arena = arena_alloc(); + lnx_perm_arena = perm_arena; + + // NOTE(allen): Initialize Paths + lnx_initial_path = os_get_path(lnx_perm_arena, OS_SystemPath_Current); + + // NOTE(rjf): Setup command line args + lnx_cmd_line_args = os_string_list_from_argcv(lnx_perm_arena, argc, argv); +} + +//////////////////////////////// +//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) + +internal void* +os_reserve(U64 size){ + void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + return(result); +} + +internal B32 +os_commit(void *ptr, U64 size){ + mprotect(ptr, size, PROT_READ|PROT_WRITE); + // TODO(allen): can we test this? + return(true); +} + +internal void* +os_reserve_large(U64 size){ + NotImplemented; + return 0; +} + +internal B32 +os_commit_large(void *ptr, U64 size){ + NotImplemented; + return 0; +} + +internal void +os_decommit(void *ptr, U64 size){ + madvise(ptr, size, MADV_DONTNEED); + mprotect(ptr, size, PROT_NONE); +} + +internal void +os_release(void *ptr, U64 size){ + munmap(ptr, size); +} + +internal void +os_set_large_pages(B32 flag) +{ + NotImplemented; +} + +internal B32 +os_large_pages_enabled(void) +{ + NotImplemented; + return 0; +} + +internal U64 +os_large_page_size(void) +{ + NotImplemented; + return 0; +} + +internal void* +os_alloc_ring_buffer(U64 size, U64 *actual_size_out) +{ + NotImplemented; + return 0; +} + +internal void +os_free_ring_buffer(void *ring_buffer, U64 actual_size) +{ + NotImplemented; +} + +//////////////////////////////// +//~ rjf: @os_hooks System Info (Implemented Per-OS) + +internal String8 +os_machine_name(void){ + local_persist B32 first = true; + local_persist String8 name = {0}; + + // TODO(allen): let's just pre-compute this at init and skip the complexity + pthread_mutex_lock(&lnx_mutex); + if (first){ + Temp scratch = scratch_begin(0, 0); + first = false; + + // get name + B32 got_final_result = false; + U8 *buffer = 0; + int size = 0; + for (S64 cap = 4096, r = 0; + r < 4; + cap *= 2, r += 1){ + scratch.restore(); + buffer = push_array_no_zero(scratch.arena, U8, cap); + size = gethostname((char*)buffer, cap); + if (size < cap){ + got_final_result = true; + break; + } + } + + // save string + if (got_final_result && size > 0){ + name.size = size; + name.str = push_array_no_zero(lnx_perm_arena, U8, name.size + 1); + MemoryCopy(name.str, buffer, name.size); + name.str[name.size] = 0; + } + + scratch_end(scratch); + } + pthread_mutex_unlock(&lnx_mutex); + + return(name); +} + +internal U64 +os_page_size(void){ + int size = getpagesize(); + return((U64)size); +} + +internal U64 +os_allocation_granularity(void) +{ + // On linux there is no equivalent of "dwAllocationGranularity" + os_page_size(); +} + +internal U64 +os_logical_core_count(void) +{ + // TODO(rjf): check this + return get_nprocs(); +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Info (Implemented Per-OS) + +internal String8List +os_get_command_line_arguments(void) +{ + return lnx_cmd_line_args; +} + +internal S32 +os_get_pid(void){ + S32 result = getpid(); + return(result); +} + +internal S32 +os_get_tid(void){ + S32 result = 0; +#ifdef SYS_gettid + result = syscall(SYS_gettid); +#else + result = gettid(); +#endif + return(result); +} + +internal String8List +os_get_environment(void) +{ + NotImplemented; + String8List result = {0}; + return result; +} + +internal U64 +os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out){ + U64 result = 0; + + switch (path){ + case OS_SystemPath_Binary: + { + local_persist B32 first = true; + local_persist String8 name = {0}; + + // TODO(allen): let's just pre-compute this at init and skip the complexity + pthread_mutex_lock(&lnx_mutex); + if (first){ + Temp scratch = scratch_begin(&arena, 1); + first = false; + + // get self string + B32 got_final_result = false; + U8 *buffer = 0; + int size = 0; + for (S64 cap = PATH_MAX, r = 0; + r < 4; + cap *= 2, r += 1){ + scratch.restore(); + buffer = push_array_no_zero(scratch.arena, U8, cap); + size = readlink("/proc/self/exe", (char*)buffer, cap); + if (size < cap){ + got_final_result = true; + break; + } + } + + // save string + if (got_final_result && size > 0){ + String8 full_name = str8(buffer, size); + String8 name_chopped = string_path_chop_last_slash(full_name); + name = push_str8_copy(lnx_perm_arena, name_chopped); + } + + scratch_end(scratch); + } + pthread_mutex_unlock(&lnx_mutex); + + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_Initial: + { + Assert(lnx_initial_path.str != 0); + result = 1; + str8_list_push(arena, out, lnx_initial_path); + }break; + + case OS_SystemPath_Current: + { + char *cwdir = getcwd(0, 0); + String8 string = push_str8_copy(arena, str8_cstring(cwdir)); + free(cwdir); + result = 1; + str8_list_push(arena, out, string); + }break; + + case OS_SystemPath_UserProgramData: + { + char *home = getenv("HOME"); + String8 string = str8_cstring(home); + result = 1; + str8_list_push(arena, out, string); + }break; + + case OS_SystemPath_ModuleLoad: + { + // TODO(allen): this one is big and complicated and only needed for making + // a debugger, skipping for now. + NotImplemented; + }break; + } + + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Control (Implemented Per-OS) + +internal void +os_exit_process(S32 exit_code){ + exit(exit_code); +} + +//////////////////////////////// +//~ rjf: @os_hooks File System (Implemented Per-OS) + +//- rjf: files + +internal OS_Handle +os_file_open(OS_AccessFlags flags, String8 path) +{ + OS_Handle file = {0}; + NotImplemented; + return file; +} + +internal void +os_file_close(OS_Handle file) +{ + NotImplemented; +} + +internal U64 +os_file_read(OS_Handle file, Rng1U64 rng, void *out_data) +{ + NotImplemented; + return 0; +} + +internal void +os_file_write(OS_Handle file, Rng1U64 rng, void *data) +{ + NotImplemented; +} + +internal B32 +os_file_set_times(OS_Handle file, DateTime time) +{ + NotImplemented; +} + +internal FileProperties +os_properties_from_file(OS_Handle file) +{ + FileProperties props = {0}; + NotImplemented; + return props; +} + +internal OS_FileID +os_id_from_file(OS_Handle file) +{ + // TODO(nick): querry struct stat with fstat(2) and use st_dev and st_ino as ids + OS_FileID id = {0}; + NotImplemented; + return id; +} + +internal B32 +os_delete_file_at_path(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + B32 result = false; + String8 name_copy = push_str8_copy(scratch.arena, name); + if (remove((char*)name_copy.str) != -1){ + result = true; + } + scratch_end(scratch); + return(result); +} + +internal B32 +os_copy_file_path(String8 dst, String8 src) +{ + NotImplemented; + return 0; +} + +internal String8 +os_full_path_from_path(Arena *arena, String8 path) +{ + // TODO: realpath can be used to resolve full path + String8 result = {0}; + NotImplemented; + return result; +} + +internal B32 +os_file_path_exists(String8 path) +{ + NotImplemented; + return 0; +} + +//- rjf: file maps + +internal OS_Handle +os_file_map_open(OS_AccessFlags flags, OS_Handle file) +{ + NotImplemented; + OS_Handle handle = {0}; + return handle; +} + +internal void +os_file_map_close(OS_Handle map) +{ + NotImplemented; +} + +internal void * +os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) +{ + NotImplemented; + return 0; +} + +internal void +os_file_map_view_close(OS_Handle map, void *ptr) +{ + NotImplemented; +} + +//- rjf: directory iteration + +internal OS_FileIter * +os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) +{ + NotImplemented; + return 0; +} + +internal B32 +os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) +{ + NotImplemented; + return 0; +} + +internal void +os_file_iter_end(OS_FileIter *iter) +{ + NotImplemented; +} + +//- rjf: directory creation + +internal B32 +os_make_directory(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + B32 result = false; + String8 name_copy = push_str8_copy(scratch.arena, name); + if (mkdir((char*)name_copy.str, 0777) != -1){ + result = true; + } + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Shared Memory (Implemented Per-OS) + +internal OS_Handle +os_shared_memory_alloc(U64 size, String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal OS_Handle +os_shared_memory_open(String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_shared_memory_close(OS_Handle handle) +{ + NotImplemented; +} + +internal void * +os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) +{ + NotImplemented; + return 0; +} + +internal void +os_shared_memory_view_close(OS_Handle handle, void *ptr) +{ + NotImplemented; +} + +//////////////////////////////// +//~ rjf: @os_hooks Time (Implemented Per-OS) + +internal OS_UnixTime +os_now_unix(void) +{ + time_t t = time(0); + return (OS_UnixTime)t; +} + +internal DateTime +os_now_universal_time(void){ + time_t t = 0; + time(&t); + struct tm universal_tm = {0}; + gmtime_r(&t, &universal_tm); + DateTime result = {0}; + lnx_date_time_from_tm(&result, &universal_tm, 0); + return(result); +} + +internal DateTime +os_universal_time_from_local_time(DateTime *local_time){ + // local time -> universal time (using whatever types it takes) + struct tm local_tm = {0}; + lnx_tm_from_date_time(&local_tm, local_time); + local_tm.tm_isdst = -1; + time_t universal_t = mktime(&local_tm); + + // whatever type we ended up with -> DateTime (don't alter the space along the way) + struct tm universal_tm = {0}; + gmtime_r(&universal_t, &universal_tm); + DateTime result = {0}; + lnx_date_time_from_tm(&result, &universal_tm, 0); + return(result); +} + +internal DateTime +os_local_time_from_universal_time(DateTime *universal_time){ + // universal time -> local time (using whatever types it takes) + struct tm universal_tm = {0}; + lnx_tm_from_date_time(&universal_tm, universal_time); + universal_tm.tm_isdst = -1; + time_t universal_t = timegm(&universal_tm); + struct tm local_tm = {0}; + localtime_r(&universal_t, &local_tm); + + // whatever type we ended up with -> DateTime (don't alter the space along the way) + DateTime result = {0}; + lnx_date_time_from_tm(&result, &local_tm, 0); + return(result); +} + +internal U64 +os_now_microseconds(void){ + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + U64 result = t.tv_sec*Million(1) + (t.tv_nsec/Thousand(1)); + return(result); +} + +internal void +os_sleep_milliseconds(U32 msec){ + usleep(msec*Thousand(1)); +} + +//////////////////////////////// +//~ rjf: @os_hooks Child Processes (Implemented Per-OS) + +internal B32 +os_launch_process(OS_LaunchOptions *options){ + // TODO(allen): I want to redo this API before I bother implementing it here + NotImplemented; + return(false); +} + +//////////////////////////////// +//~ rjf: @os_hooks Threads (Implemented Per-OS) + +internal OS_Handle +os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params){ + // entity + LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_Thread); + entity->reference_mask = 0x3; + entity->thread.func = func; + entity->thread.ptr = ptr; + + // pthread + pthread_attr_t attr; + pthread_attr_init(&attr); + int pthread_result = pthread_create(&entity->thread.handle, &attr, lnx_thread_base, entity); + pthread_attr_destroy(&attr); + if (pthread_result == -1){ + lnx_free_entity(entity); + entity = 0; + } + + // cast to opaque handle + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_release_thread_handle(OS_Handle thread){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(thread.id); + // remove my bit + U32 result = __sync_fetch_and_and(&entity->reference_mask, ~0x1); + // if the other bit is also gone, free entity + if ((result & 0x2) == 0){ + lnx_free_entity(entity); + } +} + +//////////////////////////////// +//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) + +// NOTE(allen): Mutexes are recursive - support counted acquire/release nesting +// on a single thread + +//- rjf: recursive mutexes + +internal OS_Handle +os_mutex_alloc(void){ + // entity + LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_Mutex); + + // pthread + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + int pthread_result = pthread_mutex_init(&entity->mutex, &attr); + pthread_mutexattr_destroy(&attr); + if (pthread_result == -1){ + lnx_free_entity(entity); + entity = 0; + } + + // cast to opaque handle + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_mutex_release(OS_Handle mutex){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(mutex.id); + pthread_mutex_destroy(&entity->mutex); + lnx_free_entity(entity); +} + +internal void +os_mutex_take_(OS_Handle mutex){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(mutex.id); + pthread_mutex_lock(&entity->mutex); +} + +internal void +os_mutex_drop_(OS_Handle mutex){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(mutex.id); + pthread_mutex_unlock(&entity->mutex); +} + +//- rjf: reader/writer mutexes + +internal OS_Handle +os_rw_mutex_alloc(void) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_rw_mutex_release(OS_Handle rw_mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_take_r_(OS_Handle mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_drop_r_(OS_Handle mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_take_w_(OS_Handle mutex) +{ + NotImplemented; +} + +internal void +os_rw_mutex_drop_w_(OS_Handle mutex) +{ + NotImplemented; +} + +//- rjf: condition variables + +internal OS_Handle +os_condition_variable_alloc(void){ + // entity + LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_ConditionVariable); + + // pthread + pthread_condattr_t attr; + pthread_condattr_init(&attr); + int pthread_result = pthread_cond_init(&entity->cond, &attr); + pthread_condattr_destroy(&attr); + if (pthread_result == -1){ + lnx_free_entity(entity); + entity = 0; + } + + // cast to opaque handle + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_condition_variable_release(OS_Handle cv){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(cv.id); + pthread_cond_destroy(&entity->cond); + lnx_free_entity(entity); +} + +internal B32 +os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us){ + B32 result = false; + LNX_Entity *entity_cond = (LNX_Entity*)PtrFromInt(cv.id); + LNX_Entity *entity_mutex = (LNX_Entity*)PtrFromInt(mutex.id); + // TODO(allen): implement the time control + pthread_cond_timedwait(&entity_cond->cond, &entity_mutex->mutex); + return(result); +} + +internal B32 +os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +{ + NotImplemented; + return 0; +} + +internal B32 +os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +{ + NotImplemented; + return 0; +} + +internal void +os_condition_variable_signal_(OS_Handle cv){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(cv.id); + pthread_cond_signal(&entity->cond); +} + +internal void +os_condition_variable_broadcast_(OS_Handle cv){ + LNX_Entity *entity = (LNX_Entity*)PtrFromInt(cv.id); + DontCompile; +} + +//- rjf: cross-process semaphores + +internal OS_Handle +os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_semaphore_release(OS_Handle semaphore) +{ + NotImplemented; +} + +internal OS_Handle +os_semaphore_open(String8 name) +{ + OS_Handle result = {0}; + NotImplemented; + return result; +} + +internal void +os_semaphore_close(OS_Handle semaphore) +{ + NotImplemented; +} + +internal B32 +os_semaphore_take(OS_Handle semaphore) +{ + NotImplemented; + return 0; +} + +internal void +os_semaphore_drop(OS_Handle semaphore) +{ + NotImplemented; +} + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal OS_Handle +os_library_open(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + char *path_cstr = (char *)push_str8_copy(scratch.arena, path).str; + void *so = dlopen(path_cstr, RTLD_LAZY); + OS_Handle lib = { (U64)so }; + scratch_end(scratch); + return lib; +} + +internal VoidProc * +os_library_load_proc(OS_Handle lib, String8 name) +{ + Temp scratch = scratch_begin(0, 0); + void *so = (void *)lib.id; + char *name_cstr = (char *)push_str8_copy(scratch.arena, name).str; + VoidProc *proc = (VoidProc *)dlsym(so, name_cstr); + scratch_end(scratch); + return proc; +} + +internal void +os_library_close(OS_Handle lib) +{ + void *so = (void *)lib.id; + dlclose(so); +} + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal void +os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr){ + LNX_SafeCallChain chain = {0}; + SLLStackPush(lnx_safe_call_chain, &chain); + chain.fail_handler = fail_handler; + chain.ptr = ptr; + + struct sigaction new_act = {0}; + new_act.sa_handler = lnx_safe_call_sig_handler; + + int signals_to_handle[] = { + SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, + }; + struct sigaction og_act[ArrayCount(signals_to_handle)] = {0}; + + for (U32 i = 0; i < ArrayCount(signals_to_handle); i += 1){ + sigaction(signals_to_handle[i], &new_act, &og_act[i]); + } + + func(ptr); + + for (U32 i = 0; i < ArrayCount(signals_to_handle); i += 1){ + sigaction(signals_to_handle[i], &og_act[i], 0); + } +} + +//////////////////////////////// + +internal OS_Guid +os_make_guid(void) +{ + NotImplemented; +} + diff --git a/src/os/core/linux/os_core_linux.h b/src/os/core/linux/os_core_linux.h new file mode 100644 index 00000000..9899f94a --- /dev/null +++ b/src/os/core/linux/os_core_linux.h @@ -0,0 +1,88 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef LINUX_H +#define LINUX_H + +//////////////////////////////// +//~ NOTE(allen): Get all these linux includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////// +//~ NOTE(allen): File Iterator + +struct LNX_FileIter{ + int fd; + DIR *dir; +}; +StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(LNX_FileIter), file_iter_memory_size); + +//////////////////////////////// +//~ NOTE(allen): Threading Entities + +enum LNX_EntityKind{ + LNX_EntityKind_Null, + LNX_EntityKind_Thread, + LNX_EntityKind_Mutex, + LNX_EntityKind_ConditionVariable, +}; + +struct LNX_Entity{ + LNX_Entity *next; + LNX_EntityKind kind; + volatile U32 reference_mask; + union{ + struct{ + OS_ThreadFunctionType *func; + void *ptr; + pthread_t handle; + } thread; + pthread_mutex_t mutex; + pthread_cond_t cond; + }; +}; + +//////////////////////////////// +//~ NOTE(allen): Safe Call Chain + +struct LNX_SafeCallChain{ + LNX_SafeCallChain *next; + OS_ThreadFunctionType *fail_handler; + void *ptr; +}; + +//////////////////////////////// +//~ NOTE(allen): Helpers + +internal B32 lnx_write_list_to_file_descriptor(int fd, String8List list); + +internal void lnx_date_time_from_tm(DateTime *out, struct tm *in, U32 msec); +internal void lnx_tm_from_date_time(struct tm *out, DateTime *in); +internal void lnx_dense_time_from_timespec(DenseTime *out, struct timespec *in); +internal void lnx_file_properties_from_stat(FileProperties *out, struct stat *in); + +internal String8 lnx_string_from_signal(int signum); +internal String8 lnx_string_from_errno(int error_number); + +internal LNX_Entity* lnx_alloc_entity(LNX_EntityKind kind); +internal void lnx_free_entity(LNX_Entity *entity); +internal void* lnx_thread_base(void *ptr); + +internal void lnx_safe_call_sig_handler(int); + +#endif //LINUX_H diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c new file mode 100644 index 00000000..0323091d --- /dev/null +++ b/src/os/core/os_core.c @@ -0,0 +1,265 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Handle Type Functions (Helpers, Implemented Once) + +internal OS_Handle +os_handle_zero(void) +{ + OS_Handle handle = {0}; + return handle; +} + +internal B32 +os_handle_match(OS_Handle a, OS_Handle b) +{ + return a.u64[0] == b.u64[0]; +} + +internal void +os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle) +{ + OS_HandleNode *n = push_array(arena, OS_HandleNode, 1); + n->v = handle; + SLLQueuePush(handles->first, handles->last, n); + handles->count += 1; +} + +internal OS_HandleArray +os_handle_array_from_list(Arena *arena, OS_HandleList *list) +{ + OS_HandleArray result = {0}; + result.count = list->count; + result.v = push_array_no_zero(arena, OS_Handle, result.count); + U64 idx = 0; + for(OS_HandleNode *n = list->first; n != 0; n = n->next, idx += 1) + { + result.v[idx] = n->v; + } + return result; +} + +//////////////////////////////// +//~ rjf: System Path Helper (Helper, Implemented Once) + +internal String8 +os_string_from_system_path(Arena *arena, OS_SystemPath path) +{ + String8List strs = {0}; + os_string_list_from_system_path(arena, path, &strs); + String8 result = str8_list_first(&strs); + return result; +} + +//////////////////////////////// +//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) + +internal String8List +os_string_list_from_argcv(Arena *arena, int argc, char **argv) +{ + String8List result = {0}; + for(int i = 0; i < argc; i += 1) + { + String8 str = str8_cstring(argv[i]); + str8_list_push(arena, &result, str); + } + return result; +} + +//////////////////////////////// +//~ rjf: Process Helpers (Helper, Implemented Once) + +internal void +os_relaunch_self(void){ + Temp scratch = scratch_begin(0, 0); + OS_LaunchOptions opts = {0}; + opts.cmd_line = os_get_command_line_arguments(); + opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Initial); + os_launch_process(&opts, 0); + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: Filesystem Helpers (Helpers, Implemented Once) + +internal String8 +os_data_from_file_path(Arena *arena, String8 path) +{ + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path); + FileProperties props = os_properties_from_file(file); + String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size)); + os_file_close(file); + return data; +} + +internal B32 +os_write_data_to_file_path(String8 path, String8 data) +{ + B32 good = 0; + OS_Handle file = os_file_open(OS_AccessFlag_Write, path); + if(!os_handle_match(file, os_handle_zero())) + { + good = 1; + os_file_write(file, r1u64(0, data.size), data.str); + os_file_close(file); + } + return good; +} + +internal B32 +os_write_data_list_to_file_path(String8 path, String8List list) +{ + B32 good = 0; + OS_Handle file = os_file_open(OS_AccessFlag_Write, path); + if(!os_handle_match(file, os_handle_zero())) + { + good = 1; + U64 off = 0; + for(String8Node *n = list.first; n != 0; n = n->next) + { + os_file_write(file, r1u64(off, off+n->string.size), n->string.str); + off += n->string.size; + } + os_file_close(file); + } + return good; +} + +internal FileProperties +os_properties_from_file_path(String8 path) +{ + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path); + FileProperties props = os_properties_from_file(file); + os_file_close(file); + return props; +} + +internal OS_FileID +os_id_from_file_path(String8 path) +{ + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path); + OS_FileID id = os_id_from_file(file); + os_file_close(file); + return id; +} + +internal S64 +os_file_id_compare(OS_FileID a, OS_FileID b) +{ + S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v)); + return cmp; +} + +internal String8 +os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range) +{ + U64 pre_pos = arena_pos(arena); + String8 result; + result.size = dim_1u64(range); + result.str = push_array_no_zero(arena, U8, result.size); + U64 actual_read_size = os_file_read(file, range, result.str); + if(actual_read_size < result.size) + { + arena_pop_to(arena, pre_pos + actual_read_size); + result.size = actual_read_size; + } + return result; +} + +//////////////////////////////// +//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once) + +internal void +os_mutex_take(OS_Handle mutex){ + ProfBeginLockWait((void *)(mutex.u64[0]), "take mutex"); + os_mutex_take_(mutex); + ProfEndLockWait(); + ProfLockTake((void *)(mutex.u64[0]), "take mutex"); +} + +internal void +os_mutex_drop(OS_Handle mutex){ + os_mutex_drop_(mutex); + ProfLockDrop((void *)(mutex.u64[0])); +} + +internal void +os_rw_mutex_take_r(OS_Handle rw_mutex){ + ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take r"); + os_rw_mutex_take_r_(rw_mutex); + ProfEndLockWait(); + ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take r"); +} + +internal void +os_rw_mutex_drop_r(OS_Handle rw_mutex){ + os_rw_mutex_drop_r_(rw_mutex); + ProfLockDrop((void *)(rw_mutex.u64[0])); +} + +internal void +os_rw_mutex_take_w(OS_Handle rw_mutex){ + ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take rw"); + os_rw_mutex_take_w_(rw_mutex); + ProfEndLockWait(); + ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take rw"); +} + +internal void +os_rw_mutex_drop_w(OS_Handle rw_mutex){ + os_rw_mutex_drop_w_(rw_mutex); + ProfLockDrop((void *)(rw_mutex.u64[0])); +} + +internal B32 +os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us){ + ProfLockDrop((void *)(mutex.u64[0])); + B32 result = os_condition_variable_wait_(cv, mutex, endt_us); + ProfLockTake((void *)(mutex.u64[0]), "wait cv"); + return(result); +} + +internal B32 +os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + ProfLockDrop((void *)(mutex_rw.u64[0])); + B32 result = os_condition_variable_wait_rw_r_(cv, mutex_rw, endt_us); + ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw r"); + return(result); +} + +internal B32 +os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + ProfLockDrop((void *)(mutex_rw.u64[0])); + B32 result = os_condition_variable_wait_rw_w_(cv, mutex_rw, endt_us); + ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw w"); + return(result); +} + +internal void +os_condition_variable_signal(OS_Handle cv){ + os_condition_variable_signal_(cv); +} + +internal void +os_condition_variable_broadcast(OS_Handle cv){ + os_condition_variable_broadcast_(cv); +} + +internal String8 +os_string_from_guid(Arena *arena, OS_Guid guid) +{ + String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + guid.data1, + guid.data2, + guid.data3, + guid.data4[0], + guid.data4[1], + guid.data4[2], + guid.data4[3], + guid.data4[4], + guid.data4[5], + guid.data4[6], + guid.data4[7]); + return result; +} diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h new file mode 100644 index 00000000..34d33b99 --- /dev/null +++ b/src/os/core/os_core.h @@ -0,0 +1,365 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef OS_CORE_H +#define OS_CORE_H + +//////////////////////////////// +//~ rjf: Access Flags + +typedef U32 OS_AccessFlags; +enum +{ + OS_AccessFlag_Read = (1<<0), + OS_AccessFlag_Write = (1<<1), + OS_AccessFlag_Execute = (1<<2), + OS_AccessFlag_Shared = (1<<3), +}; + +//////////////////////////////// +//~ allen: Files + +typedef U32 OS_FileIterFlags; +enum +{ + OS_FileIterFlag_SkipFolders = (1 << 0), + OS_FileIterFlag_SkipFiles = (1 << 1), + OS_FileIterFlag_SkipHiddenFiles = (1 << 2), + OS_FileIterFlag_Done = (1 << 31), +}; + +typedef struct OS_FileIter OS_FileIter; +struct OS_FileIter +{ + OS_FileIterFlags flags; + U8 memory[600]; +}; + +typedef struct OS_FileInfo OS_FileInfo; +struct OS_FileInfo +{ + String8 name; + FileProperties props; +}; + +// nick: on-disk file identifier +typedef struct OS_FileID OS_FileID; +struct OS_FileID +{ + U64 v[3]; +}; + +//////////////////////////////// +//~ rjf: System Paths + +typedef enum OS_SystemPath +{ + OS_SystemPath_Binary, + OS_SystemPath_Initial, + OS_SystemPath_Current, + OS_SystemPath_UserProgramData, + OS_SystemPath_ModuleLoad, +} +OS_SystemPath; + +typedef enum OS_PathFromUserKind +{ + OS_PathFromUserKind_Save, + OS_PathFromUserKind_Load, +} +OS_PathFromUserKind; + +typedef struct OS_PathFromUser OS_PathFromUser; +struct OS_PathFromUser +{ + OS_PathFromUserKind kind; + String8 path; + U64 filter_count; + String8 *filter_extensions; + String8 *filter_names; +}; + +//////////////////////////////// +//~ allen: Launch Input + +typedef struct OS_LaunchOptions OS_LaunchOptions; +struct OS_LaunchOptions +{ + String8List cmd_line; + String8 path; + String8List env; + B32 inherit_env; + B32 consoleless; +}; + +//////////////////////////////// +//~ rjf: Handle Type + +typedef struct OS_Handle OS_Handle; +struct OS_Handle +{ + U64 u64[1]; +}; + +typedef struct OS_HandleNode OS_HandleNode; +struct OS_HandleNode +{ + OS_HandleNode *next; + OS_Handle v; +}; + +typedef struct OS_HandleList OS_HandleList; +struct OS_HandleList +{ + OS_HandleNode *first; + OS_HandleNode *last; + U64 count; +}; + +typedef struct OS_HandleArray OS_HandleArray; +struct OS_HandleArray +{ + OS_Handle *v; + U64 count; +}; + +//////////////////////////////// +// Time + +#define OS_UNIX_TIME_MAX max_U32 +typedef U32 OS_UnixTime; + +//////////////////////////////// +// Global Unique ID + +typedef struct OS_Guid +{ + U32 data1; + U16 data2; + U16 data3; + U8 data4[8]; +} OS_Guid; +StaticAssert(sizeof(OS_Guid) == 16, os_guid_check); + +//////////////////////////////// +//~ rjf: Thread Types + +typedef void OS_ThreadFunctionType(void *ptr); + +//////////////////////////////// +//~ rjf: Handle Type Functions (Helpers, Implemented Once) + +internal OS_Handle os_handle_zero(void); +internal B32 os_handle_match(OS_Handle a, OS_Handle b); +internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle); +internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list); + +//////////////////////////////// +//~ rjf: System Path Helper (Helper, Implemented Once) + +internal String8 os_string_from_system_path(Arena *arena, OS_SystemPath path); + +//////////////////////////////// +//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) + +internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv); + +//////////////////////////////// +//~ rjf: Process Helpers (Helper, Implemented Once) + +internal void os_relaunch_self(void); + +//////////////////////////////// +//~ rjf: Filesystem Helpers (Helpers, Implemented Once) + +internal String8 os_data_from_file_path(Arena *arena, String8 path); +internal B32 os_write_data_to_file_path(String8 path, String8 data); +internal B32 os_write_data_list_to_file_path(String8 path, String8List list); +internal FileProperties os_properties_from_file_path(String8 path); +internal OS_FileID os_id_from_file_path(String8 path); +internal S64 os_file_id_compare(OS_FileID a, OS_FileID b); +internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range); + +//////////////////////////////// +//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once) + +internal void os_mutex_take(OS_Handle mutex); +internal void os_mutex_drop(OS_Handle mutex); +internal void os_rw_mutex_take_r(OS_Handle rw_mutex); +internal void os_rw_mutex_drop_r(OS_Handle rw_mutex); +internal void os_rw_mutex_take_w(OS_Handle rw_mutex); +internal void os_rw_mutex_drop_w(OS_Handle rw_mutex); +// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout +internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us); +internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us); +internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us); +internal void os_condition_variable_signal(OS_Handle cv); +internal void os_condition_variable_broadcast(OS_Handle cv); + +#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex)) +#define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex)) +#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex)) + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void os_init(int argc, char **argv); + +//////////////////////////////// +//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) + +internal void* os_reserve(U64 size); +internal B32 os_commit(void *ptr, U64 size); +internal void* os_reserve_large(U64 size); +internal B32 os_commit_large(void *ptr, U64 size); +internal void os_decommit(void *ptr, U64 size); +internal void os_release(void *ptr, U64 size); + +internal B32 os_set_large_pages(B32 flag); +internal B32 os_large_pages_enabled(void); +internal U64 os_large_page_size(void); + +internal void* os_alloc_ring_buffer(U64 size, U64 *actual_size_out); +internal void os_free_ring_buffer(void *ring_buffer, U64 actual_size); + +//////////////////////////////// +//~ rjf: @os_hooks System Info (Implemented Per-OS) + +internal String8 os_machine_name(void); +internal U64 os_page_size(void); +internal U64 os_allocation_granularity(void); +internal U64 os_logical_core_count(void); + +//////////////////////////////// +//~ rjf: @os_hooks Process Info (Implemented Per-OS) + +internal String8List os_get_command_line_arguments(void); +internal S32 os_get_pid(void); +internal S32 os_get_tid(void); +internal String8List os_get_environment(void); +internal U64 os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out); + +//////////////////////////////// +//~ rjf: @os_hooks Process Control (Implemented Per-OS) + +internal void os_exit_process(S32 exit_code); + +//////////////////////////////// +//~ rjf: @os_hooks File System (Implemented Per-OS) + +//- rjf: files +internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path); +internal void os_file_close(OS_Handle file); +internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data); +internal void os_file_write(OS_Handle file, Rng1U64 rng, void *data); +internal B32 os_file_set_times(OS_Handle file, DateTime time); +internal FileProperties os_properties_from_file(OS_Handle file); +internal OS_FileID os_id_from_file(OS_Handle file); +internal B32 os_delete_file_at_path(String8 path); +internal B32 os_copy_file_path(String8 dst, String8 src); +internal String8 os_full_path_from_path(Arena *arena, String8 path); +internal B32 os_file_path_exists(String8 path); + +//- rjf: file maps +internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file); +internal void os_file_map_close(OS_Handle map); +internal void * os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range); +internal void os_file_map_view_close(OS_Handle map, void *ptr); + +//- rjf: directory iteration +internal OS_FileIter *os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags); +internal B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out); +internal void os_file_iter_end(OS_FileIter *iter); + +//- rjf: directory creation +internal B32 os_make_directory(String8 path); + +//////////////////////////////// +//~ rjf: @os_hooks Shared Memory (Implemented Per-OS) + +internal OS_Handle os_shared_memory_alloc(U64 size, String8 name); +internal OS_Handle os_shared_memory_open(String8 name); +internal void os_shared_memory_close(OS_Handle handle); +internal void * os_shared_memory_view_open(OS_Handle handle, Rng1U64 range); +internal void os_shared_memory_view_close(OS_Handle handle, void *ptr); + +//////////////////////////////// +//~ rjf: @os_hooks Time (Implemented Per-OS) + +internal OS_UnixTime os_now_unix(void); +internal DateTime os_now_universal_time(void); +internal DateTime os_universal_time_from_local_time(DateTime *local_time); +internal DateTime os_local_time_from_universal_time(DateTime *universal_time); +internal U64 os_now_microseconds(void); +internal void os_sleep_milliseconds(U32 msec); + +//////////////////////////////// +//~ rjf: @os_hooks Child Processes (Implemented Per-OS) + +internal B32 os_launch_process(OS_LaunchOptions *options, OS_Handle *handle_out); +internal B32 os_process_wait(OS_Handle handle, U64 endt_us); +internal void os_process_release_handle(OS_Handle handle); + +//////////////////////////////// +//~ rjf: @os_hooks Threads (Implemented Per-OS) + +internal OS_Handle os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params); +internal void os_release_thread_handle(OS_Handle thread); + +//////////////////////////////// +//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) + +// NOTE(allen): Mutexes are recursive - support counted acquire/release nesting +// on a single thread + +//- rjf: recursive mutexes +internal OS_Handle os_mutex_alloc(void); +internal void os_mutex_release(OS_Handle mutex); +internal void os_mutex_take_(OS_Handle mutex); +internal void os_mutex_drop_(OS_Handle mutex); + +//- rjf: reader/writer mutexes +internal OS_Handle os_rw_mutex_alloc(void); +internal void os_rw_mutex_release(OS_Handle rw_mutex); +internal void os_rw_mutex_take_r_(OS_Handle mutex); +internal void os_rw_mutex_drop_r_(OS_Handle mutex); +internal void os_rw_mutex_take_w_(OS_Handle mutex); +internal void os_rw_mutex_drop_w_(OS_Handle mutex); + +//- rjf: condition variables +internal OS_Handle os_condition_variable_alloc(void); +internal void os_condition_variable_release(OS_Handle cv); +// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout +internal B32 os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us); +internal B32 os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); +internal B32 os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); +internal void os_condition_variable_signal_(OS_Handle cv); +internal void os_condition_variable_broadcast_(OS_Handle cv); + +//- rjf: cross-process semaphores +internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name); +internal void os_semaphore_release(OS_Handle semaphore); +internal OS_Handle os_semaphore_open(String8 name); +internal void os_semaphore_close(OS_Handle semaphore); +internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us); +internal void os_semaphore_drop(OS_Handle semaphore); + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal OS_Handle os_library_open(String8 path); +internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name); +internal void os_library_close(OS_Handle lib); + +//////////////////////////////// +//~ rjf: @os_hooks Safe Calls (Implemented Per-OS) + +internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr); + +//////////////////////////////// +//~ rjf: @os_hooks GUIDs (Implemented Per-OS) + +internal OS_Guid os_make_guid(void); +internal String8 os_string_from_guid(Arena *arena, OS_Guid guid); + +#endif // OS_CORE_H diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c new file mode 100644 index 00000000..24b53022 --- /dev/null +++ b/src/os/core/win32/os_core_win32.c @@ -0,0 +1,1476 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#pragma comment(lib, "user32") +#pragma comment(lib, "winmm") +#pragma comment(lib, "shell32") +#pragma comment(lib, "advapi32") +#pragma comment(lib, "rpcrt4") + +//////////////////////////////// +//~ allen: Definitions For Symbols That Are Sometimes Missing in Older Windows SDKs + +#if !defined(MEM_PRESERVE_PLACEHOLDER) +#define MEM_PRESERVE_PLACEHOLDER 0x2 +#endif +#if !defined(MEM_RESERVE_PLACEHOLDER) +# define MEM_REPLACE_PLACEHOLDER 0x00004000 +#endif +#if !defined(MEM_RESERVE_PLACEHOLDER) +# define MEM_RESERVE_PLACEHOLDER 0x00040000 +#endif + +typedef PVOID W32_VirtualAlloc2_Type(HANDLE Process, + PVOID BaseAddress, + SIZE_T Size, + ULONG AllocationType, + ULONG PageProtection, + void* ExtendedParameters, + ULONG ParameterCount); +typedef PVOID W32_MapViewOfFile3_Type(HANDLE FileMapping, + HANDLE Process, + PVOID BaseAddress, + ULONG64 Offset, + SIZE_T ViewSize, + ULONG AllocationType, + ULONG PageProtection, + void* ExtendedParameters, + ULONG ParameterCount); + +global W32_VirtualAlloc2_Type *w32_VirtualAlloc2_func = 0; +global W32_MapViewOfFile3_Type *w32_MapViewOfFile3_func = 0; + +//////////////////////////////// +//~ rjf: Globals + +global Arena *w32_perm_arena = 0; +global String8List w32_cmd_line_args = {0}; +global String8List w32_environment = {0}; +global CRITICAL_SECTION w32_mutex = {0}; +global String8 w32_initial_path = {0}; +global U64 w32_microsecond_resolution = 0; +global W32_Entity *w32_entity_free = 0; +global B32 w32_large_pages_enabled = 0; + +//////////////////////////////// +//~ rjf: Helpers + +//- rjf: files + +internal FilePropertyFlags +w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes){ + FilePropertyFlags flags = 0; + if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){ + flags |= FilePropertyFlag_IsFolder; + } + return(flags); +} + +internal void +w32_file_properties_from_attributes(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes){ + properties->size = Compose64Bit(attributes->nFileSizeHigh, attributes->nFileSizeLow); + w32_dense_time_from_file_time(&properties->created, &attributes->ftCreationTime); + w32_dense_time_from_file_time(&properties->modified, &attributes->ftLastWriteTime); + properties->flags = w32_file_property_flags_from_dwFileAttributes(attributes->dwFileAttributes); +} + +//- rjf: time + +internal void +w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in){ + out->year = in->wYear; + out->mon = in->wMonth - 1; + out->wday = in->wDayOfWeek; + out->day = in->wDay; + out->hour = in->wHour; + out->min = in->wMinute; + out->sec = in->wSecond; + out->msec = in->wMilliseconds; +} + +internal void +w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in){ + out->wYear = (WORD)(in->year); + out->wMonth = in->mon + 1; + out->wDay = in->day; + out->wHour = in->hour; + out->wMinute = in->min; + out->wSecond = in->sec; + out->wMilliseconds = in->msec; +} + +internal void +w32_dense_time_from_file_time(DenseTime *out, FILETIME *in){ + SYSTEMTIME systime = {0}; + FileTimeToSystemTime(in, &systime); + DateTime date_time = {0}; + w32_date_time_from_system_time(&date_time, &systime); + *out = dense_time_from_date_time(date_time); +} + +internal U32 +w32_sleep_ms_from_endt_us(U64 endt_us){ + U32 sleep_ms = 0; + if (endt_us == max_U64){ + sleep_ms = INFINITE; + } + else{ + U64 begint = os_now_microseconds(); + if (begint < endt_us){ + U64 sleep_us = endt_us - begint; + sleep_ms = (U32)((sleep_us + 999)/1000); + } + } + return(sleep_ms); +} + +//- rjf: entities + +internal W32_Entity* +w32_alloc_entity(W32_EntityKind kind){ + EnterCriticalSection(&w32_mutex); + W32_Entity *result = w32_entity_free; + if(result != 0) + { + SLLStackPop(w32_entity_free); + } + else + { + result = push_array_no_zero(w32_perm_arena, W32_Entity, 1); + } + MemoryZeroStruct(result); + Assert(result != 0); + LeaveCriticalSection(&w32_mutex); + MemoryZeroStruct(result); + result->kind = kind; + return(result); +} + +internal void +w32_free_entity(W32_Entity *entity){ + entity->kind = W32_EntityKind_Null; + EnterCriticalSection(&w32_mutex); + SLLStackPush(w32_entity_free, entity); + LeaveCriticalSection(&w32_mutex); +} + +//- rjf: threads + +internal DWORD +w32_thread_base(void *ptr){ + W32_Entity *entity = (W32_Entity*)ptr; + OS_ThreadFunctionType *func = entity->thread.func; + void *thread_ptr = entity->thread.ptr; + + func(thread_ptr); + + // remove my bit + LONG result = InterlockedAnd((LONG*)&entity->reference_mask, ~0x2); + // if the other bit is also gone, free entity + if ((result & 0x1) == 0){ + w32_free_entity(entity); + } + return(0); +} + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void +os_init(int argc, char **argv){ + // Load Fancy Memory Functions + { + HMODULE module = LoadLibraryA("kernel32.dll"); + if (module != 0){ + w32_VirtualAlloc2_func = (W32_VirtualAlloc2_Type*)GetProcAddress(module, "VirtualAlloc2"); + w32_MapViewOfFile3_func = (W32_MapViewOfFile3_Type*)GetProcAddress(module, "MapViewOfFile3"); + FreeLibrary(module); + } + } + + // Thread handshake + InitializeCriticalSection(&w32_mutex); + + // Permanent memory allocator for this layer + w32_perm_arena = arena_alloc(); + + // Init microsecond counter resolution + LARGE_INTEGER large_int_resolution; + if (QueryPerformanceFrequency(&large_int_resolution)){ + w32_microsecond_resolution = large_int_resolution.QuadPart; + } + else{ + w32_microsecond_resolution = 1; + } + + // Setup initial path + w32_initial_path = os_string_from_system_path(w32_perm_arena, OS_SystemPath_Current); + + // Setup command line arguments + w32_cmd_line_args = os_string_list_from_argcv(w32_perm_arena, argc, argv); + + // rjf: setup environment variables + { + CHAR *this_proc_env = GetEnvironmentStrings(); + U64 start_idx = 0; + for(U64 idx = 0;; idx += 1) + { + if(this_proc_env[idx] == 0) + { + if(start_idx == idx) + { + break; + } + else + { + String8 string = str8((U8 *)this_proc_env + start_idx, idx - start_idx); + str8_list_push(w32_perm_arena, &w32_environment, string); + start_idx = idx+1; + } + } + } + } +} + +//////////////////////////////// +//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) + +internal void* +os_reserve(U64 size){ + void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); + return(result); +} + +internal B32 +os_commit(void *ptr, U64 size){ + B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); + return(result); +} + +internal void* +os_reserve_large(U64 size){ + // we commit on reserve because windows + void *result = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE); + return(result); +} + +internal B32 +os_commit_large(void *ptr, U64 size){ + return 1; +} + +internal void +os_decommit(void *ptr, U64 size){ + VirtualFree(ptr, size, MEM_DECOMMIT); +} + +internal void +os_release(void *ptr, U64 size){ + // NOTE(rjf): size not used - not necessary on Windows, but necessary for other OSes. + VirtualFree(ptr, 0, MEM_RELEASE); +} + +internal B32 +os_set_large_pages(B32 flag) +{ + B32 is_ok = 0; + HANDLE token; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { + LUID luid; + if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) { + TOKEN_PRIVILEGES priv; + priv.PrivilegeCount = 1; + priv.Privileges[0].Luid = luid; + priv.Privileges[0].Attributes = flag ? SE_PRIVILEGE_ENABLED: 0; + if (AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0)) { + w32_large_pages_enabled = flag; + is_ok = 1; + } + } + CloseHandle(token); + } + return is_ok; +} + +internal B32 +os_large_pages_enabled(void) +{ + return w32_large_pages_enabled; +} + +internal U64 +os_large_page_size(void) +{ + U64 page_size = GetLargePageMinimum(); + return page_size; +} + +internal void* +os_alloc_ring_buffer(U64 size, U64 *actual_size_out){ + void *result = 0; + +#define W32_MAX_RING_SIZE GB(1) + + Assert(IsPow2(size)); + Assert(size <= W32_MAX_RING_SIZE); + + // get allocation granularity + SYSTEM_INFO info = {0}; + GetSystemInfo(&info); + Assert(IsPow2(info.dwAllocationGranularity)); + + // align size + U64 aligned_size = AlignPow2(size, (U64)(info.dwAllocationGranularity)); + + // split size + U32 lo_size = (U32)(aligned_size & 0xFFFFFFFF); + U32 hi_size = (U32)(aligned_size >> 32); + + // create pagefile-backed section + HANDLE section = CreateFileMappingA(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, hi_size, lo_size, 0); + + if (section != 0){ + if (w32_VirtualAlloc2_func != 0 && w32_MapViewOfFile3_func != 0){ + void *ptr1 = 0; + void *ptr2 = 0; + void *view1 = 0; + void *view2 = 0; + + // reserve virtual space placeholder + ptr1 = w32_VirtualAlloc2_func(0, 0, aligned_size*2, + MEM_RESERVE|MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, 0, 0); + if (ptr1 != 0){ + + // split off the first part of placeholder + VirtualFree(ptr1, aligned_size, MEM_RELEASE|MEM_PRESERVE_PLACEHOLDER); + ptr2 = ((U8*)ptr1 + aligned_size); + + // create views + view1 = w32_MapViewOfFile3_func(section, 0, ptr1, 0, aligned_size, + MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, 0, 0); + view2 = w32_MapViewOfFile3_func(section, 0, ptr2, 0, aligned_size, + MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, 0, 0); + if (view1 != 0 && view2 != 0){ + result = ptr1; + *actual_size_out = aligned_size; + } + } + + // cleanup + if (result == 0){ + if (ptr1 != 0){ + VirtualFree(ptr1, 0, MEM_RELEASE); + } + if (ptr2 != 0){ + VirtualFree(ptr2, 0, MEM_RELEASE); + } + if (view1 != 0){ + UnmapViewOfFileEx(view1, 0); + } + if (view2 != 0){ + UnmapViewOfFileEx(view2, 0); + } + } + } + + // no fancy memory functions available + else{ + for (U64 addr = GB(16); + addr < GB(272); + addr += W32_MAX_RING_SIZE){ + + // create the first view + void *view1 = MapViewOfFileEx(section, FILE_MAP_ALL_ACCESS, 0, 0, aligned_size, (void*)addr); + if (view1 != 0){ + + // create the second view + void *view2 = MapViewOfFileEx(section, FILE_MAP_ALL_ACCESS, 0, 0, aligned_size, (U8*)view1 + aligned_size); + + // on success make this the result + if (view2 != 0){ + result = view1; + *actual_size_out = aligned_size; + break; + } + + // cleanup view1 on failure + UnmapViewOfFile(view1); + } + } + } + } + + // cleanup + if (section != 0){ + CloseHandle(section); + } + + return(result); +} + +internal void +os_free_ring_buffer(void *ring_buffer, U64 actual_size){ + void *ptr1 = ring_buffer; + void *ptr2 = ((U8*)ptr1 + actual_size); + VirtualFree(ptr1, 0, MEM_RELEASE); + VirtualFree(ptr2, 0, MEM_RELEASE); + UnmapViewOfFileEx(ptr1, 0); + UnmapViewOfFileEx(ptr2, 0); +} + +//////////////////////////////// +//~ rjf: @os_hooks System Info (Implemented Per-OS) + +internal String8 +os_machine_name(void){ + local_persist U8 buffer[MAX_COMPUTERNAME_LENGTH + 1]; + local_persist String8 string = {0}; + local_persist B32 first = 1; + if (first){ + first = 0; + DWORD size = MAX_COMPUTERNAME_LENGTH + 1; + if (GetComputerNameA((char*)buffer, &size)){ + string = str8(buffer, size); + } + } + return(string); +} + +internal U64 +os_page_size(void){ + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + return(sysinfo.dwPageSize); +} + +internal U64 +os_allocation_granularity(void) +{ + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + return sysinfo.dwAllocationGranularity; +} + +internal U64 +os_logical_core_count(void) +{ + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Info (Implemented Per-OS) + +internal String8List +os_get_command_line_arguments(void) +{ + return w32_cmd_line_args; +} + +internal S32 +os_get_pid(void){ + DWORD id = GetCurrentProcessId(); + return((S32)id); +} + +internal S32 +os_get_tid(void){ + DWORD id = GetCurrentThreadId(); + return((S32)id); +} + +internal String8List +os_get_environment(void) +{ + return w32_environment; +} + +internal U64 +os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out){ + Temp scratch = scratch_begin(&arena, 1); + + U64 result = 0; + + switch (path){ + case OS_SystemPath_Binary: + { + local_persist B32 first = 1; + local_persist String8 name = {0}; + + // TODO(allen): let's just pre-compute this at init and skip the complexity + EnterCriticalSection(&w32_mutex); + if (first){ + first = 0; + DWORD size = KB(32); + U16 *buffer = push_array_no_zero(scratch.arena, U16, size); + DWORD length = GetModuleFileNameW(0, (WCHAR*)buffer, size); + String8 name8 = str8_from_16(scratch.arena, str16(buffer, length)); + String8 name_chopped = str8_chop_last_slash(name8); + name = push_str8_copy(w32_perm_arena, name_chopped); + } + LeaveCriticalSection(&w32_mutex); + + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_Initial: + { + Assert(w32_initial_path.str != 0); + result = 1; + str8_list_push(arena, out, w32_initial_path); + }break; + + case OS_SystemPath_Current: + { + DWORD length = GetCurrentDirectoryW(0, 0); + U16 *memory = push_array_no_zero(scratch.arena, U16, length + 1); + length = GetCurrentDirectoryW(length + 1, (WCHAR*)memory); + String8 name = str8_from_16(arena, str16(memory, length)); + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_UserProgramData: + { + local_persist B32 first = 1; + local_persist String8 name = {0}; + if (first){ + first = 0; + U64 size = KB(32); + U16 *buffer = push_array_no_zero(scratch.arena, U16, size); + if (SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, (WCHAR*)buffer))){ + name = str8_from_16(scratch.arena, str16_cstring(buffer)); + EnterCriticalSection(&w32_mutex); + U8 *buffer8 = push_array_no_zero(w32_perm_arena, U8, name.size); + LeaveCriticalSection(&w32_mutex); + MemoryCopy(buffer8, name.str, name.size); + name.str = buffer8; + } + } + result = 1; + str8_list_push(arena, out, name); + }break; + + case OS_SystemPath_ModuleLoad: + { + U64 og_count = out->node_count; + + { + UINT cap = GetSystemDirectoryW(0, 0); + if (cap > 0){ + U16 *buffer = push_array_no_zero(scratch.arena, U16, cap); + UINT size = GetSystemDirectoryW((WCHAR*)buffer, cap); + if (size > 0){ + str8_list_push(arena, out, str8_from_16(arena, str16(buffer, size))); + } + } + } + + { + UINT cap = GetWindowsDirectoryW(0, 0); + if (cap > 0){ + U16 *buffer = push_array_no_zero(scratch.arena, U16, cap); + UINT size = GetWindowsDirectoryW((WCHAR*)buffer, cap); + if (size > 0){ + str8_list_push(arena, out, str8_from_16(arena, str16(buffer, size))); + } + } + } + + result = out->node_count - og_count; + }break; + } + + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Process Control (Implemented Per-OS) + +internal void +os_exit_process(S32 exit_code){ + ExitProcess(exit_code); +} + +//////////////////////////////// +//~ rjf: @os_hooks File System (Implemented Per-OS) + +//- rjf: files + +internal OS_Handle +os_file_open(OS_AccessFlags flags, String8 path) +{ + OS_Handle result = {0}; + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + DWORD access_flags = 0; + DWORD share_mode = 0; + DWORD creation_disposition = OPEN_EXISTING; + if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} + if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} + if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} + if(flags & OS_AccessFlag_Shared) {share_mode = (!!(flags & OS_AccessFlag_Write)*FILE_SHARE_WRITE)|FILE_SHARE_READ;} + if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} + HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); + if(file != INVALID_HANDLE_VALUE) + { + result.u64[0] = (U64)file; + } + scratch_end(scratch); + return result; +} + +internal void +os_file_close(OS_Handle file) +{ + if(os_handle_match(file, os_handle_zero())) { return; } + HANDLE handle = (HANDLE)file.u64[0]; + CloseHandle(handle); +} + +internal U64 +os_file_read(OS_Handle file, Rng1U64 rng, void *out_data) +{ + if(os_handle_match(file, os_handle_zero())) { return 0; } + HANDLE handle = (HANDLE)file.u64[0]; + + // rjf: clamp range by file size + U64 size = 0; + GetFileSizeEx(handle, (LARGE_INTEGER *)&size); + Rng1U64 rng_clamped = r1u64(ClampTop(rng.min, size), ClampTop(rng.max, size)); + U64 total_read_size = 0; + + // rjf: read loop + { + U64 to_read = dim_1u64(rng_clamped); + for(U64 off = rng.min; total_read_size < to_read;) + { + U64 amt64 = to_read - total_read_size; + U32 amt32 = u32_from_u64_saturate(amt64); + DWORD read_size = 0; + OVERLAPPED overlapped = {0}; + overlapped.Offset = (off&0x00000000ffffffffull); + overlapped.OffsetHigh = (off&0xffffffff00000000ull) >> 32; + ReadFile(handle, (U8 *)out_data + total_read_size, amt32, &read_size, &overlapped); + off += read_size; + total_read_size += read_size; + if(read_size != amt32) + { + break; + } + } + } + + return total_read_size; +} + +internal void +os_file_write(OS_Handle file, Rng1U64 rng, void *data) +{ + if(os_handle_match(file, os_handle_zero())) { return; } + HANDLE win_handle = (HANDLE)file.u64[0]; + U64 src_off = 0; + U64 dst_off = rng.min; + U64 bytes_to_write_total = rng.max-rng.min; + for(;src_off < bytes_to_write_total;) + { + void *bytes_src = (void *)((U8 *)data + src_off); + U64 bytes_to_write_64 = (bytes_to_write_total-src_off); + U32 bytes_to_write_32 = u32_from_u64_saturate(bytes_to_write_64); + U32 bytes_written = 0; + OVERLAPPED overlapped = {0}; + overlapped.Offset = (dst_off&0x00000000ffffffffull); + overlapped.OffsetHigh = (dst_off&0xffffffff00000000ull) >> 32; + BOOL success = WriteFile(win_handle, bytes_src, bytes_to_write_32, (DWORD *)&bytes_written, &overlapped); + if(success == 0) + { + break; + } + src_off += bytes_written; + dst_off += bytes_written; + } +} + +internal B32 +os_file_set_times(OS_Handle file, DateTime time) +{ + if(os_handle_match(file, os_handle_zero())) { return 0; } + B32 result = 0; + HANDLE handle = (HANDLE)file.u64[0]; + SYSTEMTIME system_time = {0}; + w32_system_time_from_date_time(&system_time, &time); + FILETIME file_time = {0}; + result = (SystemTimeToFileTime(&system_time, &file_time) && + SetFileTime(handle, &file_time, &file_time, &file_time)); + return result; +} + +internal FileProperties +os_properties_from_file(OS_Handle file) +{ + if(os_handle_match(file, os_handle_zero())) { FileProperties r = {0}; return r; } + FileProperties props = {0}; + HANDLE handle = (HANDLE)file.u64[0]; + BY_HANDLE_FILE_INFORMATION info; + BOOL info_good = GetFileInformationByHandle(handle, &info); + if(info_good) + { + U32 size_lo = info.nFileSizeLow; + U32 size_hi = info.nFileSizeHigh; + props.size = (U64)size_lo | (((U64)size_hi)<<32); + w32_dense_time_from_file_time(&props.modified, &info.ftLastWriteTime); + w32_dense_time_from_file_time(&props.created, &info.ftCreationTime); + props.flags = w32_file_property_flags_from_dwFileAttributes(info.dwFileAttributes); + } + return props; +} + +internal OS_FileID +os_id_from_file(OS_Handle file) +{ + if(os_handle_match(file, os_handle_zero())) { OS_FileID r = {0}; return r; } + OS_FileID result = {0}; + HANDLE handle = (HANDLE)file.u64[0]; + BY_HANDLE_FILE_INFORMATION info; + BOOL is_ok = GetFileInformationByHandle(handle, &info); + if(is_ok) + { + result.v[0] = info.dwVolumeSerialNumber; + result.v[1] = info.nFileIndexLow; + result.v[2] = info.nFileIndexHigh; + } + return result; +} + +internal B32 +os_delete_file_at_path(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + B32 result = DeleteFileW((WCHAR*)path16.str); + scratch_end(scratch); + return result; +} + +internal B32 +os_copy_file_path(String8 dst, String8 src) +{ + Temp scratch = scratch_begin(0, 0); + String16 dst16 = str16_from_8(scratch.arena, dst); + String16 src16 = str16_from_8(scratch.arena, src); + B32 result = CopyFileW((WCHAR*)src16.str, (WCHAR*)dst16.str, 0); + scratch_end(scratch); + return result; +} + +internal String8 +os_full_path_from_path(Arena *arena, String8 path) +{ + Temp scratch = scratch_begin(&arena, 1); + DWORD buffer_size = MAX_PATH + 1; + U16 *buffer = push_array_no_zero(scratch.arena, U16, buffer_size); + String16 path16 = str16_from_8(scratch.arena, path); + DWORD path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, (WCHAR*)buffer, NULL); + String8 full_path = str8_from_16(arena, str16(buffer, path16_size)); + scratch_end(scratch); + return full_path; +} + +internal B32 +os_file_path_exists(String8 path) +{ + Temp scratch = scratch_begin(0,0); + String16 path16 = str16_from_8(scratch.arena, path); + DWORD attributes = GetFileAttributesW((WCHAR *)path16.str); + B32 exists = (attributes != INVALID_FILE_ATTRIBUTES) && !!(~attributes & FILE_ATTRIBUTE_DIRECTORY); + scratch_end(scratch); + return exists; +} + +//- rjf: file maps + +internal OS_Handle +os_file_map_open(OS_AccessFlags flags, OS_Handle file) +{ + OS_Handle map = {0}; + { + HANDLE file_handle = (HANDLE)file.u64[0]; + DWORD protect_flags = 0; + { + switch(flags) + { + default:{}break; + case OS_AccessFlag_Read: + {protect_flags = PAGE_READONLY;}break; + case OS_AccessFlag_Write: + case OS_AccessFlag_Read|OS_AccessFlag_Write: + {protect_flags = PAGE_READWRITE;}break; + case OS_AccessFlag_Execute: + case OS_AccessFlag_Read|OS_AccessFlag_Execute: + {protect_flags = PAGE_EXECUTE_READ;}break; + case OS_AccessFlag_Execute|OS_AccessFlag_Write|OS_AccessFlag_Read: + case OS_AccessFlag_Execute|OS_AccessFlag_Write: + {protect_flags = PAGE_EXECUTE_READWRITE;}break; + } + } + HANDLE map_handle = CreateFileMappingA(file_handle, 0, protect_flags, 0, 0, 0); + map.u64[0] = (U64)map_handle; + } + return map; +} + +internal void +os_file_map_close(OS_Handle map) +{ + HANDLE handle = (HANDLE)map.u64[0]; + CloseHandle(handle); +} + +internal void * +os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) +{ + HANDLE handle = (HANDLE)map.u64[0]; + U32 off_lo = (U32)((range.min&0x00000000ffffffffull)>>0); + U32 off_hi = (U32)((range.min&0xffffffff00000000ull)>>32); + U64 size = dim_1u64(range); + DWORD access_flags = 0; + { + switch(flags) + { + default:{}break; + case OS_AccessFlag_Read: + { + access_flags = FILE_MAP_READ; + }break; + case OS_AccessFlag_Write: + { + access_flags = FILE_MAP_WRITE; + }break; + case OS_AccessFlag_Read|OS_AccessFlag_Write: + { + access_flags = FILE_MAP_ALL_ACCESS; + }break; + case OS_AccessFlag_Execute: + case OS_AccessFlag_Read|OS_AccessFlag_Execute: + case OS_AccessFlag_Write|OS_AccessFlag_Execute: + case OS_AccessFlag_Read|OS_AccessFlag_Write|OS_AccessFlag_Execute: + { + access_flags = FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE; + }break; + } + } + void *result = MapViewOfFile(handle, access_flags, off_hi, off_lo, size); + return result; +} + +internal void +os_file_map_view_close(OS_Handle map, void *ptr) +{ + UnmapViewOfFile(ptr); +} + +//- rjf: directory iteration + +internal OS_FileIter * +os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 path_with_wildcard = push_str8_cat(scratch.arena, path, str8_lit("\\*")); + String16 path16 = str16_from_8(scratch.arena, path_with_wildcard); + OS_FileIter *iter = push_array(arena, OS_FileIter, 1); + iter->flags = flags; + W32_FileIter *w32_iter = (W32_FileIter*)iter->memory; + w32_iter->handle = FindFirstFileW((WCHAR*)path16.str, &w32_iter->find_data); + scratch_end(scratch); + return iter; +} + +internal B32 +os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) +{ + B32 result = 0; + OS_FileIterFlags flags = iter->flags; + W32_FileIter *w32_iter = (W32_FileIter*)iter->memory; + if (!(flags & OS_FileIterFlag_Done) && w32_iter->handle != INVALID_HANDLE_VALUE) + { + do + { + // check is usable + B32 usable_file = 1; + + WCHAR *file_name = w32_iter->find_data.cFileName; + DWORD attributes = w32_iter->find_data.dwFileAttributes; + if (file_name[0] == '.'){ + if (flags & OS_FileIterFlag_SkipHiddenFiles){ + usable_file = 0; + } + else if (file_name[1] == 0){ + usable_file = 0; + } + else if (file_name[1] == '.' && file_name[2] == 0){ + usable_file = 0; + } + } + if (attributes & FILE_ATTRIBUTE_DIRECTORY){ + if (flags & OS_FileIterFlag_SkipFolders){ + usable_file = 0; + } + } + else{ + if (flags & OS_FileIterFlag_SkipFiles){ + usable_file = 0; + } + } + + // emit if usable + if (usable_file){ + info_out->name = str8_from_16(arena, str16_cstring((U16*)file_name)); + info_out->props.size = (U64)w32_iter->find_data.nFileSizeLow | (((U64)w32_iter->find_data.nFileSizeHigh)<<32); + w32_dense_time_from_file_time(&info_out->props.created, &w32_iter->find_data.ftCreationTime); + w32_dense_time_from_file_time(&info_out->props.modified, &w32_iter->find_data.ftLastWriteTime); + info_out->props.flags = w32_file_property_flags_from_dwFileAttributes(attributes); + result = 1; + if (!FindNextFileW(w32_iter->handle, &w32_iter->find_data)){ + iter->flags |= OS_FileIterFlag_Done; + } + break; + } + }while(FindNextFileW(w32_iter->handle, &w32_iter->find_data)); + + if (!result){ + iter->flags |= OS_FileIterFlag_Done; + } + } + return result; +} + +internal void +os_file_iter_end(OS_FileIter *iter) +{ + W32_FileIter *w32_iter = (W32_FileIter*)iter->memory; + FindClose(w32_iter->handle); +} + +//- rjf: directory creation + +internal B32 +os_make_directory(String8 path) +{ + B32 result = 0; + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, path); + WIN32_FILE_ATTRIBUTE_DATA attributes = {0}; + GetFileAttributesExW((WCHAR*)name16.str, GetFileExInfoStandard, &attributes); + if(attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + result = 1; + } + else if(CreateDirectoryW((WCHAR*)name16.str, 0)) + { + result = 1; + } + scratch_end(scratch); + return(result); +} + +//////////////////////////////// +//~ rjf: @os_hooks Shared Memory (Implemented Per-OS) + +internal OS_Handle +os_shared_memory_alloc(U64 size, String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE file = CreateFileMappingW(INVALID_HANDLE_VALUE, + 0, + PAGE_READWRITE, + (U32)((size & 0xffffffff00000000) >> 32), + (U32)((size & 0x00000000ffffffff)), + (WCHAR *)name16.str); + OS_Handle result = {(U64)file}; + scratch_end(scratch); + return result; +} + +internal OS_Handle +os_shared_memory_open(String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE file = OpenFileMappingW(FILE_MAP_ALL_ACCESS, 0, (WCHAR *)name16.str); + OS_Handle result = {(U64)file}; + scratch_end(scratch); + return result; +} + +internal void +os_shared_memory_close(OS_Handle handle) +{ + HANDLE file = (HANDLE)(handle.u64[0]); + CloseHandle(file); +} + +internal void * +os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) +{ + HANDLE file = (HANDLE)(handle.u64[0]); + U64 offset = range.min; + U64 size = range.max-range.min; + void *ptr = MapViewOfFile(file, FILE_MAP_ALL_ACCESS, + (U32)((offset & 0xffffffff00000000) >> 32), + (U32)((offset & 0x00000000ffffffff)), + size); + return ptr; +} + +internal void +os_shared_memory_view_close(OS_Handle handle, void *ptr) +{ + UnmapViewOfFile(ptr); +} + +//////////////////////////////// +//~ rjf: @os_hooks Time (Implemented Per-OS) + +internal OS_UnixTime +os_now_unix(void) +{ + FILETIME file_time; + GetSystemTimeAsFileTime(&file_time); + + U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime; + U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000); + + Assert(unix_time64 <= OS_UNIX_TIME_MAX); + OS_UnixTime unix_time32 = (OS_UnixTime)unix_time64; + + return unix_time32; +} + +internal DateTime +os_now_universal_time(void){ + SYSTEMTIME systime = {0}; + GetSystemTime(&systime); + DateTime result = {0}; + w32_date_time_from_system_time(&result, &systime); + return(result); +} + +internal DateTime +os_universal_time_from_local_time(DateTime *date_time){ + SYSTEMTIME systime = {0}; + w32_system_time_from_date_time(&systime, date_time); + FILETIME ftime = {0}; + SystemTimeToFileTime(&systime, &ftime); + FILETIME ftime_local = {0}; + LocalFileTimeToFileTime(&ftime, &ftime_local); + FileTimeToSystemTime(&ftime_local, &systime); + DateTime result = {0}; + w32_date_time_from_system_time(&result, &systime); + return(result); +} + +internal DateTime +os_local_time_from_universal_time(DateTime *date_time){ + SYSTEMTIME systime = {0}; + w32_system_time_from_date_time(&systime, date_time); + FILETIME ftime = {0}; + SystemTimeToFileTime(&systime, &ftime); + FILETIME ftime_local = {0}; + FileTimeToLocalFileTime(&ftime, &ftime_local); + FileTimeToSystemTime(&ftime_local, &systime); + DateTime result = {0}; + w32_date_time_from_system_time(&result, &systime); + return(result); +} + +internal U64 +os_now_microseconds(void){ + U64 result = 0; + LARGE_INTEGER large_int_counter; + if (QueryPerformanceCounter(&large_int_counter)){ + result = (large_int_counter.QuadPart*Million(1))/w32_microsecond_resolution; + } + return(result); +} + +internal void +os_sleep_milliseconds(U32 msec){ + Sleep(msec); +} + +//////////////////////////////// +//~ rjf: @os_hooks Child Processes (Implemented Per-OS) + +internal B32 +os_launch_process(OS_LaunchOptions *options, OS_Handle *handle_out){ + B32 result = 0; + Temp scratch = scratch_begin(0, 0); + + StringJoin join_params = {0}; + join_params.pre = str8_lit("\""); + join_params.sep = str8_lit("\" \""); + join_params.post = str8_lit("\""); + String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); + + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + B32 use_null_env_arg = 0; + String8List all_opts = options->env; + if(options->inherit_env != 0) + { + if(all_opts.node_count != 0) + { + MemoryZeroStruct(&all_opts); + for(String8Node *n = options->env.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for(String8Node *n = w32_environment.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + else + { + use_null_env_arg = 1; + } + } + String8 env = {0}; + if(use_null_env_arg == 0) + { + env = str8_list_join(scratch.arena, &all_opts, &join_params2); + } + + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = {0}; + if(use_null_env_arg == 0) + { + env16 = str16_from_8(scratch.arena, env); + } + + DWORD creation_flags = 0; + if(options->consoleless) + { + creation_flags |= CREATE_NO_WINDOW; + } + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, creation_flags, use_null_env_arg ? 0 : (WCHAR*)env16.str, (WCHAR*)dir16.str, + &startup_info, &process_info)){ + if (handle_out == 0){ + CloseHandle(process_info.hProcess); + } + CloseHandle(process_info.hThread); + + if (handle_out != 0){ + OS_Handle handle_result = {(U64)process_info.hProcess}; + *handle_out = handle_result; + } + result = 1; + } + + scratch_end(scratch); + return(result); +} + +internal B32 +os_process_wait(OS_Handle handle, U64 endt_us){ + HANDLE process = (HANDLE)(handle.u64[0]); + DWORD sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + DWORD result = WaitForSingleObject(process, sleep_ms); + return (result == WAIT_OBJECT_0); +} + +internal void +os_process_release_handle(OS_Handle handle){ + HANDLE process = (HANDLE)(handle.u64[0]); + CloseHandle(process); +} + +//////////////////////////////// +//~ rjf: @os_hooks Threads (Implemented Per-OS) + +internal OS_Handle +os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_Thread); + entity->reference_mask = 0x3; + entity->thread.func = func; + entity->thread.ptr = ptr; + entity->thread.handle = CreateThread(0, 0, w32_thread_base, entity, 0, &entity->thread.tid); + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_release_thread_handle(OS_Handle thread){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(thread.u64[0]); + // remove my bit + LONG result = InterlockedAnd((LONG*)&entity->reference_mask, ~0x1); + // if the other bit is also gone, free entity + if ((result & 0x2) == 0){ + w32_free_entity(entity); + } +} + +//////////////////////////////// +//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) + +//- rjf: mutexes + +internal OS_Handle +os_mutex_alloc(void){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_Mutex); + InitializeCriticalSection(&entity->mutex); + + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_mutex_release(OS_Handle mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + w32_free_entity(entity); +} + +internal void +os_mutex_take_(OS_Handle mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + EnterCriticalSection(&entity->mutex); +} + +internal void +os_mutex_drop_(OS_Handle mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + LeaveCriticalSection(&entity->mutex); +} + +//- rjf: reader/writer mutexes + +internal OS_Handle +os_rw_mutex_alloc(void){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_RWMutex); + InitializeSRWLock(&entity->rw_mutex); + + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_rw_mutex_release(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + w32_free_entity(entity); +} + +internal void +os_rw_mutex_take_r_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + AcquireSRWLockShared(&entity->rw_mutex); +} + +internal void +os_rw_mutex_drop_r_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + ReleaseSRWLockShared(&entity->rw_mutex); +} + +internal void +os_rw_mutex_take_w_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + AcquireSRWLockExclusive(&entity->rw_mutex); +} + +internal void +os_rw_mutex_drop_w_(OS_Handle rw_mutex){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + ReleaseSRWLockExclusive(&entity->rw_mutex); +} + +//- rjf: condition variables + +internal OS_Handle +os_condition_variable_alloc(void){ + W32_Entity *entity = w32_alloc_entity(W32_EntityKind_ConditionVariable); + InitializeConditionVariable(&entity->cv); + OS_Handle result = {IntFromPtr(entity)}; + return(result); +} + +internal void +os_condition_variable_release(OS_Handle cv){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + w32_free_entity(entity); +} + +internal B32 +os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us){ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + W32_Entity *mutex_entity = (W32_Entity*)PtrFromInt(mutex.u64[0]); + result = SleepConditionVariableCS(&entity->cv, &mutex_entity->mutex, sleep_ms); + } + return(result); +} + +internal B32 +os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + W32_Entity *mutex_entity = (W32_Entity*)PtrFromInt(mutex_rw.u64[0]); + result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, + CONDITION_VARIABLE_LOCKMODE_SHARED); + } + return(result); +} + +internal B32 +os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + W32_Entity *mutex_entity = (W32_Entity*)PtrFromInt(mutex_rw.u64[0]); + result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, 0); + } + return(result); +} + +internal void +os_condition_variable_signal_(OS_Handle cv){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + WakeConditionVariable(&entity->cv); +} + +internal void +os_condition_variable_broadcast_(OS_Handle cv){ + W32_Entity *entity = (W32_Entity*)PtrFromInt(cv.u64[0]); + WakeAllConditionVariable(&entity->cv); +} + +//- rjf: cross-process semaphores + +internal OS_Handle +os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE handle = CreateSemaphoreW(0, initial_count, max_count, (WCHAR *)name16.str); + OS_Handle result = {(U64)handle}; + scratch_end(scratch); + return result; +} + +internal void +os_semaphore_release(OS_Handle semaphore) +{ + HANDLE handle = (HANDLE)semaphore.u64[0]; + CloseHandle(handle); +} + +internal OS_Handle +os_semaphore_open(String8 name) +{ + Temp scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE handle = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS , 0, (WCHAR *)name16.str); + OS_Handle result = {(U64)handle}; + scratch_end(scratch); + return result; +} + +internal void +os_semaphore_close(OS_Handle semaphore) +{ + HANDLE handle = (HANDLE)semaphore.u64[0]; + CloseHandle(handle); +} + +internal B32 +os_semaphore_take(OS_Handle semaphore, U64 endt_us) +{ + U32 sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + HANDLE handle = (HANDLE)semaphore.u64[0]; + DWORD wait_result = WaitForSingleObject(handle, sleep_ms); + B32 result = (wait_result == WAIT_OBJECT_0); + return result; +} + +internal void +os_semaphore_drop(OS_Handle semaphore) +{ + HANDLE handle = (HANDLE)semaphore.u64[0]; + ReleaseSemaphore(handle, 1, 0); +} + +//////////////////////////////// +//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) + +internal OS_Handle +os_library_open(String8 path){ + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + HMODULE mod = LoadLibraryW((LPCWSTR)path16.str); + OS_Handle result = { (U64)mod }; + scratch_end(scratch); + return(result); +} + +internal VoidProc* +os_library_load_proc(OS_Handle lib, String8 name){ + Temp scratch = scratch_begin(0, 0); + HMODULE mod = (HMODULE)lib.u64[0]; + name = push_str8_copy(scratch.arena, name); + VoidProc *result = (VoidProc*)GetProcAddress(mod, (LPCSTR)name.str); + scratch_end(scratch); + return(result); +} + +internal void +os_library_close(OS_Handle lib){ + HMODULE mod = (HMODULE)lib.u64[0]; + FreeLibrary(mod); +} + +//////////////////////////////// +//~ rjf: @os_hooks Safe Calls (Implemented Per-OS) + +internal void +os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr){ + __try{ + func(ptr); + } + __except (EXCEPTION_EXECUTE_HANDLER){ + if (fail_handler != 0){ + fail_handler(ptr); + } + ExitProcess(1); + } +} + +//////////////////////////////// +//~ rjf: @os_hooks GUIDs (Implemented Per-OS) + +internal OS_Guid +os_make_guid(void) +{ + OS_Guid result; MemoryZeroStruct(&result); + UUID uuid; + RPC_STATUS rpc_status = UuidCreate(&uuid); + if (rpc_status == RPC_S_OK) { + result.data1 = uuid.Data1; + result.data2 = uuid.Data2; + result.data3 = uuid.Data3; + MemoryCopyArray(result.data4, uuid.Data4); + } + return result; +} + diff --git a/src/os/core/win32/os_core_win32.h b/src/os/core/win32/os_core_win32.h new file mode 100644 index 00000000..3ce6aac4 --- /dev/null +++ b/src/os/core/win32/os_core_win32.h @@ -0,0 +1,91 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef WIN32_H +#define WIN32_H + +//////////////////////////////// +//~ NOTE(allen): Negotiate the windows header include order + +#if OS_FEATURE_SOCKET +#include +#endif + +#include +#include + +#if OS_FEATURE_GRAPHICAL +#include +#endif + +#if OS_FEATURE_SOCKET +#include +#include +#endif + +#include + +//////////////////////////////// +//~ NOTE(allen): File Iterator + +typedef struct W32_FileIter W32_FileIter; +struct W32_FileIter +{ + HANDLE handle; + WIN32_FIND_DATAW find_data; +}; +StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(W32_FileIter), file_iter_memory_size); + +//////////////////////////////// +//~ NOTE(allen): Threading Entities + +typedef enum W32_EntityKind +{ + W32_EntityKind_Null, + W32_EntityKind_Thread, + W32_EntityKind_Mutex, + W32_EntityKind_RWMutex, + W32_EntityKind_ConditionVariable, +} +W32_EntityKind; + +typedef struct W32_Entity W32_Entity; +struct W32_Entity +{ + W32_Entity *next; + W32_EntityKind kind; + volatile U32 reference_mask; + union{ + struct{ + OS_ThreadFunctionType *func; + void *ptr; + HANDLE handle; + DWORD tid; + } thread; + CRITICAL_SECTION mutex; + SRWLOCK rw_mutex; + CONDITION_VARIABLE cv; + }; +}; + +//////////////////////////////// +//~ rjf: Helpers + +//- rjf: files +internal FilePropertyFlags w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes); +internal void w32_file_properties_from_attributes(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes); + +//- rjf: time +internal void w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in); +internal void w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in); +internal void w32_dense_time_from_file_time(DenseTime *out, FILETIME *in); +internal U32 w32_sleep_ms_from_endt_us(U64 endt_us); + +//- rjf: entities +internal W32_Entity* w32_alloc_entity(W32_EntityKind kind); +internal void w32_free_entity(W32_Entity *entity); + +//- rjf: threads +internal DWORD w32_thread_base(void *ptr); + +#endif //WIN32_H diff --git a/src/os/gfx/generated/os_gfx.meta.c b/src/os/gfx/generated/os_gfx.meta.c new file mode 100644 index 00000000..b9d27fe6 --- /dev/null +++ b/src/os/gfx/generated/os_gfx.meta.c @@ -0,0 +1,5 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + diff --git a/src/os/gfx/generated/os_gfx.meta.h b/src/os/gfx/generated/os_gfx.meta.h new file mode 100644 index 00000000..9ce39166 --- /dev/null +++ b/src/os/gfx/generated/os_gfx.meta.h @@ -0,0 +1,452 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef OS_GFX_META_H +#define OS_GFX_META_H + +typedef enum OS_Key +{ +OS_Key_Null, +OS_Key_Esc, +OS_Key_F1, +OS_Key_F2, +OS_Key_F3, +OS_Key_F4, +OS_Key_F5, +OS_Key_F6, +OS_Key_F7, +OS_Key_F8, +OS_Key_F9, +OS_Key_F10, +OS_Key_F11, +OS_Key_F12, +OS_Key_F13, +OS_Key_F14, +OS_Key_F15, +OS_Key_F16, +OS_Key_F17, +OS_Key_F18, +OS_Key_F19, +OS_Key_F20, +OS_Key_F21, +OS_Key_F22, +OS_Key_F23, +OS_Key_F24, +OS_Key_Tick, +OS_Key_0, +OS_Key_1, +OS_Key_2, +OS_Key_3, +OS_Key_4, +OS_Key_5, +OS_Key_6, +OS_Key_7, +OS_Key_8, +OS_Key_9, +OS_Key_Minus, +OS_Key_Equal, +OS_Key_Backspace, +OS_Key_Tab, +OS_Key_Q, +OS_Key_W, +OS_Key_E, +OS_Key_R, +OS_Key_T, +OS_Key_Y, +OS_Key_U, +OS_Key_I, +OS_Key_O, +OS_Key_P, +OS_Key_LeftBracket, +OS_Key_RightBracket, +OS_Key_BackSlash, +OS_Key_CapsLock, +OS_Key_A, +OS_Key_S, +OS_Key_D, +OS_Key_F, +OS_Key_G, +OS_Key_H, +OS_Key_J, +OS_Key_K, +OS_Key_L, +OS_Key_Semicolon, +OS_Key_Quote, +OS_Key_Return, +OS_Key_Shift, +OS_Key_Z, +OS_Key_X, +OS_Key_C, +OS_Key_V, +OS_Key_B, +OS_Key_N, +OS_Key_M, +OS_Key_Comma, +OS_Key_Period, +OS_Key_Slash, +OS_Key_Ctrl, +OS_Key_Alt, +OS_Key_Space, +OS_Key_Menu, +OS_Key_ScrollLock, +OS_Key_Pause, +OS_Key_Insert, +OS_Key_Home, +OS_Key_PageUp, +OS_Key_Delete, +OS_Key_End, +OS_Key_PageDown, +OS_Key_Up, +OS_Key_Left, +OS_Key_Down, +OS_Key_Right, +OS_Key_Ex0, +OS_Key_Ex1, +OS_Key_Ex2, +OS_Key_Ex3, +OS_Key_Ex4, +OS_Key_Ex5, +OS_Key_Ex6, +OS_Key_Ex7, +OS_Key_Ex8, +OS_Key_Ex9, +OS_Key_Ex10, +OS_Key_Ex11, +OS_Key_Ex12, +OS_Key_Ex13, +OS_Key_Ex14, +OS_Key_Ex15, +OS_Key_Ex16, +OS_Key_Ex17, +OS_Key_Ex18, +OS_Key_Ex19, +OS_Key_Ex20, +OS_Key_Ex21, +OS_Key_Ex22, +OS_Key_Ex23, +OS_Key_Ex24, +OS_Key_Ex25, +OS_Key_Ex26, +OS_Key_Ex27, +OS_Key_Ex28, +OS_Key_Ex29, +OS_Key_NumLock, +OS_Key_NumSlash, +OS_Key_NumStar, +OS_Key_NumMinus, +OS_Key_NumPlus, +OS_Key_NumPeriod, +OS_Key_Num0, +OS_Key_Num1, +OS_Key_Num2, +OS_Key_Num3, +OS_Key_Num4, +OS_Key_Num5, +OS_Key_Num6, +OS_Key_Num7, +OS_Key_Num8, +OS_Key_Num9, +OS_Key_LeftMouseButton, +OS_Key_MiddleMouseButton, +OS_Key_RightMouseButton, +OS_Key_COUNT +} OS_Key; + +String8 os_g_key_display_string_table[] = +{ +str8_lit_comp("Invalid Key"), +str8_lit_comp("Escape"), +str8_lit_comp("F1"), +str8_lit_comp("F2"), +str8_lit_comp("F3"), +str8_lit_comp("F4"), +str8_lit_comp("F5"), +str8_lit_comp("F6"), +str8_lit_comp("F7"), +str8_lit_comp("F8"), +str8_lit_comp("F9"), +str8_lit_comp("F10"), +str8_lit_comp("F11"), +str8_lit_comp("F12"), +str8_lit_comp("F13"), +str8_lit_comp("F14"), +str8_lit_comp("F15"), +str8_lit_comp("F16"), +str8_lit_comp("F17"), +str8_lit_comp("F18"), +str8_lit_comp("F19"), +str8_lit_comp("F20"), +str8_lit_comp("F21"), +str8_lit_comp("F22"), +str8_lit_comp("F23"), +str8_lit_comp("F24"), +str8_lit_comp("Tick"), +str8_lit_comp("0"), +str8_lit_comp("1"), +str8_lit_comp("2"), +str8_lit_comp("3"), +str8_lit_comp("4"), +str8_lit_comp("5"), +str8_lit_comp("6"), +str8_lit_comp("7"), +str8_lit_comp("8"), +str8_lit_comp("9"), +str8_lit_comp("Minus"), +str8_lit_comp("Equal"), +str8_lit_comp("Backspace"), +str8_lit_comp("Tab"), +str8_lit_comp("Q"), +str8_lit_comp("W"), +str8_lit_comp("E"), +str8_lit_comp("R"), +str8_lit_comp("T"), +str8_lit_comp("Y"), +str8_lit_comp("U"), +str8_lit_comp("I"), +str8_lit_comp("O"), +str8_lit_comp("P"), +str8_lit_comp("Left Bracket"), +str8_lit_comp("Right Bracket"), +str8_lit_comp("Back Slash"), +str8_lit_comp("Caps Lock"), +str8_lit_comp("A"), +str8_lit_comp("S"), +str8_lit_comp("D"), +str8_lit_comp("F"), +str8_lit_comp("G"), +str8_lit_comp("H"), +str8_lit_comp("J"), +str8_lit_comp("K"), +str8_lit_comp("L"), +str8_lit_comp("Semicolon"), +str8_lit_comp("Quote"), +str8_lit_comp("Return"), +str8_lit_comp("Shift"), +str8_lit_comp("Z"), +str8_lit_comp("X"), +str8_lit_comp("C"), +str8_lit_comp("V"), +str8_lit_comp("B"), +str8_lit_comp("N"), +str8_lit_comp("M"), +str8_lit_comp("Comma"), +str8_lit_comp("Period"), +str8_lit_comp("Slash"), +str8_lit_comp("Ctrl"), +str8_lit_comp("Alt"), +str8_lit_comp("Space"), +str8_lit_comp("Menu"), +str8_lit_comp("Scroll Lock"), +str8_lit_comp("Pause"), +str8_lit_comp("Insert"), +str8_lit_comp("Home"), +str8_lit_comp("Page Up"), +str8_lit_comp("Delete"), +str8_lit_comp("End"), +str8_lit_comp("Page Down"), +str8_lit_comp("Up"), +str8_lit_comp("Left"), +str8_lit_comp("Down"), +str8_lit_comp("Right"), +str8_lit_comp("Ex0"), +str8_lit_comp("Ex1"), +str8_lit_comp("Ex2"), +str8_lit_comp("Ex3"), +str8_lit_comp("Ex4"), +str8_lit_comp("Ex5"), +str8_lit_comp("Ex6"), +str8_lit_comp("Ex7"), +str8_lit_comp("Ex8"), +str8_lit_comp("Ex9"), +str8_lit_comp("Ex10"), +str8_lit_comp("Ex11"), +str8_lit_comp("Ex12"), +str8_lit_comp("Ex13"), +str8_lit_comp("Ex14"), +str8_lit_comp("Ex15"), +str8_lit_comp("Ex16"), +str8_lit_comp("Ex17"), +str8_lit_comp("Ex18"), +str8_lit_comp("Ex19"), +str8_lit_comp("Ex20"), +str8_lit_comp("Ex21"), +str8_lit_comp("Ex22"), +str8_lit_comp("Ex23"), +str8_lit_comp("Ex24"), +str8_lit_comp("Ex25"), +str8_lit_comp("Ex26"), +str8_lit_comp("Ex27"), +str8_lit_comp("Ex28"), +str8_lit_comp("Ex29"), +str8_lit_comp("Num Lock"), +str8_lit_comp("Numpad Slash"), +str8_lit_comp("Numpad Star"), +str8_lit_comp("Numpad Minus"), +str8_lit_comp("Numpad Plus"), +str8_lit_comp("Numpad Period"), +str8_lit_comp("Numpad 0"), +str8_lit_comp("Numpad 1"), +str8_lit_comp("Numpad 2"), +str8_lit_comp("Numpad 3"), +str8_lit_comp("Numpad 4"), +str8_lit_comp("Numpad 5"), +str8_lit_comp("Numpad 6"), +str8_lit_comp("Numpad 7"), +str8_lit_comp("Numpad 8"), +str8_lit_comp("Numpad 9"), +str8_lit_comp("Left Mouse Button"), +str8_lit_comp("Middle Mouse Button"), +str8_lit_comp("Right Mouse Button"), +}; + +String8 os_g_key_cfg_string_table[] = +{ +str8_lit_comp("null"), +str8_lit_comp("esc"), +str8_lit_comp("f1"), +str8_lit_comp("f2"), +str8_lit_comp("f3"), +str8_lit_comp("f4"), +str8_lit_comp("f5"), +str8_lit_comp("f6"), +str8_lit_comp("f7"), +str8_lit_comp("f8"), +str8_lit_comp("f9"), +str8_lit_comp("f10"), +str8_lit_comp("f11"), +str8_lit_comp("f12"), +str8_lit_comp("f13"), +str8_lit_comp("f14"), +str8_lit_comp("f15"), +str8_lit_comp("f16"), +str8_lit_comp("f17"), +str8_lit_comp("f18"), +str8_lit_comp("f19"), +str8_lit_comp("f20"), +str8_lit_comp("f21"), +str8_lit_comp("f22"), +str8_lit_comp("f23"), +str8_lit_comp("f24"), +str8_lit_comp("tick"), +str8_lit_comp("0"), +str8_lit_comp("1"), +str8_lit_comp("2"), +str8_lit_comp("3"), +str8_lit_comp("4"), +str8_lit_comp("5"), +str8_lit_comp("6"), +str8_lit_comp("7"), +str8_lit_comp("8"), +str8_lit_comp("9"), +str8_lit_comp("minus"), +str8_lit_comp("equal"), +str8_lit_comp("backspace"), +str8_lit_comp("tab"), +str8_lit_comp("q"), +str8_lit_comp("w"), +str8_lit_comp("e"), +str8_lit_comp("r"), +str8_lit_comp("t"), +str8_lit_comp("y"), +str8_lit_comp("u"), +str8_lit_comp("i"), +str8_lit_comp("o"), +str8_lit_comp("p"), +str8_lit_comp("left_bracket"), +str8_lit_comp("right_bracket"), +str8_lit_comp("backslash"), +str8_lit_comp("caps_lock"), +str8_lit_comp("a"), +str8_lit_comp("s"), +str8_lit_comp("d"), +str8_lit_comp("f"), +str8_lit_comp("g"), +str8_lit_comp("h"), +str8_lit_comp("j"), +str8_lit_comp("k"), +str8_lit_comp("l"), +str8_lit_comp("semicolon"), +str8_lit_comp("quote"), +str8_lit_comp("return"), +str8_lit_comp("shift"), +str8_lit_comp("z"), +str8_lit_comp("x"), +str8_lit_comp("c"), +str8_lit_comp("v"), +str8_lit_comp("b"), +str8_lit_comp("n"), +str8_lit_comp("m"), +str8_lit_comp("comma"), +str8_lit_comp("period"), +str8_lit_comp("slash"), +str8_lit_comp("ctrl"), +str8_lit_comp("alt"), +str8_lit_comp("space"), +str8_lit_comp("menu"), +str8_lit_comp("scroll_lock"), +str8_lit_comp("pause"), +str8_lit_comp("insert"), +str8_lit_comp("home"), +str8_lit_comp("page_up"), +str8_lit_comp("delete"), +str8_lit_comp("end"), +str8_lit_comp("page_down"), +str8_lit_comp("up"), +str8_lit_comp("left"), +str8_lit_comp("down"), +str8_lit_comp("right"), +str8_lit_comp("ex0"), +str8_lit_comp("ex1"), +str8_lit_comp("ex2"), +str8_lit_comp("ex3"), +str8_lit_comp("ex4"), +str8_lit_comp("ex5"), +str8_lit_comp("ex6"), +str8_lit_comp("ex7"), +str8_lit_comp("ex8"), +str8_lit_comp("ex9"), +str8_lit_comp("ex10"), +str8_lit_comp("ex11"), +str8_lit_comp("ex12"), +str8_lit_comp("ex13"), +str8_lit_comp("ex14"), +str8_lit_comp("ex15"), +str8_lit_comp("ex16"), +str8_lit_comp("ex17"), +str8_lit_comp("ex18"), +str8_lit_comp("ex19"), +str8_lit_comp("ex20"), +str8_lit_comp("ex21"), +str8_lit_comp("ex22"), +str8_lit_comp("ex23"), +str8_lit_comp("ex24"), +str8_lit_comp("ex25"), +str8_lit_comp("ex26"), +str8_lit_comp("ex27"), +str8_lit_comp("ex28"), +str8_lit_comp("ex29"), +str8_lit_comp("num_lock"), +str8_lit_comp("numpad_slash"), +str8_lit_comp("numpad_star"), +str8_lit_comp("numpad_minus"), +str8_lit_comp("numpad_plus"), +str8_lit_comp("numpad_period"), +str8_lit_comp("numpad_0"), +str8_lit_comp("numpad_1"), +str8_lit_comp("numpad_2"), +str8_lit_comp("numpad_3"), +str8_lit_comp("numpad_4"), +str8_lit_comp("numpad_5"), +str8_lit_comp("numpad_6"), +str8_lit_comp("numpad_7"), +str8_lit_comp("numpad_8"), +str8_lit_comp("numpad_9"), +str8_lit_comp("left_mouse"), +str8_lit_comp("middle_mouse"), +str8_lit_comp("right_mouse"), +}; + + +#endif // OS_GFX_META_H diff --git a/src/os/gfx/os_gfx.c b/src/os/gfx/os_gfx.c new file mode 100644 index 00000000..5747e965 --- /dev/null +++ b/src/os/gfx/os_gfx.c @@ -0,0 +1,191 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Event Functions (Helpers, Implemented Once) + +internal String8List +os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags) +{ + String8List result = {0}; + String8 flag_strs[] = + { + str8_lit("Ctrl"), + str8_lit("Shift"), + str8_lit("Alt"), + }; + str8_list_from_flags(arena, &result, flags, flag_strs, ArrayCount(flag_strs)); + return result; +} + +internal U32 +os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key) +{ + U32 result = 0; + + // rjf: special-case map + local_persist read_only struct {U32 character; OS_Key key; OS_EventFlags flags;} map[] = + { + {'!', OS_Key_1, OS_EventFlag_Shift}, + {'@', OS_Key_2, OS_EventFlag_Shift}, + {'#', OS_Key_3, OS_EventFlag_Shift}, + {'$', OS_Key_4, OS_EventFlag_Shift}, + {'%', OS_Key_5, OS_EventFlag_Shift}, + {'^', OS_Key_6, OS_EventFlag_Shift}, + {'&', OS_Key_7, OS_EventFlag_Shift}, + {'*', OS_Key_8, OS_EventFlag_Shift}, + {'(', OS_Key_9, OS_EventFlag_Shift}, + {')', OS_Key_0, OS_EventFlag_Shift}, + {'_', OS_Key_Minus, OS_EventFlag_Shift}, + {'_', OS_Key_Minus, OS_EventFlag_Shift}, + {'-', OS_Key_Minus, 0}, + {'=', OS_Key_Equal, 0}, + {'+', OS_Key_Equal, OS_EventFlag_Shift}, + {'`', OS_Key_Tick, 0}, + {'~', OS_Key_Tick, OS_EventFlag_Shift}, + {'[', OS_Key_LeftBracket, 0}, + {']', OS_Key_RightBracket, 0}, + {'{', OS_Key_LeftBracket, OS_EventFlag_Shift}, + {'}', OS_Key_RightBracket, OS_EventFlag_Shift}, + {'\\', OS_Key_BackSlash, 0}, + {'|', OS_Key_BackSlash, OS_EventFlag_Shift}, + {';', OS_Key_Semicolon, 0}, + {':', OS_Key_Semicolon, OS_EventFlag_Shift}, + {'\'', OS_Key_Quote, 0}, + {'"', OS_Key_Quote, OS_EventFlag_Shift}, + {'.', OS_Key_Period, 0}, + {',', OS_Key_Comma, 0}, + {'<', OS_Key_Period, OS_EventFlag_Shift}, + {'>', OS_Key_Comma, OS_EventFlag_Shift}, + {'/', OS_Key_Slash, 0}, + {'?', OS_Key_Slash, OS_EventFlag_Shift}, + {'a', OS_Key_A, 0}, + {'b', OS_Key_B, 0}, + {'c', OS_Key_C, 0}, + {'d', OS_Key_D, 0}, + {'e', OS_Key_E, 0}, + {'f', OS_Key_F, 0}, + {'g', OS_Key_G, 0}, + {'h', OS_Key_H, 0}, + {'i', OS_Key_I, 0}, + {'j', OS_Key_J, 0}, + {'k', OS_Key_K, 0}, + {'l', OS_Key_L, 0}, + {'m', OS_Key_M, 0}, + {'n', OS_Key_N, 0}, + {'o', OS_Key_O, 0}, + {'p', OS_Key_P, 0}, + {'q', OS_Key_Q, 0}, + {'r', OS_Key_R, 0}, + {'s', OS_Key_S, 0}, + {'t', OS_Key_T, 0}, + {'u', OS_Key_U, 0}, + {'v', OS_Key_V, 0}, + {'w', OS_Key_W, 0}, + {'x', OS_Key_X, 0}, + {'y', OS_Key_Y, 0}, + {'z', OS_Key_Z, 0}, + {'A', OS_Key_A, OS_EventFlag_Shift}, + {'B', OS_Key_B, OS_EventFlag_Shift}, + {'C', OS_Key_C, OS_EventFlag_Shift}, + {'D', OS_Key_D, OS_EventFlag_Shift}, + {'E', OS_Key_E, OS_EventFlag_Shift}, + {'F', OS_Key_F, OS_EventFlag_Shift}, + {'G', OS_Key_G, OS_EventFlag_Shift}, + {'H', OS_Key_H, OS_EventFlag_Shift}, + {'I', OS_Key_I, OS_EventFlag_Shift}, + {'J', OS_Key_J, OS_EventFlag_Shift}, + {'K', OS_Key_K, OS_EventFlag_Shift}, + {'L', OS_Key_L, OS_EventFlag_Shift}, + {'M', OS_Key_M, OS_EventFlag_Shift}, + {'N', OS_Key_N, OS_EventFlag_Shift}, + {'O', OS_Key_O, OS_EventFlag_Shift}, + {'P', OS_Key_P, OS_EventFlag_Shift}, + {'Q', OS_Key_Q, OS_EventFlag_Shift}, + {'R', OS_Key_R, OS_EventFlag_Shift}, + {'S', OS_Key_S, OS_EventFlag_Shift}, + {'T', OS_Key_T, OS_EventFlag_Shift}, + {'U', OS_Key_U, OS_EventFlag_Shift}, + {'V', OS_Key_V, OS_EventFlag_Shift}, + {'W', OS_Key_W, OS_EventFlag_Shift}, + {'X', OS_Key_X, OS_EventFlag_Shift}, + {'Y', OS_Key_Y, OS_EventFlag_Shift}, + {'Z', OS_Key_Z, OS_EventFlag_Shift}, + }; + + // rjf: check numeric + if(OS_Key_0 <= key && key <= OS_Key_9) + { + result = '0' + (key - OS_Key_0); + } + + // rjf: check special-case map + for(U64 idx = 0; idx < ArrayCount(map); idx += 1) + { + if(map[idx].key == key && map[idx].flags == flags) + { + result = map[idx].character; + break; + } + } + + return result; +} + +internal void +os_eat_event(OS_EventList *events, OS_Event *event) +{ + DLLRemove(events->first, events->last, event); + events->count -= 1; +} + +internal B32 +os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key) +{ + B32 result = 0; + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && + event->kind == OS_EventKind_Press && event->key == key && event->flags == flags) + { + result = 1; + os_eat_event(events, event); + break; + } + } + return result; +} + +internal B32 +os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key) +{ + B32 result = 0; + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && + event->kind == OS_EventKind_Release && event->key == key && event->flags == flags) + { + result = 1; + os_eat_event(events, event); + break; + } + } + return result; +} + +internal B32 +os_text(OS_EventList *events, OS_Handle window, U32 character) +{ + B32 result = 0; + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && + event->kind == OS_EventKind_Text && event->character == character) + { + result = 1; + os_eat_event(events, event); + break; + } + } + return result; +} diff --git a/src/os/gfx/os_gfx.h b/src/os/gfx/os_gfx.h new file mode 100644 index 00000000..42ec880b --- /dev/null +++ b/src/os/gfx/os_gfx.h @@ -0,0 +1,162 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef OS_GRAPHICAL_H +#define OS_GRAPHICAL_H + +//////////////////////////////// +//~ rjf: Window Types + +typedef void OS_WindowRepaintFunctionType(OS_Handle window, void *user_data); + +//////////////////////////////// +//~ rjf: Cursor Types + +typedef enum OS_Cursor +{ + OS_Cursor_Pointer, + OS_Cursor_IBar, + OS_Cursor_LeftRight, + OS_Cursor_UpDown, + OS_Cursor_DownRight, + OS_Cursor_UpRight, + OS_Cursor_UpDownLeftRight, + OS_Cursor_HandPoint, + OS_Cursor_Disabled, + OS_Cursor_COUNT, +} +OS_Cursor; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "os/gfx/generated/os_gfx.meta.h" + +//////////////////////////////// +//~ rjf: Event Types + +typedef enum OS_EventKind +{ + OS_EventKind_Null, + OS_EventKind_Press, + OS_EventKind_Release, + OS_EventKind_Text, + OS_EventKind_Scroll, + OS_EventKind_WindowLoseFocus, + OS_EventKind_WindowClose, + OS_EventKind_FileDrop, + OS_EventKind_Wakeup, + OS_EventKind_COUNT +} +OS_EventKind; + +typedef U32 OS_EventFlags; +enum +{ + OS_EventFlag_Ctrl = (1<<0), + OS_EventFlag_Shift = (1<<1), + OS_EventFlag_Alt = (1<<2), +}; + +typedef struct OS_Event OS_Event; +struct OS_Event +{ + OS_Event *next; + OS_Event *prev; + OS_Handle window; + OS_EventKind kind; + OS_EventFlags flags; + OS_Key key; + B32 is_repeat; + B32 right_sided; + U32 character; + U32 repeat_count; + Vec2F32 delta; + String8List strings; +}; + +typedef struct OS_EventList OS_EventList; +struct OS_EventList +{ + U64 count; + OS_Event *first; + OS_Event *last; +}; + +//////////////////////////////// +//~ rjf: Event Functions (Helpers, Implemented Once) + +internal String8List os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags); +internal U32 os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key); +internal void os_eat_event(OS_EventList *events, OS_Event *event); +internal B32 os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key); +internal B32 os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key); +internal B32 os_text(OS_EventList *events, OS_Handle window, U32 character); + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void os_graphical_init(void); + +//////////////////////////////// +//~ rjf: @os_hooks Clipboards (Implemented Per-OS) + +internal void os_set_clipboard_text(String8 string); +internal String8 os_get_clipboard_text(Arena *arena); + +//////////////////////////////// +//~ rjf: @os_hooks Windows (Implemented Per-OS) + +internal OS_Handle os_window_open(Vec2F32 resolution, String8 title); +internal void os_window_close(OS_Handle window); +internal void os_window_first_paint(OS_Handle window); +internal void os_window_equip_repaint(OS_Handle window, OS_WindowRepaintFunctionType *repaint, void *user_data); +internal void os_window_focus(OS_Handle window); +internal B32 os_window_is_focused(OS_Handle window); +internal B32 os_window_is_fullscreen(OS_Handle window); +internal void os_window_set_fullscreen(OS_Handle window, B32 fullscreen); +internal B32 os_window_is_maximized(OS_Handle window); +internal void os_window_set_maximized(OS_Handle window, B32 maximized); +internal void os_window_bring_to_front(OS_Handle window); +internal void os_window_set_monitor(OS_Handle window, OS_Handle monitor); +internal Rng2F32 os_rect_from_window(OS_Handle window); +internal Rng2F32 os_client_rect_from_window(OS_Handle window); +internal F32 os_dpi_from_window(OS_Handle window); + +//////////////////////////////// +//~ rjf: @os_hooks Monitors (Implemented Per-OS) + +internal OS_HandleArray os_push_monitors_array(Arena *arena); +internal OS_Handle os_primary_monitor(void); +internal OS_Handle os_monitor_from_window(OS_Handle window); +internal String8 os_name_from_monitor(Arena *arena, OS_Handle monitor); +internal Vec2F32 os_dim_from_monitor(OS_Handle monitor); + +//////////////////////////////// +//~ rjf: @os_hooks Events (Implemented Per-OS) + +internal void os_send_wakeup_event(void); +internal OS_EventList os_get_events(Arena *arena, B32 wait); +internal OS_EventFlags os_get_event_flags(void); +internal B32 os_key_is_down(OS_Key key); +internal Vec2F32 os_mouse_from_window(OS_Handle window); + +//////////////////////////////// +//~ rjf: @os_hooks Cursors (Implemented Per-OS) + +internal void os_set_cursor(OS_Cursor cursor); + +//////////////////////////////// +//~ rjf: @os_hooks System Properties (Implemented Per-OS) + +internal F32 os_double_click_time(void); +internal F32 os_caret_blink_time(void); +internal F32 os_default_refresh_rate(void); +internal B32 os_granular_sleep_enabled(void); + +//////////////////////////////// +//~ rjf: @os_hooks Native Messages & Panics (Implemented Per-OS) + +internal void os_graphical_message(B32 error, String8 title, String8 message); + +#endif // OS_GRAPHICAL_H diff --git a/src/os/gfx/os_gfx.mc b/src/os/gfx/os_gfx.mc new file mode 100644 index 00000000..297f6ecf --- /dev/null +++ b/src/os/gfx/os_gfx.mc @@ -0,0 +1,175 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Tables + +@table(name, display_string, cfg_string) +OS_KeyTable: +{ + {Null "Invalid Key" "null" } + {Esc "Escape" "esc" } + {F1 "F1" "f1" } + {F2 "F2" "f2" } + {F3 "F3" "f3" } + {F4 "F4" "f4" } + {F5 "F5" "f5" } + {F6 "F6" "f6" } + {F7 "F7" "f7" } + {F8 "F8" "f8" } + {F9 "F9" "f9" } + {F10 "F10" "f10" } + {F11 "F11" "f11" } + {F12 "F12" "f12" } + {F13 "F13" "f13" } + {F14 "F14" "f14" } + {F15 "F15" "f15" } + {F16 "F16" "f16" } + {F17 "F17" "f17" } + {F18 "F18" "f18" } + {F19 "F19" "f19" } + {F20 "F20" "f20" } + {F21 "F21" "f21" } + {F22 "F22" "f22" } + {F23 "F23" "f23" } + {F24 "F24" "f24" } + {Tick "Tick" "tick" } + {0 "0" "0" } + {1 "1" "1" } + {2 "2" "2" } + {3 "3" "3" } + {4 "4" "4" } + {5 "5" "5" } + {6 "6" "6" } + {7 "7" "7" } + {8 "8" "8" } + {9 "9" "9" } + {Minus "Minus" "minus" } + {Equal "Equal" "equal" } + {Backspace "Backspace" "backspace" } + {Tab "Tab" "tab" } + {Q "Q" "q" } + {W "W" "w" } + {E "E" "e" } + {R "R" "r" } + {T "T" "t" } + {Y "Y" "y" } + {U "U" "u" } + {I "I" "i" } + {O "O" "o" } + {P "P" "p" } + {LeftBracket "Left Bracket" "left_bracket" } + {RightBracket "Right Bracket" "right_bracket" } + {BackSlash "Back Slash" "backslash" } + {CapsLock "Caps Lock" "caps_lock" } + {A "A" "a" } + {S "S" "s" } + {D "D" "d" } + {F "F" "f" } + {G "G" "g" } + {H "H" "h" } + {J "J" "j" } + {K "K" "k" } + {L "L" "l" } + {Semicolon "Semicolon" "semicolon" } + {Quote "Quote" "quote" } + {Return "Return" "return" } + {Shift "Shift" "shift" } + {Z "Z" "z" } + {X "X" "x" } + {C "C" "c" } + {V "V" "v" } + {B "B" "b" } + {N "N" "n" } + {M "M" "m" } + {Comma "Comma" "comma" } + {Period "Period" "period" } + {Slash "Slash" "slash" } + {Ctrl "Ctrl" "ctrl" } + {Alt "Alt" "alt" } + {Space "Space" "space" } + {Menu "Menu" "menu" } + {ScrollLock "Scroll Lock" "scroll_lock" } + {Pause "Pause" "pause" } + {Insert "Insert" "insert" } + {Home "Home" "home" } + {PageUp "Page Up" "page_up" } + {Delete "Delete" "delete" } + {End "End" "end" } + {PageDown "Page Down" "page_down" } + {Up "Up" "up" } + {Left "Left" "left" } + {Down "Down" "down" } + {Right "Right" "right" } + {Ex0 "Ex0" "ex0" } + {Ex1 "Ex1" "ex1" } + {Ex2 "Ex2" "ex2" } + {Ex3 "Ex3" "ex3" } + {Ex4 "Ex4" "ex4" } + {Ex5 "Ex5" "ex5" } + {Ex6 "Ex6" "ex6" } + {Ex7 "Ex7" "ex7" } + {Ex8 "Ex8" "ex8" } + {Ex9 "Ex9" "ex9" } + {Ex10 "Ex10" "ex10" } + {Ex11 "Ex11" "ex11" } + {Ex12 "Ex12" "ex12" } + {Ex13 "Ex13" "ex13" } + {Ex14 "Ex14" "ex14" } + {Ex15 "Ex15" "ex15" } + {Ex16 "Ex16" "ex16" } + {Ex17 "Ex17" "ex17" } + {Ex18 "Ex18" "ex18" } + {Ex19 "Ex19" "ex19" } + {Ex20 "Ex20" "ex20" } + {Ex21 "Ex21" "ex21" } + {Ex22 "Ex22" "ex22" } + {Ex23 "Ex23" "ex23" } + {Ex24 "Ex24" "ex24" } + {Ex25 "Ex25" "ex25" } + {Ex26 "Ex26" "ex26" } + {Ex27 "Ex27" "ex27" } + {Ex28 "Ex28" "ex28" } + {Ex29 "Ex29" "ex29" } + {NumLock "Num Lock" "num_lock" } + {NumSlash "Numpad Slash" "numpad_slash" } + {NumStar "Numpad Star" "numpad_star" } + {NumMinus "Numpad Minus" "numpad_minus" } + {NumPlus "Numpad Plus" "numpad_plus" } + {NumPeriod "Numpad Period" "numpad_period" } + {Num0 "Numpad 0" "numpad_0" } + {Num1 "Numpad 1" "numpad_1" } + {Num2 "Numpad 2" "numpad_2" } + {Num3 "Numpad 3" "numpad_3" } + {Num4 "Numpad 4" "numpad_4" } + {Num5 "Numpad 5" "numpad_5" } + {Num6 "Numpad 6" "numpad_6" } + {Num7 "Numpad 7" "numpad_7" } + {Num8 "Numpad 8" "numpad_8" } + {Num9 "Numpad 9" "numpad_9" } + {LeftMouseButton "Left Mouse Button" "left_mouse" } + {MiddleMouseButton "Middle Mouse Button" "middle_mouse" } + {RightMouseButton "Right Mouse Button" "right_mouse" } +} + +//////////////////////////////// +//~ rjf: Generators + +@table_gen_enum +OS_Key: +{ + @expand(OS_KeyTable a) `OS_Key_$(a.name),`; + `OS_Key_COUNT`; +} + +@table_gen_data(type: String8, fallback:`{0}`) +os_g_key_display_string_table: +{ + @expand(OS_KeyTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type: String8, fallback:`{0}`) +os_g_key_cfg_string_table: +{ + @expand(OS_KeyTable a) `str8_lit_comp("$(a.cfg_string)"),`; +} diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c new file mode 100644 index 00000000..29d7a6d1 --- /dev/null +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -0,0 +1,1101 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Globals + +global U32 w32_gfx_thread_tid = 0; +global HINSTANCE w32_h_instance = 0; +global W32_Window * w32_first_window = 0; +global W32_Window * w32_last_window = 0; +global W32_Window * w32_first_free_window = 0; +global OS_EventList w32_event_list = {0}; +global Arena * w32_event_arena = 0; +global HCURSOR w32_hcursor = 0; +global B32 w32_resizing = 0; +global F32 w32_default_refresh_rate = 60.f; +global B32 w32_granular_sleep_enabled = 0; + +//////////////////////////////// +//~ allen: Windows SDK Inconsistency Fixer + +typedef BOOL w32_SetProcessDpiAwarenessContext_Type(void* value); +typedef UINT w32_GetDpiForWindow_Type(HWND hwnd); +#define w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4) + +global w32_GetDpiForWindow_Type *w32_GetDpiForWindow_func = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal Rng2F32 +w32_base_rect_from_win32_rect(RECT rect) +{ + Rng2F32 r = {0}; + r.x0 = (F32)rect.left; + r.x1 = (F32)rect.right; + r.y0 = (F32)rect.top; + r.y1 = (F32)rect.bottom; + return r; +} + +//////////////////////////////// +//~ rjf: Windows + +internal OS_Handle +os_window_from_w32_window(W32_Window *window) +{ + OS_Handle handle = {(U64)window}; + return handle; +} + +internal W32_Window * +w32_window_from_os_window(OS_Handle handle) +{ + W32_Window *window = (W32_Window *)handle.u64[0]; + return window; +} + +internal W32_Window * +w32_window_from_hwnd(HWND hwnd) +{ + W32_Window *result = 0; + for(W32_Window *w = w32_first_window; w; w = w->next) + { + if(w->hwnd == hwnd) + { + result = w; + break; + } + } + return result; +} + +internal HWND +w32_hwnd_from_window(W32_Window *window) +{ + return window->hwnd; +} + +internal W32_Window * +w32_allocate_window(void) +{ + W32_Window *result = w32_first_free_window; + if(result == 0) + { + result = push_array(w32_perm_arena, W32_Window, 1); + } + else + { + w32_first_free_window = w32_first_free_window->next; + MemoryZeroStruct(result); + } + if(result) + { + DLLPushBack(w32_first_window, w32_last_window, result); + } + result->last_window_placement.length = sizeof(WINDOWPLACEMENT); + return result; +} + +internal void +w32_free_window(W32_Window *window) +{ + DestroyWindow(window->hwnd); + DLLRemove(w32_first_window, w32_last_window, window); + window->next = w32_first_free_window; + w32_first_free_window = window; +} + +internal OS_Event * +w32_push_event(OS_EventKind kind, W32_Window *window) +{ + OS_Event *result = push_array(w32_event_arena, OS_Event, 1); + DLLPushBack(w32_event_list.first, w32_event_list.last, result); + result->kind = kind; + result->window = os_window_from_w32_window(window); + result->flags = os_get_event_flags(); + return(result); +} + +internal OS_Key +w32_os_key_from_vkey(WPARAM vkey) +{ + local_persist B32 first = 1; + local_persist OS_Key key_table[256]; + if (first){ + first = 0; + MemoryZeroArray(key_table); + + key_table[(unsigned int)'A'] = OS_Key_A; + key_table[(unsigned int)'B'] = OS_Key_B; + key_table[(unsigned int)'C'] = OS_Key_C; + key_table[(unsigned int)'D'] = OS_Key_D; + key_table[(unsigned int)'E'] = OS_Key_E; + key_table[(unsigned int)'F'] = OS_Key_F; + key_table[(unsigned int)'G'] = OS_Key_G; + key_table[(unsigned int)'H'] = OS_Key_H; + key_table[(unsigned int)'I'] = OS_Key_I; + key_table[(unsigned int)'J'] = OS_Key_J; + key_table[(unsigned int)'K'] = OS_Key_K; + key_table[(unsigned int)'L'] = OS_Key_L; + key_table[(unsigned int)'M'] = OS_Key_M; + key_table[(unsigned int)'N'] = OS_Key_N; + key_table[(unsigned int)'O'] = OS_Key_O; + key_table[(unsigned int)'P'] = OS_Key_P; + key_table[(unsigned int)'Q'] = OS_Key_Q; + key_table[(unsigned int)'R'] = OS_Key_R; + key_table[(unsigned int)'S'] = OS_Key_S; + key_table[(unsigned int)'T'] = OS_Key_T; + key_table[(unsigned int)'U'] = OS_Key_U; + key_table[(unsigned int)'V'] = OS_Key_V; + key_table[(unsigned int)'W'] = OS_Key_W; + key_table[(unsigned int)'X'] = OS_Key_X; + key_table[(unsigned int)'Y'] = OS_Key_Y; + key_table[(unsigned int)'Z'] = OS_Key_Z; + + for (U64 i = '0', j = OS_Key_0; i <= '9'; i += 1, j += 1){ + key_table[i] = (OS_Key)j; + } + for (U64 i = VK_NUMPAD0, j = OS_Key_0; i <= VK_NUMPAD9; i += 1, j += 1){ + key_table[i] = (OS_Key)j; + } + for (U64 i = VK_F1, j = OS_Key_F1; i <= VK_F24; i += 1, j += 1){ + key_table[i] = (OS_Key)j; + } + + key_table[VK_SPACE] = OS_Key_Space; + key_table[VK_OEM_3] = OS_Key_Tick; + key_table[VK_OEM_MINUS] = OS_Key_Minus; + key_table[VK_OEM_PLUS] = OS_Key_Equal; + key_table[VK_OEM_4] = OS_Key_LeftBracket; + key_table[VK_OEM_6] = OS_Key_RightBracket; + key_table[VK_OEM_1] = OS_Key_Semicolon; + key_table[VK_OEM_7] = OS_Key_Quote; + key_table[VK_OEM_COMMA] = OS_Key_Comma; + key_table[VK_OEM_PERIOD]= OS_Key_Period; + key_table[VK_OEM_2] = OS_Key_Slash; + key_table[VK_OEM_5] = OS_Key_BackSlash; + + key_table[VK_TAB] = OS_Key_Tab; + key_table[VK_PAUSE] = OS_Key_Pause; + key_table[VK_ESCAPE] = OS_Key_Esc; + + key_table[VK_UP] = OS_Key_Up; + key_table[VK_LEFT] = OS_Key_Left; + key_table[VK_DOWN] = OS_Key_Down; + key_table[VK_RIGHT] = OS_Key_Right; + + key_table[VK_BACK] = OS_Key_Backspace; + key_table[VK_RETURN] = OS_Key_Return; + + key_table[VK_DELETE] = OS_Key_Delete; + key_table[VK_INSERT] = OS_Key_Insert; + key_table[VK_PRIOR] = OS_Key_PageUp; + key_table[VK_NEXT] = OS_Key_PageDown; + key_table[VK_HOME] = OS_Key_Home; + key_table[VK_END] = OS_Key_End; + + key_table[VK_CAPITAL] = OS_Key_CapsLock; + key_table[VK_NUMLOCK] = OS_Key_NumLock; + key_table[VK_SCROLL] = OS_Key_ScrollLock; + key_table[VK_APPS] = OS_Key_Menu; + + key_table[VK_CONTROL] = OS_Key_Ctrl; + key_table[VK_LCONTROL] = OS_Key_Ctrl; + key_table[VK_RCONTROL] = OS_Key_Ctrl; + key_table[VK_SHIFT] = OS_Key_Shift; + key_table[VK_LSHIFT] = OS_Key_Shift; + key_table[VK_RSHIFT] = OS_Key_Shift; + key_table[VK_MENU] = OS_Key_Alt; + key_table[VK_LMENU] = OS_Key_Alt; + key_table[VK_RMENU] = OS_Key_Alt; + + key_table[VK_DIVIDE] = OS_Key_NumSlash; + key_table[VK_MULTIPLY] = OS_Key_NumStar; + key_table[VK_SUBTRACT] = OS_Key_NumMinus; + key_table[VK_ADD] = OS_Key_NumPlus; + key_table[VK_DECIMAL] = OS_Key_NumPeriod; + + for (U32 i = 0; i < 10; i += 1){ + key_table[VK_NUMPAD0 + i] = (OS_Key)((U64)OS_Key_Num0 + i); + } + + for (U64 i = 0xDF, j = 0; i < 0xFF; i += 1, j += 1){ + key_table[i] = (OS_Key)((U64)OS_Key_Ex0 + j); + } + } + + OS_Key key = key_table[vkey&bitmask8]; + return(key); +} + +internal WPARAM +w32_vkey_from_os_key(OS_Key key) +{ + WPARAM result = 0; + { + local_persist B32 initialized = 0; + local_persist WPARAM vkey_table[OS_Key_COUNT] = {0}; + if(initialized == 0) + { + initialized = 1; + vkey_table[OS_Key_Esc] = VK_ESCAPE; + for(OS_Key key = OS_Key_F1; key <= OS_Key_F24; key = (OS_Key)(key+1)) + { + vkey_table[key] = VK_F1+(key-OS_Key_F1); + } + vkey_table[OS_Key_Tick] = VK_OEM_3; + for(OS_Key key = OS_Key_0; key <= OS_Key_9; key = (OS_Key)(key+1)) + { + vkey_table[key] = '0'+(key-OS_Key_0); + } + vkey_table[OS_Key_Minus] = VK_OEM_MINUS; + vkey_table[OS_Key_Equal] = VK_OEM_PLUS; + vkey_table[OS_Key_Backspace] = VK_BACK; + vkey_table[OS_Key_Tab] = VK_TAB; + vkey_table[OS_Key_Q] = 'Q'; + vkey_table[OS_Key_W] = 'W'; + vkey_table[OS_Key_E] = 'E'; + vkey_table[OS_Key_R] = 'R'; + vkey_table[OS_Key_T] = 'T'; + vkey_table[OS_Key_Y] = 'Y'; + vkey_table[OS_Key_U] = 'U'; + vkey_table[OS_Key_I] = 'I'; + vkey_table[OS_Key_O] = 'O'; + vkey_table[OS_Key_P] = 'P'; + vkey_table[OS_Key_LeftBracket] = VK_OEM_4; + vkey_table[OS_Key_RightBracket] = VK_OEM_6; + vkey_table[OS_Key_BackSlash] = VK_OEM_5; + vkey_table[OS_Key_CapsLock] = VK_CAPITAL; + vkey_table[OS_Key_A] = 'A'; + vkey_table[OS_Key_S] = 'S'; + vkey_table[OS_Key_D] = 'D'; + vkey_table[OS_Key_F] = 'F'; + vkey_table[OS_Key_G] = 'G'; + vkey_table[OS_Key_H] = 'H'; + vkey_table[OS_Key_J] = 'J'; + vkey_table[OS_Key_K] = 'K'; + vkey_table[OS_Key_L] = 'L'; + vkey_table[OS_Key_Semicolon] = VK_OEM_1; + vkey_table[OS_Key_Quote] = VK_OEM_7; + vkey_table[OS_Key_Return] = VK_RETURN; + vkey_table[OS_Key_Shift] = VK_SHIFT; + vkey_table[OS_Key_Z] = 'Z'; + vkey_table[OS_Key_X] = 'X'; + vkey_table[OS_Key_C] = 'C'; + vkey_table[OS_Key_V] = 'V'; + vkey_table[OS_Key_B] = 'B'; + vkey_table[OS_Key_N] = 'N'; + vkey_table[OS_Key_M] = 'M'; + vkey_table[OS_Key_Comma] = VK_OEM_COMMA; + vkey_table[OS_Key_Period] = VK_OEM_PERIOD; + vkey_table[OS_Key_Slash] = VK_OEM_2; + vkey_table[OS_Key_Ctrl] = VK_CONTROL; + vkey_table[OS_Key_Alt] = VK_MENU; + vkey_table[OS_Key_Space] = VK_SPACE; + vkey_table[OS_Key_Menu] = VK_APPS; + vkey_table[OS_Key_ScrollLock] = VK_SCROLL; + vkey_table[OS_Key_Pause] = VK_PAUSE; + vkey_table[OS_Key_Insert] = VK_INSERT; + vkey_table[OS_Key_Home] = VK_HOME; + vkey_table[OS_Key_PageUp] = VK_PRIOR; + vkey_table[OS_Key_Delete] = VK_DELETE; + vkey_table[OS_Key_End] = VK_END; + vkey_table[OS_Key_PageDown] = VK_NEXT; + vkey_table[OS_Key_Up] = VK_UP; + vkey_table[OS_Key_Left] = VK_LEFT; + vkey_table[OS_Key_Down] = VK_DOWN; + vkey_table[OS_Key_Right] = VK_RIGHT; + for(OS_Key key = OS_Key_Ex0; key <= OS_Key_Ex29; key = (OS_Key)(key+1)) + { + vkey_table[key] = 0xDF + (key-OS_Key_Ex0); + } + vkey_table[OS_Key_NumLock] = VK_NUMLOCK; + vkey_table[OS_Key_NumSlash] = VK_DIVIDE; + vkey_table[OS_Key_NumStar] = VK_MULTIPLY; + vkey_table[OS_Key_NumMinus] = VK_SUBTRACT; + vkey_table[OS_Key_NumPlus] = VK_ADD; + vkey_table[OS_Key_NumPeriod] = VK_DECIMAL; + vkey_table[OS_Key_Num0] = VK_NUMPAD0; + vkey_table[OS_Key_Num1] = VK_NUMPAD1; + vkey_table[OS_Key_Num2] = VK_NUMPAD2; + vkey_table[OS_Key_Num3] = VK_NUMPAD3; + vkey_table[OS_Key_Num4] = VK_NUMPAD4; + vkey_table[OS_Key_Num5] = VK_NUMPAD5; + vkey_table[OS_Key_Num6] = VK_NUMPAD6; + vkey_table[OS_Key_Num7] = VK_NUMPAD7; + vkey_table[OS_Key_Num8] = VK_NUMPAD8; + vkey_table[OS_Key_Num9] = VK_NUMPAD9; + } + result = vkey_table[key]; + } + return result; +} + +internal LRESULT +w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + ProfBeginFunction(); + LRESULT result = 0; + + B32 good = 1; + if(w32_event_arena == 0) + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + good = 0; + } + + if(good) + { + W32_Window *window = w32_window_from_hwnd(hwnd); + OS_Handle window_handle = os_window_from_w32_window(window); + B32 release = 0; + + switch(uMsg) + { + default: + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + }break; + + case WM_ENTERSIZEMOVE: + { + w32_resizing = 1; + }break; + + case WM_EXITSIZEMOVE: + { + w32_resizing = 0; + }break; + + case WM_SIZE: + case WM_PAINT: + { + if(window->repaint != 0) + { + PAINTSTRUCT ps = {0}; + BeginPaint(hwnd, &ps); + window->repaint(os_window_from_w32_window(window), window->repaint_user_data); + EndPaint(hwnd, &ps); + } + else + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + }break; + + case WM_CLOSE: + { + w32_push_event(OS_EventKind_WindowClose, window); + }break; + + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + release = 1; + } // fallthrough; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + OS_Event *event = w32_push_event(release ? OS_EventKind_Release : OS_EventKind_Press, window); + switch (uMsg) + { + case WM_LBUTTONUP: case WM_LBUTTONDOWN: + { + event->key = OS_Key_LeftMouseButton; + }break; + case WM_MBUTTONUP: case WM_MBUTTONDOWN: + { + event->key = OS_Key_MiddleMouseButton; + }break; + case WM_RBUTTONUP: case WM_RBUTTONDOWN: + { + event->key = OS_Key_RightMouseButton; + }break; + } + if(release) + { + ReleaseCapture(); + } + else + { + SetCapture(hwnd); + } + }break; + + case WM_MOUSEWHEEL: + { + S16 wheel_delta = HIWORD(wParam); + OS_Event *event = w32_push_event(OS_EventKind_Scroll, window); + event->delta = v2f32(0.f, -(F32)wheel_delta); + }break; + + case WM_MOUSEHWHEEL: + { + S16 wheel_delta = HIWORD(wParam); + OS_Event *event = w32_push_event(OS_EventKind_Scroll, window); + event->delta = v2f32((F32)wheel_delta, 0.f); + }break; + + case WM_SYSKEYDOWN: case WM_SYSKEYUP: + { + if(wParam != VK_MENU && (wParam < VK_F1 || VK_F24 < wParam || wParam == VK_F4)) + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + } // fallthrough; + case WM_KEYDOWN: case WM_KEYUP: + { + B32 was_down = (lParam & bit31); + B32 is_down = !(lParam & bit32); + + B32 is_repeat = 0; + if(!is_down) + { + release = 1; + } + else if(was_down) + { + is_repeat = 1; + } + + B32 right_sided = 0; + if ((lParam & bit25) && + (wParam == VK_CONTROL || wParam == VK_RCONTROL || + wParam == VK_MENU || wParam == VK_RMENU || + wParam == VK_SHIFT || wParam == VK_RSHIFT)) + { + right_sided = 1; + } + + OS_Event *event = w32_push_event(release ? OS_EventKind_Release : OS_EventKind_Press, window); + event->key = w32_os_key_from_vkey(wParam); + event->repeat_count = lParam & bitmask16; + event->is_repeat = is_repeat; + event->right_sided = right_sided; + if(event->key == OS_Key_Alt && event->flags & OS_EventFlag_Alt) { event->flags &= ~OS_EventFlag_Alt; } + if(event->key == OS_Key_Ctrl && event->flags & OS_EventFlag_Ctrl) { event->flags &= ~OS_EventFlag_Ctrl; } + if(event->key == OS_Key_Shift && event->flags & OS_EventFlag_Shift) { event->flags &= ~OS_EventFlag_Shift; } + }break; + + case WM_SYSCHAR: + {}break; + + case WM_CHAR: + { + U32 character = wParam; + if(character >= 32 && character != 127) + { + OS_Event *event = w32_push_event(OS_EventKind_Text, window); + event->character = character; + } + }break; + + case WM_KILLFOCUS: + { + w32_push_event(OS_EventKind_WindowLoseFocus, window); + ReleaseCapture(); + }break; + + case WM_SETCURSOR: + { + if(!w32_resizing && + contains_2f32(os_client_rect_from_window(window_handle), os_mouse_from_window(window_handle))) + { + SetCursor(w32_hcursor); + } + else + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + }break; + + case WM_DPICHANGED: + { + F32 new_dpi = (F32)(wParam & 0xffff); + window->dpi = new_dpi; + }break; + } + } + + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Monitors + +internal BOOL +w32_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr) +{ + W32_MonitorGatherBundle *bundle = (W32_MonitorGatherBundle *)bundle_ptr; + OS_Handle handle = {(U64)monitor}; + os_handle_list_push(bundle->arena, bundle->list, handle); + return 1; +} + +//////////////////////////////// +//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) + +internal void +os_graphical_init(void) +{ + //- rjf: grab TID of thread which is doing graphics + w32_gfx_thread_tid = (U32)GetCurrentThreadId(); + + //- rjf: grab hinstance + w32_h_instance = GetModuleHandle(0); + + //- rjf: set dpi awareness + w32_SetProcessDpiAwarenessContext_Type *SetProcessDpiAwarenessContext_func = 0; + HMODULE module = LoadLibraryA("user32.dll"); + if (module != 0) + { + SetProcessDpiAwarenessContext_func = + (w32_SetProcessDpiAwarenessContext_Type*)GetProcAddress(module, "SetProcessDpiAwarenessContext"); + w32_GetDpiForWindow_func = + (w32_GetDpiForWindow_Type*)GetProcAddress(module, "GetDpiForWindow"); + FreeLibrary(module); + } + if (SetProcessDpiAwarenessContext_func != 0) + { + SetProcessDpiAwarenessContext_func(w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + } + + //- rjf: register graphical-window class + { + WNDCLASSEXW wndclass = {sizeof(wndclass)}; + wndclass.lpfnWndProc = w32_wnd_proc; + wndclass.hInstance = w32_h_instance; + wndclass.lpszClassName = L"graphical-window"; + wndclass.hCursor = LoadCursorA(0, IDC_ARROW); + ATOM wndatom = RegisterClassExW(&wndclass); + (void)wndatom; + } + + //- rjf: grab refresh rate + { + DEVMODEW devmodew = {0}; + if(EnumDisplaySettingsW(0, ENUM_CURRENT_SETTINGS, &devmodew)) + { + w32_default_refresh_rate = (F32)devmodew.dmDisplayFrequency; + } + } + + //- rjf: try to enable granular sleep + w32_granular_sleep_enabled = (timeBeginPeriod(1) == TIMERR_NOERROR); + + //- rjf: set initial cursor + os_set_cursor(OS_Cursor_Pointer); +} + +//////////////////////////////// +//~ rjf: @os_hooks Clipboards (Implemented Per-OS) + +internal void +os_set_clipboard_text(String8 string) +{ + if(OpenClipboard(0)) + { + EmptyClipboard(); + HANDLE string_copy_handle = GlobalAlloc(GMEM_MOVEABLE, string.size+1); + if(string_copy_handle) + { + U8 *copy_buffer = (U8 *)GlobalLock(string_copy_handle); + MemoryCopy(copy_buffer, string.str, string.size); + copy_buffer[string.size] = 0; + GlobalUnlock(string_copy_handle); + SetClipboardData(CF_TEXT, string_copy_handle); + } + CloseClipboard(); + } +} + +internal String8 +os_get_clipboard_text(Arena *arena) +{ + String8 result = {0}; + if(IsClipboardFormatAvailable(CF_TEXT) && + OpenClipboard(0)) + { + HANDLE data_handle = GetClipboardData(CF_TEXT); + if(data_handle) + { + U8 *buffer = (U8 *)GlobalLock(data_handle); + if(buffer) + { + U64 size = cstring8_length(buffer); + result = push_str8_copy(arena, str8(buffer, size)); + GlobalUnlock(data_handle); + } + } + CloseClipboard(); + } + return result; +} + +//////////////////////////////// +//~ rjf: @os_hooks Windows (Implemented Per-OS) + +internal OS_Handle +os_window_open(Vec2F32 resolution, String8 title) +{ + //- rjf: make hwnd + HWND hwnd = 0; + { + Temp scratch = scratch_begin(0, 0); + String16 title16 = str16_from_8(scratch.arena, title); + hwnd = CreateWindowExW(0, + L"graphical-window", + (WCHAR*)title16.str, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + (int)resolution.x, + (int)resolution.y, + 0, 0, + w32_h_instance, + 0); + scratch_end(scratch); + } + + //- rjf- make/fill window + W32_Window *window = w32_allocate_window(); + { + window->hwnd = hwnd; + if (w32_GetDpiForWindow_func != 0){ + window->dpi = (F32)w32_GetDpiForWindow_func(hwnd); + } + else{ + window->dpi = 96.f; + } + } + + //- rjf: convert to handle + return + return os_window_from_w32_window(window); +} + +internal void +os_window_close(OS_Handle handle) +{ + W32_Window *window = w32_window_from_os_window(handle); + w32_free_window(window); +} + +internal void +os_window_first_paint(OS_Handle window_handle) +{ + W32_Window *window = w32_window_from_os_window(window_handle); + window->first_paint_done = 1; + ShowWindow(window->hwnd, SW_SHOW); + if(window->maximized) + { + ShowWindow(window->hwnd, SW_MAXIMIZE); + } +} + +internal void +os_window_equip_repaint(OS_Handle handle, OS_WindowRepaintFunctionType *repaint, void *user_data) +{ + W32_Window *window = w32_window_from_os_window(handle); + window->repaint = repaint; + window->repaint_user_data = user_data; +} + +internal void +os_window_focus(OS_Handle handle) +{ + W32_Window *window = w32_window_from_os_window(handle); + SetForegroundWindow(window->hwnd); + SetFocus(window->hwnd); +} + +internal B32 +os_window_is_focused(OS_Handle handle) +{ + W32_Window *window = w32_window_from_os_window(handle); + HWND active_hwnd = GetActiveWindow(); + return active_hwnd == window->hwnd; +} + +internal B32 +os_window_is_fullscreen(OS_Handle handle) +{ + W32_Window *window = w32_window_from_os_window(handle); + DWORD window_style = GetWindowLong(window->hwnd, GWL_STYLE); + return !(window_style & WS_OVERLAPPEDWINDOW); +} + +internal void +os_window_set_fullscreen(OS_Handle handle, B32 fullscreen) +{ + W32_Window *window = w32_window_from_os_window(handle); + OS_WindowRepaintFunctionType *repaint = window->repaint; + window->repaint = 0; + DWORD window_style = GetWindowLong(window->hwnd, GWL_STYLE); + B32 is_fullscreen_already = os_window_is_fullscreen(handle); + if(fullscreen) + { + if(!is_fullscreen_already) + { + GetWindowPlacement(window->hwnd, &window->last_window_placement); + } + MONITORINFO monitor_info = {sizeof(monitor_info)}; + if(GetMonitorInfo(MonitorFromWindow(window->hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info)) + { + SetWindowLong(window->hwnd, GWL_STYLE, window_style & ~WS_OVERLAPPEDWINDOW); + SetWindowPos(window->hwnd, HWND_TOP, + monitor_info.rcMonitor.left, + monitor_info.rcMonitor.top, + monitor_info.rcMonitor.right - monitor_info.rcMonitor.left, + monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top, + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + } + } + else + { + SetWindowLong(window->hwnd, GWL_STYLE, window_style | WS_OVERLAPPEDWINDOW); + SetWindowPlacement(window->hwnd, &window->last_window_placement); + SetWindowPos(window->hwnd, 0, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + } + window->repaint = repaint; +} + +internal B32 +os_window_is_maximized(OS_Handle handle) +{ + B32 result = 0; + W32_Window *window = w32_window_from_os_window(handle); + if(window) + { + result = !!(IsZoomed(window->hwnd)); + } + return result; +} + +internal void +os_window_set_maximized(OS_Handle handle, B32 maximized) +{ + W32_Window *window = w32_window_from_os_window(handle); + if(window != 0) + { + if(window->first_paint_done) + { + switch(maximized) + { + default: + case 0:{ShowWindow(window->hwnd, SW_RESTORE);}break; + case 1:{ShowWindow(window->hwnd, SW_MAXIMIZE);}break; + } + } + else + { + window->maximized = maximized; + } + } +} + +internal void +os_window_bring_to_front(OS_Handle handle) +{ + W32_Window *window = w32_window_from_os_window(handle); + if(window != 0) + { + BringWindowToTop(window->hwnd); + } +} + +internal void +os_window_set_monitor(OS_Handle window_handle, OS_Handle monitor) +{ + W32_Window *window = w32_window_from_os_window(window_handle); + HMONITOR hmonitor = (HMONITOR)monitor.u64[0]; + { + MONITORINFOEXW info; + info.cbSize = sizeof(MONITORINFOEXW); + if(GetMonitorInfoW(hmonitor, (MONITORINFO *)&info)) + { + Rng2F32 existing_rect = os_rect_from_window(window_handle); + Vec2F32 window_size = dim_2f32(existing_rect); + SetWindowPos(window->hwnd, HWND_TOP, + (info.rcWork.left + info.rcWork.right)/2 - window_size.x/2, + (info.rcWork.top + info.rcWork.bottom)/2 - window_size.y/2, + window_size.x, + window_size.y, 0); + } + } +} + +internal Rng2F32 +os_rect_from_window(OS_Handle handle) +{ + Rng2F32 r = {0}; + W32_Window *window = w32_window_from_os_window(handle); + if(window) + { + RECT rect = {0}; + GetWindowRect(w32_hwnd_from_window(window), &rect); + r = w32_base_rect_from_win32_rect(rect); + } + return r; +} + +internal Rng2F32 +os_client_rect_from_window(OS_Handle handle) +{ + Rng2F32 r = {0}; + W32_Window *window = w32_window_from_os_window(handle); + if(window) + { + RECT rect = {0}; + GetClientRect(w32_hwnd_from_window(window), &rect); + r = w32_base_rect_from_win32_rect(rect); + } + return r; +} + +internal F32 +os_dpi_from_window(OS_Handle handle) +{ + F32 result = 96.f; + W32_Window *window = w32_window_from_os_window(handle); + if(window != 0) + { + result = window->dpi; + } + return result; +} + +//////////////////////////////// +//~ rjf: @os_hooks Monitors (Implemented Per-OS) + +internal OS_HandleArray +os_push_monitors_array(Arena *arena) +{ + Temp scratch = scratch_begin(&arena, 1); + OS_HandleList list = {0}; + { + W32_MonitorGatherBundle bundle = {arena, &list}; + EnumDisplayMonitors(0, 0, w32_monitor_gather_enum_proc, (LPARAM)&bundle); + } + OS_HandleArray array = os_handle_array_from_list(arena, &list); + scratch_end(scratch); + return array; +} + +internal OS_Handle +os_primary_monitor(void) +{ + POINT zero_pt = {0, 0}; + HMONITOR monitor = MonitorFromPoint(zero_pt, MONITOR_DEFAULTTOPRIMARY); + OS_Handle result = {(U64)monitor}; + return result; +} + +internal OS_Handle +os_monitor_from_window(OS_Handle window) +{ + W32_Window *w = w32_window_from_os_window(window); + HMONITOR handle = MonitorFromWindow(w->hwnd, MONITOR_DEFAULTTOPRIMARY); + OS_Handle result = {(U64)handle}; + return result; +} + +internal String8 +os_name_from_monitor(Arena *arena, OS_Handle monitor) +{ + String8 result = {0}; + HMONITOR monitor_handle = (HMONITOR)monitor.u64[0]; + MONITORINFOEXW info; + info.cbSize = sizeof(MONITORINFOEXW); + if(GetMonitorInfoW(monitor_handle, (MONITORINFO *)&info)) + { + String16 result16 = str16_cstring((U16 *)info.szDevice); + result = str8_from_16(arena, result16); + } + return result; +} + +internal Vec2F32 +os_dim_from_monitor(OS_Handle monitor) +{ + Vec2F32 result = {0}; + HMONITOR monitor_handle = (HMONITOR)monitor.u64[0]; + MONITORINFO info = {0}; + info.cbSize = sizeof(MONITORINFO); + if(GetMonitorInfoW(monitor_handle, &info)) + { + result.x = info.rcWork.right - info.rcWork.left; + result.y = info.rcWork.bottom - info.rcWork.top; + } + return result; +} + +//////////////////////////////// +//~ rjf: @os_hooks Events (Implemented Per-OS) + +internal void +os_send_wakeup_event(void) +{ + PostThreadMessageA(w32_gfx_thread_tid, 0x401, 0, 0); +} + +internal OS_EventList +os_get_events(Arena *arena, B32 wait) +{ + w32_event_arena = arena; + MemoryZeroStruct(&w32_event_list); + MSG msg = {0}; + if(!wait || GetMessage(&msg, 0, 0, 0)) + { + B32 first_wait = wait; + for(;first_wait || PeekMessage(&msg, 0, 0, 0, PM_REMOVE); first_wait = 0) + { + DispatchMessage(&msg); + TranslateMessage(&msg); + if(msg.message == WM_QUIT) + { + w32_push_event(OS_EventKind_WindowClose, 0); + } + } + } + return w32_event_list; +} + +internal OS_EventFlags +os_get_event_flags(void) +{ + OS_EventFlags flags = 0; + if(GetKeyState(VK_CONTROL) & 0x8000) + { + flags |= OS_EventFlag_Ctrl; + } + if(GetKeyState(VK_SHIFT) & 0x8000) + { + flags |= OS_EventFlag_Shift; + } + if(GetKeyState(VK_MENU) & 0x8000) + { + flags |= OS_EventFlag_Alt; + } + return(flags); +} + +internal B32 +os_key_is_down(OS_Key key) +{ + B32 result = 0; + { + WPARAM vkey_code = w32_vkey_from_os_key(key); + SHORT state = GetAsyncKeyState(vkey_code); + result = !!(state & (0x8000)); + } + return result; +} + +internal Vec2F32 +os_mouse_from_window(OS_Handle handle) +{ + ProfBeginFunction(); + Vec2F32 v = {0}; + POINT p; + if(GetCursorPos(&p)) + { + W32_Window *window = w32_window_from_os_window(handle); + ScreenToClient(window->hwnd, &p); + v.x = (F32)p.x; + v.y = (F32)p.y; + } + ProfEnd(); + return v; +} + +//////////////////////////////// +//~ rjf: @os_hooks Cursors (Implemented Per-OS) + +internal void +os_set_cursor(OS_Cursor cursor) +{ + B32 valid_cursor = 1; + + HCURSOR hcursor = 0; + switch(cursor) + { + default: {valid_cursor = 0;}break; +#define Win32CursorXList(X) \ +X(Pointer, IDC_ARROW) \ +X(IBar, IDC_IBEAM) \ +X(LeftRight, IDC_SIZEWE) \ +X(UpDown, IDC_SIZENS) \ +X(DownRight, IDC_SIZENWSE) \ +X(UpRight, IDC_SIZENESW) \ +X(UpDownLeftRight, IDC_SIZEALL) \ +X(HandPoint, IDC_HAND)\ +X(Disabled, IDC_NO) +#define CursorCase(E,R) case OS_Cursor_##E:{ \ +local_persist HCURSOR curs = 0; \ +if (curs == 0){ curs = LoadCursor(NULL, R); } \ +hcursor = curs; }break; + Win32CursorXList(CursorCase) +#undef CursorCase +#undef Win32CursorXList + } + + if(valid_cursor && !w32_resizing) + { + if(hcursor != w32_hcursor) + { + PostMessage(0, WM_SETCURSOR, 0, 0); + POINT p = {0}; + GetCursorPos(&p); + SetCursorPos(p.x, p.y); + } + w32_hcursor = hcursor; + } +} + +//////////////////////////////// +//~ rjf: @os_hooks System Properties (Implemented Per-OS) + +internal F32 +os_double_click_time(void) +{ + UINT time_milliseconds = GetDoubleClickTime(); + return time_milliseconds / 1000.f; +} + +internal F32 +os_caret_blink_time(void) +{ + UINT time_milliseconds = GetCaretBlinkTime(); + return time_milliseconds / 1000.f; +} + +internal F32 +os_default_refresh_rate(void) +{ + return w32_default_refresh_rate; +} + +internal B32 +os_granular_sleep_enabled(void) +{ + return w32_granular_sleep_enabled; +} + +//////////////////////////////// +//~ rjf: @os_hooks Native Messages & Panics (Implemented Per-OS) + +internal void +os_graphical_message(B32 error, String8 title, String8 message) +{ + Temp scratch = scratch_begin(0, 0); + String16 title16 = str16_from_8(scratch.arena, title); + String16 message16 = str16_from_8(scratch.arena, message); + MessageBoxW(0, (WCHAR *)message16.str, (WCHAR *)title16.str, MB_OK|(!!error*MB_ICONERROR)); + scratch_end(scratch); +} diff --git a/src/os/gfx/win32/os_gfx_win32.h b/src/os/gfx/win32/os_gfx_win32.h new file mode 100644 index 00000000..306c048d --- /dev/null +++ b/src/os/gfx/win32/os_gfx_win32.h @@ -0,0 +1,62 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef WIN32_GRAPHICAL_H +#define WIN32_GRAPHICAL_H + +#pragma comment(lib, "user32") +#pragma comment(lib, "gdi32") +#pragma comment(lib, "winmm") + +//////////////////////////////// +//~ rjf: Windows + +typedef struct W32_Window W32_Window; +struct W32_Window +{ + W32_Window *next; + W32_Window *prev; + HWND hwnd; + WINDOWPLACEMENT last_window_placement; + OS_WindowRepaintFunctionType *repaint; + void *repaint_user_data; + F32 dpi; + B32 first_paint_done; + B32 maximized; +}; + +//////////////////////////////// +//~ rjf: Monitor Gathering Bundle + +typedef struct W32_MonitorGatherBundle W32_MonitorGatherBundle; +struct W32_MonitorGatherBundle +{ + Arena *arena; + OS_HandleList *list; +}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal Rng2F32 w32_base_rect_from_win32_rect(RECT rect); + +//////////////////////////////// +//~ rjf: Windows + +internal OS_Handle os_window_from_w32_window(W32_Window *window); +internal W32_Window * w32_window_from_os_window(OS_Handle window); +internal W32_Window * w32_window_from_hwnd(HWND hwnd); +internal HWND w32_hwnd_from_window(W32_Window *window); +internal W32_Window * w32_allocate_window(void); +internal void w32_free_window(W32_Window *window); +internal OS_Event * w32_push_event(OS_EventKind kind, W32_Window *window); +internal OS_Key w32_os_key_from_vkey(WPARAM vkey); +internal WPARAM w32_vkey_from_os_key(OS_Key key); +internal LRESULT w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +//////////////////////////////// +//~ rjf: Monitors + +internal BOOL w32_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr); + +#endif // WIN32_GRAPHICAL_H diff --git a/src/os/os_inc.c b/src/os/os_inc.c new file mode 100644 index 00000000..8be65f0d --- /dev/null +++ b/src/os/os_inc.c @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Include OS features for extra features and target OS + +#include "core/os_core.c" + +#if OS_FEATURE_SOCKET +#include "socket/os_socket.c" +#endif + +#if OS_FEATURE_GRAPHICAL +#include "gfx/os_gfx.c" +#endif + +#if OS_WINDOWS +# include "core/win32/os_core_win32.c" +# if OS_FEATURE_SOCKET +# include "socket/win32/os_socket_win32.c" +# endif +# if OS_FEATURE_GRAPHICAL +# include "gfx/win32/os_gfx_win32.c" +# endif +#elif OS_LINUX +# include "core/linux/os_core_linux.c" +#else +# error no OS layer setup +#endif diff --git a/src/os/os_inc.h b/src/os/os_inc.h new file mode 100644 index 00000000..25d04243 --- /dev/null +++ b/src/os/os_inc.h @@ -0,0 +1,39 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef OS_INC_H +#define OS_INC_H + +#if !defined(OS_FEATURE_SOCKET) +# define OS_FEATURE_SOCKET 0 +#endif + +#if !defined(OS_FEATURE_GRAPHICAL) +# define OS_FEATURE_GRAPHICAL 0 +#endif + +#include "core/os_core.h" + +#if OS_FEATURE_SOCKET +#include "socket/os_socket.h" +#endif + +#if OS_FEATURE_GRAPHICAL +#include "gfx/os_gfx.h" +#endif + +#if OS_WINDOWS +# include "core/win32/os_core_win32.h" +# if OS_FEATURE_SOCKET +# include "socket/win32/os_socket_win32.h" +# endif +# if OS_FEATURE_GRAPHICAL +# include "gfx/win32/os_gfx_win32.h" +# endif +#elif OS_LINUX +# include "core/linux/os_core_linux.h" +#else +# error no OS layer setup +#endif + +#endif //OS_SWITCH_H diff --git a/src/os/socket/os_socket.c b/src/os/socket/os_socket.c new file mode 100644 index 00000000..dc2ef23a --- /dev/null +++ b/src/os/socket/os_socket.c @@ -0,0 +1,16 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// NOTE(allen): Helper + +internal B32 +os_socket_write(OS_Socket *socket, String8 data){ + String8Node node = {0}; + String8List list = {0}; + str8_list_push(&list, &node, data); + B32 result = os_socket_write(socket, list); + return(result); +} + +#endif diff --git a/src/os/socket/os_socket.h b/src/os/socket/os_socket.h new file mode 100644 index 00000000..b9a9a94b --- /dev/null +++ b/src/os/socket/os_socket.h @@ -0,0 +1,49 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef OS_SOCKET_H +#define OS_SOCKET_H + +enum OS_SocketStatus{ + OS_SocketStatus_Uninitialized, + OS_SocketStatus_Connected, + OS_SocketStatus_GracefullyClosed, + OS_SocketStatus_Error, +}; + +typedef U16 OS_SocketError; +enum{ + OS_SocketError_None, + OS_SocketError_SocketSystemNotInitialized, + OS_SocketError_BadPortArgument, + OS_SocketError_BadIPArgument, + OS_SocketError_WSAError, +}; + +struct OS_Socket{ + U8 memory[32]; +}; + + +//////////////////////////////// +//~ NOTE(allen): Implemented Per Operating System + +internal void os_socket_init(void); + +internal void os_socket_listen(OS_Socket *socket, String8 port); +internal void os_socket_connect(OS_Socket *socket, String8 ip, String8 port); +internal void os_socket_close(OS_Socket *socket); + +internal String8 os_socket_read(Arena *arena, OS_Socket *socket); +internal B32 os_socket_write(OS_Socket *socket, String8List list); + +internal B32 os_socket_status(OS_Socket *socket, OS_SocketStatus status); +internal String8 os_socket_error_string(Arena *arena, OS_Socket *socket); +internal void os_socket_assert_on_error(OS_Socket *socket, B32 assert_on_error); + +//////////////////////////////// +//~ NOTE(allen): Helpers - Portable Implementation + +internal B32 os_socket_write(OS_Socket *socket, String8 data); + +#endif //OS_SOCKET_H diff --git a/src/os/socket/win32/os_socket_win32.c b/src/os/socket/win32/os_socket_win32.c new file mode 100644 index 00000000..03218840 --- /dev/null +++ b/src/os/socket/win32/os_socket_win32.c @@ -0,0 +1,353 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Helpers + +internal void +w32_socket_set_error(W32_Socket *socket, OS_SocketError error){ + socket->error = error; + // NOTE(allen): This flag was set earlier so that the socket would assert + // when an error occurs. The "bug" or issue is whatever caused this error + // not the fact the flag is set. Unless the flag wasn't supposed to be set! + Assert(!(socket->flags & W32_SocketFlag_AssertOnError)); +} + +internal void +w32_socket_set_error_wsa(W32_Socket *socket, int wsa_error){ + switch (wsa_error){ + default: + { + socket->wsa_error = wsa_error; + w32_socket_set_error(socket, OS_SocketError_WSAError); + }break; + case WSANOTINITIALISED: + { + w32_socket_set_error(socket, OS_SocketError_SocketSystemNotInitialized); + }break; + } +} + +internal B32 +w32_socket_read_looped(W32_Socket *w32_socket, void *buffer, U32 size){ + U32 p = 0; + CHAR *ptr = (CHAR*)buffer; + for (;p < size;){ + DWORD amt = (DWORD)(size - p); + WSABUF wsabuf = {amt, ptr}; + // NOTE(allen): The flags pointer is _NOT_ optional but we can ignore it. + // We have to zero it because it's an in/out pointer. + DWORD ignore = 0; + if (WSARecv(w32_socket->socket, &wsabuf, 1, &amt, &ignore, 0, 0) != 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + break; + } + if (amt == 0){ + w32_socket->flags |= W32_SocketFlag_Closed; + break; + } + p += amt; + ptr += amt; + } + B32 result = (p == size); + return(result); +} + +//////////////////////////////// +//~ rjf: Per-OS Hook Implementations + +internal void +os_socket_init(void){ + WSADATA wsaData; + WORD vreq = MAKEWORD(2,2); + WSAStartup(vreq, &wsaData); +} + +internal void +os_socket_listen(OS_Socket *s, String8 port){ + W32_Socket *w32_socket = (W32_Socket*)s->memory; + + // NOTE(allen): check port string + char port_buffer[6]; + if (port.size == 0 || port.size >= sizeof(port_buffer)){ + w32_socket_set_error(w32_socket, OS_SocketError_BadPortArgument); + return; + } + MemoryCopy(port_buffer, port.str, port.size); + port_buffer[port.size] = 0; + + // NOTE(allen): listen socket addrinfo + addrinfo listen_hint = {0}; + listen_hint.ai_flags = AI_PASSIVE|AI_NUMERICSERV; + listen_hint.ai_family = AF_UNSPEC; + listen_hint.ai_socktype = SOCK_STREAM; + listen_hint.ai_protocol = AF_UNSPEC; + + addrinfo *addr = {0}; + INT error = getaddrinfo(0, port_buffer, &listen_hint, &addr); + if (error != 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + + // NOTE(allen): init listen socket + SOCKET socket_listener = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + W32_SocketCloser listener_closer(&socket_listener); + + // NOTE(allen): reuseraddr + { + union { B32 b; char c[1]; } enable; + enable.b = true; + if (setsockopt(socket_listener, SOL_SOCKET, SO_REUSEADDR, enable.c, sizeof(enable)) < 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + } + + // NOTE(allen): bind + if (bind(socket_listener, addr->ai_addr, (int)addr->ai_addrlen) < 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + + // NOTE(allen): listen + if (listen(socket_listener, 1) < 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + + // NOTE(allen): accept + SOCKET client_socket = accept(socket_listener, 0, 0); + W32_SocketCloser client_closer(&client_socket); + + // NOTE(allen): TCP_NODELAY + { + union { B32 b; char c[1]; } enable; + enable.b = true; + if (setsockopt(client_socket, IPPROTO_TCP, TCP_NODELAY, enable.c, sizeof(enable)) < 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + } + + // NOTE(allen): success + w32_socket->flags |= W32_SocketFlag_Connected; + w32_socket->socket = client_socket; + w32_socket->error = OS_SocketError_None; + client_closer.do_not_close(); +} + +internal void +os_socket_connect(OS_Socket *s, String8 ip, String8 port){ + W32_Socket *w32_socket = (W32_Socket*)s->memory; + + // NOTE(allen): check port string + char port_buffer[6]; + if (port.size == 0 || port.size >= sizeof(port_buffer)){ + w32_socket_set_error(w32_socket, OS_SocketError_BadPortArgument); + return; + } + MemoryCopy(port_buffer, port.str, port.size); + port_buffer[port.size] = 0; + + // NOTE(allen): check ip string + if (ip.size == 0){ + ip = str8_lit("localhost"); + } + char ip_buffer[KB(1)]; + if (ip.size >= sizeof(ip_buffer)){ + w32_socket_set_error(w32_socket, OS_SocketError_BadIPArgument); + return; + } + MemoryCopy(ip_buffer, ip.str, ip.size); + ip_buffer[ip.size] = 0; + + // NOTE(allen): socket addrinfo + addrinfo hint = {0}; + hint.ai_flags = AI_PASSIVE|AI_NUMERICSERV; + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = AF_UNSPEC; + + addrinfo *addr = {0}; + INT error = getaddrinfo(ip_buffer, port_buffer, &hint, &addr); + if (error != 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + + // NOTE(allen): init socket + SOCKET socket_server = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + W32_SocketCloser closer(&socket_server); + + // NOTE(allen): TCP_NODELAY + { + union { B32 b; char c[1]; } enable; + enable.b = true; + if (setsockopt(socket_server, IPPROTO_TCP, TCP_NODELAY, enable.c, sizeof(enable)) < 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + } + + // NOTE(allen): connect + if (connect(socket_server, addr->ai_addr, (int)addr->ai_addrlen) < 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + return; + } + + // NOTE(allen): success + w32_socket->flags |= W32_SocketFlag_Connected; + w32_socket->socket = socket_server; + w32_socket->error = OS_SocketError_None; + closer.do_not_close(); +} + +internal void +os_socket_close(OS_Socket *socket){ + W32_Socket *w32_socket = (W32_Socket*)socket->memory; + closesocket(w32_socket->socket); + MemoryZeroStruct(w32_socket); +} + +internal String8 +os_socket_read(Arena *arena, OS_Socket *socket){ + W32_Socket *w32_socket = (W32_Socket*)socket->memory; + String8 result = {0}; + U32 size = 0; + if (w32_socket_read_looped(w32_socket, &size, sizeof(size))){ + Temp restore = temp_begin(arena); + result.str = push_array_no_zero(arena, U8, size); + if (w32_socket_read_looped(w32_socket, result.str, size)){ + result.size = size; + } + else{ + temp_end(restore); + result.str = 0; + } + } + return(result); +} + +internal B32 +os_socket_write(OS_Socket *socket, String8List list){ + U32 size = (U32)list.total_size; + String8Node node = {0}; + str8_list_push_front(&list, &node, str8_struct(&size)); + + W32_Socket *w32_socket = (W32_Socket*)socket->memory; + + WSABUF wsabuf[64]; + Assert(list.node_count <= ArrayCount(wsabuf)); + + U64 wsabuf_count = 0; + for (String8Node *node = list.first; + node != 0; + node = node->next){ + wsabuf[wsabuf_count].len = (U32)node->string.size; + wsabuf[wsabuf_count].buf = (CHAR*)node->string.str; + wsabuf_count += 1; + } + + B32 result = false; + DWORD amt = 0; + if (WSASend(w32_socket->socket, wsabuf, wsabuf_count, &amt, 0, 0, 0) != 0){ + w32_socket_set_error_wsa(w32_socket, WSAGetLastError()); + } + else if (amt == 0){ + w32_socket->flags |= W32_SocketFlag_Connected; + } + else{ + result = true; + } + + return(result); +} + +internal B32 +os_socket_status(OS_Socket *socket, OS_SocketStatus status){ + W32_Socket *w32_socket = (W32_Socket*)socket; + B32 result = false; + switch (status){ + case OS_SocketStatus_Uninitialized: + { + result = (((w32_socket->flags & (W32_SocketFlag_Connected|W32_SocketFlag_Closed)) == 0) && + (w32_socket->error == 0)); + }break; + + case OS_SocketStatus_Connected: + { + result = (((w32_socket->flags & (W32_SocketFlag_Connected|W32_SocketFlag_Closed)) == W32_SocketFlag_Connected) && + (w32_socket->error == 0)); + }break; + + case OS_SocketStatus_GracefullyClosed: + { + result = (((w32_socket->flags & W32_SocketFlag_Closed) == W32_SocketFlag_Closed) && (w32_socket->error == 0)); + }break; + + case OS_SocketStatus_Error: + { + result = (w32_socket->error != 0); + }break; + } + return(result); +} + +internal String8 +os_socket_error_string(Arena *arena, OS_Socket *socket){ + String8 result = str8_lit("no error"); + + W32_Socket *w32_socket = (W32_Socket*)socket; + switch (w32_socket->error){ + default: + { + result = str8_lit("Bad error code"); + }break; + + case OS_SocketError_None:break; + + case OS_SocketError_SocketSystemNotInitialized: + { + result = str8_lit("Missing call to os_socket_init"); + }break; + + case OS_SocketError_BadPortArgument: + { + result = str8_lit("Invalid port argument to socket API"); + }break; + + case OS_SocketError_BadIPArgument: + { + result = str8_lit("Invalid ip argument to socket API"); + }break; + + case OS_SocketError_WSAError: + { + DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM; + CHAR *message = 0; + DWORD size = FormatMessageA(flags, 0, w32_socket->wsa_error, 0, (CHAR*)&message, 0, 0); + if (size == 0){ + result = str8_lit("Unknown WSA error"); + } + else{ + String8 string = str8_skip_chop_whitespace(str8((U8*)message, size)); + result = push_str8_copy(arena, string); + LocalFree(message); + } + }break; + } + + return(result); +} + +internal void +os_socket_assert_on_error(OS_Socket *socket, B32 assert_on_error){ + W32_Socket *w32_socket = (W32_Socket*)socket; + if (assert_on_error){ + w32_socket->flags |= W32_SocketFlag_AssertOnError; + } + else{ + w32_socket->flags &= ~W32_SocketFlag_AssertOnError; + } +} diff --git a/src/os/socket/win32/os_socket_win32.h b/src/os/socket/win32/os_socket_win32.h new file mode 100644 index 00000000..6f6ad766 --- /dev/null +++ b/src/os/socket/win32/os_socket_win32.h @@ -0,0 +1,54 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef WIN32_SOCKET_H +#define WIN32_SOCKET_H + +//////////////////////////////// +//~ rjf: Types + +typedef U16 W32_SocketFlags; +enum{ + W32_SocketFlag_Connected = (1 << 0), + W32_SocketFlag_Closed = (1 << 1), + W32_SocketFlag_AssertOnError = (1 << 2), +}; + +struct W32_Socket{ + W32_SocketFlags flags; + OS_SocketError error; + int wsa_error; + SOCKET socket; +}; + +struct W32_SocketCloser{ + B32 need_to_close; + SOCKET *socket; + W32_SocketCloser(SOCKET *s){ + this->need_to_close = true; + this->socket = s; + } + ~W32_SocketCloser(){ + this->close_now(); + } + void close_now(){ + if (this->need_to_close){ + closesocket(*this->socket); + this->need_to_close = false; + } + } + void do_not_close(){ + this->need_to_close = false; + } +}; + +StaticAssert(sizeof(Member(OS_Socket, memory)) >= sizeof(W32_Socket), socket_memory_size); + +//////////////////////////////// +//~ rjf: Helpers + +internal void w32_socket_set_error(W32_Socket *socket, OS_SocketError error); +internal void w32_socket_set_error_wsa(W32_Socket *socket, int wsa_error); +internal B32 w32_socket_read_looped(W32_Socket *w32_socket, void *buffer, U32 size); + +#endif // WIN32_SOCKET_H diff --git a/src/path/path.c b/src/path/path.c new file mode 100644 index 00000000..d80a5d69 --- /dev/null +++ b/src/path/path.c @@ -0,0 +1,167 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ allen: Path Helper Functions + +internal StringMatchFlags +path_match_flags_from_os(OperatingSystem os) +{ + StringMatchFlags flags = StringMatchFlag_SlashInsensitive; + switch(os) + { + default:{}break; + case OperatingSystem_Windows: + { + flags |= StringMatchFlag_CaseInsensitive; + }break; + case OperatingSystem_Linux: + case OperatingSystem_Mac: + { + // NOTE(rjf): no-op + }break; + } + return flags; +} + +internal String8 +path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src) +{ + Temp scratch = scratch_begin(&arena, 1); + + // rjf: gather path parts + String8 dst_name = str8_skip_last_slash(dst); + String8 src_folder = str8_chop_last_slash(src); + String8 dst_folder = str8_chop_last_slash(dst); + String8List src_folders = str8_split_path(scratch.arena, src_folder); + String8List dst_folders = str8_split_path(scratch.arena, dst_folder); + + // rjf: count # of backtracks to get from src -> dest + U64 num_backtracks = src_folders.node_count; + for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first; + src_n != 0 && bp_n != 0; + src_n = src_n->next, bp_n = bp_n->next) + { + if(str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context()))) + { + num_backtracks -= 1; + } + else + { + break; + } + } + + // rjf: only build relative string if # of backtracks is not the entire `src`. + // if getting to `dst` from `src` requires erasing the entire `src`, then the + // only possible way to get to `dst` from `src` is via absolute path. + String8 dst_path = {0}; + if(num_backtracks >= src_folders.node_count) + { + dst_path = path_normalized_from_string(arena, dst); + } + else + { + // rjf: build backtrack parts + String8List dst_path_strs = {0}; + for(U64 idx = 0; idx < num_backtracks; idx += 1) + { + str8_list_push(scratch.arena, &dst_path_strs, str8_lit("..")); + } + + // rjf: build parts of dst which are unique from src + { + B32 unique_from_src = 0; + for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first; + bp_n != 0; + bp_n = bp_n->next) + { + if(!unique_from_src && (src_n == 0 || !str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context())))) + { + unique_from_src = 1; + } + if(unique_from_src) + { + str8_list_push(scratch.arena, &dst_path_strs, bp_n->string); + } + if(src_n != 0) + { + src_n = src_n->next; + } + } + } + + // rjf: build file name + str8_list_push(scratch.arena, &dst_path_strs, dst_name); + + // rjf: join + StringJoin join = {0}; + { + join.sep = str8_lit("/"); + } + dst_path = str8_list_join(arena, &dst_path_strs, &join); + } + scratch_end(scratch); + return dst_path; +} + +internal String8 +path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src) +{ + String8 result = dst; + PathStyle dst_style = path_style_from_str8(dst); + if(dst_style == PathStyle_Relative) + { + Temp scratch = scratch_begin(&arena, 1); + String8 dst_from_src_absolute = push_str8f(scratch.arena, "%S/%S", src, dst); + String8 dst_from_src_absolute_normalized = path_normalized_from_string(arena, dst_from_src_absolute); + result = dst_from_src_absolute_normalized; + scratch_end(scratch); + } + return result; +} + +internal String8List +path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out){ + // analyze path + PathStyle path_style = path_style_from_str8(path_string); + String8List path = str8_split_path(arena, path_string); + + // prepend current path to convert relative -> absolute + PathStyle path_style_full = path_style; + if (path.node_count != 0 && path_style == PathStyle_Relative){ + String8List current_path_strs = {0}; + os_string_list_from_system_path(arena, OS_SystemPath_Current, ¤t_path_strs); + String8 current_path_string = str8_list_first(¤t_path_strs); + + PathStyle current_path_style = path_style_from_str8(current_path_string); + Assert(current_path_style != PathStyle_Relative); + + String8List current_path = str8_split_path(arena, current_path_string); + str8_list_concat_in_place(¤t_path, &path); + path = current_path; + path_style_full = current_path_style; + } + + // resolve dots + str8_path_list_resolve_dots_in_place(&path, path_style_full); + + // return + if (style_out != 0){ + *style_out = path_style_full; + } + return(path); +} + +internal String8 +path_normalized_from_string(Arena *arena, String8 path_string){ + Temp scratch = scratch_begin(&arena, 1); + + PathStyle style = PathStyle_Relative; + String8List path = path_normalized_list_from_string(scratch.arena, path_string, &style); + + String8 result = str8_path_list_join_by_style(arena, &path, style); + scratch_end(scratch); + return(result); +} + diff --git a/src/path/path.h b/src/path/path.h new file mode 100644 index 00000000..6455386c --- /dev/null +++ b/src/path/path.h @@ -0,0 +1,16 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef PATH_H +#define PATH_H + +//////////////////////////////// +//~ allen: Path Helper Functions + +internal StringMatchFlags path_match_flags_from_os(OperatingSystem os); +internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src); +internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src); +internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out); +internal String8 path_normalized_from_string(Arena *arena, String8 path); + +#endif //PATH_H diff --git a/src/pe/dos_program.asm b/src/pe/dos_program.asm new file mode 100644 index 00000000..39c47cc5 --- /dev/null +++ b/src/pe/dos_program.asm @@ -0,0 +1,17 @@ +; Copyright (c) 2024 Epic Games Tools +; Licensed under the MIT license (https://opensource.org/license/mit/) +; $ c:\devel\projects\bin\win32\nasm src\pe\dos_program.asm -fbin -o dos_program.bin + +BITS 16 + +SEGMENT CODE + push cs ; copy psp segment address to ds + pop ds + mov dx, msg ; set print string + mov ah, 9h ; print to stdout + int 21h + mov ax, 0x4c01 ; terminate with return code 1 in al + int 0x21 + +msg: DB "This program cannot be run in DOS mode.$",0 +ALIGN 8, DB diff --git a/src/pe/pe.c b/src/pe/pe.c new file mode 100644 index 00000000..c41e2d0b --- /dev/null +++ b/src/pe/pe.c @@ -0,0 +1,808 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Parser Functions + +internal PE_BinInfo +pe_bin_info_from_data(Arena *arena, String8 data) +{ + PE_BinInfo info = {0}; + B32 valid = 1; + + // rjf: read dos header + PE_DosHeader dos_header = {0}; + str8_deserial_read_struct(data, 0, &dos_header); + + // rjf: bad dos magic -> bad + if(dos_header.magic != PE_DOS_MAGIC) + { + valid = 0; + } + + // rjf: read pe magic + U32 coff_off = dos_header.coff_file_offset; + U32 pe_magic = 0; + if(valid) + { + str8_deserial_read_struct(data, coff_off, &pe_magic); + } + + // rjf: bad pe magic -> abort + if(pe_magic != PE_MAGIC) + { + valid = 0; + } + + // rjf: read coff header + U32 coff_header_off = coff_off + sizeof(pe_magic); + COFF_Header coff_header = {0}; + if(valid) + { + str8_deserial_read_struct(data, coff_header_off, &coff_header); + } + + // rjf: range of optional extension header ("optional" for short) + U32 optional_size = coff_header.optional_header_size; + U64 after_coff_header_off = coff_header_off + sizeof(coff_header); + U64 after_optional_header_off = after_coff_header_off + optional_size; + Rng1U64 optional_range = {0}; + if(valid) + { + optional_range.min = ClampTop(after_coff_header_off, data.size); + optional_range.max = ClampTop(after_optional_header_off, data.size); + } + + // rjf: get sections + U64 sec_array_off = optional_range.max; + U64 sec_array_raw_opl = sec_array_off + coff_header.section_count*sizeof(COFF_SectionHeader); + U64 sec_array_opl = ClampTop(sec_array_raw_opl, data.size); + U64 clamped_sec_count = (sec_array_opl - sec_array_off)/sizeof(COFF_SectionHeader); + COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str + sec_array_off); + + // rjf: get symbols + U64 symbol_array_off = coff_header.symbol_table_foff; + U64 symbol_count = coff_header.symbol_count; + + // rjf: get string table + U64 string_table_off = symbol_array_off + sizeof(COFF_Symbol16) * symbol_count; + + // rjf: read optional header + U16 optional_magic = 0; + U64 image_base = 0; + U64 entry_point = 0; + U32 data_dir_count = 0; + U64 virt_section_align = 0; + U64 file_section_align = 0; + Rng1U64 *data_dir_franges = 0; + if(valid && optional_size > 0) + { + // rjf: read magic number + str8_deserial_read_struct(data, optional_range.min, &optional_magic); + + // rjf: read info + U32 reported_data_dir_offset = 0; + U32 reported_data_dir_count = 0; + switch(optional_magic) + { + case PE_PE32_MAGIC: + { + PE_OptionalHeader32 pe_optional = {0}; + str8_deserial_read_struct(data, optional_range.min, &pe_optional); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + case PE_PE32PLUS_MAGIC: + { + PE_OptionalHeader32Plus pe_optional = {0}; + str8_deserial_read_struct(data, optional_range.min, &pe_optional); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + } + + // rjf: find file ranges of data directories + U32 data_dir_max = (optional_size - reported_data_dir_offset) / sizeof(PE_DataDirectory); + data_dir_count = ClampTop(reported_data_dir_count, data_dir_max); + + // rjf: convert PE directories to ranges + data_dir_franges = push_array(arena, Rng1U64, data_dir_count); + for(U32 dir_idx = 0; dir_idx < data_dir_count; dir_idx += 1) + { + U64 dir_offset = optional_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*dir_idx; + PE_DataDirectory dir = {0}; + str8_deserial_read_struct(data, dir_offset, &dir); + U64 file_off = coff_foff_from_voff(sections, clamped_sec_count, dir.virt_off); + data_dir_franges[dir_idx] = r1u64(file_off, file_off+dir.virt_size); + } + } + + // rjf: read info about debug file + U32 dbg_time = 0; + U32 dbg_age = 0; + OS_Guid dbg_guid = {0}; + U64 dbg_path_off = 0; + U64 dbg_path_size = 0; + if(valid && PE_DataDirectoryIndex_DEBUG < data_dir_count) + { + // rjf: read debug directory + PE_DebugDirectory dbg_data = {0}; + str8_deserial_read_struct(data, data_dir_franges[PE_DataDirectoryIndex_DEBUG].min, &dbg_data); + + // rjf: extract external file info from codeview header + if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW) + { + U64 cv_offset = dbg_data.foff; + U32 cv_magic = 0; + str8_deserial_read_struct(data, cv_offset, &cv_magic); + switch(cv_magic) + { + default:break; + case PE_CODEVIEW_PDB20_MAGIC: + { + PE_CvHeaderPDB20 cv = {0}; + str8_deserial_read_struct(data, cv_offset, &cv); + dbg_time = cv.time; + dbg_age = cv.age; + dbg_path_off = cv_offset + sizeof(cv); + }break; + case PE_CODEVIEW_PDB70_MAGIC: + { + PE_CvHeaderPDB70 cv = {0}; + str8_deserial_read_struct(data, cv_offset, &cv); + dbg_guid = cv.guid; + dbg_age = cv.age; + dbg_path_off = cv_offset + sizeof(cv); + }break; + } + if(dbg_path_off > 0) + { + U8 *dbg_path_cstring_base = data.str+dbg_path_off; + dbg_path_size = cstring8_length(dbg_path_cstring_base); + } + } + } + + // rjf: extract tls header + PE_TLSHeader64 tls_header = {0}; + if(valid && PE_DataDirectoryIndex_TLS < data_dir_count) + { + Rng1U64 tls_header_frng = data_dir_franges[PE_DataDirectoryIndex_TLS]; + switch(coff_header.machine) + { + default:{}break; + case COFF_MachineType_X86: + { + PE_TLSHeader32 tls_header32 = {0}; + str8_deserial_read_struct(data, tls_header_frng.min, &tls_header32); + tls_header.raw_data_start = (U64)tls_header32.raw_data_start; + tls_header.raw_data_end = (U64)tls_header32.raw_data_end; + tls_header.index_address = (U64)tls_header32.index_address; + tls_header.callbacks_address = (U64)tls_header32.callbacks_address; + tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; + tls_header.characteristics = (U64)tls_header32.characteristics; + }break; + case COFF_MachineType_X64: + { + str8_deserial_read_struct(data, tls_header_frng.min, &tls_header); + }break; + } + } + + // rjf: fill info + if(valid) + { + info.image_base = image_base; + info.entry_point = entry_point; + info.is_pe32 = (optional_magic == PE_PE32_MAGIC); + info.virt_section_align = virt_section_align; + info.file_section_align = file_section_align; + info.section_array_off = sec_array_off; + info.section_count = clamped_sec_count; + info.symbol_array_off = symbol_array_off; + info.symbol_count = symbol_count; + info.string_table_off = string_table_off; + info.dbg_path_off = dbg_path_off; + info.dbg_path_size = dbg_path_size; + info.dbg_guid = dbg_guid; + info.dbg_age = dbg_age; + info.dbg_time = dbg_time; + info.data_dir_franges = data_dir_franges; + info.data_dir_count = data_dir_count; + switch(coff_header.machine) + { + default:{}break; + case COFF_MachineType_X86: {info.arch = Architecture_x86;}break; + case COFF_MachineType_X64: {info.arch = Architecture_x64;}break; + case COFF_MachineType_ARM: {info.arch = Architecture_arm32;}break; + case COFF_MachineType_ARM64: {info.arch = Architecture_arm64;}break; + } + MemoryCopyStruct(&info.tls_header, &tls_header); + } + return info; +} + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 +pe_intel_pdata_off_from_voff__binary_search(String8 data, PE_BinInfo *bin, U64 voff) +{ + // TODO(allen): cleanup pass. + Assert(bin->arch == Architecture_x86 || bin->arch == Architecture_x64); + Rng1U64 range = bin->data_dir_franges[PE_DataDirectoryIndex_EXCEPTIONS]; + U64 pdata_off = range.min; + U64 pdata_count = (range.max - range.min)/sizeof(PE_IntelPdata); + + U64 result = 0; + + // check if this bin includes a pdata array + if(pdata_count > 0) + { + PE_IntelPdata *pdata_array = (PE_IntelPdata*)(data.str + pdata_off); + if(voff >= pdata_array[0].voff_first) + { + // binary search: + // find max index s.t. pdata_array[index].voff_first <= voff + // we assume (i < j) -> (pdata_array[i].voff_first < pdata_array[j].voff_first) + U64 index = pdata_count; + U64 min = 0; + U64 opl = pdata_count; + for(;;) + { + U64 mid = (min + opl)/2; + PE_IntelPdata *pdata = pdata_array + mid; + if(voff < pdata->voff_first) + { + opl = mid; + } + else if(pdata->voff_first < voff) + { + min = mid; + } + else + { + index = mid; + break; + } + if(min + 1 >= opl) + { + index = min; + break; + } + } + + // if we are in range fill result + { + PE_IntelPdata *pdata = pdata_array + index; + if(pdata->voff_first <= voff && voff < pdata->voff_one_past_last) + { + result = pdata_off + index*sizeof(PE_IntelPdata); + } + } + } + } + return(result); +} + +internal void * +pe_ptr_from_voff(String8 data, PE_BinInfo *bin, U64 voff) +{ + // rjf: get the section for this voff + U64 sec_count = bin->section_count; + COFF_SectionHeader *sec_array = (COFF_SectionHeader*)((U8*)data.str + bin->section_array_off); + COFF_SectionHeader *sec_ptr = sec_array; + COFF_SectionHeader *sec = 0; + for(U64 i = 1; i <= sec_count; i += 1, sec_ptr += 1) + { + if(sec_ptr->voff <= voff && voff < sec_ptr->voff + sec_ptr->vsize) + { + sec = sec_ptr; + break; + } + } + + // rjf: adjust to file pointer + void *result = 0; + if(sec != 0 && sec_ptr->fsize > 0) + { + U64 off = voff - sec->voff + sec->foff; + if(off < data.size) + { + result = data.str + off; + } + } + return result; +} + +internal U64 +pe_section_num_from_voff(String8 data, PE_BinInfo *bin, U64 voff) +{ + U64 sec_count = bin->section_count; + COFF_SectionHeader *sec_array = (COFF_SectionHeader*)((U8*)data.str + bin->section_array_off); + COFF_SectionHeader *sec_ptr = sec_array; + U64 result = 0; + for(U64 i = 1; i <= sec_count; i += 1, sec_ptr += 1) + { + if(sec_ptr->voff <= voff && voff < sec_ptr->voff + sec_ptr->vsize) + { + result = i; + break; + } + } + return result; +} + +internal void * +pe_ptr_from_section_num(String8 data, PE_BinInfo *bin, U64 n) +{ + void *result = 0; + U64 sec_count = bin->section_count; + if(1 <= n && n <= sec_count) + { + COFF_SectionHeader *sec_array = (COFF_SectionHeader*)((U8*)data.str + bin->section_array_off); + COFF_SectionHeader *sec = sec_array + n - 1; + if(sec->fsize > 0) + { + result = data.str + sec->foff; + } + } + return(result); +} + +internal U64 +pe_foff_from_voff(String8 data, PE_BinInfo *bin, U64 voff) +{ + U64 foff = 0; + COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str+bin->section_array_off); + U64 section_count = bin->section_count; + for(U64 sect_idx = 0; sect_idx < section_count; sect_idx += 1) + { + COFF_SectionHeader *sect = §ions[sect_idx]; + if(sect->voff <= voff && voff < sect->voff + sect->vsize) + { + if(!(sect->flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA)) + { + foff = sect->foff + (voff - sect->voff); + } + break; + } + } + return foff; +} + +internal PE_BaseRelocBlockList +pe_base_reloc_block_list_from_bin(Arena *arena, String8 data, PE_BinInfo *bin) +{ + PE_BaseRelocBlockList list = {0}; + Rng1U64 base_reloc_range = bin->data_dir_franges[PE_DataDirectoryIndex_BASE_RELOC]; + U64 range_dim = dim_1u64(base_reloc_range); + for(U64 off = base_reloc_range.min; off < range_dim;) + { + // rjf: read next entry + U32 page_virt_off = 0; + U32 block_size = 0; + off += str8_deserial_read_struct(data, off, &page_virt_off); + off += str8_deserial_read_struct(data, off, &block_size); + + // rjf: break on sentinel + if(block_size == 0) + { + break; + } + + // rjf: add node + PE_BaseRelocBlockNode *node = push_array(arena, PE_BaseRelocBlockNode, 1); + SLLQueuePush(list.first, list.last, node); + list.count += 1; + + // rjf: fill block + PE_BaseRelocBlock *block = &node->v; + U64 entries_size = block_size - (sizeof(block_size) + sizeof(page_virt_off)); + block->page_virt_off = page_virt_off; + block->entry_count = entries_size / sizeof(U16); + block->entries = push_array(arena, U16, block->entry_count); + off += str8_deserial_read_array(data, off, &block->entries[0], entries_size); + } + return list; +} + +internal Rng1U64 +pe_tls_rng_from_bin_base_vaddr(String8 data, PE_BinInfo *bin, U64 base_vaddr) +{ + U64 result_addr = (bin->tls_header.index_address - bin->image_base); + U64 result_size = sizeof(U32); + if(bin->arch != Architecture_Null) + { + U64 addr_size = bit_size_from_arch(bin->arch)/8; + Temp scratch = scratch_begin(0, 0); + PE_BaseRelocBlockList relocs = pe_base_reloc_block_list_from_bin(scratch.arena, data, bin); + for(PE_BaseRelocBlockNode *n = relocs.first; n != 0; n = n->next) + { + PE_BaseRelocBlock *block = &n->v; + for(U64 ientry = 0; ientry < block->entry_count;) + { + U32 reloc = block->entries[ientry]; + U16 kind = PE_BaseRelocKindFromEntry(reloc); + U16 offset = PE_BaseRelocOffsetFromEntry(reloc); + U64 apply_to_voff = block->page_virt_off + offset; + U64 apply_to_foff = pe_foff_from_voff(data, bin, apply_to_voff); + U64 apply_to = 0; + str8_deserial_read(data, apply_to_foff, &apply_to, addr_size, 1); + if(apply_to == bin->tls_header.index_address) + { + U64 base_diff = base_vaddr-bin->image_base; + switch(kind) + { + default: + { + // NOTE(rjf): these relocs are arm/mips/riscv specific which aren't supported at the moment + }break; + case PE_BaseRelocKind_ABSOLUTE:{}break; + case PE_BaseRelocKind_HIGH: + { + // rjf: relocate high 16-bits. + U64 high_bits = (apply_to & max_U16) << 16; + result_addr = (high_bits + ((base_diff & max_U32) >> 16)) & max_U16; + }break; + case PE_BaseRelocKind_LOW: + { + // rjf: relocate low 16-bits. + U64 low_bits = apply_to & max_U16; + result_addr = (low_bits + (base_diff & max_U32)) & max_U16; + }break; + case PE_BaseRelocKind_HIGHLOW: + { + // rjf: relocate 32-bits. + result_addr = (apply_to & max_U32) + (base_diff & max_U32); + }break; + case PE_BaseRelocKind_HIGHADJ: + { + if(ientry + 1 >= block->entry_count) + { + // NOTE(rjf): malformed relocation, expected two 16-bit entries + break; + } + + // rjf: relocate high bits and adjust sign bit on lower half. + U16 adj_offset = PE_BaseRelocOffsetFromEntry(block->entries[ientry + 1]); + result_addr = (apply_to & max_U16) << 16; + result_addr += adj_offset; + result_addr += (base_diff & max_U32); + result_addr += 0x8000; + result_addr = (result_addr >> 16) & max_U16; + }break; + case PE_BaseRelocKind_DIR64: + { + // rjf: image base relocation. + result_addr = apply_to + base_diff; + }break; + } + + goto dbl_break; + } + + U32 advance = (kind == PE_BaseRelocKind_HIGHADJ) ? 2 : 1; + ientry += advance; + } + } + dbl_break:; + scratch_end(scratch); + } + Rng1U64 result = r1u64(result_addr, result_addr+result_size); + return result; +} + +//////////////////////////////// + +internal B32 +pe_is_res(String8 data) +{ + U8 magic[sizeof(PE_RES_MAGIC)]; MemoryZeroStruct(&magic); + str8_deserial_read_struct(data, 0, &magic); + B32 is_res = MemoryCompare(&PE_RES_MAGIC, &magic, sizeof(magic)) == 0; + return is_res; +} + +internal PE_ResourceNode * +pe_resource_dir_push_dir_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, U32 characteristics, COFF_TimeStamp time_stamp, U16 major_version, U16 minor_version) +{ + PE_ResourceList *list = 0; + switch (id.type) { + default: + case COFF_ResourceIDType_NULL: break; + case COFF_ResourceIDType_STRING: list = &dir->named_list; break; + case COFF_ResourceIDType_NUMBER: list = &dir->id_list; break; + } + + PE_ResourceNode *res_node = push_array(arena, PE_ResourceNode, 1); + SLLQueuePush(list->first, list->last, res_node); + list->count += 1; + + PE_ResourceDir *sub_dir = push_array(arena, PE_ResourceDir, 1); + sub_dir->characteristics = characteristics; + sub_dir->time_stamp = time_stamp; + sub_dir->major_version = major_version; + sub_dir->minor_version = minor_version; + + PE_Resource *res = &res_node->data; + res->id = id; + res->type = PE_ResData_DIR; + res->u.dir = sub_dir; + + return res_node; +} + +internal PE_ResourceNode * +pe_resource_dir_push_entry_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, COFF_ResourceID type, U32 data_version, U32 version, COFF_ResourceMemoryFlags memory_flags, String8 data) +{ + PE_ResourceList *list = NULL; + switch (id.type) { + default: + case COFF_ResourceIDType_NULL: break; + case COFF_ResourceIDType_STRING: list = &dir->named_list; break; + case COFF_ResourceIDType_NUMBER: list = &dir->id_list; break; + } + + PE_ResourceNode *res_node = push_array(arena, PE_ResourceNode, 1); + SLLQueuePush(list->first, list->last, res_node); + list->count += 1; + + PE_Resource *res = &res_node->data; + res->id = id; + res->type = PE_ResData_COFF_RESOURCE; + res->u.coff_res.type = type; + res->u.coff_res.data_version = data_version; + res->u.coff_res.version = version; + res->u.coff_res.memory_flags = memory_flags; + res->u.coff_res.data = data; + + return res_node; +} + +internal PE_Resource * +pe_resource_dir_push_entry(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, COFF_ResourceID type, U32 data_version, U32 version, COFF_ResourceMemoryFlags memory_flags, String8 data) +{ + PE_ResourceNode *node = pe_resource_dir_push_entry_node(arena, dir, id, type, data_version, version, memory_flags, data); + return &node->data; +} + +internal PE_Resource * +pe_resource_dir_push_dir(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, U32 characteristics, COFF_TimeStamp time_stamp, U16 major_version, U16 minor_version) +{ + PE_ResourceNode *dir_node = pe_resource_dir_push_dir_node(arena, dir, id, characteristics, time_stamp, major_version, minor_version); + return &dir_node->data; +} + +internal PE_ResourceNode * +pe_resource_dir_search_node(PE_ResourceDir *dir, COFF_ResourceID id) +{ + for (PE_ResourceNode *i = dir->id_list.first; i != NULL; i = i->next) { + if (coff_resource_id_is_equal(i->data.id, id)) { + return i; + } + } + return NULL; +} + +internal PE_Resource * +pe_resource_dir_search(PE_ResourceDir *dir, COFF_ResourceID id) +{ + PE_ResourceNode *node = pe_resource_dir_search_node(dir, id); + return node ? &node->data : NULL; +} + +internal PE_ResourceArray +pe_resource_list_to_array(Arena *arena, PE_ResourceList *list) +{ + PE_ResourceArray result; + result.count = 0; + result.v = push_array(arena, PE_Resource, list->count); + for (PE_ResourceNode *n = list->first; n != NULL; n = n->next) { + result.v[result.count++] = n->data; + } + return result; +} + +internal void +pe_resource_dir_push_res_file(Arena *arena, PE_ResourceDir *root_dir, String8 res_file) +{ + // parse file into resource list + String8 res_data = str8_substr(res_file, rng_1u64(sizeof(PE_RES_MAGIC), res_file.size)); + COFF_ResourceList list = coff_resource_list_from_data(arena, res_data); + + // move resources to directories based on type + for (COFF_ResourceNode *res_node = list.first; res_node != NULL; res_node = res_node->next) { + COFF_Resource *res = &res_node->data; + + // search existing directories + PE_Resource *dir_res = pe_resource_dir_search(root_dir, res->type); + + // create new directory + if (dir_res == NULL) { + dir_res = pe_resource_dir_push_dir(arena, root_dir, res->type, 0, 0, 0, 0); + } + PE_ResourceDir *dir = dir_res->u.dir; + + // check for name collisions + PE_Resource *check_res = pe_resource_dir_search(dir, res->name); + if (check_res != NULL) { + // TODO: how do we handle name conflicts? + Assert(!"name collision"); + continue; + } + + // push entry + PE_Resource *sub_dir_res = pe_resource_dir_push_dir(arena, dir, res->name, 0, 0, 0, 0); + COFF_ResourceID id; + id.type = COFF_ResourceIDType_NUMBER; + id.u.number = res->language_id; + pe_resource_dir_push_entry(arena, sub_dir_res->u.dir, id, res->type, res->data_version, res->version, res->memory_flags, res->data); + } +} + +internal PE_ResourceDir * +pe_resource_table_from_directory_data(Arena *arena, String8 data) +{ + struct stack_s { + struct stack_s *next; + U64 table_offset; + U64 name_base_offset; + U64 id_base_offset; + PE_ResourceDir *table; + PE_ResourceDir **directory_ptr; + U64 name_ientry; + U64 id_ientry; + U64 name_entry_count; + U64 id_entry_count; + }; + + Temp scratch = scratch_begin(&arena,1); + struct stack_s *bottom_frame = push_array(scratch.arena, struct stack_s, 1); + struct stack_s *stack = bottom_frame; + + while (stack) { + if (stack->table == NULL) { + COFF_ResourceDirTable coff_table = {0}; + str8_deserial_read_struct(data, stack->table_offset, &coff_table); + + PE_ResourceDir *table = push_array(arena, PE_ResourceDir, 1); + table->characteristics = coff_table.characteristics; + table->time_stamp = coff_table.time_stamp; + table->major_version = coff_table.major_version; + table->minor_version = coff_table.minor_version; + + stack->table = table; + stack->name_base_offset = stack->table_offset + sizeof(COFF_ResourceDirTable); + stack->id_base_offset = stack->table_offset + sizeof(COFF_ResourceDirTable) + sizeof(COFF_ResourceDirEntry) * coff_table.name_entry_count; + stack->name_entry_count = coff_table.name_entry_count; + stack->id_entry_count = coff_table.id_entry_count; + + if (stack->directory_ptr) { + *stack->directory_ptr = table; + } + } + + while (stack->name_ientry < stack->name_entry_count) { + U64 entry_offset = stack->name_base_offset + stack->name_ientry * sizeof(COFF_ResourceDirEntry); + ++stack->name_ientry; + + PE_ResourceNode *named_node = push_array(arena, PE_ResourceNode, 1); + SLLQueuePush(stack->table->named_list.first, stack->table->named_list.last, named_node); + ++stack->table->named_list.count; + PE_Resource *entry = &named_node->data; + + COFF_ResourceDirEntry coff_entry = {0}; + str8_deserial_read_struct(data, entry_offset, &coff_entry); + + // NOTE: this is not documented on MSDN but high bit here is set for some reason + U32 name_offset = coff_entry.name.offset & ~COFF_RESOURCE_SUB_DIR_FLAG; + U16 name_size = 0; + str8_deserial_read_struct(data, name_offset, &name_size); + + String8 name_block; + str8_deserial_read_block(data, name_offset + sizeof(name_size), name_size*sizeof(U16), &name_block); + String16 name16 = str16((U16*)name_block.str, name_size); + + B32 is_dir = !!(coff_entry.id.data_entry_offset & COFF_RESOURCE_SUB_DIR_FLAG); + + entry->id.type = COFF_ResourceIDType_STRING; + entry->id.u.string = str8_from_16(arena, name16); + entry->type = is_dir ? PE_ResData_DIR : PE_ResData_COFF_LEAF; + + if (is_dir) { + struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); + frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_RESOURCE_SUB_DIR_FLAG; + frame->directory_ptr = &entry->u.dir; + SLLStackPush(stack, frame); + goto yeild; + } else { + str8_deserial_read_struct(data, coff_entry.id.data_entry_offset, &entry->u.leaf); + } + } + + while (stack->id_ientry < stack->id_entry_count) { + U64 entry_offset = stack->id_base_offset + stack->id_ientry * sizeof(COFF_ResourceDirEntry); + ++stack->id_ientry; + + PE_ResourceNode *id_node = push_array(arena, PE_ResourceNode, 1); + SLLQueuePush(stack->table->id_list.first, stack->table->id_list.last, id_node); + ++stack->table->id_list.count; + PE_Resource *entry = &id_node->data; + + COFF_ResourceDirEntry coff_entry = {0}; + str8_deserial_read_struct(data, entry_offset, &coff_entry); + + B32 is_dir = !!(coff_entry.id.sub_dir_offset & COFF_RESOURCE_SUB_DIR_FLAG); + + entry->id.type = COFF_ResourceIDType_NUMBER; + entry->id.u.number = coff_entry.name.id; + entry->type = is_dir ? PE_ResData_DIR : PE_ResData_COFF_LEAF; + + if (is_dir) { + struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); + frame->table_offset = coff_entry.id.sub_dir_offset & ~COFF_RESOURCE_SUB_DIR_FLAG; + frame->directory_ptr = &entry->u.dir; + SLLStackPush(stack, frame); + goto yeild; + } else { + str8_deserial_read_struct(data, coff_entry.id.sub_dir_offset, &entry->u.leaf); + } + } + + SLLStackPop(stack); + + yeild:; + } + + scratch_end(scratch); + return bottom_frame->table; +} + +//////////////////////////////// + +internal String8 +pe_get_dos_program(void) +{ + // generated from pe/dos_program.asm + static U8 program[] = { + 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, + 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x24, 0x00, 0x00 + }; + return str8(program, sizeof(program)); +} + +//////////////////////////////// + +internal String8 +pe_string_from_subsystem(PE_WindowsSubsystem subsystem) +{ + switch (subsystem) { + case PE_WindowsSubsystem_UNKNOWN: return str8_lit("UNKNOWN"); + case PE_WindowsSubsystem_NATIVE: return str8_lit("NATIVE"); + case PE_WindowsSubsystem_WINDOWS_GUI: return str8_lit("WINDOWS_GUI"); + case PE_WindowsSubsystem_WINDOWS_CUI: return str8_lit("WINDOWS_CUI"); + case PE_WindowsSubsystem_OS2_CUI: return str8_lit("OS2_CUI"); + case PE_WindowsSubsystem_POSIX_CUI: return str8_lit("POSIX_CUI"); + case PE_WindowsSubsystem_NATIVE_WINDOWS: return str8_lit("NATIVE_WINDOWS"); + case PE_WindowsSubsystem_WINDOWS_CE_GUI: return str8_lit("WINDOWS_CE_GUID"); + case PE_WindowsSubsystem_EFI_APPLICATION: return str8_lit("EFI_APPLICATION"); + case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER: return str8_lit("EFI_BOOT_SERVICE_DRIVER"); + case PE_WindowsSubsystem_EFI_ROM: return str8_lit("EFI_ROM"); + case PE_WindowsSubsystem_XBOX: return str8_lit("XBOX"); + case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: return str8_lit("WINDOWS_BOOT_APPLICATION"); + default: break; + } + return str8(0,0); +} + diff --git a/src/pe/pe.h b/src/pe/pe.h new file mode 100644 index 00000000..28635a48 --- /dev/null +++ b/src/pe/pe.h @@ -0,0 +1,672 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/* date = September 6th 2023 8:54 am */ + +#ifndef PE_H +#define PE_H + +//////////////////////////////// +//~ rjf: PE Format Types + +#pragma pack(push,1) + +typedef struct PE_DosHeader PE_DosHeader; +struct PE_DosHeader +{ + U16 magic; + U16 last_page_size; + U16 page_count; + U16 reloc_count; + U16 paragraph_header_size; + U16 min_paragraph; + U16 max_paragraph; + U16 init_ss; + U16 init_sp; + U16 checksum; + U16 init_ip; + U16 init_cs; + U16 reloc_table_file_off; + U16 overlay_number; + U16 reserved[4]; + U16 oem_id; + U16 oem_info; + U16 reserved2[10]; + U32 coff_file_offset; +}; + +typedef U16 PE_WindowsSubsystem; +enum +{ + PE_WindowsSubsystem_UNKNOWN = 0, + PE_WindowsSubsystem_NATIVE = 1, + PE_WindowsSubsystem_WINDOWS_GUI = 2, + PE_WindowsSubsystem_WINDOWS_CUI = 3, + PE_WindowsSubsystem_OS2_CUI = 5, + PE_WindowsSubsystem_POSIX_CUI = 7, + PE_WindowsSubsystem_NATIVE_WINDOWS = 8, + PE_WindowsSubsystem_WINDOWS_CE_GUI = 9, + PE_WindowsSubsystem_EFI_APPLICATION = 10, + PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER = 11, + PE_WindowsSubsystem_EFI_RUNTIME_DRIVER = 12, + PE_WindowsSubsystem_EFI_ROM = 13, + PE_WindowsSubsystem_XBOX = 14, + PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION = 16, + PE_WindowsSubsystem_COUNT = 14 +}; + +typedef U16 PE_ImageFileCharacteristics; +enum +{ + PE_ImageFileCharacteristic_STRIPPED = (1 << 0), + PE_ImageFileCharacteristic_EXE = (1 << 1), + PE_ImageFileCharacteristic_NUMS_STRIPPED = (1 << 2), + PE_ImageFileCharacteristic_PE_STRIPPED = (1 << 3), + PE_ImageFileCharacteristic_AGGRESIVE_WS_TRIM = (1 << 4), + PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE = (1 << 5), + PE_ImageFileCharacteristic_UNUSED1 = (1 << 6), + PE_ImageFileCharacteristic_BYTES_RESERVED_LO = (1 << 7), + PE_ImageFileCharacteristic_32BIT_MACHINE = (1 << 8), + PE_ImageFileCharacteristic_DEBUG_STRIPPED = (1 << 9), + PE_ImageFileCharacteristic_FILE_REMOVABLE_RUN_FROM_SWAP = (1 << 10), + PE_ImageFileCharacteristic_NET_RUN_FROM_SWAP = (1 << 11), + PE_ImageFileCharacteristic_FILE_SYSTEM = (1 << 12), + PE_ImageFileCharacteristic_FILE_DLL = (1 << 13), + PE_ImageFileCharacteristic_FILE_UP_SYSTEM_ONLY = (1 << 14), + PE_ImageFileCharacteristic_BYTES_RESERVED_HI = (1 << 15), +}; + +typedef U16 PE_DllCharacteristics; +enum +{ + PE_DllCharacteristic_HIGH_ENTROPY_VA = (1 << 5), + PE_DllCharacteristic_DYNAMIC_BASE = (1 << 6), + PE_DllCharacteristic_FORCE_INTEGRITY = (1 << 7), + PE_DllCharacteristic_NX_COMPAT = (1 << 8), + PE_DllCharacteristic_NO_ISOLATION = (1 << 9), + PE_DllCharacteristic_NO_SEH = (1 << 10), + PE_DllCharacteristic_NO_BIND = (1 << 11), + PE_DllCharacteristic_APPCONTAINER = (1 << 12), + PE_DllCharacteristic_WDM_DRIVER = (1 << 13), + PE_DllCharacteristic_GUARD_CF = (1 << 14), + PE_DllCharacteristic_TERMINAL_SERVER_AWARE = (1 << 15), +}; + +typedef struct PE_OptionalHeader32 PE_OptionalHeader32; +struct PE_OptionalHeader32 +{ + U16 magic; + U8 major_linker_version; + U8 minor_linker_version; + U32 sizeof_code; + U32 sizeof_inited_data; + U32 sizeof_uninited_data; + U32 entry_point_va; + U32 code_base; + U32 data_base; + U32 image_base; + U32 section_alignment; + U32 file_alignment; + U16 major_os_ver; + U16 minor_os_ver; + U16 major_img_ver; + U16 minor_img_ver; + U16 major_subsystem_ver; + U16 minor_subsystem_ver; + U32 win32_version_value; + U32 sizeof_image; + U32 sizeof_headers; + U32 check_sum; + PE_WindowsSubsystem subsystem; + PE_DllCharacteristics dll_characteristics; + U32 sizeof_stack_reserve; + U32 sizeof_stack_commit; + U32 sizeof_heap_reserve; + U32 sizeof_heap_commit; + U32 loader_flags; + U32 data_dir_count; +}; + +typedef struct PE_OptionalHeader32Plus PE_OptionalHeader32Plus; +struct PE_OptionalHeader32Plus +{ + U16 magic; + U8 major_linker_version; + U8 minor_linker_version; + U32 sizeof_code; + U32 sizeof_inited_data; + U32 sizeof_uninited_data; + U32 entry_point_va; + U32 code_base; + U64 image_base; + U32 section_alignment; + U32 file_alignment; + U16 major_os_ver; + U16 minor_os_ver; + U16 major_img_ver; + U16 minor_img_ver; + U16 major_subsystem_ver; + U16 minor_subsystem_ver; + U32 win32_version_value; + U32 sizeof_image; + U32 sizeof_headers; + U32 check_sum; + PE_WindowsSubsystem subsystem; + PE_DllCharacteristics dll_characteristics; + U64 sizeof_stack_reserve; + U64 sizeof_stack_commit; + U64 sizeof_heap_reserve; + U64 sizeof_heap_commit; + U32 loader_flags; + U32 data_dir_count; +}; + +typedef enum PE_DataDirectoryIndex +{ + PE_DataDirectoryIndex_EXPORT, + PE_DataDirectoryIndex_IMPORT, + PE_DataDirectoryIndex_RESOURCES, + PE_DataDirectoryIndex_EXCEPTIONS, + PE_DataDirectoryIndex_CERT, + PE_DataDirectoryIndex_BASE_RELOC, + PE_DataDirectoryIndex_DEBUG, + PE_DataDirectoryIndex_ARCH, + PE_DataDirectoryIndex_GLOBAL_PTR, + PE_DataDirectoryIndex_TLS, + PE_DataDirectoryIndex_LOAD_CONFIG, + PE_DataDirectoryIndex_BOUND_IMPORT, + PE_DataDirectoryIndex_IMPORT_ADDR, + PE_DataDirectoryIndex_DELAY_IMPORT, + PE_DataDirectoryIndex_COM_DESCRIPTOR, + PE_DataDirectoryIndex_RESERVED, + PE_DataDirectoryIndex_COUNT = 16 +} +PE_DataDirectoryIndex; + +typedef struct PE_DataDirectory PE_DataDirectory; +struct PE_DataDirectory +{ + U32 virt_off; + U32 virt_size; +}; + +typedef U32 PE_DebugDirectoryType; +enum +{ + PE_DebugDirectoryType_UNKNOWN = 0, + PE_DebugDirectoryType_COFF = 1, + PE_DebugDirectoryType_CODEVIEW = 2, + PE_DebugDirectoryType_FPO = 3, + PE_DebugDirectoryType_MISC = 4, + PE_DebugDirectoryType_EXCEPTION = 5, + PE_DebugDirectoryType_FIXUP = 6, + PE_DebugDirectoryType_OMAP_TO_SRC = 7, + PE_DebugDirectoryType_OMAP_FROM_SRC = 8, + PE_DebugDirectoryType_BORLAND = 9, + PE_DebugDirectoryType_RESERVED10 = 10, + PE_DebugDirectoryType_CLSID = 11, + PE_DebugDirectoryType_VC_FEATURE = 12, + PE_DebugDirectoryType_POGO = 13, + PE_DebugDirectoryType_ILTCG = 14, + PE_DebugDirectoryType_MPX = 15, + PE_DebugDirectoryType_REPRO = 16, + PE_DebugDirectoryType_EX_DLLCHARACTERISTICS = 20, + PE_DebugDirectoryType_COUNT = 18 +}; + +typedef U8 PE_FPOFlags; +enum +{ + PE_FPOFlags_HAS_SEH = 0x800, + PE_FPOFlags_USE_BP_REG = 0x1000, + PE_FPOFlags_RESERVED = 0x2000, + PE_FPOFlags_COUNT = 3 +}; + +typedef U16 PE_FPOEncoded; +enum +{ + PE_FPOEncoded_PROLOG_SIZE_SHIFT = 0, PE_FPOEncoded_PROLOG_SIZE_MASK = 0xff, + PE_FPOEncoded_SAVED_REGS_SIZE_SHIFT = 8, PE_FPOEncoded_SAVED_REGS_SIZE_MASK = 0x7, + PE_FPOEncoded_FLAGS_SHIFT = 11, PE_FPOEncoded_FLAGS_MASK = 0x7, + PE_FPOEncoded_FRAME_TYPE_SHIFT = 14, PE_FPOEncoded_FRAME_TYPE_MASK = 0x3, +}; +#define PE_FPOEncoded_Extract_PROLOG_SIZE(f) (U8)(((f) >> PE_FPOEncoded_PROLOG_SIZE_SHIFT) & PE_FPOEncoded_PROLOG_SIZE_MASK) +#define PE_FPOEncoded_Extract_SAVED_REGS_SIZE(f) (U8)(((f) >> PE_FPOEncoded_SAVED_REGS_SIZE_SHIFT) & PE_FPOEncoded_SAVED_REGS_SIZE_MASK) +#define PE_FPOEncoded_Extract_FLAGS(f) (U8)(((f) >> PE_FPOEncoded_FLAGS_SHIFT) & PE_FPOEncoded_FLAGS_MASK) +#define PE_FPOEncoded_Extract_FRAME_TYPE(f) (U8)(((f) >> PE_FPOEncoded_FRAME_TYPE_SHIFT) & PE_FPOEncoded_FRAME_TYPE_MASK) + +typedef U8 PE_FPOType; +enum +{ + PE_FPOType_FPO = 0, + PE_FPOType_TRAP = 1, + PE_FPOType_TSS = 2, + PE_FPOType_NOFPO = 3, + PE_FPOType_COUNT = 4 +}; + +typedef U32 PE_DebugMiscType; +enum +{ + PE_DebugMiscType_NULL, + PE_DebugMiscType_EXE_NAME, + PE_DebugMiscType_COUNT = 2 +}; + +typedef struct PE_DebugDirectory PE_DebugDirectory; +struct PE_DebugDirectory +{ + U32 characteristics; + COFF_TimeStamp time_stamp; + U16 major_ver; + U16 minor_ver; + PE_DebugDirectoryType type; + U32 size; + U32 voff; + U32 foff; +}; + +typedef U32 PE_GlobalFlags; +enum +{ + PE_GlobalFlags_STOP_ON_EXCEPTION = (1 << 0), + PE_GlobalFlags_SHOW_LDR_SNAPS = (1 << 1), + PE_GlobalFlags_DEBUG_INITIAL_COMMAND = (1 << 2), + PE_GlobalFlags_STOP_ON_HUNG_GUI = (1 << 3), + PE_GlobalFlags_HEAP_ENABLE_TAIL_CHECK = (1 << 4), + PE_GlobalFlags_HEAP_ENABLE_FREE_CHECK = (1 << 5), + PE_GlobalFlags_HEAP_VALIDATE_PARAMETERS = (1 << 6), + PE_GlobalFlags_HEAP_VALIDATE_ALL = (1 << 7), + PE_GlobalFlags_APPLICATION_VERIFIER = (1 << 8), + PE_GlobalFlags_POOL_ENABLE_TAGGING = (1 << 10), + PE_GlobalFlags_HEAP_ENABLE_TAGGING = (1 << 11), + PE_GlobalFlags_STACK_TRACE_DB = (1 << 12), + PE_GlobalFlags_KERNEL_STACK_TRACE_DB = (1 << 13), + PE_GlobalFlags_MAINTAIN_OBJECT_TYPELIST = (1 << 14), + PE_GlobalFlags_HEAP_ENABLE_TAG_BY_DLL = (1 << 15), + PE_GlobalFlags_DISABLE_STACK_EXTENSION = (1 << 16), + PE_GlobalFlags_ENABLE_CSRDEBUG = (1 << 17), + PE_GlobalFlags_ENABLE_KDEBUG_SYMBOL_LOAD = (1 << 18), + PE_GlobalFlags_DISABLE_PAGE_KERNEL_STACKS = (1 << 19), + PE_GlobalFlags_ENABLE_SYSTEM_CRIT_BREAKS = (1 << 20), + PE_GlobalFlags_HEAP_DISABLE_COALESCING = (1 << 21), + PE_GlobalFlags_ENABLE_CLOSE_EXCEPTIONS = (1 << 22), + PE_GlobalFlags_ENABLE_EXCEPTION_LOGGING = (1 << 23), + PE_GlobalFlags_ENABLE_HANDLE_TYPE_TAGGING = (1 << 24), + PE_GlobalFlags_HEAP_PAGE_ALLOCS = (1 << 25), + PE_GlobalFlags_DEBUG_INITIAL_COMMAND_EX = (1 << 26), + PE_GlobalFlags_DISABLE_DBGPRINT = (1 << 27), + PE_GlobalFlags_CRITSEC_EVENT_CREATION = (1 << 28), + PE_GlobalFlags_LDR_TOP_DOWN = (1 << 29), + PE_GlobalFlags_ENABLE_HANDLE_EXCEPTIONS = (1 << 30), + PE_GlobalFlags_DISABLE_PROTDLLS = (1 << 31), +}; + +typedef U32 PE_LoadConfigGuardFlags; +enum +{ + PE_LoadConfigGuardFlags_CF_INSTRUMENTED = (1 << 8), + PE_LoadConfigGuardFlags_CFW_INSTRUMENTED = (1 << 9), + PE_LoadConfigGuardFlags_CF_FUNCTION_TABLE_PRESENT = (1 << 10), + PE_LoadConfigGuardFlags_SECURITY_COOKIE_UNUSED = (1 << 11), + PE_LoadConfigGuardFlags_PROTECT_DELAYLOAD_IAT = (1 << 12), + PE_LoadConfigGuardFlags_DELAYLOAD_IAT_IN_ITS_OWN_SECTION = (1 << 13), + PE_LoadConfigGuardFlags_CF_EXPORT_SUPPRESSION_INFO_PRESENT = (1 << 14), + PE_LoadConfigGuardFlags_CF_ENABLE_EXPORT_SUPPRESSION = (1 << 15), + PE_LoadConfigGuardFlags_CF_LONGJUMP_TABLE_PRESENT = (1 << 16), + PE_LoadConfigGuardFlags_EH_CONTINUATION_TABLE_PRESENT = (1 << 22), + PE_LoadConfigGuardFlags_CF_FUNCTION_TABLE_SIZE_SHIFT = 28, PE_LoadConfigGuardFlags_CF_FUNCTION_TABLE_SIZE_MASK = 0xf, +}; +#define PE_LoadConfigGuardFlags_Extract_CF_FUNCTION_TABLE_SIZE(f) (U32)(((f) >> PE_LoadConfigGuardFlags_CF_FUNCTION_TABLE_SIZE_SHIFT) & PE_LoadConfigGuardFlags_CF_FUNCTION_TABLE_SIZE_MASK) + +// this is the "MZ" as a 16-bit short +#define PE_DOS_MAGIC 0x5a4d +#define PE_MAGIC 0x00004550u +#define PE_PE32_MAGIC 0x010bu +#define PE_PE32PLUS_MAGIC 0x020bu + +typedef struct PE_MipsPdata PE_MipsPdata; +struct PE_MipsPdata +{ + U32 voff_first; + U32 voff_one_past_last; + U32 voff_exception_handler; + U32 voff_exception_handler_data; + U32 voff_one_past_prolog; +}; + +typedef struct PE_ArmPdata PE_ArmPdata; +struct PE_ArmPdata +{ + U32 voff_first; + // NOTE(allen): + // bits | meaning + // [0:7] | prolog length + // [8:29] | function length + // [30:30] | instructions_are_32bits (otherwise they are 16 bits) + // [31:31] | has_exception_handler + U32 combined; +}; + +typedef struct PE_IntelPdata PE_IntelPdata; +struct PE_IntelPdata +{ + U32 voff_first; + U32 voff_one_past_last; + U32 voff_unwind_info; +}; + +#define PE_CODEVIEW_PDB20_MAGIC 0x3031424e +#define PE_CODEVIEW_PDB70_MAGIC 0x53445352 + +typedef struct PE_CvHeaderPDB20 PE_CvHeaderPDB20; +struct PE_CvHeaderPDB20 +{ + U32 magic; + U32 offset; + U32 time; + U32 age; + // file name packed after struct +}; + +typedef struct PE_CvHeaderPDB70 PE_CvHeaderPDB70; +struct PE_CvHeaderPDB70 +{ + U32 magic; + OS_Guid guid; + U32 age; + // file name packed after struct +}; + +typedef struct PE_ImportEntry PE_ImportEntry; +struct PE_ImportEntry +{ + U32 lookup_table_voff; + COFF_TimeStamp time_stamp; + U32 forwarder_chain; + U32 name_voff; + U32 import_addr_table_voff; +}; + +typedef struct PE_DelayedImportEntry PE_DelayedImportEntry; +struct PE_DelayedImportEntry +{ + // According to PE/COFF spec this field is unused and should be set zero, + // but when I compile mule with MSVC 2019 this is set to 1. + U32 attributes; + U32 name_voff; // Name of the DLL + U32 module_handle_voff; // Place where module handle from LoadLibrary is stored + U32 iat_voff; + U32 name_table_voff; // Array of hint/name or oridnals + U32 bound_table_voff; // (Optional) Points to an array of PE_ThunkData + U32 unload_table_voff; // (Optional) Copy of iat_voff + // 0 not bound + // -1 if bound and real timestamp located in bounded import directory + // Otherwise time when dll was bound + COFF_TimeStamp time_stamp; +}; + +typedef struct PE_ExportTable PE_ExportTable; +struct PE_ExportTable +{ + U32 flags; // must be zero + COFF_TimeStamp time_stamp; // time and date when export table was created + U16 major_ver; // table version, user can change major and minor version + U16 minor_ver; + U32 name_voff; // ASCII name of the dll + U32 ordinal_base; // Starting oridnal number + U32 export_address_table_count; + U32 name_pointer_table_count; + U32 export_address_table_voff; + U32 name_pointer_table_voff; + U32 ordinal_table_voff; +}; + +typedef struct PE_TLSHeader32 PE_TLSHeader32; +struct PE_TLSHeader32 +{ + U32 raw_data_start; // Range of initialized data that is copied for each thread from the image. + U32 raw_data_end; // (Typically points to .tls section) + U32 index_address; // Address where image loader places TLS slot index. + U32 callbacks_address; // Zero terminated list of callbacks used for initializing data with constructors. + U32 zero_fill_size; // Amount of memory to fill with zeroes in TLS. + U32 characteristics; // COFF_SectionFlags but only align flags are used. +}; + +typedef struct PE_TLSHeader64 PE_TLSHeader64; +struct PE_TLSHeader64 +{ + U64 raw_data_start; // Range of initialized data that is copied for each thread from the image. + U64 raw_data_end; // (Typically points to .tls section) + U64 index_address; // Address where image loader places TLS slot index. + U64 callbacks_address; // Zero terminated list of callbacks used for initializing data with constructors. + U32 zero_fill_size; // Amount of memory to fill with zeroes in TLS. + U32 characteristics; // COFF_SectionFlags but only align flags are used. +}; + +#pragma pack(pop) + +//////////////////////////////// +//~ rjf: Parsed Info Types + +typedef struct PE_BinInfo PE_BinInfo; +struct PE_BinInfo +{ + U64 image_base; + U64 entry_point; + B32 is_pe32; + U64 virt_section_align; + U64 file_section_align; + U64 section_array_off; + U64 section_count; + U64 symbol_array_off; + U64 symbol_count; + U64 string_table_off; + U64 dbg_path_off; + U64 dbg_path_size; + OS_Guid dbg_guid; + U32 dbg_age; + U32 dbg_time; + Architecture arch; + Rng1U64 *data_dir_franges; + U32 data_dir_count; + PE_TLSHeader64 tls_header; +}; + +//////////////////////////////// +//~ rjf: Parsed Info Extraction Helper Types + +typedef U16 PE_BaseRelocKind; +enum +{ + PE_BaseRelocKind_ABSOLUTE = 0, // No reallocation is applied. Can be used as padding. + PE_BaseRelocKind_HIGH = 1, + PE_BaseRelocKind_LOW = 2, + PE_BaseRelocKind_HIGHLOW = 3, + PE_BaseRelocKind_HIGHADJ = 4, + PE_BaseRelocKind_MIPS_JMPADDR = 5, + PE_BaseRelocKind_ARM_MOV32 = 5, + PE_BaseRelocKind_RISCV_HIGH20 = 5, + // 6 is reserved + PE_BaseRelocKind_THUMB_MOV32 = 7, + PE_BaseRelocKind_RISCV_LOW12I = 7, + PE_BaseRelocKind_RISCV_LOW12S = 8, + PE_BaseRelocKind_LOONGARCH32_MARK_LA = 8, + PE_BaseRelocKind_LOONGARCH64_MARK_LA = 8, + PE_BaseRelocKind_MIPS_JMPADDR16 = 9, + PE_BaseRelocKind_DIR64 = 10, +}; +#define PE_BaseRelocOffsetFromEntry(x) ((x) & 0x1fff) +#define PE_BaseRelocKindFromEntry(x) (((x) >> 12) & 0xf) +#define PE_BaseRelocMake(k, off) ((((U16)(k) & 0xf) << 12) | (U16)((off) & 0x1fff)) + +typedef struct PE_BaseRelocBlock PE_BaseRelocBlock; +struct PE_BaseRelocBlock +{ + U64 page_virt_off; + U64 entry_count; + U16 *entries; +}; + +typedef struct PE_BaseRelocBlockNode PE_BaseRelocBlockNode; +struct PE_BaseRelocBlockNode +{ + PE_BaseRelocBlockNode *next; + PE_BaseRelocBlock v; +}; + +typedef struct PE_BaseRelocBlockList PE_BaseRelocBlockList; +struct PE_BaseRelocBlockList +{ + PE_BaseRelocBlockNode *first; + PE_BaseRelocBlockNode *last; + U64 count; +}; + +//////////////////////////////// +//~ Resources + +#define PE_RES_ALIGN 4u + +read_only U8 PE_RES_MAGIC[] = { 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +enum +{ + PE_Resource_CURSOR = 0x1, + PE_Resource_BITMAP = 0x2, + PE_Resource_ICON = 0x3, + PE_Resource_MENU = 0x4, + PE_Resource_DIALOG = 0x5, + PE_Resource_STRING = 0x6, + PE_Resource_FONTDIR = 0x7, + PE_Resource_FONT = 0x8, + PE_Resource_ACCELERATOR = 0x9, + PE_Resource_RCDATA = 0xA, + PE_Resource_MESSAGETABLE = 0xB, + PE_Resource_GROUP_CURSOR = 0xC, + PE_Resource_GROUP_ICON = 0xE, + PE_Resource_VERSION = 0x10, + PE_Resource_DLGINCLUDE = 0x11, + PE_Resource_PLUGPLAY = 0x13, + PE_Resource_VXD = 0x14, + PE_Resource_ANICURSOR = 0x15, + PE_Resource_ANIICON = 0x16, + PE_Resource_HTML = 0x17, + PE_Resource_MANIFEST = 0x18, + PE_Resource_BITMAP_NEW = 0x2002, + PE_Resource_MENU_NEW = 0x2004, + PE_Resource_DIALOG_NEW = 0x2005, +}; +typedef U32 PE_ResourceType; + +#pragma pack(push, 1) +typedef struct PE_ResourceHeader +{ + COFF_ResourceHeaderPrefix prefix; + U16 type; + U16 pad0; + U16 name; + U16 pad1; + U32 data_version; + COFF_ResourceMemoryFlags memory_flags; + U16 language_id; + U32 version; + U32 characteristics; +} PE_ResourceHeader; +#pragma pack(pop) + +typedef enum +{ + PE_ResData_NULL, + PE_ResData_DIR, + PE_ResData_COFF_LEAF, + PE_ResData_COFF_RESOURCE, +} PE_ResDataType; + +typedef struct PE_Resource +{ + COFF_ResourceID id; + PE_ResDataType type; + union { + COFF_ResourceDataEntry leaf; + struct PE_ResourceDir *dir; + struct { + COFF_ResourceID type; + U32 data_version; + U32 version; + COFF_ResourceMemoryFlags memory_flags; + String8 data; + } coff_res; + } u; +} PE_Resource; + +typedef struct PE_ResourceNode +{ + struct PE_ResourceNode *next; + PE_Resource data; +} PE_ResourceNode; + +typedef struct PE_ResourceList +{ + U64 count; + PE_ResourceNode *first; + PE_ResourceNode *last; +} PE_ResourceList; + +typedef struct PE_ResourceArray +{ + U64 count; + PE_Resource *v; +} PE_ResourceArray; + +typedef struct PE_ResourceDir +{ + U32 characteristics; + COFF_TimeStamp time_stamp; + U16 major_version; + U16 minor_version; + PE_ResourceList named_list; + PE_ResourceList id_list; +} PE_ResourceDir; + +//////////////////////////////// +//~ rjf: Parser Functions + +internal PE_BinInfo pe_bin_info_from_data(Arena *arena, String8 data); + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 pe_intel_pdata_off_from_voff__binary_search(String8 data, PE_BinInfo *bin, U64 voff); +internal void *pe_ptr_from_voff(String8 data, PE_BinInfo *bin, U64 voff); +internal U64 pe_section_num_from_voff(String8 data, PE_BinInfo *bin, U64 voff); +internal void *pe_ptr_from_section_num(String8 data, PE_BinInfo *bin, U64 n); +internal U64 pe_foff_from_voff(String8 data, PE_BinInfo *bin, U64 voff); +internal PE_BaseRelocBlockList pe_base_reloc_block_list_from_bin(Arena *arena, String8 data, PE_BinInfo *bin); +internal Rng1U64 pe_tls_rng_from_bin_base_vaddr(String8 data, PE_BinInfo *bin, U64 base_vaddr); + +//////////////////////////////// +//~ Resource Helpers + +internal B32 pe_is_res(String8 data); +internal void pe_resource_dir_push_res_file(Arena *arena, PE_ResourceDir *root_dir, String8 res_file); +internal PE_ResourceNode * pe_resource_dir_push_dir_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, U32 characteristics, COFF_TimeStamp time_stamp, U16 major_version, U16 minor_version); +internal PE_ResourceNode * pe_resource_dir_push_entry_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, COFF_ResourceID type, U32 data_version, U32 version, COFF_ResourceMemoryFlags memory_flags, String8 data); +internal PE_Resource * pe_resource_dir_push_entry(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, COFF_ResourceID type, U32 data_version, U32 version, COFF_ResourceMemoryFlags memory_flags, String8 data); +internal PE_Resource * pe_resource_dir_push_dir(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, U32 characteristics, COFF_TimeStamp time_stamp, U16 major_version, U16 minor_version); +internal PE_ResourceNode * pe_resource_dir_search_node(PE_ResourceDir *dir, COFF_ResourceID id); +internal PE_Resource * pe_resource_dir_search(PE_ResourceDir *dir, COFF_ResourceID id); +internal PE_ResourceArray pe_resource_list_to_array(Arena *arena, PE_ResourceList *list); +internal PE_ResourceDir * pe_resource_table_from_directory_data(Arena *arena, String8 data); + +//////////////////////////////// + +internal String8 pe_get_dos_program(void); + +//////////////////////////////// + +internal String8 pe_string_from_subsystem(PE_WindowsSubsystem subsystem); + +#endif //PE_H diff --git a/src/raddbg/raddbg.cpp b/src/raddbg/raddbg.cpp new file mode 100644 index 00000000..1b6bae0e --- /dev/null +++ b/src/raddbg/raddbg.cpp @@ -0,0 +1,1086 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Settings + +#define ENABLE_DEV 1 +#define DE2CTRL 1 + +//////////////////////////////// +//~ rjf: 2024/1 tasks +// +//*[ ] @cleanup @feature double & triple click select in source views +//*[ ] @bug disasm animation & go-to-address +// +//*[ ] @bug table column boundaries should be checked against *AFTER* table contents, not before +//*[ ] @cleanup @feature autocomplete lister should respect position in edited expression, tabbing through should autocomplete but not exit, etc. +//*[ ] @cleanup @feature figure out 'watch window state' question, and how watch windows relate to targets, entities, & so on +//*[ ] @feature undo/redo +//*[ ] @feature proper "go back" + "go forward" history navigations +// +// [ ] @bug view-snapping in scroll-lists, accounting for mapping between visual positions & logical positions (variably sized rows in watch, table headers, etc.) +// [ ] @bug selected frame should be keyed by run_idx or something so that it can gracefully reset to the top frame when running +// +// [ ] @cleanup collapse DF_CfgNodes into just being MD trees, find another way to encode config source - don't need it at every node +// +// [ ] @feature fancy "escape hatch" view rules +// [ ] `text[:lang]` - interpret memory as text, in lang `lang` +// [ ] `disasm:arch` - interpret memory as machine code for isa `arch` +// [ ] `memory` - view memory in usual memory hex-editor view +// NOTE(rjf): When the visualization system is solid, layers like dasm, txti, and so on +// can be dispensed with, as things like the source view, disasm view, or memory view will +// simply be specializations of the general purpose viz system. +// +// [ ] @feature view rule hook for standalone visualization ui, granted its own tab +// [ ] @feature hovering truncated text in UI for some amount of time -> show tooltip with full text +// +// [ ] @cleanup straighten out index/number space & types & terminology for scroll lists +// [ ] @cleanup simplification pass over eval visualization pipeline & types, including view rule hooks +// [ ] @cleanup naming pass over eval visualization part of the frontend, "blocks" vs. "canvas" vs. "expansion" - etc. +// +// [ ] @feature disasm keyboard navigation & copy/paste +// [ ] @feature debug info overrides (both path-based AND module-based) +// +// [ ] @polish globally disable/configure default view rule-like things (string viz for u8s in particular) +// [ ] @polish configure tab size +// +// [ ] @polish @feature ui for dragging tab -> bundling panel split options +// [ ] @polish @feature visualize mismatched source code and debug info +// [ ] @polish @feature visualize remapped files (via path map) +// [ ] @polish @feature run-to-line needs to work if no processes are running - place temp bp, attach "die on hit" flag or something like that? +// +// [ ] @feature processor/data breakpoints +// [ ] @feature automatically snap to search matches when searching source files +// [ ] @feature entity views: filtering & reordering +// +// [ ] @cleanup central worker thread pool - eliminate per-layer thread pools +// +// [ ] @feature search-in-all-files +// [ ] @feature memory view mutation controls +// [ ] @feature memory view user-made annotations + +//////////////////////////////// +//~ rjf: 2024/2 tasks +// +// [ ] @perf ue/chromium testing +// [ ] @perf converter perf +// [ ] @perf frontend perf +// +// [ ] @feature types -> auto view rules (don't statefully fill view rules given types, just query if no other view rule is present, & autofill when editing) +// [ ] @feature eval system -> somehow evaluate breakpoint hit counts? "meta" variables? +// [ ] @feature watch window labels +// [ ] @feature scheduler -> thread grid view? +// [ ] @feature global entry point overrides (settings) +// +// [ ] @feature disasm view improvement features +// [ ] interleaved src/dasm view +// [ ] visualize jump destinations in disasm +// +// [ ] @feature eval ui improvement features +// [ ] serializing eval view maps +// [ ] view rule editors in hover-eval +// [ ] view rule hook coverage +// [ ] `each:(expr addition)` - apply some additional expression to all elements in an array/linked list would be useful to look at only a subset of an array of complex structs +// [ ] `slider:(min max)` view rule +// [ ] `v2f32` view rule +// [ ] `v3` view rule +// [ ] `quat` view rule +// [ ] `matrix` view rule +// [ ] `audio` waveform view rule +// [ ] smart scopes - expression operators for "grab me the first type X" +// [ ] "pinning" watch expressions, to attach it to a particular ctrl_ctx +// +// [ ] @feature header file for target -> debugger communication; printf, log, etc. +// [ ] @feature just-in-time debugging +// [ ] @feature step-out-of-loop + +//////////////////////////////// +//~ rjf: Unsorted User Notes +// +//-[ ] jeff notes +// [ ] keyboard controls & copy/paste in disasm view +// [ ] disasm animation unexpected and/or annoying +// +//-[ ] notes from allen +// [ ] 'browse' in modules debug info map editor +// [ ] debug info map revisit... ctrl thread needs to know string -> string, not just handle -> string +// [ ] panel-split options in right-click menu. maybe just do the full +// 'contextual ctx menu stack' thing here? then ctx menus buried deep in +// the callstack still gather all the right stuff... +// [ ] ui color pallette inspector/editor - function which takes ui_box -> theme_color +// [ ] watch-window-wide view rule +// +//-[ ] short-term major issues from martins +// [ ] F10/F5 is not stepping over line, if line invokes macro with bunch of code (if checks, functions +// calls) then debugger thinks there is a breakpoint on every condition? or every function call? so +// I hits my breakpoint multiple times when I just want to get over it +// +//-[ ] short-term minor issues from martins +// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions? +// [ ] mouse back button should make view to go back after I double clicked on function to open it +// [ ] middle mouse button on tab should close it +// [ ] pressing random keyboard keys in source code advances text cursor like you were inputting text, very strange. +// [ ] Alt+8 to switch to disassembly would be nice (regardless on which panel was previous, don't want to use ctrl+, multiple times) +// Alt+8 for disasm and Alt+6 for memory view are shortcuts I often use in VS +// [ ] what's up with decimal number coloring where every group of 3 are in different color? can I turn it off? And why sometimes digits in number start with brighter color, but sometimes with darker - shouldn't it always have the same color ordering? +// [ ] it would be nice to have "show in explorer" for right click on source file tab (opens explorer & selects the file) +// [ ] it would be nice if Alt+o in source file would switch between .h and .c/cpp file (just look for same name in same folder) +// [ ] in watch window when I enter some new expression and then click mouse away from cell, then it should behave the same as if I pressed enter. Currently it does the same as if I have pressed esc and I have lost my expression +// [ ] navigation in watch window cells (not text editing, but which cell is selected) is bad - home/end/pgup/pgdown buttons navigate not where I expect (and with ctrl combination too) +// [ ] for big source files the scrollbar element for active position is a bit to small - maybe have min size it never goes below (like 50px or maybe exactly 1 line of source code in height) +// [ ] default font size is too small for me - not only source code, but menus/tab/watch names (which don't resize). Maybe you could query Windows for initial font size? +// [ ] zooming behaves very strangely - sometimes it zooms source code, sometimes both source code and menu/tab/watch font size, sometimes just menu/tab/watch font size not source size. +// [ ] icon fonts glyphs sometimes disappear for specific font size, but they reappear if you go +1 higher or -1 lower. Mostly red triangle in watch values for "unknown identifier". But also yellow arrow in call stack disappears if font size gets too large. +// [ ] undo close tab would be nice. If not for everything, then at least just for source files +// +//-[ ] long-term future notes from martins +// [ ] core dump saving/loading +// [ ] parallel call stacks view +// [ ] parallel watch view +// [ ] mixed native/interpreted/jit debugging +// - it seems python has a top-level linked list of interpreter states, +// which should allow the debugger to map native callstacks to python +// code + +//////////////////////////////// +//~ rjf: Long-Term Deferred Polish & Improvements +// +// [ ] fancy string runs can include "weakness" information for text truncation... can prioritize certain parts of strings to be truncated before others. would be good for e.g. the middle of a path +// [ ] ui code maintenance, simplification, design, & robustness pass +// [ ] page-up & page-down correct handling in keyboard nav +// [ ] collapse context menus & command lister into same codepaths. filter by context. parameterize by context. +// [ ] collapse text cells & command lister & etc. into same codepath (?) +// [ ] nested context menus +// [ ] unified top-level cursor/typing/lister helper +// [ ] font selection lister +// [ ] font cache eviction (both for font tags, closing fp handles, and rasterizations) +// [ ] frontend speedup opportunities +// [ ] tables in UI -> currently building per-row, could probably cut down on # of boxes and # of draws by doing per-column in some cases? +// [ ] font cache layer -> can probably cache (string*font*size) -> (run) too (not just rasterization)... would save a *lot*, there is a ton of work just in looking up & stitching stuff repeatedly +// [ ] convert UI layout pass to not be naive recursive version +// [ ] (big change) parallelize window ui build codepaths per-panel + +//////////////////////////////// +//~ rjf: Completed Tasks +// +// [x] adding watches to source locations +// [x] tab overflow buttons +// [x] "working set" of targets, just used 'enabled' slot on target entities +// [x] convert hover-eval ui to a frontend-wide global ui concept, so that we can have watch-hover trees from anywhere +// [x] annotate code slices with relevant watches +// [x] ability to duplicate targets easily +// [x] ability to label targets separately from their EXE +// +// [x] txti layer needs lexing +// [x] dbgi autoconversion layer needs to work reliably +// [x] new dbgi system on frontend +// [x] new bini system on frontend +// [x] new dbgi system needs in-parallel typegraph builders +// [x] eval is busted +// [x] fail or debug non-text +// [x] clean loading +// [x] watch pins +// [x] snapping should still work if a file is loading while the snap first occurs +// [x] keyboard usage (set-next-statement, run-to-line, etc.) +// [x] go-to-name (both file & symbol) +// +// [x] in-memory disassembly view +// [x] visualize conversion tasks as they occur +// [x] raddbg.exe self-sufficiency => built-in converter execution mode +// [x] move path-mapping fallback from pending-entity into code view +// [x] per-target entry point overrides +// [x] logic on when double click on callstack entry goes to source or disassembly is very confusing, +// because it seems it matters whether disassembly tab is in same panel as source, or is placed in +// different panel in VS double clicking on stack stays in disassembly if disassembly tab is currently +// active. Otherwise if source is active, it goes to source code (regardless if disasm is open/visible +// or not) +// [x] global variable (just regular C++ bool in the same file) does not show value when hovering over source +// code, or when put into watch window. +// +// [x] debugger ui thread needs wakeup when a debug event is hit +// [x] ctrl thread needs to re-resolve breakpoints as modules/threads come in during a run +// [x] automatically pull in members from containing struct in member functions +// when looking up locals +// [x] iron out weird state machine bugs with hover-eval +// +// [x] thread-local eval +// [x] tabs in source code render as squares +// +// [x] breakpoint stop-conditions +// [x] first-chance exception hitting (d3d11 as an example offender) +// [x] soft-halt refresh +// +// [x] conditional breakpoints cannot be submitted if they don't compile +// need to (a) visualize and (b) equip the ctrl thread with a 'halt on +// new debug info feature', which can be done repeatedly until something +// compiles (?) +// +// [x] outputdebugstring logs +// +// [x] memory view +// +// [x] when application starts then the focus is on cmd.exe window of application not +// debugger. This means if I press F11 to step into main(), the application cmd.exe will go fullscreen +// hiding debugger (F11 key for ConEmu I use makes it go fullscreen) +// [x] I'd prefer if ctrl+click on word would go to function definition, not double click +// double clicking in source code should select word - which easy way to double click and ctrl+c to copy +// it, pretty much standard thing in any text editorr/viewer and triple click for selecting whole line +// [x] command line DF_CfgSrc -> explicitly visualize as temporary, provide UI +// path to make permanent (in either user or profile?) +// +// [x] memory view annotations: bytes in a range of memory actually have a +// *stack* of possible interpretations, for any particular low-level +// representation (assuming 1 is fine for this case). a U32 member in +// a local struct on the stack has 3 layers: U32 -> local -> stack. +// each of these are useful information about that U32's range of bytes. +// so, the memory view annotation system ought to be expanded to support- +// ing stacks of annotations, and gracefully visualizing multiple nested +// ones. after that is supported, we can use the type info to derive the +// lowest level representation of some bytes. each stack can only have +// one low-level type. that low-level type, then, can be used to directly +// interpret the bytes - the others can be used to show the "conceptual +// stack". +// +// [x] entity tree ui replacement (scheduler, modules, breakpoints, pins) +// [x] theme menu +// [x] complete transition to UI_ScrollPt coordinate space scrolling - eliminate +// old scrolls & scroll regions +// [x] settings menu +// [x] exception filter settings & controls in ctrl layer +// +// [x] @polish @cleanup convert eval/watch to scroll list +// [x] @feature memory view keyboard navigation +// [x] @bug fix general ui line edit editing rules - conflicting with navigation, etc. +// [x] @polish have expander space even if not used in watch window +// [x] @bug references do not expand properly +// [x] @bug panel deletion improper size bug +// [x] @bug panel serialization/deserialization bug? +// [x] unfinished char/string literal lexing +// +// [x] C++ problems in watch window: evaluating "this" shows no members. The type seems correct reference +// to struct (which is local variable) does not show any members, like I have "tm_mem_zone_rt& z = ..." +// in source code, and doing "z" produces no children, nor does "&z" but then at least it shows correct +// address as value. if I ask for member of this when currently inside of member function (like "m_zone_stack") +// it shows "unknown identifier m_zone_stack" but "this->m_zone_stack" works fine! +// [x] if I write x'z in watch window and press enter, it only shows x and loses 'z - it does not show it, but when I edit cell then 'z comes back. It pretends I entered just x and shows x value. +// [x] it seems the glyph advance for default font size is kind of wrong, as characters are a blitted a bit over top of each other +// +// [x] @bug deleting a watch tree while it is expanded causes cursor to go back to first row - cannot simply increment cursor. maybe keep in same spot, but rebuild viz blocks? +// [x] @bug do not squish partially-cut-off view rule block uis +// [x] @feature "solo step", or "solo mode" freeze-all-unselected-threads-on-step-commands +// [x] @feature typing autocomplete lister +// [x] @feature directional navigation of panel focus +// [x] @cleanup @feature cache eviction in texture cache & hash store +// +//- 2023/12/7 +// +// [x] @bug hash store cache eviction can only work if user never blindly tries to go from hash -> data, because +// they must be able to retry... hmm... +// [x] txt cell revamp. keyboard focus in both default & non w/ multiple options, helper lister, etc. +// [x] `bitmap:(w:width, h:height, [fmt:fmt])` - interpret memory as raw bitmap data +// [x] `geo:n[ topology stride]` - interpret memory as geometry +// [x] cursor helper -> upgraded txt cell. classify inputs & show dropdowns (locals, globals, types, view rules, etc.) +// [x] @bug page-up and page-down in src view, when near the end of file +// +//- 2023/12/8 +// +// [x] @bug parse `unsigned int` correctly in eval parser +// [x] @bug ., + operators should work on registers +// [x] @bug straighten out register eval problems +// [x] @cleanup finish ui_em transition +// +//- 2023/12/22 +// +// [x] @bug set-bp-while-running seems to not resume after soft-halt, might be a soft-halt bug +// [x] @bug weird view snapping in watch scrolling down +// +//- 2024/01/10 +// +// [x] @feature allow `,count`, `,x`, `,b` style watch window expression extensions, which add to view rule, for VS-like behavior fastpaths + +//////////////////////////////// +//~ rjf: Includes + +//- rjf: [h] +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "mdesk/mdesk.h" +#include "hash_store/hash_store.h" +#include "text_cache/text_cache.h" +#include "path/path.h" +#include "txti/txti.h" +#include "coff/coff.h" +#include "pe/pe.h" +#include "raddbg_format/raddbg_format.h" +#include "raddbg_format/raddbg_format_parse.h" +#include "raddbg_cons/raddbg_cons.h" +#include "raddbg_convert/pdb/raddbg_coff.h" +#include "raddbg_convert/pdb/raddbg_codeview.h" +#include "raddbg_convert/pdb/raddbg_msf.h" +#include "raddbg_convert/pdb/raddbg_pdb.h" +#include "raddbg_convert/pdb/raddbg_coff_conversion.h" +#include "raddbg_convert/pdb/raddbg_codeview_conversion.h" +#include "raddbg_convert/pdb/raddbg_from_pdb.h" +#include "raddbg_convert/pdb/raddbg_codeview_stringize.h" +#include "raddbg_convert/pdb/raddbg_pdb_stringize.h" +#include "regs/regs.h" +#include "regs/raddbg/regs_raddbg.h" +#include "type_graph/type_graph.h" +#include "dbgi/dbgi.h" +#include "demon/demon_inc.h" +#include "eval/eval_compiler.h" +#include "eval/eval_machine.h" +#include "eval/eval_parser.h" +#include "unwind/unwind.h" +#include "ctrl/ctrl_inc.h" +#include "dasm/dasm.h" +#include "font_provider/font_provider_inc.h" +#include "render/render_inc.h" +#include "texture_cache/texture_cache.h" +#include "geo_cache/geo_cache.h" +#include "font_cache/font_cache.h" +#include "draw/draw.h" +#include "ui/ui_inc.h" +#include "df/df_inc.h" + +//- rjf: [c] +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "mdesk/mdesk.c" +#include "hash_store/hash_store.c" +#include "text_cache/text_cache.c" +#include "path/path.c" +#include "txti/txti.c" +#include "coff/coff.c" +#include "pe/pe.c" +#include "raddbg_format/raddbg_format.c" +#include "raddbg_format/raddbg_format_parse.c" +#include "raddbg_cons/raddbg_cons.c" +#include "raddbg_convert/pdb/raddbg_msf.c" +#include "raddbg_convert/pdb/raddbg_codeview.c" +#include "raddbg_convert/pdb/raddbg_pdb.c" +#include "raddbg_convert/pdb/raddbg_coff_conversion.c" +#include "raddbg_convert/pdb/raddbg_codeview_conversion.c" +#include "raddbg_convert/pdb/raddbg_codeview_stringize.c" +#include "raddbg_convert/pdb/raddbg_pdb_stringize.c" +#include "raddbg_convert/pdb/raddbg_from_pdb.c" +#include "regs/regs.c" +#include "regs/raddbg/regs_raddbg.c" +#include "type_graph/type_graph.c" +#include "dbgi/dbgi.c" +#include "demon/demon_inc.c" +#include "eval/eval_compiler.c" +#include "eval/eval_machine.c" +#include "eval/eval_parser.c" +#include "unwind/unwind.c" +#include "ctrl/ctrl_inc.c" +#include "dasm/dasm.c" +#include "font_provider/font_provider_inc.c" +#include "render/render_inc.c" +#include "texture_cache/texture_cache.c" +#include "geo_cache/geo_cache.c" +#include "font_cache/font_cache.c" +#include "draw/draw.c" +#include "ui/ui_inc.c" +#include "df/df_inc.c" + +//////////////////////////////// +//~ rjf: Top-Level Execution Types + +typedef enum ExecMode +{ + ExecMode_Normal, + ExecMode_IPCSender, + ExecMode_Converter, + ExecMode_Help, +} +ExecMode; + +typedef struct IPCInfo IPCInfo; +struct IPCInfo +{ + U64 msg_size; +}; + +//////////////////////////////// +//~ rjf: Top-Level Execution Globals + +#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(16) +StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement); +read_only global String8 ipc_shared_memory_name = str8_lit_comp("_raddbg_ipc_shared_memory_"); +read_only global String8 ipc_semaphore_name = str8_lit_comp("_raddbg_ipc_semaphore_"); + +//////////////////////////////// +//~ rjf: Frontend Entry Points + +internal void +update_and_render(OS_Handle repaint_window_handle, void *user_data) +{ + ProfTick(0); + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + + //- rjf: tick cache layers + txt_user_clock_tick(); + geo_user_clock_tick(); + tex_user_clock_tick(); + + //- rjf: pick delta-time + // TODO(rjf): maximize, given all windows and their monitors + F32 dt = 1.f/os_default_refresh_rate(); + + //- rjf: get events from the OS + OS_EventList events = {0}; + if(os_handle_match(repaint_window_handle, os_handle_zero())) + { + events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0); + } + + //- rjf: bind change + if(df_gfx_state->bind_change_active) + { + if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Esc)) + { + df_gfx_state->bind_change_active = 0; + } + if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Delete)) + { + df_unbind_spec(df_gfx_state->bind_change_cmd_spec, df_gfx_state->bind_change_binding); + df_gfx_state->bind_change_active = 0; + DF_CmdParams p = df_cmd_params_from_gfx(); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_write_cmd_kind_table[DF_CfgSrc_User])); + } + for(OS_Event *event = events.first, *next = 0; event != 0; event = next) + { + if(event->kind == OS_EventKind_Press && + event->key != OS_Key_Esc && + event->key != OS_Key_Return && + event->key != OS_Key_Backspace && + event->key != OS_Key_Delete && + event->key != OS_Key_LeftMouseButton && + event->key != OS_Key_RightMouseButton && + event->key != OS_Key_Ctrl && + event->key != OS_Key_Alt && + event->key != OS_Key_Shift) + { + df_gfx_state->bind_change_active = 0; + DF_Binding binding = zero_struct; + { + binding.key = event->key; + binding.flags = event->flags; + } + df_unbind_spec(df_gfx_state->bind_change_cmd_spec, df_gfx_state->bind_change_binding); + df_bind_spec(df_gfx_state->bind_change_cmd_spec, binding); + U32 codepoint = os_codepoint_from_event_flags_and_key(event->flags, event->key); + os_text(&events, os_handle_zero(), codepoint); + os_eat_event(&events, event); + DF_CmdParams p = df_cmd_params_from_gfx(); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_write_cmd_kind_table[DF_CfgSrc_User])); + break; + } + } + } + + //- rjf: take hotkeys + { + for(OS_Event *event = events.first, *next = 0; + event != 0; + event = next) + { + next = event->next; + DF_Window *window = df_window_from_os_handle(event->window); + DF_CmdParams params = window ? df_cmd_params_from_window(window) : df_cmd_params_from_gfx(); + if(event->kind == OS_EventKind_Press) + { + DF_Binding binding = {event->key, event->flags}; + DF_CmdSpecList spec_candidates = df_cmd_spec_list_from_binding(scratch.arena, binding); + if(spec_candidates.first != 0 && !df_cmd_spec_is_nil(spec_candidates.first->spec)) + { + DF_CmdSpec *spec = spec_candidates.first->spec; + params.cmd_spec = spec; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); + U32 hit_char = os_codepoint_from_event_flags_and_key(event->flags, event->key); + os_eat_event(&events, event); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CommandFastPath)); + if(event->flags & OS_EventFlag_Alt) + { + window->menu_bar_focus_press_started = 0; + } + } + df_gfx_request_frame(); + } + else if(event->kind == OS_EventKind_Text) + { + String32 insertion32 = str32(&event->character, 1); + String8 insertion8 = str8_from_32(scratch.arena, insertion32); + DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_InsertText); + params.string = insertion8; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, spec); + df_gfx_request_frame(); + } + } + } + + //- rjf: menu bar focus + { + for(OS_Event *event = events.first, *next = 0; event != 0; event = next) + { + next = event->next; + DF_Window *ws = df_window_from_os_handle(event->window); + if(ws == 0) + { + continue; + } + if(event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->is_repeat == 0) + { + ws->menu_bar_focused_on_press = ws->menu_bar_focused; + ws->menu_bar_key_held = 1; + ws->menu_bar_focus_press_started = 1; + } + if(event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->is_repeat == 0) + { + ws->menu_bar_key_held = 0; + } + if(ws->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->is_repeat == 0) + { + os_eat_event(&events, event); + ws->menu_bar_focused = 0; + } + else if(ws->menu_bar_focus_press_started && !ws->menu_bar_focused && event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->is_repeat == 0) + { + os_eat_event(&events, event); + ws->menu_bar_focused = !ws->menu_bar_focused_on_press; + ws->menu_bar_focus_press_started = 0; + } + else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && ws->menu_bar_focused && !ui_any_ctx_menu_is_open()) + { + os_eat_event(&events, event); + ws->menu_bar_focused = 0; + } + } + } + + //- rjf: gather root-level commands + DF_CmdList cmds = df_core_gather_root_cmds(scratch.arena); + + //- rjf: begin frame + df_core_begin_frame(scratch.arena, &cmds, dt); + df_gfx_begin_frame(scratch.arena, &cmds); + + //- rjf: queue drop for drag/drop + if(df_drag_is_active()) + { + for(OS_Event *event = events.first; event != 0; event = event->next) + { + if(event->kind == OS_EventKind_Release && event->key == OS_Key_LeftMouseButton) + { + df_queue_drag_drop(); + break; + } + } + } + + //- rjf: auto-focus moused-over windows while dragging + if(df_drag_is_active()) + { + B32 over_focused_window = 0; + { + for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) + { + Vec2F32 mouse = os_mouse_from_window(window->os); + Rng2F32 rect = os_client_rect_from_window(window->os); + if(os_window_is_focused(window->os) && contains_2f32(rect, mouse)) + { + over_focused_window = 1; + break; + } + } + } + if(!over_focused_window) + { + for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) + { + Vec2F32 mouse = os_mouse_from_window(window->os); + Rng2F32 rect = os_client_rect_from_window(window->os); + if(!os_window_is_focused(window->os) && contains_2f32(rect, mouse)) + { + os_window_focus(window->os); + break; + } + } + } + } + + //- rjf: update & render + { + d_begin_frame(); + for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) + { + df_window_update_and_render(scratch.arena, &events, w, &cmds); + } + } + + //- rjf: end frontend frame, send signals, etc. + df_gfx_end_frame(); + df_core_end_frame(); + + //- rjf: submit rendering to all windows + { + r_begin_frame(); + for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) + { + r_window_begin_frame(w->os, w->r); + d_submit_bucket(w->os, w->r, w->draw_bucket); + r_window_end_frame(w->os, w->r); + } + r_end_frame(); + } + + //- rjf: take window closing events + for(OS_Event *e = events.first; e; e = e->next) + { + if(e->kind == OS_EventKind_WindowClose) + { + for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) + { + if(os_handle_match(w->os, e->window)) + { + DF_CmdParams params = df_cmd_params_from_window(w); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow)); + break; + } + } + } + } + + scratch_end(scratch); + ProfEnd(); +} + +internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook) +{ + os_send_wakeup_event(); +} + +internal void +entry_point(int argc, char **argv) +{ + Temp scratch = scratch_begin(0, 0); +#if PROFILE_TELEMETRY + local_persist U8 tm_data[MB(64)]; + tmLoadLibrary(TM_RELEASE); + tmSetMaxThreadCount(1024); + tmInitialize(sizeof(tm_data), (char *)tm_data); +#endif + ThreadName("[main]"); + + //- rjf: initialize basic dependencies + os_init(argc, argv); + + //- rjf: parse command line arguments + CmdLine cmdln = cmd_line_from_string_list(scratch.arena, os_get_command_line_arguments()); + ExecMode exec_mode = ExecMode_Normal; + String8 user_cfg_path = str8_lit(""); + String8 profile_cfg_path = str8_lit(""); + B32 capture = 0; + B32 auto_run = 0; + B32 auto_step = 0; + B32 jit_attach = 0; + U64 jit_pid = 0; + U64 jit_code = 0; + U64 jit_addr = 0; + { + if(cmd_line_has_flag(&cmdln, str8_lit("ipc"))) + { + exec_mode = ExecMode_IPCSender; + } + else if(cmd_line_has_flag(&cmdln, str8_lit("convert"))) + { + exec_mode = ExecMode_Converter; + } + else if(cmd_line_has_flag(&cmdln, str8_lit("?")) || + cmd_line_has_flag(&cmdln, str8_lit("help"))) + { + exec_mode = ExecMode_Help; + } + user_cfg_path = cmd_line_string(&cmdln, str8_lit("user")); + profile_cfg_path = cmd_line_string(&cmdln, str8_lit("profile")); + capture = cmd_line_has_flag(&cmdln, str8_lit("capture")); + auto_run = cmd_line_has_flag(&cmdln, str8_lit("auto_run")); + auto_step = cmd_line_has_flag(&cmdln, str8_lit("auto_step")); + String8 jit_pid_string = {0}; + String8 jit_code_string = {0}; + String8 jit_addr_string = {0}; + jit_pid_string = cmd_line_string(&cmdln, str8_lit("jit_pid")); + jit_code_string = cmd_line_string(&cmdln, str8_lit("jit_code")); + jit_addr_string = cmd_line_string(&cmdln, str8_lit("jit_addr")); + try_u64_from_str8_c_rules(jit_pid_string, &jit_pid); + try_u64_from_str8_c_rules(jit_code_string, &jit_code); + try_u64_from_str8_c_rules(jit_addr_string, &jit_addr); + jit_attach = (jit_addr != 0); + } + + //- rjf: auto-start capture + if(capture) + { + ProfBeginCapture("raddbg"); + } + + //- rjf: set default user/profile paths + { + String8 user_program_data_path = os_string_from_system_path(scratch.arena, OS_SystemPath_UserProgramData); + String8 user_data_folder = push_str8f(scratch.arena, "%S/%S", user_program_data_path, str8_lit("raddbg")); + os_make_directory(user_data_folder); + if(user_cfg_path.size == 0) + { + user_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_user", user_data_folder); + } + if(profile_cfg_path.size == 0) + { + profile_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_profile", user_data_folder); + } + } + + //- rjf: dispatch to top-level codepath based on execution mode + switch(exec_mode) + { + //- rjf: normal execution + default: + case ExecMode_Normal: + { + //- rjf: set up shared memory for ipc + OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); + void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); + OS_Handle ipc_semaphore = os_semaphore_alloc(1, 1, ipc_semaphore_name); + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + ipc_info->msg_size = 0; + + //- rjf: initialize stuff we depend on + { + hs_init(); + txt_init(); + dbgi_init(); + txti_init(); + demon_init(); + ctrl_init(wakeup_hook); + dasm_init(); + os_graphical_init(); + fp_init(); + r_init(); + tex_init(); + geo_init(); + f_init(); + DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); + df_core_init(user_cfg_path, profile_cfg_path, hist); + df_gfx_init(update_and_render, hist); + os_set_cursor(OS_Cursor_Pointer); + } + + //- rjf: setup initial target from command line args + { + String8List args = cmdln.inputs; + if(args.node_count > 0 && args.first->string.size != 0) + { + Temp scratch = scratch_begin(0, 0); + DF_Entity *target = df_entity_alloc(0, df_entity_root(), DF_EntityKind_Target); + df_entity_equip_b32(target, 1); + df_entity_equip_cfg_src(target, DF_CfgSrc_CommandLine); + String8List passthrough_args_list = {0}; + for(String8Node *n = args.first->next; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &passthrough_args_list, n->string); + } + + // rjf: equip exe + if(args.first->string.size != 0) + { + DF_Entity *exe = df_entity_alloc(0, target, DF_EntityKind_Executable); + df_entity_equip_name(0, exe, args.first->string); + } + + // rjf: equip path + String8 path_part_of_arg = str8_chop_last_slash(args.first->string); + if(path_part_of_arg.size != 0) + { + String8 path = push_str8f(scratch.arena, "%S/", path_part_of_arg); + DF_Entity *execution_path = df_entity_alloc(0, target, DF_EntityKind_ExecutionPath); + df_entity_equip_name(0, execution_path, path); + } + + // rjf: equip args + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + String8 args_str = str8_list_join(scratch.arena, &passthrough_args_list, &join); + if(args_str.size != 0) + { + DF_Entity *args_entity = df_entity_alloc(0, target, DF_EntityKind_Arguments); + df_entity_equip_name(0, args_entity, args_str); + } + scratch_end(scratch); + } + } + + //- rjf: main application loop + { + for(;;) + { + //- rjf: get IPC messages & dispatch ui commands from them + { + if(os_semaphore_take(ipc_semaphore, max_U64)) + { + if(ipc_info->msg_size != 0) + { + U8 *buffer = (U8 *)(ipc_info+1); + U64 msg_size = ipc_info->msg_size; + String8 cmd_string = str8(buffer, msg_size); + ipc_info->msg_size = 0; + DF_Window *dst_window = df_gfx_state->first_window; + for(DF_Window *window = dst_window; window != 0; window = window->next) + { + if(os_window_is_focused(window->os)) + { + dst_window = window; + break; + } + } + if(dst_window != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 cmd_spec_string = df_cmd_name_part_from_string(cmd_string); + DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(cmd_spec_string); + if(!df_cmd_spec_is_nil(cmd_spec)) + { + DF_CmdParams params = df_cmd_params_from_gfx(); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(dst_window); + String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, cmd_spec, df_cmd_arg_part_from_string(cmd_string)); + if(error.size == 0) + { + df_push_cmd__root(¶ms, cmd_spec); + } + else + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + params.string = error; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + } + scratch_end(scratch); + } + } + os_semaphore_drop(ipc_semaphore); + } + } + + //- rjf: update & render frame + OS_Handle repaint_window = {0}; + update_and_render(repaint_window, 0); + + //- rjf: auto run + if(auto_run) + { + auto_run = 0; + DF_CmdParams params = df_cmd_params_from_gfx(); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); + } + + //- rjf: auto step + if(auto_step) + { + auto_step = 0; + DF_CmdParams params = df_cmd_params_from_gfx(); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_StepInto)); + } + + //- rjf: jit attach + if(jit_attach) + { + jit_attach = 0; + DF_CmdParams params = df_cmd_params_from_gfx(); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_ID); + params.id = jit_pid; + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Attach)); + } + + //- rjf: quit if no windows are left + if(df_gfx_state->first_window == 0) + { + break; + } + } + } + + }break; + + //- rjf: inter-process communication message sender + case ExecMode_IPCSender: + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: grab ipc shared memory + OS_Handle ipc_shared_memory = os_shared_memory_open(ipc_shared_memory_name); + void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, MB(16))); + if(ipc_shared_memory_base != 0) + { + OS_Handle ipc_semaphore = os_semaphore_open(ipc_semaphore_name); + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + if(os_semaphore_take(ipc_semaphore, os_now_microseconds() + Million(6))) + { + U8 *buffer = (U8 *)(ipc_info+1); + U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + String8 msg = str8_list_join(scratch.arena, &cmdln.inputs, &join); + ipc_info->msg_size = Min(buffer_max, msg.size); + MemoryCopy(buffer, msg.str, ipc_info->msg_size); + os_semaphore_drop(ipc_semaphore); + } + } + + scratch_end(scratch); + }break; + + //- rjf: built-in pdb/dwarf -> raddbg converter mode + case ExecMode_Converter: + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: parse arguments + PDBCONV_Params *params = pdb_convert_params_from_cmd_line(scratch.arena, &cmdln); + + //- rjf: open output file + String8 output_name = push_str8_copy(scratch.arena, params->output_name); + OS_Handle out_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, output_name); + B32 out_file_is_good = !os_handle_match(out_file, os_handle_zero()); + + //- rjf: convert + PDBCONV_Out *out = 0; + if(out_file_is_good) + { + out = pdbconv_convert(scratch.arena, params); + } + + //- rjf: bake file + if(out != 0 && params->output_name.size > 0) + { + String8List baked = {0}; + cons_bake_file(scratch.arena, out->root, &baked); + U64 off = 0; + for(String8Node *node = baked.first; node != 0; node = node->next) + { + os_file_write(out_file, r1u64(off, off+node->string.size), node->string.str); + off += node->string.size; + } + } + + //- rjf: close output file + os_file_close(out_file); + + scratch_end(scratch); + }break; + + //- rjf: help message box + case ExecMode_Help: + { + os_graphical_message(0, + str8_lit("The RAD Debugger - Help"), + str8_lit("The following options may be used when starting the RAD Debugger from the command line:\n\n" + "--user:\n" + "Use to specify the location of a user file which should be used. User files are used to store settings for users, including window and panel setups, path mapping, and visual settings. If this file does not exist, it will be created as necessary. This file will be autosaved as user-related changes are made.\n\n" + "--profile:\n" + "Use to specify the location of a profile file which should be used. Profile files are used to store settings for users and projects. If this file does not exist, it will be created as necessary. This file will be autosaved as profile-related changes are made.\n\n" + "--auto_step\n" + "This will step into all targets after the debugger initially starts.\n\n" + "--auto_run\n" + "This will run all targets after the debugger initially starts.\n\n" + "--ipc \n" + "This will launch the debugger in the non-graphical IPC mode, which is used to communicate with another running instance of the debugger. The debugger instance will launch, send the specified command, then immediately terminate. This may be used by editors or other programs to control the debugger.\n\n")); + }break; + } + + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: Low-Level Entry Points + +#if OS_WINDOWS + +global DWORD g_saved_exception_code = 0; + +internal DWORD +win32_exception_filter(DWORD dwExceptionCode) +{ + g_saved_exception_code = dwExceptionCode; + return EXCEPTION_EXECUTE_HANDLER; +} + +int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) +{ + HANDLE output_handles[3] = + { + GetStdHandle(STD_INPUT_HANDLE), + GetStdHandle(STD_OUTPUT_HANDLE), + GetStdHandle(STD_ERROR_HANDLE), + }; + for(U64 idx = 0; idx < ArrayCount(output_handles); idx += 1) + { + B32 duplicate = 0; + for(U64 idx2 = 0; idx2 < idx; idx2 += 1) + { + if(output_handles[idx2] == output_handles[idx]) + { + duplicate = 1; + break; + } + } + if(duplicate) + { + output_handles[idx] = 0; + } + } + for(U64 idx = 0; idx < ArrayCount(output_handles); idx += 1) + { + if(output_handles[idx] != 0) + { + CloseHandle(output_handles[idx]); + } + } + SetStdHandle(STD_INPUT_HANDLE, 0); + SetStdHandle(STD_OUTPUT_HANDLE, 0); + SetStdHandle(STD_ERROR_HANDLE, 0); + static TCTX main_thread_tctx = {0}; + tctx_init_and_equip(&main_thread_tctx); + Arena *perm_arena = arena_alloc(); + WCHAR *command_line = GetCommandLineW(); + int argc; + WCHAR **argv_16 = CommandLineToArgvW(command_line, &argc); + char **argv = push_array(perm_arena, char *, argc); + for(int i = 0; i < argc; i += 1) + { + String16 arg16 = str16_cstring((U16 *)argv_16[i]); + String8 arg8 = str8_from_16(perm_arena, arg16); + argv[i] = (char *)arg8.str; + } + __try + { + entry_point(argc, argv); + } + __except(win32_exception_filter(GetExceptionCode())) + { + char buffer[256] = {0}; + raddbg_snprintf(buffer, sizeof(buffer), "A fatal exception (code 0x%x) occurred. The process is terminating.", (U32)g_saved_exception_code); + os_graphical_message(1, str8_lit("Fatal Exception"), str8_cstring(buffer)); + ExitProcess(1); + } + return 0; +} +#elif OS_LINUX +int main(int argument_count, char **arguments) +{ + static TCTX main_thread_tctx = {0}; + tctx_init_and_equip(&main_thread_tctx); + entry_point(argument_count, arguments); + return 0; +} +#endif diff --git a/src/raddbg_cons/raddbg_cons.c b/src/raddbg_cons/raddbg_cons.c new file mode 100644 index 00000000..6d2a3b1d --- /dev/null +++ b/src/raddbg_cons/raddbg_cons.c @@ -0,0 +1,3375 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//- "Public Facing" Cons API + +//- init +static CONS_Root* +cons_root_new(CONS_RootParams *params){ + Arena *arena = arena_alloc__sized(GB(64), MB(256)); + CONS_Root *result = push_array(arena, CONS_Root, 1); + result->arena = arena; + + // fill in root parameters + { + result->addr_size = params->addr_size; + } + + // setup singular types + { + result->nil_type = cons__type_new(result); + result->variadic_type = cons__type_new(result); + result->variadic_type->kind = RADDBG_TypeKind_Variadic; + + // references to "handled nil type" should be emitted as + // references to nil - but should not generate error + // messages when they are detected - they are expected! + Assert(result->nil_type->idx == result->handled_nil_type.idx); + } + + // setup a null scope + { + CONS_Scope *scope = push_array(result->arena, CONS_Scope, 1); + SLLQueuePush_N(result->first_scope, result->last_scope, scope, next_order); + result->scope_count += 1; + } + + // initialize maps + { +#define BKTCOUNT(x) ((x)?(u64_up_to_pow2(x)):(128)) + + cons__u64toptr_init(arena, &result->unit_map, BKTCOUNT(params->bucket_count_units)); + cons__u64toptr_init(arena, &result->symbol_map, BKTCOUNT(params->bucket_count_symbols)); + cons__u64toptr_init(arena, &result->scope_map, BKTCOUNT(params->bucket_count_scopes)); + cons__u64toptr_init(arena, &result->local_map, BKTCOUNT(params->bucket_count_locals)); + cons__u64toptr_init(arena, &result->type_from_id_map, BKTCOUNT(params->bucket_count_types)); + +#undef BKTCOUNT + } + + return(result); +} + +static void +cons_root_release(CONS_Root *root){ + arena_release(root->arena); +} + +//- baking +static void +cons_bake_file(Arena *arena, CONS_Root *root, String8List *out){ + ProfBegin("cons_bake_file"); + str8_serial_begin(arena, out); + + // setup cons helpers + CONS__DSections dss = {0}; + cons__dsection(arena, &dss, 0, 0, RADDBG_DataSectionTag_NULL); + + CONS__BakeCtx *bctx = cons__bake_ctx_begin(); + + //////////////////////////////// + // MAIN PART: allocating and filling out sections of the file + + // top level info + RADDBG_TopLevelInfo *tli = push_array(arena, RADDBG_TopLevelInfo, 1); + { + CONS_TopLevelInfo *cons_tli = &root->top_level_info; + tli->architecture = cons_tli->architecture; + tli->exe_name_string_idx = cons__string(bctx, cons_tli->exe_name); + tli->exe_hash = cons_tli->exe_hash; + tli->voff_max = cons_tli->voff_max; + } + cons__dsection(arena, &dss, tli, sizeof(*tli), RADDBG_DataSectionTag_TopLevelInfo); + + // binary sections array + { + U32 count = root->binary_section_count; + RADDBG_BinarySection *sections = push_array(arena, RADDBG_BinarySection, count); + RADDBG_BinarySection *dsec = sections; + for (CONS_BinarySection *ssec = root->binary_section_first; + ssec != 0; + ssec = ssec->next, dsec += 1){ + dsec->name_string_idx = cons__string(bctx, ssec->name); + dsec->flags = ssec->flags; + dsec->voff_first = ssec->voff_first; + dsec->voff_opl = ssec->voff_opl; + dsec->foff_first = ssec->foff_first; + dsec->foff_opl = ssec->foff_opl; + } + cons__dsection(arena, &dss, sections, sizeof(*sections)*count, RADDBG_DataSectionTag_BinarySections); + } + + // units array + // * pass for per-unit information including: + // * top-level unit information + // * combining line info for whole unit + { + U32 count = root->unit_count; + RADDBG_Unit *units = push_array(arena, RADDBG_Unit, count); + RADDBG_Unit *dunit = units; + for (CONS_Unit *sunit = root->unit_first; + sunit != 0; + sunit = sunit->next_order, dunit += 1){ + // strings & paths + U32 unit_name = cons__string(bctx, sunit->unit_name); + U32 cmp_name = cons__string(bctx, sunit->compiler_name); + + U32 src_path = cons__paths_idx_from_path(bctx, sunit->source_file); + U32 obj_path = cons__paths_idx_from_path(bctx, sunit->object_file); + U32 archive_path = cons__paths_idx_from_path(bctx, sunit->archive_file); + U32 build_path = cons__paths_idx_from_path(bctx, sunit->build_path); + + dunit->unit_name_string_idx = unit_name; + dunit->compiler_name_string_idx = cmp_name; + dunit->source_file_path_node = src_path; + dunit->object_file_path_node = obj_path; + dunit->archive_file_path_node = archive_path; + dunit->build_path_node = build_path; + dunit->language = sunit->language; + + // line info (voff -> file*line*col) + CONS_LineSequenceNode *first_seq = sunit->line_seq_first; + CONS__UnitLinesCombined *lines = cons__unit_combine_lines(arena, bctx, first_seq); + + U32 line_count = lines->line_count; + if (line_count > 0){ + dunit->line_info_voffs_data_idx = + cons__dsection(arena, &dss, lines->voffs, sizeof(U64)*(line_count + 1), + RADDBG_DataSectionTag_LineInfoVoffs); + dunit->line_info_data_idx = + cons__dsection(arena, &dss, lines->lines, sizeof(RADDBG_Line)*line_count, + RADDBG_DataSectionTag_LineInfoData); + if (lines->cols != 0){ + dunit->line_info_col_data_idx = + cons__dsection(arena, &dss, lines->cols, sizeof(RADDBG_Column)*line_count, + RADDBG_DataSectionTag_LineInfoColumns); + } + dunit->line_info_count = line_count; + } + } + + cons__dsection(arena, &dss, units, sizeof(*units)*count, RADDBG_DataSectionTag_Units); + } + + // source file line info baking + // * pass for "source_combine_line" for each source file - + // * can only be run after a pass that does "unit_combine_lines" for each unit. + for (CONS__SrcNode *src_node = bctx->tree->src_first; + src_node != 0; + src_node = src_node->next){ + CONS__LineMapFragment *first_fragment = src_node->first_fragment; + CONS__SrcLinesCombined *lines = cons__source_combine_lines(arena, first_fragment); + U32 line_count = lines->line_count; + + if (line_count > 0){ + src_node->line_map_count = line_count; + + src_node->line_map_nums_data_idx = + cons__dsection(arena, &dss, lines->line_nums, sizeof(*lines->line_nums)*line_count, + RADDBG_DataSectionTag_LineMapNumbers); + + src_node->line_map_range_data_idx = + cons__dsection(arena, &dss, lines->line_ranges, sizeof(*lines->line_ranges)*(line_count + 1), + RADDBG_DataSectionTag_LineMapRanges); + + src_node->line_map_voff_data_idx = + cons__dsection(arena, &dss, lines->voffs, sizeof(*lines->voffs)*lines->voff_count, + RADDBG_DataSectionTag_LineMapVoffs); + } + } + + // source file name mapping + { + CONS__NameMap* map = cons__name_map_for_kind(root, RADDBG_NameMapKind_NormalSourcePaths); + for (CONS__SrcNode *src_node = bctx->tree->src_first; + src_node != 0; + src_node = src_node->next){ + if (src_node->idx != 0){ + cons__name_map_add_pair(root, map, src_node->normal_full_path, src_node->idx); + } + } + } + + // unit vmap baking + { + CONS__VMap *vmap = cons__vmap_from_unit_ranges(arena, + root->unit_vmap_range_first, + root->unit_vmap_range_count); + + U64 vmap_size = sizeof(*vmap->vmap)*(vmap->count + 1); + cons__dsection(arena, &dss, vmap->vmap, vmap_size, RADDBG_DataSectionTag_UnitVmap); + } + + // type info baking + { + CONS__TypeData *types = cons__type_data_combine(arena, root, bctx); + + U64 type_nodes_size = sizeof(*types->type_nodes)*types->type_node_count; + cons__dsection(arena, &dss, types->type_nodes, type_nodes_size, RADDBG_DataSectionTag_TypeNodes); + + U64 udt_size = sizeof(*types->udts)*types->udt_count; + cons__dsection(arena, &dss, types->udts, udt_size, RADDBG_DataSectionTag_UDTs); + + U64 member_size = sizeof(*types->members)*types->member_count; + cons__dsection(arena, &dss, types->members, member_size, RADDBG_DataSectionTag_Members); + + U64 enum_member_size = sizeof(*types->enum_members)*types->enum_member_count; + cons__dsection(arena, &dss, types->enum_members, enum_member_size, RADDBG_DataSectionTag_EnumMembers); + } + + // symbol info baking + { + CONS__SymbolData *symbol_data = cons__symbol_data_combine(arena, root, bctx); + + U64 global_variables_size = + sizeof(*symbol_data->global_variables)*symbol_data->global_variable_count; + cons__dsection(arena, &dss, symbol_data->global_variables, global_variables_size, + RADDBG_DataSectionTag_GlobalVariables); + + CONS__VMap *global_vmap = symbol_data->global_vmap; + U64 global_vmap_size = sizeof(*global_vmap->vmap)*(global_vmap->count + 1); + cons__dsection(arena, &dss, global_vmap->vmap, global_vmap_size, + RADDBG_DataSectionTag_GlobalVmap); + + U64 thread_variables_size = + sizeof(*symbol_data->thread_variables)*symbol_data->thread_variable_count; + cons__dsection(arena, &dss, symbol_data->thread_variables, thread_variables_size, + RADDBG_DataSectionTag_ThreadVariables); + + U64 procedures_size = sizeof(*symbol_data->procedures)*symbol_data->procedure_count; + cons__dsection(arena, &dss, symbol_data->procedures, procedures_size, + RADDBG_DataSectionTag_Procedures); + + U64 scopes_size = sizeof(*symbol_data->scopes)*symbol_data->scope_count; + cons__dsection(arena, &dss, symbol_data->scopes, scopes_size, RADDBG_DataSectionTag_Scopes); + + U64 scope_voffs_size = sizeof(*symbol_data->scope_voffs)*symbol_data->scope_voff_count; + cons__dsection(arena, &dss, symbol_data->scope_voffs, scope_voffs_size, + RADDBG_DataSectionTag_ScopeVoffData); + + CONS__VMap *scope_vmap = symbol_data->scope_vmap; + U64 scope_vmap_size = sizeof(*scope_vmap->vmap)*(scope_vmap->count + 1); + cons__dsection(arena, &dss, scope_vmap->vmap, scope_vmap_size, RADDBG_DataSectionTag_ScopeVmap); + + U64 local_size = sizeof(*symbol_data->locals)*symbol_data->local_count; + cons__dsection(arena, &dss, symbol_data->locals, local_size, RADDBG_DataSectionTag_Locals); + + U64 location_blocks_size = + sizeof(*symbol_data->location_blocks)*symbol_data->location_block_count; + cons__dsection(arena, &dss, symbol_data->location_blocks, location_blocks_size, + RADDBG_DataSectionTag_LocationBlocks); + + U64 location_data_size = symbol_data->location_data_size; + cons__dsection(arena, &dss, symbol_data->location_data, location_data_size, + RADDBG_DataSectionTag_LocationData); + } + + // name map baking + { + U32 name_map_count = 0; + for (U32 i = 0; i < RADDBG_NameMapKind_COUNT; i += 1){ + if (root->name_maps[i] != 0){ + name_map_count += 1; + } + } + + RADDBG_NameMap *name_maps = push_array(arena, RADDBG_NameMap, name_map_count); + + RADDBG_NameMap *name_map_ptr = name_maps; + for (U32 i = 0; i < RADDBG_NameMapKind_COUNT; i += 1){ + CONS__NameMap *map = root->name_maps[i]; + if (map != 0){ + CONS__NameMapBaked *baked = cons__name_map_bake(arena, root, bctx, map); + + name_map_ptr->kind = i; + name_map_ptr->bucket_data_idx = + cons__dsection(arena, &dss, baked->buckets, sizeof(*baked->buckets)*baked->bucket_count, + RADDBG_DataSectionTag_NameMapBuckets); + name_map_ptr->node_data_idx = + cons__dsection(arena, &dss, baked->nodes, sizeof(*baked->nodes)*baked->node_count, + RADDBG_DataSectionTag_NameMapNodes); + name_map_ptr += 1; + } + } + + cons__dsection(arena, &dss, name_maps, sizeof(*name_maps)*name_map_count, + RADDBG_DataSectionTag_NameMaps); + } + + //////////////////////////////// + // LATE PART: baking loose structures and creating final layout + + // generate data sections for file paths + { + U32 count = bctx->tree->count; + RADDBG_FilePathNode *nodes = push_array(arena, RADDBG_FilePathNode, count); + + RADDBG_FilePathNode *out_node = nodes; + for (CONS__PathNode *node = bctx->tree->first; + node != 0; + node = node->next_order, out_node += 1){ + out_node->name_string_idx = cons__string(bctx, node->name); + if (node->parent != 0){ + out_node->parent_path_node = node->parent->idx; + } + if (node->first_child != 0){ + out_node->first_child = node->first_child->idx; + } + if (node->next_sibling != 0){ + out_node->next_sibling = node->next_sibling->idx; + } + if (node->src_file != 0){ + out_node->source_file_idx = node->src_file->idx; + } + } + + cons__dsection(arena, &dss, nodes, sizeof(*nodes)*count, RADDBG_DataSectionTag_FilePathNodes); + } + + // generate data sections for files + { + U32 count = bctx->tree->src_count; + RADDBG_SourceFile *src_files = push_array(arena, RADDBG_SourceFile, count); + + RADDBG_SourceFile *out_src_file = src_files; + for (CONS__SrcNode *node = bctx->tree->src_first; + node != 0; + node = node->next, out_src_file += 1){ + out_src_file->file_path_node_idx = node->path_node->idx; + out_src_file->normal_full_path_string_idx = cons__string(bctx, node->normal_full_path); + out_src_file->line_map_nums_data_idx = node->line_map_nums_data_idx; + out_src_file->line_map_range_data_idx = node->line_map_range_data_idx; + out_src_file->line_map_count = node->line_map_count; + out_src_file->line_map_voff_data_idx = node->line_map_voff_data_idx; + } + + cons__dsection(arena, &dss, src_files, sizeof(*src_files)*count, RADDBG_DataSectionTag_SourceFiles); + } + + // generate data sections for strings + { + U32 *str_offs = push_array_no_zero(arena, U32, bctx->strs.count + 1); + + U32 off_cursor = 0; + { + U32 *off_ptr = str_offs; + *off_ptr = 0; + off_ptr += 1; + for (CONS__StringNode *node = bctx->strs.order_first; + node != 0; + node = node->order_next){ + off_cursor += node->str.size; + *off_ptr = off_cursor; + off_ptr += 1; + } + } + + U8 *buf = push_array(arena, U8, off_cursor); + { + U8 *ptr = buf; + for (CONS__StringNode *node = bctx->strs.order_first; + node != 0; + node = node->order_next){ + MemoryCopy(ptr, node->str.str, node->str.size); + ptr += node->str.size; + } + } + + cons__dsection(arena, &dss, str_offs, sizeof(*str_offs)*(bctx->strs.count + 1), + RADDBG_DataSectionTag_StringTable); + cons__dsection(arena, &dss, buf, off_cursor, RADDBG_DataSectionTag_StringData); + } + + // generate data sections for index runs + { + U32 *idx_data = push_array_no_zero(arena, U32, bctx->idxs.idx_count); + + { + U32 *out_ptr = idx_data; + U32 *opl = out_ptr + bctx->idxs.idx_count; + CONS__IdxRunNode *node = bctx->idxs.order_first; + for (;node != 0 && out_ptr < opl; + node = node->order_next){ + MemoryCopy(out_ptr, node->idx_run, sizeof(*node->idx_run)*node->count); + out_ptr += node->count; + } + // both iterators should reach the end at the same time + Assert(node == 0); + Assert(out_ptr == opl); + } + + cons__dsection(arena, &dss, idx_data, sizeof(*idx_data)*bctx->idxs.idx_count, + RADDBG_DataSectionTag_IndexRuns); + } + + // layout + // * the header and data section table have to be initialized "out of order" + // * so that the rest of the system can avoid this tricky order-layout interdependence stuff + RADDBG_Header *header = push_array(arena, RADDBG_Header, 1); + RADDBG_DataSection *dstable = push_array(arena, RADDBG_DataSection, dss.count); + str8_serial_push_align(arena, out, 8); + U64 header_off = out->total_size; + str8_list_push(arena, out, str8_struct(header)); + str8_serial_push_align(arena, out, 8); + U64 data_section_off = out->total_size; + str8_list_push(arena, out, str8((U8 *)dstable, sizeof(*dstable)*dss.count)); + { + header->magic = RADDBG_MAGIC_CONSTANT; + header->encoding_version = RADDBG_ENCODING_VERSION; + header->data_section_off = data_section_off; + header->data_section_count = dss.count; + } + { + U64 test_dss_count = 0; + for (CONS__DSectionNode *node = dss.first; + node != 0; + node = node->next){ + test_dss_count += 1; + } + Assert(test_dss_count == dss.count); + + RADDBG_DataSection *ptr = dstable; + for (CONS__DSectionNode *node = dss.first; + node != 0; + node = node->next, ptr += 1){ + U64 data_section_offset = 0; + if(node->size != 0) + { + str8_serial_push_align(arena, out, 8); + data_section_offset = out->total_size; + str8_list_push(arena, out, str8((U8 *)node->data, node->size)); + } + ptr->tag = node->tag; + ptr->encoding = RADDBG_DataSectionEncoding_Unpacked; + ptr->off = data_section_offset; + ptr->encoded_size = node->size; + ptr->unpacked_size = node->size; + } + Assert(ptr == dstable + dss.count); + } + + cons__bake_ctx_release(bctx); + ProfEnd(); +} + + +//- errors +static void +cons_errorf(CONS_Root *root, char *fmt, ...){ + ProfBeginFunction(); + CONS_Error *error = push_array(root->arena, CONS_Error, 1); + SLLQueuePush(root->errors.first, root->errors.last, error); + root->errors.count += 1; + + va_list args; + va_start(args, fmt); + String8 str = push_str8fv(root->arena, fmt, args); + va_end(args); + + error->msg = str; + ProfEnd(); +} + +static CONS_Error* +cons_get_first_error(CONS_Root *root){ + return(root->errors.first); +} + + +//- information declaration + +// top level info + +static void +cons_set_top_level_info(CONS_Root *root, CONS_TopLevelInfo *tli){ + if (root->top_level_info_is_set){ + // TODO(allen): API error + } + else{ + MemoryCopyStruct(&root->top_level_info, tli); + root->top_level_info_is_set = 1; + } +} + +// binary sections + +static void +cons_add_binary_section(CONS_Root *root, String8 name, RADDBG_BinarySectionFlags flags, + U64 voff_first, U64 voff_opl, U64 foff_first, U64 foff_opl){ + CONS_BinarySection *sec = push_array(root->arena, CONS_BinarySection, 1); + SLLQueuePush(root->binary_section_first, root->binary_section_last, sec); + root->binary_section_count += 1; + + sec->name = name; + sec->flags = flags; + sec->voff_first = voff_first; + sec->voff_opl = voff_opl; + sec->foff_first = foff_first; + sec->foff_opl = foff_opl; +} + +// units + +static CONS_Unit* +cons_unit_handle_from_user_id(CONS_Root *root, U64 unit_user_id){ + CONS__U64ToPtrLookup lookup = {0}; + cons__u64toptr_lookup(&root->unit_map, unit_user_id, &lookup); + + CONS_Unit *result = 0; + if (lookup.match != 0){ + result = (CONS_Unit*)lookup.match; + } + else{ + result = push_array(root->arena, CONS_Unit, 1); + result->idx = root->unit_count; + SLLQueuePush_N(root->unit_first, root->unit_last, result, next_order); + root->unit_count += 1; + cons__u64toptr_insert(root->arena, &root->unit_map, unit_user_id, &lookup, result); + } + + return(result); +} + +static void +cons_unit_set_info(CONS_Root *root, CONS_Unit *unit, CONS_UnitInfo *info){ + if (unit->info_is_set){ + // TODO(allen): API error + } + else{ + unit->info_is_set = 1; + unit->unit_name = push_str8_copy(root->arena, info->unit_name); + unit->compiler_name = push_str8_copy(root->arena, info->compiler_name); + unit->source_file = push_str8_copy(root->arena, info->source_file); + unit->object_file = push_str8_copy(root->arena, info->object_file); + unit->archive_file = push_str8_copy(root->arena, info->archive_file); + unit->build_path = push_str8_copy(root->arena, info->build_path); + unit->language = info->language; + } +} + +static void +cons_unit_add_line_sequence(CONS_Root *root, CONS_Unit *unit, CONS_LineSequence *line_sequence){ + CONS_LineSequenceNode *node = push_array(root->arena, CONS_LineSequenceNode, 1); + SLLQueuePush(unit->line_seq_first, unit->line_seq_last, node); + unit->line_seq_count += 1; + + node->line_seq.file_name = push_str8_copy(root->arena, line_sequence->file_name); + + node->line_seq.voffs = push_array(root->arena, U64, line_sequence->line_count + 1); + MemoryCopy(node->line_seq.voffs, line_sequence->voffs, sizeof(U64)*(line_sequence->line_count + 1)); + + node->line_seq.line_nums = push_array(root->arena, U32, line_sequence->line_count); + MemoryCopy(node->line_seq.line_nums, line_sequence->line_nums, sizeof(U32)*line_sequence->line_count); + + if (line_sequence->col_nums != 0){ + node->line_seq.col_nums = push_array(root->arena, U16, line_sequence->line_count); + MemoryCopy(node->line_seq.col_nums, line_sequence->col_nums, sizeof(U16)*line_sequence->line_count); + } + + node->line_seq.line_count = line_sequence->line_count; +} + +static void +cons_unit_vmap_add_range(CONS_Root *root, CONS_Unit *unit, U64 first, U64 opl){ + CONS_UnitVMapRange *node = push_array(root->arena, CONS_UnitVMapRange, 1); + SLLQueuePush(root->unit_vmap_range_first, root->unit_vmap_range_last, node); + root->unit_vmap_range_count += 1; + + node->unit = unit; + node->first = first; + node->opl = opl; +} + +// types + +static CONS_Type* +cons_type_from_id(CONS_Root *root, U64 type_user_id){ + CONS__U64ToPtrLookup lookup = {0}; + cons__u64toptr_lookup(&root->type_from_id_map, type_user_id, &lookup); + + CONS_Type *result = (CONS_Type*)lookup.match; + return(result); +} + +static CONS_Reservation* +cons_type_reserve_id(CONS_Root *root, U64 type_user_id){ + CONS__U64ToPtrLookup lookup = {0}; + cons__u64toptr_lookup(&root->type_from_id_map, type_user_id, &lookup); + + CONS_Reservation *result = 0; + if (lookup.match == 0){ + cons__u64toptr_insert(root->arena, &root->type_from_id_map, type_user_id, &lookup, root->nil_type); + void **slot = &lookup.fill_node->ptr[lookup.fill_k]; + result = (CONS_Reservation*)slot; + } + + return(result); +} + +static void +cons_type_fill_id(CONS_Root *root, CONS_Reservation *res, CONS_Type *type){ + if (res != 0 && type != 0){ + *(void**)res = type; + } +} + +static B32 +cons_type_is_unhandled_nil(CONS_Root *root, CONS_Type *type){ + B32 result = (type->kind == RADDBG_TypeKind_NULL && + type != &root->handled_nil_type); + return(result); +} + +static CONS_Type* +cons_type_handled_nil(CONS_Root *root){ + return(&root->handled_nil_type); +} + +static CONS_Type* +cons_type_nil(CONS_Root *root){ + return(root->nil_type); +} + +static CONS_Type* +cons_type_variadic(CONS_Root *root){ + return(root->variadic_type); +} + +static CONS_Type* +cons_type_basic(CONS_Root *root, RADDBG_TypeKind type_kind, String8 name){ + CONS_Type *result = root->nil_type; + + if (!(RADDBG_TypeKind_FirstBuiltIn <= type_kind && + type_kind <= RADDBG_TypeKind_LastBuiltIn)){ + // TODO(allen): API error + } + else{ + Temp scratch = scratch_begin(0, 0); + + // setup construct buffer + U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(type_kind) + name.size; + U8 *buf = push_array(scratch.arena, U8, buf_size); + { + U8 *ptr = buf; + // "basic" + *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Basic; + ptr += sizeof(CONS_TypeConstructKind); + // type_kind + MemoryCopy(ptr, &type_kind, sizeof(type_kind)); + ptr += sizeof(type_kind); + // name + MemoryCopy(ptr, name.str, name.size); + ptr += name.size; + } + + // check for duplicate construct + String8 blob = str8(buf, buf_size); + U64 blob_hash = raddbg_hash(buf, buf_size); + void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); + result = (CONS_Type*)lookup_ptr; + if (result == 0){ + // calculate size + U32 byte_size = raddbg_size_from_basic_type_kind(type_kind); + if (byte_size == 0xFFFFFFFF){ + byte_size = root->addr_size; + } + + // setup new node + result = cons__type_new(root); + result->kind = type_kind; + result->name = push_str8_copy(root->arena, name); + result->byte_size = byte_size; + + // save in construct map + cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); + + // save in name map + { + CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); + cons__name_map_add_pair(root, map, result->name, result->idx); + } + } + + scratch_end(scratch); + } + + Assert(result != 0); + return(result); +} + +static CONS_Type* +cons_type_modifier(CONS_Root *root, CONS_Type *direct_type, RADDBG_TypeModifierFlags flags){ + ProfBeginFunction(); + CONS_Type *result = root->nil_type; + + { + Temp scratch = scratch_begin(0, 0); + + // setup construct buffer + U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(flags) + sizeof(direct_type->idx); + U8 *buf = push_array(scratch.arena, U8, buf_size); + { + U8 *ptr = buf; + // "modifier" + *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Modifier; + ptr += sizeof(CONS_TypeConstructKind); + // flags + MemoryCopy(ptr, &flags, sizeof(flags)); + ptr += sizeof(flags); + // direct_type->idx + MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); + ptr += sizeof(direct_type->idx); + } + + // check for duplicate construct + String8 blob = str8(buf, buf_size); + U64 blob_hash = raddbg_hash(buf, buf_size); + void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); + result = (CONS_Type*)lookup_ptr; + if (result == 0){ + + // setup new node + result = cons__type_new(root); + result->kind = RADDBG_TypeKind_Modifier; + result->flags = flags; + result->byte_size = direct_type->byte_size; + result->direct_type = direct_type; + + // save in construct map + cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); + } + + scratch_end(scratch); + } + + Assert(result != 0); + ProfEnd(); + return(result); +} + +static CONS_Type* +cons_type_bitfield(CONS_Root *root, CONS_Type *direct_type, U32 bit_off, U32 bit_count){ + CONS_Type *result = root->nil_type; + + { + Temp scratch = scratch_begin(0, 0); + + // setup construct buffer + U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(direct_type->idx) + sizeof(U32)*2; + U8 *buf = push_array(scratch.arena, U8, buf_size); + { + U8 *ptr = buf; + // "bitfield" + *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Bitfield; + ptr += sizeof(CONS_TypeConstructKind); + // direct_type->idx + MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); + ptr += sizeof(direct_type->idx); + // bit_off + MemoryCopy(ptr, &bit_off, sizeof(bit_off)); + ptr += sizeof(bit_off); + // bit_count + MemoryCopy(ptr, &bit_count, sizeof(bit_count)); + ptr += sizeof(bit_count); + } + + // check for duplicate construct + String8 blob = str8(buf, buf_size); + U64 blob_hash = raddbg_hash(buf, buf_size); + void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); + result = (CONS_Type*)lookup_ptr; + if (result == 0){ + + // setup new node + result = cons__type_new(root); + result->kind = RADDBG_TypeKind_Bitfield; + result->byte_size = direct_type->byte_size; + result->off = bit_off; + result->count = bit_count; + result->direct_type = direct_type; + + // save in construct map + cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); + } + + scratch_end(scratch); + } + + Assert(result != 0); + return(result); +} + +static CONS_Type* +cons_type_pointer(CONS_Root *root, CONS_Type *direct_type, RADDBG_TypeKind ptr_type_kind){ + ProfBeginFunction(); + CONS_Type *result = root->nil_type; + + if (!(ptr_type_kind == RADDBG_TypeKind_Ptr || + ptr_type_kind == RADDBG_TypeKind_LRef || + ptr_type_kind == RADDBG_TypeKind_RRef)){ + // TODO(allen): API error + } + else{ + Temp scratch = scratch_begin(0, 0); + + // setup construct buffer + U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(ptr_type_kind) + sizeof(direct_type->idx); + U8 *buf = push_array(scratch.arena, U8, buf_size); + { + U8 *ptr = buf; + // "pointer" + *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Pointer; + ptr += sizeof(CONS_TypeConstructKind); + // type_kind + MemoryCopy(ptr, &ptr_type_kind, sizeof(ptr_type_kind)); + ptr += sizeof(ptr_type_kind); + // direct_type->idx + MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); + ptr += sizeof(direct_type->idx); + } + + // check for duplicate construct + String8 blob = str8(buf, buf_size); + U64 blob_hash = raddbg_hash(buf, buf_size); + void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); + result = (CONS_Type*)lookup_ptr; + if (result == 0){ + + // setup new node + result = cons__type_new(root); + result->kind = ptr_type_kind; + result->byte_size = root->addr_size; + result->direct_type = direct_type; + + // save in construct map + cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); + } + + scratch_end(scratch); + } + + Assert(result != 0); + ProfEnd(); + return(result); +} + +static CONS_Type* +cons_type_array(CONS_Root *root, CONS_Type *direct_type, U64 count){ + CONS_Type *result = root->nil_type; + + { + Temp scratch = scratch_begin(0, 0); + + // setup construct buffer + U64 buf_size = + sizeof(CONS_TypeConstructKind) + sizeof(direct_type->idx) + sizeof(count); + U8 *buf = push_array(scratch.arena, U8, buf_size); + { + U8 *ptr = buf; + // "array" + *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Array; + ptr += sizeof(CONS_TypeConstructKind); + // direct_type->idx + MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); + ptr += sizeof(direct_type->idx); + // count + MemoryCopy(ptr, &count, sizeof(count)); + ptr += sizeof(count); + } + + // check for duplicate construct + String8 blob = str8(buf, buf_size); + U64 blob_hash = raddbg_hash(buf, buf_size); + void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); + result = (CONS_Type*)lookup_ptr; + if (result == 0){ + + // setup new node + result = cons__type_new(root); + result->kind = RADDBG_TypeKind_Array; + result->count = count; + result->direct_type = direct_type; + result->byte_size = direct_type->byte_size*count; + + // save in construct map + cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); + } + + scratch_end(scratch); + } + + Assert(result != 0); + return(result); +} + +static CONS_Type* +cons_type_proc(CONS_Root *root, CONS_Type *return_type, CONS_TypeList *params){ + ProfBeginFunction(); + CONS_Type *result = root->nil_type; + + { + Temp scratch = scratch_begin(0, 0); + + // setup construct buffer + U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(return_type->idx)*(1 + params->count); + U8 *buf = push_array(scratch.arena, U8, buf_size); + { + U8 *ptr = buf; + // "procedure" + *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Procedure; + ptr += sizeof(CONS_TypeConstructKind); + // ret_type->idx + MemoryCopy(ptr, &return_type->idx, sizeof(return_type->idx)); + ptr += sizeof(return_type->idx); + // (params ...)->idx + for (CONS_TypeNode *node = params->first; + node != 0; + node = node->next){ + MemoryCopy(ptr, &node->type->idx, sizeof(node->type->idx)); + ptr += sizeof(node->type->idx); + } + } + + // check for duplicate construct + String8 blob = str8(buf, buf_size); + U64 blob_hash = raddbg_hash(buf, buf_size); + void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); + result = (CONS_Type*)lookup_ptr; + if (result == 0){ + + // setup param buffer + CONS_Type **param_types = push_array(root->arena, CONS_Type*, params->count); + { + CONS_Type **ptr = param_types; + for (CONS_TypeNode *node = params->first; + node != 0; + node = node->next){ + *ptr = node->type; + ptr += 1; + } + } + + // setup new node + result = cons__type_new(root); + result->kind = RADDBG_TypeKind_Function; + result->byte_size = root->addr_size; + result->count = params->count; + result->direct_type = return_type; + result->param_types = param_types; + + // save in construct map + cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); + } + + scratch_end(scratch); + } + + Assert(result != 0); + ProfEnd(); + return(result); +} + +static CONS_Type* +cons_type_method(CONS_Root *root, CONS_Type *this_type, CONS_Type *return_type, CONS_TypeList *params){ + ProfBeginFunction(0, 0); + CONS_Type *result = root->nil_type; + + { + Temp scratch = scratch_begin(0, 0); + + // setup construct buffer + U64 buf_size = + sizeof(CONS_TypeConstructKind) + sizeof(return_type->idx)*(2 + params->count); + U8 *buf = push_array(scratch.arena, U8, buf_size); + { + U8 *ptr = buf; + // "method" + *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Method; + ptr += sizeof(CONS_TypeConstructKind); + // ret_type->idx + MemoryCopy(ptr, &return_type->idx, sizeof(return_type->idx)); + ptr += sizeof(return_type->idx); + // this_type->idx + MemoryCopy(ptr, &this_type->idx, sizeof(this_type->idx)); + ptr += sizeof(this_type->idx); + // (params ...)->idx + for (CONS_TypeNode *node = params->first; + node != 0; + node = node->next){ + MemoryCopy(ptr, &node->type->idx, sizeof(node->type->idx)); + ptr += sizeof(node->type->idx); + } + } + + // check for duplicate construct + String8 blob = str8(buf, buf_size); + U64 blob_hash = raddbg_hash(buf, buf_size); + void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); + result = (CONS_Type*)lookup_ptr; + if (result == 0){ + + // setup param buffer + CONS_Type **param_types = push_array(root->arena, CONS_Type*, params->count + 1); + { + CONS_Type **ptr = param_types; + { + *ptr = this_type; + ptr += 1; + } + for (CONS_TypeNode *node = params->first; + node != 0; + node = node->next){ + *ptr = node->type; + ptr += 1; + } + } + + // setup new node + result = cons__type_new(root); + result->kind = RADDBG_TypeKind_Method; + result->byte_size = root->addr_size; + result->count = params->count; + result->direct_type = return_type; + result->param_types = param_types; + + // save in construct map + cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); + } + + scratch_end(scratch); + } + + Assert(result != 0); + ProfEnd(); + return(result); +} + +static CONS_Type* +cons_type_udt(CONS_Root *root, RADDBG_TypeKind record_type_kind, String8 name, U64 size){ + CONS_Type *result = root->nil_type; + + if (!(record_type_kind == RADDBG_TypeKind_Struct || + record_type_kind == RADDBG_TypeKind_Class || + record_type_kind == RADDBG_TypeKind_Union)){ + // TODO(allen): API error + } + else{ + result = cons__type_new(root); + result->kind = record_type_kind; + result->byte_size = size; + result->name = push_str8_copy(root->arena, name); + + // save in name map + { + CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); + cons__name_map_add_pair(root, map, result->name, result->idx); + } + } + + return(result); +} + +static CONS_Type* +cons_type_enum(CONS_Root *root, CONS_Type *direct_type, String8 name){ + CONS_Type *result = cons__type_new(root); + result->kind = RADDBG_TypeKind_Enum; + result->byte_size = direct_type->byte_size; + result->name = push_str8_copy(root->arena, name); + result->direct_type = direct_type; + + // save in name map + { + CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); + cons__name_map_add_pair(root, map, result->name, result->idx); + } + + return(result); +} + +static CONS_Type* +cons_type_alias(CONS_Root *root, CONS_Type *direct_type, String8 name){ + CONS_Type *result = cons__type_new(root); + result->kind = RADDBG_TypeKind_Alias; + result->byte_size = direct_type->byte_size; + result->name = push_str8_copy(root->arena, name); + result->direct_type = direct_type; + + // save in name map + { + CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); + cons__name_map_add_pair(root, map, result->name, result->idx); + } + + return(result); +} + +static CONS_Type* +cons_type_incomplete(CONS_Root *root, RADDBG_TypeKind type_kind, String8 name){ + CONS_Type *result = root->nil_type; + + if (!(type_kind == RADDBG_TypeKind_IncompleteStruct || + type_kind == RADDBG_TypeKind_IncompleteClass || + type_kind == RADDBG_TypeKind_IncompleteUnion || + type_kind == RADDBG_TypeKind_IncompleteEnum)){ + // TODO(allen): API error + } + else{ + result = cons__type_new(root); + result->kind = type_kind; + result->name = push_str8_copy(root->arena, name); + + // save in name map + { + CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); + cons__name_map_add_pair(root, map, result->name, result->idx); + } + } + + return(result); +} + +static void +cons_type_add_member_data_field(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type, U32 off){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_DataField; + member->name = push_str8_copy(root->arena, name); + member->type = mem_type; + member->off = off; + } +} + +static void +cons_type_add_member_static_data(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_StaticData; + member->name = push_str8_copy(root->arena, name); + member->type = mem_type; + } +} + +static void +cons_type_add_member_method(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_Method; + member->name = push_str8_copy(root->arena, name); + member->type = mem_type; + } +} + +static void +cons_type_add_member_static_method(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_StaticMethod; + member->name = push_str8_copy(root->arena, name); + member->type = mem_type; + } +} + +static void +cons_type_add_member_virtual_method(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_VirtualMethod; + member->name = push_str8_copy(root->arena, name); + member->type = mem_type; + } +} + +static void +cons_type_add_member_base(CONS_Root *root, CONS_Type *record_type, + CONS_Type *base_type, U32 off){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_Base; + member->type = base_type; + member->off = off; + } +} + +static void +cons_type_add_member_virtual_base(CONS_Root *root, CONS_Type *record_type, + CONS_Type *base_type, U32 vptr_off, U32 vtable_off){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_VirtualBase; + member->type = base_type; + // TODO(allen): what to do with the two offsets in this case? + } +} + +static void +cons_type_add_member_nested_type(CONS_Root *root, CONS_Type *record_type, + CONS_Type *nested_type){ + CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); + if (udt != 0){ + CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); + SLLQueuePush(udt->first_member, udt->last_member, member); + udt->member_count += 1; + + root->total_member_count += 1; + + member->kind = RADDBG_MemberKind_NestedType; + member->type = nested_type; + } +} + +static void +cons_type_add_enum_val(CONS_Root *root, CONS_Type *enum_type, String8 name, U64 val){ + if (enum_type->kind != RADDBG_TypeKind_Enum){ + // TODO(allen): API error + } + else{ + CONS_TypeUDT *udt = cons__type_udt_from_any_type(root, enum_type); + + CONS_TypeEnumVal *enum_val = push_array(root->arena, CONS_TypeEnumVal, 1); + SLLQueuePush(udt->first_enum_val, udt->last_enum_val, enum_val); + udt->enum_val_count += 1; + + root->total_enum_val_count += 1; + + enum_val->name = push_str8_copy(root->arena, name); + enum_val->val = val; + } +} + +static void +cons_type_set_source_coordinates(CONS_Root *root, CONS_Type *defined_type, + String8 source_path, U32 line, U32 col){ + if (!(RADDBG_TypeKind_FirstUserDefined <= defined_type->kind && + defined_type->kind <= RADDBG_TypeKind_LastUserDefined)){ + // TODO(allen): API error + } + else{ + CONS_TypeUDT *udt = cons__type_udt_from_any_type(root, defined_type); + + udt->source_path = push_str8_copy(root->arena, source_path); + udt->line = line; + udt->col = col; + } +} + +// type list + +static void +cons_type_list_push(Arena *arena, CONS_TypeList *list, CONS_Type *type){ + CONS_TypeNode *node = push_array(arena, CONS_TypeNode, 1); + SLLQueuePush(list->first, list->last, node); + list->count += 1; + node->type = type; +} + +// symbols + +static CONS_Symbol* +cons_symbol_handle_from_user_id(CONS_Root *root, U64 symbol_user_id){ + CONS__U64ToPtrLookup lookup = {0}; + cons__u64toptr_lookup(&root->symbol_map, symbol_user_id, &lookup); + + CONS_Symbol *result = 0; + if (lookup.match != 0){ + result = (CONS_Symbol*)lookup.match; + } + else{ + result = push_array(root->arena, CONS_Symbol, 1); + SLLQueuePush_N(root->first_symbol, root->last_symbol, result, next_order); + root->symbol_count += 1; + cons__u64toptr_insert(root->arena, &root->symbol_map, symbol_user_id, &lookup, result); + } + + return(result); +} + +static void +cons_symbol_set_info(CONS_Root *root, CONS_Symbol *symbol, CONS_SymbolInfo *info){ + CONS_SymbolKind kind = info->kind; + + if (symbol->kind != CONS_SymbolKind_NULL){ + // TODO(allen): API error + } + else if (kind == CONS_SymbolKind_NULL || kind >= CONS_SymbolKind_COUNT){ + // TODO(allen): API error + } + else if (info->type == 0){ + // TODO(allen): API error + } + else{ + CONS_Symbol *container_symbol = info->container_symbol; + CONS_Type *container_type = info->container_type; + if (info->container_symbol != 0 && info->container_type != 0){ + // TODO(allen): API error + container_type = 0; + } + + root->symbol_kind_counts[kind] += 1; + symbol->idx = root->symbol_kind_counts[kind]; + + symbol->kind = kind; + symbol->name = push_str8_copy(root->arena, info->name); + symbol->link_name = push_str8_copy(root->arena, info->link_name); + symbol->type = info->type; + symbol->is_extern = info->is_extern; + symbol->offset = info->offset; + symbol->container_symbol = container_symbol; + symbol->container_type = container_type; + + // set root scope + switch (kind){ + default:{}break; + case CONS_SymbolKind_GlobalVariable: + case CONS_SymbolKind_ThreadVariable: + { + if (info->root_scope != 0){ + // TODO(allen): API error + } + }break; + + case CONS_SymbolKind_Procedure: + { + if (info->root_scope == 0){ + // TODO(allen): API error + } + else{ + symbol->root_scope = info->root_scope; + cons__scope_recursive_set_symbol(info->root_scope, symbol); + } + }break; + } + + // save name map + { + CONS__NameMap *map = 0; + switch (kind){ + default:{}break; + case CONS_SymbolKind_GlobalVariable: + { + map = cons__name_map_for_kind(root, RADDBG_NameMapKind_GlobalVariables); + }break; + case CONS_SymbolKind_ThreadVariable: + { + map = cons__name_map_for_kind(root, RADDBG_NameMapKind_ThreadVariables); + }break; + case CONS_SymbolKind_Procedure: + { + map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Procedures); + }break; + } + if (map != 0){ + cons__name_map_add_pair(root, map, symbol->name, symbol->idx); + } + } + + // save link name map + if (kind == CONS_SymbolKind_Procedure && symbol->link_name.size > 0){ + CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_LinkNameProcedures); + cons__name_map_add_pair(root, map, symbol->link_name, symbol->idx); + } + } +} + +// scopes + +static CONS_Scope* +cons_scope_handle_from_user_id(CONS_Root *root, U64 scope_user_id){ + CONS__U64ToPtrLookup lookup = {0}; + cons__u64toptr_lookup(&root->scope_map, scope_user_id, &lookup); + + CONS_Scope *result = 0; + if (lookup.match != 0){ + result = (CONS_Scope*)lookup.match; + } + else{ + result = push_array(root->arena, CONS_Scope, 1); + result->idx = root->scope_count; + SLLQueuePush_N(root->first_scope, root->last_scope, result, next_order); + root->scope_count += 1; + cons__u64toptr_insert(root->arena, &root->scope_map, scope_user_id, &lookup, result); + } + + return(result); +} + +static void +cons_scope_set_parent(CONS_Root *root, CONS_Scope *scope, CONS_Scope *parent){ + if (scope->parent_scope != 0){ + // TODO(allen): API error + } + else if (parent == 0){ + // TODO(allen): API error + } + else{ + scope->symbol = parent->symbol; + scope->parent_scope = parent; + SLLQueuePush_N(parent->first_child, parent->last_child, scope, next_sibling); + } +} + +static void +cons_scope_add_voff_range(CONS_Root *root, CONS_Scope *scope, U64 voff_first, U64 voff_opl){ + CONS__VOffRange *range = push_array(root->arena, CONS__VOffRange, 1); + SLLQueuePush(scope->first_range, scope->last_range, range); + scope->range_count += 1; + range->voff_first = voff_first; + range->voff_opl = voff_opl; + scope->voff_base = Min(scope->voff_base, voff_first); + root->scope_voff_count += 2; +} + +// locals + +static CONS_Local* +cons_local_handle_from_user_id(CONS_Root *root, U64 local_user_id){ + CONS__U64ToPtrLookup lookup = {0}; + cons__u64toptr_lookup(&root->local_map, local_user_id, &lookup); + + CONS_Local *result = 0; + if (lookup.match != 0){ + result = (CONS_Local*)lookup.match; + } + else{ + result = push_array(root->arena, CONS_Local, 1); + cons__u64toptr_insert(root->arena, &root->local_map, local_user_id, &lookup, result); + } + + return(result); +} + +static void +cons_local_set_basic_info(CONS_Root *root, CONS_Local *local, CONS_LocalInfo *info){ + if (local->kind != RADDBG_LocalKind_NULL){ + // TODO(allen): API error + } + else if (info->scope == 0){ + // TODO(allen): API error + } + else if (info->kind == RADDBG_LocalKind_NULL || RADDBG_LocalKind_COUNT <= info->kind){ + // TODO(allen): API error + } + else if (info->type == 0){ + // TODO(allen): API error + } + else{ + CONS_Scope *scope = info->scope; + SLLQueuePush(scope->first_local, scope->last_local, local); + scope->local_count += 1; + root->local_count += 1; + local->kind = info->kind; + local->name = push_str8_copy(root->arena, info->name); + local->type = info->type; + } +} + +static CONS_LocationSet* +cons_location_set_from_local(CONS_Root *root, CONS_Local *local){ + CONS_LocationSet *result = local->locset; + if (result == 0){ + local->locset = push_array(root->arena, CONS_LocationSet, 1); + result = local->locset; + } + return(result); +} + +static void +cons_location_set_add_case(CONS_Root *root, CONS_LocationSet *locset, + U64 voff_first, U64 voff_opl, CONS_Location *location){ + CONS__LocationCase *location_case = push_array(root->arena, CONS__LocationCase, 1); + SLLQueuePush(locset->first_location_case, locset->last_location_case, location_case); + locset->location_case_count += 1; + root->location_count += 1; + + location_case->voff_first = voff_first; + location_case->voff_opl = voff_opl; + location_case->location = location; +} + +static CONS_Location* +cons_location_addr_bytecode_stream(CONS_Root *root, CONS_EvalBytecode *bytecode){ + CONS_Location *result = push_array(root->arena, CONS_Location, 1); + result->kind = RADDBG_LocationKind_AddrBytecodeStream; + result->bytecode = *bytecode; + return(result); +} + +static CONS_Location* +cons_location_val_bytecode_stream(CONS_Root *root, CONS_EvalBytecode *bytecode){ + CONS_Location *result = push_array(root->arena, CONS_Location, 1); + result->kind = RADDBG_LocationKind_ValBytecodeStream; + result->bytecode = *bytecode; + return(result); +} + +static CONS_Location* +cons_location_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset){ + CONS_Location *result = push_array(root->arena, CONS_Location, 1); + result->kind = RADDBG_LocationKind_AddrRegisterPlusU16; + result->register_code = reg_code; + result->offset = offset; + return(result); +} + +static CONS_Location* +cons_location_addr_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset){ + CONS_Location *result = push_array(root->arena, CONS_Location, 1); + result->kind = RADDBG_LocationKind_AddrAddrRegisterPlusU16; + result->register_code = reg_code; + result->offset = offset; + return(result); +} + +static CONS_Location* +cons_location_val_reg(CONS_Root *root, U8 reg_code){ + CONS_Location *result = push_array(root->arena, CONS_Location, 1); + result->kind = RADDBG_LocationKind_ValRegister; + result->register_code = reg_code; + return(result); +} + +// bytecode + +static void +cons_bytecode_push_op(Arena *arena, CONS_EvalBytecode *bytecode, RADDBG_EvalOp op, U64 p){ + U8 ctrlbits = raddbg_eval_opcode_ctrlbits[op]; + U32 p_size = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); + + CONS_EvalBytecodeOp *node = push_array(arena, CONS_EvalBytecodeOp, 1); + node->op = op; + node->p_size = p_size; + node->p = p; + + SLLQueuePush(bytecode->first_op, bytecode->last_op, node); + bytecode->op_count += 1; + bytecode->encoded_size += 1 + p_size; +} + +static void +cons_bytecode_push_uconst(Arena *arena, CONS_EvalBytecode *bytecode, U64 x){ + if (x <= 0xFF){ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU8, x); + } + else if (x <= 0xFFFF){ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU16, x); + } + else if (x <= 0xFFFFFFFF){ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU32, x); + } + else{ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU64, x); + } +} + +static void +cons_bytecode_push_sconst(Arena *arena, CONS_EvalBytecode *bytecode, S64 x){ + if (-0x80 <= x && x <= 0x7F){ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU8, (U64)x); + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_TruncSigned, 8); + } + else if (-0x8000 <= x && x <= 0x7FFF){ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU16, (U64)x); + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_TruncSigned, 16); + } + else if (-0x80000000ll <= x && x <= 0x7FFFFFFFll){ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU32, (U64)x); + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_TruncSigned, 32); + } + else{ + cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU64, (U64)x); + } +} + +static void +cons_bytecode_concat_in_place(CONS_EvalBytecode *left_dst, CONS_EvalBytecode *right_destroyed){ + if (right_destroyed->first_op != 0){ + if (left_dst->first_op == 0){ + MemoryCopyStruct(left_dst, right_destroyed); + } + else{ + left_dst->last_op = right_destroyed->last_op; + left_dst->op_count += right_destroyed->op_count; + left_dst->encoded_size += right_destroyed->encoded_size; + } + MemoryZeroStruct(right_destroyed); + } +} + + + +//////////////////////////////// +//- Implementation Helpers + +// types + +static CONS_Type* +cons__type_new(CONS_Root *root){ + ProfBeginFunction(); + CONS_Type *result = push_array(root->arena, CONS_Type, 1); + result->idx = root->type_count; + SLLQueuePush_N(root->first_type, root->last_type, result, next_order); + root->type_count += 1; + ProfEnd(); + return(result); +} + +static CONS_TypeUDT* +cons__type_udt_from_any_type(CONS_Root *root, CONS_Type *type){ + if (type->udt == 0){ + CONS_TypeUDT *new_udt = push_array(root->arena, CONS_TypeUDT, 1); + new_udt->idx = root->type_udt_count; + SLLQueuePush_N(root->first_udt, root->last_udt, new_udt, next_order); + root->type_udt_count += 1; + new_udt->self_type = type; + type->udt = new_udt; + } + CONS_TypeUDT *result = type->udt; + return(result); +} + +static CONS_TypeUDT* +cons__type_udt_from_record_type(CONS_Root *root, CONS_Type *type){ + CONS_TypeUDT *result = 0; + + if (!(type->kind == RADDBG_TypeKind_Struct || + type->kind == RADDBG_TypeKind_Class || + type->kind == RADDBG_TypeKind_Union)){ + // TODO(allen): API error + } + else{ + result = cons__type_udt_from_any_type(root, type); + } + + return(result); +} + +// scopes + +static void +cons__scope_recursive_set_symbol(CONS_Scope *scope, CONS_Symbol *symbol){ + scope->symbol = symbol; + for (CONS_Scope *node = scope->first_child; + node != 0; + node = node->next_sibling){ + cons__scope_recursive_set_symbol(node, symbol); + } +} + +// name maps + +static CONS__NameMap* +cons__name_map_for_kind(CONS_Root *root, RADDBG_NameMapKind kind){ + CONS__NameMap *result = 0; + if (kind < RADDBG_NameMapKind_COUNT){ + if (root->name_maps[kind] == 0){ + root->name_maps[kind] = push_array(root->arena, CONS__NameMap, 1); + } + result = root->name_maps[kind]; + } + return(result); +} + +static void +cons__name_map_add_pair(CONS_Root *root, CONS__NameMap *map, String8 string, U32 idx){ + // hash + U64 hash = raddbg_hash(string.str, string.size); + U64 bucket_idx = hash%ArrayCount(map->buckets); + + // find existing name node + CONS__NameMapNode *match = 0; + for (CONS__NameMapNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->bucket_next){ + if (str8_match(string, node->string, 0)){ + match = node; + break; + } + } + + // make name node if necessary + if (match == 0){ + match = push_array(root->arena, CONS__NameMapNode, 1); + match->string = push_str8_copy(root->arena, string); + SLLStackPush_N(map->buckets[bucket_idx], match, bucket_next); + SLLQueuePush_N(map->first, map->last, match, order_next); + map->name_count += 1; + } + + // find existing idx + B32 existing_idx = 0; + for (CONS__NameMapIdxNode *node = match->idx_first; + node != 0; + node = node->next){ + for (U32 i = 0; i < ArrayCount(node->idx); i += 1){ + if (node->idx[i] == 0){ + break; + } + if (node->idx[i] == idx){ + existing_idx = 1; + break; + } + } + } + + // insert new idx if necessary + if (!existing_idx){ + CONS__NameMapIdxNode *idx_node = match->idx_last; + + U32 insert_i = match->idx_count%ArrayCount(idx_node->idx); + if (insert_i == 0){ + idx_node = push_array(root->arena, CONS__NameMapIdxNode, 1); + SLLQueuePush(match->idx_first, match->idx_last, idx_node); + } + + idx_node->idx[insert_i] = idx; + match->idx_count += 1; + } +} + +// u64 to ptr map + +static void +cons__u64toptr_init(Arena *arena, CONS__U64ToPtrMap *map, U64 bucket_count){ + Assert(IsPow2OrZero(bucket_count) && bucket_count > 0); + map->buckets = push_array(arena, CONS__U64ToPtrNode*, bucket_count); + map->bucket_count = bucket_count; +} + +static void +cons__u64toptr_lookup(CONS__U64ToPtrMap *map, U64 key, CONS__U64ToPtrLookup *lookup_out){ + ProfBeginFunction(); + U64 bucket_idx = key&(map->bucket_count - 1); + CONS__U64ToPtrNode *check_node = map->buckets[bucket_idx]; + for (;check_node != 0; check_node = check_node->next){ + for (U32 k = 0; k < ArrayCount(check_node->key); k += 1){ + if (check_node->ptr[k] == 0){ + lookup_out->fill_node = check_node; + lookup_out->fill_k = k; + break; + } + else if (check_node->key[k] == key){ + lookup_out->match = check_node->ptr[k]; + break; + } + } + } + ProfEnd(); +} + +static void +cons__u64toptr_insert(Arena *arena, CONS__U64ToPtrMap *map, U64 key, + CONS__U64ToPtrLookup *lookup, void *ptr){ + if (lookup->fill_node != 0){ + CONS__U64ToPtrNode *node = lookup->fill_node; + U32 k = lookup->fill_k; + node->key[k] = key; + node->ptr[k] = ptr; + } + else{ + U64 bucket_idx = key&(map->bucket_count - 1); + + CONS__U64ToPtrNode *node = push_array(arena, CONS__U64ToPtrNode, 1); + SLLStackPush(map->buckets[bucket_idx], node); + node->key[0] = key; + node->ptr[0] = ptr; + + lookup->fill_node = node; + lookup->fill_k = 0; + } +} + +// str8 to ptr map + +static void* +cons__str8toptr_lookup(CONS__Str8ToPtrMap *map, String8 key, U64 hash){ + ProfBeginFunction(); + void *result = 0; + U64 bucket_idx = hash%ArrayCount(map->buckets); + for (CONS__Str8ToPtrNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->hash == hash && str8_match(node->key, key, 0)){ + result = node->ptr; + break; + } + } + ProfEnd(); + return(result); +} + +static void +cons__str8toptr_insert(Arena *arena, CONS__Str8ToPtrMap *map, String8 key, U64 hash, void *ptr){ + ProfBeginFunction(); + U64 bucket_idx = hash%ArrayCount(map->buckets); + + CONS__Str8ToPtrNode *node = push_array(arena, CONS__Str8ToPtrNode, 1); + SLLStackPush(map->buckets[bucket_idx], node); + + node->key = push_str8_copy(arena, key); + node->hash = hash; + node->ptr = ptr; + ProfEnd(); +} + + +//- cons intermediate functions + +static U32 +cons__dsection(Arena *arena, CONS__DSections *dss, void *data, U64 size, RADDBG_DataSectionTag tag){ + U32 result = dss->count; + + CONS__DSectionNode *node = push_array(arena, CONS__DSectionNode, 1); + SLLQueuePush(dss->first, dss->last, node); + node->data = data; + node->size = size; + node->tag = tag; + dss->count += 1; + + return(result); +} + +static CONS__BakeCtx* +cons__bake_ctx_begin(void){ + Arena *arena = arena_alloc(); + CONS__BakeCtx *result = push_array(arena, CONS__BakeCtx, 1); + result->arena = arena; + + cons__string(result, str8_lit("")); + + cons__idx_run(result, 0, 0); + + result->tree = push_array(arena, CONS__PathTree, 1); + { + CONS__PathNode *nil_path_node = cons__paths_new_node(result); + nil_path_node->name = str8_lit(""); + CONS__SrcNode *nil_src_node = cons__paths_new_src_node(result); + nil_src_node->path_node = nil_path_node; + nil_src_node->normal_full_path = str8_lit(""); + nil_path_node->src_file = nil_src_node; + } + + return(result); +} + +static void +cons__bake_ctx_release(CONS__BakeCtx *bake_ctx){ + arena_release(bake_ctx->arena); +} + + +static U32 +cons__string(CONS__BakeCtx *bctx, String8 str){ + Arena *arena = bctx->arena; + CONS__Strings *strs = &bctx->strs; + + U64 hash = raddbg_hash(str.str, str.size); + U64 bucket_idx = hash%ArrayCount(strs->buckets); + + // look for a match + CONS__StringNode *match = 0; + for (CONS__StringNode *node = strs->buckets[bucket_idx]; + node != 0; + node = node->bucket_next){ + if (node->hash == hash && + str8_match(node->str, str, 0)){ + match = node; + break; + } + } + + // insert new node if no match + if (match == 0){ + CONS__StringNode *node = push_array_no_zero(arena, CONS__StringNode, 1); + node->str = push_str8_copy(arena, str); + node->hash = hash; + node->idx = strs->count; + strs->count += 1; + + SLLQueuePush_N(strs->order_first, strs->order_last, node, order_next); + SLLStackPush_N(strs->buckets[bucket_idx], node, bucket_next); + + match = node; + } + + // extract idx to return + Assert(match != 0); + U32 result = match->idx; + + return(result); +} + +static U64 +cons__idx_run_hash(U32 *idx_run, U32 count){ + U64 hash = 5381; + U32 *ptr = idx_run; + U32 *opl = idx_run + count; + for (; ptr < opl; ptr += 1){ + hash = ((hash << 5) + hash) + (*ptr); + } + return(hash); +} + +static U32 +cons__idx_run(CONS__BakeCtx *bctx, U32 *idx_run, U32 count){ + Arena *arena = bctx->arena; + CONS__IdxRuns *idxs = &bctx->idxs; + + U64 hash = cons__idx_run_hash(idx_run, count); + U64 bucket_idx = hash%ArrayCount(idxs->buckets); + + // look for a match + CONS__IdxRunNode *match = 0; + for (CONS__IdxRunNode *node = idxs->buckets[bucket_idx]; + node != 0; + node = node->bucket_next){ + if (node->hash == hash){ + S32 is_match = 1; + U32 *node_idx = node->idx_run; + for (U32 i = 0; i < count; i += 1){ + if (node_idx[i] != idx_run[i]){ + is_match = 0; + break; + } + } + if (is_match){ + match = node; + break; + } + } + } + + // insert new node if no match + if (match == 0){ + CONS__IdxRunNode *node = push_array_no_zero(arena, CONS__IdxRunNode, 1); + U32 *idx_run_copy = push_array_no_zero(arena, U32, count); + for (U32 i = 0; i < count; i += 1){ + idx_run_copy[i] = idx_run[i]; + } + node->idx_run = idx_run_copy; + node->hash = hash; + node->count = count; + node->first_idx = idxs->idx_count; + + idxs->count += 1; + idxs->idx_count += count; + + SLLQueuePush_N(idxs->order_first, idxs->order_last, node, order_next); + SLLStackPush_N(idxs->buckets[bucket_idx], node, bucket_next); + + match = node; + } + + // extract idx to return + Assert(match != 0); + U32 result = match->first_idx; + + return(result); +} + +static CONS__PathNode* +cons__paths_new_node(CONS__BakeCtx *bctx){ + CONS__PathTree *tree = bctx->tree; + CONS__PathNode *result = push_array(bctx->arena, CONS__PathNode, 1); + SLLQueuePush_N(tree->first, tree->last, result, next_order); + result->idx = tree->count; + tree->count += 1; + return(result); +} + +static CONS__PathNode* +cons__paths_sub_path(CONS__BakeCtx *bctx, CONS__PathNode *dir, String8 sub_dir){ + // look for existing match + CONS__PathNode *match = 0; + for (CONS__PathNode *node = dir->first_child; + node != 0; + node = node->next_sibling){ + if (str8_match(node->name, sub_dir, StringMatchFlag_CaseInsensitive)){ + match = node; + break; + } + } + + // construct new node if no match + CONS__PathNode *new_node = 0; + if (match == 0){ + new_node = cons__paths_new_node(bctx); + new_node->parent = dir; + SLLQueuePush_N(dir->first_child, dir->last_child, new_node, next_sibling); + new_node->name = push_str8_copy(bctx->arena, sub_dir); + } + + // select result from the two paths + CONS__PathNode *result = match; + if (match == 0){ + result = new_node; + } + + return(result); +} + +static CONS__PathNode* +cons__paths_node_from_path(CONS__BakeCtx *bctx, String8 path){ + CONS__PathNode *node_cursor = &bctx->tree->root; + + U8 *ptr = path.str; + U8 *opl = path.str + path.size; + for (;ptr < opl;){ + // skip past slashes + for (;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); + + // save beginning of non-slash range + U8 *range_first = ptr; + + // skip past non-slashes + for (;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); + + // if range is non-empty advance the node cursor + if (range_first < ptr){ + String8 sub_dir = str8_range(range_first, ptr); + node_cursor = cons__paths_sub_path(bctx, node_cursor, sub_dir); + } + } + + CONS__PathNode *result = node_cursor; + return(result); +} + +static U32 +cons__paths_idx_from_path(CONS__BakeCtx *bctx, String8 path){ + CONS__PathNode *node = cons__paths_node_from_path(bctx, path); + U32 result = node->idx; + return(result); +} + +static CONS__SrcNode* +cons__paths_new_src_node(CONS__BakeCtx *bctx){ + CONS__PathTree *tree = bctx->tree; + CONS__SrcNode *result = push_array(bctx->arena, CONS__SrcNode, 1); + SLLQueuePush(tree->src_first, tree->src_last, result); + result->idx = tree->src_count; + tree->src_count += 1; + return(result); +} + +static CONS__SrcNode* +cons__paths_src_node_from_path_node(CONS__BakeCtx *bctx, CONS__PathNode *path_node){ + CONS__SrcNode *result = path_node->src_file; + if (result == 0){ + CONS__SrcNode *new_node = cons__paths_new_src_node(bctx); + new_node->path_node = path_node; + new_node->normal_full_path = cons__normal_string_from_path_node(bctx->arena, path_node); + result = path_node->src_file = new_node; + } + return(result); +} + + +//- cons path helper + +static String8 +cons__normal_string_from_path_node(Arena *arena, CONS__PathNode *node){ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + if (node != 0){ + cons__normal_string_from_path_node_build(scratch.arena, node, &list); + } + StringJoin join = {0}; + join.sep = str8_lit("/"); + String8 result = str8_list_join(arena, &list, &join); + { + U8 *ptr = result.str; + U8 *opl = result.str + result.size; + for (; ptr < opl; ptr += 1){ + U8 c = *ptr; + if ('A' <= c && c <= 'Z') c += 'a' - 'A'; + *ptr = c; + } + } + scratch_end(scratch); + return(result); +} + +static void +cons__normal_string_from_path_node_build(Arena *arena, CONS__PathNode *node, String8List *out){ + if (node->parent != 0){ + cons__normal_string_from_path_node_build(arena, node->parent, out); + } + if (node->name.size > 0){ + str8_list_push(arena, out, node->name); + } +} + + +//- cons sort helper + +static CONS__SortKey* +cons__sort_key_array(Arena *arena, CONS__SortKey *keys, U64 count){ + // This sort is designed to take advantage of lots of pre-existing sorted ranges. + // Most line info is already sorted or close to already sorted. + // Similarly most vmap data has lots of pre-sorted ranges. etc. etc. + // Also - this sort should be a "stable" sort. In the use case of sorting vmap + // ranges, we want to be able to rely on order, so it needs to be preserved here. + + ProfBegin("cons__sort_key_array"); + Temp scratch = scratch_begin(&arena, 1); + + CONS__SortKey *result = 0; + + if (count <= 1){ + result = keys; + } + else{ + CONS__OrderedRange *ranges_first = 0; + CONS__OrderedRange *ranges_last = 0; + U64 range_count = 0; + { + U64 pos = 0; + for (;pos < count;){ + // identify ordered range + U64 first = pos; + U64 opl = pos + 1; + for (; opl < count && keys[opl - 1].key <= keys[opl].key; opl += 1); + + // generate an ordered range node + CONS__OrderedRange *new_range = push_array(scratch.arena, CONS__OrderedRange, 1); + SLLQueuePush(ranges_first, ranges_last, new_range); + range_count += 1; + new_range->first = first; + new_range->opl = opl; + + // update pos + pos = opl; + } + } + + if (range_count == 1){ + result = keys; + } + else{ + CONS__SortKey *keys_swap = push_array_no_zero(arena, CONS__SortKey, count); + + CONS__SortKey *src = keys; + CONS__SortKey *dst = keys_swap; + + CONS__OrderedRange *src_ranges = ranges_first; + CONS__OrderedRange *dst_ranges = 0; + CONS__OrderedRange *dst_ranges_last = 0; + + for (;;){ + // begin a pass + for (;;){ + // end pass when out of ranges + if (src_ranges == 0){ + break; + } + + // get first range + CONS__OrderedRange *range1 = src_ranges; + SLLStackPop(src_ranges); + + // if this range is the whole array, we are done + if (range1->first == 0 && range1->opl == count){ + result = src; + goto sort_done; + } + + // if there is not a second range, save this range for next time and end this pass + if (src_ranges == 0){ + U64 first = range1->first; + MemoryCopy(dst + first, src + first, sizeof(*src)*(range1->opl - first)); + SLLQueuePush(dst_ranges, dst_ranges_last, range1); + break; + } + + // get second range + CONS__OrderedRange *range2 = src_ranges; + SLLStackPop(src_ranges); + + Assert(range1->opl == range2->first); + + // merge these ranges + U64 jd = range1->first; + U64 j1 = range1->first; + U64 j1_opl = range1->opl; + U64 j2 = range2->first; + U64 j2_opl = range2->opl; + for (;;){ + if (src[j1].key <= src[j2].key){ + MemoryCopy(dst + jd, src + j1, sizeof(*src)); + j1 += 1; + jd += 1; + if (j1 >= j1_opl){ + break; + } + } + else{ + MemoryCopy(dst + jd, src + j2, sizeof(*src)); + j2 += 1; + jd += 1; + if (j2 >= j2_opl){ + break; + } + } + } + if (j1 < j1_opl){ + MemoryCopy(dst + jd, src + j1, sizeof(*src)*(j1_opl - j1)); + } + else{ + MemoryCopy(dst + jd, src + j2, sizeof(*src)*(j2_opl - j2)); + } + + // save this as one range + range1->opl = range2->opl; + SLLQueuePush(dst_ranges, dst_ranges_last, range1); + } + + // end pass by swapping buffers and range nodes + Swap(CONS__SortKey*, src, dst); + src_ranges = dst_ranges; + dst_ranges = 0; + dst_ranges_last = 0; + } + } + } + sort_done:; + +#if 0 + // assert sortedness + for (U64 i = 1; i < count; i += 1){ + Assert(result[i - 1].key <= result[i].key); + } +#endif + + scratch_end(scratch); + ProfEnd(); + + return(result); +} + + +//- cons intermediate unit line info +static CONS__UnitLinesCombined* +cons__unit_combine_lines(Arena *arena, CONS__BakeCtx *bctx, CONS_LineSequenceNode *first_seq){ + ProfBegin("cons__unit_combine_lines"); + Temp scratch = scratch_begin(&arena, 1); + + // gather up all line info into two arrays + // keys: sortable array; pairs voffs with line info records; null records are sequence enders + // recs: contains all the source coordinates for a range of voffs + U64 line_count = 0; + U64 seq_count = 0; + for (CONS_LineSequenceNode *node = first_seq; + node != 0; + node = node->next){ + seq_count += 1; + line_count += node->line_seq.line_count; + } + + U64 key_count = line_count + seq_count; + CONS__SortKey *line_keys = push_array_no_zero(scratch.arena, CONS__SortKey, key_count); + CONS__LineRec *line_recs = push_array_no_zero(scratch.arena, CONS__LineRec, line_count); + + { + CONS__SortKey *key_ptr = line_keys; + CONS__LineRec *rec_ptr = line_recs; + + for (CONS_LineSequenceNode *node = first_seq; + node != 0; + node = node->next){ + CONS__PathNode *src_path = + cons__paths_node_from_path(bctx, node->line_seq.file_name); + CONS__SrcNode *src_file = cons__paths_src_node_from_path_node(bctx, src_path); + U32 file_id = src_file->idx; + + U64 node_line_count = node->line_seq.line_count; + for (U64 i = 0; i < node_line_count; i += 1){ + key_ptr->key = node->line_seq.voffs[i]; + key_ptr->val = rec_ptr; + key_ptr += 1; + + rec_ptr->file_id = file_id; + rec_ptr->line_num = node->line_seq.line_nums[i]; + if (node->line_seq.col_nums != 0){ + rec_ptr->col_first = node->line_seq.col_nums[i*2]; + rec_ptr->col_opl = node->line_seq.col_nums[i*2 + 1]; + } + rec_ptr += 1; + } + + key_ptr->key = node->line_seq.voffs[node_line_count]; + key_ptr->val = 0; + key_ptr += 1; + + CONS__LineMapFragment *fragment = push_array(arena, CONS__LineMapFragment, 1); + SLLQueuePush(src_file->first_fragment, src_file->last_fragment, fragment); + fragment->sequence = node; + } + } + + // sort + CONS__SortKey *sorted_line_keys = cons__sort_key_array(scratch.arena, line_keys, key_count); + + // TODO(allen): do a pass over sorted keys to make sure duplicate keys are sorted with + // null record first, and no more than one null record and one non-null record + + // arrange output + U64 *arranged_voffs = push_array_no_zero(arena, U64, key_count + 1); + RADDBG_Line *arranged_lines = push_array_no_zero(arena, RADDBG_Line, key_count); + + for (U64 i = 0; i < key_count; i += 1){ + arranged_voffs[i] = sorted_line_keys[i].key; + } + arranged_voffs[key_count] = ~0ull; + for (U64 i = 0; i < key_count; i += 1){ + CONS__LineRec *rec = (CONS__LineRec*)sorted_line_keys[i].val; + if (rec != 0){ + arranged_lines[i].file_idx = rec->file_id; + arranged_lines[i].line_num = rec->line_num; + } + else{ + arranged_lines[i].file_idx = 0; + arranged_lines[i].line_num = 0; + } + } + + CONS__UnitLinesCombined *result = push_array(arena, CONS__UnitLinesCombined, 1); + result->voffs = arranged_voffs; + result->lines = arranged_lines; + result->cols = 0; + result->line_count = key_count; + + scratch_end(scratch); + ProfEnd(); + + return(result); +} + + +//- cons intermediate source line info +static CONS__SrcLinesCombined* +cons__source_combine_lines(Arena *arena, CONS__LineMapFragment *first){ + ProfBegin("cons__source_combine_lines"); + Temp scratch = scratch_begin(&arena, 1); + + // gather line number map + CONS__SrcLineMapBucket *first_bucket = 0; + CONS__SrcLineMapBucket *last_bucket = 0; + + U64 line_count = 0; + U64 voff_count = 0; + U64 max_line_num = 0; + for (CONS__LineMapFragment *map_fragment = first; + map_fragment != 0; + map_fragment = map_fragment->next){ + CONS_LineSequence *sequence = &map_fragment->sequence->line_seq; + + U64 *seq_voffs = sequence->voffs; + U32 *seq_line_nums = sequence->line_nums; + U64 seq_line_count = sequence->line_count; + for (U64 i = 0; i < seq_line_count; i += 1){ + U32 line_num = seq_line_nums[i]; + U64 voff = seq_voffs[i]; + + // update unique voff counter & max line number + voff_count += 1; + max_line_num = Max(max_line_num, line_num); + + // find match + CONS__SrcLineMapBucket *match = 0; + for (CONS__SrcLineMapBucket *node = first_bucket; + node != 0; + node = node->next){ + if (node->line_num == line_num){ + match = node; + break; + } + } + + // introduce new line if no match + if (match == 0){ + match = push_array(scratch.arena, CONS__SrcLineMapBucket, 1); + SLLQueuePush(first_bucket, last_bucket, match); + match->line_num = line_num; + line_count += 1; + } + + // insert new voff + { + CONS__SrcLineMapVoffBlock *block = push_array(scratch.arena, CONS__SrcLineMapVoffBlock, 1); + SLLQueuePush(match->first_voff_block, match->last_voff_block, block); + match->voff_count += 1; + block->voff = voff; + } + } + } + + // bake sortable keys array + CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, line_count); + { + CONS__SortKey *key_ptr = keys; + for (CONS__SrcLineMapBucket *node = first_bucket; + node != 0; + node = node->next, key_ptr += 1){ + key_ptr->key = node->line_num; + key_ptr->val = node; + } + } + + // sort + CONS__SortKey *sorted_keys = cons__sort_key_array(scratch.arena, keys, line_count); + + // bake result + U32 *line_nums = push_array_no_zero(arena, U32, line_count); + U32 *line_ranges = push_array_no_zero(arena, U32, line_count + 1); + U64 *voffs = push_array_no_zero(arena, U64, voff_count); + + { + U64 *voff_ptr = voffs; + for (U32 i = 0; i < line_count; i += 1){ + line_nums[i] = sorted_keys[i].key; + line_ranges[i] = (U32)(voff_ptr - voffs); + CONS__SrcLineMapBucket *bucket = (CONS__SrcLineMapBucket*)sorted_keys[i].val; + for (CONS__SrcLineMapVoffBlock *node = bucket->first_voff_block; + node != 0; + node = node->next){ + *voff_ptr = node->voff; + voff_ptr += 1; + } + } + line_ranges[line_count] = voff_count; + } + + CONS__SrcLinesCombined *result = push_array(arena, CONS__SrcLinesCombined, 1); + result->line_nums = line_nums; + result->line_ranges = line_ranges; + result->line_count = line_count; + result->voffs = voffs; + result->voff_count = voff_count; + + scratch_end(scratch); + ProfEnd(); + + return(result); +} + + +//- cons intermediate vmap type +static CONS__VMap* +cons__vmap_from_markers(Arena *arena, CONS__VMapMarker *markers, CONS__SortKey *keys, U64 marker_count){ + Temp scratch = scratch_begin(&arena, 1); + + // sort markers + CONS__SortKey *sorted_keys = cons__sort_key_array(scratch.arena, keys, marker_count); + + // determine if an extra vmap entry for zero is needed + U32 extra_vmap_entry = 0; + if (marker_count > 0 && sorted_keys[0].key != 0){ + extra_vmap_entry = 1; + } + + // fill output vmap entries + U32 vmap_count_raw = marker_count - 1 + extra_vmap_entry; + RADDBG_VMapEntry *vmap = push_array_no_zero(arena, RADDBG_VMapEntry, vmap_count_raw + 1); + U32 vmap_entry_count_pass_1 = 0; + + { + RADDBG_VMapEntry *vmap_ptr = vmap; + + if (extra_vmap_entry){ + vmap_ptr->voff = 0; + vmap_ptr->idx = 0; + vmap_ptr += 1; + } + + CONS__VMapRangeTracker *tracker_stack = 0; + CONS__VMapRangeTracker *tracker_free = 0; + + CONS__SortKey *key_ptr = sorted_keys; + CONS__SortKey *key_opl = sorted_keys + marker_count; + for (;key_ptr < key_opl;){ + // get initial map state from tracker stack + U32 initial_idx = max_U32; + if (tracker_stack != 0){ + initial_idx = tracker_stack->idx; + } + + // update tracker stack + // * we must process _all_ of the changes that apply at this voff before moving on + U64 voff = key_ptr->key; + + for (;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1){ + CONS__VMapMarker *marker = (CONS__VMapMarker*)key_ptr->val; + U32 idx = marker->idx; + + // push to stack + if (marker->begin_range){ + CONS__VMapRangeTracker *new_tracker = tracker_free; + if (new_tracker != 0){ + SLLStackPop(tracker_free); + } + else{ + new_tracker = push_array(scratch.arena, CONS__VMapRangeTracker, 1); + } + SLLStackPush(tracker_stack, new_tracker); + new_tracker->idx = idx; + } + + // pop matching node from stack (not always the top) + else{ + CONS__VMapRangeTracker **ptr_in = &tracker_stack; + CONS__VMapRangeTracker *match = 0; + for (CONS__VMapRangeTracker *node = tracker_stack; + node != 0;){ + if (node->idx == idx){ + match = node; + break; + } + ptr_in = &node->next; + node = node->next; + } + if (match != 0){ + *ptr_in = match->next; + SLLStackPush(tracker_free, match); + } + } + } + + // get final map state from tracker stack + U32 final_idx = 0; + if (tracker_stack != 0){ + final_idx = tracker_stack->idx; + } + + // if final is different from initial - emit new vmap entry + if (final_idx != initial_idx){ + vmap_ptr->voff = voff; + vmap_ptr->idx = final_idx; + vmap_ptr += 1; + } + } + + vmap_entry_count_pass_1 = (U32)(vmap_ptr - vmap); + } + + // replace zero unit indexes that follow a non-zero + // TODO(rjf): 0 *is* a real unit index right now + if(0) + { + // (the last entry is not replaced because it acts as a terminator) + U32 last = vmap_entry_count_pass_1 - 1; + + RADDBG_VMapEntry *vmap_ptr = vmap; + U64 real_idx = 0; + + for (U32 i = 0; i < last; i += 1, vmap_ptr += 1){ + // is this a zero after a real index? + if (vmap_ptr->idx == 0){ + vmap_ptr->idx = real_idx; + } + + // remember a real index + else{ + real_idx = vmap_ptr->idx; + } + } + } + + // combine duplicate neighbors + U32 vmap_entry_count = 0; + { + RADDBG_VMapEntry *vmap_ptr = vmap; + RADDBG_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; + RADDBG_VMapEntry *vmap_out = vmap; + + for (;vmap_ptr < vmap_opl;){ + RADDBG_VMapEntry *vmap_range_first = vmap_ptr; + U64 idx = vmap_ptr->idx; + vmap_ptr += 1; + for (;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; + MemoryCopyStruct(vmap_out, vmap_range_first); + vmap_out += 1; + } + + vmap_entry_count = (U32)(vmap_out - vmap); + } + + // fill result + CONS__VMap *result = push_array(arena, CONS__VMap, 1); + result->vmap = vmap; + result->count = vmap_entry_count - 1; + + scratch_end(scratch); + + return(result); +} + + +//- cons intermediate unit vmap +static CONS__VMap* +cons__vmap_from_unit_ranges(Arena *arena, CONS_UnitVMapRange *first, U64 count){ + Temp scratch = scratch_begin(&arena, 1); + + // count necessary markers + U64 marker_count = count*2; + + // fill markers + CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); + CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); + + { + CONS__SortKey *key_ptr = keys; + CONS__VMapMarker *marker_ptr = markers; + for (CONS_UnitVMapRange *range = first; + range != 0; + range = range->next){ + if (range->first < range->opl){ + U32 unit_idx = range->unit->idx; + + key_ptr->key = range->first; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = range->opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + } + + // construct vmap + CONS__VMap *result = cons__vmap_from_markers(arena, markers, keys, marker_count); + + scratch_end(scratch); + + return(result); +} + +//- cons intermediate types +static CONS__TypeData* +cons__type_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx){ + ProfBegin("cons__type_data_combine"); + Temp scratch = scratch_begin(&arena, 1); + + // fill type nodes + U32 type_count = root->type_count; + RADDBG_TypeNode *type_nodes = push_array_no_zero(arena, RADDBG_TypeNode, type_count); + + { + RADDBG_TypeNode *ptr = type_nodes; + RADDBG_TypeNode *opl = ptr + type_count; + CONS_Type *loose_type = root->first_type; + for (;loose_type != 0 && ptr < opl; + loose_type = loose_type->next_order, ptr += 1){ + + RADDBG_TypeKind kind = loose_type->kind; + + // shared + ptr->kind = kind; + ptr->flags = loose_type->flags; + ptr->byte_size = loose_type->byte_size; + + // built-in + if (RADDBG_TypeKind_FirstBuiltIn <= kind && kind <= RADDBG_TypeKind_LastBuiltIn){ + ptr->built_in.name_string_idx = cons__string(bctx, loose_type->name); + } + + // constructed + else if (RADDBG_TypeKind_FirstConstructed <= kind && kind <= RADDBG_TypeKind_LastConstructed){ + ptr->constructed.direct_type_idx = loose_type->direct_type->idx; + + switch (kind){ + case RADDBG_TypeKind_Array: + { + ptr->constructed.count = loose_type->count; + }break; + + case RADDBG_TypeKind_Function: + { + // parameters + U32 count = loose_type->count; + U32 *idx_run = cons__idx_run_from_types(scratch.arena, loose_type->param_types, count); + ptr->constructed.param_idx_run_first = cons__idx_run(bctx, idx_run, count); + ptr->constructed.count = count; + }break; + + case RADDBG_TypeKind_Method: + { + // parameters + U32 count = loose_type->count; + U32 *idx_run = cons__idx_run_from_types(scratch.arena, loose_type->param_types, count); + ptr->constructed.param_idx_run_first = cons__idx_run(bctx, idx_run, count); + ptr->constructed.count = count; + }break; + } + } + + // user-defined + else if (RADDBG_TypeKind_FirstUserDefined <= kind && kind <= RADDBG_TypeKind_LastUserDefined){ + ptr->user_defined.name_string_idx = cons__string(bctx, loose_type->name); + if (loose_type->udt != 0){ + ptr->user_defined.udt_idx = loose_type->udt->idx; + } + if (loose_type->direct_type != 0){ + ptr->user_defined.direct_type_idx = loose_type->direct_type->idx; + } + } + + // bitfield + else if (kind == RADDBG_TypeKind_Bitfield){ + ptr->bitfield.off = loose_type->off; + ptr->bitfield.size = loose_type->count; + } + + temp_end(scratch); + } + + // both iterators should end at the same time + Assert(loose_type == 0); + Assert(ptr == opl); + } + + + // fill udts + U32 udt_count = root->type_udt_count; + RADDBG_UDT *udts = push_array_no_zero(arena, RADDBG_UDT, udt_count); + + U32 member_count = root->total_member_count; + RADDBG_Member *members = push_array_no_zero(arena, RADDBG_Member, member_count); + + U32 enum_member_count = root->total_enum_val_count; + RADDBG_EnumMember *enum_members = push_array_no_zero(arena, RADDBG_EnumMember, enum_member_count); + + { + RADDBG_UDT *ptr = udts; + RADDBG_UDT *opl = ptr + udt_count; + + RADDBG_Member *member_ptr = members; + RADDBG_Member *member_opl = members + member_count; + + RADDBG_EnumMember *enum_member_ptr = enum_members; + RADDBG_EnumMember *enum_member_opl = enum_members + enum_member_count; + + CONS_TypeUDT *loose_udt = root->first_udt; + for (;loose_udt != 0 && ptr < opl; + loose_udt = loose_udt->next_order, ptr += 1){ + ptr->self_type_idx = loose_udt->self_type->idx; + + Assert(loose_udt->member_count == 0 || + loose_udt->enum_val_count == 0); + + // enum members + if (loose_udt->enum_val_count != 0){ + ptr->flags |= RADDBG_UserDefinedTypeFlag_EnumMembers; + + ptr->member_first = (U32)(enum_member_ptr - enum_members); + ptr->member_count = loose_udt->enum_val_count; + + U32 local_enum_val_count = loose_udt->enum_val_count; + CONS_TypeEnumVal *loose_enum_val = loose_udt->first_enum_val; + for (U32 i = 0; + i < local_enum_val_count; + i += 1, enum_member_ptr += 1, loose_enum_val = loose_enum_val->next){ + enum_member_ptr->name_string_idx = cons__string(bctx, loose_enum_val->name); + enum_member_ptr->val = loose_enum_val->val; + } + } + + // struct/class/union members + else{ + ptr->member_first = (U32)(member_ptr - members); + ptr->member_count = loose_udt->member_count; + + U32 local_member_count = loose_udt->member_count; + CONS_TypeMember *loose_member = loose_udt->first_member; + for (U32 i = 0; + i < local_member_count; + i += 1, member_ptr += 1, loose_member = loose_member->next){ + member_ptr->kind = loose_member->kind; + // TODO(allen): member_ptr->visibility = ; + member_ptr->name_string_idx = cons__string(bctx, loose_member->name); + member_ptr->off = loose_member->off; + member_ptr->type_idx = loose_member->type->idx; + + // TODO(allen): + if (loose_member->kind == RADDBG_MemberKind_Method){ + //loose_member_ptr->unit_idx = ; + //loose_member_ptr->proc_symbol_idx = ; + } + } + + } + + U32 file_idx = 0; + if (loose_udt->source_path.size > 0){ + CONS__PathNode *path_node = cons__paths_node_from_path(bctx, loose_udt->source_path); + CONS__SrcNode *src_node = cons__paths_src_node_from_path_node(bctx, path_node); + file_idx = src_node->idx; + } + + ptr->file_idx = file_idx; + ptr->line = loose_udt->line; + ptr->col = loose_udt->col; + } + + // all iterators should end at the same time + Assert(loose_udt == 0); + Assert(ptr == opl); + Assert(member_ptr == member_opl); + Assert(enum_member_ptr == enum_member_opl); + } + + + // fill result + CONS__TypeData *result = push_array(arena, CONS__TypeData, 1); + result->type_nodes = type_nodes; + result->type_node_count = type_count; + result->udts = udts; + result->udt_count = udt_count; + result->members = members; + result->member_count = member_count; + result->enum_members = enum_members; + result->enum_member_count = enum_member_count; + + scratch_end(scratch); + ProfEnd(); + + return(result); +} + +static U32* +cons__idx_run_from_types(Arena *arena, CONS_Type **types, U32 count){ + U32 *result = push_array(arena, U32, count); + for (U32 i = 0; i < count; i += 1){ + result[i] = types[i]->idx; + } + return(result); +} + +//- cons serializer for symbols +static CONS__SymbolData* +cons__symbol_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx){ + ProfBegin("cons__symbol_data_combine"); + Temp scratch = scratch_begin(&arena, 1); + + // count symbol kinds + U32 globalvar_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_GlobalVariable]; + U32 threadvar_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_ThreadVariable]; + U32 procedure_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_Procedure]; + + // allocate symbol arrays + RADDBG_GlobalVariable *global_variables = + push_array(arena, RADDBG_GlobalVariable, globalvar_count); + + RADDBG_ThreadVariable *thread_variables = + push_array(arena, RADDBG_ThreadVariable, threadvar_count); + + RADDBG_Procedure *procedures = push_array(arena, RADDBG_Procedure, procedure_count); + + // fill symbol arrays + { + RADDBG_GlobalVariable *global_ptr = global_variables; + RADDBG_ThreadVariable *thread_local_ptr = thread_variables; + RADDBG_Procedure *procedure_ptr = procedures; + + // nils + global_ptr += 1; + thread_local_ptr += 1; + procedure_ptr += 1; + + // symbol nodes + for (CONS_Symbol *node = root->first_symbol; + node != 0; + node = node->next_order){ + U32 name_string_idx = cons__string(bctx, node->name); + U32 link_name_string_idx = cons__string(bctx, node->link_name); + U32 type_idx = node->type->idx; + + RADDBG_LinkFlags link_flags = 0; + U32 container_idx = 0; + { + if (node->is_extern){ + link_flags |= RADDBG_LinkFlag_External; + } + if (node->container_symbol != 0){ + container_idx = node->container_symbol->idx; + link_flags |= RADDBG_LinkFlag_ProcScoped; + } + else if (node->container_type != 0 && node->container_type->udt != 0){ + container_idx = node->container_type->udt->idx; + link_flags |= RADDBG_LinkFlag_TypeScoped; + } + } + + switch (node->kind){ + default:{}break; + + case CONS_SymbolKind_GlobalVariable: + { + global_ptr->name_string_idx = name_string_idx; + global_ptr->link_flags = link_flags; + global_ptr->voff = node->offset; + global_ptr->type_idx = type_idx; + global_ptr->container_idx = container_idx; + global_ptr += 1; + }break; + + case CONS_SymbolKind_ThreadVariable: + { + thread_local_ptr->name_string_idx = name_string_idx; + thread_local_ptr->link_flags = link_flags; + thread_local_ptr->tls_off = (U32)node->offset; + thread_local_ptr->type_idx = type_idx; + thread_local_ptr->container_idx = container_idx; + thread_local_ptr += 1; + }break; + + case CONS_SymbolKind_Procedure: + { + procedure_ptr->name_string_idx = name_string_idx; + procedure_ptr->link_name_string_idx = link_name_string_idx; + procedure_ptr->link_flags = link_flags; + procedure_ptr->type_idx = type_idx; + procedure_ptr->root_scope_idx = node->root_scope->idx; + procedure_ptr->container_idx = container_idx; + procedure_ptr += 1; + }break; + } + } + + Assert(global_ptr - global_variables == globalvar_count); + Assert(thread_local_ptr - thread_variables == threadvar_count); + Assert(procedure_ptr - procedures == procedure_count); + } + + // global vmap + CONS__VMap *global_vmap = 0; + { + // count necessary markers + U32 marker_count = globalvar_count*2; + + // fill markers + CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); + CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); + + CONS__SortKey *key_ptr = keys; + CONS__VMapMarker *marker_ptr = markers; + + // real globals + for (CONS_Symbol *node = root->first_symbol; + node != 0; + node = node->next_order){ + if (node->kind == CONS_SymbolKind_GlobalVariable){ + U32 global_idx = node->idx; + + U64 first = node->offset; + U64 opl = first + node->type->byte_size; + + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + // nil global + { + U32 global_idx = 0; + + U64 first = 0; + U64 opl = max_U64; + + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + + // assert we filled all the markers + Assert(key_ptr - keys == marker_count && + marker_ptr - markers == marker_count); + + // construct vmap + global_vmap = cons__vmap_from_markers(arena, markers, keys, marker_count); + } + + // allocate scope array + + // (assert there is a nil scope) + Assert(root->first_scope != 0 && + root->first_scope->symbol == 0 && + root->first_scope->first_child == 0 && + root->first_scope->next_sibling == 0 && + root->first_scope->range_count == 0); + + U32 scope_count = root->scope_count; + RADDBG_Scope *scopes = push_array(arena, RADDBG_Scope, scope_count); + + U32 scope_voff_count = root->scope_voff_count; + U64 *scope_voffs = push_array(arena, U64, scope_voff_count); + + U32 local_count = root->local_count; + RADDBG_Local *locals = push_array(arena, RADDBG_Local, local_count); + + U32 location_block_count = root->location_count; + RADDBG_LocationBlock *location_blocks = + push_array(arena, RADDBG_LocationBlock, location_block_count); + + String8List location_data = {0}; + + // iterate scopes, locals, and locations + // fill scope voffs, locals, and location information + { + RADDBG_Scope *scope_ptr = scopes; + U64 *scope_voff_ptr = scope_voffs; + RADDBG_Local *local_ptr = locals; + RADDBG_LocationBlock *location_block_ptr = location_blocks; + + for (CONS_Scope *node = root->first_scope; + node != 0; + node = node->next_order, scope_ptr += 1){ + + // emit voffs + U32 voff_first = (U32)(scope_voff_ptr - scope_voffs); + for (CONS__VOffRange *range = node->first_range; + range != 0; + range = range->next){ + *scope_voff_ptr = range->voff_first; + scope_voff_ptr += 1; + *scope_voff_ptr = range->voff_opl; + scope_voff_ptr += 1; + } + U32 voff_opl = (U32)(scope_voff_ptr - scope_voffs); + + // emit locals + U32 scope_local_count = node->local_count; + U32 scope_local_first = (U32)(local_ptr - locals); + for (CONS_Local *slocal = node->first_local; + slocal != 0; + slocal = slocal->next, local_ptr += 1){ + local_ptr->kind = slocal->kind; + local_ptr->name_string_idx = cons__string(bctx, slocal->name); + local_ptr->type_idx = slocal->type->idx; + + CONS_LocationSet *locset = slocal->locset; + if (locset != 0){ + U32 location_first = (U32)(location_block_ptr - location_blocks); + U32 location_opl = location_first + locset->location_case_count; + local_ptr->location_first = location_first; + local_ptr->location_opl = location_opl; + + for (CONS__LocationCase *location_case = locset->first_location_case; + location_case != 0; + location_case = location_case->next){ + location_block_ptr->scope_off_first = location_case->voff_first; + location_block_ptr->scope_off_opl = location_case->voff_opl; + location_block_ptr->location_data_off = location_data.total_size; + location_block_ptr += 1; + + CONS_Location *location = location_case->location; + if (location == 0){ + U64 data = 0; + str8_serial_push_align(scratch.arena, &location_data, 8); + str8_serial_push_data(scratch.arena, &location_data, &data, 1); + } + else{ + switch (location->kind){ + default: + { + U64 data = 0; + str8_serial_push_align(scratch.arena, &location_data, 8); + str8_serial_push_data(scratch.arena, &location_data, &data, 1); + }break; + + case RADDBG_LocationKind_AddrBytecodeStream: + case RADDBG_LocationKind_ValBytecodeStream: + { + str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&location->kind))); + for (CONS_EvalBytecodeOp *op_node = location->bytecode.first_op; + op_node != 0; + op_node = op_node->next){ + U8 op_data[9]; + op_data[0] = op_node->op; + MemoryCopy(op_data + 1, &op_node->p, op_node->p_size); + String8 op_data_str = str8(op_data, 1 + op_node->p_size); + str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, op_data_str)); + } + { + U64 data = 0; + String8 data_str = str8((U8 *)&data, 1); + str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, data_str)); + } + }break; + + case RADDBG_LocationKind_AddrRegisterPlusU16: + case RADDBG_LocationKind_AddrAddrRegisterPlusU16: + { + RADDBG_LocationRegisterPlusU16 loc = {0}; + loc.kind = location->kind; + loc.register_code = location->register_code; + loc.offset = location->offset; + str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&loc))); + }break; + + case RADDBG_LocationKind_ValRegister: + { + RADDBG_LocationRegister loc = {0}; + loc.kind = location->kind; + loc.register_code = location->register_code; + str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&loc))); + }break; + } + } + } + + Assert(location_block_ptr - location_blocks == location_opl); + } + } + + Assert(local_ptr - locals == scope_local_first + scope_local_count); + + // emit scope + scope_ptr->proc_idx = (node->symbol == 0)?0:node->symbol->idx; + scope_ptr->parent_scope_idx = (node->parent_scope == 0)?0:node->parent_scope->idx; + scope_ptr->first_child_scope_idx = (node->first_child == 0)?0:node->first_child->idx; + scope_ptr->next_sibling_scope_idx = (node->next_sibling == 0)?0:node->next_sibling->idx; + scope_ptr->voff_range_first = voff_first; + scope_ptr->voff_range_opl = voff_opl; + scope_ptr->local_first = scope_local_first; + scope_ptr->local_count = scope_local_count; + + // TODO(allen): + //scope_ptr->static_local_idx_run_first = ; + //scope_ptr->static_local_count = ; + } + + Assert(scope_ptr - scopes == scope_count); + Assert(local_ptr - locals == local_count); + } + + // flatten location data + String8 location_data_str = str8_list_join(arena, &location_data, 0); + + // scope vmap + CONS__VMap *scope_vmap = 0; + { + // count necessary markers + U32 marker_count = scope_voff_count; + + // fill markers + CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); + CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); + + CONS__SortKey *key_ptr = keys; + CONS__VMapMarker *marker_ptr = markers; + + for (CONS_Scope *node = root->first_scope; + node != 0; + node = node->next_order){ + U32 scope_idx = node->idx; + + for (CONS__VOffRange *range = node->first_range; + range != 0; + range = range->next){ + key_ptr->key = range->voff_first; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = range->voff_opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + scope_vmap = cons__vmap_from_markers(arena, markers, keys, marker_count); + } + + // fill result + CONS__SymbolData *result = push_array(arena, CONS__SymbolData, 1); + result->global_variables = global_variables; + result->global_variable_count = globalvar_count; + result->global_vmap = global_vmap; + result->thread_variables = thread_variables; + result->thread_variable_count = threadvar_count; + result->procedures = procedures; + result->procedure_count = procedure_count; + result->scopes = scopes; + result->scope_count = scope_count; + result->scope_voffs = scope_voffs; + result->scope_voff_count = scope_voff_count; + result->scope_vmap = scope_vmap; + result->locals = locals; + result->local_count = local_count; + result->location_blocks = location_blocks; + result->location_block_count = location_block_count; + result->location_data = location_data_str.str; + result->location_data_size = location_data_str.size; + + scratch_end(scratch); + ProfEnd(); + + return(result); +} + +//- cons serializer for name maps + +static CONS__NameMapBaked* +cons__name_map_bake(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx, CONS__NameMap *map){ + Temp scratch = scratch_begin(&arena, 1); + + U32 bucket_count = map->name_count; + U32 node_count = map->name_count; + + // setup the final bucket layouts + CONS__NameMapSemiBucket *sbuckets = push_array(scratch.arena, CONS__NameMapSemiBucket, bucket_count); + for (CONS__NameMapNode *node = map->first; + node != 0; + node = node->order_next){ + U64 hash = raddbg_hash(node->string.str, node->string.size); + U64 bi = hash%bucket_count; + CONS__NameMapSemiNode *snode = push_array(scratch.arena, CONS__NameMapSemiNode, 1); + SLLQueuePush(sbuckets[bi].first, sbuckets[bi].last, snode); + snode->node = node; + sbuckets[bi].count += 1; + } + + // allocate tables + RADDBG_NameMapBucket *buckets = push_array(arena, RADDBG_NameMapBucket, bucket_count); + RADDBG_NameMapNode *nodes = push_array_no_zero(arena, RADDBG_NameMapNode, node_count); + + // convert to serialized buckets & nodes + { + RADDBG_NameMapBucket *bucket_ptr = buckets; + RADDBG_NameMapNode *node_ptr = nodes; + for (U32 i = 0; i < bucket_count; i += 1, bucket_ptr += 1){ + bucket_ptr->first_node = (U32)(node_ptr - nodes); + bucket_ptr->node_count = sbuckets[i].count; + + for (CONS__NameMapSemiNode *snode = sbuckets[i].first; + snode != 0; + snode = snode->next){ + CONS__NameMapNode *node = snode->node; + + // cons name and index(es) + U32 string_idx = cons__string(bctx, node->string); + U32 match_count = node->idx_count; + U32 idx = 0; + if (match_count == 1){ + idx = node->idx_first->idx[0]; + } + else{ + Temp temp = temp_begin(scratch.arena); + U32 *idx_run = push_array_no_zero(temp.arena, U32, match_count); + U32 *idx_ptr = idx_run; + for (CONS__NameMapIdxNode *idxnode = node->idx_first; + idxnode != 0; + idxnode = idxnode->next){ + for (U32 i = 0; i < ArrayCount(idxnode->idx); i += 1){ + if (idxnode->idx[i] == 0){ + goto dblbreak; + } + *idx_ptr = idxnode->idx[i]; + idx_ptr += 1; + } + } + dblbreak:; + Assert(idx_ptr == idx_run + match_count); + idx = cons__idx_run(bctx, idx_run, match_count); + temp_end(temp); + } + + // write to node + node_ptr->string_idx = string_idx; + node_ptr->match_count = match_count; + node_ptr->match_idx_or_idx_run_first = idx; + node_ptr += 1; + } + } + Assert(node_ptr - nodes == node_count); + } + + scratch_end(scratch); + + CONS__NameMapBaked *result = push_array(arena, CONS__NameMapBaked, 1); + result->buckets = buckets; + result->nodes = nodes; + result->bucket_count = bucket_count; + result->node_count = node_count; + return(result); +} diff --git a/src/raddbg_cons/raddbg_cons.h b/src/raddbg_cons/raddbg_cons.h new file mode 100644 index 00000000..3fcbca6e --- /dev/null +++ b/src/raddbg_cons/raddbg_cons.h @@ -0,0 +1,896 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_CONS_H +#define RADDBG_CONS_H + +//////////////////////////////// +//- "Public Facing" Cons API + +// frequently used opaque types +typedef struct CONS_Root CONS_Root; +typedef struct CONS_Unit CONS_Unit; +typedef struct CONS_Type CONS_Type; +typedef struct CONS_Reservation CONS_Reservation; +typedef struct CONS_Symbol CONS_Symbol; +typedef struct CONS_Scope CONS_Scope; +typedef struct CONS_Local CONS_Local; +typedef struct CONS_LocationSet CONS_LocationSet; +typedef struct CONS_Location CONS_Location; + +typedef struct CONS_TypeNode{ + struct CONS_TypeNode *next; + CONS_Type *type; +} CONS_TypeNode; + +typedef struct CONS_TypeList{ + CONS_TypeNode *first; + CONS_TypeNode *last; + U64 count; +} CONS_TypeList; + +typedef struct CONS_EvalBytecodeOp{ + struct CONS_EvalBytecodeOp *next; + RADDBG_EvalOp op; + U32 p_size; + U64 p; +} CONS_EvalBytecodeOp; + +typedef struct CONS_EvalBytecode{ + CONS_EvalBytecodeOp *first_op; + CONS_EvalBytecodeOp *last_op; + U32 op_count; + U32 encoded_size; +} CONS_EvalBytecode; + +//- init + +typedef struct CONS_RootParams{ + // important to set this correctly so pointer + // types get the correct sizes + U64 addr_size; + + // options to optimize map bucket counts + // * if these are left as zeros a modest default is used instead + U32 bucket_count_units; + U32 bucket_count_symbols; + U32 bucket_count_scopes; + U32 bucket_count_locals; + U32 bucket_count_types; +} CONS_RootParams; + +static CONS_Root* cons_root_new(CONS_RootParams *params); +static void cons_root_release(CONS_Root *root); + + +//- baking +static void cons_bake_file(Arena *arena, CONS_Root *root, String8List *out); + + +//- errors +typedef struct CONS_Error{ + struct CONS_Error *next; + String8 msg; +} CONS_Error; + +static void cons_errorf(CONS_Root *root, char *fmt, ...); + +static CONS_Error* cons_get_first_error(CONS_Root *root); + + + +//- information declaration + +// top level info +typedef struct CONS_TopLevelInfo{ + RADDBG_Arch architecture; + String8 exe_name; + U64 exe_hash; + U64 voff_max; +} CONS_TopLevelInfo; + +static void cons_set_top_level_info(CONS_Root *root, CONS_TopLevelInfo *tli); + + +// binary sections +static void cons_add_binary_section(CONS_Root *root, + String8 name, RADDBG_BinarySectionFlags flags, + U64 voff_first, U64 voff_opl, U64 foff_first, + U64 foff_opl); + + +// units +static CONS_Unit* cons_unit_handle_from_user_id(CONS_Root *root, U64 unit_user_id); + +typedef struct CONS_UnitInfo{ + String8 unit_name; + String8 compiler_name; + String8 source_file; + String8 object_file; + String8 archive_file; + String8 build_path; + RADDBG_Language language; +} CONS_UnitInfo; + +static void cons_unit_set_info(CONS_Root *root, CONS_Unit *unit, CONS_UnitInfo *info); + +typedef struct CONS_LineSequence{ + String8 file_name; + U64 *voffs; // [line_count + 1] (sorted) + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + U64 line_count; +} CONS_LineSequence; + +static void cons_unit_add_line_sequence(CONS_Root *root, CONS_Unit *unit, + CONS_LineSequence *line_sequence); + +static void cons_unit_vmap_add_range(CONS_Root *root, CONS_Unit *unit, U64 first, U64 opl); + + +// types +static CONS_Type* cons_type_from_id(CONS_Root *root, U64 type_user_id); +static CONS_Reservation* cons_type_reserve_id(CONS_Root *root, U64 type_user_id); +static void cons_type_fill_id(CONS_Root *root, CONS_Reservation *res, CONS_Type *type); + +static B32 cons_type_is_unhandled_nil(CONS_Root *root, CONS_Type *type); + +static CONS_Type* cons_type_handled_nil(CONS_Root *root); +static CONS_Type* cons_type_nil(CONS_Root *root); +static CONS_Type* cons_type_variadic(CONS_Root *root); + +static CONS_Type* cons_type_basic(CONS_Root *root, RADDBG_TypeKind type_kind, String8 name); +static CONS_Type* cons_type_modifier(CONS_Root *root, + CONS_Type *direct_type, RADDBG_TypeModifierFlags flags); +static CONS_Type* cons_type_bitfield(CONS_Root *root, + CONS_Type *direct_type, U32 bit_off, U32 bit_count); +static CONS_Type* cons_type_pointer(CONS_Root *root, + CONS_Type *direct_type, RADDBG_TypeKind ptr_type_kind); +static CONS_Type* cons_type_array(CONS_Root *root, + CONS_Type *direct_type, U64 count); +static CONS_Type* cons_type_proc(CONS_Root *root, + CONS_Type *return_type, struct CONS_TypeList *params); +static CONS_Type* cons_type_method(CONS_Root *root, + CONS_Type *this_type, CONS_Type *return_type, + struct CONS_TypeList *params); + +static CONS_Type* cons_type_udt(CONS_Root *root, + RADDBG_TypeKind record_type_kind, String8 name, U64 size); +static CONS_Type* cons_type_enum(CONS_Root *root, + CONS_Type *direct_type, String8 name); +static CONS_Type* cons_type_alias(CONS_Root *root, + CONS_Type *direct_type, String8 name); +static CONS_Type* cons_type_incomplete(CONS_Root *root, + RADDBG_TypeKind type_kind, String8 name); + +static void cons_type_add_member_data_field(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type, U32 off); +static void cons_type_add_member_static_data(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type); +static void cons_type_add_member_method(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type); +static void cons_type_add_member_static_method(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type); +static void cons_type_add_member_virtual_method(CONS_Root *root, CONS_Type *record_type, + String8 name, CONS_Type *mem_type); +static void cons_type_add_member_base(CONS_Root *root, CONS_Type *record_type, + CONS_Type *base_type, U32 off); +static void cons_type_add_member_virtual_base(CONS_Root *root, CONS_Type *record_type, + CONS_Type *base_type, U32 vptr_off, U32 vtable_off); +static void cons_type_add_member_nested_type(CONS_Root *root, CONS_Type *record_type, + CONS_Type *nested_type); + +static void cons_type_add_enum_val(CONS_Root *root, CONS_Type *enum_type, String8 name, U64 val); + +static void cons_type_set_source_coordinates(CONS_Root *root, CONS_Type *defined_type, + String8 source_path, U32 line, U32 col); + +// type list +static void cons_type_list_push(Arena *arena, CONS_TypeList *list, CONS_Type *type); + +// symbols +static CONS_Symbol* cons_symbol_handle_from_user_id(CONS_Root *root, U64 symbol_user_id); + +typedef enum{ + CONS_SymbolKind_NULL, + CONS_SymbolKind_GlobalVariable, + CONS_SymbolKind_ThreadVariable, + CONS_SymbolKind_Procedure, + CONS_SymbolKind_COUNT +} CONS_SymbolKind; + +typedef struct CONS_SymbolInfo{ + CONS_SymbolKind kind; + String8 name; + String8 link_name; + CONS_Type *type; + B32 is_extern; + U64 offset; + // TODO(allen): should this actually be "container scope"? + CONS_Symbol *container_symbol; + CONS_Type *container_type; + CONS_Scope *root_scope; +} CONS_SymbolInfo; + +static void cons_symbol_set_info(CONS_Root *root, CONS_Symbol *symbol, CONS_SymbolInfo *info); + +// scopes +static CONS_Scope *cons_scope_handle_from_user_id(CONS_Root *root, U64 scope_user_id); + +static void cons_scope_set_parent(CONS_Root *root, CONS_Scope *scope, CONS_Scope *parent); +static void cons_scope_add_voff_range(CONS_Root *root, CONS_Scope *scope, U64 voff_first, U64 voff_opl); + +// locals +static CONS_Local* cons_local_handle_from_user_id(CONS_Root *root, U64 local_user_id); + +typedef struct CONS_LocalInfo{ + RADDBG_LocalKind kind; + CONS_Scope *scope; + String8 name; + CONS_Type *type; +} CONS_LocalInfo; + +static void cons_local_set_basic_info(CONS_Root *root, CONS_Local *local, + CONS_LocalInfo *info); + +static CONS_LocationSet* cons_location_set_from_local(CONS_Root *root, CONS_Local *local); + +// locations +static void cons_location_set_add_case(CONS_Root *root, CONS_LocationSet *locset, + U64 voff_min, U64 voff_max, + CONS_Location *location); + +static CONS_Location* cons_location_addr_bytecode_stream(CONS_Root *root, + struct CONS_EvalBytecode *bytecode); +static CONS_Location* cons_location_val_bytecode_stream(CONS_Root *root, + struct CONS_EvalBytecode *bytecode); +static CONS_Location* cons_location_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset); +static CONS_Location* cons_location_addr_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset); +static CONS_Location* cons_location_val_reg(CONS_Root *root, U8 reg_code); + +// bytecode +static void cons_bytecode_push_op(Arena *arena, CONS_EvalBytecode *bytecode, RADDBG_EvalOp op, U64 p); +static void cons_bytecode_push_uconst(Arena *arena, CONS_EvalBytecode *bytecode, U64 x); +static void cons_bytecode_push_sconst(Arena *arena, CONS_EvalBytecode *bytecode, S64 x); +static void cons_bytecode_concat_in_place(CONS_EvalBytecode *left_dst, + CONS_EvalBytecode *right_destroyed); + +//////////////////////////////// +//- Concrete Types & Implementation Helpers + +// NOTE: the user should generally treat these as opaque + +// errors +typedef struct CONS_ErrorList{ + CONS_Error *first; + CONS_Error *last; + U64 count; +} CONS_ErrorList; + + +// binary sections +typedef struct CONS_BinarySection{ + struct CONS_BinarySection *next; + String8 name; + RADDBG_BinarySectionFlags flags; + U64 voff_first; + U64 voff_opl; + U64 foff_first; + U64 foff_opl; +} CONS_BinarySection; + + +// units +typedef struct CONS_LineSequenceNode{ + struct CONS_LineSequenceNode *next; + CONS_LineSequence line_seq; +} CONS_LineSequenceNode; + +typedef struct CONS_Unit{ + struct CONS_Unit *next_order; + + U32 idx; + + B32 info_is_set; + String8 unit_name; + String8 compiler_name; + String8 source_file; + String8 object_file; + String8 archive_file; + String8 build_path; + RADDBG_Language language; + + CONS_LineSequenceNode *line_seq_first; + CONS_LineSequenceNode *line_seq_last; + U64 line_seq_count; + +} CONS_Unit; + +typedef struct CONS_UnitVMapRange{ + struct CONS_UnitVMapRange *next; + CONS_Unit *unit; + U64 first; + U64 opl; +} CONS_UnitVMapRange; + + +// types +typedef struct CONS_Type{ + struct CONS_Type *next_order; + + RADDBG_TypeKind kind; + U32 idx; + U32 byte_size; + U32 flags; + U32 off; + U32 count; + + String8 name; + + struct CONS_Type *direct_type; + struct CONS_Type **param_types; + + struct CONS_TypeUDT *udt; +} CONS_Type; + +typedef struct CONS_TypeMember{ + struct CONS_TypeMember *next; + + RADDBG_MemberKind kind; + String8 name; + CONS_Type *type; + U32 off; +} CONS_TypeMember; + +typedef struct CONS_TypeEnumVal{ + struct CONS_TypeEnumVal *next; + + String8 name; + U64 val; +} CONS_TypeEnumVal; + +typedef struct CONS_TypeUDT{ + struct CONS_TypeUDT *next_order; + + U32 idx; + struct CONS_Type *self_type; + + CONS_TypeMember *first_member; + CONS_TypeMember *last_member; + U64 member_count; + + CONS_TypeEnumVal *first_enum_val; + CONS_TypeEnumVal *last_enum_val; + U64 enum_val_count; + + String8 source_path; + U32 line; + U32 col; +} CONS_TypeUDT; + +typedef U8 CONS_TypeConstructKind; +enum{ + CONS_TypeConstructKind_Basic, + CONS_TypeConstructKind_Modifier, + CONS_TypeConstructKind_Bitfield, + CONS_TypeConstructKind_Pointer, + CONS_TypeConstructKind_Array, + CONS_TypeConstructKind_Procedure, + CONS_TypeConstructKind_Method, +}; + +static CONS_Type* cons__type_new(CONS_Root *root); +static CONS_TypeUDT* cons__type_udt_from_any_type(CONS_Root *root, CONS_Type *type); +static CONS_TypeUDT* cons__type_udt_from_record_type(CONS_Root *root, CONS_Type *type); + + +// symbols +typedef struct CONS_Symbol{ + struct CONS_Symbol *next_order; + + U32 idx; + + CONS_SymbolKind kind; + String8 name; + String8 link_name; + CONS_Type *type; + B32 is_extern; + B8 offset_is_set; + U64 offset; + + CONS_Symbol *container_symbol; + CONS_Type *container_type; + + CONS_Scope *root_scope; +} CONS_Symbol; + + +// scopes +typedef struct CONS_Local{ + struct CONS_Local *next; + RADDBG_LocalKind kind; + String8 name; + CONS_Type *type; + CONS_LocationSet *locset; +} CONS_Local; + +typedef struct CONS__VOffRange{ + struct CONS__VOffRange *next; + U64 voff_first; + U64 voff_opl; +} CONS__VOffRange; + +typedef struct CONS_Scope{ + struct CONS_Scope *next_order; + + CONS_Symbol *symbol; + CONS_Scope *parent_scope; + CONS_Scope *first_child; + CONS_Scope *last_child; + CONS_Scope *next_sibling; + + U64 voff_base; + CONS__VOffRange *first_range; + CONS__VOffRange *last_range; + U32 range_count; + + U32 idx; + + CONS_Local *first_local; + CONS_Local *last_local; + U32 local_count; + +} CONS_Scope; + +static void cons__scope_recursive_set_symbol(CONS_Scope *scope, CONS_Symbol *symbol); + + +// locations +typedef struct CONS_Location{ + RADDBG_LocationKind kind; + U8 register_code; + U16 offset; + CONS_EvalBytecode bytecode; +} CONS_Location; + +typedef struct CONS__LocationCase{ + struct CONS__LocationCase *next; + U64 voff_first; + U64 voff_opl; + CONS_Location *location; +} CONS__LocationCase; + +typedef struct CONS_LocationSet{ + CONS__LocationCase *first_location_case; + CONS__LocationCase *last_location_case; + U64 location_case_count; +} CONS_LocationSet; + + +// name maps +typedef struct CONS__NameMapIdxNode{ + struct CONS__NameMapIdxNode *next; + U32 idx[8]; +} CONS__NameMapIdxNode; + +typedef struct CONS__NameMapNode{ + struct CONS__NameMapNode *bucket_next; + struct CONS__NameMapNode *order_next; + String8 string; + CONS__NameMapIdxNode *idx_first; + CONS__NameMapIdxNode *idx_last; + U64 idx_count; +} CONS__NameMapNode; + +typedef struct CONS__NameMap{ + CONS__NameMapNode *buckets[1<<24]; + CONS__NameMapNode *first; + CONS__NameMapNode *last; + U64 name_count; +} CONS__NameMap; + +static CONS__NameMap* cons__name_map_for_kind(CONS_Root *root, RADDBG_NameMapKind kind); +static void cons__name_map_add_pair(CONS_Root *root, CONS__NameMap *map, + String8 name, U32 idx); + + +// u64 to ptr map +typedef struct CONS__U64ToPtrNode{ + struct CONS__U64ToPtrNode *next; + U64 key[3]; + void *ptr[3]; +} CONS__U64ToPtrNode; + +typedef struct CONS__U64ToPtrMap{ + CONS__U64ToPtrNode **buckets; + U64 bucket_count; +} CONS__U64ToPtrMap; + +typedef struct CONS__U64ToPtrLookup{ + void *match; + CONS__U64ToPtrNode *fill_node; + U32 fill_k; +} CONS__U64ToPtrLookup; + +static void cons__u64toptr_init(Arena *arena, CONS__U64ToPtrMap *map, U64 bucket_count); + +static void cons__u64toptr_lookup(CONS__U64ToPtrMap *map, U64 key, CONS__U64ToPtrLookup *lookup_out); +static void cons__u64toptr_insert(Arena *arena, CONS__U64ToPtrMap *map, U64 key, + CONS__U64ToPtrLookup *lookup, void *ptr); + + + +// str8 to ptr map +typedef struct CONS__Str8ToPtrNode{ + struct CONS__Str8ToPtrNode *next; + String8 key; + U64 hash; + void *ptr; +} CONS__Str8ToPtrNode; + +typedef struct CONS__Str8ToPtrMap{ + CONS__Str8ToPtrNode *buckets[1<<24]; +} CONS__Str8ToPtrMap; + +static void*cons__str8toptr_lookup(CONS__Str8ToPtrMap *map, String8 key, U64 hash); +static void cons__str8toptr_insert(Arena *arena, CONS__Str8ToPtrMap *map, + String8 key, U64 hash, void *ptr); + +// root +struct CONS_Root{ + Arena *arena; + CONS_ErrorList errors; + + //////// Contextual Information + + U64 addr_size; + + //////// Info Declared By User + + // top level info + B32 top_level_info_is_set; + CONS_TopLevelInfo top_level_info; + + // binary layout + CONS_BinarySection *binary_section_first; + CONS_BinarySection *binary_section_last; + U64 binary_section_count; + + // compilation units + CONS_Unit *unit_first; + CONS_Unit *unit_last; + U64 unit_count; + + CONS_UnitVMapRange *unit_vmap_range_first; + CONS_UnitVMapRange *unit_vmap_range_last; + U64 unit_vmap_range_count; + + // types + CONS_Type *first_type; + CONS_Type *last_type; + U64 type_count; + + CONS_Type *nil_type; + CONS_Type *variadic_type; + + CONS_Type handled_nil_type; + + CONS_TypeUDT *first_udt; + CONS_TypeUDT *last_udt; + U64 type_udt_count; + + U64 total_member_count; + U64 total_enum_val_count; + + // symbols + CONS_Symbol *first_symbol; + CONS_Symbol *last_symbol; + union{ + U64 symbol_count; + U64 symbol_kind_counts[CONS_SymbolKind_COUNT]; + }; + + CONS_Scope *first_scope; + CONS_Scope *last_scope; + U64 scope_count; + U64 scope_voff_count; + + CONS_Local *first_local; + CONS_Local *last_local; + U64 local_count; + U64 location_count; + + // name maps + CONS__NameMap *name_maps[RADDBG_NameMapKind_COUNT]; + + //////// Handle Relationship Maps + + CONS__U64ToPtrMap unit_map; + CONS__U64ToPtrMap symbol_map; + CONS__U64ToPtrMap scope_map; + CONS__U64ToPtrMap local_map; + CONS__U64ToPtrMap type_from_id_map; + CONS__Str8ToPtrMap construct_map; +}; + + +//- cons intermediate data sections +typedef struct CONS__DSectionNode{ + struct CONS__DSectionNode *next; + void *data; + U64 size; + RADDBG_DataSectionTag tag; +} CONS__DSectionNode; + +typedef struct CONS__DSections{ + CONS__DSectionNode *first; + CONS__DSectionNode *last; + U32 count; +} CONS__DSections; + +//- cons intermediate strings +typedef struct CONS__StringNode{ + struct CONS__StringNode *order_next; + struct CONS__StringNode *bucket_next; + String8 str; + U64 hash; + U32 idx; +} CONS__StringNode; + +typedef struct CONS__Strings{ + CONS__StringNode *order_first; + CONS__StringNode *order_last; + CONS__StringNode *buckets[1<<24]; + U32 count; +} CONS__Strings; + +//- cons intermediate index runs +typedef struct CONS__IdxRunNode{ + struct CONS__IdxRunNode *order_next; + struct CONS__IdxRunNode *bucket_next; + U32 *idx_run; + U64 hash; + U32 count; + U32 first_idx; +} CONS__IdxRunNode; + +typedef struct CONS__IdxRuns{ + CONS__IdxRunNode *order_first; + CONS__IdxRunNode *order_last; + CONS__IdxRunNode *buckets[1<<24]; + U32 count; + U32 idx_count; +} CONS__IdxRuns; + +//- cons intermediate file path tree +typedef struct CONS__PathNode{ + struct CONS__PathNode *next_order; + struct CONS__PathNode *parent; + struct CONS__PathNode *first_child; + struct CONS__PathNode *last_child; + struct CONS__PathNode *next_sibling; + String8 name; + struct CONS__SrcNode *src_file; + U32 idx; +} CONS__PathNode; + +typedef struct CONS__LineMapFragment{ + struct CONS__LineMapFragment *next; + CONS_LineSequenceNode *sequence; +} CONS__LineMapFragment; + +typedef struct CONS__SrcNode{ + struct CONS__SrcNode *next; + CONS__PathNode *path_node; + U32 idx; + + String8 normal_full_path; + + // place to gather the line info attached to this src file + CONS__LineMapFragment *first_fragment; + CONS__LineMapFragment *last_fragment; + + // place to put the final baked version of this file's line map + U32 line_map_nums_data_idx; + U32 line_map_range_data_idx; + U32 line_map_count; + U32 line_map_voff_data_idx; +} CONS__SrcNode; + +typedef struct CONS__PathTree{ + CONS__PathNode *first; + CONS__PathNode *last; + U32 count; + CONS__PathNode root; + CONS__SrcNode *src_first; + CONS__SrcNode *src_last; + U32 src_count; +} CONS__PathTree; + +typedef struct CONS__BakeCtx{ + Arena *arena; + CONS__Strings strs; + CONS__IdxRuns idxs; + CONS__PathTree *tree; +} CONS__BakeCtx; + +//- cons intermediate functions +static U32 cons__dsection(Arena *arena, CONS__DSections *dss, + void *data, U64 size, RADDBG_DataSectionTag tag); + +static CONS__BakeCtx* cons__bake_ctx_begin(void); +static void cons__bake_ctx_release(CONS__BakeCtx *bake_ctx); + +static U32 cons__string(CONS__BakeCtx *bctx, String8 str); + +static U64 cons__idx_run_hash(U32 *idx_run, U32 count); +static U32 cons__idx_run(CONS__BakeCtx *bctx, U32 *idx_run, U32 count); + +static CONS__PathNode* cons__paths_new_node(CONS__BakeCtx *bctx); +static CONS__PathNode* cons__paths_sub_path(CONS__BakeCtx *bctx, CONS__PathNode *dir, String8 sub_dir); +static CONS__PathNode* cons__paths_node_from_path(CONS__BakeCtx *bctx, String8 path); +static U32 cons__paths_idx_from_path(CONS__BakeCtx *bctx, String8 path); + +static CONS__SrcNode* cons__paths_new_src_node(CONS__BakeCtx *bctx); +static CONS__SrcNode* cons__paths_src_node_from_path_node(CONS__BakeCtx *bctx, CONS__PathNode *path); + +//- cons path helper +static String8 cons__normal_string_from_path_node(Arena *arena, CONS__PathNode *node); +static void cons__normal_string_from_path_node_build(Arena *arena, CONS__PathNode *node, + String8List *out); + + +//- cons sort helper +typedef struct CONS__SortKey{ + U64 key; + void *val; +} CONS__SortKey; + +typedef struct CONS__OrderedRange{ + struct CONS__OrderedRange *next; + U64 first; + U64 opl; +} CONS__OrderedRange; + +static CONS__SortKey* cons__sort_key_array(Arena *arena, CONS__SortKey *keys, U64 count); + + +//- cons serializer for unit line info +typedef struct CONS__LineRec{ + U32 file_id; + U32 line_num; + U16 col_first; + U16 col_opl; +} CONS__LineRec; + +typedef struct CONS__UnitLinesCombined{ + U64 *voffs; + RADDBG_Line *lines; + U16 *cols; + U32 line_count; +} CONS__UnitLinesCombined; + +static CONS__UnitLinesCombined* cons__unit_combine_lines(Arena *arena, CONS__BakeCtx *bctx, + CONS_LineSequenceNode *first); + +//- cons serializer for source line info +typedef struct CONS__SrcLinesCombined{ + U32 *line_nums; + U32 *line_ranges; + U64 *voffs; + U32 line_count; + U32 voff_count; +} CONS__SrcLinesCombined; + +typedef struct CONS__SrcLineMapVoffBlock{ + struct CONS__SrcLineMapVoffBlock *next; + U64 voff; +} CONS__SrcLineMapVoffBlock; + +typedef struct CONS__SrcLineMapBucket{ + struct CONS__SrcLineMapBucket *next; + U32 line_num; + CONS__SrcLineMapVoffBlock *first_voff_block; + CONS__SrcLineMapVoffBlock *last_voff_block; + U64 voff_count; +} CONS__SrcLineMapBucket; + +static CONS__SrcLinesCombined* cons__source_combine_lines(Arena *arena, CONS__LineMapFragment *first); + +//- cons serializer for vmap type +typedef struct CONS__VMap{ + RADDBG_VMapEntry *vmap; // [count + 1] + U32 count; +} CONS__VMap; + +typedef struct CONS__VMapMarker{ + U32 idx; + U32 begin_range; +} CONS__VMapMarker; + +typedef struct CONS__VMapRangeTracker{ + struct CONS__VMapRangeTracker *next; + U32 idx; +} CONS__VMapRangeTracker; + +static CONS__VMap* cons__vmap_from_markers(Arena *arena, CONS__VMapMarker *markers, CONS__SortKey *keys, + U64 marker_count); + +//- cons serializer for unit vmap +static CONS__VMap* cons__vmap_from_unit_ranges(Arena *arena, CONS_UnitVMapRange *first, U64 count); + +//- cons serializer for types +typedef struct CONS__TypeData{ + RADDBG_TypeNode *type_nodes; + U32 type_node_count; + + RADDBG_UDT *udts; + U32 udt_count; + + RADDBG_Member *members; + U32 member_count; + + RADDBG_EnumMember *enum_members; + U32 enum_member_count; +} CONS__TypeData; + +static CONS__TypeData* cons__type_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx); + +static U32* cons__idx_run_from_types(Arena *arena, CONS_Type **types, U32 count); + +//- cons serializer for symbols +typedef struct CONS__SymbolData{ + RADDBG_GlobalVariable *global_variables; + U32 global_variable_count; + + CONS__VMap *global_vmap; + + RADDBG_ThreadVariable *thread_variables; + U32 thread_variable_count; + + RADDBG_Procedure *procedures; + U32 procedure_count; + + RADDBG_Scope *scopes; + U32 scope_count; + + U64 *scope_voffs; + U32 scope_voff_count; + + CONS__VMap *scope_vmap; + + RADDBG_Local *locals; + U32 local_count; + + RADDBG_LocationBlock *location_blocks; + U32 location_block_count; + + void *location_data; + U32 location_data_size; + +} CONS__SymbolData; + +static CONS__SymbolData* cons__symbol_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx); + +//- cons serializer for name maps +typedef struct CONS__NameMapSemiNode{ + struct CONS__NameMapSemiNode *next; + CONS__NameMapNode *node; +} CONS__NameMapSemiNode; + +typedef struct CONS__NameMapSemiBucket{ + CONS__NameMapSemiNode *first; + CONS__NameMapSemiNode *last; + U64 count; +} CONS__NameMapSemiBucket; + +typedef struct CONS__NameMapBaked{ + RADDBG_NameMapBucket *buckets; + RADDBG_NameMapNode *nodes; + U32 bucket_count; + U32 node_count; +} CONS__NameMapBaked; + +static CONS__NameMapBaked* cons__name_map_bake(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx, CONS__NameMap *map); + +#endif //RADDBG_CONS_H diff --git a/src/raddbg_convert/dwarf/raddbg_dwarf.c b/src/raddbg_convert/dwarf/raddbg_dwarf.c new file mode 100644 index 00000000..06abc03c --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_dwarf.c @@ -0,0 +1,1888 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ Dwarf Decode Helpers + +static U64 +dwarf_leb128_decode_U64(U8 *ptr, U8 *opl){ + U64 r = 0; + switch (opl - ptr){ + case 10: r |= ((U64)(ptr[9]&0x7F) << 63); + case 9: r |= ((U64)(ptr[8]&0x7F) << 56); + case 8: r |= ((U64)(ptr[7]&0x7F) << 49); + case 7: r |= ((U64)(ptr[6]&0x7F) << 42); + case 6: r |= ((U64)(ptr[5]&0x7F) << 35); + case 5: r |= ((U64)(ptr[4]&0x7F) << 28); + case 4: r |= ((U64)(ptr[3]&0x7F) << 21); + case 3: r |= ((U64)(ptr[2]&0x7F) << 14); + case 2: r |= ((U64)(ptr[1]&0x7F) << 7); + case 1: r |= ((U64)(ptr[0]&0x7F) ); + case 0: default: break; + } + return(r); +} + +static S64 +dwarf_leb128_decode_S64(U8 *ptr, U8 *opl){ + U64 u = dwarf_leb128_decode_U32(ptr, opl); + U64 s = (U64)(opl - ptr)*7; + B32 neg = ((u & (1llu << s)) != 0); + if (neg){ + switch (opl - ptr){ + case 9: u |= ~0x7FFFFFFFFFFFFFFFllu; break; + case 8: u |= ~0x00FFFFFFFFFFFFFFllu; break; + case 7: u |= ~ 0x01FFFFFFFFFFFFllu; break; + case 6: u |= ~ 0x03FFFFFFFFFFllu; break; + case 5: u |= ~ 0x07FFFFFFFFllu; break; + case 4: u |= ~ 0x0FFFFFFFllu; break; + case 3: u |= ~ 0x1FFFFFllu; break; + case 2: u |= ~ 0x3FFFllu; break; + case 1: u |= ~ 0x7Fllu; break; + } + } + S64 r = (S64)(u); + return(r); +} + +static U32 +dwarf_leb128_decode_U32(U8 *ptr, U8 *opl){ + U32 r = 0; + switch (opl - ptr){ + case 5: r |= ((U32)(ptr[4]&0x7F) << 28); + case 4: r |= ((U32)(ptr[3]&0x7F) << 21); + case 3: r |= ((U32)(ptr[2]&0x7F) << 14); + case 2: r |= ((U32)(ptr[1]&0x7F) << 7); + case 1: r |= ((U32)(ptr[0]&0x7F) ); + case 0: default: break; + } + return(r); +} + + +//////////////////////////////// +//~ Dwarf Parser Functions + +static DWARF_Parsed* +dwarf_parsed_from_elf(Arena *arena, ELF_Parsed *elf){ + DWARF_Parsed *result = 0; + + if (elf != 0){ + //- extract debug info + U32 debug_section_idx[DWARF_SectionCode_COUNT] = {0}; + String8 debug_section_name[DWARF_SectionCode_COUNT] = {0}; + String8 debug_data[DWARF_SectionCode_COUNT] = {0}; + for (U64 i = 1; i < DWARF_SectionCode_COUNT; i += 1){ + DWARF_SectionNameRow *row = dwarf_section_name_table + i; + U32 idx = 0; + for (U32 j = 0; idx == 0 && j < DWARF_SECTION_NAME_VARIANT_COUNT; j += 1){ + idx = elf_section_idx_from_name(elf, row->name[j]); + } + debug_section_idx[i] = idx; + debug_section_name[i] = elf_section_name_from_idx(elf, idx); + debug_data[i] = elf_section_data_from_idx(elf, idx); + } + + //- fill result + { + result = push_array(arena, DWARF_Parsed, 1); + result->elf = elf; + MemoryCopyArray(result->debug_section_idx, debug_section_idx); + MemoryCopyArray(result->debug_section_name, debug_section_name); + MemoryCopyArray(result->debug_data, debug_data); + } + } + + return(result); +} + +static DWARF_IndexParsed* +dwarf_index_from_data(Arena *arena, String8 data){ + DWARF_IndexParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_SupParsed* +dwarf_sup_from_data(Arena *arena, String8 data){ + DWARF_SupParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_InfoParsed* +dwarf_info_from_data(Arena *arena, String8 data){ + // supported version numbers: 4,5 + + + // empty unit list + DWARF_InfoUnit *first = 0; + DWARF_InfoUnit *last = 0; + U64 count = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + // remember header offset + U64 hdr_off = (ptr - data.str); + + // initial length + U8 *unit_opl = 0; + B32 is_64bit = 0; + dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); + + // version + U8 version = MemoryConsume(U16, ptr, unit_opl); + + // rest of header depends on version + U64 abbrev_off = 0; + U8 address_size = 0; + U8 unit_type = 0; + U64 unit_dwo_id = 0; + U64 unit_type_signature = 0; + U64 unit_type_offset = 0; + switch (version){ + case 4: + { + // abbrev_off + if (is_64bit){ + abbrev_off = MemoryConsume(U64, ptr, unit_opl); + } + else{ + abbrev_off = MemoryConsume(U32, ptr, unit_opl); + } + + // address_size + address_size = MemoryConsume(U8, ptr, unit_opl); + }break; + + case 5: + { + // unit_type + unit_type = (DWARF_UnitType)MemoryConsume(U8, ptr, unit_opl); + + // address_size + address_size = MemoryConsume(U8, ptr, unit_opl); + + // abbrev_off + if (is_64bit){ + abbrev_off = MemoryConsume(U64, ptr, unit_opl); + } + else{ + abbrev_off = MemoryConsume(U32, ptr, unit_opl); + } + + // rest of header depends on unit_type + switch (unit_type){ + case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile: + { + unit_dwo_id = MemoryConsume(U64, ptr, unit_opl); + }break; + case DWARF_UnitType_type: case DWARF_UnitType_split_type: + { + unit_type_signature = MemoryConsume(U64, ptr, unit_opl); + if (is_64bit){ + unit_type_offset = MemoryConsume(U64, ptr, unit_opl); + } + else{ + unit_type_offset = MemoryConsume(U32, ptr, unit_opl); + } + }break; + } + }break; + } + + // offset size + U8 offset_size = is_64bit?8:4; + + // unit offsets + U64 base_off = (ptr - data.str); + U64 opl_off = (unit_opl - data.str); + + // emit unit + DWARF_InfoUnit *unit = push_array(arena, DWARF_InfoUnit, 1); + SLLQueuePush(first, last, unit); + count += 1; + + unit->hdr_off = hdr_off; + unit->base_off = base_off; + unit->opl_off = opl_off; + + unit->offset_size = offset_size; + unit->version = version; + unit->unit_type = unit_type; + unit->address_size = address_size; + unit->abbrev_off = abbrev_off; + + switch (unit_type){ + case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile: + { + unit->dwo_id = unit_dwo_id; + }break; + case DWARF_UnitType_type: case DWARF_UnitType_split_type: + { + unit->type_signature = unit_type_signature; + unit->type_offset = unit_type_offset; + }break; + } + + // advance to end of unit + ptr = unit_opl; + } + + // fill result + DWARF_InfoParsed *result = push_array(arena, DWARF_InfoParsed, 1); + result->unit_first = first; + result->unit_last = last; + result->unit_count = count; + return(result); +} + +static DWARF_PubNamesParsed* +dwarf_pubnames_from_data(Arena *arena, String8 data){ + // supported version numbers: 2 + + + // empty unit list + DWARF_PubNamesUnit *first = 0; + DWARF_PubNamesUnit *last = 0; + U64 count = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + // remember header offset + U64 hdr_off = (ptr - data.str); + + // initial length + U8 *unit_opl = 0; + B32 is_64bit = 0; + dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); + + // version + U8 version = MemoryConsume(U16, ptr, unit_opl); + + // info_off + U64 info_off = 0; + if (is_64bit){ + info_off = MemoryConsume(U64, ptr, unit_opl); + } + else{ + info_off = MemoryConsume(U32, ptr, unit_opl); + } + + // info_length + U64 info_length = 0; + if (is_64bit){ + info_length = MemoryConsume(U64, ptr, unit_opl); + } + else{ + info_length = MemoryConsume(U32, ptr, unit_opl); + } + + // offset size + U8 offset_size = is_64bit?8:4; + + // unit offsets + U64 base_off = (ptr - data.str); + U64 opl_off = (unit_opl - data.str); + + // emit unit + DWARF_PubNamesUnit *unit = push_array(arena, DWARF_PubNamesUnit, 1); + SLLQueuePush(first, last, unit); + count += 1; + + unit->hdr_off = hdr_off; + unit->base_off = base_off; + unit->opl_off = opl_off; + + unit->offset_size = offset_size; + unit->version = version; + unit->info_off = info_off; + unit->info_length = info_length; + + // advance to end of unit + ptr = unit_opl; + } + + // fill result + DWARF_PubNamesParsed *result = push_array(arena, DWARF_PubNamesParsed, 1); + result->unit_first = first; + result->unit_last = last; + result->unit_count = count; + return(result); +} + +static DWARF_NamesParsed* +dwarf_names_from_data(Arena *arena, String8 data){ + // supported version numbers: 5 + + + // empty unit list + DWARF_NamesUnit *first = 0; + DWARF_NamesUnit *last = 0; + U64 count = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + // remember header offset + U64 hdr_off = (ptr - data.str); + + // initial length + U8 *unit_opl = 0; + B32 is_64bit = 0; + dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); + + // version + U8 version = MemoryConsume(U16, ptr, unit_opl); + + // *padding* + MemoryConsume(U16, ptr, unit_opl); + + // comp_unit_count + U32 comp_unit_count = MemoryConsume(U32, ptr, unit_opl); + + // local_type_unit_count + U32 local_type_unit_count = MemoryConsume(U32, ptr, unit_opl); + + // foreign_type_unit_count + U32 foreign_type_unit_count = MemoryConsume(U32, ptr, unit_opl); + + // bucket_count + U32 bucket_count = MemoryConsume(U32, ptr, unit_opl); + + // name_count + U32 name_count = MemoryConsume(U32, ptr, unit_opl); + + // abbrev_table_size + U32 abbrev_table_size = MemoryConsume(U32, ptr, unit_opl); + + // augmentation_string_size + U32 augmentation_string_size = MemoryConsume(U32, ptr, unit_opl); + + // augmentation_string + U8 *augmentation_string = ptr; + { + U8 *ptr_raw = ptr + augmentation_string_size; + ptr = PtrClampTop(ptr_raw, unit_opl); + } + + // offset size + U8 offset_size = is_64bit?8:4; + + // unit offsets + U64 base_off = (ptr - data.str); + U64 opl_off = (unit_opl - data.str); + + // emit unit + DWARF_NamesUnit *unit = push_array(arena, DWARF_NamesUnit, 1); + SLLQueuePush(first, last, unit); + count += 1; + + unit->hdr_off = hdr_off; + unit->base_off = base_off; + unit->opl_off = opl_off; + + unit->version = version; + unit->comp_unit_count = comp_unit_count; + unit->local_type_unit_count = local_type_unit_count; + unit->foreign_type_unit_count = foreign_type_unit_count; + unit->bucket_count = bucket_count; + unit->name_count = name_count; + unit->abbrev_table_size = abbrev_table_size; + unit->augmentation_string = str8_cstring_capped(augmentation_string, unit_opl); + + // advance to end of unit + ptr = unit_opl; + } + + // fill result + DWARF_NamesParsed *result = push_array(arena, DWARF_NamesParsed, 1); + result->unit_first = first; + result->unit_last = last; + result->unit_count = count; + return(result); +} + +static DWARF_ArangesParsed* +dwarf_aranges_from_data(Arena *arena, String8 data){ + // supported version numbers: 2 + + + // empty unit list + DWARF_ArangesUnit *first = 0; + DWARF_ArangesUnit *last = 0; + U64 count = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + // remember header offset + U64 hdr_off = (ptr - data.str); + + // initial length + U8 *unit_opl = 0; + B32 is_64bit = 0; + dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); + + // version + U8 version = MemoryConsume(U16, ptr, unit_opl); + + // info_off + U64 info_off = 0; + if (is_64bit){ + info_off = MemoryConsume(U64, ptr, unit_opl); + } + else{ + info_off = MemoryConsume(U32, ptr, unit_opl); + } + + // address_size + U8 address_size = MemoryConsume(U8, ptr, unit_opl); + + // segment_selector_size + U8 segment_selector_size = MemoryConsume(U8, ptr, unit_opl); + + // offset size + U8 offset_size = is_64bit?8:4; + + // unit offsets + U64 base_off = (ptr - data.str); + U64 opl_off = (unit_opl - data.str); + + // emit unit + DWARF_ArangesUnit *unit = push_array(arena, DWARF_ArangesUnit, 1); + SLLQueuePush(first, last, unit); + count += 1; + + unit->hdr_off = hdr_off; + unit->base_off = base_off; + unit->opl_off = opl_off; + + unit->version = version; + unit->address_size = address_size; + unit->segment_selector_size = segment_selector_size; + unit->offset_size = offset_size; + unit->info_off = info_off; + + // advance to end of unit + ptr = unit_opl; + } + + // fill result + DWARF_ArangesParsed *result = push_array(arena, DWARF_ArangesParsed, 1); + result->unit_first = first; + result->unit_last = last; + result->unit_count = count; + return(result); +} + +static DWARF_LineParsed* +dwarf_line_from_data(Arena *arena, String8 data){ + // supported version numbers: 4, 5 + + + // empty unit list + DWARF_LineUnit *first = 0; + DWARF_LineUnit *last = 0; + U64 count = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + // remember header offset + U64 hdr_off = (ptr - data.str); + + // initial length + U8 *unit_opl = 0; + B32 is_64bit = 0; + dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); + + // version + U8 version = MemoryConsume(U16, ptr, unit_opl); + + // offset size + U8 offset_size = is_64bit?8:4; + + // rest of header depends on version + U8 minimum_instruction_length = 0; + U8 maximum_operations_per_instruction = 0; + U8 default_is_stmt = 0; + S8 line_base = 0; + U8 line_range = 0; + U8 opcode_base = 0; + U8 *standard_opcode_lengths = 0; + // v4 + String8List include_directories = {0}; + DWARF_V4LineFileNamesList file_names = {0}; + // v5 + U8 address_size = 0; + U8 segment_selector_size = 0; + U8 directory_entry_format_count = 0; + DWARF_V5LinePathEntryFormat *directory_entry_format = 0; + U64 directories_count = 0; + U8 file_name_entry_format_count = 0; + DWARF_V5LinePathEntryFormat *file_name_entry_format = 0; + U64 file_names_count = 0; + + switch (version){ + case 4: + { + // header_length + U64 header_length = 0; + if (is_64bit){ + header_length = MemoryConsume(U64, ptr, unit_opl); + } + else{ + header_length = MemoryConsume(U32, ptr, unit_opl); + } + + // header opl + U8 *header_opl_raw = ptr + header_length; + U8 *header_opl = PtrClampTop(header_opl_raw, unit_opl); + + // minimum_instruction_length + minimum_instruction_length = MemoryConsume(U8, ptr, header_opl); + + // maximum_operations_per_instruction + maximum_operations_per_instruction = MemoryConsume(U8, ptr, header_opl); + + // default_is_stmt + default_is_stmt = MemoryConsume(U8, ptr, header_opl); + + // line_base + line_base = MemoryConsume(S8, ptr, header_opl); + + // line_range + line_range = MemoryConsume(U8, ptr, header_opl); + + // opcode_base + opcode_base = MemoryConsume(U8, ptr, header_opl); + + // standard_opcode_lengths + if (opcode_base > 1){ + standard_opcode_lengths = ptr; + ptr += opcode_base - 1; + } + + // include_directories + for (;ptr < header_opl;){ + // null byte ends entries + if (*ptr == 0){ + ptr += 1; + break; + } + + // extract dir range + U8 *dir_first = ptr; + for (;ptr < header_opl && *ptr != 0;) ptr += 1; + U8 *dir_opl = ptr; + if (ptr < header_opl){ + ptr += 1; + } + + // attach dir to list + String8 dir = str8_range(dir_first, dir_opl); + str8_list_push(arena, &include_directories, dir); + } + + // file_names + for (;ptr < header_opl;){ + // null byte ends entries + if (*ptr == 0){ + ptr += 1; + break; + } + + // extract file_name range + U8 *file_name_first = ptr; + for (;ptr < header_opl && *ptr != 0;) ptr += 1; + U8 *file_name_opl = ptr; + if (ptr < header_opl){ + ptr += 1; + } + + // extract include directory index + U64 include_directory_idx = 0; + DWARF_LEB128_DECODE_ADV(U64, include_directory_idx, ptr, header_opl); + + // extract last modified time + U64 last_modified_time = 0; + DWARF_LEB128_DECODE_ADV(U64, last_modified_time, ptr, header_opl); + + // extract file size + U64 file_size = 0; + DWARF_LEB128_DECODE_ADV(U64, file_size, ptr, header_opl); + + // emit file name entry + DWARF_V4LineFileNamesEntry *entry = push_array(arena, DWARF_V4LineFileNamesEntry, 1); + SLLQueuePush(file_names.first, file_names.last, entry); + file_names.count += 1; + entry->file_name = str8_range(file_name_first, file_name_opl); + entry->include_directory_idx = include_directory_idx; + entry->last_modified_time = last_modified_time; + entry->file_size = file_size; + } + + ptr = header_opl; + }break; + + case 5: + { + // address_size + address_size = MemoryConsume(U8, ptr, unit_opl); + + // segment_selector_size + segment_selector_size = MemoryConsume(U8, ptr, unit_opl); + + // header_length + U64 header_length = 0; + if (is_64bit){ + header_length = MemoryConsume(U64, ptr, unit_opl); + } + else{ + header_length = MemoryConsume(U32, ptr, unit_opl); + } + + // header opl + U8 *header_opl_raw = ptr + header_length; + U8 *header_opl = PtrClampTop(header_opl_raw, unit_opl); + + // minimum_instruction_length + minimum_instruction_length = MemoryConsume(U8, ptr, header_opl); + + // maximum_operations_per_instruction + maximum_operations_per_instruction = MemoryConsume(U8, ptr, header_opl); + + // default_is_stmt + default_is_stmt = MemoryConsume(U8, ptr, header_opl); + + // line_base + line_base = MemoryConsume(S8, ptr, header_opl); + + // line_range + line_range = MemoryConsume(U8, ptr, header_opl); + + // opcode_base + opcode_base = MemoryConsume(U8, ptr, header_opl); + + // standard_opcode_lengths + if (opcode_base > 1){ + standard_opcode_lengths = ptr; + ptr += opcode_base - 1; + } + + // directory_entry_format_count + directory_entry_format_count = MemoryConsume(U8, ptr, header_opl); + + // directory_entry_format + { + directory_entry_format = push_array(arena, DWARF_V5LinePathEntryFormat, + directory_entry_format_count); + DWARF_V5LinePathEntryFormat *entry = directory_entry_format; + DWARF_V5LinePathEntryFormat *entry_opl = + directory_entry_format + directory_entry_format_count; + for (;entry < entry_opl && ptr < header_opl; entry += 1){ + DWARF_LEB128_DECODE_ADV(U64, entry->content_type, ptr, header_opl); + DWARF_LEB128_DECODE_ADV(U64, entry->form, ptr, header_opl); + } + } + + // directories_count + DWARF_LEB128_DECODE_ADV(U64, directories_count, ptr, header_opl); + + // directories + DWARF_V5Directory *directories = push_array(arena, DWARF_V5Directory, directories_count); + dwarf__line_v5_directories(address_size, offset_size, + directory_entry_format, directory_entry_format_count, + directories, directories_count, + &ptr, header_opl); + + // file_name_entry_format_count + file_name_entry_format_count = MemoryConsume(U8, ptr, header_opl); + + // file_name_entry_format + { + file_name_entry_format = push_array(arena, DWARF_V5LinePathEntryFormat, + file_name_entry_format_count); + DWARF_V5LinePathEntryFormat *entry = file_name_entry_format; + for (;ptr < header_opl; entry += 1){ + DWARF_LEB128_DECODE_ADV(U64, entry->content_type, ptr, header_opl); + DWARF_LEB128_DECODE_ADV(U64, entry->form, ptr, header_opl); + } + } + + // file_names_count + DWARF_LEB128_DECODE_ADV(U64, file_names_count, ptr, header_opl); + + // file_names + DWARF_V5Directory *file_names = push_array(arena, DWARF_V5Directory, file_names_count); + dwarf__line_v5_directories(address_size, offset_size, + directory_entry_format, directory_entry_format_count, + file_names, file_names_count, + &ptr, header_opl); + }break; + } + + // unit offsets + U64 base_off = (ptr - data.str); + U64 opl_off = (unit_opl - data.str); + + // emit unit + DWARF_LineUnit *unit = push_array(arena, DWARF_LineUnit, 1); + SLLQueuePush(first, last, unit); + count += 1; + + unit->hdr_off = hdr_off; + unit->base_off = base_off; + unit->opl_off = opl_off; + + unit->version = version; + + // advance to end of unit + ptr = unit_opl; + } + + // fill result + DWARF_LineParsed *result = push_array(arena, DWARF_LineParsed, 1); + result->unit_first = first; + result->unit_last = last; + result->unit_count = count; + return(result); +} + +static DWARF_MacInfoParsed* +dwarf_mac_info_from_data(Arena *arena, String8 data){ + DWARF_MacInfoParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_MacroParsed* +dwarf_macro_from_data(Arena *arena, String8 data){ + DWARF_MacroParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_FrameParsed* +dwarf_frame_from_data(Arena *arena, String8 data){ + DWARF_FrameParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_RangesParsed* +dwarf_ranges_from_data(Arena *arena, String8 data){ + DWARF_RangesParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_StrOffsetsParsed* +dwarf_str_offsets_from_data(Arena *arena, String8 data){ + DWARF_StrOffsetsParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_AddrParsed* +dwarf_addr_from_data(Arena *arena, String8 data){ + // supported version numbers: 5 + + + // addr unit list + DWARF_AddrUnit *first = 0; + DWARF_AddrUnit *last = 0; + U64 count = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + U64 hdr_off = (ptr - data.str); + + // initial length + U8 *unit_opl = 0; + B32 is_64bit = 0; + dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); + + // version + U8 version = MemoryConsume(U16, ptr, unit_opl); + + // address size + U8 address_size = MemoryConsume(U8, ptr, unit_opl); + + // segment selector size + U8 segment_selector_size = MemoryConsume(U8, ptr, unit_opl); + + // offset size + U32 offset_size = is_64bit?8:4; + + // unit offsets + U64 base_off = (ptr - data.str); + U64 opl_off = (unit_opl - data.str); + + // emit addr unit + DWARF_AddrUnit *unit = push_array(arena, DWARF_AddrUnit, 1); + SLLQueuePush(first, last, unit); + count += 1; + + unit->hdr_off = hdr_off; + unit->base_off = base_off; + unit->opl_off = opl_off; + + unit->offset_size = offset_size; + unit->dwarf_version = version; + unit->address_size = address_size; + unit->segment_selector_size = segment_selector_size; + + // advance to next unit + ptr = unit_opl; + } + + // fill result + DWARF_AddrParsed *result = push_array(arena, DWARF_AddrParsed, 1); + result->unit_first = first; + result->unit_last = last; + result->unit_count = count; + return(result); +} + +static DWARF_RngListsParsed* +dwarf_rng_lists_from_data(Arena *arena, String8 data){ + DWARF_RngListsParsed *result = 0; + // TODO(allen): + return(result); +} + +static DWARF_LocListsParsed* +dwarf_loc_lists_from_data(Arena *arena, String8 data){ + DWARF_LocListsParsed *result = 0; + // TODO(allen): + return(result); +} + + +// parse helpers + +static void +dwarf__initial_length(String8 data, U8 **ptr_inout, U8 **unit_opl_out, B32 *is_64bit_out){ + U8 *unit_opl = 0; + B32 is_64bit = 0; + + U8 *opl = data.str + data.size; + U8 *ptr = *ptr_inout; + { + U64 length = 0; + U32 m = MemoryConsume(U32, ptr, opl); + if (m == 0xFFFFFFFF){ + is_64bit = 1; + length = MemoryConsume(U64, ptr, opl); + } + else{ + length = ClampTop(m, 0xFFFFFFF0); + } + if (length > 0){ + U64 unit_opl_off_raw = (ptr - data.str) + length; + U64 unit_opl_off = ClampTop(unit_opl_off_raw, data.size); + unit_opl = data.str + unit_opl_off; + } + else{ + unit_opl = ptr; + } + } + + *ptr_inout = ptr; + *unit_opl_out = unit_opl; + *is_64bit_out = is_64bit; +} + +static void +dwarf__line_v5_directories(U64 address_size, U64 offset_size, + DWARF_V5LinePathEntryFormat *format, U64 format_count, + DWARF_V5Directory *directories_out, U64 dir_count, + U8 **ptr_io, U8 *opl){ + + U8 *ptr = *ptr_io; + + DWARF_V5Directory *directory_ptr = directories_out; + for (U32 i = 0; i < dir_count; i += 1, directory_ptr += 1){ + DWARF_V5LinePathEntryFormat *fmt = format; + for (U32 j = 0; j < format_count; j += 1){ + + // form decode + DWARF_FormDecodeRules rules = + dwarf_form_decode_rule(fmt->form, address_size, offset_size); + + // execute decoding + DWARF_FormDecoded decoded = dwarf_form_decode(&rules, &ptr, opl, 0, 0); + + // store to correct field + U64 *target = 0; + switch (fmt->content_type){ + case DWARF_LineEntryFormat_path: + { + if (decoded.dataptr != 0){ + directory_ptr->path_str = str8(decoded.dataptr, decoded.val); + } + else{ + directory_ptr->path_off = decoded.val; + directory_ptr->path_sec_form = fmt->form; + } + }break; + + case DWARF_LineEntryFormat_directory_index: + { + target = &directory_ptr->directory_index; + }goto v5_directory_u64; + + case DWARF_LineEntryFormat_timestamp: + { + target = &directory_ptr->timestamp; + }goto v5_directory_u64; + + case DWARF_LineEntryFormat_size: + { + target = &directory_ptr->size; + }goto v5_directory_u64; + + v5_directory_u64: + { + if (decoded.dataptr != 0){ + U64 size = ClampTop(decoded.val, 8); + MemoryCopy(target, decoded.dataptr, size); + } + else{ + *target = decoded.val; + } + }break; + + case DWARF_LineEntryFormat_MD5: + { + if (decoded.dataptr != 0){ + U64 size = ClampTop(decoded.val, 16); + MemoryCopy(directory_ptr->md5_checksum, decoded.dataptr, size); + } + }break; + } + } + } + + *ptr_io = ptr; +} + + +// debug sections + +static String8 +dwarf_name_from_debug_section(DWARF_Parsed *dwarf, DWARF_SectionCode sec_code){ + String8 result = str8_lit("invalid_debug_section"); + if (sec_code < DWARF_SectionCode_COUNT){ + if (dwarf->debug_section_idx[sec_code] != 0){ + result = dwarf->debug_section_name[sec_code]; + } + } + return(result); +} + + +// abbrev functions + +static DWARF_AbbrevUnit* +dwarf_abbrev_unit_from_offset(DWARF_AbbrevParsed *abbrev, U64 offset){ + DWARF_AbbrevUnit *result = 0; + for (DWARF_AbbrevUnit *unit = abbrev->unit_first; + unit != 0; + unit = unit->next){ + if (unit->offset == offset){ + result = unit; + break; + } + } + return(result); +} + +static DWARF_AbbrevDecl* +dwarf_abbrev_decl_from_code(DWARF_AbbrevUnit *unit, U32 abbrev_code){ + DWARF_AbbrevDecl *result = 0; + for (DWARF_AbbrevDecl *decl = unit->first; + decl != 0; + decl = decl->next){ + if (decl->abbrev_code == abbrev_code){ + result = decl; + break; + } + } + return(result); +} + +// attribute decoding functions + +static DWARF_AttributeClassFlags +dwarf_attribute_class_from_form(DWARF_AttributeForm form){ + DWARF_AttributeClassFlags result = 0; + switch (form){ +#define X(N,C,f) case C: result = DWARF_AttributeClassFlag_##f; break; + DWARF_AttributeFormXList(X) +#undef X + } + return(result); +} + +static DWARF_AttributeClassFlags +dwarf_attribute_class_from_name(DWARF_AttributeName name){ + DWARF_AttributeClassFlags result = 0; + switch (name){ +#define X(N,C,f1,f2,f3,f4) case C: result = 0\ +|DWARF_AttributeClassFlag_##f1\ +|DWARF_AttributeClassFlag_##f2\ +|DWARF_AttributeClassFlag_##f3\ +|DWARF_AttributeClassFlag_##f4\ +;break; + DWARF_AttributeNameXList(X) +#undef X + } + return(result); +} + +// form decoding functions + +static DWARF_FormDecodeRules +dwarf_form_decode_rule(DWARF_AttributeForm form, U64 address_size, U64 offset_size){ + DWARF_FormDecodeRules result = {0}; + switch (form){ + case DWARF_AttributeForm_addr: result.size = address_size; break; + case DWARF_AttributeForm_addrx: result.uleb128 = 1; break; + case DWARF_AttributeForm_addrx1: result.size = 1; break; + case DWARF_AttributeForm_addrx2: result.size = 2; break; + case DWARF_AttributeForm_addrx3: result.size = 3; break; + case DWARF_AttributeForm_addrx4: result.size = 4; break; + + case DWARF_AttributeForm_sec_offset: result.size = offset_size; break; + + case DWARF_AttributeForm_block1: result.size = 1; result.block = 1; break; + case DWARF_AttributeForm_block2: result.size = 2; result.block = 1; break; + case DWARF_AttributeForm_block4: result.size = 4; result.block = 1; break; + case DWARF_AttributeForm_block: result.uleb128 = 1; result.block = 1; break; + + case DWARF_AttributeForm_data1: result.size = 1; break; + case DWARF_AttributeForm_data2: result.size = 2; break; + case DWARF_AttributeForm_data4: result.size = 4; break; + case DWARF_AttributeForm_data8: result.size = 8; break; + case DWARF_AttributeForm_data16: result.size = 16; break; + + case DWARF_AttributeForm_sdata: result.sleb128 = 1; break; + case DWARF_AttributeForm_udata: result.uleb128 = 1; break; + + case DWARF_AttributeForm_implicit_const: result.in_abbrev = 1; break; + + case DWARF_AttributeForm_exprloc: result.uleb128 = 1; result.block = 1; break; + + case DWARF_AttributeForm_flag: result.size = 1; break; + case DWARF_AttributeForm_flag_present: result.auto_1 = 1; break; + + case DWARF_AttributeForm_loclistx: result.uleb128 = 1; break; + case DWARF_AttributeForm_rnglistx: result.uleb128 = 1; break; + + case DWARF_AttributeForm_ref1: result.size = 1; break; + case DWARF_AttributeForm_ref2: result.size = 2; break; + case DWARF_AttributeForm_ref4: result.size = 4; break; + case DWARF_AttributeForm_ref8: result.size = 8; break; + case DWARF_AttributeForm_ref_udata: result.uleb128 = 1; break; + + case DWARF_AttributeForm_ref_addr: result.size = offset_size; break; + + case DWARF_AttributeForm_ref_sig8: result.size = 8; break; + + case DWARF_AttributeForm_ref_sup4: result.size = 4; break; + case DWARF_AttributeForm_ref_sup8: result.size = 8; break; + + case DWARF_AttributeForm_string: result.null_terminated = 1; break; + + case DWARF_AttributeForm_strp: result.size = offset_size; break; + case DWARF_AttributeForm_line_strp: result.size = offset_size; break; + case DWARF_AttributeForm_strp_sup: result.size = offset_size; break; + + case DWARF_AttributeForm_strx: result.uleb128 = 1; break; + case DWARF_AttributeForm_strx1: result.size = 1; break; + case DWARF_AttributeForm_strx2: result.size = 2; break; + case DWARF_AttributeForm_strx3: result.size = 3; break; + case DWARF_AttributeForm_strx4: result.size = 4; break; + } + + return(result); +} + +static DWARF_FormDecoded +dwarf_form_decode(DWARF_FormDecodeRules *rules, U8 **ptr_io, U8 *opl, + DWARF_AbbrevDecl *abbrev_decl, U32 attrib_i){ + + // local copy of ptr + U8 *ptr = *ptr_io; + + // apply rules + U64 val = 0; + U8 *dataptr = 0; + + B32 success = 1; + if (rules->size > 0){ + if (ptr + rules->size <= opl){ + MemoryCopy(&val, ptr, rules->size); + ptr += rules->size; + } + else{ + success = 0; + } + } + else if (rules->uleb128 || rules->sleb128){ + U8 *val_ptr = ptr; + DWARF_LEB128_ADV(ptr, opl, success); + if (success){ + if (rules->uleb128){ + val = dwarf_leb128_decode_U64(val_ptr, ptr); + } + else{ + val = (U64)dwarf_leb128_decode_S64(val_ptr, ptr); + } + } + } + else if (rules->in_abbrev){ + if (abbrev_decl != 0){ + if (abbrev_decl->implicit_const != 0){ + val = (U64)abbrev_decl->implicit_const[attrib_i]; + } + } + else{ + success = 0; + } + } + else if (rules->auto_1){ + val = 1; + } + if (rules->block){ + dataptr = ptr; + ptr += val; + } + else if (rules->null_terminated){ + dataptr = ptr; + for (;ptr < opl && *ptr != 0;) ptr += 1; + val = (U64)(ptr - dataptr); + if (ptr < opl){ + ptr += 1; + } + } + + // store out ptr + *ptr_io = ptr; + + // fill result + DWARF_FormDecoded result = {0}; + result.val = val; + result.dataptr = dataptr; + result.error = !success; + return(result); +} + + +// string functions + +static String8 +dwarf_string_from_unit_type(DWARF_UnitType type){ + String8 result = str8_lit("unrecognized_type"); + switch (type){ +#define X(N,C) case C: result = str8_lit(#N); break; + DWARF_UnitTypeXList(X) +#undef X + } + return(result); +} + +static String8 +dwarf_string_from_tag(DWARF_Tag tag){ + String8 result = str8_lit("unrecognized_tag"); + switch (tag){ +#define X(N,C) case C: result = str8_lit(#N); break; + DWARF_TagXList(X) +#undef X + } + return(result); +} + +static String8 +dwarf_string_from_attribute_name(DWARF_AttributeName name){ + String8 result = str8_lit("unrecognized_attribute_name"); + switch (name){ +#define X(N,C,f1,f2,f3,f4) case C: result = str8_lit(#N); break; + DWARF_AttributeNameXList(X) +#undef X + } + return(result); +} + +static String8 +dwarf_string_from_attribute_form(DWARF_AttributeForm form){ + String8 result = str8_lit("unrecognized_attribute_form"); + switch (form){ +#define X(N,C,k) case C: result = str8_lit(#N); break; + DWARF_AttributeFormXList(X) +#undef X + } + return(result); +} + +static String8 +dwarf_string_from_line_std_op(DWARF_LineStdOp op){ + String8 result = str8_lit("unrecognized_line_std_op"); + switch (op){ +#define X(N,C) case C: result = str8_lit(#N); break; + DWARF_LineStdOpXList(X) +#undef X + } + return(result); +} + +static String8 +dwarf_string_from_line_ext_op(DWARF_LineExtOp op){ + String8 result = str8_lit("unrecognized_line_ext_op"); + switch (op){ +#define X(N,C) case C: result = str8_lit(#N); break; + DWARF_LineExtOpXList(X) +#undef X + } + return(result); +} + +static String8 +dwarf_string_from_line_entry_format(DWARF_LineEntryFormat format){ + String8 result = str8_lit("unrecognized_line_entry_format"); + switch (format){ +#define X(N,C) case C: result = str8_lit(#N); break; + DWARF_LineEntryFormatXList(X) +#undef X + } + return(result); +} + +static String8 +dwarf_string_from_section_code(DWARF_SectionCode sec_code){ + String8 result = str8_lit("unrecognized_section_code"); + switch (sec_code){ +#define X(Nc,Vf,N0,N1,N2) case DWARF_SectionCode_##Nc: result = str8_lit(#Nc); break; + DWARF_SectionNameXList(X,0,0) +#undef X + } + return(result); +} + + + + + +#if 0 +static DWARF_InfoParsed* +dwarf_info_from_data(Arena *arena, String8 data, DWARF_InfoParams *params, + DWARF_AbbrevParsed *abbrev){ + + // unit index range to extract + U64 unit_idx_min = params->unit_idx_min; + U64 unit_idx_max = params->unit_idx_max; + + // empty unit list + DWARF_InfoUnit *unit_first = 0; + DWARF_InfoUnit *unit_last = 0; + U64 unit_count = 0; + B32 decoding_error = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + // early escape on unit idx + if (unit_idx > unit_idx_max){ + break; + } + + // determine whether to full parse this unit + B32 full_parse = (unit_idx_min <= unit_idx); + + // header fields + U8 *unit_opl = 0; + B32 is_64bit = 0; + U16 version = 0; + U64 abbrev_offset = 0; + U32 address_size = 0; + DWARF_UnitType unit_type = DWARF_UnitType_null; + U64 unit_dwo_id = 0; + U64 unit_type_signature = 0; + U64 unit_type_offset = 0; + + // initial length + dwarf__initial_length(&ptr, opl, &unit_opl, &is_64bit); + + // if this is not a full parse we may use + // unit_opl to skip to the next unit now + if (full_parse){ + + // version (part of header) + version = MemoryConsume(U16, ptr, unit_opl); + + // rest of header depends on version + switch (version){ + case 4: + { + // abbrev_offset (part of header) + if (is_64bit){ + abbrev_offset = MemoryConsume(U64, ptr, unit_opl); + } + else{ + abbrev_offset = MemoryConsume(U32, ptr, unit_opl); + } + + // address_size (part of header) + address_size = MemoryConsume(U8, ptr, unit_opl); + }break; + + case 5: + { + // unit_type (part of header) + unit_type = (DWARF_UnitType)MemoryConsume(U8, ptr, unit_opl); + + // address_size (part of header) + address_size = MemoryConsume(U8, ptr, unit_opl); + + // abbrev_offset (part of header) + if (is_64bit){ + abbrev_offset = MemoryConsume(U64, ptr, unit_opl); + } + else{ + abbrev_offset = MemoryConsume(U32, ptr, unit_opl); + } + + // rest of header depends on unit_type + switch (unit_type){ + case DWARF_UnitType_skeleton: + case DWARF_UnitType_split_compile: + { + unit_dwo_id = MemoryConsume(U64, ptr, unit_opl); + }break; + case DWARF_UnitType_type: + case DWARF_UnitType_split_type: + { + unit_type_signature = MemoryConsume(U64, ptr, unit_opl); + if (is_64bit){ + unit_type_offset = MemoryConsume(U64, ptr, unit_opl); + } + else{ + unit_type_offset = MemoryConsume(U32, ptr, unit_opl); + } + }break; + } + }break; + } + + // offset size + U32 offset_size = is_64bit?8:4; + + // find matching abbrev unit + DWARF_AbbrevUnit *abbrev_unit = dwarf_abbrev_unit_from_offset(abbrev, abbrev_offset); + if (abbrev_unit == 0){ + // TODO: preserve error info + decoding_error = 1; + } + + // consume info entries + DWARF_InfoEntry *entry_root = 0; + U64 entry_count = 0; + + DWARF_InfoEntry *entry_consptr = 0; + if (abbrev_unit != 0){ + for (;ptr < unit_opl;){ + B32 success = 1; + + // mark beginning of entry + U8 *entry_start_ptr = ptr; + + // extract abbrev code + U8 *abbrev_code_ptr = ptr; + DWARF_LEB128_ADV(ptr, unit_opl, success); + if (!success){ + // TODO: preserve error info + decoding_error = 1; + goto exit_unit_loop; + } + + U32 abbrev_code = dwarf_leb128_decode_U32(abbrev_code_ptr, ptr); + + // null abbrev code means pop + if (abbrev_code == 0){ + if (entry_consptr == 0){ + goto exit_unit_loop; + } + else{ + entry_consptr = entry_consptr->parent; + goto skip_entry; + } + } + + // get abbrev decl + DWARF_AbbrevDecl *abbrev_decl = dwarf_abbrev_decl_from_code(abbrev_unit, abbrev_code); + if (abbrev_decl == 0){ + // TODO: preserve error info + decoding_error = 1; + goto exit_unit_loop; + } + + // allocate entry + U32 attrib_count = abbrev_decl->attrib_count; + DWARF_InfoEntry *entry = push_array(arena, DWARF_InfoEntry, 1); + DWARF_InfoAttribVal *attrib_vals = + push_array_no_zero(arena, DWARF_InfoAttribVal, attrib_count); + + // save entry offset + entry->info_offset = (U64)(entry_start_ptr - data.str); + + // set root at beginning + if (entry_root == 0){ + entry_root = entry; + } + + // attribute loop + DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs; + DWARF_InfoAttribVal *attrib_val = attrib_vals; + for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){ + + // determine decoding rules + U32 size = 0; + B8 uleb128 = 0; + B8 sleb128 = 0; + B8 in_abbrev = 0; + B8 auto_1 = 0; + B8 block = 0; + B8 null_terminated = 0; + { + DWARF_AttributeForm form = attrib_spec->form; + switch (form){ + case DWARF_AttributeForm_addr: size = address_size; break; + case DWARF_AttributeForm_addrx: uleb128 = 1; break; + case DWARF_AttributeForm_addrx1: size = 1; break; + case DWARF_AttributeForm_addrx2: size = 2; break; + case DWARF_AttributeForm_addrx3: size = 3; break; + case DWARF_AttributeForm_addrx4: size = 4; break; + + case DWARF_AttributeForm_sec_offset: size = offset_size; break; + + case DWARF_AttributeForm_block1: size = 1; block = 1; break; + case DWARF_AttributeForm_block2: size = 2; block = 1; break; + case DWARF_AttributeForm_block4: size = 4; block = 1; break; + case DWARF_AttributeForm_block: uleb128 = 1; block = 1; break; + + case DWARF_AttributeForm_data1: size = 1; break; + case DWARF_AttributeForm_data2: size = 2; break; + case DWARF_AttributeForm_data4: size = 4; break; + case DWARF_AttributeForm_data8: size = 8; break; + case DWARF_AttributeForm_data16: size = 16; break; + + case DWARF_AttributeForm_sdata: sleb128 = 1; break; + case DWARF_AttributeForm_udata: uleb128 = 1; break; + + case DWARF_AttributeForm_implicit_const: in_abbrev = 1; break; + + case DWARF_AttributeForm_exprloc: uleb128 = 1; block = 1; break; + + case DWARF_AttributeForm_flag: size = 1; break; + case DWARF_AttributeForm_flag_present: auto_1 = 1; break; + + case DWARF_AttributeForm_loclistx: uleb128 = 1; break; + case DWARF_AttributeForm_rnglistx: uleb128 = 1; break; + + case DWARF_AttributeForm_ref1: size = 1; break; + case DWARF_AttributeForm_ref2: size = 2; break; + case DWARF_AttributeForm_ref4: size = 4; break; + case DWARF_AttributeForm_ref8: size = 8; break; + case DWARF_AttributeForm_ref_udata: uleb128 = 1; break; + + case DWARF_AttributeForm_ref_addr: size = offset_size; break; + + case DWARF_AttributeForm_ref_sig8: size = 8; break; + + case DWARF_AttributeForm_ref_sup4: size = 4; break; + case DWARF_AttributeForm_ref_sup8: size = 8; break; + + case DWARF_AttributeForm_string: null_terminated = 1; break; + + case DWARF_AttributeForm_strp: size = offset_size; break; + case DWARF_AttributeForm_line_strp: size = offset_size; break; + case DWARF_AttributeForm_strp_sup: size = offset_size; break; + + case DWARF_AttributeForm_strx: uleb128 = 1; break; + case DWARF_AttributeForm_strx1: size = 1; break; + case DWARF_AttributeForm_strx2: size = 2; break; + case DWARF_AttributeForm_strx3: size = 3; break; + case DWARF_AttributeForm_strx4: size = 4; break; + } + } + + // execute decoding rules + U64 val = 0; + U8 *dataptr = 0; + { + if (size > 0){ + if (ptr + size <= unit_opl){ + MemoryCopy(&val, ptr, size); + ptr += size; + } + else{ + // TODO: preserve error info + decoding_error = 1; + goto exit_unit_loop; + } + } + else if (uleb128 || sleb128){ + U8 *val_ptr = ptr; + DWARF_LEB128_ADV(ptr, unit_opl, success); + if (!success){ + // TODO: preserve error info + decoding_error = 1; + goto exit_unit_loop; + } + else{ + if (uleb128){ + val = dwarf_leb128_decode_U64(val_ptr, ptr); + } + else{ + val = (U64)dwarf_leb128_decode_S64(val_ptr, ptr); + } + } + } + else if (in_abbrev){ + if (abbrev_decl->implicit_const != 0){ + val = (U64)abbrev_decl->implicit_const[i]; + } + } + else if (auto_1){ + val = 1; + } + if (block){ + dataptr = ptr; + ptr += val; + } + else if (null_terminated){ + dataptr = ptr; + for (;ptr < unit_opl && *ptr != 0;) ptr += 1; + val = (U64)(ptr - dataptr); + } + } + + // save attribute + attrib_val->val = val; + attrib_val->dataptr = dataptr; + } + + // emit entry + if (entry_consptr != 0){ + SLLQueuePush_N(entry_consptr->first_child, entry_consptr->last_child, + entry, next_sibling); + entry_consptr->child_count += 1; + entry->parent = entry_consptr; + } + entry_count += 1; + entry->abbrev_decl = abbrev_decl; + entry->attrib_vals = attrib_vals; + + // move consptr down if has children + if (abbrev_decl->has_children){ + entry_consptr = entry; + } + + skip_entry:; + } + } + exit_unit_loop:; + + // TODO: notice errors, emit them, and exit loop here + if (decoding_error){ + break; + } + + // extract root attributes + U64 language = 0; + U64 str_offsets_base = 0; + U64 line_info_offset = 0; + U64 vbase = 0; + U64 addr_base = 0; + U64 rnglists_base = 0; + U64 loclists_base = 0; + if (entry_root != 0){ + + // pull out attributes + DWARF_AbbrevDecl *root_abbrev_decl = entry_root->abbrev_decl; + DWARF_AbbrevAttribSpec *attrib_specs = root_abbrev_decl->attrib_specs; + DWARF_InfoAttribVal *attrib_vals = entry_root->attrib_vals; + U32 attrib_count = root_abbrev_decl->attrib_count; + + // examine each attribute + DWARF_AbbrevAttribSpec *attrib_spec = attrib_specs; + DWARF_InfoAttribVal *attrib_val = attrib_vals; + for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){ + + // determine if there is a root attribute to extract here + U64 *target_u64 = 0; + switch (attrib_spec->name){ + case DWARF_AttributeName_language: target_u64 = &language; break; + case DWARF_AttributeName_str_offsets_base: target_u64 = &str_offsets_base; break; + case DWARF_AttributeName_stmt_list: target_u64 = &line_info_offset; break; + case DWARF_AttributeName_low_pc: target_u64 = &vbase; break; + case DWARF_AttributeName_addr_base: target_u64 = &addr_base; break; + case DWARF_AttributeName_rnglists_base: target_u64 = &rnglists_base; break; + case DWARF_AttributeName_loclists_base: target_u64 = &loclists_base; break; + } + + // set target from attrib value + if (target_u64 != 0){ + *target_u64 = attrib_val->val; + } + } + } + + // allocate unit + DWARF_InfoUnit *unit = push_array(arena, DWARF_InfoUnit, 1); + + // fill & emit unit + SLLQueuePush(unit_first, unit_last, unit); + unit_count += 1; + // [header] + unit->dwarf_version = version; + unit->offset_size = offset_size; + unit->address_size = address_size; + // [root attributes] + unit->language = (DWARF_Language)language; + unit->str_offsets_base = str_offsets_base; + unit->line_info_offset = line_info_offset; + unit->vbase = vbase; + unit->addr_base = addr_base; + unit->rnglists_base = rnglists_base; + unit->loclists_base = loclists_base; + // [entries] + unit->entry_root = entry_root; + unit->entry_count = entry_count; + + } + + // set ptr to end of this unit + ptr = unit_opl; + } + + // fill result + DWARF_InfoParsed *result = push_array(arena, DWARF_InfoParsed, 1); + result->unit_first = unit_first; + result->unit_last = unit_last; + result->unit_count = unit_count; + result->decoding_error = decoding_error; + return(result); +} + +static DWARF_AbbrevParsed* +dwarf_abbrev_from_data(Arena *arena, String8 data, DWARF_AbbrevParams *params){ + /* .debug_abbrev + ** Layout + ** List(Tag) + ** Tag = { id:ULEB128, tag:ULEB128, has_children:B8, ListNullTerminated(Attribute) } + ** Attribute = { name:ULEB128, form:ULEB128, (val:SLEB128)? } + */ + + // unit index range to extract + U64 unit_idx_min = params->unit_idx_min; + U64 unit_idx_max = params->unit_idx_max; + + // empty unit list + DWARF_AbbrevUnit *unit_first = 0; + DWARF_AbbrevUnit *unit_last = 0; + U64 unit_count = 0; + B32 decoding_error = 0; + + // whole section loop + U64 unit_idx = 0; + U8 *ptr = data.str; + U8 *opl = data.str + data.size; + for (;ptr < opl; unit_idx += 1){ + + // early escape on unit idx + if (unit_idx > unit_idx_max){ + break; + } + + // determine whether to full parse this unit + B32 full_parse = (unit_idx_min <= unit_idx); + + // save unit offset + U64 abbrev_unit_offset = (U64)(ptr - data.str); + + // allocate unit + DWARF_AbbrevUnit *unit = push_array(arena, DWARF_AbbrevUnit, 1); + + // empty abbrev list + DWARF_AbbrevDecl *abbrev_first = 0; + DWARF_AbbrevDecl *abbrev_last = 0; + U64 abbrev_count = 0; + + // abbrev decl loop + for (;ptr < opl;){ + B32 success = 1; + + // mark abbrev_code field + U8 *abbrev_code_ptr = ptr; + DWARF_LEB128_ADV(ptr, opl, success); + + // null abbrev code means end of unit + if (success && *abbrev_code_ptr == 0){ + break; + } + + // mark tag + U8 *tag_ptr = ptr; + DWARF_LEB128_ADV(ptr, opl, success); + U8 *end_tag_ptr = ptr; + + // extract has_children + B8 has_children = 0; + if (ptr < opl){ + has_children = *ptr; + ptr += 1; + } + else{ + success = 0; + } + + // count attributes + U8 *attrib_start_ptr = ptr; + U32 attrib_count = 0; + B32 has_implicit_const = 0; + if (success){ + for (;;){ + // decode normal attribute layout + U8 *attrib_name = ptr; + DWARF_LEB128_ADV(ptr, opl, success); + U8 *attrib_form = ptr; + DWARF_LEB128_ADV(ptr, opl, success); + + // handle special case implicit_const + if (success && *attrib_form == (U8)DWARF_AttributeForm_implicit_const){ + DWARF_LEB128_ADV(ptr, opl, success); + has_implicit_const = 1; + } + + // termination conditions + if (ptr == opl || + (*attrib_name == 0 && *attrib_form == 0)){ + break; + } + + // increment + attrib_count += 1; + } + } + + // build the abbreviation declaration + if (full_parse && success){ + + // allocate abbrev + DWARF_AbbrevDecl *abbrev = push_array(arena, DWARF_AbbrevDecl, 1); + DWARF_AbbrevAttribSpec *attribs = + push_array_no_zero(arena, DWARF_AbbrevAttribSpec, attrib_count); + U64 *implicit_const = 0; + if (has_implicit_const){ + implicit_const = push_array(arena, U64, attrib_count); + } + + // extract abbrev fields + U32 abbrev_code = dwarf_leb128_decode_U32(abbrev_code_ptr, tag_ptr); + U32 tag = dwarf_leb128_decode_U32(tag_ptr, end_tag_ptr); + + U8 *attrib_ptr = attrib_start_ptr; + DWARF_AbbrevAttribSpec *attrib = attribs; + for (U32 i = 0; i < attrib_count; i += 1, attrib += 1){ + // mark attribute fields + U8 *attrib_name = attrib_ptr; + DWARF_LEB128_ADV_NOCAP(attrib_ptr); + U8 *attrib_form = attrib_ptr; + DWARF_LEB128_ADV_NOCAP(attrib_ptr); + + // extract attribute fields + U32 name = dwarf_leb128_decode_U32(attrib_name, attrib_form); + U32 form = dwarf_leb128_decode_U32(attrib_form, attrib_ptr); + + // fill attribute spec + attrib->name = (DWARF_AttributeName)name; + attrib->form = (DWARF_AttributeForm)form; + + // handle special case implicit_const + if (form == DWARF_AttributeForm_implicit_const){ + U8 *attrib_value = attrib_ptr; + DWARF_LEB128_ADV_NOCAP(attrib_ptr); + S64 value = dwarf_leb128_decode_S64(attrib_form, attrib_ptr); + implicit_const[i] = value; + } + } + + // fill abbreviation + SLLQueuePush(abbrev_first, abbrev_last, abbrev); + abbrev_count += 1; + abbrev->abbrev_code = abbrev_code; + abbrev->tag = (DWARF_Tag)tag; + abbrev->has_children = has_children; + abbrev->attrib_count = attrib_count; + abbrev->attrib_specs = attribs; + abbrev->implicit_const = implicit_const; + } + + // handle failure + if (!success){ + // TODO: emit error message + decoding_error = 1; + goto done_parse; + } + } + + // fill unit + if (full_parse){ + SLLQueuePush(unit_first, unit_last, unit); + unit_count += 1; + unit->offset = abbrev_unit_offset; + unit->first = abbrev_first; + unit->last = abbrev_last; + unit->count = abbrev_count; + } + } + + done_parse:; + + // fill result + DWARF_AbbrevParsed *result = push_array(arena, DWARF_AbbrevParsed, 1); + result->unit_first = unit_first; + result->unit_last = unit_last; + result->unit_count = unit_count; + result->decoding_error = decoding_error; + return(result); +} +#endif diff --git a/src/raddbg_convert/dwarf/raddbg_dwarf.h b/src/raddbg_convert/dwarf/raddbg_dwarf.h new file mode 100644 index 00000000..f9927685 --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_dwarf.h @@ -0,0 +1,1332 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_DWARF_H +#define RADDBG_DWARF_H + +// https://dwarfstd.org/doc/DWARF4.pdf +// https://dwarfstd.org/doc/DWARF5.pdf + +// TODO(allen): +// [ ] function to parse info just for unit headers & root attributes +// [ ] put together unit info from all sections in one structure +// [ ] actually check version numbers in unit header parsers + +#pragma pack(push,1) + +//////////////////////////////// +//~ Dwarf Format Code X Lists + +// unit type X(name, code) +#define DWARF_UnitTypeXList(X)\ +X(null, 0x00)\ +X(compile, 0x01)\ +X(type, 0x02)\ +X(partial, 0x03)\ +X(skeleton, 0x04)\ +X(split_compile, 0x05)\ +X(split_type, 0x06)\ +X(lo_user, 0x80)\ +X(hi_user, 0xff) + +typedef enum DWARF_UnitType{ +#define X(N,C) DWARF_UnitType_##N = C, + DWARF_UnitTypeXList(X) +#undef X +} DWARF_UnitType; + + +// tag X(name, code) +#define DWARF_TagXList(X)\ +X(null, 0x00)\ +X(array_type, 0x01)\ +X(class_type, 0x02)\ +X(entry_point, 0x03)\ +X(enumeration_type, 0x04)\ +X(formal_parameter, 0x05)\ +X(imported_declaration, 0x08)\ +X(label, 0x0a)\ +X(lexical_block, 0x0b)\ +X(member, 0x0d)\ +X(pointer_type, 0x0f)\ +X(reference_type, 0x10)\ +X(compile_unit, 0x11)\ +X(string_type, 0x12)\ +X(structure_type, 0x13)\ +X(subroutine_type, 0x15)\ +X(typedef, 0x16)\ +X(union_type, 0x17)\ +X(unspecified_parameters, 0x18)\ +X(variant, 0x19)\ +X(common_block, 0x1a)\ +X(common_inclusion, 0x1b)\ +X(inheritance, 0x1c)\ +X(inlined_subroutine, 0x1d)\ +X(module, 0x1e)\ +X(ptr_to_member_type, 0x1f)\ +X(set_type, 0x20)\ +X(subrange_type, 0x21)\ +X(with_stmt, 0x22)\ +X(access_declaration, 0x23)\ +X(base_type, 0x24)\ +X(catch_block, 0x25)\ +X(const_type, 0x26)\ +X(constant, 0x27)\ +X(enumerator, 0x28)\ +X(file_type, 0x29)\ +X(friend, 0x2a)\ +X(namelist, 0x2b)\ +X(namelist_item, 0x2c)\ +X(packed_type, 0x2d)\ +X(subprogram, 0x2e)\ +X(template_type_parameter, 0x2f)\ +X(template_value_parameter, 0x30)\ +X(thrown_type, 0x31)\ +X(try_block, 0x32)\ +X(variant_part, 0x33)\ +X(variable, 0x34)\ +X(volatile_type, 0x35)\ +X(dwarf_procedure, 0x36)\ +X(restrict_type, 0x37)\ +X(interface_type, 0x38)\ +X(namespace, 0x39)\ +X(imported_module, 0x3a)\ +X(unspecified_type, 0x3b)\ +X(partial_unit, 0x3c)\ +X(imported_unit, 0x3d)\ +X(condition, 0x3f)\ +X(shared_type, 0x40)\ +X(type_unit, 0x41)\ +X(rvalue_reference_type, 0x42)\ +X(template_alias, 0x43)\ +X(coarray_type, 0x44)\ +X(generic_subrange, 0x45)\ +X(dynamic_type, 0x46)\ +X(atomic_type, 0x47)\ +X(call_site, 0x48)\ +X(call_site_parameter, 0x49)\ +X(skeleton_unit, 0x4a)\ +X(immutable_type, 0x4b)\ +X(lo_user, 0x4080)\ +X(hi_user, 0xffff) + +typedef enum DWARF_Tag{ +#define X(N,C) DWARF_Tag_##N = C, + DWARF_TagXList(X) +#undef X +} DWARF_Tag; + + +// attribute classes: X(name,code) +#define DWARF_AttributeClassXList(X)\ +X(address, 0)\ +X(addrptr, 1)\ +X(block, 2)\ +X(constant, 3)\ +X(exprloc, 4)\ +X(flag, 5)\ +X(lineptr, 6)\ +X(loclist, 7)\ +X(loclistsptr, 8)\ +X(macptr, 9)\ +X(reference, 10)\ +X(rnglist, 11)\ +X(rnglistsptr, 12)\ +X(string, 13)\ +X(stroffsetsptr, 14) + +typedef U32 DWARF_AttributeClassFlags; +enum{ +#define X(N,C) DWARF_AttributeClassFlag_##N = (1 << C), + DWARF_AttributeClassXList(X) +#undef X + + DWARF_AttributeClassFlag_0 = 0, + DWARF_AttributeClassFlag_specialcase = ~0, + DWARF_AttributeClassFlag_sec_offset_classes = + (DWARF_AttributeClassFlag_addrptr | + DWARF_AttributeClassFlag_lineptr | + DWARF_AttributeClassFlag_loclist | + DWARF_AttributeClassFlag_loclistsptr | + DWARF_AttributeClassFlag_macptr | + DWARF_AttributeClassFlag_rnglist | + DWARF_AttributeClassFlag_rnglistsptr | + DWARF_AttributeClassFlag_stroffsetsptr | + 0), + +}; + + +// attribute name: X(name, code, classflag1, classflag2, classflag3, classflag4) +#define DWARF_AttributeNameXList(X)\ +X(null, 0x00, 0, 0, 0, 0)\ +X(sibling, 0x01, reference, 0, 0, 0)\ +X(location, 0x02, exprloc, loclist, 0, 0)\ +X(name, 0x03, string, 0, 0, 0)\ +X(ordering, 0x09, constant, 0, 0, 0)\ +X(byte_size, 0x0b, constant, exprloc, reference, 0)\ +X(bit_size, 0x0d, constant, exprloc, reference, 0)\ +X(stmt_list, 0x10, lineptr, 0, 0, 0)\ +X(low_pc, 0x11, address, 0, 0, 0)\ +X(high_pc, 0x12, address, constant, 0, 0)\ +X(language, 0x13, constant, 0, 0, 0)\ +X(discr, 0x15, reference, 0, 0, 0)\ +X(discr_value, 0x16, constant, 0, 0, 0)\ +X(visibility, 0x17, constant, 0, 0, 0)\ +X(import, 0x18, reference, 0, 0, 0)\ +X(string_length, 0x19, exprloc, loclist, reference, 0)\ +X(common_reference, 0x1a, reference, 0, 0, 0)\ +X(comp_dir, 0x1b, string, 0, 0, 0)\ +X(const_value, 0x1c, block, constant, string, 0)\ +X(containing_type, 0x1d, reference, 0, 0, 0)\ +X(default_value, 0x1e, constant, reference, flag, 0)\ +X(inline, 0x20, constant, 0, 0, 0)\ +X(is_optional, 0x21, flag, 0, 0, 0)\ +X(lower_bound, 0x22, constant, exprloc, reference, 0)\ +X(producer, 0x25, string, 0, 0, 0)\ +X(prototyped, 0x27, flag, 0, 0, 0)\ +X(return_addr, 0x2a, exprloc, loclist, 0, 0)\ +X(start_scope, 0x2c, constant, rnglist, 0, 0)\ +X(bit_stride, 0x2e, constant, exprloc, reference, 0)\ +X(upper_bound, 0x2f, constant, exprloc, reference, 0)\ +X(abstract_origin, 0x31, reference, 0, 0, 0)\ +X(accessibility, 0x32, constant, 0, 0, 0)\ +X(address_class, 0x33, constant, 0, 0, 0)\ +X(artificial, 0x34, flag, 0, 0, 0)\ +X(base_types, 0x35, reference, 0, 0, 0)\ +X(calling_convention, 0x36, constant, 0, 0, 0)\ +X(count, 0x37, constant, exprloc, reference, 0)\ +X(data_member_location, 0x38, constant, exprloc, loclist, 0)\ +X(decl_column, 0x39, constant, 0, 0, 0)\ +X(decl_file, 0x3a, constant, 0, 0, 0)\ +X(decl_line, 0x3b, constant, 0, 0, 0)\ +X(declaration, 0x3c, flag, 0, 0, 0)\ +X(discr_list, 0x3d, block, 0, 0, 0)\ +X(encoding, 0x3e, constant, 0, 0, 0)\ +X(external, 0x3f, flag, 0, 0, 0)\ +X(frame_base, 0x40, exprloc, loclist, 0, 0)\ +X(friend, 0x41, reference, 0, 0, 0)\ +X(identifier_case, 0x42, constant, 0, 0, 0)\ +X(namelist_item, 0x44, reference, 0, 0, 0)\ +X(priority, 0x45, reference, 0, 0, 0)\ +X(segment, 0x46, exprloc, loclist, 0, 0)\ +X(specification, 0x47, reference, 0, 0, 0)\ +X(static_link, 0x48, exprloc, loclist, 0, 0)\ +X(type, 0x49, reference, 0, 0, 0)\ +X(use_location, 0x4a, exprloc, loclist, 0, 0)\ +X(variable_parameter, 0x4b, flag, 0, 0, 0)\ +X(virtuality, 0x4c, constant, 0, 0, 0)\ +X(vtable_elem_location, 0x4d, exprloc, loclist, 0, 0)\ +X(allocated, 0x4e, constant, exprloc, reference, 0)\ +X(associated, 0x4f, constant, exprloc, reference, 0)\ +X(data_location, 0x50, exprloc, 0, 0, 0)\ +X(byte_stride, 0x51, constant, exprloc, reference, 0)\ +X(entry_pc, 0x52, address, constant, 0, 0)\ +X(use_UTF8, 0x53, flag, 0, 0, 0)\ +X(extension, 0x54, reference, 0, 0, 0)\ +X(ranges, 0x55, rnglist, 0, 0, 0)\ +X(trampoline, 0x56, address, flag, reference, string)\ +X(call_column, 0x57, constant, 0, 0, 0)\ +X(call_file, 0x58, constant, 0, 0, 0)\ +X(call_line, 0x59, constant, 0, 0, 0)\ +X(description, 0x5a, string, 0, 0, 0)\ +X(binary_scale, 0x5b, constant, 0, 0, 0)\ +X(decimal_scale, 0x5c, constant, 0, 0, 0)\ +X(small, 0x5d, reference, 0, 0, 0)\ +X(decimal_sign, 0x5e, constant, 0, 0, 0)\ +X(digit_count, 0x5f, constant, 0, 0, 0)\ +X(picture_string, 0x60, string, 0, 0, 0)\ +X(mutable, 0x61, flag, 0, 0, 0)\ +X(threads_scaled, 0x62, flag, 0, 0, 0)\ +X(explicit, 0x63, flag, 0, 0, 0)\ +X(object_pointer, 0x64, reference, 0, 0, 0)\ +X(endianity, 0x65, constant, 0, 0, 0)\ +X(elemental, 0x66, flag, 0, 0, 0)\ +X(pure, 0x67, flag, 0, 0, 0)\ +X(recursive, 0x68, flag, 0, 0, 0)\ +X(signature, 0x69, reference, 0, 0, 0)\ +X(main_subprogram, 0x6a, flag, 0, 0, 0)\ +X(data_bit_offset, 0x6b, constant, 0, 0, 0)\ +X(const_expr, 0x6c, flag, 0, 0, 0)\ +X(enum_class, 0x6d, flag, 0, 0, 0)\ +X(linkage_name, 0x6e, string, 0, 0, 0)\ +X(string_length_bit_size, 0x6f, constant, 0, 0, 0)\ +X(string_length_byte_size, 0x70, constant, 0, 0, 0)\ +X(rank, 0x71, constant, exprloc, 0, 0)\ +X(str_offsets_base, 0x72, stroffsetsptr, 0, 0, 0)\ +X(addr_base, 0x73, addrptr, 0, 0, 0)\ +X(rnglists_base, 0x74, rnglistsptr, 0, 0, 0)\ +X(dwo_name, 0x76, string, 0, 0, 0)\ +X(reference, 0x77, flag, 0, 0, 0)\ +X(rvalue_reference, 0x78, flag, 0, 0, 0)\ +X(macros, 0x79, macptr, 0, 0, 0)\ +X(call_all_calls, 0x7a, flag, 0, 0, 0)\ +X(call_all_source_calls, 0x7b, flag, 0, 0, 0)\ +X(call_all_tail_calls, 0x7c, flag, 0, 0, 0)\ +X(call_return_pc, 0x7d, address, 0, 0, 0)\ +X(call_value, 0x7e, exprloc, 0, 0, 0)\ +X(call_origin, 0x7f, exprloc, 0, 0, 0)\ +X(call_parameter, 0x80, reference, 0, 0, 0)\ +X(call_pc, 0x81, address, 0, 0, 0)\ +X(call_tail_call, 0x82, flag, 0, 0, 0)\ +X(call_target, 0x83, exprloc, 0, 0, 0)\ +X(call_target_clobbered, 0x84, exprloc, 0, 0, 0)\ +X(call_data_location, 0x85, exprloc, 0, 0, 0)\ +X(call_data_value, 0x86, exprloc, 0, 0, 0)\ +X(noreturn, 0x87, flag, 0, 0, 0)\ +X(alignment, 0x88, constant, 0, 0, 0)\ +X(export_symbols, 0x89, flag, 0, 0, 0)\ +X(deleted, 0x8a, flag, 0, 0, 0)\ +X(defaulted, 0x8b, constant, 0, 0, 0)\ +X(loclists_base, 0x8c, loclistsptr, 0, 0, 0)\ +X(lo_user, 0x2000, 0, 0, 0, 0)\ +X(hi_user, 0x3fff, 0, 0, 0, 0) + +typedef enum DWARF_AttributeName{ +#define X(N,C,f1,f2,f3,f4) DWARF_AttributeName_##N = C, + DWARF_AttributeNameXList(X) +#undef X +} DWARF_AttributeName; + + +// attribute forms: X(name, code, classflag) +#define DWARF_AttributeFormXList(X)\ +X(null, 0x00, 0)\ +X(addr, 0x01, address)\ +X(block2, 0x03, block)\ +X(block4, 0x04, block)\ +X(data2, 0x05, constant)\ +X(data4, 0x06, constant)\ +X(data8, 0x07, constant)\ +X(string, 0x08, string)\ +X(block, 0x09, block)\ +X(block1, 0x0a, block)\ +X(data1, 0x0b, constant)\ +X(flag, 0x0c, flag)\ +X(sdata, 0x0d, constant)\ +X(strp, 0x0e, string)\ +X(udata, 0x0f, constant)\ +X(ref_addr, 0x10, reference)\ +X(ref1, 0x11, reference)\ +X(ref2, 0x12, reference)\ +X(ref4, 0x13, reference)\ +X(ref8, 0x14, reference)\ +X(ref_udata, 0x15, reference)\ +X(indirect, 0x16, specialcase)\ +X(sec_offset, 0x17, sec_offset_classes)\ +X(exprloc, 0x18, exprloc)\ +X(flag_present, 0x19, flag)\ +X(strx, 0x1a, string)\ +X(addrx, 0x1b, address)\ +X(ref_sup4, 0x1c, reference)\ +X(strp_sup, 0x1d, string)\ +X(data16, 0x1e, constant)\ +X(line_strp, 0x1f, string)\ +X(ref_sig8, 0x20, reference)\ +X(implicit_const, 0x21, specialcase)\ +X(loclistx, 0x22, loclist)\ +X(rnglistx, 0x23, rnglist)\ +X(ref_sup8, 0x24, reference)\ +X(strx1, 0x25, string)\ +X(strx2, 0x26, string)\ +X(strx3, 0x27, string)\ +X(strx4, 0x28, string)\ +X(addrx1, 0x29, address)\ +X(addrx2, 0x2a, address)\ +X(addrx3, 0x2b, address)\ +X(addrx4, 0x2c, address) + +typedef enum DWARF_AttributeForm{ +#define X(N,C,f) DWARF_AttributeForm_##N = C, + DWARF_AttributeFormXList(X) +#undef X +} DWARF_AttributeForm; + + +// ops: X(name, code, opnum) +#define DWARF_OpXList(X)\ +X(addr, 0x03, 1)\ +X(deref, 0x06, 0)\ +X(const1u, 0x08, 1)\ +X(const1s, 0x09, 1)\ +X(const2u, 0x0a, 1)\ +X(const2s, 0x0b, 1)\ +X(const4u, 0x0c, 1)\ +X(const4s, 0x0d, 1)\ +X(const8u, 0x0e, 1)\ +X(const8s, 0x0f, 1)\ +X(constu, 0x10, 1)\ +X(consts, 0x11, 1)\ +X(dup, 0x12, 0)\ +X(drop, 0x13, 0)\ +X(over, 0x14, 0)\ +X(pick, 0x15, 1)\ +X(swap, 0x16, 0)\ +X(rot, 0x17, 0)\ +X(xderef, 0x18, 0)\ +X(abs, 0x19, 0)\ +X(and, 0x1a, 0)\ +X(div, 0x1b, 0)\ +X(minus, 0x1c, 0)\ +X(mod, 0x1d, 0)\ +X(mul, 0x1e, 0)\ +X(neg, 0x1f, 0)\ +X(not, 0x20, 0)\ +X(or, 0x21, 0)\ +X(plus, 0x22, 0)\ +X(plus_uconst, 0x23, 1)\ +X(shl, 0x24, 0)\ +X(shr, 0x25, 0)\ +X(shra, 0x26, 0)\ +X(xor, 0x27, 0)\ +X(bra, 0x28, 1)\ +X(eq, 0x29, 0)\ +X(ge, 0x2a, 0)\ +X(gt, 0x2b, 0)\ +X(le, 0x2c, 0)\ +X(lt, 0x2d, 0)\ +X(ne, 0x2e, 0)\ +X(skip, 0x2f, 1)\ +X(lit0, 0x30, 0)\ +X(lit1, 0x31, 0)\ +X(lit31, 0x4f, 0)\ +X(reg0, 0x50, 0)\ +X(reg1, 0x51, 0)\ +X(reg31, 0x6f, 0)\ +X(breg0, 0x70, 1)\ +X(breg1, 0x71, 1)\ +X(breg31, 0x8f, 1)\ +X(regx, 0x90, 1)\ +X(fbreg, 0x91, 1)\ +X(bregx, 0x92, 2)\ +X(piece, 0x93, 1)\ +X(deref_size, 0x94, 1)\ +X(xderef_size, 0x95, 1)\ +X(nop, 0x96, 0)\ +X(push_object_address, 0x97, 0)\ +X(call2, 0x98, 1)\ +X(call4, 0x99, 1)\ +X(call_ref, 0x9a, 1)\ +X(form_tls_address, 0x9b, 0)\ +X(call_frame_cfa, 0x9c, 0)\ +X(bit_piece, 0x9d, 2)\ +X(implicit_value, 0x9e, 2)\ +X(stack_value, 0x9f, 0)\ +X(implicit_pointer, 0xa0, 2)\ +X(addrx, 0xa1, 1)\ +X(constx, 0xa2, 1)\ +X(entry_value, 0xa3, 2)\ +X(const_type, 0xa4, 3)\ +X(regval_type, 0xa5, 2)\ +X(deref_type, 0xa6, 2)\ +X(xderef_type, 0xa7, 2)\ +X(convert, 0xa8, 1)\ +X(reinterpret, 0xa9, 1)\ +X(lo_user, 0xe0, 0)\ +X(hi_user, 0xff, 0) + +typedef enum DWARF_Op{ +#define X(N,C,k) DWARF_Op_##N = C, + DWARF_OpXList(X) +#undef X +} DWARF_Op; + + +// location list entry: X(name, code) +#define DWARF_LocationListEntryXList(X)\ +X(end_of_list, 0x00)\ +X(base_addressx, 0x01)\ +X(startx_endx, 0x02)\ +X(startx_length, 0x03)\ +X(offset_pair, 0x04)\ +X(default_location, 0x05)\ +X(base_address, 0x06)\ +X(start_end, 0x07)\ +X(start_length, 0x08) + +typedef enum DWARF_LocationListEntry{ +#define X(N,C) DWARF_LocationListEntry_##N = C, + DWARF_LocationListEntryXList(X) +#undef X +} DWARF_LocationListEntry; + + +// base type: X(name, code) +#define DWARF_BaseTypeXList(X)\ +X(address, 0x01)\ +X(boolean, 0x02)\ +X(complex_float, 0x03)\ +X(float, 0x04)\ +X(signed, 0x05)\ +X(signed_char, 0x06)\ +X(unsigned, 0x07)\ +X(unsigned_char, 0x08)\ +X(imaginary_float, 0x09)\ +X(packed_decimal, 0x0a)\ +X(numeric_string, 0x0b)\ +X(edited, 0x0c)\ +X(signed_fixed, 0x0d)\ +X(unsigned_fixed, 0x0e)\ +X(decimal_float, 0x0f)\ +X(UTF, 0x10)\ +X(UCS, 0x11)\ +X(ASCII, 0x12)\ +X(lo_user, 0x80)\ +X(hi_user, 0xff) + +typedef enum DWARF_BaseType{ +#define X(N,C) DWARF_BaseType_##N = C, + DWARF_BaseTypeXList(X) +#undef X +} DWARF_BaseType; + + +// decimal sign: X(name, code) +#define DWARF_DecimalSignXList(X)\ +X(unsigned, 0x01)\ +X(leading_overpunch, 0x02)\ +X(trailing_overpunch, 0x03)\ +X(leading_separate, 0x04)\ +X(trailing_separate, 0x05) + +typedef enum DWARF_DecimalSign{ +#define X(N,C) DWARF_DecimalSign_##N = C, + DWARF_DecimalSignXList(X) +#undef X +} DWARF_DecimalSign; + + +// endianity: X(name, code) +#define DWARF_EndianityXList(X)\ +X(default, 0x00)\ +X(big, 0x01)\ +X(little, 0x02)\ +X(lo_user, 0x40)\ +X(hi_user, 0xff) + +typedef enum DWARF_Endianity{ +#define X(N,C) DWARF_Endianity_##N = C, + DWARF_EndianityXList(X) +#undef X +} DWARF_Endianity; + + +// access: X(name, code) +#define DWARF_AccessXList(X)\ +X(public, 0x01)\ +X(protected, 0x02)\ +X(private, 0x03) + +typedef enum DWARF_Access{ +#define X(N,C) DWARF_Access_##N = C, + DWARF_AccessXList(X) +#undef X +} DWARF_Access; + + +// visibility: X(name, code) +#define DWARF_VisibilityXList(X)\ +X(local, 0x01)\ +X(exported, 0x02)\ +X(qualified, 0x03) + +typedef enum DWARF_Visibility{ +#define X(N,C) DWARF_Visibility_##N = C, + DWARF_VisibilityXList(X) +#undef X +} DWARF_Visibility; + + +// virtuality: X(name, code) +#define DWARF_VirtualityXList(X)\ +X(none, 0x00)\ +X(virtual, 0x01)\ +X(pure_virtual, 0x02) + +typedef enum DWARF_Virtuality{ +#define X(N,C) DWARF_Virtuality_##N = C, + DWARF_VirtualityXList(X) +#undef X +} DWARF_Virtuality; + + +// language: X(name, code, deflowerbound) +#define DWARF_LanguageXList(X)\ +X(C89, 0x0001, 0)\ +X(C, 0x0002, 0)\ +X(Ada83, 0x0003, 1)\ +X(C_plus_plus, 0x0004, 0)\ +X(Cobol74, 0x0005, 1)\ +X(Cobol85, 0x0006, 1)\ +X(Fortran77, 0x0007, 1)\ +X(Fortran90, 0x0008, 1)\ +X(Pascal83, 0x0009, 1)\ +X(Modula2, 0x000a, 1)\ +X(Java, 0x000b, 0)\ +X(C99, 0x000c, 0)\ +X(Ada95, 0x000d, 1)\ +X(Fortran95, 0x000e, 1)\ +X(PLI, 0x000f, 1)\ +X(ObjC, 0x0010, 0)\ +X(ObjC_plus_plus, 0x0011, 0)\ +X(UPC, 0x0012, 0)\ +X(D, 0x0013, 0)\ +X(Python, 0x0014, 0)\ +X(OpenCL, 0x0015, 0)\ +X(Go, 0x0016, 0)\ +X(Modula3, 0x0017, 1)\ +X(Haskell, 0x0018, 0)\ +X(C_plus_plus_03, 0x0019, 0)\ +X(C_plus_plus_11, 0x001a, 0)\ +X(OCaml, 0x001b, 0)\ +X(Rust, 0x001c, 0)\ +X(C11, 0x001d, 0)\ +X(Swift, 0x001e, 0)\ +X(Julia, 0x001f, 1)\ +X(Dylan, 0x0020, 0)\ +X(C_plus_plus_14, 0x0021, 0)\ +X(Fortran03, 0x0022, 1)\ +X(Fortran08, 0x0023, 1)\ +X(RenderScript, 0x0024, 0)\ +X(BLISS, 0x0025, 0)\ +X(lo_user, 0x8000, 0)\ +X(hi_user, 0xffff, 0) + +typedef enum DWARF_Language{ +#define X(N,C,k) DWARF_Language_##N = C, + DWARF_LanguageXList(X) +#undef X +} DWARF_Language; + + +// identifier case: X(name, code) +#define DWARF_IdentifierCaseXList(X)\ +X(case_sensitive, 0x00)\ +X(up_case, 0x01)\ +X(down_case, 0x02)\ +X(case_insensitive, 0x03) + +typedef enum DWARF_IdentifierCase{ +#define X(N,C) DWARF_IdentifierCase_##N = C, + DWARF_IdentifierCaseXList(X) +#undef X +} DWARF_IdentifierCase; + + +// calling convention: X(name, code) +#define DWARF_CallingConventionXList(X)\ +X(normal, 0x01)\ +X(program, 0x02)\ +X(nocall, 0x03)\ +X(pass_by_reference, 0x04)\ +X(pass_by_value, 0x05)\ +X(lo_user, 0x40)\ +X(hi_user, 0xff) + +typedef enum DWARF_CallingConvention{ +#define X(N,C) DWARF_CallingConvention_##N = C, + DWARF_CallingConventionXList(X) +#undef X +} DWARF_CallingConvention; + + +// inline: X(name, code) +#define DWARF_InlineXList(X)\ +X(not_inlined, 0x00)\ +X(inlined, 0x01)\ +X(declared_not_inlined, 0x02)\ +X(declared_inlined, 0x03) + +typedef enum DWARF_Inline{ +#define X(N,C) DWARF_Inline_##N = C, + DWARF_InlineXList(X) +#undef X +} DWARF_Inline; + + +// array ordering: X(name, code) +#define DWARF_ArrayOrderingXList(X)\ +X(row_major, 0x00)\ +X(col_major, 0x01) + +typedef enum DWARF_ArrayOrdering{ +#define X(N,C) DWARF_ArrayOrdering_##N = C, + DWARF_ArrayOrderingXList(X) +#undef X +} DWARF_ArrayOrdering; + + +// discriminant: X(name, code) +#define DWARF_DiscriminantXList(X)\ +X(label, 0x00)\ +X(range, 0x01) + +typedef enum DWARF_Discriminant{ +#define X(N,C) DWARF_Discriminant_##N = C, + DWARF_DiscriminantXList(X) +#undef X +} DWARF_Discriminant; + + +// name index: X(name, code) +#define DWARF_NameIndexXList(X)\ +X(compile_unit, 1)\ +X(type_unit, 2)\ +X(die_offset, 3)\ +X(parent, 4)\ +X(type_hash, 5)\ +X(lo_user, 0x2000)\ +X(hi_user, 0x3fff) + +typedef enum DWARF_NameIndex{ +#define X(N,C) DWARF_NameIndex_##N = C, + DWARF_NameIndexXList(X) +#undef X +} DWARF_NameIndex; + + +// defaulted: X(name, code) +#define DWARF_DefaultedXList(X)\ +X(no, 0x00)\ +X(in_class, 0x01)\ +X(out_of_class, 0x02) + +typedef enum DWARF_Defaulted{ +#define X(N,C) DWARF_Defaulted_##N = C, + DWARF_DefaultedXList(X) +#undef X +} DWARF_Defaulted; + +// call frame instruction: X(N, hi2bits, matchlow, low6bits, operand1, operand2) +// "CFA" +#define DWARF_CallFrameInsnXList(X)\ +X(advance_loc, 0x1, 0, 0, NULL, NULL)\ +X(offset, 0x2, 0, 0, ULEB, NULL)\ +X(restore, 0x3, 0, 0, NULL, NULL)\ +X(nop, 0x0, 1, 0, NULL, NULL)\ +X(set_loc, 0x0, 1, 0x01, ADDRESS, NULL)\ +X(advance_loc1, 0x0, 1, 0x02, 1BYTE, NULL)\ +X(advance_loc2, 0x0, 1, 0x03, 2BYTE, NULL)\ +X(advance_loc4, 0x0, 1, 0x04, 4BYTE, NULL)\ +X(offset_extended, 0x0, 1, 0x05, ULEB, ULEB)\ +X(restore_extended, 0x0, 1, 0x06, ULEB, NULL)\ +X(undefined, 0x0, 1, 0x07, ULEB, NULL)\ +X(same_value, 0x0, 1, 0x08, ULEB, NULL)\ +X(register, 0x0, 1, 0x09, ULEB, ULEB)\ +X(remember_state, 0x0, 1, 0x0a, NULL, NULL)\ +X(restore_state, 0x0, 1, 0x0b, NULL, NULL)\ +X(def_cfa, 0x0, 1, 0x0c, ULEB, ULEB)\ +X(def_cfa_register, 0x0, 1, 0x0d, ULEB, NULL)\ +X(def_cfa_offset, 0x0, 1, 0x0e, ULEB, NULL)\ +X(def_cfa_expression,0x0, 1, 0x0f, BLOCK, NULL)\ +X(expression, 0x0, 1, 0x10, ULEB, BLOCK)\ +X(offset_extended_sf,0x0, 1, 0x11, ULEB, SLEB)\ +X(def_cfa_sf, 0x0, 1, 0x12, ULEB, SLEB)\ +X(def_cfa_offset_sf, 0x0, 1, 0x13, SLEB, NULL)\ +X(val_offset, 0x0, 1, 0x14, ULEB, ULEB)\ +X(val_offset_sf, 0x0, 1, 0x15, ULEB, SLEB)\ +X(val_expression, 0x0, 1, 0x16, ULEB, BLOCK)\ +X(lo_user, 0x0, 1, 0x1c, NULL, NULL)\ +X(hi_user, 0x0, 1, 0x3f, NULL, NULL) + +// line number encoding codes +// (DWARF4.pdf + 7.21) (DWARF5.pdf + 7.22) + +// X(name, code) (V4 & V5) +#define DWARF_LineStdOpXList(X) \ +X(copy, 0x01)\ +X(advance_pc, 0x02)\ +X(advance_line, 0x03)\ +X(set_file, 0x04)\ +X(set_column, 0x05)\ +X(negate_stmt, 0x06)\ +X(set_basic_block, 0x07)\ +X(const_add_pc, 0x08)\ +X(fixed_advance_pc, 0x09)\ +X(set_prologue_end, 0x0a)\ +X(set_epilogue_begin, 0x0b)\ +X(set_isa, 0x0c) + +typedef enum DWARF_LineStdOp{ +#define X(N,C) DWARF_LineStdOp_##N = C, + DWARF_LineStdOpXList(X) +#undef X +} DWARF_LineStdOp; + +// X(name, code) (V4 & V5) +#define DWARF_LineExtOpXList(X) \ +X(end_sequence, 0x01)\ +X(set_address, 0x02)\ +X(define_file, 0x03)\ +X(set_discriminator, 0x04)\ +X(lo_user, 0x80)\ +X(hi_user, 0xff) + +typedef enum DWARF_LineExtOp{ +#define X(N,C) DWARF_LineExtOp_##N = C, + DWARF_LineExtOpXList(X) +#undef X +} DWARF_LineExtOp; + +// X(name, code) (V5) +#define DWARF_LineEntryFormatXList(X) \ +X(path, 0x1)\ +X(directory_index, 0x2)\ +X(timestamp, 0x3)\ +X(size, 0x4)\ +X(MD5, 0x5)\ +X(lo_user, 0x2000)\ +X(hi_user, 0x3fff) + +typedef enum DWARF_LineEntryFormat{ +#define X(N,C) DWARF_LineEntryFormat_##N = C, + DWARF_LineEntryFormatXList(X) +#undef X +} DWARF_LineEntryFormat; + +//////////////////////////////// +//~ Dwarf Parser Codes and Data Tables + +#define DWARF_SECTION_NAME_VARIANT_COUNT 3 + +// X(section_code_name, versionflags, section_name0, section_name1, section_name2) +#define DWARF_SectionNameXList(X,V4,V5)\ +X(Null, 0, "", "", "")\ +X(Loc, V4, ".debug_loc", ".debug_loc.dwo", "__debug_loc")\ +X(Str, V4|V5, ".debug_str", ".debug_str.dwo", "__debug_str")\ +X(LineStr, V5, ".debug_line_str", ".debug_line_str.dwo", "__debug_line_str")\ +X(CmpUnitIdx, V5, ".debug_cu_index", ".debug_cu_index.dwo", "__debug_cu_index")\ +X(TypeIdx, V5, ".debug_tu_index", ".debug_tu_index.dwo", "__debug_tu_index")\ +X(Supplement, V5, ".debug_sup", ".debug_sup.dwo", "__debug_sup")\ +X(Info, V4|V5, ".debug_info", ".debug_info.dwo", "__debug_info")\ +X(Abbrev, V4|V5, ".debug_abbrev", ".debug_abbrev.dwo", "__debug_abbrev")\ +X(PubNames, V4, ".debug_pubnames", ".debug_pubnames.dwo", "__debug_pubnames")\ +X(PubTypes, V4, ".debug_pubtypes", ".debug_pubtypes.dwo", "__debug_pubtypes")\ +X(Names, V5, ".debug_names", ".debug_names.dwo", "__debug_names")\ +X(Aranges, V4|V5, ".debug_aranges", ".debug_aranges.dwo", "__debug_aranges")\ +X(Line, V4|V5, ".debug_line", ".debug_line.dwo", "__debug_line")\ +X(MacInfo, V4, ".debug_macinfo", ".debug_macinfo.dwo", "__debug_macinfo")\ +X(Macro, V5, ".debug_macro", ".debug_macro.dwo", "__debug_macro")\ +X(Frame, V4|V5, ".debug_frame", ".debug_frame.dwo", "__debug_frame")\ +X(Ranges, V4, ".debug_ranges", ".debug_ranges.dwo", "__debug_ranges")\ +X(StrOffsets, V5, ".debug_str_offsets", ".debug_str_offsets.dwo", "__debug_str_offsets")\ +X(Addr, V5, ".debug_addr", ".debug_addr.dwo", "__debug_addr")\ +X(RngLists, V5, ".debug_rnglists", ".debug_rnglists.dwo", "__debug_rnglists")\ +X(LocLists, V5, ".debug_loclists", ".debug_loclists.dwo", "__debug_loclists") + + +typedef enum DWARF_SectionCode{ +#define X(c,vf,n0,n1,n2) DWARF_SectionCode_##c, + DWARF_SectionNameXList(X,0,0) +#undef X + DWARF_SectionCode_COUNT +} DWARF_SectionCode; + +typedef struct DWARF_SectionNameRow{ + String8 name[DWARF_SECTION_NAME_VARIANT_COUNT]; +} DWARF_SectionNameRow; + +read_only global DWARF_SectionNameRow dwarf_section_name_table[] = { +#define X(c,vf,n0,n1,n2) \ +{ { str8_lit_comp(n0), str8_lit_comp(n1), str8_lit_comp(n2) } }, + DWARF_SectionNameXList(X,0,0) +#undef X +}; + + +#pragma pack(pop) + + +//////////////////////////////// +//~ Dwarf Parser Types + +typedef struct DWARF_Parsed{ + ELF_Parsed *elf; + U32 debug_section_idx[DWARF_SectionCode_COUNT]; + String8 debug_section_name[DWARF_SectionCode_COUNT]; + String8 debug_data[DWARF_SectionCode_COUNT]; +} DWARF_Parsed; + + +// form decoding + +typedef struct DWARF_FormDecodeRules{ + union{ + // form decode fields + struct{ + U8 size; + B8 uleb128; + B8 sleb128; + B8 in_abbrev; + B8 auto_1; + B8 block; + B8 null_terminated; + }; + + // for alignment and padding to 8 + U64 x; + }; +} DWARF_FormDecodeRules; + +typedef struct DWARF_FormDecoded{ + U64 val; + U8 *dataptr; + B32 error; +} DWARF_FormDecoded; + + +// index section: .debug_cu_index .debug_tu_index +// (DWARF5.pdf + 7.3.5) + +// ** not implemented yet ** + +typedef struct DWARF_IndexParsed{ + U32 dummy; +} DWARF_IndexParsed; + + +// supplementary section: .debug_sup +// (DWARF5.pdf + 7.3.6) + +// ** not implemented yet ** + +typedef struct DWARF_SupParsed{ + U32 dummy; +} DWARF_SupParsed; + + +// info section: .debug_info +// (DWARF4.pdb + 7.5) (DWARF5.pdf + 7.5) + +typedef struct DWARF_InfoAttribVal{ + U64 val; + U8 *dataptr; +} DWARF_InfoAttribVal; + +typedef struct DWARF_InfoEntry{ + struct DWARF_InfoEntry *next_sibling; + struct DWARF_InfoEntry *first_child; + struct DWARF_InfoEntry *last_child; + U64 child_count; + struct DWARF_InfoEntry *parent; + + U64 info_offset; + struct DWARF_AbbrevDecl *abbrev_decl; + DWARF_InfoAttribVal *attrib_vals; +} DWARF_InfoEntry; + +#if 0 +typedef struct DWARF_InfoUnit{ + struct DWARF_InfoUnit *next; + + // header + U32 version; + U32 offset_size; + U32 address_size; + + // root attributes + DWARF_Language language; + U64 line_info_offset; + U64 vbase; + U64 str_offsets_base; + U64 addr_base; + U64 rnglists_base; + U64 loclists_base; + + // info entries + DWARF_InfoEntry *entry_root; + U64 entry_count; +} DWARF_InfoUnit; +#endif + +#if 0 +typedef struct DWARF_InfoParams{ + U64 unit_idx_min; + U64 unit_idx_max; +} DWARF_InfoParams; +#endif + +typedef struct DWARF_InfoUnit{ + struct DWARF_InfoUnit *next; + + U64 hdr_off; + U64 base_off; + U64 opl_off; + + U8 offset_size; + U8 version; + U8 unit_type; // (DWARF_UnitType) + U8 address_size; + U64 abbrev_off; + + union{ + // unit_type: skeleton, split_compile + U64 dwo_id; + // unit_type: type, split_type + struct{ + U64 type_signature; + U64 type_offset; + }; + }; +} DWARF_InfoUnit; + +typedef struct DWARF_InfoParsed{ + DWARF_InfoUnit *unit_first; + DWARF_InfoUnit *unit_last; + U64 unit_count; +} DWARF_InfoParsed; + + +// abbreviations section: .debug_abbrev +// (DWARF4.pdf + 7.5.3) (DWARF5.pdf + 7.5.3) + +typedef struct DWARF_AbbrevAttribSpec{ + DWARF_AttributeName name; + DWARF_AttributeForm form; +} DWARF_AbbrevAttribSpec; + +typedef struct DWARF_AbbrevDecl{ + struct DWARF_AbbrevDecl *next; + U32 abbrev_code; + DWARF_Tag tag; + B8 has_children; + U8 __filler__; + U16 attrib_count; + DWARF_AbbrevAttribSpec *attrib_specs; + S64 *implicit_const; +} DWARF_AbbrevDecl; + +typedef struct DWARF_AbbrevUnit{ + struct DWARF_AbbrevUnit *next; + U64 offset; + DWARF_AbbrevDecl *first; + DWARF_AbbrevDecl *last; + U64 count; +} DWARF_AbbrevUnit; + +#if 0 +typedef struct DWARF_AbbrevParams{ + U64 unit_idx_min; + U64 unit_idx_max; +} DWARF_AbbrevParams; +#endif + +typedef struct DWARF_AbbrevParsed{ + DWARF_AbbrevUnit *unit_first; + DWARF_AbbrevUnit *unit_last; + U64 unit_count; + B32 decoding_error; +} DWARF_AbbrevParsed; + + +// name lookup tables (V4): .debug_pubnames .debug_pubtypes +// (DWARF4.pdf + 7.19) + +typedef struct DWARF_PubNamesUnit{ + struct DWARF_PubNamesUnit *next; + + U64 hdr_off; + U64 base_off; + U64 opl_off; + + U8 offset_size; + U8 version; + U64 info_off; + U64 info_length; +} DWARF_PubNamesUnit; + +typedef struct DWARF_PubNamesParsed{ + DWARF_PubNamesUnit *unit_first; + DWARF_PubNamesUnit *unit_last; + U64 unit_count; +} DWARF_PubNamesParsed; + + +// name lookup tables (V5): .debug_names +// (DWARF5.pdf + 6.1.1.4.1 & 7.19) + +typedef struct DWARF_NamesUnit{ + struct DWARF_NamesUnit *next; + + U64 hdr_off; + U64 base_off; + U64 opl_off; + + U8 version; + U32 comp_unit_count; + U32 local_type_unit_count; + U32 foreign_type_unit_count; + U32 bucket_count; + U32 name_count; + U32 abbrev_table_size; + String8 augmentation_string; + +} DWARF_NamesUnit; + +typedef struct DWARF_NamesParsed{ + DWARF_NamesUnit *unit_first; + DWARF_NamesUnit *unit_last; + U64 unit_count; +} DWARF_NamesParsed; + + +// address range table: .debug_aranges +// (DWARF4.pdf + 7.20) (DWARF5.pdf + 7.21) + +typedef struct DWARF_ArangesUnit{ + struct DWARF_ArangesUnit *next; + + U64 hdr_off; + U64 base_off; + U64 opl_off; + + U8 version; + U8 address_size; + U8 segment_selector_size; + U8 offset_size; + U64 info_off; +} DWARF_ArangesUnit; + +typedef struct DWARF_ArangesParsed{ + DWARF_ArangesUnit *unit_first; + DWARF_ArangesUnit *unit_last; + U64 unit_count; +} DWARF_ArangesParsed; + + +// line number information: .debug_line +// (DWARF4.pdf + 6.2.4 & 7.21) (DWARF5.pdf + 6.2.4 & 7.22) + +typedef struct DWARF_V4LineFileNamesEntry{ + struct DWARF_V4LineFileNamesEntry *next; + String8 file_name; + U64 include_directory_idx; + U64 last_modified_time; + U64 file_size; +} DWARF_V4LineFileNamesEntry; + +typedef struct DWARF_V4LineFileNamesList{ + DWARF_V4LineFileNamesEntry *first; + DWARF_V4LineFileNamesEntry *last; + U64 count; +} DWARF_V4LineFileNamesList; + +typedef struct DWARF_V5LinePathEntryFormat{ + U32 content_type; /* DWARF_LineEntryFormat */ + U32 form; /* DWARF_AttributeForm */ +} DWARF_V5LinePathEntryFormat; + +typedef struct DWARF_V5Directory{ + String8 path_str; + U64 path_off; + U64 path_sec_form; + U64 directory_index; + U64 timestamp; + U64 size; + U8 md5_checksum[16]; +} DWARF_V5Directory; + +typedef struct DWARF_LineUnit{ + struct DWARF_LineUnit *next; + + U64 hdr_off; + U64 base_off; + U64 opl_off; + + U8 version; + +} DWARF_LineUnit; + +typedef struct DWARF_LineParsed{ + DWARF_LineUnit *unit_first; + DWARF_LineUnit *unit_last; + U64 unit_count; +} DWARF_LineParsed; + + +// macro information (V4): .debug_macinfo +// (DWARF4.pdf + 7.22) + +// ** not implemented yet ** + +typedef struct DWARF_MacInfoParsed{ + U32 dummy; +} DWARF_MacInfoParsed; + + +// macro information (V5): .debug_macro +// (DWARF5.pdf + 7.23) + +// ** not implemented yet ** + +typedef struct DWARF_MacroParsed{ + U32 dummy; +} DWARF_MacroParsed; + + +// call frame information: .debug_frame +// (DWARF4.pdf + 7.23) (DWARF5.pdf + 7.24) + +// ** not implemented yet ** + +typedef struct DWARF_FrameParsed{ + U32 dummy; +} DWARF_FrameParsed; + + +// range lists (V4): .debug_ranges +// (DWARF4.pdf + 7.24) + +// ** not implemented yet ** + +typedef struct DWARF_RangesParsed{ + U32 dummy; +} DWARF_RangesParsed; + + +// string offsets table: .debug_str_offsets +// (DWARF5.pdf + 7.26) + +// ** not implemented yet ** + +typedef struct DWARF_StrOffsetsParsed{ + U32 dummy; +} DWARF_StrOffsetsParsed; + + +// address table: .debug_addr +// (DWARF5.pdf + 7.27) + +typedef struct DWARF_AddrUnit{ + struct DWARF_AddrUnit *next; + + U64 hdr_off; + U64 base_off; + U64 opl_off; + + U8 offset_size; + U8 dwarf_version; + U8 address_size; + U8 segment_selector_size; +} DWARF_AddrUnit; + +typedef struct DWARF_AddrParsed{ + DWARF_AddrUnit *unit_first; + DWARF_AddrUnit *unit_last; + U64 unit_count; +} DWARF_AddrParsed; + + +// range lists (V5): .debug_rnglists +// (DWARF5.pdf + 7.28 & 7.25) + +// ** not implemented yet ** + +typedef struct DWARF_RngListsParsed{ + U32 dummy; +} DWARF_RngListsParsed; + + +// location lists: .debug_loclists +// (DWARF5.pdf + 7.29) + +// ** not implemented yet ** + +typedef struct DWARF_LocListsParsed{ + U32 dummy; +} DWARF_LocListsParsed; + + +//////////////////////////////// +//~ Dwarf Decode Helpers + +#define DWARF_LEB128_ADV(p,o,s) do{ for(;; (p)+=1){\ +if ((p) == (o)) { (s)=0; break; } \ +if (((*(p))&0x80) == 0) { (p)+=1; break; } \ +} }while(0) + +#define DWARF_LEB128_ADV_NOCAP(p) for((p)+=1; ((*(p-1))&0x80) != 0; (p)+=1) + +static U64 dwarf_leb128_decode_U64(U8 *ptr, U8 *opl); +static S64 dwarf_leb128_decode_S64(U8 *ptr, U8 *opl); +static U32 dwarf_leb128_decode_U32(U8 *ptr, U8 *opl); + +#define dwarf_leb128_decode(T,ptr,opl) dwarf_leb128_decode_##T(ptr,opl) + +#define DWARF_LEB128_DECODE_ADV(T,x,p,o) do{ \ +U8 *first__ = (p); B32 success__; \ +DWARF_LEB128_ADV(p,o,success__); \ +if (success__) \ +(x) = dwarf_leb128_decode(T,first__, (p)); \ +}while(0) + +//////////////////////////////// +//~ Dwarf Parser Functions + +static DWARF_Parsed* dwarf_parsed_from_elf(Arena *arena, ELF_Parsed *elf); + +static DWARF_IndexParsed* dwarf_index_from_data(Arena *arena, String8 data); +static DWARF_SupParsed* dwarf_sup_from_data(Arena *arena, String8 data); +static DWARF_InfoParsed* dwarf_info_from_data(Arena *arena, String8 data); +static DWARF_PubNamesParsed* dwarf_pubnames_from_data(Arena *arena, String8 data); +static DWARF_NamesParsed* dwarf_names_from_data(Arena *arena, String8 data); +static DWARF_ArangesParsed* dwarf_aranges_from_data(Arena *arena, String8 data); +static DWARF_LineParsed* dwarf_line_from_data(Arena *arena, String8 data); +static DWARF_MacInfoParsed* dwarf_mac_info_from_data(Arena *arena, String8 data); +static DWARF_MacroParsed* dwarf_macro_from_data(Arena *arena, String8 data); +static DWARF_FrameParsed* dwarf_frame_from_data(Arena *arena, String8 data); +static DWARF_RangesParsed* dwarf_ranges_from_data(Arena *arena, String8 data); +static DWARF_StrOffsetsParsed* dwarf_str_offsets_from_data(Arena *arena, String8 data); +static DWARF_AddrParsed* dwarf_addr_from_data(Arena *arena, String8 data); +static DWARF_RngListsParsed* dwarf_rng_lists_from_data(Arena *arena, String8 data); +static DWARF_LocListsParsed* dwarf_loc_lists_from_data(Arena *arena, String8 data); + + +// parse helpers + +// (DWARF4.pdf + 7.2.2) (DWARF5.pdf + 7.2.2) +static void dwarf__initial_length(String8 data, + U8 **ptr_inout, U8 **unit_opl_out, B32 *is_64bit_out); + +static void +dwarf__line_v5_directories(U64 address_size, U64 offset_size, + DWARF_V5LinePathEntryFormat *format, U64 format_count, + DWARF_V5Directory *directories_out, U64 dir_count, + U8 **ptr_io, U8 *opl); + +// debug sections + +static String8 dwarf_name_from_debug_section(DWARF_Parsed *dwarf, DWARF_SectionCode sec_code); + +// abbrev functions + +static DWARF_AbbrevUnit* dwarf_abbrev_unit_from_offset(DWARF_AbbrevParsed *abbrev, U64 off); +static DWARF_AbbrevDecl* dwarf_abbrev_decl_from_code(DWARF_AbbrevUnit *unit, U32 code); + +// attribute decoding functions + +static DWARF_AttributeClassFlags dwarf_attribute_class_from_form(DWARF_AttributeForm form); +static DWARF_AttributeClassFlags dwarf_attribute_class_from_name(DWARF_AttributeName name); + +// form decoding functions + +static DWARF_FormDecodeRules +dwarf_form_decode_rule(DWARF_AttributeForm form, U64 address_size, U64 offset_size); + +static DWARF_FormDecoded +dwarf_form_decode(DWARF_FormDecodeRules *rules, U8 **ptr_io, U8 *opl, + DWARF_AbbrevDecl *abbrev_decl, U32 attrib_i); + +// string functions + +static String8 dwarf_string_from_unit_type(DWARF_UnitType type); +static String8 dwarf_string_from_tag(DWARF_Tag tag); +static String8 dwarf_string_from_attribute_name(DWARF_AttributeName name); +static String8 dwarf_string_from_attribute_form(DWARF_AttributeForm form); +static String8 dwarf_string_from_line_std_op(DWARF_LineStdOp op); +static String8 dwarf_string_from_line_ext_op(DWARF_LineExtOp op); +static String8 dwarf_string_from_line_entry_format(DWARF_LineEntryFormat format); +static String8 dwarf_string_from_section_code(DWARF_SectionCode sec_code); + +#endif //RADDBG_DWARF_H + diff --git a/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.c b/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.c new file mode 100644 index 00000000..9b0bfdce --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.c @@ -0,0 +1,102 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ DWARF Stringize Functions + +static char dwarf_spaces[] = " "; + +static void +dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent){ + String8 unit_type_string = dwarf_string_from_unit_type((DWARF_UnitType)unit->unit_type); + + str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); + str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); + str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); + str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, + unit->offset_size); + str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); + str8_list_pushf(arena, out, "%.*sunit_type=%.*s\n", indent, dwarf_spaces, + str8_varg(unit_type_string)); + str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces, + unit->address_size); + str8_list_pushf(arena, out, "%.*sabbrev_off=0x%llx\n", indent, dwarf_spaces, + unit->abbrev_off); + + switch (unit->unit_type){ + case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile: + { + str8_list_pushf(arena, out, "%.*sdwo_id=%llu\n", indent, dwarf_spaces, unit->dwo_id); + }break; + + case DWARF_UnitType_type: case DWARF_UnitType_split_type: + { + str8_list_pushf(arena, out, "%.*stype_signature=%llu\n", indent, dwarf_spaces, + unit->type_signature); + str8_list_pushf(arena, out, "%.*stype_offset=%llu\n", indent, dwarf_spaces, + unit->type_offset); + }break; + } +} + +static void +dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit, + U32 indent){ + str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); + str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); + str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); + str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size); + str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); + str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off); + str8_list_pushf(arena, out, "%.*sinfo_length=0x%llx\n", indent, dwarf_spaces, + unit->info_length); +} + +static void +dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent){ + str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); + str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); + str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); + str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); + str8_list_pushf(arena, out, "%.*scomp_unit_count=%u\n", indent, dwarf_spaces, + unit->comp_unit_count); + str8_list_pushf(arena, out, "%.*slocal_type_unit_count=%u\n", indent, dwarf_spaces, + unit->local_type_unit_count); + str8_list_pushf(arena, out, "%.*sforeign_type_unit_count=%u\n", indent, dwarf_spaces, + unit->foreign_type_unit_count); + str8_list_pushf(arena, out, "%.*sbucket_count=%u\n", indent, dwarf_spaces, + unit->bucket_count); + str8_list_pushf(arena, out, "%.*sname_count=%u\n", indent, dwarf_spaces, unit->name_count); + str8_list_pushf(arena, out, "%.*sabbrev_table_size=%u\n", indent, dwarf_spaces, + unit->abbrev_table_size); + str8_list_pushf(arena, out, "%.*saugmentation_string=%.*s\n", indent, dwarf_spaces, + str8_varg(unit->augmentation_string)); +} + +static void +dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent){ + str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); + str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); + str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); + str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); + str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces, + unit->address_size); + str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces, + unit->segment_selector_size); + str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size); + str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off); +} + +static void +dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent){ + str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); + str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); + str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); + str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, + unit->offset_size); + str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->dwarf_version); + str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces, + unit->address_size); + str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces, + unit->segment_selector_size); +} diff --git a/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.h b/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.h new file mode 100644 index 00000000..dc322ad1 --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.h @@ -0,0 +1,28 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_DWARF_STRINGIZE_H +#define RADDBG_DWARF_STRINGIZE_H + +//////////////////////////////// +//~ DWARF Stringize Functions + +static void +dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent); + +static void +dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit, + U32 indent); + +static void +dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent); + +static void +dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent); + +static void +dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent); + + + +#endif //RADDBG_DWARF_STRINGIZE_H diff --git a/src/raddbg_convert/dwarf/raddbg_elf.c b/src/raddbg_convert/dwarf/raddbg_elf.c new file mode 100644 index 00000000..ff8e3c9e --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_elf.c @@ -0,0 +1,555 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ ELF Parser Functions + +static ELF_Parsed* +elf_parsed_from_data(Arena *arena, String8 elf_data){ + //- test magic number + B32 has_good_magic_number = 0; + if (elf_data.size >= sizeof(ELF_NIDENT) && + MemoryMatch(elf_data.str, elf_magic, sizeof(elf_magic))){ + has_good_magic_number = 1; + } + + //- determine elf class + U8 elf_class = ELF_Class_NONE; + if (has_good_magic_number){ + elf_class = elf_data.str[ELF_Identification_CLASS]; + } + + //- extract header information + B32 decoded_header = 0; + + U8 e_data_encoding = ELF_DataEncoding_NONE; + U16 e_machine = ELF_Machine_NONE; + + U64 e_entry = 0; + + U64 e_shoff = 0; + U16 e_shentsize = 0; + U16 e_shnum = 0; + + U64 e_phoff = 0; + U16 e_phentsize = 0; + U16 e_phnum = 0; + + U16 e_shstrndx = 0; + + switch (elf_class){ + case ELF_Class_NONE: /* not good */ break; + + case ELF_Class_32: + { + if (elf_data.size >= sizeof(ELF_Ehdr32)){ + ELF_Ehdr32 *hdr = (ELF_Ehdr32*)elf_data.str; + + decoded_header = 1; + e_data_encoding = hdr->e_ident[ELF_Identification_DATA]; + e_machine = hdr->e_machine; + e_entry = hdr->e_entry; + e_phoff = hdr->e_phoff; + e_shoff = hdr->e_shoff; + e_phentsize = hdr->e_phentsize; + e_phnum = hdr->e_phnum; + e_shentsize = hdr->e_shentsize; + e_shnum = hdr->e_shnum; + e_shstrndx = hdr->e_shstrndx; + } + }break; + + case ELF_Class_64: + { + if (elf_data.size >= sizeof(ELF_Ehdr64)){ + ELF_Ehdr64 *hdr = (ELF_Ehdr64*)elf_data.str; + + decoded_header = 1; + e_data_encoding = hdr->e_ident[ELF_Identification_DATA]; + e_machine = hdr->e_machine; + e_entry = hdr->e_entry; + e_phoff = hdr->e_phoff; + e_shoff = hdr->e_shoff; + e_phentsize = hdr->e_phentsize; + e_phnum = hdr->e_phnum; + e_shentsize = hdr->e_shentsize; + e_shnum = hdr->e_shnum; + e_shstrndx = hdr->e_shstrndx; + } + }break; + } + + //- validate & translate header values + B32 header_is_good = 0; + Architecture arch = Architecture_Null; + if (decoded_header){ + header_is_good = 1; + + // only supporting little-endian versions right now + if (header_is_good){ + if (e_data_encoding != ELF_DataEncoding_2LSB){ + header_is_good = 0; + } + } + + // make sure this is a supported machine type + if (header_is_good){ + switch (e_machine){ + default: header_is_good = 0; + case ELF_Machine_386: arch = Architecture_x86; break; + case ELF_Machine_X86_64: arch = Architecture_x64; break; + } + } + + // make sure section & segment sizes are correct + if (header_is_good){ + switch (elf_class){ + case ELF_Class_32: + { + if (e_shentsize != sizeof(ELF_Shdr32) || + e_phentsize != sizeof(ELF_Phdr32)){ + header_is_good = 0; + } + }break; + case ELF_Class_64: + { + if (e_shentsize != sizeof(ELF_Shdr64) || + e_phentsize != sizeof(ELF_Phdr64)){ + header_is_good = 0; + } + }break; + } + } + } + + //- extract extra information from the special first section + U64 section_count_raw = e_shnum; + U32 section_header_string_table_index = e_shstrndx; + if (header_is_good){ + if (e_shoff <= elf_data.size && e_shentsize <= elf_data.size && + e_shoff + e_shentsize <= elf_data.size){ + U64 size = 0; + U32 link = 0; + switch (elf_class){ + case ELF_Class_32: + { + ELF_Shdr32 *shdr = (ELF_Shdr32*)(elf_data.str + e_shoff); + size = shdr->sh_size; + link = shdr->sh_link; + }break; + case ELF_Class_64: + { + ELF_Shdr64 *shdr = (ELF_Shdr64*)(elf_data.str + e_shoff); + size = shdr->sh_size; + link = shdr->sh_link; + }break; + } + + // extended section count + if (size != 0){ + section_count_raw = size; + } + + // extended section header string table index + if (link != 0){ + section_header_string_table_index = link; + } + } + } + + //- clamp section & program arrays to size + U64 section_foff = 0; + U64 section_size = 0; + U64 section_count = 0; + + U64 segment_foff = 0; + U64 segment_size = 0; + U64 segment_count = 0; + + if (header_is_good){ + if (e_shentsize > 0){ + U64 section_opl_raw = e_shoff + e_shentsize*section_count_raw; + U64 section_opl = ClampTop(section_opl_raw, elf_data.size); + if (section_opl > e_shoff){ + section_foff = e_shoff; + section_size = e_shentsize; + section_count = (section_opl - e_shoff)/e_shentsize; + } + } + + if (e_phentsize > 0){ + U64 segment_opl_raw = e_phoff + e_phentsize*e_phnum; + U64 segment_opl = ClampTop(segment_opl_raw, elf_data.size); + if (segment_opl > e_phoff){ + segment_foff = e_phoff; + segment_size = e_phentsize; + segment_count = (segment_opl - e_phoff)/e_phentsize; + } + } + } + + //- determine the vbase for this file + U64 vbase = 0; + if (header_is_good){ + // find the first LOAD segment + U64 load_segment_off = 0; + { + U64 segment_cursor = segment_foff; + U64 segment_opl = segment_foff + segment_size*segment_count; + for (;segment_cursor < segment_opl; segment_cursor += segment_size){ + U32 p_type = *(U32*)(elf_data.str + segment_cursor); + if (p_type == ELF_SegmentType_LOAD){ + load_segment_off = segment_cursor; + break; + } + } + } + + // use the segment's p_vaddr to determine vbase + if (load_segment_off != 0){ + switch (elf_class){ + case ELF_Class_32: + { + ELF_Phdr32 *phdr = (ELF_Phdr32*)(elf_data.str + load_segment_off); + vbase = phdr->p_vaddr; + }break; + case ELF_Class_64: + { + ELF_Phdr64 *phdr = (ELF_Phdr64*)(elf_data.str + load_segment_off); + vbase = phdr->p_vaddr; + }break; + } + } + } + + //- locate the section header string table + U64 section_name_table_foff = 0; + U64 section_name_table_opl = 0; + if (header_is_good){ + if (section_header_string_table_index < section_count){ + U64 sec_foff = section_foff + section_header_string_table_index*section_size; + switch (elf_class){ + case ELF_Class_32: + { + ELF_Shdr32 *shdr = (ELF_Shdr32*)(elf_data.str + sec_foff); + section_name_table_foff = shdr->sh_offset; + section_name_table_opl = shdr->sh_offset + shdr->sh_size; + }break; + case ELF_Class_64: + { + ELF_Shdr64 *shdr = (ELF_Shdr64*)(elf_data.str + sec_foff); + section_name_table_foff = shdr->sh_offset; + section_name_table_opl = shdr->sh_offset + shdr->sh_size; + }break; + } + } + } + + //- format sections data + ELF_Shdr64 *sections = 0; + if (header_is_good && section_count > 0){ + switch (elf_class){ + case ELF_Class_32: + { + sections = push_array(arena, ELF_Shdr64, section_count); + { + ELF_Shdr32 *shdr32 = (ELF_Shdr32*)(elf_data.str + section_foff); + ELF_Shdr64 *shdr64 = sections; + for (U64 i = 0; i < section_count; i += 1, shdr32 += 1, shdr64 += 1){ + shdr64->sh_name = shdr32->sh_name; + shdr64->sh_type = shdr32->sh_type; + shdr64->sh_flags = shdr32->sh_flags; + shdr64->sh_addr = shdr32->sh_addr; + shdr64->sh_offset = shdr32->sh_offset; + shdr64->sh_size = shdr32->sh_size; + shdr64->sh_link = shdr32->sh_link; + shdr64->sh_info = shdr32->sh_info; + shdr64->sh_addralign = shdr32->sh_addralign; + shdr64->sh_entsize = shdr32->sh_entsize; + } + } + }break; + case ELF_Class_64: + { + sections = (ELF_Shdr64*)(elf_data.str + section_foff); + }break; + } + } + + //- extract section names + String8 *section_names = 0; + if (sections != 0 && section_count > 0){ + U8 *string_table_opl = elf_data.str + section_name_table_opl; + + section_names = push_array(arena, String8, section_count); + String8 *sec_name = section_names; + ELF_Shdr64 *sec = sections; + for (U64 i = 0; + i < section_count; + i += 1, sec += 1, sec_name += 1){ + U64 name_foff = section_name_table_foff + sec->sh_name; + if (section_name_table_foff <= name_foff && name_foff < section_name_table_opl){ + U8 *base = elf_data.str + name_foff; + U8 *opl = base; + for (;opl < string_table_opl && *opl != 0; opl += 1); + sec_name->str = base; + sec_name->size = (U64)(opl - base); + } + } + } + + //- format segments data + ELF_Phdr64 *segments = 0; + if (header_is_good && segment_count > 0){ + switch (elf_class){ + case ELF_Class_32: + { + segments = push_array(arena, ELF_Phdr64, segment_count); + { + ELF_Phdr32 *phdr32 = (ELF_Phdr32*)(elf_data.str + segment_foff); + ELF_Phdr64 *phdr64 = segments; + for (U64 i = 0; i < segment_count; i += 1, phdr32 += 1, phdr64 += 1){ + phdr64->p_type = phdr32->p_type; + phdr64->p_flags = phdr32->p_flags; + phdr64->p_offset = phdr32->p_offset; + phdr64->p_vaddr = phdr32->p_vaddr; + phdr64->p_paddr = phdr32->p_paddr; + phdr64->p_filesz = phdr32->p_filesz; + phdr64->p_memsz = phdr32->p_memsz; + phdr64->p_align = phdr32->p_align; + } + } + }break; + case ELF_Class_64: + { + segments = (ELF_Phdr64*)(elf_data.str + segment_foff); + }break; + } + } + + //- find special sections + U64 strtab_idx = 0; + U64 symtab_idx = 0; + U64 dynsym_idx = 0; + if (section_names != 0){ + for (U64 i = 0; i < section_count; i += 1){ + String8 name = section_names[i]; + if (str8_match(name, str8_lit(".strtab"), 0)){ + strtab_idx = i; + } + else if (str8_match(name, str8_lit(".symtab"), 0)){ + symtab_idx = i; + } + else if (str8_match(name, str8_lit(".dynsym"), 0)){ + dynsym_idx = i; + } + } + } + + + //- fill result + ELF_Parsed *result = 0; + if (header_is_good){ + result = push_array(arena, ELF_Parsed, 1); + result->data = elf_data; + result->elf_class = elf_class; + result->arch = arch; + result->sections = sections; + result->section_names = section_names; + result->section_foff = section_foff; + result->section_count = section_count; + result->segments = segments; + result->segment_foff = segment_foff; + result->segment_count = segment_count; + result->vbase = vbase; + result->entry_vaddr = e_entry; + result->section_name_table_foff = section_name_table_foff; + result->section_name_table_opl = section_name_table_opl; + result->strtab_idx = strtab_idx; + result->symtab_idx = symtab_idx; + result->dynsym_idx = dynsym_idx; + } + + return(result); +} + +static ELF_SectionArray +elf_section_array_from_elf(ELF_Parsed *elf){ + ELF_SectionArray result = {0}; + if (elf != 0){ + result.sections = elf->sections; + result.count = elf->section_count; + } + return(result); +} + +static String8Array +elf_section_name_array_from_elf(ELF_Parsed *elf){ + String8Array result = {0}; + if (elf != 0){ + result.strings = elf->section_names; + result.count = elf->section_count; + } + return(result); +} + +static ELF_SegmentArray +elf_segment_array_from_elf(ELF_Parsed *elf){ + ELF_SegmentArray result = {0}; + if (elf != 0){ + result.segments = elf->segments; + result.count = elf->segment_count; + } + return(result); +} + +static String8 +elf_section_name_from_name_offset(ELF_Parsed *elf, U64 offset){ + String8 result = {0}; + if (elf != 0){ + if (offset > 0){ + U64 foff = elf->section_name_table_foff + offset; + if (elf->section_name_table_foff <= foff && foff < elf->section_name_table_opl){ + U8 *base = elf->data.str + foff; + U8 *section_opl = elf->data.str + elf->section_name_table_opl; + U8 *opl = base; + for (;opl < section_opl && *opl != 0; opl += 1); + result.str = base; + result.size = opl - base; + } + } + } + return(result); +} + +static String8 +elf_section_name_from_idx(ELF_Parsed *elf, U32 idx){ + String8 result = {0}; + if (elf != 0){ + if (idx < elf->section_count){ + result = elf->section_names[idx]; + } + } + return(result); +} + +static U32 +elf_section_idx_from_name(ELF_Parsed *elf, String8 name){ + U32 result = 0; + if (elf != 0){ + String8 *sec_name = elf->section_names; + U64 count = elf->section_count; + for (U64 i = 0; i < count; i += 1, sec_name += 1){ + if (str8_match(*sec_name, name, 0)){ + result = i; + break; + } + } + } + return(result); +} + +static String8 +elf_section_data_from_idx(ELF_Parsed *elf, U32 idx){ + String8 result = {0}; + if (elf != 0){ + if (idx < elf->section_count){ + ELF_Shdr64 *shdr = elf->sections + idx; + U64 off_raw = shdr->sh_offset; + U64 size = shdr->sh_size; + if (shdr->sh_flags & ELF_SectionType_NOBITS){ + size = 0; + } + U64 opl_raw = off_raw + size; + U64 opl = ClampTop(opl_raw, elf->data.size); + U64 off = ClampTop(off_raw, opl); + result.str = elf->data.str + off; + result.size = opl - off; + } + } + return(result); +} + +static ELF_SymArray +elf_sym_array_from_data(Arena *arena, ELF_Class elf_class, String8 data){ + // converge to sym64 layout + ELF_Sym64 *symbols = 0; + U64 count = 0; + switch (elf_class){ + case ELF_Class_32: + { + count = data.size/sizeof(ELF_Sym32); + symbols = push_array(arena, ELF_Sym64, count); + { + ELF_Sym32 *sym32 = (ELF_Sym32*)(data.str); + ELF_Sym64 *sym64 = symbols; + for (U64 i = 0; i < count; i += 1, sym32 += 1, sym64 += 1){ + sym64->st_name = sym32->st_name; + sym64->st_value = sym32->st_value; + sym64->st_size = sym32->st_size; + sym64->st_info = sym32->st_info; + sym64->st_other = sym32->st_other; + sym64->st_shndx = sym32->st_shndx; + } + } + }break; + + case ELF_Class_64: + { + count = data.size/sizeof(ELF_Sym64); + symbols = (ELF_Sym64*)(data.str); + }break; + } + + // fill result + ELF_SymArray result = {0}; + result.symbols = symbols; + result.count = count; + return(result); +} + +// string functions + +static String8 +elf_string_from_section_type(ELF_SectionType section_type){ + String8 result = str8_lit("INVALID_SECTION_TYPE"); + switch (section_type){ +#define X(N,C) case C: result = str8_lit(#N); break; + ELF_SectionTypeXList(X) +#undef X + } + return(result); +} + +static String8 +elf_string_from_symbol_binding(ELF_SymbolBinding binding){ + String8 result = str8_lit("INVALID_SYMBOL_BINDING"); + switch (binding){ +#define X(N,C) case C: result = str8_lit(#N); break; + ELF_SymbolBindingXList(X) +#undef X + } + return(result); +} + +static String8 +elf_string_from_symbol_type(ELF_SymbolType type){ + String8 result = str8_lit("INVALID_SYMBOL_TYPE"); + switch (type){ +#define X(N,C) case C: result = str8_lit(#N); break; + ELF_SymbolTypeXList(X) +#undef X + } + return(result); +} + +static String8 +elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility){ + String8 result = str8_lit("INVALID_SYMBOL_VISIBILITY"); + switch (visibility){ +#define X(N,C) case C: result = str8_lit(#N); break; + ELF_SymbolVisibilityXList(X) +#undef X + } + return(result); +} diff --git a/src/raddbg_convert/dwarf/raddbg_elf.h b/src/raddbg_convert/dwarf/raddbg_elf.h new file mode 100644 index 00000000..5b04c11e --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_elf.h @@ -0,0 +1,517 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_ELF_H +#define RADDBG_ELF_H + +// https://refspecs.linuxfoundation.org/elf/elf.pdf + +//////////////////////////////// +//~ Elf Format Types + +// elf header + +#define ELF_NIDENT 16 + +typedef struct ELF_Ehdr32{ + U8 e_ident[ELF_NIDENT]; + U16 e_type; + U16 e_machine; + U32 e_version; + U32 e_entry; + U32 e_phoff; + U32 e_shoff; + U32 e_flags; + U16 e_ehsize; + U16 e_phentsize; + U16 e_phnum; + U16 e_shentsize; + U16 e_shnum; + U16 e_shstrndx; +} ELF_Ehdr32; + +typedef struct ELF_Ehdr64{ + U8 e_ident[ELF_NIDENT]; + U16 e_type; + U16 e_machine; + U32 e_version; + U64 e_entry; + U64 e_phoff; + U64 e_shoff; + U32 e_flags; + U16 e_ehsize; + U16 e_phentsize; + U16 e_phnum; + U16 e_shentsize; + U16 e_shnum; + U16 e_shstrndx; +} ELF_Ehdr64; + +typedef enum ELF_Type{ + ELF_Type_NONE = 0, + ELF_Type_REL = 1, + ELF_Type_EXEC = 2, + ELF_Type_DYN = 3, + ELF_Type_CORE = 4, + ELF_Type_LOOS = 0xfe00, + ELF_Type_HIOS = 0xfeff, + ELF_Type_LOPROC = 0xff00, + ELF_Type_HIPROC = 0xffff, +} ELF_Type; + +typedef enum ELF_Machine{ + ELF_Machine_NONE = 0, + ELF_Machine_M32 = 1, + ELF_Machine_SPARC = 2, + ELF_Machine_386 = 3, + ELF_Machine_68K = 4, + ELF_Machine_88K = 5, + ELF_Machine_860 = 7, + ELF_Machine_MIPS = 8, + ELF_Machine_S370 = 9, + ELF_Machine_MIPS_RS3_LE = 10, + ELF_Machine_PARISC = 15, + ELF_Machine_VPP500 = 17, + ELF_Machine_SPARC32PLUS = 18, + ELF_Machine_960 = 19, + ELF_Machine_PPC = 20, + ELF_Machine_PPC64 = 21, + ELF_Machine_S390 = 22, + ELF_Machine_V800 = 36, + ELF_Machine_FR20 = 37, + ELF_Machine_RH32 = 38, + ELF_Machine_RCE = 39, + ELF_Machine_ARM = 40, + ELF_Machine_ALPHA = 41, + ELF_Machine_SH = 42, + ELF_Machine_SPARCV9 = 43, + ELF_Machine_TRICORE = 44, + ELF_Machine_ARC = 45, + ELF_Machine_H8_300 = 46, + ELF_Machine_H8_300H = 47, + ELF_Machine_H8S = 48, + ELF_Machine_H8_500 = 49, + ELF_Machine_IA_64 = 50, + ELF_Machine_MIPS_X = 51, + ELF_Machine_COLDFIRE = 52, + ELF_Machine_68HC12 = 53, + ELF_Machine_MMA = 54, + ELF_Machine_PCP = 55, + ELF_Machine_NCPU = 56, + ELF_Machine_NDR1 = 57, + ELF_Machine_STARCORE = 58, + ELF_Machine_ME16 = 59, + ELF_Machine_ST100 = 60, + ELF_Machine_TINYJ = 61, + ELF_Machine_X86_64 = 62, + ELF_Machine_PDSP = 63, + ELF_Machine_PDP10 = 64, + ELF_Machine_PDP11 = 65, + ELF_Machine_FX66 = 66, + ELF_Machine_ST9PLUS = 67, + ELF_Machine_ST7 = 68, + ELF_Machine_68HC16 = 69, + ELF_Machine_68HC11 = 70, + ELF_Machine_68HC08 = 71, + ELF_Machine_68HC05 = 72, + ELF_Machine_SVX = 73, + ELF_Machine_ST19 = 74, + ELF_Machine_VAX = 75, + ELF_Machine_CRIS = 76, + ELF_Machine_JAVELIN = 77, + ELF_Machine_FIREPATH = 78, + ELF_Machine_ZSP = 79, + ELF_Machine_MMIX = 80, + ELF_Machine_HUANY = 81, + ELF_Machine_PRISM = 82, + ELF_Machine_AVR = 83, + ELF_Machine_FR30 = 84, + ELF_Machine_D10V = 85, + ELF_Machine_D30V = 86, + ELF_Machine_V850 = 87, + ELF_Machine_M32R = 88, + ELF_Machine_MN10300 = 89, + ELF_Machine_MN10200 = 90, + ELF_Machine_PJ = 91, + ELF_Machine_OPENRISC = 92, + ELF_Machine_ARC_A5 = 93, + ELF_Machine_XTENSA = 94, + ELF_Machine_VIDEOCORE = 95, + ELF_Machine_TMM_GPP = 96, + ELF_Machine_NS32K = 97, + ELF_Machine_TPC = 98, + ELF_Machine_SNP1K = 99, + ELF_Machine_ST200 = 100, +} ELF_Machine; + +typedef enum ELF_Version{ + ELF_Version_NONE = 0, + ELF_Version_CURRENT = 1, +} ELF_Version; + +typedef enum ELF_Identification{ + ELF_Identification_MAG0 = 0, + ELF_Identification_MAG1 = 1, + ELF_Identification_MAG2 = 2, + ELF_Identification_MAG3 = 3, + ELF_Identification_CLASS = 4, + ELF_Identification_DATA = 5, + ELF_Identification_VERSION = 6, + ELF_Identification_OSABI = 7, + ELF_Identification_ABIVERSION = 8, + ELF_Identification_PAD = 9, +} ELF_Identification; + +read_only global U8 elf_magic[] = {0x7F, 'E', 'L', 'F'}; + +typedef enum ELF_Class{ + ELF_Class_NONE = 0, + ELF_Class_32 = 1, + ELF_Class_64 = 2, +} ELF_Class; + +typedef enum ELF_DataEncoding{ + ELF_DataEncoding_NONE = 0, + ELF_DataEncoding_2LSB = 1, + ELF_DataEncoding_2MSB = 2, +} ELF_DataEncoding; + +typedef enum ELF_OsAbi{ + ELF_OsAbi_NONE = 0, + ELF_OsAbi_HPUX = 1, + ELF_OsAbi_NETBSD = 2, + ELF_OsAbi_LINUX = 3, + ELF_OsAbi_SOLARIS = 6, + ELF_OsAbi_AIX = 7, + ELF_OsAbi_IRIX = 8, + ELF_OsAbi_FREEBSD = 9, + ELF_OsAbi_TRU64 = 10, + ELF_OsAbi_MODESTO = 11, + ELF_OsAbi_OPENBSD = 12, + ELF_OsAbi_OPENVMS = 13, + ELF_OsAbi_NSK = 14, +} ELF_OsAbi; + +// sections + +typedef enum ELF_ReservedSectionIndex{ + ELF_ReservedSectionIndex_UNDEF = 0, + ELF_ReservedSectionIndex_LORESERVE = 0xFF00, + ELF_ReservedSectionIndex_LOPROC = 0xFF00, + ELF_ReservedSectionIndex_HIPROC = 0xFF1F, + ELF_ReservedSectionIndex_LOOS = 0xFF20, + ELF_ReservedSectionIndex_HIOS = 0xFF3F, + ELF_ReservedSectionIndex_ABS = 0xFFF1, + ELF_ReservedSectionIndex_COMMON = 0xFFF2, + ELF_ReservedSectionIndex_XINDEX = 0xFFFF, + ELF_ReservedSectionIndex_HIRESERVE = 0xFFFF, +} ELF_ReservedSectionIndex; + +typedef struct ELF_Shdr32{ + U32 sh_name; + U32 sh_type; + U32 sh_flags; + U32 sh_addr; + U32 sh_offset; + U32 sh_size; + U32 sh_link; + U32 sh_info; + U32 sh_addralign; + U32 sh_entsize; +} ELF_Shdr32; + +typedef struct ELF_Shdr64{ + U32 sh_name; + U32 sh_type; + U64 sh_flags; + U64 sh_addr; + U64 sh_offset; + U64 sh_size; + U32 sh_link; + U32 sh_info; + U64 sh_addralign; + U64 sh_entsize; +} ELF_Shdr64; + +// X(name, code) +#define ELF_SectionTypeXList(X)\ +X(NULL, 0)\ +X(PROGBITS, 1)\ +X(SYMTAB, 2)\ +X(STRTAB, 3)\ +X(RELA, 4)\ +X(HASH, 5)\ +X(DYNAMIC, 6)\ +X(NOTE, 7)\ +X(NOBITS, 8)\ +X(REL, 9)\ +X(SHLIB, 10)\ +X(DYNSYM, 11)\ +X(INIT_ARRAY, 14)\ +X(FINI_ARRAY, 15)\ +X(PREINIT_ARRAY, 16)\ +X(GROUP, 17)\ +X(SYMTAB_SHNDX, 18)\ +X(LOOS, 0x60000000)\ +X(HIOS, 0x6FFFFFFF)\ +X(LOPROC, 0x70000000)\ +X(HIPROC, 0x7FFFFFFF)\ +X(LOUSER, 0x80000000)\ +X(HIUSER, 0x8FFFFFFF) + +typedef enum ELF_SectionType{ +#define X(N,C) ELF_SectionType_##N = C, + ELF_SectionTypeXList(X) +#undef X +} ELF_SectionType; + +typedef enum ELF_SectionAttributeFlags{ + ELF_SectionAttributeFlag_WRITE = 0x001, + ELF_SectionAttributeFlag_ALLOC = 0x002, + ELF_SectionAttributeFlag_EXECINSTR = 0x004, + ELF_SectionAttributeFlag_MERGE = 0x010, + ELF_SectionAttributeFlag_STRINGS = 0x020, + ELF_SectionAttributeFlag_INFO_LINK = 0x040, + ELF_SectionAttributeFlag_LINK_ORDER = 0x080, + ELF_SectionAttributeFlag_OS_NONCONFORMING = 0x100, + ELF_SectionAttributeFlag_GROUP = 0x200, + ELF_SectionAttributeFlag_TLS = 0x400, + ELF_SectionAttributeFlag_MASKOS = 0x0FF00000, + ELF_SectionAttributeFlag_MASKPROC = 0xF0000000, +} ELF_SectionAttributeFlags; + +typedef enum ELF_SectionGroupFlags{ + ELF_SectionGroupFlag_COMDAT = 0x1, + ELF_SectionGroupFlag_MASKOS = 0x0FF00000, + ELF_SectionGroupFlag_MASKPROC = 0xF0000000, +} ELF_SectionGroupFlags; + +typedef enum ELF_ReservedSymbolTableIndex{ + ELF_ReservedSymbolTableIndex_UNDEF = 0, +} ELF_ReservedSymbolTableIndex; + +// symbol table + +typedef struct ELF_Sym32{ + U32 st_name; + U32 st_value; + U32 st_size; + U8 st_info; + U8 st_other; + U16 st_shndx; +} ELF_Sym32; + +typedef struct ELF_Sym64{ + U32 st_name; + U8 st_info; + U8 st_other; + U16 st_shndx; + U64 st_value; + U64 st_size; +} ELF_Sym64; + +#define ELF_SymBindingFromInfo(x) (ELF_SymbolBinding)((x)>>4) +#define ELF_SymTypeFromInfo(x) (ELF_SymbolType)((x)&0xF) +#define ELF_SymInfoFromBindingType(b,t) ((((b)<<4)&0xF)|((t)&0xF)) + +#define ELF_SymVisibilityFromOther(x) ((x)&0x3) +#define ELF_SymOtherFromVisibility(x) ((x)&0x3) + +#define ELF_SymbolBindingXList(X)\ +X(LOCAL, 0)\ +X(GLOBAL, 1)\ +X(WEAK, 2)\ +X(LOOS, 10)\ +X(HIOS, 12)\ +X(LOPROC, 13)\ +X(HIPROC, 15)\ + +typedef enum ELF_SymbolBinding{ +#define X(N,C) ELF_SymbolBinding_##N = C, + ELF_SymbolBindingXList(X) +#undef X +} ELF_SymbolBinding; + +#define ELF_SymbolTypeXList(X)\ +X(NOTYPE, 0)\ +X(OBJECT, 1)\ +X(FUNC, 2)\ +X(SECTION, 3)\ +X(FILE, 4)\ +X(COMMON, 5)\ +X(TLS, 6)\ +X(LOOS, 10)\ +X(HIOS, 12)\ +X(LOPROC, 13)\ +X(HIPROC, 15) + +typedef enum ELF_SymbolType{ +#define X(N,C) ELF_SymbolType_##N = C, + ELF_SymbolTypeXList(X) +#undef X +} ELF_SymbolType; + +#define ELF_SymbolVisibilityXList(X)\ +X(DEFAULT, 0)\ +X(INTERNAL, 1)\ +X(HIDDEN, 2)\ +X(PROTECTED, 3) + +typedef enum ELF_SymbolVisibility{ +#define X(N,C) ELF_SymbolVisibility_##N = C, + ELF_SymbolVisibilityXList(X) +#undef X +} ELF_SymbolVisibility; + +// relocation + +typedef struct ELF_Rel32{ + U32 r_offset; + U32 r_info; +} ELF_Rel32; + +typedef struct ELF_Rela32{ + U32 r_offset; + U32 r_info; + S32 r_addend; +} ELF_Rela32; + +typedef struct ELF_Rel64{ + U64 r_offset; + U64 r_info; +} ELF_Rel64; + +typedef struct ELF_Rela64{ + U64 r_offset; + U64 r_info; + S64 r_addend; +} ELF_Rela64; + +#define ELF_RelSymIndexFromInfo32(x) ((x)>>8) +#define ELF_RelTypeFromInfo32(x) ((x)&0xF) +#define ELF_RelInfoFromSymIndexType32(n,t) (((n)<<8)|((t)&0xF)) + +#define ELF_RelSymIndexFromInfo64(x) ((x)>>32) +#define ELF_RelTypeFromInfo64(x) ((x)&0xFFFFFFFFL) +#define ELF_RelInfoFromSymIndexType64(n,t) (((n)<<8)|((t)&0xFFFFFFFFL)) + + + +// program header + +typedef struct ELF_Phdr32{ + U32 p_type; + U32 p_offset; + U32 p_vaddr; + U32 p_paddr; + U32 p_filesz; + U32 p_memsz; + U32 p_flags; + U32 p_align; +} ELF_Phdr32; + +typedef struct ELF_Phdr64{ + U32 p_type; + U32 p_flags; + U64 p_offset; + U64 p_vaddr; + U64 p_paddr; + U64 p_filesz; + U64 p_memsz; + U64 p_align; +} ELF_Phdr64; + +typedef enum ELF_SegmentType{ + ELF_SegmentType_NULL = 0, + ELF_SegmentType_LOAD = 1, + ELF_SegmentType_DYNAMIC = 2, + ELF_SegmentType_INTERP = 3, + ELF_SegmentType_NOTE = 4, + ELF_SegmentType_SHLIB = 5, + ELF_SegmentType_PHDR = 6, + ELF_SegmentType_TLS = 7, + ELF_SegmentType_LOOS = 0x60000000, + ELF_SegmentType_HIOS = 0x6fffffff, + ELF_SegmentType_LOPROC = 0x70000000, + ELF_SegmentType_HIPROC = 0x7fffffff, +} ELF_SegmentType; + +typedef enum ELF_SegmentFlags{ + ELF_SegmentFlag_X = 0x1, + ELF_SegmentFlag_W = 0x2, + ELF_SegmentFlag_R = 0x4, + ELF_SegmentFlag_MASKOS = 0x0FF00000, + ELF_SegmentFlag_MASKPROC = 0xF0000000, +} ELF_SegmentFlags; + +//////////////////////////////// +//~ ELF Parser Types + +// elf top level + +typedef struct ELF_SectionArray{ + ELF_Shdr64 *sections; + U64 count; +} ELF_SectionArray; + +typedef struct ELF_SegmentArray{ + ELF_Phdr64 *segments; + U64 count; +} ELF_SegmentArray; + +typedef struct ELF_Parsed{ + String8 data; + ELF_Class elf_class; + Architecture arch; + + ELF_Shdr64 *sections; + String8 *section_names; + U64 section_foff; + U64 section_count; + + ELF_Phdr64 *segments; + U64 segment_foff; + U64 segment_count; + + U64 vbase; + U64 entry_vaddr; + U64 section_name_table_foff; + U64 section_name_table_opl; + + U64 strtab_idx; + U64 symtab_idx; + U64 dynsym_idx; +} ELF_Parsed; + +// elf symtab + +typedef struct ELF_SymArray{ + ELF_Sym64 *symbols; + U64 count; +} ELF_SymArray; + +//////////////////////////////// +//~ ELF Parser Functions + +static ELF_Parsed* elf_parsed_from_data(Arena *arena, String8 elf_data); + +static ELF_SectionArray elf_section_array_from_elf(ELF_Parsed *elf); +static String8Array elf_section_name_array_from_elf(ELF_Parsed *elf); +static ELF_SegmentArray elf_segment_array_from_elf(ELF_Parsed *elf); + +static String8 elf_section_name_from_name_offset(ELF_Parsed *elf, U64 offset); +static String8 elf_section_name_from_idx(ELF_Parsed *elf, U32 idx); +static U32 elf_section_idx_from_name(ELF_Parsed *elf, String8 name); + +static String8 elf_section_data_from_idx(ELF_Parsed *elf, U32 idx); + +static ELF_SymArray elf_sym_array_from_data(Arena *arena, ELF_Class elf_class, String8 data); + +// string functions + +static String8 elf_string_from_section_type(ELF_SectionType section_type); +static String8 elf_string_from_symbol_binding(ELF_SymbolBinding binding); +static String8 elf_string_from_symbol_type(ELF_SymbolType type); +static String8 elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility); + +#endif //RADDBG_ELF_H diff --git a/src/raddbg_convert/dwarf/raddbg_from_dwarf.c b/src/raddbg_convert/dwarf/raddbg_from_dwarf.c new file mode 100644 index 00000000..76c013bc --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_from_dwarf.c @@ -0,0 +1,905 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "raddbg_format/raddbg_format.h" +#include "raddbg_cons/raddbg_cons.h" + +#include "raddbg_elf.h" +#include "raddbg_dwarf.h" + +#include "raddbg_dwarf_stringize.h" + +#include "raddbg_from_dwarf.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "raddbg_format/raddbg_format.c" +#include "raddbg_cons/raddbg_cons.c" + +#include "raddbg_elf.c" +#include "raddbg_dwarf.c" + +#include "raddbg_dwarf_stringize.c" + +// TODO(allen): +// [ ] need sample data for .debug_names + + +//////////////////////////////// +//~ Program Parameters Parser + +static DWARFCONV_Params* +dwarf_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline){ + DWARFCONV_Params *result = push_array(arena, DWARFCONV_Params, 1); + result->unit_idx_max = ~0ull; + + // get input pdb + { + String8 input_name = cmd_line_string(cmdline, str8_lit("elf")); + if (input_name.size == 0){ + str8_list_push(arena, &result->errors, + str8_lit("missing required parameter '--elf:'")); + } + + if (input_name.size > 0){ + String8 input_data = os_data_from_file_path(arena, input_name); + + if (input_data.size == 0){ + str8_list_pushf(arena, &result->errors, + "could not load input file '%.*s'", str8_varg(input_name)); + } + + if (input_data.size != 0){ + result->input_elf_name = input_name; + result->input_elf_data = input_data; + } + } + } + + // get output name + { + result->output_name = cmd_line_string(cmdline, str8_lit("out")); + } + + // error options + if (cmd_line_has_flag(cmdline, str8_lit("hide_errors"))){ + String8List vals = cmd_line_strings(cmdline, str8_lit("hide_errors")); + + // if no values - set all to hidden + if (vals.node_count == 0){ + B8 *ptr = (B8*)&result->hide_errors; + B8 *opl = ptr + sizeof(result->hide_errors); + for (;ptr < opl; ptr += 1){ + *ptr = 1; + } + } + + // for each explicit value set the corresponding flag to hidden + for (String8Node *node = vals.first; + node != 0; + node = node->next){ + if (str8_match(node->string, str8_lit("input"), 0)){ + result->hide_errors.input = 1; + } + } + + } + + // unit idx selector + if (cmd_line_has_flag(cmdline, str8_lit("unit_idx"))){ + String8List vals = cmd_line_strings(cmdline, str8_lit("unit_idx")); + + // single value unit index + if (vals.node_count == 1){ + U64 idx = u64_from_str8(vals.first->string, 10); + result->unit_idx_min = idx; + result->unit_idx_max = idx; + } + + // range value unit index + else if (vals.node_count >= 2){ + U64 idx_a = u64_from_str8(vals.first->string, 10); + U64 idx_b = u64_from_str8(vals.first->next->string, 10); + result->unit_idx_min = Min(idx_a, idx_b); + result->unit_idx_max = Max(idx_a, idx_b); + } + } + + // dump options + if (cmd_line_has_flag(cmdline, str8_lit("dump"))){ + result->dump = 1; + + String8List vals = cmd_line_strings(cmdline, str8_lit("dump")); + if (vals.first == 0){ + B8 *ptr = &result->dump__first; + for (; ptr < &result->dump__last; ptr += 1){ + *ptr = 1; + } + } + else{ + for (String8Node *node = vals.first; + node != 0; + node = node->next){ + if (str8_match(node->string, str8_lit("header"), 0)){ + result->dump_header = 1; + } + else if (str8_match(node->string, str8_lit("sections"), 0)){ + result->dump_sections = 1; + } + else if (str8_match(node->string, str8_lit("segments"), 0)){ + result->dump_segments = 1; + } + else if (str8_match(node->string, str8_lit("symtab"), 0)){ + result->dump_symtab = 1; + } + else if (str8_match(node->string, str8_lit("dynsym"), 0)){ + result->dump_dynsym = 1; + } + else if (str8_match(node->string, str8_lit("debug_sections"), 0)){ + result->dump_debug_sections = 1; + } + else if (str8_match(node->string, str8_lit("debug_info"), 0)){ + result->dump_debug_info = 1; + } + else if (str8_match(node->string, str8_lit("debug_abbrev"), 0)){ + result->dump_debug_abbrev = 1; + } + else if (str8_match(node->string, str8_lit("debug_pubnames"), 0)){ + result->dump_debug_pubnames = 1; + } + else if (str8_match(node->string, str8_lit("debug_pubtypes"), 0)){ + result->dump_debug_pubtypes = 1; + } + else if (str8_match(node->string, str8_lit("debug_names"), 0)){ + result->dump_debug_names = 1; + } + else if (str8_match(node->string, str8_lit("debug_aranges"), 0)){ + result->dump_debug_aranges = 1; + } + else if (str8_match(node->string, str8_lit("debug_addr"), 0)){ + result->dump_debug_addr = 1; + } + } + } + } + + return(result); +} + +//////////////////////////////// +//~ Entry Point + +static void +dump_symtab(Arena *arena, String8List *out, ELF_SymArray *symbols, String8 strtab, + U32 indent){ + static char spaces[] = " "; + + U8 *str_first = strtab.str; + U8 *str_opl = strtab.str + strtab.size; + + ELF_Sym64 *symbol = symbols->symbols; + U64 count = symbols->count; + for (U64 i = 0; i < count; i += 1, symbol += 1){ + U8 *name_first = str_first + symbol->st_name; + U8 *name_opl = name_first; + for (;name_opl < str_opl && *name_opl != 0;) name_opl += 1; + String8 name = str8_range(name_first, name_opl); + + ELF_SymbolBinding binding = ELF_SymBindingFromInfo(symbol->st_info); + String8 binding_string = elf_string_from_symbol_binding(binding); + + ELF_SymbolType type = ELF_SymTypeFromInfo(symbol->st_info); + String8 type_string = elf_string_from_symbol_type(type); + + ELF_SymbolVisibility vis = ELF_SymVisibilityFromOther(symbol->st_other); + String8 vis_string = elf_string_from_symbol_visibility(vis); + + str8_list_pushf(arena, out, + "%.*ssymbol[%5llu] %6.*s %7.*s %9.*s 0x%08llx size=%-5llu sec=%-5u " + "%.*s\n", + indent, spaces, i, + str8_varg(binding_string), str8_varg(type_string), + str8_varg(vis_string), + symbol->st_value, symbol->st_size, + symbol->st_shndx, str8_varg(name)); + } +} + +#if 0 +static void +dump_entry_tree(Arena *arena, String8List *out, + DWARF_Parsed *dwarf, DWARF_InfoUnit *unit, + DWARF_InfoEntry *entry, U32 indent){ + static char spaces[] = " "; + + DWARF_AbbrevDecl *abbrev_decl = entry->abbrev_decl; + + // tag + DWARF_Tag tag = abbrev_decl->tag; + String8 tag_string = dwarf_string_from_tag(tag); + str8_list_pushf(arena, out, "%.*sentry(@%llx) TAG %.*s\n", + indent, spaces, entry->info_offset, str8_varg(tag_string)); + + // attributes + U32 attrib_count = abbrev_decl->attrib_count; + DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs; + DWARF_InfoAttribVal *attrib_val = entry->attrib_vals; + for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){ + // attribute name + DWARF_AttributeName name = attrib_spec->name; + String8 name_string = dwarf_string_from_attribute_name(name); + str8_list_pushf(arena, out, "%.*sATTR %.*s ", indent + 4, spaces, str8_varg(name_string)); + + // attribute value + switch (attrib_spec->form){ + default: + { + String8 form_string = dwarf_string_from_attribute_form(attrib_spec->form); + str8_list_pushf(arena, out, " {%llu, 0x%p}\n", + str8_varg(form_string), attrib_val->val, attrib_val->dataptr); + }break; + + case DWARF_AttributeForm_strp: + { + String8 str = {0}; + + String8 data = dwarf->debug_data[DWARF_SectionCode_Str]; + U64 off = attrib_val->val; + if (off < data.size){ + U8 *start = data.str + off; + U8 *opl = data.str + data.size; + U8 *ptr = start; + for (;ptr < opl && *ptr != 0;) ptr += 1; + str = str8_range(start, ptr); + } + + str8_list_pushf(arena, out, "'%.*s'\n", str8_varg(str)); + }break; + + case DWARF_AttributeForm_sec_offset: + { + DWARF_AttributeClassFlags attr_classes1 = dwarf_attribute_class_from_name(name); + DWARF_AttributeClassFlags attr_classes2 = DWARF_AttributeClassFlag_sec_offset_classes; + DWARF_AttributeClassFlags attr_classes = attr_classes1&attr_classes2; + + DWARF_SectionCode sec_code = DWARF_SectionCode_Null; + if (unit->dwarf_version == 5){ + switch (attr_classes){ + case DWARF_AttributeClassFlag_addrptr: sec_code = DWARF_SectionCode_Addr; break; + case DWARF_AttributeClassFlag_lineptr: sec_code = DWARF_SectionCode_Line; break; + case DWARF_AttributeClassFlag_loclist: sec_code = DWARF_SectionCode_LocLists; break; + case DWARF_AttributeClassFlag_loclistsptr: sec_code = DWARF_SectionCode_LocLists; break; + case DWARF_AttributeClassFlag_macptr: sec_code = DWARF_SectionCode_Macro; break; + case DWARF_AttributeClassFlag_rnglist: sec_code = DWARF_SectionCode_RngLists; break; + case DWARF_AttributeClassFlag_rnglistsptr: sec_code = DWARF_SectionCode_RngLists; break; + case DWARF_AttributeClassFlag_stroffsetsptr: sec_code = DWARF_SectionCode_StrOffsets; break; + } + } + else if (unit->dwarf_version == 4){ + switch (attr_classes){ + case DWARF_AttributeClassFlag_lineptr: sec_code = DWARF_SectionCode_Line; break; + case DWARF_AttributeClassFlag_loclist: sec_code = DWARF_SectionCode_Loc; break; + case DWARF_AttributeClassFlag_macptr: sec_code = DWARF_SectionCode_MacInfo; break; + case DWARF_AttributeClassFlag_rnglist: sec_code = DWARF_SectionCode_Ranges; break; + } + } + + String8 sec_name = dwarf_name_from_debug_section(dwarf, sec_code); + str8_list_pushf(arena, out, "sec(%.*s) + %llu\n", str8_varg(sec_name), attrib_val->val); + }break; + + case DWARF_AttributeForm_ref1: + case DWARF_AttributeForm_ref2: + case DWARF_AttributeForm_ref4: + case DWARF_AttributeForm_ref8: + case DWARF_AttributeForm_ref_udata: + { + str8_list_pushf(arena, out, "entry(@%llx)\n", attrib_val->val); + }break; + + case DWARF_AttributeForm_addr: + { + str8_list_pushf(arena, out, "0x%llx\n", attrib_val->val); + }break; + + case DWARF_AttributeForm_exprloc: + { + str8_list_pushf(arena, out, "expression\n"); + // TODO(allen): dwarf expression dumping + }break; + + case DWARF_AttributeForm_strx1: + case DWARF_AttributeForm_strx2: + case DWARF_AttributeForm_strx3: + case DWARF_AttributeForm_strx4: + { + String8 str = {0}; + + U32 idx = attrib_val->val; + U64 str_offsets_off = unit->str_offsets_base + idx*unit->offset_size; + + String8 str_offsets = dwarf->debug_data[DWARF_SectionCode_StrOffsets]; + if (str_offsets_off + unit->offset_size < str_offsets.size){ + U64 off = 0; + MemoryCopy(&off, str_offsets.str + str_offsets_off, unit->offset_size); + + String8 data = dwarf->debug_data[DWARF_SectionCode_Str]; + if (off < data.size){ + U8 *start = data.str + off; + U8 *opl = data.str + data.size; + U8 *ptr = start; + for (;ptr < opl && *ptr != 0;) ptr += 1; + str = str8_range(start, ptr); + } + } + + str8_list_pushf(arena, out, "'%.*s'\n", str8_varg(str)); + }break; + + case DWARF_AttributeForm_addrx: + case DWARF_AttributeForm_addrx1: + case DWARF_AttributeForm_addrx2: + case DWARF_AttributeForm_addrx3: + case DWARF_AttributeForm_addrx4: + { + U64 address = 0; + + U32 idx = attrib_val->val; + U64 address_off = unit->addr_base + idx*unit->address_size; + + String8 data = dwarf->debug_data[DWARF_SectionCode_Addr]; + if (address_off + unit->address_size < data.size){ + MemoryCopy(&address, data.str + address_off, unit->address_size); + } + + str8_list_pushf(arena, out, "0x%x\n", address); + }break; + + case DWARF_AttributeForm_rnglistx: + { + U64 rnglist_off = unit->rnglists_base + attrib_val->val; + int x = 0; + }break; + + case DWARF_AttributeForm_data1: + case DWARF_AttributeForm_data2: + case DWARF_AttributeForm_data4: + case DWARF_AttributeForm_data8: + case DWARF_AttributeForm_data16: + case DWARF_AttributeForm_udata: + case DWARF_AttributeForm_implicit_const: + case DWARF_AttributeForm_flag: + case DWARF_AttributeForm_flag_present: + { + str8_list_pushf(arena, out, "%llu\n", attrib_val->val); + }break; + + case DWARF_AttributeForm_sdata: + { + str8_list_pushf(arena, out, "%lld\n", (S64)attrib_val->val); + }break; + + case DWARF_AttributeForm_string: + { + str8_list_pushf(arena, out, "'%.*s'\n", (int)attrib_val->val, attrib_val->dataptr); + }break; + } + } + + // dump children + for (DWARF_InfoEntry *child = entry->first_child; + child != 0; + child = child->next_sibling){ + dump_entry_tree(arena, out, dwarf, unit, child, indent + 1); + } +} +#endif + +int +main(int argc, char **argv){ + local_persist TCTX main_thread_tctx = {0}; + tctx_init_and_equip(&main_thread_tctx); + +#if PROFILE_TELEMETRY + U64 tm_data_size = GB(1); + U8 *tm_data = os_reserve(tm_data_size); + os_commit(tm_data, tm_data_size); + tmLoadLibrary(TM_RELEASE); + tmSetMaxThreadCount(1024); + tmInitialize(tm_data_size, tm_data); +#endif + + ThreadName("[main]"); + + Arena *arena = arena_alloc(); + String8List args = os_string_list_from_argcv(arena, argc, argv); + CmdLine cmdline = cmd_line_from_string_list(arena, args); + + ProfBeginCapture("raddbg_from_dwarf"); + + // parse arguments + DWARFCONV_Params *params = dwarf_convert_params_from_cmd_line(arena, &cmdline); + + // show input errors + if (params->errors.node_count > 0 && + !params->hide_errors.input){ + for (String8Node *node = params->errors.first; + node != 0; + node = node->next){ + fprintf(stdout, "error(input): %.*s\n", str8_varg(node->string)); + } + } + + // will we try to parse an input file? + B32 try_parse_input = (params->errors.node_count == 0); + + // track parse success + B32 successful_parse = 1; + +#define PARSE_CHECK_ERROR(p,fmt,...) do{ if ((p) == 0){ \ +successful_parse = 0; \ +fprintf(stdout, "error(parsing): " fmt "\n", __VA_ARGS__); \ +} }while(0) + + // parse elf + ELF_Parsed *elf = 0; + if (try_parse_input) ProfScope("parse elf"){ + elf = elf_parsed_from_data(arena, params->input_elf_data); + PARSE_CHECK_ERROR(elf, "ELF"); + } + + // parse strtab + String8 strtab = {0}; + if (elf != 0) ProfScope("parse strtab"){ + strtab = elf_section_data_from_idx(elf, elf->strtab_idx); + } + + // parse symtab + ELF_SymArray symtab = {0}; + if (elf != 0) ProfScope("parse symtab"){ + String8 data = elf_section_data_from_idx(elf, elf->symtab_idx); + symtab = elf_sym_array_from_data(arena, elf->elf_class, data); + } + + // parse dynsym + ELF_SymArray dynsym = {0}; + if (elf != 0) ProfScope("parse dynsym"){ + String8 data = elf_section_data_from_idx(elf, elf->dynsym_idx); + dynsym = elf_sym_array_from_data(arena, elf->elf_class, data); + } + + // parse dwarf + DWARF_Parsed *dwarf = 0; + if (elf != 0) ProfScope("parse dwarf"){ + dwarf = dwarf_parsed_from_elf(arena, elf); + PARSE_CHECK_ERROR(dwarf, "DWARF"); + } + + // parse info + DWARF_InfoParsed *info = 0; + if (dwarf != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_Info]; + if (data.size > 0) ProfScope("parse .debug_info"){ + info = dwarf_info_from_data(arena, data); + PARSE_CHECK_ERROR(info, "DEBUG INFO"); + } + } + + // parse pubnames + DWARF_PubNamesParsed *pubnames = 0; + if (dwarf != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_PubNames]; + if (data.size) ProfScope("parse .debug_pubnames"){ + pubnames = dwarf_pubnames_from_data(arena, data); + PARSE_CHECK_ERROR(pubnames, "DEBUG PUBNAMES"); + } + } + + // parse pubtypes + DWARF_PubNamesParsed *pubtypes = 0; + if (dwarf != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_PubTypes]; + if (data.size) ProfScope("parse .debug_pubtypes"){ + pubtypes = dwarf_pubnames_from_data(arena, data); + PARSE_CHECK_ERROR(pubtypes, "DEBUG PUBTYPES"); + } + } + + // parse names + DWARF_NamesParsed *names = 0; + if (dwarf != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_Names]; + if (data.size) ProfScope("parse .debug_names"){ + names = dwarf_names_from_data(arena, data); + PARSE_CHECK_ERROR(names, "DEBUG NAMES"); + } + } + + // parse aranges + DWARF_ArangesParsed *aranges = 0; + if (dwarf != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_Aranges]; + if (data.size) ProfScope("parse .debug_aranges"){ + aranges = dwarf_aranges_from_data(arena, data); + PARSE_CHECK_ERROR(aranges, "DEBUG ARANGES"); + } + } + + // parse addr + DWARF_AddrParsed *addr = 0; + if (dwarf != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_Addr]; + if (data.size) ProfScope("parse .debug_addr"){ + addr = dwarf_addr_from_data(arena, data); + PARSE_CHECK_ERROR(addr, "DEBUG ADDR"); + } + } + +#if 0 + // parse abbrev + DWARF_AbbrevParsed *abbrev = 0; + if (dwarf != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_Abbrev]; + if (data.size > 0) ProfScope("parse .debug_abbrev"){ + DWARF_AbbrevParams abbrev_params = {0}; + abbrev_params.unit_idx_min = params->unit_idx_min; + abbrev_params.unit_idx_max = params->unit_idx_max; + abbrev = dwarf_abbrev_from_data(arena, data, &abbrev_params); + PARSE_CHECK_ERROR(abbrev, "DEBUG ABBREV"); + } + } + + // parse info + DWARF_InfoParsed *info = 0; + if (abbrev != 0){ + String8 data = dwarf->debug_data[DWARF_SectionCode_Info]; + if (data.size > 0) ProfScope("parse .debug_info"){ + DWARF_InfoParams info_params = {0}; + info_params.unit_idx_min = params->unit_idx_min; + info_params.unit_idx_max = params->unit_idx_max; + info = dwarf_info_from_data(arena, data, &info_params, abbrev); + PARSE_CHECK_ERROR(info, "DEBUG INFO"); + } + } +#endif + + // dump + if (params->dump) ProfScope("dump"){ + String8List dump = {0}; + + // ELF + if (params->dump_header){ + if (elf != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "ELF:\n")); + + // TODO: better stringizers for fields here + str8_list_pushf(arena, &dump, " elf_class=%u\n", elf->elf_class); + str8_list_pushf(arena, &dump, " arch=%u\n", elf->arch); + str8_list_pushf(arena, &dump, " section_count=%llu\n", elf->section_count); + str8_list_pushf(arena, &dump, " segment_count=%llu\n", elf->segment_count); + str8_list_pushf(arena, &dump, " vbase=0x%llx\n", elf->vbase); + str8_list_pushf(arena, &dump, " entry_vaddr=0x%llx\n", elf->vbase); + + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + // SECTIONS + if (params->dump_sections){ + if (elf != 0){ + ELF_SectionArray section_array = elf_section_array_from_elf(elf); + String8Array section_name_array = elf_section_name_array_from_elf(elf); + + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "SECTIONS:\n")); + + ELF_Shdr64 *sec = section_array.sections; + String8 *sec_name = section_name_array.strings; + U64 count = section_array.count; + for (U64 i = 0 ; i < count; i += 1, sec += 1, sec_name += 1){ + String8 type_string = elf_string_from_section_type(sec->sh_type); + + // TODO: better stringizers for fields here + str8_list_pushf(arena, &dump, " section[%llu]:\n", i); + str8_list_pushf(arena, &dump, " name='%.*s'\n", str8_varg(*sec_name)); + str8_list_pushf(arena, &dump, " type=%.*s\n", str8_varg(type_string)); + str8_list_pushf(arena, &dump, " flags=0x%llx\n", sec->sh_flags); + str8_list_pushf(arena, &dump, " addr=0x%llx\n", sec->sh_addr); + str8_list_pushf(arena, &dump, " offset=0x%llx\n", sec->sh_offset); + str8_list_pushf(arena, &dump, " size=%llu\n", sec->sh_size); + str8_list_pushf(arena, &dump, " link=%u\n", sec->sh_link); + str8_list_pushf(arena, &dump, " info=%u\n", sec->sh_info); + str8_list_pushf(arena, &dump, " addralign=0x%llx\n", sec->sh_addralign); + str8_list_pushf(arena, &dump, " entsize=%llu\n", sec->sh_entsize); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + } + + // SYMTAB + if (symtab.count > 0 && params->dump_symtab){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "SYMTAB:\n")); + str8_list_pushf(arena, &dump, " section: %llu\n", elf->symtab_idx); + dump_symtab(arena, &dump, &symtab, strtab, 1); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // DYNSYM + if (dynsym.count > 0 && params->dump_dynsym){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DYNSYM:\n")); + str8_list_pushf(arena, &dump, " section: %llu\n", elf->dynsym_idx); + dump_symtab(arena, &dump, &dynsym, strtab, 1); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // SEGMENTS + if (params->dump_segments){ + if (elf != 0){ + ELF_SegmentArray segment_array = elf_segment_array_from_elf(elf); + + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "SEGMENTS:\n")); + + ELF_Phdr64 *segments = segment_array.segments; + U64 count = segment_array.count; + for (U64 i = 0 ; i < count; i += 1){ + ELF_Phdr64 *seg = segments + i; + + // TODO: better stringizers for fields here + str8_list_pushf(arena, &dump, " segment[%llu]:\n", i); + str8_list_pushf(arena, &dump, " p_type=%u\n", seg->p_type); + str8_list_pushf(arena, &dump, " p_flags=0x%x\n", seg->p_flags); + str8_list_pushf(arena, &dump, " p_offset=0x%llx\n", seg->p_offset); + str8_list_pushf(arena, &dump, " p_vaddr=0x%llx\n", seg->p_vaddr); + str8_list_pushf(arena, &dump, " p_paddr=0x%llx\n", seg->p_paddr); + str8_list_pushf(arena, &dump, " p_filesz=%llu\n", seg->p_filesz); + str8_list_pushf(arena, &dump, " p_memsz=%llu\n", seg->p_memsz); + str8_list_pushf(arena, &dump, " p_align=%llu\n", seg->p_align); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + } + + // DEBUG SECTIONS + if (params->dump_debug_sections){ + if (dwarf != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG SECTIONS:\n")); + + U32 *debug_section_idx = dwarf->debug_section_idx; + String8 *debug_data = dwarf->debug_data; + for (U32 i = 1; i < DWARF_SectionCode_COUNT; i += 1, debug_data += 1){ + U32 idx = debug_section_idx[i]; + String8 name = dwarf_string_from_section_code(i); + str8_list_pushf(arena, &dump, " %-10.*s section_idx=%u\n", str8_varg(name), idx); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + // DEBUG INFO + if (params->dump_debug_info){ + if (info != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG INFO:\n")); + + U32 i = 0; + for (DWARF_InfoUnit *unit = info->unit_first; + unit != 0; + unit = unit->next, i += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + dwarf_stringize_info(arena, &dump, unit, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + } + } + + // DEBUG PUBNAMES + if (params->dump_debug_pubnames){ + if (pubnames != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG PUBNAMES:\n")); + + U32 i = 0; + for (DWARF_PubNamesUnit *unit = pubnames->unit_first; + unit != 0; + unit = unit->next, i += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + dwarf_stringize_pubnames(arena, &dump, unit, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + } + } + + // DEBUG PUBTYPES + if (params->dump_debug_pubtypes){ + if (pubtypes != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG PUBTYPES:\n")); + + U32 i = 0; + for (DWARF_PubNamesUnit *unit = pubtypes->unit_first; + unit != 0; + unit = unit->next, i += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + dwarf_stringize_pubnames(arena, &dump, unit, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + } + } + + // DEBUG NAMES + if (params->dump_debug_names){ + if (names != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG NAMES:\n")); + + U32 i = 0; + for (DWARF_NamesUnit *unit = names->unit_first; + unit != 0; + unit = unit->next, i += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + dwarf_stringize_names(arena, &dump, unit, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + } + } + + // DEBUG ARANGES + if (params->dump_debug_aranges){ + if (aranges != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG ARANGES:\n")); + + U32 i = 0; + for (DWARF_ArangesUnit *unit = aranges->unit_first; + unit != 0; + unit = unit->next, i += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + dwarf_stringize_aranges(arena, &dump, unit, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + } + } + + // DEBUG ADDR + if (params->dump_debug_addr){ + if (addr != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG ADDR:\n")); + + U32 i = 0; + for (DWARF_AddrUnit *unit = addr->unit_first; + unit != 0; + unit = unit->next, i += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + dwarf_stringize_addr(arena, &dump, unit, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + } + } + +#if 0 + // DEBUG ABBREV + if (params->dump_debug_abbrev){ + if (abbrev != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG ABBREV:\n")); + + U32 i = 0; + for (DWARF_AbbrevUnit *unit = abbrev->unit_first; + unit != 0; + unit = unit->next, i += 1){ + U32 j = 0; + for (DWARF_AbbrevDecl *abbrev_decl = unit->first; + abbrev_decl != 0; + abbrev_decl = abbrev_decl->next, j += 1){ + String8 tag_string = dwarf_string_from_tag(abbrev_decl->tag); + + str8_list_pushf(arena, &dump, " unit[%u],abbrev[%u]:\n", i, j); + str8_list_pushf(arena, &dump, " code=%llu\n", abbrev_decl->abbrev_code); + str8_list_pushf(arena, &dump, " tag=%.*s\n", str8_varg(tag_string)); + str8_list_pushf(arena, &dump, " has_children=%u\n", abbrev_decl->has_children); + str8_list_pushf(arena, &dump, " attrib_count=%u\n", abbrev_decl->attrib_count); + str8_list_pushf(arena, &dump, " attribs:\n", abbrev_decl->attrib_count); + + U32 attrib_count = abbrev_decl->attrib_count; + DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs; + for (U32 k = 0; k < attrib_count; k += 1, attrib_spec += 1){ + String8 name_string = dwarf_string_from_attribute_name(attrib_spec->name); + String8 form_string = dwarf_string_from_attribute_form(attrib_spec->form); + + str8_list_pushf(arena, &dump, " [%-14.*s %-10.*s]\n", + str8_varg(name_string), str8_varg(form_string)); + } + + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + } + } +#endif + +#if 0 + // DEBUG INFO + if (params->dump_debug_info){ + if (info != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DEBUG INFO:\n")); + + U32 i = 0; + for (DWARF_InfoUnit *unit = info->unit_first; + unit != 0; + unit = unit->next, i += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + str8_list_pushf(arena, &dump, " [header]\n"); + str8_list_pushf(arena, &dump, " version=%u\n", unit->dwarf_version); + str8_list_pushf(arena, &dump, " offset_size=%u\n", unit->offset_size); + str8_list_pushf(arena, &dump, " address_size=%u\n", unit->address_size); + str8_list_pushf(arena, &dump, " [extracted attributes]\n"); + str8_list_pushf(arena, &dump, " langauge=%u\n", (U32)unit->language); + str8_list_pushf(arena, &dump, " line_info_offset=%llu\n", unit->line_info_offset); + str8_list_pushf(arena, &dump, " vbase=0x%llx\n", unit->vbase); + str8_list_pushf(arena, &dump, " str_offsets_base=%llu\n", unit->str_offsets_base); + str8_list_pushf(arena, &dump, " addr_base=%llu\n", unit->addr_base); + str8_list_pushf(arena, &dump, " rnglists_base=%llu\n", unit->rnglists_base); + str8_list_pushf(arena, &dump, " loclists_base=%llu\n", unit->loclists_base); + dump_entry_tree(arena, &dump, dwarf, unit, unit->entry_root, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + } + } +#endif + + // print dump + for (String8Node *node = dump.first; + node != 0; + node = node->next){ + fwrite(node->string.str, 1, node->string.size, stdout); + } + } + + ProfEndCapture(); + return(0); +} diff --git a/src/raddbg_convert/dwarf/raddbg_from_dwarf.h b/src/raddbg_convert/dwarf/raddbg_from_dwarf.h new file mode 100644 index 00000000..46ed6616 --- /dev/null +++ b/src/raddbg_convert/dwarf/raddbg_from_dwarf.h @@ -0,0 +1,50 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_FROM_DWARF_H +#define RADDBG_FROM_DWARF_H + +//////////////////////////////// +//~ Program Parameters Type + +typedef struct DWARFCONV_Params{ + String8 input_elf_name; + String8 input_elf_data; + + String8 output_name; + + U64 unit_idx_min; + U64 unit_idx_max; + + struct{ + B8 input; + } hide_errors; + + B8 dump; + B8 dump__first; + B8 dump_header; + B8 dump_sections; + B8 dump_segments; + B8 dump_symtab; + B8 dump_dynsym; + B8 dump_debug_sections; + B8 dump_debug_info; + B8 dump_debug_abbrev; + B8 dump_debug_pubnames; + B8 dump_debug_pubtypes; + B8 dump_debug_names; + B8 dump_debug_aranges; + B8 dump_debug_addr; + B8 dump__last; + + String8List errors; +} DWARFCONV_Params; + +//////////////////////////////// +//~ Program Parameters Parser + +static DWARFCONV_Params *dwarf_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline); + + + +#endif //RADDBG_FROM_DWARF_H diff --git a/src/raddbg_convert/pdb/raddbg_codeview.c b/src/raddbg_convert/pdb/raddbg_codeview.c new file mode 100644 index 00000000..099365e4 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_codeview.c @@ -0,0 +1,488 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ CodeView Common Functions + +static CV_NumericParsed +cv_numeric_from_data_range(U8 *first, U8 *opl){ + CV_NumericParsed result = {0}; + if (first + 2 <= opl){ + U16 x = *(U16*)first; + if (x < 0x8000){ + result.kind = CV_NumericKind_USHORT; + result.val = first; + result.encoded_size = 2; + } + else{ + U64 val_size = 0; + switch (x){ + case CV_NumericKind_CHAR: val_size = 1; break; + case CV_NumericKind_SHORT: + case CV_NumericKind_USHORT: val_size = 2; break; + case CV_NumericKind_LONG: + case CV_NumericKind_ULONG: val_size = 4; break; + case CV_NumericKind_FLOAT32: val_size = 4; break; + case CV_NumericKind_FLOAT64: val_size = 8; break; + case CV_NumericKind_FLOAT80: val_size = 10; break; + case CV_NumericKind_FLOAT128: val_size = 16; break; + case CV_NumericKind_QUADWORD: + case CV_NumericKind_UQUADWORD: val_size = 8; break; + case CV_NumericKind_FLOAT48: val_size = 6; break; + case CV_NumericKind_COMPLEX32: val_size = 8; break; + case CV_NumericKind_COMPLEX64: val_size = 16; break; + case CV_NumericKind_COMPLEX80: val_size = 20; break; + case CV_NumericKind_COMPLEX128:val_size = 32; break; + case CV_NumericKind_VARSTRING: val_size = 0; break; // TODO: ??? + case CV_NumericKind_OCTWORD: + case CV_NumericKind_UOCTWORD: val_size = 16; break; + case CV_NumericKind_DECIMAL: val_size = 0; break; // TODO: ??? + case CV_NumericKind_DATE: val_size = 0; break; // TODO: ??? + case CV_NumericKind_UTF8STRING:val_size = 0; break; // TODO: ??? + case CV_NumericKind_FLOAT16: val_size = 2; break; + } + + if (first + 2 + val_size <= opl){ + result.kind = x; + result.val = (first + 2); + result.encoded_size = 2 + val_size; + } + } + } + return(result); +} + +static B32 +cv_numeric_fits_in_u64(CV_NumericParsed *num){ + B32 result = 0; + switch (num->kind){ + case CV_NumericKind_USHORT: + case CV_NumericKind_ULONG: + case CV_NumericKind_UQUADWORD: + { + result = 1; + }break; + } + return(result); +} + +static B32 +cv_numeric_fits_in_s64(CV_NumericParsed *num){ + B32 result = 0; + switch (num->kind){ + case CV_NumericKind_CHAR: + case CV_NumericKind_SHORT: + case CV_NumericKind_LONG: + case CV_NumericKind_QUADWORD: + { + result = 1; + }break; + } + return(result); +} + +static B32 +cv_numeric_fits_in_f64(CV_NumericParsed *num){ + B32 result = 0; + switch (num->kind){ + case CV_NumericKind_FLOAT32: + case CV_NumericKind_FLOAT64: + { + result = 1; + }break; + } + return(result); +} + +static U64 +cv_u64_from_numeric(CV_NumericParsed *num){ + U64 result = 0; + switch (num->kind){ + case CV_NumericKind_USHORT: + { + result = *(U16*)num->val; + }break; + + case CV_NumericKind_ULONG: + { + result = *(U32*)num->val; + }break; + + case CV_NumericKind_UQUADWORD: + { + result = *(U64*)num->val; + }break; + } + return(result); +} + +static S64 +cv_s64_from_numeric(CV_NumericParsed *num){ + S64 result = 0; + switch (num->kind){ + case CV_NumericKind_CHAR: + { + result = *(S8*)num->val; + }break; + + case CV_NumericKind_SHORT: + { + result = *(S16*)num->val; + }break; + + case CV_NumericKind_LONG: + { + result = *(S32*)num->val; + }break; + + case CV_NumericKind_QUADWORD: + { + result = *(S64*)num->val; + }break; + } + return(result); +} + +static F64 +cv_f64_from_numeric(CV_NumericParsed *num){ + F64 result = 0; + switch (num->kind){ + case CV_NumericKind_FLOAT32: + { + result = *(F32*)num->val; + }break; + + case CV_NumericKind_FLOAT64: + { + result = *(F64*)num->val; + }break; + } + return(result); +} + + +//////////////////////////////// +//~ CodeView Sym Parser Functions + +static CV_SymParsed* +cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align){ + Assert(1 <= sym_align && IsPow2OrZero(sym_align)); + ProfBegin("cv_sym_from_data"); + + Temp scratch = scratch_begin(&arena, 1); + + // gather up symbols + CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, sym_data, sym_align); + + // convert to result + CV_SymParsed *result = push_array(arena, CV_SymParsed, 1); + result->data = sym_data; + result->sym_align = sym_align; + result->sym_ranges = cv_rec_range_array_from_stream(arena, stream); + cv_sym_top_level_info_from_syms(arena, sym_data, &result->sym_ranges, &result->info); + + scratch_end(scratch); + + ProfEnd(); + + return(result); +} + +static CV_LeafParsed* +cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId itype_first){ + ProfBegin("cv_leaf_from_data"); + + Temp scratch = scratch_begin(&arena, 1); + + // gather up symbols + CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, leaf_data, 1); + + // convert to result + CV_LeafParsed *result = push_array(arena, CV_LeafParsed, 1); + result->data = leaf_data; + result->itype_first = itype_first; + result->itype_opl = itype_first + stream->total_count; + result->leaf_ranges = cv_rec_range_array_from_stream(arena, stream); + + scratch_end(scratch); + + ProfEnd(); + + return(result); +} + +static CV_RecRangeStream* +cv_rec_range_stream_from_data(Arena *arena, String8 sym_data, U64 sym_align){ + Assert(1 <= sym_align && IsPow2OrZero(sym_align)); + + CV_RecRangeStream *result = push_array(arena, CV_RecRangeStream, 1); + + U8 *data = sym_data.str; + U64 cursor = 0; + U64 cap = sym_data.size; + for (;cursor + sizeof(CV_RecHeader) <= cap;){ + // setup a new chunk + arena_push_align(arena, 64); + CV_RecRangeChunk *cur_chunk = cv_rec_range_stream_push_chunk(arena, result); + + U64 partial_count = 0; + for (;partial_count < CV_REC_RANGE_CHUNK_SIZE && cursor + sizeof(CV_RecHeader) <= cap; + partial_count += 1){ + // compute cap + CV_RecHeader *hdr = (CV_RecHeader*)(data + cursor); + U64 symbol_cap_unclamped = cursor + 2 + hdr->size; + U64 symbol_cap = ClampTop(symbol_cap_unclamped, cap); + + // push on range + cur_chunk->ranges[partial_count].off = cursor + 2; + cur_chunk->ranges[partial_count].hdr = *hdr; + + // update cursor + U32 next_pos = AlignPow2(symbol_cap, sym_align); + cursor = next_pos; + } + + result->total_count += partial_count; + } + + return(result); +} + +static void +cv_sym_top_level_info_from_syms(Arena *arena, String8 sym_data, + CV_RecRangeArray *ranges, + CV_SymTopLevelInfo *info_out){ + MemoryZeroStruct(info_out); + + CV_RecRange *range = ranges->ranges; + CV_RecRange *opl = range + ranges->count; + for (; range < opl; range += 1){ + U8 *first = sym_data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + + switch (range->hdr.kind){ + case CV_SymKind_COMPILE: + { + if (sizeof(CV_SymCompile) <= cap){ + CV_SymCompile *compile = (CV_SymCompile*)first; + + String8 ver_str = str8_cstring_capped((char*)(compile + 1), (char *)(first + cap)); + + info_out->arch = compile->machine; + info_out->language = CV_CompileFlags_ExtractLanguage(compile->flags);; + info_out->compiler_name = ver_str; + } + }break; + + case CV_SymKind_COMPILE2: + { + if (sizeof(CV_SymCompile2) <= cap){ + CV_SymCompile2 *compile2 = (CV_SymCompile2*)first; + + String8 ver_str = str8_cstring_capped((char*)(compile2 + 1), (char*)(first + cap)); + String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u", + str8_varg(ver_str), + compile2->ver_major, + compile2->ver_minor, + compile2->ver_build); + + info_out->arch = compile2->machine; + info_out->language = CV_Compile2Flags_ExtractLanguage(compile2->flags);; + info_out->compiler_name = compiler_name; + } + }break; + + case CV_SymKind_COMPILE3: + { + if (sizeof(CV_SymCompile3) <= cap){ + CV_SymCompile3 *compile3 = (CV_SymCompile3*)first; + + String8 ver_str = str8_cstring_capped((char*)(compile3 + 1), (char *)(first + cap)); + String8 compiler_name = push_str8f(arena, "%.*s %u.%u.%u", + str8_varg(ver_str), + compile3->ver_major, + compile3->ver_minor, + compile3->ver_build); + + info_out->arch = compile3->machine; + info_out->language = CV_Compile3Flags_ExtractLanguage(compile3->flags);; + info_out->compiler_name = compiler_name; + } + }break; + } + } +} + + +//- range streams + +static CV_RecRangeChunk* +cv_rec_range_stream_push_chunk(Arena *arena, CV_RecRangeStream *stream){ + CV_RecRangeChunk *result = push_array_no_zero(arena, CV_RecRangeChunk, 1); + SLLQueuePush(stream->first_chunk, stream->last_chunk, result); + return(result); +} + +static CV_RecRangeArray +cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream){ + U64 total_count = stream->total_count; + CV_RecRange *ranges = push_array_no_zero(arena, CV_RecRange, total_count); + U64 idx = 0; + for (CV_RecRangeChunk *chunk = stream->first_chunk; + chunk != 0; + chunk = chunk->next){ + U64 copy_count_raw = total_count - idx; + U64 copy_count = ClampTop(copy_count_raw, CV_REC_RANGE_CHUNK_SIZE); + MemoryCopy(ranges + idx, chunk->ranges, copy_count*sizeof(CV_RecRange)); + idx += copy_count; + } + CV_RecRangeArray result = {0}; + result.ranges = ranges; + result.count = total_count; + return(result); +} + +//////////////////////////////// +//~ CodeView C13 Parser Functions + +static CV_C13Parsed* +cv_c13_from_data(Arena *arena, String8 c13_data, + PDB_Strtbl *strtbl, PDB_CoffSectionArray *sections){ + ProfBegin("cv_c13_from_data"); + + // gather c13 data + CV_C13SubSectionNode *file_chksms = 0; + CV_C13SubSectionNode *first = 0; + CV_C13SubSectionNode *last = 0; + U64 count = 0; + { + U32 cursor = 0; + for (; cursor + sizeof(CV_C13_SubSectionHeader) <= c13_data.size;){ + // read header + CV_C13_SubSectionHeader *hdr = (CV_C13_SubSectionHeader*)(c13_data.str + cursor); + + // get sub section info + U32 sub_section_off = cursor + sizeof(*hdr); + U32 sub_section_size_raw = hdr->size; + U32 after_sub_section_off_unclamped = sub_section_off + sub_section_size_raw; + U32 after_sub_section_off = ClampTop(after_sub_section_off_unclamped, c13_data.size); + U32 sub_section_size = after_sub_section_off - sub_section_off; + + // emit sub section + if (!(hdr->kind & CV_C13_SubSectionKind_IgnoreFlag)){ + CV_C13SubSectionNode *node = push_array(arena, CV_C13SubSectionNode, 1); + SLLQueuePush(first, last, node); + count += 1; + node->kind = hdr->kind; + node->off = sub_section_off; + node->size = sub_section_size; + + if (hdr->kind == CV_C13_SubSectionKind_FileChksms){ + file_chksms = node; + } + } + + // move cursor + cursor = AlignPow2(after_sub_section_off, 4); + } + } + + // parse each section + for (CV_C13SubSectionNode *node = first; + node != 0; + node = node->next){ + U8 *first = c13_data.str + node->off; + U32 cap = node->size; + + switch (node->kind){ + case CV_C13_SubSectionKind_Lines: + { + // read header + if (sizeof(CV_C13_SubSecLinesHeader) <= cap){ + CV_C13_SubSecLinesHeader *hdr = (CV_C13_SubSecLinesHeader*)first; + + // read file + U32 file_info_off = sizeof(*hdr); + if (file_info_off + sizeof(CV_C13_File) <= cap){ + CV_C13_File *file = (CV_C13_File*)(first + file_info_off); + + // extract top level info + U32 sec_idx = hdr->sec; + if (1 <= sec_idx && sec_idx <= sections->count){ + B32 has_cols = !!(hdr->flags & CV_C13_SubSecLinesFlag_HasColumns); + U64 secrel_off = hdr->sec_off; + U64 secrel_opl = secrel_off + hdr->len; + + U64 sec_base_off = sections->sections[sec_idx - 1].voff; + + U32 file_off = file->file_off; + U32 line_count_unclamped = file->num_lines; + U32 block_size = file->block_size; + + // file_name from file_off + String8 file_name = {0}; + if (file_off + sizeof(CV_C13_Checksum) <= file_chksms->size){ + CV_C13_Checksum *checksum = (CV_C13_Checksum*)(c13_data.str + file_chksms->off + file_off); + U32 name_off = checksum->name_off; + file_name = pdb_strtbl_string_from_off(strtbl, name_off); + } + + // array layouts + U32 line_item_size = sizeof(CV_C13_Line); + if (has_cols){ + line_item_size += sizeof(CV_C13_Column); + } + + U32 line_array_off = file_info_off + sizeof(*file); + U32 line_count_max = (cap - line_array_off)/line_item_size; + U32 line_count = ClampTop(line_count_unclamped, line_count_max); + + U32 col_array_off = line_array_off + line_count*sizeof(CV_C13_Line); + + // parse lines + U64 *voffs = push_array_no_zero(arena, U64, line_count + 1); + U32 *line_nums = push_array_no_zero(arena, U32, line_count); + + { + CV_C13_Line *line_ptr = (CV_C13_Line*)(first + line_array_off); + CV_C13_Line *line_opl = line_ptr + line_count; + + // TODO(allen): check order correctness here + + U32 i = 0; + for (; line_ptr < line_opl; line_ptr += 1, i += 1){ + voffs[i] = line_ptr->off + secrel_off + sec_base_off; + line_nums[i] = CV_C13_LineFlags_ExtractLineNumber(line_ptr->flags); + } + voffs[i] = secrel_opl + sec_base_off; + } + + // emit parsed lines + CV_C13LinesParsed *lines_parsed = push_array(arena, CV_C13LinesParsed, 1); + lines_parsed->sec_idx = sec_idx; + lines_parsed->file_off = file_off; + lines_parsed->secrel_base_off = secrel_off; + lines_parsed->file_name = file_name; + lines_parsed->voffs = voffs; + lines_parsed->line_nums = line_nums; + lines_parsed->line_count = line_count; + + node->lines = lines_parsed; + } + } + } + }break; + } + } + + // convert to result + CV_C13Parsed *result = push_array(arena, CV_C13Parsed, 1); + result->first_sub_section = first; + result->last_sub_section = last; + result->sub_section_count = count; + result->file_chksms_sub_section = file_chksms; + + ProfEnd(); + + return(result); +} diff --git a/src/raddbg_convert/pdb/raddbg_codeview.h b/src/raddbg_convert/pdb/raddbg_codeview.h new file mode 100644 index 00000000..70d60209 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_codeview.h @@ -0,0 +1,3055 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_CODEVIEW_H +#define RADDBG_CODEVIEW_H + +#pragma pack(push, 1) + +// https://github.com/microsoft/microsoft-pdb/blob/master/include/cvinfo.h + +//////////////////////////////// +//~ CodeView Format Shared Types + +typedef U32 CV_TypeId; +typedef U32 CV_ItemId; + +static CV_TypeId cv_type_id_variadic = 0xFFFFFFFF; + +typedef U16 CV_ModIndex; +typedef U16 CV_SectionIndex; + +typedef U16 CV_Reg; + +#define CV_NumericKindXList(X) \ +X(CHAR, 0x8000)\ +X(SHORT, 0x8001)\ +X(USHORT, 0x8002)\ +X(LONG, 0x8003)\ +X(ULONG, 0x8004)\ +X(FLOAT32, 0x8005)\ +X(FLOAT64, 0x8006)\ +X(FLOAT80, 0x8007)\ +X(FLOAT128, 0x8008)\ +X(QUADWORD, 0x8009)\ +X(UQUADWORD, 0x800a)\ +X(FLOAT48, 0x800b)\ +X(COMPLEX32, 0x800c)\ +X(COMPLEX64, 0x800d)\ +X(COMPLEX80, 0x800e)\ +X(COMPLEX128, 0x800f)\ +X(VARSTRING, 0x8010)\ +X(OCTWORD, 0x8017)\ +X(UOCTWORD, 0x8018)\ +X(DECIMAL, 0x8019)\ +X(DATE, 0x801a)\ +X(UTF8STRING, 0x801b)\ +X(FLOAT16, 0x801c) + +typedef U16 CV_NumericKind; +typedef enum{ +#define X(N,c) CV_NumericKind_##N = c, + CV_NumericKindXList(X) +#undef X +} CV_NumericKindEnum; + +#define CV_ArchXList(X) \ +X(8080, 0x00)\ +X(8086, 0x01)\ +X(80286, 0x02)\ +X(80386, 0x03)\ +X(80486, 0x04)\ +X(PENTIUM, 0x05)\ +X(PENTIUMII, 0x06)\ +X(PENTIUMIII, 0x07)\ +X(MIPS, 0x10)\ +X(MIPS16, 0x11)\ +X(MIPS32, 0x12)\ +X(MIPS64, 0x13)\ +X(MIPSI, 0x14)\ +X(MIPSII, 0x15)\ +X(MIPSIII, 0x16)\ +X(MIPSIV, 0x17)\ +X(MIPSV, 0x18)\ +X(M68000, 0x20)\ +X(M68010, 0x21)\ +X(M68020, 0x22)\ +X(M68030, 0x23)\ +X(M68040, 0x24)\ +X(ALPHA, 0x30)\ +X(ALPHA_21164, 0x31)\ +X(ALPHA_21164A, 0x32)\ +X(ALPHA_21264, 0x33)\ +X(ALPHA_21364, 0x34)\ +X(PPC601, 0x40)\ +X(PPC603, 0x41)\ +X(PPC604, 0x42)\ +X(PPC620, 0x43)\ +X(PPCFP, 0x44)\ +X(PPCBE, 0x45)\ +X(SH3, 0x50)\ +X(SH3E, 0x51)\ +X(SH3DSP, 0x52)\ +X(SH4, 0x53)\ +X(SHMEDIA, 0x54)\ +X(ARM3, 0x60)\ +X(ARM4, 0x61)\ +X(ARM4T, 0x62)\ +X(ARM5, 0x63)\ +X(ARM5T, 0x64)\ +X(ARM6, 0x65)\ +X(ARM_XMAC, 0x66)\ +X(ARM_WMMX, 0x67)\ +X(ARM7, 0x68)\ +X(OMNI, 0x70)\ +X(IA64_1, 0x80)\ +X(IA64_2, 0x81)\ +X(CEE, 0x90)\ +X(AM33, 0xA0)\ +X(M32R, 0xB0)\ +X(TRICORE, 0xC0)\ +X(X64, 0xD0)\ +X(EBC, 0xE0)\ +X(THUMB, 0xF0)\ +X(ARMNT, 0xF4)\ +X(ARM64, 0xF6)\ +X(D3D11_SHADER, 0x100) + +#define CV_Arch_IA64 CV_Arch_IA64_1 + +typedef U16 CV_Arch; +typedef enum{ +#define X(N,c) CV_Arch_##N = c, + CV_ArchXList(X) +#undef X +} CV_ArchEnum; +#define CV_Arch_PENTIUMPRO CV_Arch_PENTIUMII +#define CV_Arch_MIPSR4000 CV_Arch_MIPS +#define CV_Arch_ALPHA_21064 CV_Arch_ALPHA +#define CV_Arch_AMD64 CV_Arch_X64 + + +typedef U16 CV_Reg; + + +#define CV_AllRegXList(X) \ +X(ERR, 30000)\ +X(TEB, 30001)\ +X(TIMER, 30002)\ +X(EFAD1, 30003)\ +X(EFAD2, 30004)\ +X(EFAD3, 30005)\ +X(VFRAME, 30006)\ +X(HANDLE, 30007)\ +X(PARAMS, 30008)\ +X(LOCALS, 30009)\ +X(TID, 30010)\ +X(ENV, 30011)\ +X(CMDLN, 30012) + +typedef U16 CV_AllReg; +typedef enum{ +#define X(N,c) CV_AllReg_##N = c, + CV_AllRegXList(X) +#undef X +} CV_AllRegEnum; + + +// X(NAME, CODE, (RADDBG_RegsiterCode_X86) NAME, BYTE_POS, BYTE_SIZE) +#define CV_Reg_X86_XList(X) \ +X(NONE, 0, nil, 0, 0)\ +X(AL, 1, eax, 0, 1)\ +X(CL, 2, ecx, 0, 1)\ +X(DL, 3, edx, 0, 1)\ +X(BL, 4, ebx, 0, 1)\ +X(AH, 5, eax, 1, 1)\ +X(CH, 6, ecx, 1, 1)\ +X(DH, 7, edx, 1, 1)\ +X(BH, 8, ebx, 1, 1)\ +X(AX, 9, eax, 0, 2)\ +X(CX, 10, ecx, 0, 2)\ +X(DX, 11, edx, 0, 2)\ +X(BX, 12, ebx, 0, 2)\ +X(SP, 13, esp, 0, 2)\ +X(BP, 14, ebp, 0, 2)\ +X(SI, 15, esi, 0, 2)\ +X(DI, 16, edi, 0, 2)\ +X(EAX, 17, eax, 0, 4)\ +X(ECX, 18, ecx, 0, 4)\ +X(EDX, 19, edx, 0, 4)\ +X(EBX, 20, ebx, 0, 4)\ +X(ESP, 21, esp, 0, 4)\ +X(EBP, 22, ebp, 0, 4)\ +X(ESI, 23, esi, 0, 4)\ +X(EDI, 24, edi, 0, 4)\ +X(ES, 25, es, 0, 2)\ +X(CS, 26, cs, 0, 2)\ +X(SS, 27, ss, 0, 2)\ +X(DS, 28, ds, 0, 2)\ +X(FS, 29, fs, 0, 2)\ +X(GS, 30, gs, 0, 2)\ +X(IP, 31, eip, 0, 2)\ +X(FLAGS, 32, eflags, 0, 2)\ +X(EIP, 33, eip, 0, 4)\ +X(EFLAGS, 34, eflags, 0, 4)\ +X(MM0, 146, fpr0, 0, 8)\ +X(MM1, 147, fpr1, 0, 8)\ +X(MM2, 148, fpr2, 0, 8)\ +X(MM3, 149, fpr3, 0, 8)\ +X(MM4, 150, fpr4, 0, 8)\ +X(MM5, 151, fpr5, 0, 8)\ +X(MM6, 152, fpr6, 0, 8)\ +X(MM7, 153, fpr7, 0, 8)\ +X(XMM0, 154, ymm0, 0, 16)\ +X(XMM1, 155, ymm1, 0, 16)\ +X(XMM2, 156, ymm2, 0, 16)\ +X(XMM3, 157, ymm3, 0, 16)\ +X(XMM4, 158, ymm4, 0, 16)\ +X(XMM5, 159, ymm5, 0, 16)\ +X(XMM6, 160, ymm6, 0, 16)\ +X(XMM7, 161, ymm7, 0, 16)\ +X(XMM00, 162, ymm0, 0, 4)\ +X(XMM01, 163, ymm0, 4, 4)\ +X(XMM02, 164, ymm0, 8, 4)\ +X(XMM03, 165, ymm0, 12, 4)\ +X(XMM10, 166, ymm1, 0, 4)\ +X(XMM11, 167, ymm1, 4, 4)\ +X(XMM12, 168, ymm1, 8, 4)\ +X(XMM13, 169, ymm1, 12, 4)\ +X(XMM20, 170, ymm2, 0, 4)\ +X(XMM21, 171, ymm2, 4, 4)\ +X(XMM22, 172, ymm2, 8, 4)\ +X(XMM23, 173, ymm2, 12, 4)\ +X(XMM30, 174, ymm3, 0, 4)\ +X(XMM31, 175, ymm3, 4, 4)\ +X(XMM32, 176, ymm3, 8, 4)\ +X(XMM33, 177, ymm3, 12, 4)\ +X(XMM40, 178, ymm4, 0, 4)\ +X(XMM41, 179, ymm4, 4, 4)\ +X(XMM42, 180, ymm4, 8, 4)\ +X(XMM43, 181, ymm4, 12, 4)\ +X(XMM50, 182, ymm5, 0, 4)\ +X(XMM51, 183, ymm5, 4, 4)\ +X(XMM52, 184, ymm5, 8, 4)\ +X(XMM53, 185, ymm5, 12, 4)\ +X(XMM60, 186, ymm6, 0, 4)\ +X(XMM61, 187, ymm6, 4, 4)\ +X(XMM62, 188, ymm6, 8, 4)\ +X(XMM63, 189, ymm6, 12, 4)\ +X(XMM70, 190, ymm7, 0, 4)\ +X(XMM71, 191, ymm7, 4, 4)\ +X(XMM72, 192, ymm7, 8, 4)\ +X(XMM73, 193, ymm7, 12, 4)\ +X(XMM0L, 194, ymm0, 0, 8)\ +X(XMM1L, 195, ymm1, 0, 8)\ +X(XMM2L, 196, ymm2, 0, 8)\ +X(XMM3L, 197, ymm3, 0, 8)\ +X(XMM4L, 198, ymm4, 0, 8)\ +X(XMM5L, 199, ymm5, 0, 8)\ +X(XMM6L, 200, ymm6, 0, 8)\ +X(XMM7L, 201, ymm7, 0, 8)\ +X(XMM0H, 202, ymm0, 8, 8)\ +X(XMM1H, 203, ymm1, 8, 8)\ +X(XMM2H, 204, ymm2, 8, 8)\ +X(XMM3H, 205, ymm3, 8, 8)\ +X(XMM4H, 206, ymm4, 8, 8)\ +X(XMM5H, 207, ymm5, 8, 8)\ +X(XMM6H, 208, ymm6, 8, 8)\ +X(XMM7H, 209, ymm7, 8, 8)\ +X(YMM0, 252, ymm0, 0, 32)\ +X(YMM1, 253, ymm1, 0, 32)\ +X(YMM2, 254, ymm2, 0, 32)\ +X(YMM3, 255, ymm3, 0, 32)\ +X(YMM4, 256, ymm4, 0, 32)\ +X(YMM5, 257, ymm5, 0, 32)\ +X(YMM6, 258, ymm6, 0, 32)\ +X(YMM7, 259, ymm7, 0, 32)\ +X(YMM0H, 260, ymm0, 16, 16)\ +X(YMM1H, 261, ymm1, 16, 16)\ +X(YMM2H, 262, ymm2, 16, 16)\ +X(YMM3H, 263, ymm3, 16, 16)\ +X(YMM4H, 264, ymm4, 16, 16)\ +X(YMM5H, 265, ymm5, 16, 16)\ +X(YMM6H, 266, ymm6, 16, 16)\ +X(YMM7H, 267, ymm7, 16, 16)\ +X(YMM0I0, 268, ymm0, 0, 8)\ +X(YMM0I1, 269, ymm0, 8, 8)\ +X(YMM0I2, 270, ymm0, 16, 8)\ +X(YMM0I3, 271, ymm0, 24, 8)\ +X(YMM1I0, 272, ymm1, 0, 8)\ +X(YMM1I1, 273, ymm1, 8, 8)\ +X(YMM1I2, 274, ymm1, 16, 8)\ +X(YMM1I3, 275, ymm1, 24, 8)\ +X(YMM2I0, 276, ymm2, 0, 8)\ +X(YMM2I1, 277, ymm2, 8, 8)\ +X(YMM2I2, 278, ymm2, 16, 8)\ +X(YMM2I3, 279, ymm2, 24, 8)\ +X(YMM3I0, 280, ymm3, 0, 8)\ +X(YMM3I1, 281, ymm3, 8, 8)\ +X(YMM3I2, 282, ymm3, 16, 8)\ +X(YMM3I3, 283, ymm3, 24, 8)\ +X(YMM4I0, 284, ymm4, 0, 8)\ +X(YMM4I1, 285, ymm4, 8, 8)\ +X(YMM4I2, 286, ymm4, 16, 8)\ +X(YMM4I3, 287, ymm4, 24, 8)\ +X(YMM5I0, 288, ymm5, 0, 8)\ +X(YMM5I1, 289, ymm5, 8, 8)\ +X(YMM5I2, 290, ymm5, 16, 8)\ +X(YMM5I3, 291, ymm5, 24, 8)\ +X(YMM6I0, 292, ymm6, 0, 8)\ +X(YMM6I1, 293, ymm6, 8, 8)\ +X(YMM6I2, 294, ymm6, 16, 8)\ +X(YMM6I3, 295, ymm6, 24, 8)\ +X(YMM7I0, 296, ymm7, 0, 8)\ +X(YMM7I1, 297, ymm7, 8, 8)\ +X(YMM7I2, 298, ymm7, 16, 8)\ +X(YMM7I3, 299, ymm7, 24, 8)\ +X(YMM0F0, 300, ymm0, 0, 4)\ +X(YMM0F1, 301, ymm0, 4, 4)\ +X(YMM0F2, 302, ymm0, 8, 4)\ +X(YMM0F3, 303, ymm0, 12, 4)\ +X(YMM0F4, 304, ymm0, 16, 4)\ +X(YMM0F5, 305, ymm0, 20, 4)\ +X(YMM0F6, 306, ymm0, 24, 4)\ +X(YMM0F7, 307, ymm0, 28, 4)\ +X(YMM1F0, 308, ymm1, 0, 4)\ +X(YMM1F1, 309, ymm1, 4, 4)\ +X(YMM1F2, 310, ymm1, 8, 4)\ +X(YMM1F3, 311, ymm1, 12, 4)\ +X(YMM1F4, 312, ymm1, 16, 4)\ +X(YMM1F5, 313, ymm1, 20, 4)\ +X(YMM1F6, 314, ymm1, 24, 4)\ +X(YMM1F7, 315, ymm1, 28, 4)\ +X(YMM2F0, 316, ymm2, 0, 4)\ +X(YMM2F1, 317, ymm2, 4, 4)\ +X(YMM2F2, 318, ymm2, 8, 4)\ +X(YMM2F3, 319, ymm2, 12, 4)\ +X(YMM2F4, 320, ymm2, 16, 4)\ +X(YMM2F5, 321, ymm2, 20, 4)\ +X(YMM2F6, 322, ymm2, 24, 4)\ +X(YMM2F7, 323, ymm2, 28, 4)\ +X(YMM3F0, 324, ymm3, 0, 4)\ +X(YMM3F1, 325, ymm3, 4, 4)\ +X(YMM3F2, 326, ymm3, 8, 4)\ +X(YMM3F3, 327, ymm3, 12, 4)\ +X(YMM3F4, 328, ymm3, 16, 4)\ +X(YMM3F5, 329, ymm3, 20, 4)\ +X(YMM3F6, 330, ymm3, 24, 4)\ +X(YMM3F7, 331, ymm3, 28, 4)\ +X(YMM4F0, 332, ymm4, 0, 4)\ +X(YMM4F1, 333, ymm4, 4, 4)\ +X(YMM4F2, 334, ymm4, 8, 4)\ +X(YMM4F3, 335, ymm4, 12, 4)\ +X(YMM4F4, 336, ymm4, 16, 4)\ +X(YMM4F5, 337, ymm4, 20, 4)\ +X(YMM4F6, 338, ymm4, 24, 4)\ +X(YMM4F7, 339, ymm4, 28, 4)\ +X(YMM5F0, 340, ymm5, 0, 4)\ +X(YMM5F1, 341, ymm5, 4, 4)\ +X(YMM5F2, 342, ymm5, 8, 4)\ +X(YMM5F3, 343, ymm5, 12, 4)\ +X(YMM5F4, 344, ymm5, 16, 4)\ +X(YMM5F5, 345, ymm5, 20, 4)\ +X(YMM5F6, 346, ymm5, 24, 4)\ +X(YMM5F7, 347, ymm5, 28, 4)\ +X(YMM6F0, 348, ymm6, 0, 4)\ +X(YMM6F1, 349, ymm6, 4, 4)\ +X(YMM6F2, 350, ymm6, 8, 4)\ +X(YMM6F3, 351, ymm6, 12, 4)\ +X(YMM6F4, 352, ymm6, 16, 4)\ +X(YMM6F5, 353, ymm6, 20, 4)\ +X(YMM6F6, 354, ymm6, 24, 4)\ +X(YMM6F7, 355, ymm6, 28, 4)\ +X(YMM7F0, 356, ymm7, 0, 4)\ +X(YMM7F1, 357, ymm7, 4, 4)\ +X(YMM7F2, 358, ymm7, 8, 4)\ +X(YMM7F3, 359, ymm7, 12, 4)\ +X(YMM7F4, 360, ymm7, 16, 4)\ +X(YMM7F5, 361, ymm7, 20, 4)\ +X(YMM7F6, 362, ymm7, 24, 4)\ +X(YMM7F7, 363, ymm7, 28, 4)\ +X(YMM0D0, 364, ymm0, 0, 8)\ +X(YMM0D1, 365, ymm0, 8, 8)\ +X(YMM0D2, 366, ymm0, 16, 8)\ +X(YMM0D3, 367, ymm0, 24, 8)\ +X(YMM1D0, 368, ymm1, 0, 8)\ +X(YMM1D1, 369, ymm1, 8, 8)\ +X(YMM1D2, 370, ymm1, 16, 8)\ +X(YMM1D3, 371, ymm1, 24, 8)\ +X(YMM2D0, 372, ymm2, 0, 8)\ +X(YMM2D1, 373, ymm2, 8, 8)\ +X(YMM2D2, 374, ymm2, 16, 8)\ +X(YMM2D3, 375, ymm2, 24, 8)\ +X(YMM3D0, 376, ymm3, 0, 8)\ +X(YMM3D1, 377, ymm3, 8, 8)\ +X(YMM3D2, 378, ymm3, 16, 8)\ +X(YMM3D3, 379, ymm3, 24, 8)\ +X(YMM4D0, 380, ymm4, 0, 8)\ +X(YMM4D1, 381, ymm4, 8, 8)\ +X(YMM4D2, 382, ymm4, 16, 8)\ +X(YMM4D3, 383, ymm4, 24, 8)\ +X(YMM5D0, 384, ymm5, 0, 8)\ +X(YMM5D1, 385, ymm5, 8, 8)\ +X(YMM5D2, 386, ymm5, 16, 8)\ +X(YMM5D3, 387, ymm5, 24, 8)\ +X(YMM6D0, 388, ymm6, 0, 8)\ +X(YMM6D1, 389, ymm6, 8, 8)\ +X(YMM6D2, 390, ymm6, 16, 8)\ +X(YMM6D3, 391, ymm6, 24, 8)\ +X(YMM7D0, 392, ymm7, 0, 8)\ +X(YMM7D1, 393, ymm7, 8, 8)\ +X(YMM7D2, 394, ymm7, 16, 8)\ +X(YMM7D3, 395, ymm7, 24, 8) + +typedef U16 CV_Regx86; +typedef enum{ +#define X(CVN,C,RDN,BP,BZ) CV_Regx86_##CVN = C, + CV_Reg_X86_XList(X) +#undef X +} CV_Regx86Enum; + +// X(NAME, CODE, (RADDBG_RegsiterCode_X64) NAME, BYTE_POS, BYTE_SIZE) +#define CV_Reg_X64_XList(X) \ +X(NONE, 0, nil, 0, 0)\ +X(AL, 1, rax, 0, 1)\ +X(CL, 2, rcx, 0, 1)\ +X(DL, 3, rdx, 0, 1)\ +X(BL, 4, rbx, 0, 1)\ +X(AH, 5, rax, 1, 1)\ +X(CH, 6, rcx, 1, 1)\ +X(DH, 7, rdx, 1, 1)\ +X(BH, 8, rbx, 1, 1)\ +X(AX, 9, rax, 0, 2)\ +X(CX, 10, rcx, 0, 2)\ +X(DX, 11, rdx, 0, 2)\ +X(BX, 12, rbx, 0, 2)\ +X(SP, 13, rsp, 0, 2)\ +X(BP, 14, rbp, 0, 2)\ +X(SI, 15, rsi, 0, 2)\ +X(DI, 16, rdi, 0, 2)\ +X(EAX, 17, rax, 0, 4)\ +X(ECX, 18, rcx, 0, 4)\ +X(EDX, 19, rdx, 0, 4)\ +X(EBX, 20, rbx, 0, 4)\ +X(ESP, 21, rsp, 0, 4)\ +X(EBP, 22, rbp, 0, 4)\ +X(ESI, 23, rsi, 0, 4)\ +X(EDI, 24, rdi, 0, 4)\ +X(ES, 25, es, 0, 2)\ +X(CS, 26, cs, 0, 2)\ +X(SS, 27, ss, 0, 2)\ +X(DS, 28, ds, 0, 2)\ +X(FS, 29, fs, 0, 2)\ +X(GS, 30, gs, 0, 2)\ +X(FLAGS, 32, rflags, 0, 2)\ +X(RIP, 33, rip, 0, 8)\ +X(EFLAGS, 34, rflags, 0, 4)\ +/* TODO: possibly missing control registers in x64 definitions? */ \ +X(CR0, 80, nil, 0, 0)\ +X(CR1, 81, nil, 0, 0)\ +X(CR2, 82, nil, 0, 0)\ +X(CR3, 83, nil, 0, 0)\ +X(CR4, 84, nil, 0, 0)\ +X(CR8, 88, nil, 0, 0)\ +X(DR0, 90, dr0, 0, 4)\ +X(DR1, 91, dr1, 0, 4)\ +X(DR2, 92, dr2, 0, 4)\ +X(DR3, 93, dr3, 0, 4)\ +X(DR4, 94, dr4, 0, 4)\ +X(DR5, 95, dr5, 0, 4)\ +X(DR6, 96, dr6, 0, 4)\ +X(DR7, 97, dr7, 0, 4)\ +/* TODO: possibly missing debug registers 8-15 in x64 definitions? */ \ +X(DR8, 98, nil, 0, 0)\ +X(DR9, 99, nil, 0, 0)\ +X(DR10, 100, nil, 0, 0)\ +X(DR11, 101, nil, 0, 0)\ +X(DR12, 102, nil, 0, 0)\ +X(DR13, 103, nil, 0, 0)\ +X(DR14, 104, nil, 0, 0)\ +X(DR15, 105, nil, 0, 0)\ +/* TODO: possibly missing ~whatever these are~ in x64 definitions? */ \ +X(GDTR, 110, nil, 0, 0)\ +X(GDTL, 111, nil, 0, 0)\ +X(IDTR, 112, nil, 0, 0)\ +X(IDTL, 113, nil, 0, 0)\ +X(LDTR, 114, nil, 0, 0)\ +X(TR, 115, nil, 0, 0)\ +X(ST0, 128, st0, 0, 10)\ +X(ST1, 129, st1, 0, 10)\ +X(ST2, 130, st2, 0, 10)\ +X(ST3, 131, st3, 0, 10)\ +X(ST4, 132, st4, 0, 10)\ +X(ST5, 133, st5, 0, 10)\ +X(ST6, 134, st6, 0, 10)\ +X(ST7, 135, st7, 0, 10)\ +/* TODO: possibly missing these, or not sure how they map to our x64 definitions? */ \ +X(CTRL, 136, nil, 0, 0)\ +X(STAT, 137, nil, 0, 0)\ +X(TAG, 138, nil, 0, 0)\ +X(FPIP, 139, nil, 0, 0)\ +X(FPCS, 140, nil, 0, 0)\ +X(FPDO, 141, nil, 0, 0)\ +X(FPDS, 142, nil, 0, 0)\ +X(ISEM, 143, nil, 0, 0)\ +X(FPEIP, 144, nil, 0, 0)\ +X(FPEDO, 145, nil, 0, 0)\ +X(MM0, 146, fpr0, 0, 8)\ +X(MM1, 147, fpr1, 0, 8)\ +X(MM2, 148, fpr2, 0, 8)\ +X(MM3, 149, fpr3, 0, 8)\ +X(MM4, 150, fpr4, 0, 8)\ +X(MM5, 151, fpr5, 0, 8)\ +X(MM6, 152, fpr6, 0, 8)\ +X(MM7, 153, fpr7, 0, 8)\ +X(XMM0, 154, ymm0, 0, 16)\ +X(XMM1, 155, ymm1, 0, 16)\ +X(XMM2, 156, ymm2, 0, 16)\ +X(XMM3, 157, ymm3, 0, 16)\ +X(XMM4, 158, ymm4, 0, 16)\ +X(XMM5, 159, ymm5, 0, 16)\ +X(XMM6, 160, ymm6, 0, 16)\ +X(XMM7, 161, ymm7, 0, 16)\ +X(XMM0_0, 162, ymm0, 0, 4)\ +X(XMM0_1, 163, ymm0, 4, 4)\ +X(XMM0_2, 164, ymm0, 8, 4)\ +X(XMM0_3, 165, ymm0, 12, 4)\ +X(XMM1_0, 166, ymm1, 0, 4)\ +X(XMM1_1, 167, ymm1, 4, 4)\ +X(XMM1_2, 168, ymm1, 8, 4)\ +X(XMM1_3, 169, ymm1, 12, 4)\ +X(XMM2_0, 170, ymm2, 0, 4)\ +X(XMM2_1, 171, ymm2, 4, 4)\ +X(XMM2_2, 172, ymm2, 8, 4)\ +X(XMM2_3, 173, ymm2, 12, 4)\ +X(XMM3_0, 174, ymm3, 0, 4)\ +X(XMM3_1, 175, ymm3, 4, 4)\ +X(XMM3_2, 176, ymm3, 8, 4)\ +X(XMM3_3, 177, ymm3, 12, 4)\ +X(XMM4_0, 178, ymm4, 0, 4)\ +X(XMM4_1, 179, ymm4, 4, 4)\ +X(XMM4_2, 180, ymm4, 8, 4)\ +X(XMM4_3, 181, ymm4, 12, 4)\ +X(XMM5_0, 182, ymm5, 0, 4)\ +X(XMM5_1, 183, ymm5, 4, 4)\ +X(XMM5_2, 184, ymm5, 8, 4)\ +X(XMM5_3, 185, ymm5, 12, 4)\ +X(XMM6_0, 186, ymm6, 0, 4)\ +X(XMM6_1, 187, ymm6, 4, 4)\ +X(XMM6_2, 188, ymm6, 8, 4)\ +X(XMM6_3, 189, ymm6, 12, 4)\ +X(XMM7_0, 190, ymm7, 0, 4)\ +X(XMM7_1, 191, ymm7, 4, 4)\ +X(XMM7_2, 192, ymm7, 8, 4)\ +X(XMM7_3, 193, ymm7, 12, 4)\ +X(XMM0L, 194, ymm0, 0, 8)\ +X(XMM1L, 195, ymm1, 0, 8)\ +X(XMM2L, 196, ymm2, 0, 8)\ +X(XMM3L, 197, ymm3, 0, 8)\ +X(XMM4L, 198, ymm4, 0, 8)\ +X(XMM5L, 199, ymm5, 0, 8)\ +X(XMM6L, 200, ymm6, 0, 8)\ +X(XMM7L, 201, ymm7, 0, 8)\ +X(XMM0H, 202, ymm0, 8, 8)\ +X(XMM1H, 203, ymm1, 8, 8)\ +X(XMM2H, 204, ymm2, 8, 8)\ +X(XMM3H, 205, ymm3, 8, 8)\ +X(XMM4H, 206, ymm4, 8, 8)\ +X(XMM5H, 207, ymm5, 8, 8)\ +X(XMM6H, 208, ymm6, 8, 8)\ +X(XMM7H, 209, ymm7, 8, 8)\ +X(MXCSR, 211, mxcsr, 0, 4)\ +X(EMM0L, 220, ymm0, 0, 8)\ +X(EMM1L, 221, ymm1, 0, 8)\ +X(EMM2L, 222, ymm2, 0, 8)\ +X(EMM3L, 223, ymm3, 0, 8)\ +X(EMM4L, 224, ymm4, 0, 8)\ +X(EMM5L, 225, ymm5, 0, 8)\ +X(EMM6L, 226, ymm6, 0, 8)\ +X(EMM7L, 227, ymm7, 0, 8)\ +X(EMM0H, 228, ymm0, 8, 8)\ +X(EMM1H, 229, ymm1, 8, 8)\ +X(EMM2H, 230, ymm2, 8, 8)\ +X(EMM3H, 231, ymm3, 8, 8)\ +X(EMM4H, 232, ymm4, 8, 8)\ +X(EMM5H, 233, ymm5, 8, 8)\ +X(EMM6H, 234, ymm6, 8, 8)\ +X(EMM7H, 235, ymm7, 8, 8)\ +X(MM00, 236, fpr0, 0, 4)\ +X(MM01, 237, fpr0, 4, 4)\ +X(MM10, 238, fpr1, 0, 4)\ +X(MM11, 239, fpr1, 4, 4)\ +X(MM20, 240, fpr2, 0, 4)\ +X(MM21, 241, fpr2, 4, 4)\ +X(MM30, 242, fpr3, 0, 4)\ +X(MM31, 243, fpr3, 4, 4)\ +X(MM40, 244, fpr4, 0, 4)\ +X(MM41, 245, fpr4, 4, 4)\ +X(MM50, 246, fpr5, 0, 4)\ +X(MM51, 247, fpr5, 4, 4)\ +X(MM60, 248, fpr6, 0, 4)\ +X(MM61, 249, fpr6, 4, 4)\ +X(MM70, 250, fpr7, 0, 4)\ +X(MM71, 251, fpr7, 4, 4)\ +X(XMM8, 252, ymm8, 0, 16)\ +X(XMM9, 253, ymm9, 0, 16)\ +X(XMM10, 254, ymm10, 0, 16)\ +X(XMM11, 255, ymm11, 0, 16)\ +X(XMM12, 256, ymm12, 0, 16)\ +X(XMM13, 257, ymm13, 0, 16)\ +X(XMM14, 258, ymm14, 0, 16)\ +X(XMM15, 259, ymm15, 0, 16)\ +X(XMM8_0, 260, ymm8, 0, 16)\ +X(XMM8_1, 261, ymm8, 4, 16)\ +X(XMM8_2, 262, ymm8, 8, 16)\ +X(XMM8_3, 263, ymm8, 12, 16)\ +X(XMM9_0, 264, ymm9, 0, 4)\ +X(XMM9_1, 265, ymm9, 4, 4)\ +X(XMM9_2, 266, ymm9, 8, 4)\ +X(XMM9_3, 267, ymm9, 12, 4)\ +X(XMM10_0, 268, ymm10, 0, 4)\ +X(XMM10_1, 269, ymm10, 4, 4)\ +X(XMM10_2, 270, ymm10, 8, 4)\ +X(XMM10_3, 271, ymm10, 12, 4)\ +X(XMM11_0, 272, ymm11, 0, 4)\ +X(XMM11_1, 273, ymm11, 4, 4)\ +X(XMM11_2, 274, ymm11, 8, 4)\ +X(XMM11_3, 275, ymm11, 12, 4)\ +X(XMM12_0, 276, ymm12, 0, 4)\ +X(XMM12_1, 277, ymm12, 4, 4)\ +X(XMM12_2, 278, ymm12, 8, 4)\ +X(XMM12_3, 279, ymm12, 12, 4)\ +X(XMM13_0, 280, ymm13, 0, 4)\ +X(XMM13_1, 281, ymm13, 4, 4)\ +X(XMM13_2, 282, ymm13, 8, 4)\ +X(XMM13_3, 283, ymm13, 12, 4)\ +X(XMM14_0, 284, ymm14, 0, 4)\ +X(XMM14_1, 285, ymm14, 4, 4)\ +X(XMM14_2, 286, ymm14, 8, 4)\ +X(XMM14_3, 287, ymm14, 12, 4)\ +X(XMM15_0, 288, ymm15, 0, 4)\ +X(XMM15_1, 289, ymm15, 4, 4)\ +X(XMM15_2, 290, ymm15, 8, 4)\ +X(XMM15_3, 291, ymm15, 12, 4)\ +X(XMM8L, 292, ymm8, 0, 8)\ +X(XMM9L, 293, ymm9, 0, 8)\ +X(XMM10L, 294, ymm10, 0, 8)\ +X(XMM11L, 295, ymm11, 0, 8)\ +X(XMM12L, 296, ymm12, 0, 8)\ +X(XMM13L, 297, ymm13, 0, 8)\ +X(XMM14L, 298, ymm14, 0, 8)\ +X(XMM15L, 299, ymm15, 0, 8)\ +X(XMM8H, 300, ymm8, 8, 8)\ +X(XMM9H, 301, ymm9, 8, 8)\ +X(XMM10H, 302, ymm10, 8, 8)\ +X(XMM11H, 303, ymm11, 8, 8)\ +X(XMM12H, 304, ymm12, 8, 8)\ +X(XMM13H, 305, ymm13, 8, 8)\ +X(XMM14H, 306, ymm14, 8, 8)\ +X(XMM15H, 307, ymm15, 8, 8)\ +X(EMM8L, 308, ymm8, 0, 8)\ +X(EMM9L, 309, ymm9, 0, 8)\ +X(EMM10L, 310, ymm10, 0, 8)\ +X(EMM11L, 311, ymm11, 0, 8)\ +X(EMM12L, 312, ymm12, 0, 8)\ +X(EMM13L, 313, ymm13, 0, 8)\ +X(EMM14L, 314, ymm14, 0, 8)\ +X(EMM15L, 315, ymm15, 0, 8)\ +X(EMM8H, 316, ymm8, 8, 8)\ +X(EMM9H, 317, ymm9, 8, 8)\ +X(EMM10H, 318, ymm10, 8, 8)\ +X(EMM11H, 319, ymm11, 8, 8)\ +X(EMM12H, 320, ymm12, 8, 8)\ +X(EMM13H, 321, ymm13, 8, 8)\ +X(EMM14H, 322, ymm14, 8, 8)\ +X(EMM15H, 323, ymm15, 8, 8)\ +X(SIL, 324, rsi, 0, 1)\ +X(DIL, 325, rdi, 0, 1)\ +X(BPL, 326, rbp, 0, 1)\ +X(SPL, 327, rsp, 0, 1)\ +X(RAX, 328, rax, 0, 8)\ +X(RBX, 329, rbx, 0, 8)\ +X(RCX, 330, rcx, 0, 8)\ +X(RDX, 331, rdx, 0, 8)\ +X(RSI, 332, rsi, 0, 8)\ +X(RDI, 333, rdi, 0, 8)\ +X(RBP, 334, rbp, 0, 8)\ +X(RSP, 335, rsp, 0, 8)\ +X(R8, 336, r8, 0, 8)\ +X(R9, 337, r9, 0, 8)\ +X(R10, 338, r10, 0, 8)\ +X(R11, 339, r11, 0, 8)\ +X(R12, 340, r12, 0, 8)\ +X(R13, 341, r13, 0, 8)\ +X(R14, 342, r14, 0, 8)\ +X(R15, 343, r15, 0, 8)\ +X(R8B, 344, r8, 0, 1)\ +X(R9B, 345, r9, 0, 1)\ +X(R10B, 346, r10, 0, 1)\ +X(R11B, 347, r11, 0, 1)\ +X(R12B, 348, r12, 0, 1)\ +X(R13B, 349, r13, 0, 1)\ +X(R14B, 350, r14, 0, 1)\ +X(R15B, 351, r15, 0, 1)\ +X(R8W, 352, r8, 0, 2)\ +X(R9W, 353, r9, 0, 2)\ +X(R10W, 354, r10, 0, 2)\ +X(R11W, 355, r11, 0, 2)\ +X(R12W, 356, r12, 0, 2)\ +X(R13W, 357, r13, 0, 2)\ +X(R14W, 358, r14, 0, 2)\ +X(R15W, 359, r15, 0, 2)\ +X(R8D, 360, r8, 0, 4)\ +X(R9D, 361, r9, 0, 4)\ +X(R10D, 362, r10, 0, 4)\ +X(R11D, 363, r11, 0, 4)\ +X(R12D, 364, r12, 0, 4)\ +X(R13D, 365, r13, 0, 4)\ +X(R14D, 366, r14, 0, 4)\ +X(R15D, 367, r15, 0, 4)\ +X(YMM0, 368, ymm0, 0, 32)\ +X(YMM1, 369, ymm1, 0, 32)\ +X(YMM2, 370, ymm2, 0, 32)\ +X(YMM3, 371, ymm3, 0, 32)\ +X(YMM4, 372, ymm4, 0, 32)\ +X(YMM5, 373, ymm5, 0, 32)\ +X(YMM6, 374, ymm6, 0, 32)\ +X(YMM7, 375, ymm7, 0, 32)\ +X(YMM8, 376, ymm8, 0, 32)\ +X(YMM9, 377, ymm9, 0, 32)\ +X(YMM10, 378, ymm10, 0, 32)\ +X(YMM11, 379, ymm11, 0, 32)\ +X(YMM12, 380, ymm12, 0, 32)\ +X(YMM13, 381, ymm13, 0, 32)\ +X(YMM14, 382, ymm14, 0, 32)\ +X(YMM15, 383, ymm15, 0, 32)\ +X(YMM0H, 384, ymm0, 16, 32)\ +X(YMM1H, 385, ymm1, 16, 32)\ +X(YMM2H, 386, ymm2, 16, 32)\ +X(YMM3H, 387, ymm3, 16, 32)\ +X(YMM4H, 388, ymm4, 16, 32)\ +X(YMM5H, 389, ymm5, 16, 32)\ +X(YMM6H, 390, ymm6, 16, 32)\ +X(YMM7H, 391, ymm7, 16, 32)\ +X(YMM8H, 392, ymm8, 16, 32)\ +X(YMM9H, 393, ymm9, 16, 32)\ +X(YMM10H, 394, ymm10, 16, 32)\ +X(YMM11H, 395, ymm11, 16, 32)\ +X(YMM12H, 396, ymm12, 16, 32)\ +X(YMM13H, 397, ymm13, 16, 32)\ +X(YMM14H, 398, ymm14, 16, 32)\ +X(YMM15H, 399, ymm15, 16, 32)\ +X(XMM0IL, 400, ymm0, 0, 8)\ +X(XMM1IL, 401, ymm1, 0, 8)\ +X(XMM2IL, 402, ymm2, 0, 8)\ +X(XMM3IL, 403, ymm3, 0, 8)\ +X(XMM4IL, 404, ymm4, 0, 8)\ +X(XMM5IL, 405, ymm5, 0, 8)\ +X(XMM6IL, 406, ymm6, 0, 8)\ +X(XMM7IL, 407, ymm7, 0, 8)\ +X(XMM8IL, 408, ymm8, 0, 8)\ +X(XMM9IL, 409, ymm9, 0, 8)\ +X(XMM10IL, 410, ymm10, 0, 8)\ +X(XMM11IL, 411, ymm11, 0, 8)\ +X(XMM12IL, 412, ymm12, 0, 8)\ +X(XMM13IL, 413, ymm13, 0, 8)\ +X(XMM14IL, 414, ymm14, 0, 8)\ +X(XMM15IL, 415, ymm15, 0, 8)\ +X(XMM0IH, 416, ymm0, 8, 8)\ +X(XMM1IH, 417, ymm1, 8, 8)\ +X(XMM2IH, 418, ymm2, 8, 8)\ +X(XMM3IH, 419, ymm3, 8, 8)\ +X(XMM4IH, 420, ymm4, 8, 8)\ +X(XMM5IH, 421, ymm5, 8, 8)\ +X(XMM6IH, 422, ymm6, 8, 8)\ +X(XMM7IH, 423, ymm7, 8, 8)\ +X(XMM8IH, 424, ymm8, 8, 8)\ +X(XMM9IH, 425, ymm9, 8, 8)\ +X(XMM10IH, 426, ymm10, 8, 8)\ +X(XMM11IH, 427, ymm11, 8, 8)\ +X(XMM12IH, 428, ymm12, 8, 8)\ +X(XMM13IH, 429, ymm13, 8, 8)\ +X(XMM14IH, 430, ymm14, 8, 8)\ +X(XMM15IH, 431, ymm15, 8, 8)\ +X(YMM0I0, 432, ymm0, 0, 8)\ +X(YMM0I1, 433, ymm0, 8, 8)\ +X(YMM0I2, 434, ymm0, 16, 8)\ +X(YMM0I3, 435, ymm0, 24, 8)\ +X(YMM1I0, 436, ymm1, 0, 8)\ +X(YMM1I1, 437, ymm1, 8, 8)\ +X(YMM1I2, 438, ymm1, 16, 8)\ +X(YMM1I3, 439, ymm1, 24, 8)\ +X(YMM2I0, 440, ymm2, 0, 8)\ +X(YMM2I1, 441, ymm2, 8, 8)\ +X(YMM2I2, 442, ymm2, 16, 8)\ +X(YMM2I3, 443, ymm2, 24, 8)\ +X(YMM3I0, 444, ymm3, 0, 8)\ +X(YMM3I1, 445, ymm3, 8, 8)\ +X(YMM3I2, 446, ymm3, 16, 8)\ +X(YMM3I3, 447, ymm3, 24, 8)\ +X(YMM4I0, 448, ymm4, 0, 8)\ +X(YMM4I1, 449, ymm4, 8, 8)\ +X(YMM4I2, 450, ymm4, 16, 8)\ +X(YMM4I3, 451, ymm4, 24, 8)\ +X(YMM5I0, 452, ymm5, 0, 8)\ +X(YMM5I1, 453, ymm5, 8, 8)\ +X(YMM5I2, 454, ymm5, 16, 8)\ +X(YMM5I3, 455, ymm5, 24, 8)\ +X(YMM6I0, 456, ymm6, 0, 8)\ +X(YMM6I1, 457, ymm6, 8, 8)\ +X(YMM6I2, 458, ymm6, 16, 8)\ +X(YMM6I3, 459, ymm6, 24, 8)\ +X(YMM7I0, 460, ymm7, 0, 8)\ +X(YMM7I1, 461, ymm7, 8, 8)\ +X(YMM7I2, 462, ymm7, 16, 8)\ +X(YMM7I3, 463, ymm7, 24, 8)\ +X(YMM8I0, 464, ymm8, 0, 8)\ +X(YMM8I1, 465, ymm8, 8, 8)\ +X(YMM8I2, 466, ymm8, 16, 8)\ +X(YMM8I3, 467, ymm8, 24, 8)\ +X(YMM9I0, 468, ymm9, 0, 8)\ +X(YMM9I1, 469, ymm9, 8, 8)\ +X(YMM9I2, 470, ymm9, 16, 8)\ +X(YMM9I3, 471, ymm9, 24, 8)\ +X(YMM10I0, 472, ymm10, 0, 8)\ +X(YMM10I1, 473, ymm10, 8, 8)\ +X(YMM10I2, 474, ymm10, 16, 8)\ +X(YMM10I3, 475, ymm10, 24, 8)\ +X(YMM11I0, 476, ymm11, 0, 8)\ +X(YMM11I1, 477, ymm11, 8, 8)\ +X(YMM11I2, 478, ymm11, 16, 8)\ +X(YMM11I3, 479, ymm11, 24, 8)\ +X(YMM12I0, 480, ymm12, 0, 8)\ +X(YMM12I1, 481, ymm12, 8, 8)\ +X(YMM12I2, 482, ymm12, 16, 8)\ +X(YMM12I3, 483, ymm12, 24, 8)\ +X(YMM13I0, 484, ymm13, 0, 8)\ +X(YMM13I1, 485, ymm13, 8, 8)\ +X(YMM13I2, 486, ymm13, 16, 8)\ +X(YMM13I3, 487, ymm13, 24, 8)\ +X(YMM14I0, 488, ymm14, 0, 8)\ +X(YMM14I1, 489, ymm14, 8, 8)\ +X(YMM14I2, 490, ymm14, 16, 8)\ +X(YMM14I3, 491, ymm14, 24, 8)\ +X(YMM15I0, 492, ymm15, 0, 8)\ +X(YMM15I1, 493, ymm15, 8, 8)\ +X(YMM15I2, 494, ymm15, 16, 8)\ +X(YMM15I3, 495, ymm15, 24, 8)\ +X(YMM0F0, 496, ymm0, 0, 4)\ +X(YMM0F1, 497, ymm0, 4, 4)\ +X(YMM0F2, 498, ymm0, 8, 4)\ +X(YMM0F3, 499, ymm0, 12, 4)\ +X(YMM0F4, 500, ymm0, 16, 4)\ +X(YMM0F5, 501, ymm0, 20, 4)\ +X(YMM0F6, 502, ymm0, 24, 4)\ +X(YMM0F7, 503, ymm0, 28, 4)\ +X(YMM1F0, 504, ymm1, 0, 4)\ +X(YMM1F1, 505, ymm1, 4, 4)\ +X(YMM1F2, 506, ymm1, 8, 4)\ +X(YMM1F3, 507, ymm1, 12, 4)\ +X(YMM1F4, 508, ymm1, 16, 4)\ +X(YMM1F5, 509, ymm1, 20, 4)\ +X(YMM1F6, 510, ymm1, 24, 4)\ +X(YMM1F7, 511, ymm1, 28, 4)\ +X(YMM2F0, 512, ymm2, 0, 4)\ +X(YMM2F1, 513, ymm2, 4, 4)\ +X(YMM2F2, 514, ymm2, 8, 4)\ +X(YMM2F3, 515, ymm2, 12, 4)\ +X(YMM2F4, 516, ymm2, 16, 4)\ +X(YMM2F5, 517, ymm2, 20, 4)\ +X(YMM2F6, 518, ymm2, 24, 4)\ +X(YMM2F7, 519, ymm2, 28, 4)\ +X(YMM3F0, 520, ymm3, 0, 4)\ +X(YMM3F1, 521, ymm3, 4, 4)\ +X(YMM3F2, 522, ymm3, 8, 4)\ +X(YMM3F3, 523, ymm3, 12, 4)\ +X(YMM3F4, 524, ymm3, 16, 4)\ +X(YMM3F5, 525, ymm3, 20, 4)\ +X(YMM3F6, 526, ymm3, 24, 4)\ +X(YMM3F7, 527, ymm3, 28, 4)\ +X(YMM4F0, 528, ymm4, 0, 4)\ +X(YMM4F1, 529, ymm4, 4, 4)\ +X(YMM4F2, 530, ymm4, 8, 4)\ +X(YMM4F3, 531, ymm4, 12, 4)\ +X(YMM4F4, 532, ymm4, 16, 4)\ +X(YMM4F5, 533, ymm4, 20, 4)\ +X(YMM4F6, 534, ymm4, 24, 4)\ +X(YMM4F7, 535, ymm4, 28, 4)\ +X(YMM5F0, 536, ymm5, 0, 4)\ +X(YMM5F1, 537, ymm5, 4, 4)\ +X(YMM5F2, 538, ymm5, 8, 4)\ +X(YMM5F3, 539, ymm5, 12, 4)\ +X(YMM5F4, 540, ymm5, 16, 4)\ +X(YMM5F5, 541, ymm5, 20, 4)\ +X(YMM5F6, 542, ymm5, 24, 4)\ +X(YMM5F7, 543, ymm5, 28, 4)\ +X(YMM6F0, 544, ymm6, 0, 4)\ +X(YMM6F1, 545, ymm6, 4, 4)\ +X(YMM6F2, 546, ymm6, 8, 4)\ +X(YMM6F3, 547, ymm6, 12, 4)\ +X(YMM6F4, 548, ymm6, 16, 4)\ +X(YMM6F5, 549, ymm6, 20, 4)\ +X(YMM6F6, 550, ymm6, 24, 4)\ +X(YMM6F7, 551, ymm6, 28, 4)\ +X(YMM7F0, 552, ymm7, 0, 4)\ +X(YMM7F1, 553, ymm7, 4, 4)\ +X(YMM7F2, 554, ymm7, 8, 4)\ +X(YMM7F3, 555, ymm7, 12, 4)\ +X(YMM7F4, 556, ymm7, 16, 4)\ +X(YMM7F5, 557, ymm7, 20, 4)\ +X(YMM7F6, 558, ymm7, 24, 4)\ +X(YMM7F7, 559, ymm7, 28, 4)\ +X(YMM8F0, 560, ymm8, 0, 4)\ +X(YMM8F1, 561, ymm8, 4, 4)\ +X(YMM8F2, 562, ymm8, 8, 4)\ +X(YMM8F3, 563, ymm8, 12, 4)\ +X(YMM8F4, 564, ymm8, 16, 4)\ +X(YMM8F5, 565, ymm8, 20, 4)\ +X(YMM8F6, 566, ymm8, 24, 4)\ +X(YMM8F7, 567, ymm8, 28, 4)\ +X(YMM9F0, 568, ymm9, 0, 4)\ +X(YMM9F1, 569, ymm9, 4, 4)\ +X(YMM9F2, 570, ymm9, 8, 4)\ +X(YMM9F3, 571, ymm9, 12, 4)\ +X(YMM9F4, 572, ymm9, 16, 4)\ +X(YMM9F5, 573, ymm9, 20, 4)\ +X(YMM9F6, 574, ymm9, 24, 4)\ +X(YMM9F7, 575, ymm9, 28, 4)\ +X(YMM10F0, 576, ymm10, 0, 4)\ +X(YMM10F1, 577, ymm10, 4, 4)\ +X(YMM10F2, 578, ymm10, 8, 4)\ +X(YMM10F3, 579, ymm10, 12, 4)\ +X(YMM10F4, 580, ymm10, 16, 4)\ +X(YMM10F5, 581, ymm10, 20, 4)\ +X(YMM10F6, 582, ymm10, 24, 4)\ +X(YMM10F7, 583, ymm10, 28, 4)\ +X(YMM11F0, 584, ymm11, 0, 4)\ +X(YMM11F1, 585, ymm11, 4, 4)\ +X(YMM11F2, 586, ymm11, 8, 4)\ +X(YMM11F3, 587, ymm11, 12, 4)\ +X(YMM11F4, 588, ymm11, 16, 4)\ +X(YMM11F5, 589, ymm11, 20, 4)\ +X(YMM11F6, 590, ymm11, 24, 4)\ +X(YMM11F7, 591, ymm11, 28, 4)\ +X(YMM12F0, 592, ymm12, 0, 4)\ +X(YMM12F1, 593, ymm12, 4, 4)\ +X(YMM12F2, 594, ymm12, 8, 4)\ +X(YMM12F3, 595, ymm12, 12, 4)\ +X(YMM12F4, 596, ymm12, 16, 4)\ +X(YMM12F5, 597, ymm12, 20, 4)\ +X(YMM12F6, 598, ymm12, 24, 4)\ +X(YMM12F7, 599, ymm12, 28, 4)\ +X(YMM13F0, 600, ymm13, 0, 4)\ +X(YMM13F1, 601, ymm13, 4, 4)\ +X(YMM13F2, 602, ymm13, 8, 4)\ +X(YMM13F3, 603, ymm13, 12, 4)\ +X(YMM13F4, 604, ymm13, 16, 4)\ +X(YMM13F5, 605, ymm13, 20, 4)\ +X(YMM13F6, 606, ymm13, 24, 4)\ +X(YMM13F7, 607, ymm13, 28, 4)\ +X(YMM14F0, 608, ymm14, 0, 4)\ +X(YMM14F1, 609, ymm14, 4, 4)\ +X(YMM14F2, 610, ymm14, 8, 4)\ +X(YMM14F3, 611, ymm14, 12, 4)\ +X(YMM14F4, 612, ymm14, 16, 4)\ +X(YMM14F5, 613, ymm14, 20, 4)\ +X(YMM14F6, 614, ymm14, 24, 4)\ +X(YMM14F7, 615, ymm14, 28, 4)\ +X(YMM15F0, 616, ymm15, 0, 4)\ +X(YMM15F1, 617, ymm15, 4, 4)\ +X(YMM15F2, 618, ymm15, 8, 4)\ +X(YMM15F3, 619, ymm15, 12, 4)\ +X(YMM15F4, 620, ymm15, 16, 4)\ +X(YMM15F5, 621, ymm15, 20, 4)\ +X(YMM15F6, 622, ymm15, 24, 4)\ +X(YMM15F7, 623, ymm15, 28, 4)\ +X(YMM0D0, 624, ymm0, 0, 8)\ +X(YMM0D1, 625, ymm0, 8, 8)\ +X(YMM0D2, 626, ymm0, 16, 8)\ +X(YMM0D3, 627, ymm0, 24, 8)\ +X(YMM1D0, 628, ymm1, 0, 8)\ +X(YMM1D1, 629, ymm1, 8, 8)\ +X(YMM1D2, 630, ymm1, 16, 8)\ +X(YMM1D3, 631, ymm1, 24, 8)\ +X(YMM2D0, 632, ymm2, 0, 8)\ +X(YMM2D1, 633, ymm2, 8, 8)\ +X(YMM2D2, 634, ymm2, 16, 8)\ +X(YMM2D3, 635, ymm2, 24, 8)\ +X(YMM3D0, 636, ymm3, 0, 8)\ +X(YMM3D1, 637, ymm3, 8, 8)\ +X(YMM3D2, 638, ymm3, 16, 8)\ +X(YMM3D3, 639, ymm3, 24, 8)\ +X(YMM4D0, 640, ymm4, 0, 8)\ +X(YMM4D1, 641, ymm4, 8, 8)\ +X(YMM4D2, 642, ymm4, 16, 8)\ +X(YMM4D3, 643, ymm4, 24, 8)\ +X(YMM5D0, 644, ymm5, 0, 8)\ +X(YMM5D1, 645, ymm5, 8, 8)\ +X(YMM5D2, 646, ymm5, 16, 8)\ +X(YMM5D3, 647, ymm5, 24, 8)\ +X(YMM6D0, 648, ymm6, 0, 8)\ +X(YMM6D1, 649, ymm6, 8, 8)\ +X(YMM6D2, 650, ymm6, 16, 8)\ +X(YMM6D3, 651, ymm6, 24, 8)\ +X(YMM7D0, 652, ymm7, 0, 8)\ +X(YMM7D1, 653, ymm7, 8, 8)\ +X(YMM7D2, 654, ymm7, 16, 8)\ +X(YMM7D3, 655, ymm7, 24, 8)\ +X(YMM8D0, 656, ymm8, 0, 8)\ +X(YMM8D1, 657, ymm8, 8, 8)\ +X(YMM8D2, 658, ymm8, 16, 8)\ +X(YMM8D3, 659, ymm8, 24, 8)\ +X(YMM9D0, 660, ymm9, 0, 8)\ +X(YMM9D1, 661, ymm9, 8, 8)\ +X(YMM9D2, 662, ymm9, 16, 8)\ +X(YMM9D3, 663, ymm9, 24, 8)\ +X(YMM10D0, 664, ymm10, 0, 8)\ +X(YMM10D1, 665, ymm10, 8, 8)\ +X(YMM10D2, 666, ymm10, 16, 8)\ +X(YMM10D3, 667, ymm10, 24, 8)\ +X(YMM11D0, 668, ymm11, 0, 8)\ +X(YMM11D1, 669, ymm11, 8, 8)\ +X(YMM11D2, 670, ymm11, 16, 8)\ +X(YMM11D3, 671, ymm11, 24, 8)\ +X(YMM12D0, 672, ymm12, 0, 8)\ +X(YMM12D1, 673, ymm12, 8, 8)\ +X(YMM12D2, 674, ymm12, 16, 8)\ +X(YMM12D3, 675, ymm12, 24, 8)\ +X(YMM13D0, 676, ymm13, 0, 8)\ +X(YMM13D1, 677, ymm13, 8, 8)\ +X(YMM13D2, 678, ymm13, 16, 8)\ +X(YMM13D3, 679, ymm13, 24, 8)\ +X(YMM14D0, 680, ymm14, 0, 8)\ +X(YMM14D1, 681, ymm14, 8, 8)\ +X(YMM14D2, 682, ymm14, 16, 8)\ +X(YMM14D3, 683, ymm14, 24, 8)\ +X(YMM15D0, 684, ymm15, 0, 8)\ +X(YMM15D1, 685, ymm15, 8, 8)\ +X(YMM15D2, 686, ymm15, 16, 8)\ +X(YMM15D3, 687, ymm15, 24, 8) + +typedef U16 CV_Regx64; +typedef enum{ +#define X(CVN,C,RDN,BP,BZ) CV_Regx64_##CVN = C, + CV_Reg_X64_XList(X) +#undef X +} CV_Regx64Enum; + + +#define CV_SignatureXList(X) \ +X(C6, 0)\ +X(C7, 1)\ +X(C11, 2)\ +X(C13, 4)\ +X(RESERVED, 5) + +typedef U16 CV_Signature; +typedef enum{ +#define X(N,c) CV_Signature_##N = c, + CV_SignatureXList(X) +#undef X +} CV_SignatureEnum; + + +#define CV_LanguageXList(X) \ +X(C, 0x00)\ +X(CXX, 0x01)\ +X(FORTRAN, 0x02)\ +X(MASM, 0x03)\ +X(PASCAL, 0x04)\ +X(BASIC, 0x05)\ +X(COBOL, 0x06)\ +X(LINK, 0x07)\ +X(CVTRES, 0x08)\ +X(CVTPGD, 0x09)\ +X(CSHARP, 0x0A)\ +X(VB, 0x0B)\ +X(ILASM, 0x0C)\ +X(JAVA, 0x0D)\ +X(JSCRIPT, 0x0E)\ +X(MSIL, 0x0F)\ +X(HLSL, 0x10) + +typedef U16 CV_Language; +typedef enum{ +#define X(N,c) CV_Language_##N = c, + CV_LanguageXList(X) +#undef X +} CV_LanguageEnum; + + + +//////////////////////////////// +//~ CodeView Format "Sym" and "Leaf" Header Type + +typedef struct CV_RecHeader{ + U16 size; + U16 kind; +} CV_RecHeader; + + +//////////////////////////////// +//~ CodeView Format "Sym" Types +// (per-compilation-unit info, variables, procedures, etc.) + +#define CV_SymKindXList(X) \ +X(COMPILE, 0x0001)\ +X(REGISTER_16t, 0x0002)\ +X(CONSTANT_16t, 0x0003)\ +X(UDT_16t, 0x0004)\ +X(SSEARCH, 0x0005)\ +X(END, 0x0006)\ +X(SKIP, 0x0007)\ +X(CVRESERVE, 0x0008)\ +X(OBJNAME_ST, 0x0009)\ +X(ENDARG, 0x000a)\ +X(COBOLUDT_16t, 0x000b)\ +X(MANYREG_16t, 0x000c)\ +X(RETURN, 0x000d)\ +X(ENTRYTHIS, 0x000e)\ +X(BPREL16, 0x0100)\ +X(LDATA16, 0x0101)\ +X(GDATA16, 0x0102)\ +X(PUB16, 0x0103)\ +X(LPROC16, 0x0104)\ +X(GPROC16, 0x0105)\ +X(THUNK16, 0x0106)\ +X(BLOCK16, 0x0107)\ +X(WITH16, 0x0108)\ +X(LABEL16, 0x0109)\ +X(CEXMODEL16, 0x010a)\ +X(VFTABLE16, 0x010b)\ +X(REGREL16, 0x010c)\ +X(BPREL32_16t, 0x0200)\ +X(LDATA32_16t, 0x0201)\ +X(GDATA32_16t, 0x0202)\ +X(PUB32_16t, 0x0203)\ +X(LPROC32_16t, 0x0204)\ +X(GPROC32_16t, 0x0205)\ +X(THUNK32_ST, 0x0206)\ +X(BLOCK32_ST, 0x0207)\ +X(WITH32_ST, 0x0208)\ +X(LABEL32_ST, 0x0209)\ +X(CEXMODEL32, 0x020a)\ +X(VFTABLE32_16t, 0x020b)\ +X(REGREL32_16t, 0x020c)\ +X(LTHREAD32_16t, 0x020d)\ +X(GTHREAD32_16t, 0x020e)\ +X(SLINK32, 0x020f)\ +X(LPROCMIPS_16t, 0x0300)\ +X(GPROCMIPS_16t, 0x0301)\ +X(PROCREF_ST, 0x0400)\ +X(DATAREF_ST, 0x0401)\ +X(ALIGN, 0x0402)\ +X(LPROCREF_ST, 0x0403)\ +X(OEM, 0x0404)\ +X(TI16_MAX, 0x1000)\ +X(CONSTANT_ST, 0x1002)\ +X(UDT_ST, 0x1003)\ +X(COBOLUDT_ST, 0x1004)\ +X(MANYREG_ST, 0x1005)\ +X(BPREL32_ST, 0x1006)\ +X(LDATA32_ST, 0x1007)\ +X(GDATA32_ST, 0x1008)\ +X(PUB32_ST, 0x1009)\ +X(LPROC32_ST, 0x100a)\ +X(GPROC32_ST, 0x100b)\ +X(VFTABLE32, 0x100c)\ +X(REGREL32_ST, 0x100d)\ +X(LTHREAD32_ST, 0x100e)\ +X(GTHREAD32_ST, 0x100f)\ +X(LPROCMIPS_ST, 0x1010)\ +X(GPROCMIPS_ST, 0x1011)\ +X(FRAMEPROC, 0x1012)\ +X(COMPILE2_ST, 0x1013)\ +X(MANYREG2_ST, 0x1014)\ +X(LPROCIA64_ST, 0x1015)\ +X(GPROCIA64_ST, 0x1016)\ +X(LOCALSLOT_ST, 0x1017)\ +X(PARAMSLOT_ST, 0x1018)\ +X(ANNOTATION, 0x1019)\ +X(GMANPROC_ST, 0x101a)\ +X(LMANPROC_ST, 0x101b)\ +X(RESERVED1, 0x101c)\ +X(RESERVED2, 0x101d)\ +X(RESERVED3, 0x101e)\ +X(RESERVED4, 0x101f)\ +X(LMANDATA_ST, 0x1020)\ +X(GMANDATA_ST, 0x1021)\ +X(MANFRAMEREL_ST, 0x1022)\ +X(MANREGISTER_ST, 0x1023)\ +X(MANSLOT_ST, 0x1024)\ +X(MANMANYREG_ST, 0x1025)\ +X(MANREGREL_ST, 0x1026)\ +X(MANMANYREG2_ST, 0x1027)\ +X(MANTYPREF, 0x1028)\ +X(UNAMESPACE_ST, 0x1029)\ +X(ST_MAX, 0x1100)\ +X(OBJNAME, 0x1101)\ +X(THUNK32, 0x1102)\ +X(BLOCK32, 0x1103)\ +X(WITH32, 0x1104)\ +X(LABEL32, 0x1105)\ +X(REGISTER, 0x1106)\ +X(CONSTANT, 0x1107)\ +X(UDT, 0x1108)\ +X(COBOLUDT, 0x1109)\ +X(MANYREG, 0x110a)\ +X(BPREL32, 0x110b)\ +X(LDATA32, 0x110c)\ +X(GDATA32, 0x110d)\ +X(PUB32, 0x110e)\ +X(LPROC32, 0x110f)\ +X(GPROC32, 0x1110)\ +X(REGREL32, 0x1111)\ +X(LTHREAD32, 0x1112)\ +X(GTHREAD32, 0x1113)\ +X(LPROCMIPS, 0x1114)\ +X(GPROCMIPS, 0x1115)\ +X(COMPILE2, 0x1116)\ +X(MANYREG2, 0x1117)\ +X(LPROCIA64, 0x1118)\ +X(GPROCIA64, 0x1119)\ +X(LOCALSLOT, 0x111a)\ +X(PARAMSLOT, 0x111b)\ +X(LMANDATA, 0x111c)\ +X(GMANDATA, 0x111d)\ +X(MANFRAMEREL, 0x111e)\ +X(MANREGISTER, 0x111f)\ +X(MANSLOT, 0x1120)\ +X(MANMANYREG, 0x1121)\ +X(MANREGREL, 0x1122)\ +X(MANMANYREG2, 0x1123)\ +X(UNAMESPACE, 0x1124)\ +X(PROCREF, 0x1125)\ +X(DATAREF, 0x1126)\ +X(LPROCREF, 0x1127)\ +X(ANNOTATIONREF, 0x1128)\ +X(TOKENREF, 0x1129)\ +X(GMANPROC, 0x112a)\ +X(LMANPROC, 0x112b)\ +X(TRAMPOLINE, 0x112c)\ +X(MANCONSTANT, 0x112d)\ +X(ATTR_FRAMEREL, 0x112e)\ +X(ATTR_REGISTER, 0x112f)\ +X(ATTR_REGREL, 0x1130)\ +X(ATTR_MANYREG, 0x1131)\ +X(SEPCODE, 0x1132)\ +X(DEFRANGE_2005, 0x1134)\ +X(DEFRANGE2_2005, 0x1135)\ +X(SECTION, 0x1136)\ +X(COFFGROUP, 0x1137)\ +X(EXPORT, 0x1138)\ +X(CALLSITEINFO, 0x1139)\ +X(FRAMECOOKIE, 0x113a)\ +X(DISCARDED, 0x113b)\ +X(COMPILE3, 0x113c)\ +X(ENVBLOCK, 0x113d)\ +X(LOCAL, 0x113e)\ +X(DEFRANGE, 0x113f)\ +X(DEFRANGE_SUBFIELD, 0x1140)\ +X(DEFRANGE_REGISTER, 0x1141)\ +X(DEFRANGE_FRAMEPOINTER_REL, 0x1142)\ +X(DEFRANGE_SUBFIELD_REGISTER, 0x1143)\ +X(DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144)\ +X(DEFRANGE_REGISTER_REL, 0x1145)\ +X(LPROC32_ID, 0x1146)\ +X(GPROC32_ID, 0x1147)\ +X(LPROCMIPS_ID, 0x1148)\ +X(GPROCMIPS_ID, 0x1149)\ +X(LPROCIA64_ID, 0x114a)\ +X(GPROCIA64_ID, 0x114b)\ +X(BUILDINFO, 0x114c)\ +X(INLINESITE, 0x114d)\ +X(INLINESITE_END, 0x114e)\ +X(PROC_ID_END, 0x114f)\ +X(DEFRANGE_HLSL, 0x1150)\ +X(GDATA_HLSL, 0x1151)\ +X(LDATA_HLSL, 0x1152)\ +X(FILESTATIC, 0x1153)\ +X(LPROC32_DPC, 0x1155)\ +X(LPROC32_DPC_ID, 0x1156)\ +X(DEFRANGE_DPC_PTR_TAG, 0x1157)\ +X(DPC_SYM_TAG_MAP, 0x1158)\ +X(ARMSWITCHTABLE, 0x1159)\ +X(CALLEES, 0x115a)\ +X(CALLERS, 0x115b)\ +X(POGODATA, 0x115c)\ +X(INLINESITE2, 0x115d)\ +X(HEAPALLOCSITE, 0x115e)\ +X(MOD_TYPEREF, 0x115f)\ +X(REF_MINIPDB, 0x1160)\ +X(PDBMAP, 0x1161)\ +X(GDATA_HLSL32, 0x1162)\ +X(LDATA_HLSL32, 0x1163)\ +X(GDATA_HLSL32_EX, 0x1164)\ +X(LDATA_HLSL32_EX, 0x1165)\ +X(FASTLINK, 0x1167)\ +X(INLINEES, 0x1168) + +typedef U16 CV_SymKind; +typedef enum{ +#define X(N,c) CV_SymKind_##N = c, + CV_SymKindXList(X) +#undef X +} CV_SymKindEnum; + +typedef U8 CV_ProcFlags; +enum{ + CV_ProcFlag_NoFPO = (1 << 0), + CV_ProcFlag_IntReturn = (1 << 1), + CV_ProcFlag_FarReturn = (1 << 2), + CV_ProcFlag_NeverReturn = (1 << 3), + CV_ProcFlag_NotReached = (1 << 4), + CV_ProcFlag_CustomCall = (1 << 5), + CV_ProcFlag_NoInline = (1 << 6), + CV_ProcFlag_OptDbgInfo = (1 << 7), +}; + +typedef U16 CV_LocalFlags; +enum{ + CV_LocalFlag_Param = (1 << 0), + CV_LocalFlag_AddrTaken = (1 << 1), + CV_LocalFlag_Compgen = (1 << 2), + CV_LocalFlag_Aggregate = (1 << 3), + CV_LocalFlag_PartOfAggregate = (1 << 4), + CV_LocalFlag_Aliased = (1 << 5), + CV_LocalFlag_Alias = (1 << 6), + CV_LocalFlag_Retval = (1 << 7), + CV_LocalFlag_OptOut = (1 << 8), + CV_LocalFlag_Global = (1 << 9), + CV_LocalFlag_Static = (1 << 10), +}; + +typedef struct CV_LocalVarAttr{ + U32 off; + U16 seg; + CV_LocalFlags flags; +} CV_LocalVarAttr; + +// (SymKind: COMPILE) +typedef U32 CV_CompileFlags; +#define CV_CompileFlags_ExtractLanguage(f) (((f) )&0xFF) +#define CV_CompileFlags_ExtractFloatPrec(f) (((f)>> 8)&0x03) +#define CV_CompileFlags_ExtractFloatPkg(f) (((f)>>10)&0x03) +#define CV_CompileFlags_ExtractAmbientData(f) (((f)>>12)&0x07) +#define CV_CompileFlags_ExtractAmbientCode(f) (((f)>>15)&0x07) +#define CV_CompileFlags_ExtractMode(f) (((f)>>18)&0x01) + +typedef struct CV_SymCompile{ + U8 machine; + CV_CompileFlags flags; + // U8[] ver_str (null terminated) +} CV_SymCompile; + +// (SymKind: SSEARCH) +typedef struct CV_SymStartSearch{ + U32 start_symbol; + U16 segment; +} CV_SymStartSearch; + +// (SymKind: END) (empty) + +// (SymKind: RETURN) +typedef U8 CV_GenericStyle; +typedef enum{ + CV_GenericStyle_VOID, + CV_GenericStyle_REG, // "return data is in register" + CV_GenericStyle_ICAN, // "indirect caller allocated near" + CV_GenericStyle_ICAF, // "indirect caller allocated far" + CV_GenericStyle_IRAN, // "indirect returnee allocated near" + CV_GenericStyle_IRAF, // "indirect returnee allocated far" + CV_GenericStyle_UNUSED, +} CV_GenericStyleEnum; + +typedef U16 CV_GenericFlags; +enum{ + CV_GenericFlags_CSTYLE = (1 << 0), + CV_GenericFlags_RSCLEAN = (1 << 1), // "returnee stack cleanup" +}; + +typedef struct CV_Return{ + CV_GenericFlags flags; + CV_GenericStyle style; +} CV_Return; + +// (SymKind: SLINK32) +typedef struct CV_SymSLink32{ + U32 frame_size; + U32 offset; + U16 reg; +} CV_SymSLink32; + +// (SymKind: OEM) +typedef struct CV_SymOEM{ + COFF_Guid id; + CV_TypeId itype; + // padding align(4) +} CV_SymOEM; + +// (SymKind: VFTABLE32) +typedef struct CV_SymVPath32{ + CV_TypeId root; + CV_TypeId path; + U32 off; + U16 seg; +} CV_SymVPath32; + +// (SymKind: FRAMEPROC) +typedef U8 CV_EncodedFramePtrReg; +typedef enum{ + CV_EncodedFramePtrReg_None, + CV_EncodedFramePtrReg_StackPtr, + CV_EncodedFramePtrReg_FramePtr, + CV_EncodedFramePtrReg_BasePtr, +} CV_EncodedFramePtrRegEnum; + +typedef U32 CV_FrameprocFlags; +enum{ + CV_FrameprocFlag_UsesAlloca = (1 << 0), + CV_FrameprocFlag_UsesSetJmp = (1 << 1), + CV_FrameprocFlag_UsesLongJmp = (1 << 2), + CV_FrameprocFlag_UsesInlAsm = (1 << 3), + CV_FrameprocFlag_UsesEH = (1 << 4), + CV_FrameprocFlag_Inline = (1 << 5), + CV_FrameprocFlag_HasSEH = (1 << 6), + CV_FrameprocFlag_Naked = (1 << 7), + CV_FrameprocFlag_HasSecurityChecks = (1 << 8), + CV_FrameprocFlag_AsyncEH = (1 << 9), + CV_FrameprocFlag_GSNoStackOrdering = (1 << 10), + CV_FrameprocFlag_WasInlined = (1 << 11), + CV_FrameprocFlag_GSCheck = (1 << 12), + CV_FrameprocFlag_SafeBuffers = (1 << 13), + // LocalBasePointer: 14,15 + // ParamBasePointer: 16,17 + CV_FrameprocFlag_PogoOn = (1 << 18), + CV_FrameprocFlag_PogoCountsValid = (1 << 19), + CV_FrameprocFlag_OptSpeed = (1 << 20), + CV_FrameprocFlag_HasCFG = (1 << 21), + CV_FrameprocFlag_HasCFW = (1 << 22), +}; + +#define CV_FrameprocFlags_ExtractLocalBasePointer(f) (((f) >> 14)&3) +#define CV_FrameprocFlags_ExtractParamBasePointer(f) (((f) >> 16)&3) + +typedef struct CV_SymFrameproc{ + U32 frame_size; + U32 pad_size; + U32 pad_off; + U32 save_reg_size; + U32 eh_off; + CV_SectionIndex eh_sec; + CV_FrameprocFlags flags; +} CV_SymFrameproc; + +// (SymKind: ANNOTATION) +typedef struct CV_SymAnnotation{ + U32 off; + U16 seg; + U16 count; + // U8[] annotation (null terminated) +} CV_SymAnnotation; + +// (SymKind: OBJNAME) +typedef struct CV_SymObjname{ + U32 sig; + // U8[] name (null terminated) +} CV_SymObjname; + +// (SymKind: THUNK32) +typedef U8 CV_ThunkOrdinal; +typedef enum{ + CV_ThunkOrdinal_NoType, + CV_ThunkOrdinal_Adjustor, + CV_ThunkOrdinal_VCall, + CV_ThunkOrdinal_PCode, + CV_ThunkOrdinal_Load, + CV_ThunkOrdinal_TrampIncremental, + CV_ThunkOrdinal_TrampBranchIsland, +} CV_ThunkOrdinalEnum; + +typedef struct CV_SymThunk32{ + U32 parent; + U32 end; + U32 next; + U32 off; + U16 sec; + U16 len; + CV_ThunkOrdinal ord; + // U8[] name (null terminated) + // U8[] variant (null terminated) +} CV_SymThunk32; + +// (SymKind: BLOCK32) +typedef struct CV_SymBlock32{ + U32 parent; + U32 end; + U32 len; + U32 off; + U16 sec; + // U8[] name (null terminated) +} CV_SymBlock32; + +// (SymKind: LABEL32) +typedef struct CV_SymLabel32{ + U32 off; + U16 sec; + CV_ProcFlags flags; + // U8[] name (null terminated) +} CV_SymLabel32; + +// (SymKind: REGISTER) +typedef struct CV_SymRegister{ + CV_TypeId itype; + U16 reg; + // U8[] name (null terminated) +} CV_SymRegister; + +// (SymKind: CONSTANT) +typedef struct CV_SymConstant{ + CV_TypeId itype; + // CV_Numeric num + // U8[] name (null terminated) +} CV_SymConstant; + +// (SymKind: UDT) +typedef struct CV_SymUDT{ + CV_TypeId itype; + // U8[] name (null terminated) +} CV_SymUDT; + +// (SymKind: MANYREG) +typedef struct CV_SymManyreg{ + CV_TypeId itype; + U8 count; + // U8[count] regs; +} CV_SymManyreg; + +// (SymKind: BPREL32) +typedef struct CV_SymBPRel32{ + U32 off; + CV_TypeId itype; + // U8[] name (null terminated) +} CV_SymBPRel32; + +// (SymKind: LDATA32, GDATA32) +typedef struct CV_SymData32{ + CV_TypeId itype; + U32 off; + CV_SectionIndex sec; + // U8[] name (null terminated) +} CV_SymData32; + +// (SymKind: PUB32) +typedef U32 CV_PubFlags; +enum{ + CV_PubFlag_Code = (1 << 0), + CV_PubFlag_Function = (1 << 1), + CV_PubFlag_ManagedCode = (1 << 2), + CV_PubFlag_MSIL = (1 << 3), +}; + +typedef struct CV_SymPub32{ + CV_PubFlags flags; + U32 off; + CV_SectionIndex sec; + // U8[] name (null terminated) +} CV_SymPub32; + +// (SymKind: LPROC32, GPROC32) +typedef struct CV_SymProc32{ + U32 parent; + U32 end; + U32 next; + U32 len; + U32 dbg_start; + U32 dbg_end; + CV_TypeId itype; + U32 off; + U16 sec; + CV_ProcFlags flags; + // U8[] name (null terminated) +} CV_SymProc32; + +// (SymKind: REGREL32) +typedef struct CV_SymRegrel32{ + U32 reg_off; + CV_TypeId itype; + CV_Reg reg; + // U8[] name (null terminated) +} CV_SymRegrel32; + +// (SymKind: LTHREAD32, GTHREAD32) +typedef struct CV_SymThread32{ + CV_TypeId itype; + U32 tls_off; + U16 tls_seg; + // U8[] name (null terminated) +} CV_SymThread32; + +// (SymKind: COMPILE2) +typedef U32 CV_Compile2Flags; +#define CV_Compile2Flags_ExtractLanguage(f) (((f) )&0xFF) +#define CV_Compile2Flags_ExtractEditAndContinue(f) (((f)>> 8)&0x01) +#define CV_Compile2Flags_ExtractNoDbgInfo(f) (((f)>> 9)&0x01) +#define CV_Compile2Flags_ExtractLTCG(f) (((f)>>10)&0x01) +#define CV_Compile2Flags_ExtractNoDataAlign(f) (((f)>>11)&0x01) +#define CV_Compile2Flags_ExtractManagedPresent(f) (((f)>>12)&0x01) +#define CV_Compile2Flags_ExtractSecurityChecks(f) (((f)>>13)&0x01) +#define CV_Compile2Flags_ExtractHotPatch(f) (((f)>>14)&0x01) +#define CV_Compile2Flags_ExtractCVTCIL(f) (((f)>>15)&0x01) +#define CV_Compile2Flags_ExtractMSILModule(f) (((f)>>16)&0x01) + +typedef struct CV_SymCompile2{ + CV_Compile2Flags flags; + CV_Arch machine; + U16 ver_fe_major; + U16 ver_fe_minor; + U16 ver_fe_build; + U16 ver_major; + U16 ver_minor; + U16 ver_build; + // U8[] ver_str (null terminated) +} CV_SymCompile2; + +// (SymKind: MANYREG2) +typedef struct CV_SymManyreg2{ + CV_TypeId itype; + U16 count; + // U16[count] regs; +} CV_SymManyreg2; + +// (SymKind: LOCALSLOT) +typedef struct CV_SymSlot{ + U32 slot_index; + CV_TypeId itype; + // U8[] name (null terminated) +} CV_SymSlot; + +// (SymKind: MANFRAMEREL, ATTR_FRAMEREL) +typedef struct CV_SymAttrFrameRel{ + U32 off; + CV_TypeId itype; + CV_LocalVarAttr attr; + // U8[] name (null terminated) +} CV_SymAttrFrameRel; + +// (SymKind: MANREGISTER, ATTR_REGISTER) +typedef struct CV_SymAttrReg{ + CV_TypeId itype; + CV_LocalVarAttr attr; + U16 reg; + // U8[] name (null terminated) +} CV_SymAttrReg; + +// (SymKind: MANMANYREG, ATTR_MANYREG) +typedef struct CV_SymAttrManyReg{ + CV_TypeId itype; + CV_LocalVarAttr attr; + U8 count; + // U8[count] regs + // U8[] name (null terminated) +} CV_SymAttrManyReg; + +// (SymKind: MANREGREL, ATTR_REGREL) +typedef struct CV_SymAttrRegRel{ + U32 off; + CV_TypeId itype; + U16 reg; + CV_LocalVarAttr attr; + // U8[] name (null terminated) +} CV_SymAttrRegRel; + +// (SymKind: UNAMESPACE) +typedef struct CV_SymUNamespace{ + // *** "dummy" is the first character of name - it should not be skipped! + // *** It is placed here so the C compiler will accept this struct. + // *** The actual fixed size part of this record has a size of zero. + + U8 dummy; + + // U8[] name (null terminated) +} CV_SymUNamespace; + +// (SymKind: PROCREF, DATAREF, LPROCREF) +typedef struct CV_SymRef2{ + U32 suc_name; + U32 sym_off; + CV_ModIndex imod; + // U8[] name (null terminated) +} CV_SymRef2; + +// (SymKind: TRAMPOLINE) +typedef U16 CV_TrampolineKind; +typedef enum{ + CV_TrampolineKind_Incremental, + CV_TrampolineKind_BranchIsland, +} CV_TrampolineKindEnum; + +typedef struct CV_SymTrampoline{ + CV_TrampolineKind kind; + U16 thunk_size; + U32 thunk_sec_off; + U32 target_sec_off; + CV_SectionIndex thunk_sec; + CV_SectionIndex target_sec; +} CV_SymTrampoline; + +// (SymKind: SEPCODE) +typedef U32 CV_SepcodeFlags; +enum{ + CV_SepcodeFlag_IsLexicalScope = (1 << 0), + CV_SepcodeFlag_ReturnsToParent = (1 << 1), +}; + +typedef struct CV_SymSepcode{ + U32 parent; + U32 end; + U32 len; + CV_SepcodeFlags flags; + U32 sec_off; + U32 sec_parent_off; + U16 sec; + U16 sec_parent; +} CV_SymSepcode; + +// (SymKind: SECTION) +typedef struct CV_SymSection{ + U16 sec_index; + U8 align; + U8 pad; + U32 rva; + U32 size; + U32 characteristics; + // U8[] name (null terminated) +} CV_SymSection; + +// (SymKind: COFFGROUP) +typedef struct CV_SymCoffGroup{ + U32 size; + U32 characteristics; + U32 off; + U16 sec; + // U8[] name (null terminated) +} CV_SymCoffGroup; + +// (SymKind: EXPORT) +typedef U16 CV_ExportFlags; +enum{ + CV_ExportFlag_Constant = (1 << 0), + CV_ExportFlag_Data = (1 << 1), + CV_ExportFlag_Private = (1 << 2), + CV_ExportFlag_NoName = (1 << 3), + CV_ExportFlag_Ordinal = (1 << 4), + CV_ExportFlag_Forwarder = (1 << 5), +}; + +typedef struct CV_SymExport{ + U16 ordinal; + CV_ExportFlags flags; + // U8[] name (null terminated) +} CV_SymExport; + +// (SymKind: CALLSITEINFO) +typedef struct CV_SymCallSiteInfo{ + U32 off; + U16 sec; + U16 pad; + CV_TypeId itype; +} CV_SymCallSiteInfo; + +// (SymKind: FRAMECOOKIE) +typedef U8 CV_FrameCookieKind; +typedef enum{ + CV_FrameCookieKind_Copy, + CV_FrameCookieKind_XorSP, + CV_FrameCookieKind_XorBP, + CV_FrameCookieKind_XorR13, +} CV_FrameCookieKindEnum; + +typedef struct CV_SymFrameCookie{ + U32 off; + CV_Reg reg; + CV_FrameCookieKind kind; + U8 flags; +} CV_SymFrameCookie; + +// (SymKind: DISCARDED) +typedef U8 CV_DiscardedKind; +typedef enum{ + CV_DiscardedKind_Unknown, + CV_DiscardedKind_NotSelected, + CV_DiscardedKind_NotReferenced, +} CV_DiscardedKindEnum; + +typedef struct CV_SymDiscarded{ + CV_DiscardedKind kind; + U32 file_id; + U32 file_ln; + // U8[] data (rest of data) +} CV_SymDiscarded; + +// (SymKind: COMPILE3) +typedef U32 CV_Compile3Flags; +#define CV_Compile3Flags_ExtractLanguage(f) (((f) )&0xFF) +#define CV_Compile3Flags_ExtractEditAndContinue(f) (((f)>> 9)&0x01) +#define CV_Compile3Flags_ExtractNoDbgInfo(f) (((f)>>10)&0x01) +#define CV_Compile3Flags_ExtractLTCG(f) (((f)>>11)&0x01) +#define CV_Compile3Flags_ExtractNoDataAlign(f) (((f)>>12)&0x01) +#define CV_Compile3Flags_ExtractManagedPresent(f) (((f)>>13)&0x01) +#define CV_Compile3Flags_ExtractSecurityChecks(f) (((f)>>14)&0x01) +#define CV_Compile3Flags_ExtractHotPatch(f) (((f)>>15)&0x01) +#define CV_Compile3Flags_ExtractCVTCIL(f) (((f)>>16)&0x01) +#define CV_Compile3Flags_ExtractMSILModule(f) (((f)>>17)&0x01) +#define CV_Compile3Flags_ExtractSDL(f) (((f)>>18)&0x01) +#define CV_Compile3Flags_ExtractPGO(f) (((f)>>19)&0x01) +#define CV_Compile3Flags_ExtractEXP(f) (((f)>>20)&0x01) + +typedef struct CV_SymCompile3{ + CV_Compile3Flags flags; + CV_Arch machine; + U16 ver_fe_major; + U16 ver_fe_minor; + U16 ver_fe_build; + U16 ver_feqfe; + U16 ver_major; + U16 ver_minor; + U16 ver_build; + U16 ver_qfe; + // U8[] ver_str (null terminated) +} CV_SymCompile3; + +// (SymKind: ENVBLOCK) +typedef struct CV_SymEnvBlock{ + U8 flags; + // U8[][] rgsz (sequence null terminated strings) +} CV_SymEnvBlock; + +// (SymKind: LOCAL) +typedef struct CV_SymLocal{ + CV_TypeId itype; + CV_LocalFlags flags; + // U8[] name (null terminated) +} CV_SymLocal; + +//- DEFRANGE + +typedef struct CV_LvarAddrRange{ + U32 off; + U16 sec; + U16 len; +} CV_LvarAddrRange; + +typedef struct CV_LvarAddrGap{ + U16 off; + U16 len; +} CV_LvarAddrGap; + +typedef U16 CV_RangeAttribs; +enum{ + CV_RangeAttrib_Maybe = (1 << 0), +}; + +// (SymKind: DEFRANGE_SUBFIELD) +typedef struct CV_SymDefrangeSubfield{ + U32 program; + U32 off_in_parent; + CV_LvarAddrRange range; + // CV_LvarAddrGap[] gaps (rest of data) +} CV_SymDefrangeSubfield; + +// (SymKind: DEFRANGE_REGISTER) +typedef struct CV_SymDefrangeRegister{ + CV_Reg reg; + CV_RangeAttribs attribs; + CV_LvarAddrRange range; + // CV_LvarAddrGap[] gaps (rest of data) +} CV_SymDefrangeRegister; + +// (SymKind: DEFRANGE_FRAMEPOINTER_REL) +typedef struct CV_SymDefrangeFramepointerRel{ + U32 off; + CV_LvarAddrRange range; + // CV_LvarAddrGap[] gaps (rest of data) +} CV_SymDefrangeFramepointerRel; + +// (SymKind: DEFRANGE_SUBFIELD_REGISTER) +typedef struct CV_SymDefrangeSubfieldRegister{ + CV_Reg reg; + CV_RangeAttribs attribs; + U32 field_offset; + CV_LvarAddrRange range; + // CV_LvarAddrGap[] gaps (rest of data) +} CV_SymDefrangeSubfieldRegister; + +// (SymKind: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE) +typedef struct CV_SymDefrangeFramepointerRelFullScope{ + U32 off; +} CV_SymDefrangeFramepointerRelFullScope; + +// (SymKind: DEFRANGE_REGISTER_REL) +typedef U16 CV_DefrangeRegisterRelFlags; +enum{ + CV_DefrangeRegisterRelFlag_SpilledOutUDTMember = (1 << 0), +}; +#define CV_DefrangeRegisterRelFlag_ExtractOffsetParent(f) (((f)>>4)&0xFFF) + +typedef struct CV_SymDefrangeRegisterRel{ + CV_Reg reg; + CV_DefrangeRegisterRelFlags flags; + U32 reg_off; + CV_LvarAddrRange range; + // CV_LvarAddGap[] gaps (rest of data) +} CV_SymDefrangeRegisterRel; + +// (SymKind: BUILDINFO) +typedef struct CV_SymBuildInfo{ + CV_ItemId id; +} CV_SymBuildInfo; + +// (SymKind: INLINESITE) +typedef struct CV_SymInlineSite{ + U32 parent; + U32 end; + CV_ItemId inlinee; + // CV_BinaryAnnotation annotations (rest of data) +} CV_SymInlineSite; + +// (SymKind: INLINESITE_END) (empty) + +// (SymKind: FILESTATIC) +typedef struct CV_SymFileStatic{ + CV_TypeId itype; + U32 mod_offset; + CV_LocalFlags flags; + // U8[] name (null terminated) +} CV_SymFileStatic; + +// (SymKind: ARMSWITCHTABLE) +typedef U16 CV_ArmSwitchKind; +typedef enum{ + CV_ArmSwitchKind_INT1, + CV_ArmSwitchKind_UINT1, + CV_ArmSwitchKind_INT2, + CV_ArmSwitchKind_UINT2, + CV_ArmSwitchKind_INT4, + CV_ArmSwitchKind_UINT5, + CV_ArmSwitchKind_POINTER, + CV_ArmSwitchKind_UINT1SHL1, + CV_ArmSwitchKind_UINT2SHL1, + CV_ArmSwitchKind_INT1SSHL1, + CV_ArmSwitchKind_INT2SSHL1, +} CV_ArmSwitchKindEnum; + +typedef struct CV_SymArmSwitchTable{ + U32 off_base; + U16 sec_base; + CV_ArmSwitchKind kind; + U32 off_branch; + U32 off_table; + U16 sec_branch; + U16 sec_table; + U32 entry_count; +} CV_SymArmSwitchTable; + +// (SymKind: CALLEES, CALLERS) +typedef struct CV_SymFunctionList{ + U32 count; + // CV_TypeId[count] funcs + // U32[clamp(count, rest_of_data/4)] invocations +} CV_SymFunctionList; + +// (SymKind: POGODATA) +typedef struct CV_SymPogoInfo{ + U32 invocations; + U64 dynamic_inst_count; + U32 static_inst_count; + U32 post_inline_static_inst_count; +} CV_SymPogoInfo; + +// (SymKind: INLINESITE2) +typedef struct CV_SymInlineSite2{ + U32 parent_off; + U32 end_off; + CV_ItemId inlinee; + U32 invocations; + // CV_BinaryAnnotation annotations (rest of data) +} CV_SymInlineSite2; + +// (SymKind: HEAPALLOCSITE) +typedef struct CV_SymHeapAllocSite{ + U32 off; + U16 sec; + U16 call_inst_len; + CV_TypeId itype; +} CV_SymHeapAllocSite; + +// (SymKind: MOD_TYPEREF) +typedef U32 CV_ModTypeRefFlags; +enum{ + CV_ModTypeRefFlag_None = (1 << 0), + CV_ModTypeRefFlag_RefTMPCT = (1 << 1), + CV_ModTypeRefFlag_OwnTMPCT = (1 << 2), + CV_ModTypeRefFlag_OwnTMR = (1 << 3), + CV_ModTypeRefFlag_OwnTM = (1 << 4), + CV_ModTypeRefFlag_RefTM = (1 << 5), +}; + +typedef struct CV_SymModTypeRef{ + CV_ModTypeRefFlags flags; + // contain stream number or module index depending on flags (undocumented) + U32 word0; + U32 word1; +} CV_SymModTypeRef; + +// (SymKind: REF_MINIPDB) +typedef U16 CV_RefMiniPdbFlags; +enum{ + CV_RefMiniPdbFlag_Local = (1 << 0), + CV_RefMiniPdbFlag_Data = (1 << 1), + CV_RefMiniPdbFlag_UDT = (1 << 2), + CV_RefMiniPdbFlag_Label = (1 << 3), + CV_RefMiniPdbFlag_Const = (1 << 4), +}; + +typedef struct CV_SymRefMiniPdb{ + U32 data; + CV_ModIndex imod; + CV_RefMiniPdbFlags flags; + // U8[] name (null terminated) +} CV_SymRefMiniPdb; + +// (SymKind: FASTLINK) +typedef U16 CV_FastLinkFlags; +enum{ + CV_FastLinkFlag_IsGlobalData = (1 << 0), + CV_FastLinkFlag_IsData = (1 << 1), + CV_FastLinkFlag_IsUDT = (1 << 2), + // 3 ~ unknown/unused + CV_FastLinkFlag_IsConst = (1 << 4), + // 5 ~ unknown/unused + CV_FastLinkFlag_IsNamespace = (1 << 6), +}; + +typedef struct CV_SymFastLink{ + CV_TypeId itype; + CV_FastLinkFlags flags; + // U8[] name (null terminated) +} CV_SymFastLink; + +// (SymKind: INLINEES) +typedef struct CV_SymInlinees{ + U32 count; + // U32[count] desc; +} CV_SymInlinees; + + +//////////////////////////////// +//~ CodeView Format "Leaf" Types +// (type info) + +#define CV_LeafKindXList(X) \ +X(MODIFIER_16t, 0x0001)\ +X(POINTER_16t, 0x0002)\ +X(ARRAY_16t, 0x0003)\ +X(CLASS_16t, 0x0004)\ +X(STRUCTURE_16t, 0x0005)\ +X(UNION_16t, 0x0006)\ +X(ENUM_16t, 0x0007)\ +X(PROCEDURE_16t, 0x0008)\ +X(MFUNCTION_16t, 0x0009)\ +X(VTSHAPE, 0x000a)\ +X(COBOL0_16t, 0x000b)\ +X(COBOL1, 0x000c)\ +X(BARRAY_16t, 0x000d)\ +X(LABEL, 0x000e)\ +X(NULL, 0x000f)\ +X(NOTTRAN, 0x0010)\ +X(DIMARRAY_16t, 0x0011)\ +X(VFTPATH_16t, 0x0012)\ +X(PRECOMP_16t, 0x0013)\ +X(ENDPRECOMP, 0x0014)\ +X(OEM_16t, 0x0015)\ +X(TYPESERVER_ST, 0x0016)\ +X(SKIP_16t, 0x0200)\ +X(ARGLIST_16t, 0x0201)\ +X(DEFARG_16t, 0x0202)\ +X(LIST, 0x0203)\ +X(FIELDLIST_16t, 0x0204)\ +X(DERIVED_16t, 0x0205)\ +X(BITFIELD_16t, 0x0206)\ +X(METHODLIST_16t, 0x0207)\ +X(DIMCONU_16t, 0x0208)\ +X(DIMCONLU_16t, 0x0209)\ +X(DIMVARU_16t, 0x020a)\ +X(DIMVARLU_16t, 0x020b)\ +X(REFSYM, 0x020c)\ +X(BCLASS_16t, 0x0400)\ +X(VBCLASS_16t, 0x0401)\ +X(IVBCLASS_16t, 0x0402)\ +X(ENUMERATE_ST, 0x0403)\ +X(FRIENDFCN_16t, 0x0404)\ +X(INDEX_16t, 0x0405)\ +X(MEMBER_16t, 0x0406)\ +X(STMEMBER_16t, 0x0407)\ +X(METHOD_16t, 0x0408)\ +X(NESTTYPE_16t, 0x0409)\ +X(VFUNCTAB_16t, 0x040a)\ +X(FRIENDCLS_16t, 0x040b)\ +X(ONEMETHOD_16t, 0x040c)\ +X(VFUNCOFF_16t, 0x040d)\ +X(TI16_MAX, 0x1000)\ +X(MODIFIER, 0x1001)\ +X(POINTER, 0x1002)\ +X(ARRAY_ST, 0x1003)\ +X(CLASS_ST, 0x1004)\ +X(STRUCTURE_ST, 0x1005)\ +X(UNION_ST, 0x1006)\ +X(ENUM_ST, 0x1007)\ +X(PROCEDURE, 0x1008)\ +X(MFUNCTION, 0x1009)\ +X(COBOL0, 0x100a)\ +X(BARRAY, 0x100b)\ +X(DIMARRAY_ST, 0x100c)\ +X(VFTPATH, 0x100d)\ +X(PRECOMP_ST, 0x100e)\ +X(OEM, 0x100f)\ +X(ALIAS_ST, 0x1010)\ +X(OEM2, 0x1011)\ +X(SKIP, 0x1200)\ +X(ARGLIST, 0x1201)\ +X(DEFARG_ST, 0x1202)\ +X(FIELDLIST, 0x1203)\ +X(DERIVED, 0x1204)\ +X(BITFIELD, 0x1205)\ +X(METHODLIST, 0x1206)\ +X(DIMCONU, 0x1207)\ +X(DIMCONLU, 0x1208)\ +X(DIMVARU, 0x1209)\ +X(DIMVARLU, 0x120a)\ +X(BCLASS, 0x1400)\ +X(VBCLASS, 0x1401)\ +X(IVBCLASS, 0x1402)\ +X(FRIENDFCN_ST, 0x1403)\ +X(INDEX, 0x1404)\ +X(MEMBER_ST, 0x1405)\ +X(STMEMBER_ST, 0x1406)\ +X(METHOD_ST, 0x1407)\ +X(NESTTYPE_ST, 0x1408)\ +X(VFUNCTAB, 0x1409)\ +X(FRIENDCLS, 0x140a)\ +X(ONEMETHOD_ST, 0x140b)\ +X(VFUNCOFF, 0x140c)\ +X(NESTTYPEEX_ST, 0x140d)\ +X(MEMBERMODIFY_ST, 0x140e)\ +X(MANAGED_ST, 0x140f)\ +X(ST_MAX, 0x1500)\ +X(TYPESERVER, 0x1501)\ +X(ENUMERATE, 0x1502)\ +X(ARRAY, 0x1503)\ +X(CLASS, 0x1504)\ +X(STRUCTURE, 0x1505)\ +X(UNION, 0x1506)\ +X(ENUM, 0x1507)\ +X(DIMARRAY, 0x1508)\ +X(PRECOMP, 0x1509)\ +X(ALIAS, 0x150a)\ +X(DEFARG, 0x150b)\ +X(FRIENDFCN, 0x150c)\ +X(MEMBER, 0x150d)\ +X(STMEMBER, 0x150e)\ +X(METHOD, 0x150f)\ +X(NESTTYPE, 0x1510)\ +X(ONEMETHOD, 0x1511)\ +X(NESTTYPEEX, 0x1512)\ +X(MEMBERMODIFY, 0x1513)\ +X(MANAGED, 0x1514)\ +X(TYPESERVER2, 0x1515)\ +X(STRIDED_ARRAY, 0x1516)\ +X(HLSL, 0x1517)\ +X(MODIFIER_EX, 0x1518)\ +X(INTERFACE, 0x1519)\ +X(BINTERFACE, 0x151a)\ +X(VECTOR, 0x151b)\ +X(MATRIX, 0x151c)\ +X(VFTABLE, 0x151d)\ +/* ONGOING REVERSE ENGINEERING */ \ +X(CLASS2, 0x1608)\ +X(STRUCT2, 0x1609) + +typedef U16 CV_LeafKind; +typedef enum{ +#define X(N,c) CV_LeafKind_##N = c, + CV_LeafKindXList(X) +#undef X +} CV_LeafKindEnum; + +#define CV_LeafIDKindXList(X) \ +X(FUNC_ID, 0x1601)\ +X(MFUNC_ID, 0x1602)\ +X(BUILDINFO, 0x1603)\ +X(SUBSTR_LIST, 0x1604)\ +X(STRING_ID, 0x1605)\ +X(UDT_SRC_LINE, 0x1606)\ +X(UDT_MOD_SRC_LINE, 0x1607) + +typedef U16 CV_LeafIDKind; +typedef enum{ +#define X(N,c) CV_LeafIDKind_##N = c, + CV_LeafIDKindXList(X) +#undef X +} CV_LeafIDKindEnum; + +#define CV_BasicTypeXList(X) \ +X(NOTYPE, 0x00)\ +X(ABS, 0x01)\ +X(SEGMENT, 0x02)\ +X(VOID, 0x03)\ +X(CURRENCY, 0x04)\ +X(NBASICSTR, 0x05)\ +X(FBASICSTR, 0x06)\ +X(NOTTRANS, 0x07)\ +X(HRESULT, 0x08)\ +X(CHAR, 0x10)\ +X(SHORT, 0x11)\ +X(LONG, 0x12)\ +X(QUAD, 0x13)\ +X(OCT, 0x14)\ +X(UCHAR, 0x20)\ +X(USHORT, 0x21)\ +X(ULONG, 0x22)\ +X(UQUAD, 0x23)\ +X(UOCT, 0x24)\ +X(BOOL8, 0x30)\ +X(BOOL16, 0x31)\ +X(BOOL32, 0x32)\ +X(BOOL64, 0x33)\ +X(FLOAT32, 0x40)\ +X(FLOAT64, 0x41)\ +X(FLOAT80, 0x42)\ +X(FLOAT128, 0x43)\ +X(FLOAT48, 0x44)\ +X(FLOAT32PP, 0x45)\ +X(FLOAT16, 0x46)\ +X(COMPLEX32, 0x50)\ +X(COMPLEX64, 0x51)\ +X(COMPLEX80, 0x52)\ +X(COMPLEX128, 0x53)\ +X(BIT, 0x60)\ +X(PASCHAR, 0x61)\ +X(BOOL32FF, 0x62)\ +X(INT8, 0x68)\ +X(UINT8, 0x69)\ +X(RCHAR, 0x70)\ +X(WCHAR, 0x71)\ +X(INT16, 0x72)\ +X(UINT16, 0x73)\ +X(INT32, 0x74)\ +X(UINT32, 0x75)\ +X(INT64, 0x76)\ +X(UINT64, 0x77)\ +X(INT128, 0x78)\ +X(UINT128, 0x79)\ +X(CHAR16, 0x7a)\ +X(CHAR32, 0x7b)\ +X(CHAR8, 0x7c)\ +X(PTR, 0xf0) + +typedef U8 CV_BasicType; +typedef enum{ +#define X(N,c) CV_BasicType_##N = c, + CV_BasicTypeXList(X) +#undef X +} CV_BasicTypeEnum; + +#define CV_TypeId_Variadic 0 + +#define CV_BasicPointerKindXList(X) \ +X(VALUE, 0x0)\ +X(16BIT, 0x1)\ +X(FAR_16BIT, 0x2)\ +X(HUGE_16BIT, 0x3)\ +X(32BIT, 0x4)\ +X(16_32BIT, 0x5)\ +X(64BIT, 0x6) + +typedef U8 CV_BasicPointerKind; +typedef enum{ +#define X(N,c) CV_BasicPointerKind_##N = c, + CV_BasicPointerKindXList(X) +#undef X +} CV_BasicPointerKindEnum; + +#define CV_BasicTypeFromTypeId(x) ((x)&0xFF) +#define CV_BasicPointerKindFromTypeId(x) (((x)>>8)&0xFF) + +typedef U8 CV_HFAKind; +typedef enum{ + CV_HFAKind_None, + CV_HFAKind_Float, + CV_HFAKind_Double, + CV_HFAKind_Other +} CV_HFAKindEnum; + +typedef U8 CV_MoComUDTKind; +typedef enum{ + CV_MoComUDTKind_None, + CV_MoComUDTKind_Ref, + CV_MoComUDTKind_Value, + CV_MoComUDTKind_Interface +} CV_MoComUDTKindEnum; + +typedef U16 CV_TypeProps; +enum{ + CV_TypeProp_Packed = (1 << 0), + CV_TypeProp_HasConstructorsDestructors = (1 << 1), + CV_TypeProp_OverloadedOperators = (1 << 2), + CV_TypeProp_IsNested = (1 << 3), + CV_TypeProp_ContainsNested = (1 << 4), + CV_TypeProp_OverloadedAssignment = (1 << 5), + CV_TypeProp_OverloadedCasting = (1 << 6), + CV_TypeProp_FwdRef = (1 << 7), + CV_TypeProp_Scoped = (1 << 8), + CV_TypeProp_HasUniqueName = (1 << 9), + CV_TypeProp_Sealed = (1 << 10), + // HFA: 11,12 + CV_TypeProp_Intrinsic = (1 << 13), + // MOCOM: 14,15 +}; + +#define CV_TypeProps_ExtractHFA(f) (((f)>>11)&0x3) +#define CV_TypeProps_ExtractMOCOM(f) (((f)>>14)&0x3) + +typedef U8 CV_PointerKind; +typedef enum{ + CV_PointerKind_Near, // 16 bit + CV_PointerKind_Far, // 16:16 bit + CV_PointerKind_Huge, // 16:16 bit + CV_PointerKind_BaseSeg, + CV_PointerKind_BaseVal, + CV_PointerKind_BaseSegVal, + CV_PointerKind_BaseAddr, + CV_PointerKind_BaseSegAddr, + CV_PointerKind_BaseType, + CV_PointerKind_BaseSelf, + CV_PointerKind_Near32, // 32 bit + CV_PointerKind_Far32, // 16:32 bit + CV_PointerKind_64, // 64 bit +} CV_PointerKindEnum; + +typedef U8 CV_PointerMode; +typedef enum{ + CV_PointerMode_Ptr, + CV_PointerMode_LRef, + CV_PointerMode_PtrMem, + CV_PointerMode_PtrMethod, + CV_PointerMode_RRef, +} CV_PointerModeEnum; + +typedef U16 CV_MemberPointerKind; +typedef enum{ + CV_MemberPointerKind_Undef, + CV_MemberPointerKind_DataSingle, + CV_MemberPointerKind_DataMultiple, + CV_MemberPointerKind_DataVirtual, + CV_MemberPointerKind_DataGeneral, + CV_MemberPointerKind_FuncSingle, + CV_MemberPointerKind_FuncMultiple, + CV_MemberPointerKind_FuncVirtual, + CV_MemberPointerKind_FuncGeneral, +} CV_MemberPointerKindEnum; + +typedef U32 CV_VirtualTableShape; +typedef enum{ + CV_VirtualTableShape_Near, // 16 bit ptr + CV_VirtualTableShape_Far, // 16:16 bit ptr + CV_VirtualTableShape_Thin, // ??? + CV_VirtualTableShape_Outer, // address point displacment to outermost class entry[-1] + CV_VirtualTableShape_Meta, // far pointer to metaclass descriptor entry[-2] + CV_VirtualTableShape_Near32, // 32 bit ptr + CV_VirtualTableShape_Far32, // ??? +} CV_VirtualTableShapeEnum; + +typedef U8 CV_MethodProp; +enum{ + CV_MethodProp_Vanilla, + CV_MethodProp_Virtual, + CV_MethodProp_Static, + CV_MethodProp_Friend, + CV_MethodProp_Intro, + CV_MethodProp_PureVirtual, + CV_MethodProp_PureIntro, +}; + +typedef U8 CV_MemberAccess; +typedef enum{ + CV_MemberAccess_Null, + CV_MemberAccess_Private, + CV_MemberAccess_Protected, + CV_MemberAccess_Public +} CV_MemberAccessEnum; + +typedef U16 CV_FieldAttribs; +enum{ + // Access: 0,1 + // MethodProp: [2:4] + CV_FieldAttrib_Pseudo = (1 << 5), + CV_FieldAttrib_NoInherit = (1 << 6), + CV_FieldAttrib_NoConstruct = (1 << 7), + CV_FieldAttrib_CompilerGenated = (1 << 8), + CV_FieldAttrib_Sealed = (1 << 9), +}; +#define CV_FieldAttribs_ExtractAccess(f) ((f)&0x3) +#define CV_FieldAttribs_ExtractMethodProp(f) (((f)>>2)&0x7) + +typedef U16 CV_LabelKind; +typedef enum{ + CV_LabelKind_Near = 0, + CV_LabelKind_Far = 4, +} CV_LabelKindEnum; + +typedef U8 CV_FunctionAttribs; +enum{ + CV_FunctionAttrib_CxxReturnUDT = (1 << 0), + CV_FunctionAttrib_Constructor = (1 << 1), + CV_FunctionAttrib_ConstructorVBase = (1 << 2), +}; + +typedef U8 CV_CallKind; +typedef enum{ + CV_CallKind_NearC, + CV_CallKind_FarC, + CV_CallKind_NearPascal, + CV_CallKind_FarPascal, + CV_CallKind_NearFast, + CV_CallKind_FarFast, + CV_CallKind_UNUSED, + CV_CallKind_NearStd, + CV_CallKind_FarStd, + CV_CallKind_NearSys, + CV_CallKind_FarSys, + CV_CallKind_This, + CV_CallKind_Mips, + CV_CallKind_Generic, + CV_CallKind_Alpha, + CV_CallKind_PPC, + CV_CallKind_HitachiSuperH, + CV_CallKind_Arm, + CV_CallKind_AM33, + CV_CallKind_TriCore, + CV_CallKind_HitachiSuperH5, + CV_CallKind_M32R, + CV_CallKind_Clr, + CV_CallKind_Inline, + CV_CallKind_NearVector, +} CV_CallKindEnum; + +// (LeafKind: PRECOMP) +typedef struct CV_LeafPreComp{ + U32 start_index; + U32 count; + U32 signature; + // U8[] name (null terminated) +} CV_LeafPreComp; + +// (LeafKind: TYPESERVER) +typedef struct CV_LeafTypeServer{ + U32 sig; + U32 age; + // U8[] name (null terminated) +} CV_LeafTypeServer; + +// (LeafKind: TYPESERVER2) +typedef struct CV_LeafTypeServer2{ + COFF_Guid sig70; + U32 age; + // U8[] name (null terminated) +} CV_LeafTypeServer2; + +// (LeafKind: SKIP) +typedef struct CV_LeafSkip{ + CV_TypeId itype; +} CV_LeafSkip; + +// (LeafKind: VTSHAPE) +typedef struct CV_LeafVTShape{ + U16 count; + // U4[count] shapes (CV_VirtualTableShape) +} CV_LeafVTShape; + +// (LeafKind: LABEL) +typedef struct CV_LeafLabel{ + CV_LabelKind kind; +} CV_LeafLabel; + +// (LeafKind: MODIFIER) +typedef U16 CV_ModifierFlags; +enum{ + CV_ModifierFlag_Const = (1 << 0), + CV_ModifierFlag_Volatile = (1 << 1), + CV_ModifierFlag_Unaligned = (1 << 2), +}; + +typedef struct CV_LeafModifier{ + CV_TypeId itype; + CV_ModifierFlags flags; +} CV_LeafModifier; + +// (LeafKind: POINTER) +typedef U32 CV_PointerAttribs; +enum{ + // Kind: [0:4] + // Mode: [5:7] + CV_PointerAttrib_IsFlat = (1 << 8), + CV_PointerAttrib_Volatile = (1 << 9), + CV_PointerAttrib_Const = (1 << 10), + CV_PointerAttrib_Unaligned = (1 << 11), + CV_PointerAttrib_Restricted = (1 << 12), + // Size: [13,18] + CV_PointerAttrib_MOCOM = (1 << 19), + CV_PointerAttrib_LRef = (1 << 21), + CV_PointerAttrib_RRef = (1 << 22) +}; + +#define CV_PointerAttribs_ExtractKind(a) ((a)&0x1F) +#define CV_PointerAttribs_ExtractMode(a) (((a)>>5)&0x7) +#define CV_PointerAttribs_ExtractSize(a) (((a)>>13)&0x3F) + +typedef struct CV_LeafPointer{ + CV_TypeId itype; + CV_PointerAttribs attribs; +} CV_LeafPointer; + +// (LeafKind: PROCEDURE) +typedef struct CV_LeafProcedure{ + CV_TypeId ret_itype; + CV_CallKind call_kind; + CV_FunctionAttribs attribs; + U16 arg_count; + CV_TypeId arg_itype; +} CV_LeafProcedure; + +// (LeafKind: MFUNCTION) +typedef struct CV_LeafMFunction{ + CV_TypeId ret_itype; + CV_TypeId class_itype; + CV_TypeId this_itype; + CV_CallKind call_kind; + CV_FunctionAttribs attribs; + U16 arg_count; + CV_TypeId arg_itype; + S32 this_adjust; +} CV_LeafMFunction; + +// (LeafKind: ARGLIST) +typedef struct CV_LeafArgList{ + U32 count; + // CV_TypeId[count] itypes; +} CV_LeafArgList; + +// (LeafKind: BITFIELD) +typedef struct CV_LeafBitField{ + CV_TypeId itype; + U8 len; + U8 pos; +} CV_LeafBitField; + +// (LeafKind: METHODLIST) +// ("jagged" array of these vvvvvvvv) +typedef struct CV_LeafMethodListMember{ + CV_FieldAttribs attribs; + U16 pad; + CV_TypeId itype; + // U32 vbaseoff (when Intro or PureIntro) +} CV_LeafMethodListMember; + +// (LeafKind: INDEX) +typedef struct CV_LeafIndex{ + U16 pad; + CV_TypeId itype; +} CV_LeafIndex; + +// (LeafKind: ARRAY) +typedef struct CV_LeafArray{ + CV_TypeId entry_itype; + CV_TypeId index_itype; + // CV_Numeric count +} CV_LeafArray; + +// (LeafKind: CLASS, STRUCTURE, INTERFACE) +typedef struct CV_LeafStruct{ + U16 count; + CV_TypeProps props; + CV_TypeId field_itype; + CV_TypeId derived_itype; + CV_TypeId vshape_itype; + // CV_Numeric size + // U8[] name (null terminated) + // U8[] unique_name (null terminated) +} CV_LeafStruct; + +// (LeafKind: UNION) +typedef struct CV_LeafUnion{ + U16 count; + CV_TypeProps props; + CV_TypeId field_itype; + // CV_Numeric size + // U8[] name (null terminated) + // U8[] unique_name (null terminated) +} CV_LeafUnion; + +// (LeafKind: ENUM) +typedef struct CV_LeafEnum{ + U16 count; + CV_TypeProps props; + CV_TypeId base_itype; + CV_TypeId field_itype; + // U8[] name (null terminated) + // U8[] unique_name (null terminated) +} CV_LeafEnum; + +// (LeafKind: ALIAS) +typedef struct CV_LeafAlias{ + CV_TypeId itype; + // U8[] name (null terminated) +} CV_LeafAlias; + +// (LeafKind: MEMBER) +typedef struct CV_LeafMember{ + CV_FieldAttribs attribs; + CV_TypeId itype; + // CV_Numeric offset + // U8[] name (null terminated) +} CV_LeafMember; + +// (LeafKind: STMEMBER) +typedef struct CV_LeafStMember{ + CV_FieldAttribs attribs; + CV_TypeId itype; + // U8[] name (null terminated) +} CV_LeafStMember; + +// (LeafKind: METHOD) +typedef struct CV_LeafMethod{ + U16 count; + CV_TypeId list_itype; + // U8[] name (null terminated) +} CV_LeafMethod; + +// (LeafKind: ONEMETHOD) +typedef struct CV_LeafOneMethod{ + CV_FieldAttribs attribs; + CV_TypeId itype; + // U32 vbaseoff (when Intro or PureIntro) + // U8[] name (null terminated) +} CV_LeafOneMethod; + +// (LeafKind: ENUMERATE) +typedef struct CV_LeafEnumerate{ + CV_FieldAttribs attribs; + // CV_Numeric val + // U8[] name (null terminated) +} CV_LeafEnumerate; + +// (LeafKind: NESTTYPE) +typedef struct CV_LeafNestType{ + U16 pad; + CV_TypeId itype; + // U8[] name (null terminated) +} CV_LeafNestType; + +// (LeafKind: NESTTYPEEX) +typedef struct CV_LeafNestTypeEx{ + CV_FieldAttribs attribs; + CV_TypeId itype; + // U8[] name (null terminated) +} CV_LeafNestTypeEx; + +// (LeafKind: BCLASS) +typedef struct CV_LeafBClass{ + CV_FieldAttribs attribs; + CV_TypeId itype; + // CV_Numeric offset +} CV_LeafBClass; + +// (LeafKind: VBCLASS, IVBCLASS) +typedef struct CV_LeafVBClass{ + CV_FieldAttribs attribs; + CV_TypeId itype; + CV_TypeId vbptr_itype; + // CV_Numeric vbptr_off + // CV_Numeric vtable_off +} CV_LeafVBClass; + +// (LeafKind: VFUNCTAB) +typedef struct CV_LeafVFuncTab{ + U16 pad; + CV_TypeId itype; +} CV_LeafVFuncTab; + +// (LeafKind: VFUNCOFF) +typedef struct CV_LeafVFuncOff{ + U16 pad; + CV_TypeId itype; + U32 off; +} CV_LeafVFuncOff; + +// (LeafKind: VFTABLE) +typedef struct CV_LeafVFTable{ + CV_TypeId owner_itype; + CV_TypeId base_table_itype; + U32 offset_in_object_layout; + U32 names_len; + // U8[] names (multiple null terminated strings) +} CV_LeafVFTable; + +// (LeafKind: VFTPATH) +typedef struct CV_LeafVFPath{ + U32 count; + // CV_TypeId[count] base; +} CV_LeafVFPath; + +// (LeafKind: CLASS2, CLASS2) +typedef struct CV_LeafStruct2{ + // NOTE: still reverse engineering this - if you find docs please help! + CV_TypeProps props; + U16 unknown1; + CV_TypeId field_itype; + CV_TypeId derived_itype; + CV_TypeId vshape_itype; + U16 unknown2; + U16 size; + // U8[] name (null terminated) + // U8[] unique_name (null terminated) +} CV_LeafStruct2; + + +// (LeafIDKind: FUNC_ID) +typedef struct CV_LeafFuncId{ + CV_ItemId scope_string_id; + CV_TypeId itype; + // U8[] name (null terminated) +} CV_LeafFuncId; + +// (LeafIDKind: MFUNC_ID) +typedef struct CV_LeafMFuncId{ + CV_TypeId owner_itype; + CV_TypeId itype; + // U8[] name (null terminated) +} CV_LeafMFuncId; + +// (LeafIDKind: STRING_ID) +typedef struct CV_LeafStringId{ + CV_ItemId substr_list_id; + // U8[] string (null terminated) +} CV_LeafStringId; + +// (LeafIDKind: BUILDINFO) +typedef enum{ + CV_BuildInfoIndex_BuildDirectory = 0, + CV_BuildInfoIndex_CompilerExecutable = 1, + CV_BuildInfoIndex_TargetSourceFile = 2, + CV_BuildInfoIndex_CombinedPdb = 3, + CV_BuildInfoIndex_CompileArguments = 4, +} CV_BuildInfoIndexEnum; + +typedef struct CV_LeafBuildInfo{ + U16 count; + // CV_ItemId[count] items +} CV_LeafBuildInfo; + +// (LeafIDKind: SUBSTR_LIST) +typedef struct CV_LeafSubstrList{ + U32 count; + // CV_ItemId[count] items +} CV_LeafSubstrList; + +// (LeafIDKind: UDT_SRC_LINE) +typedef struct CV_LeafUDTSrcLine{ + CV_TypeId udt_itype; + CV_ItemId src_string_id; + U32 line; +} CV_LeafUDTSrcLine; + +// (LeafIDKind: UDT_MOD_SRC_LINE) +typedef struct CV_LeafUDTModSrcLine{ + CV_TypeId udt_itype; + CV_ItemId src_string_id; + U32 line; + CV_ModIndex imod; +} CV_LeafUDTModSrcLine; + + +//////////////////////////////// +//~ CodeView Format C13 Line Info Types + +#define CV_C13_SubSectionKind_IgnoreFlag 0x80000000 + +#define CV_C13_SubSectionKindXList(X)\ +X(Symbols, 0xF1)\ +X(Lines, 0xF2)\ +X(StringTable, 0xF3)\ +X(FileChksms, 0xF4)\ +X(FrameData, 0xF5)\ +X(InlineeLines, 0xF6)\ +X(CrossScopeImports, 0xF7)\ +X(CrossScopeExports, 0xF8)\ +X(IlLines, 0xF9)\ +X(FuncMDTokenMap, 0xFA)\ +X(TypeMDTokenMap, 0xFB)\ +X(MergedAssemblyInput, 0xFC)\ +X(CoffSymbolRVA, 0xFD) + +typedef U32 CV_C13_SubSectionKind; +typedef enum{ +#define X(N,c) CV_C13_SubSectionKind_##N = c, + CV_C13_SubSectionKindXList(X) +#undef X +} CV_C13_SubSectionKindEnum; + +typedef struct CV_C13_SubSectionHeader{ + CV_C13_SubSectionKind kind; + U32 size; +} CV_C13_SubSectionHeader; + +//- FileChksms sub-section + +typedef U8 CV_C13_ChecksumKind; +typedef enum{ + CV_C13_ChecksumKind_Null, + CV_C13_ChecksumKind_MD5, + CV_C13_ChecksumKind_SHA1, + CV_C13_ChecksumKind_SHA256, +} CV_C13_ChecksumKindEnum; + +typedef struct CV_C13_Checksum{ + U32 name_off; + U8 len; + CV_C13_ChecksumKind kind; +} CV_C13_Checksum; + +//- Lines sub-section + +typedef U16 CV_C13_SubSecLinesFlags; +enum{ + CV_C13_SubSecLinesFlag_HasColumns = (1 << 0) +}; + +typedef struct CV_C13_SubSecLinesHeader{ + U32 sec_off; + CV_SectionIndex sec; + CV_C13_SubSecLinesFlags flags; + U32 len; +} CV_C13_SubSecLinesHeader; + +typedef struct CV_C13_File{ + U32 file_off; + U32 num_lines; + U32 block_size; + // CV_C13_Line[num_lines] lines; + // CV_C13_Column[num_lines] columns; (if HasColumns) +} CV_C13_File; + +typedef U32 CV_C13_LineFlags; +#define CV_C13_LineFlags_ExtractLineNumber(f) ((f)&0xFFFFFF) +#define CV_C13_LineFlags_ExtractDeltaToEnd(f) (((f)>>24)&0x7F) +#define CV_C13_LineFlags_ExtractStatement(f) (((f)>>31)&0x1) + +typedef struct CV_C13_Line{ + U32 off; + CV_C13_LineFlags flags; +} CV_C13_Line; + +typedef struct CV_C13_Column{ + U16 start; + U16 end; +} CV_C13_Column; + +//- FrameData sub-section + +typedef U32 CV_C13_FrameDataFlags; +enum{ + CV_C13_FrameDataFlag_HasStructuredExceptionHandling = (1 << 0), + CV_C13_FrameDataFlag_HasExceptionHandling = (1 << 1), + CV_C13_FrameDataFlag_HasIsFuncStart = (1 << 2), +}; + +typedef struct CV_C13_FrameData{ + U32 start_voff; + U32 code_size; + U32 local_size; + U32 params_size; + U32 max_stack_size; + U32 frame_func; + U16 prolog_size; + U16 saved_reg_size; + CV_C13_FrameDataFlags flags; +} CV_C13_FrameData; + +#pragma pack(pop) + +//////////////////////////////// +//~ CodeView Common Parser Types + +// CV_Numeric layout +// x: U16 +// buf: U8[] +// case (x < 0x8000): kind=U16 val=x +// case (x >= 0x8000): kind=x val=buf + +typedef struct CV_NumericParsed{ + CV_NumericKind kind; + U8 *val; + U64 encoded_size; +} CV_NumericParsed; + +typedef struct CV_RecRange{ + U32 off; + CV_RecHeader hdr; +} CV_RecRange; + +#define CV_REC_RANGE_CHUNK_SIZE 511 + +typedef struct CV_RecRangeChunk{ + struct CV_RecRangeChunk *next; + CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE]; +} CV_RecRangeChunk; + +typedef struct CV_RecRangeStream{ + CV_RecRangeChunk *first_chunk; + CV_RecRangeChunk *last_chunk; + U64 total_count; +} CV_RecRangeStream; + +typedef struct CV_RecRangeArray{ + CV_RecRange *ranges; + U64 count; +} CV_RecRangeArray; + +//////////////////////////////// +//~ CodeView Sym Parser Types + +typedef struct CV_SymTopLevelInfo{ + CV_Arch arch; + CV_Language language; + String8 compiler_name; +} CV_SymTopLevelInfo; + +typedef struct CV_SymParsed{ + // source information + String8 data; + U64 sym_align; + + // sym index derived from source + CV_RecRangeArray sym_ranges; + + // top-level info derived from the syms + CV_SymTopLevelInfo info; +} CV_SymParsed; + + +//////////////////////////////// +//~ CodeView Leaf Parser Types + +typedef struct CV_LeafParsed{ + // source information + String8 data; + CV_TypeId itype_first; + CV_TypeId itype_opl; + + // leaf index derived from source + CV_RecRangeArray leaf_ranges; +} CV_LeafParsed; + +//////////////////////////////// +//~ CodeView C13 Info Parser Types + +typedef struct CV_C13LinesParsed{ + // raw info + U32 sec_idx; + U32 file_off; + U64 secrel_base_off; + + // parsed info + String8 file_name; + U64 *voffs; // [line_count + 1] + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + U32 line_count; +} CV_C13LinesParsed; + +typedef struct CV_C13SubSectionNode{ + struct CV_C13SubSectionNode *next; + CV_C13_SubSectionKind kind; + U32 off; + U32 size; + union{ + CV_C13LinesParsed *lines; + }; +} CV_C13SubSectionNode; + +typedef struct CV_C13Parsed{ + CV_C13SubSectionNode *first_sub_section; + CV_C13SubSectionNode *last_sub_section; + U64 sub_section_count; + + // accelerator + CV_C13SubSectionNode *file_chksms_sub_section; +} CV_C13Parsed; + + +//////////////////////////////// +//~ CodeView Compound Types + +typedef struct CV_TypeIdArray{ + CV_TypeId *itypes; + U64 count; +} CV_TypeIdArray; + + +//////////////////////////////// +//~ CodeView Common Functions + +static CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl); + +static B32 cv_numeric_fits_in_u64(CV_NumericParsed *num); +static B32 cv_numeric_fits_in_s64(CV_NumericParsed *num); +static B32 cv_numeric_fits_in_f64(CV_NumericParsed *num); + +static U64 cv_u64_from_numeric(CV_NumericParsed *num); +static S64 cv_s64_from_numeric(CV_NumericParsed *num); +static F64 cv_f64_from_numeric(CV_NumericParsed *num); + +//////////////////////////////// +//~ CodeView Sym/Leaf Parser Functions + +//- the first pass parser +static CV_RecRangeStream* cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align); + +//- sym +static CV_SymParsed* cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align); + +static void cv_sym_top_level_info_from_syms(Arena *arena, String8 sym_data, + CV_RecRangeArray *ranges, + CV_SymTopLevelInfo *info_out); + +//- leaf +static CV_LeafParsed* cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first); + +//- range streams +static CV_RecRangeChunk* cv_rec_range_stream_push_chunk(Arena *arena, + CV_RecRangeStream *stream); +// TODO(allen): check why this isn't a pointer return - +// leave a note if there's a good reason, otherwise switch to pointer return +static CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, + CV_RecRangeStream *stream); + +//////////////////////////////// +//~ CodeView C13 Parser Functions + +typedef struct PDB_Strtbl PDB_Strtbl; +typedef struct PDB_CoffSectionArray PDB_CoffSectionArray; +static CV_C13Parsed* cv_c13_from_data(Arena *arena, String8 c13_data, + struct PDB_Strtbl *strtbl, struct PDB_CoffSectionArray *sections); + +#endif //RADDBG_CODEVIEW_H diff --git a/src/raddbg_convert/pdb/raddbg_codeview_conversion.c b/src/raddbg_convert/pdb/raddbg_codeview_conversion.c new file mode 100644 index 00000000..9930b4ed --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_codeview_conversion.c @@ -0,0 +1,124 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ CodeView Conversion Functions + +static RADDBG_Arch +raddbg_arch_from_cv_arch(CV_Arch cv_arch){ + RADDBG_Arch result = 0; + switch (cv_arch){ + case CV_Arch_8086: result = RADDBG_Arch_X86; break; + case CV_Arch_X64: result = RADDBG_Arch_X64; break; + + //case CV_Arch_8080: break; + //case CV_Arch_80286: break; + //case CV_Arch_80386: break; + //case CV_Arch_80486: break; + //case CV_Arch_PENTIUM: break; + //case CV_Arch_PENTIUMII: break; + //case CV_Arch_PENTIUMIII: break; + //case CV_Arch_MIPS: break; + //case CV_Arch_MIPS16: break; + //case CV_Arch_MIPS32: break; + //case CV_Arch_MIPS64: break; + //case CV_Arch_MIPSI: break; + //case CV_Arch_MIPSII: break; + //case CV_Arch_MIPSIII: break; + //case CV_Arch_MIPSIV: break; + //case CV_Arch_MIPSV: break; + //case CV_Arch_M68000: break; + //case CV_Arch_M68010: break; + //case CV_Arch_M68020: break; + //case CV_Arch_M68030: break; + //case CV_Arch_M68040: break; + //case CV_Arch_ALPHA: break; + //case CV_Arch_ALPHA_21164: break; + //case CV_Arch_ALPHA_21164A: break; + //case CV_Arch_ALPHA_21264: break; + //case CV_Arch_ALPHA_21364: break; + //case CV_Arch_PPC601: break; + //case CV_Arch_PPC603: break; + //case CV_Arch_PPC604: break; + //case CV_Arch_PPC620: break; + //case CV_Arch_PPCFP: break; + //case CV_Arch_PPCBE: break; + //case CV_Arch_SH3: break; + //case CV_Arch_SH3E: break; + //case CV_Arch_SH3DSP: break; + //case CV_Arch_SH4: break; + //case CV_Arch_SHMEDIA: break; + //case CV_Arch_ARM3: break; + //case CV_Arch_ARM4: break; + //case CV_Arch_ARM4T: break; + //case CV_Arch_ARM5: break; + //case CV_Arch_ARM5T: break; + //case CV_Arch_ARM6: break; + //case CV_Arch_ARM_XMAC: break; + //case CV_Arch_ARM_WMMX: break; + //case CV_Arch_ARM7: break; + //case CV_Arch_OMNI: break; + //case CV_Arch_IA64_1: break; + //case CV_Arch_IA64_2: break; + //case CV_Arch_CEE: break; + //case CV_Arch_AM33: break; + //case CV_Arch_M32R: break; + //case CV_Arch_TRICORE: break; + //case CV_Arch_EBC: break; + //case CV_Arch_THUMB: break; + //case CV_Arch_ARMNT: break; + //case CV_Arch_ARM64: break; + //case CV_Arch_D3D11_SHADER: break; + } + return(result); +} + +static RADDBG_RegisterCode +raddbg_reg_code_from_cv_reg_code(RADDBG_Arch arch, CV_Reg reg_code){ + RADDBG_RegisterCode result = 0; + switch (arch){ + case RADDBG_Arch_X86: + { + switch (reg_code){ +#define X(CVN,C,RDN,BP,BZ) case C: result = RADDBG_RegisterCode_X86_##RDN; break; + CV_Reg_X86_XList(X) +#undef X + } + }break; + + case RADDBG_Arch_X64: + { + switch (reg_code){ +#define X(CVN,C,RDN,BP,BZ) case C: result = RADDBG_RegisterCode_X64_##RDN; break; + CV_Reg_X64_XList(X) +#undef X + } + }break; + } + return(result); +} + +static RADDBG_Language +raddbg_language_from_cv_language(CV_Language cv_language){ + RADDBG_Language result = 0; + switch (cv_language){ + case CV_Language_C: result = RADDBG_Language_C; break; + case CV_Language_CXX: result = RADDBG_Language_CPlusPlus; break; + //case CV_Language_FORTRAN: result = ; break; + //case CV_Language_MASM: result = ; break; + //case CV_Language_PASCAL: result = ; break; + //case CV_Language_BASIC: result = ; break; + //case CV_Language_COBOL: result = ; break; + //case CV_Language_LINK: result = ; break; + //case CV_Language_CVTRES: result = ; break; + //case CV_Language_CVTPGD: result = ; break; + //case CV_Language_CSHARP: result = ; break; + //case CV_Language_VB: result = ; break; + //case CV_Language_ILASM: result = ; break; + //case CV_Language_JAVA: result = ; break; + //case CV_Language_JSCRIPT: result = ; break; + //case CV_Language_MSIL: result = ; break; + //case CV_Language_HLSL: result = ; break; + } + return(result); +} diff --git a/src/raddbg_convert/pdb/raddbg_codeview_conversion.h b/src/raddbg_convert/pdb/raddbg_codeview_conversion.h new file mode 100644 index 00000000..369e0949 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_codeview_conversion.h @@ -0,0 +1,14 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_CODEVIEW_CONVERSION_H +#define RADDBG_CODEVIEW_CONVERSION_H + +//////////////////////////////// +//~ CodeView Conversion Functions + +static RADDBG_Arch raddbg_arch_from_cv_arch(CV_Arch arch); +static RADDBG_RegisterCode raddbg_reg_code_from_cv_reg_code(RADDBG_Arch arch, CV_Reg reg_code); +static RADDBG_Language raddbg_language_from_cv_language(CV_Language language); + +#endif //RADDBG_CODEVIEW_CONVERSION_H diff --git a/src/raddbg_convert/pdb/raddbg_codeview_stringize.c b/src/raddbg_convert/pdb/raddbg_codeview_stringize.c new file mode 100644 index 00000000..1dee063d --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_codeview_stringize.c @@ -0,0 +1,2385 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ CodeView Common Stringize Functions + +static void +cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num){ + String8 numeric_kind_str = cv_string_from_numeric_kind(num->kind); + str8_list_pushf(arena, out, "(%.*s)", str8_varg(numeric_kind_str)); + + if (cv_numeric_fits_in_u64(num)){ + U64 n = cv_u64_from_numeric(num); + str8_list_pushf(arena, out, "(%llu)", n); + } + else if (cv_numeric_fits_in_s64(num)){ + S64 n = cv_s64_from_numeric(num); + str8_list_pushf(arena, out, "(%lld)", n); + } + else if (cv_numeric_fits_in_f64(num)){ + F64 n = cv_f64_from_numeric(num); + str8_list_pushf(arena, out, "(%f)", n); + } +} + +static void +cv_stringize_lvar_addr_range(Arena *arena, String8List *out, CV_LvarAddrRange *range){ + str8_list_pushf(arena, out, "{off=%x, sec=%u, len=%u}", range->off, range->sec, range->len); +} + +static void +cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap){ + str8_list_pushf(arena, out, "{off=%x, len=%u}", gap->off, gap->len); +} + +static void +cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, void *first, void *opl){ + U64 gap_count = ((U8*)first - (U8*)opl)/sizeof(CV_LvarAddrGap); + if (gap_count > 0){ + str8_list_push(arena, out, str8_lit(" gaps=\n")); + CV_LvarAddrGap *gap = (CV_LvarAddrGap*)first; + CV_LvarAddrGap *opl = gap + gap_count; + for (;gap < opl; gap += 1){ + str8_list_push(arena, out, str8_lit(" ")); + cv_stringize_lvar_addr_gap(arena, out, gap); + str8_list_push(arena, out, str8_lit("\n")); + } + } +} + +static String8 +cv_string_from_sym_kind(CV_SymKind kind){ + String8 result = str8_lit("UNRECOGNIZED_SYM_KIND"); + switch (kind){ +#define X(N,c) case CV_SymKind_##N: result = str8_lit(#N); break; + CV_SymKindXList(X) +#undef X + } + return(result); +} + +static String8 +cv_string_from_basic_type(CV_BasicType basic_type){ + String8 result = str8_lit("UNRECOGNIZED_BASIC_TYPE"); + switch (basic_type){ +#define X(N,c) case CV_BasicType_##N: result = str8_lit(#N); break; + CV_BasicTypeXList(X) +#undef X + } + return(result); +} + +static String8 +cv_string_from_leaf_kind(CV_LeafKind kind){ + String8 result = str8_lit("UNRECOGNIZED_LEAF_KIND"); + switch (kind){ +#define X(N,c) case CV_LeafKind_##N: result = str8_lit(#N); break; + CV_LeafKindXList(X) +#undef X + +#define X(N,c) case CV_LeafIDKind_##N: result = str8_lit(#N); break; + CV_LeafIDKindXList(X) +#undef X + } + return(result); +} + +static String8 +cv_string_from_numeric_kind(CV_NumericKind kind){ + String8 result = str8_lit("UNRECOGNIZED_NUMERIC_KIND"); + switch (kind){ + case 0: str8_lit("PARSE_ERROR"); break; +#define X(N,c) case CV_NumericKind_##N: result = str8_lit(#N); break; + CV_NumericKindXList(X) +#undef X + } + return(result); +} + +static String8 +cv_string_from_c13_sub_section_kind(CV_C13_SubSectionKind kind){ + String8 result = str8_lit("UNRECOGNIZED_C13_SUB_SECTION_KIND"); + switch (kind){ + case 0: str8_lit("PARSE_ERROR"); break; +#define X(N,c) case CV_C13_SubSectionKind_##N: result = str8_lit(#N); break; + CV_C13_SubSectionKindXList(X) +#undef X + } + return(result); +} + +static String8 +cv_string_from_machine(CV_Arch arch){ + String8 result = {0}; + switch (arch){ +#define X(N,c) case CV_Arch_##N: result = str8_lit(#N); break; + CV_ArchXList(X) +#undef X + } + return(result); +} + +static String8 +cv_string_from_reg(CV_Arch arch, CV_Reg reg){ + String8 result = {0}; + switch (arch){ + default: result = str8_lit(""); break; + + case CV_Arch_8086: + { + switch (reg){ +#define X(CVN,C,RDN,BP,BZ) case CV_Regx86_##CVN: result = str8_lit(#CVN); break; + CV_Reg_X86_XList(X) +#undef X + } + }break; + + case CV_Arch_X64: + { + switch (reg){ +#define X(CVN,C,RDN,BP,BZ) case CV_Regx64_##CVN: result = str8_lit(#CVN); break; + CV_Reg_X64_XList(X) +#undef X + } + }break; + } + return(result); +} + +static String8 +cv_string_from_pointer_kind(CV_PointerKind ptr_kind){ + String8 result = {0}; + switch (ptr_kind){ + default: result = str8_lit(""); break; + case CV_PointerKind_Near: result = str8_lit("Near"); break; + case CV_PointerKind_Far: result = str8_lit("Far"); break; + case CV_PointerKind_Huge: result = str8_lit("Huge"); break; + case CV_PointerKind_BaseSeg: result = str8_lit("BaseSeg"); break; + case CV_PointerKind_BaseVal: result = str8_lit("BaseVal"); break; + case CV_PointerKind_BaseSegVal: result = str8_lit("BaseSegVal"); break; + case CV_PointerKind_BaseAddr: result = str8_lit("BaseAddr"); break; + case CV_PointerKind_BaseSegAddr: result = str8_lit("BaseSegAddr"); break; + case CV_PointerKind_BaseType: result = str8_lit("BaseType"); break; + case CV_PointerKind_BaseSelf: result = str8_lit("BaseSelf"); break; + case CV_PointerKind_Near32: result = str8_lit("Near32"); break; + case CV_PointerKind_Far32: result = str8_lit("Far32"); break; + case CV_PointerKind_64: result = str8_lit("64"); break; + } + return(result); +} + +static String8 +cv_string_from_pointer_mode(CV_PointerMode ptr_mode){ + String8 result = {0}; + switch (ptr_mode){ + default: result = str8_lit(""); break; + case CV_PointerMode_Ptr: result = str8_lit("Ptr"); break; + case CV_PointerMode_LRef: result = str8_lit("LRef"); break; + case CV_PointerMode_PtrMem: result = str8_lit("PtrMem"); break; + case CV_PointerMode_PtrMethod: result = str8_lit("PtrMethod"); break; + case CV_PointerMode_RRef: result = str8_lit("RRef"); break; + } + return(result); +} + +static String8 +cv_string_from_hfa_kind(CV_HFAKind hfa_kind){ + String8 result = {0}; + switch (hfa_kind){ + default: result = str8_lit(""); break; + case CV_HFAKind_None: result = str8_lit("None"); break; + case CV_HFAKind_Float: result = str8_lit("Float"); break; + case CV_HFAKind_Double: result = str8_lit("Double"); break; + case CV_HFAKind_Other: result = str8_lit("Other"); break; + } + return(result); +} + +static String8 +cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind){ + String8 result = {0}; + switch (mo_com_udt_kind){ + default: result = str8_lit(""); break; + case CV_MoComUDTKind_None: result = str8_lit("None"); break; + case CV_MoComUDTKind_Ref: result = str8_lit("Ref"); break; + case CV_MoComUDTKind_Value: result = str8_lit("Value"); break; + case CV_MoComUDTKind_Interface: result = str8_lit("Interface"); break; + } + return(result); +} + +//////////////////////////////// +//~ CodeView Flags Stringize Functions + +static char cv_stringize_spaces[] = " "; + +#define SPACES cv_stringize_spaces + +static void +cv_stringize_modifier_flags(Arena *arena, String8List *out, + U32 indent, CV_ModifierFlags flags){ + if (flags & CV_ModifierFlag_Const){ + str8_list_pushf(arena, out, "%.*sConst\n", indent, SPACES); + } + if (flags & CV_ModifierFlag_Volatile){ + str8_list_pushf(arena, out, "%.*sVolatile\n", indent, SPACES); + } + if (flags & CV_ModifierFlag_Unaligned){ + str8_list_pushf(arena, out, "%.*sUnaligned\n", indent, SPACES); + } +} + +static void +cv_stringize_type_props(Arena *arena, String8List *out, + U32 indent, CV_TypeProps props){ + if (props & CV_TypeProp_Packed){ + str8_list_pushf(arena, out, "%.*sPacked\n", indent, SPACES); + } + if (props & CV_TypeProp_HasConstructorsDestructors){ + str8_list_pushf(arena, out, "%.*sHasConstructorsDesctructors\n", indent, SPACES); + } + if (props & CV_TypeProp_OverloadedOperators){ + str8_list_pushf(arena, out, "%.*sOverloadedOperators\n", indent, SPACES); + } + if (props & CV_TypeProp_IsNested){ + str8_list_pushf(arena, out, "%.*sIsNested\n", indent, SPACES); + } + if (props & CV_TypeProp_ContainsNested){ + str8_list_pushf(arena, out, "%.*sContainsNested\n", indent, SPACES); + } + if (props & CV_TypeProp_OverloadedAssignment){ + str8_list_pushf(arena, out, "%.*sOverloadedAssignment\n", indent, SPACES); + } + if (props & CV_TypeProp_OverloadedCasting){ + str8_list_pushf(arena, out, "%.*sOverloadedCasting\n", indent, SPACES); + } + if (props & CV_TypeProp_FwdRef){ + str8_list_pushf(arena, out, "%.*sFwdRef\n", indent, SPACES); + } + if (props & CV_TypeProp_Scoped){ + str8_list_pushf(arena, out, "%.*sScoped\n", indent, SPACES); + } + if (props & CV_TypeProp_HasUniqueName){ + str8_list_pushf(arena, out, "%.*sHasUniqueName\n", indent, SPACES); + } + if (props & CV_TypeProp_Sealed){ + str8_list_pushf(arena, out, "%.*sSealed\n", indent, SPACES); + } + if (props & CV_TypeProp_Intrinsic){ + str8_list_pushf(arena, out, "%.*sIntrinsic\n", indent, SPACES); + } + + CV_HFAKind hfa = CV_TypeProps_ExtractHFA(props); + { + String8 hfa_str = cv_string_from_hfa_kind(hfa); + str8_list_pushf(arena, out, "%.*shfa=%.*s\n", + indent, SPACES, str8_varg(hfa_str)); + } + + CV_MoComUDTKind mo_com = CV_TypeProps_ExtractMOCOM(props); + { + String8 mo_com_str = cv_string_from_mo_com_udt_kind(mo_com); + str8_list_pushf(arena, out, "%.*smocom=%.*s\n", + indent, SPACES, str8_varg(mo_com_str)); + } +} + +static void +cv_stringize_pointer_attribs(Arena *arena, String8List *out, + U32 indent, CV_PointerAttribs attribs){ + if (attribs & CV_PointerAttrib_IsFlat){ + str8_list_pushf(arena, out, "%.*sIsFlat\n", indent, SPACES); + } + if (attribs & CV_PointerAttrib_Volatile){ + str8_list_pushf(arena, out, "%.*sVolatile\n", indent, SPACES); + } + if (attribs & CV_PointerAttrib_Const){ + str8_list_pushf(arena, out, "%.*sConst\n", indent, SPACES); + } + if (attribs & CV_PointerAttrib_Unaligned){ + str8_list_pushf(arena, out, "%.*sUnaligned\n", indent, SPACES); + } + if (attribs & CV_PointerAttrib_Restricted){ + str8_list_pushf(arena, out, "%.*sRestricted\n", indent, SPACES); + } + if (attribs & CV_PointerAttrib_MOCOM){ + str8_list_pushf(arena, out, "%.*sMOCOM\n", indent, SPACES); + } + if (attribs & CV_PointerAttrib_LRef){ + str8_list_pushf(arena, out, "%.*sLRef\n", indent, SPACES); + } + if (attribs & CV_PointerAttrib_RRef){ + str8_list_pushf(arena, out, "%.*sRRef\n", indent, SPACES); + } + + CV_PointerKind kind = CV_PointerAttribs_ExtractKind(attribs); + { + String8 kind_str = cv_string_from_pointer_kind(kind); + str8_list_pushf(arena, out, "%.*skind=%.*s\n", + indent, SPACES, str8_varg(kind_str)); + } + + CV_PointerMode mode = CV_PointerAttribs_ExtractMode(attribs); + { + String8 mode_str = cv_string_from_pointer_mode(mode); + str8_list_pushf(arena, out, "%.*smode=%.*s\n", + indent, SPACES, str8_varg(mode_str)); + } + + U32 size = CV_PointerAttribs_ExtractSize(attribs); + str8_list_pushf(arena, out, "%.*ssize=%u\n", + indent, SPACES, size); +} + +static void +cv_stringize_local_flags(Arena *arena, String8List *out, + U32 indent, CV_LocalFlags flags){ + if (flags & CV_LocalFlag_Param){ + str8_list_pushf(arena, out, "%.*sParam\n", indent, SPACES); + } + if (flags & CV_LocalFlag_AddrTaken){ + str8_list_pushf(arena, out, "%.*sAddrTaken\n", indent, SPACES); + } + if (flags & CV_LocalFlag_Compgen){ + str8_list_pushf(arena, out, "%.*sCompgen\n", indent, SPACES); + } + if (flags & CV_LocalFlag_Aggregate){ + str8_list_pushf(arena, out, "%.*sAggregate\n", indent, SPACES); + } + if (flags & CV_LocalFlag_PartOfAggregate){ + str8_list_pushf(arena, out, "%.*sPartOfAggregate\n", indent, SPACES); + } + if (flags & CV_LocalFlag_Aliased){ + str8_list_pushf(arena, out, "%.*sAliased\n", indent, SPACES); + } + if (flags & CV_LocalFlag_Alias){ + str8_list_pushf(arena, out, "%.*sAlias\n", indent, SPACES); + } + if (flags & CV_LocalFlag_Retval){ + str8_list_pushf(arena, out, "%.*sRetval\n", indent, SPACES); + } + if (flags & CV_LocalFlag_OptOut){ + str8_list_pushf(arena, out, "%.*sOptOut\n", indent, SPACES); + } + if (flags & CV_LocalFlag_Global){ + str8_list_pushf(arena, out, "%.*sGlobal\n", indent, SPACES); + } + if (flags & CV_LocalFlag_Static){ + str8_list_pushf(arena, out, "%.*sStatic\n", indent, SPACES); + } +} + + +#undef SPACES + +//////////////////////////////// +//~ CodeView Sym Stringize Functions + +static void +cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym){ + CV_StringizeSymParams params = {0}; + params.arch = sym->info.arch; + + cv_stringize_sym_array(arena, out, &sym->sym_ranges, sym->data, ¶ms); +} + +static void +cv_stringize_sym_range(Arena *arena, String8List *out, + CV_RecRange *range, String8 data, + CV_StringizeSymParams *p){ + U64 opl_off = range->off + range->hdr.size; + if (opl_off > data.size){ + str8_list_push(arena, out, str8_lit("bad symbol range\n")); + } + + if (opl_off <= data.size){ + // [off]: kind + { + String8 kind_str = cv_string_from_sym_kind(range->hdr.kind); + str8_list_pushf(arena, out, "[%06x]: %.*s\n", + range->off + 2, str8_varg(kind_str)); + } + + // details + U8 *first = data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + + switch (range->hdr.kind){ + default:break; + + case CV_SymKind_COMPILE: + { + if (sizeof(CV_SymCompile) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymCompile *compile = (CV_SymCompile*)first; + + // machine + String8 machine = cv_string_from_machine(compile->machine); + str8_list_pushf(arena, out, " machine=%.*s\n", + str8_varg(machine)); + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", compile->flags); + + // ver_str + String8 ver_str = str8_cstring_capped((char*)(compile + 1), first + cap); + str8_list_pushf(arena, out, " ver_str='%.*s'\n", str8_varg(ver_str)); + } + }break; + + case CV_SymKind_END: + { + // no contents + }break; + + case CV_SymKind_FRAMEPROC: + { + if (sizeof(CV_SymFrameproc) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymFrameproc *frameproc = (CV_SymFrameproc*)first; + + // frame sizes and offsets + str8_list_pushf(arena, out, " frame_size=%u\n", + frameproc->frame_size); + str8_list_pushf(arena, out, " pad_size=%u\n", + frameproc->pad_size); + str8_list_pushf(arena, out, " pad_off=%u\n", + frameproc->pad_off); + str8_list_pushf(arena, out, " save_reg_size=%u\n", + frameproc->save_reg_size); + str8_list_pushf(arena, out, " eh_off=%x\n", + frameproc->eh_off); + + // eh section + str8_list_pushf(arena, out, " eh_sec=%u\n", + frameproc->eh_sec); + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", frameproc->flags); + } + }break; + + case CV_SymKind_OBJNAME: + { + if (sizeof(CV_SymObjname) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymObjname *objname = (CV_SymObjname*)first; + + // sig + str8_list_pushf(arena, out, " sig=%u\n", objname->sig); + + // name + String8 name = str8_cstring_capped((char*)(objname + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_THUNK32: + { + if (sizeof(CV_SymThunk32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymThunk32 *thunk32 = (CV_SymThunk32*)first; + + // members + str8_list_pushf(arena, out, " parent=%x\n", thunk32->parent); + str8_list_pushf(arena, out, " end=%x\n", thunk32->end); + str8_list_pushf(arena, out, " next=%x\n", thunk32->next); + str8_list_pushf(arena, out, " off=%u\n", thunk32->off); + str8_list_pushf(arena, out, " sec=%u\n", thunk32->sec); + str8_list_pushf(arena, out, " len=%u\n", thunk32->len); + + // ord + // TODO(allen): better ord path + str8_list_pushf(arena, out, " ord=%u\n", thunk32->ord); + + // name + String8 name = str8_cstring_capped((char*)(thunk32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + + // variant + String8 variant = str8_cstring_capped(name.str + name.size + 1, first + cap); + str8_list_pushf(arena, out, " variant='%.*s'\n", str8_varg(variant)); + } + }break; + + case CV_SymKind_BLOCK32: + { + if (sizeof(CV_SymBlock32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymBlock32 *block32 = (CV_SymBlock32*)first; + + // block attributes + str8_list_pushf(arena, out, " parent=%x\n", block32->parent); + str8_list_pushf(arena, out, " end=%x\n", block32->end); + str8_list_pushf(arena, out, " len=%u\n", block32->len); + str8_list_pushf(arena, out, " off=%x\n", block32->off); + str8_list_pushf(arena, out, " sec=%u\n", block32->sec); + + // name + String8 name = str8_cstring_capped((char*)(block32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", + str8_varg(name)); + } + }break; + + case CV_SymKind_LABEL32: + { + if (sizeof(CV_SymLabel32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymLabel32 *label32 = (CV_SymLabel32*)first; + + // label attributes + str8_list_pushf(arena, out, " off=%x\n", label32->off); + str8_list_pushf(arena, out, " sec=%u\n", label32->sec); + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", label32->flags); + + // name + String8 name = str8_cstring_capped((char*)(label32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", + str8_varg(name)); + } + }break; + + case CV_SymKind_CONSTANT: + { + if (sizeof(CV_SymConstant) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymConstant *constant = (CV_SymConstant*)first; + + // itype + str8_list_pushf(arena, out, " itype=%u\n", constant->itype); + + // num + U8 *numeric_ptr = (U8*)(constant + 1); + CV_NumericParsed numeric = cv_numeric_from_data_range(numeric_ptr, first + cap); + str8_list_push(arena, out, str8_lit(" num=")); + cv_stringize_numeric(arena, out, &numeric); + str8_list_push(arena, out, str8_lit("\n")); + + // name + U8 *name_ptr = numeric_ptr + numeric.encoded_size; + String8 name = str8_cstring_capped((char*)(name_ptr), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_UDT: + { + if (sizeof(CV_SymUDT) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymUDT *udt = (CV_SymUDT*)first; + + // itype + str8_list_pushf(arena, out, " itype=%u\n", udt->itype); + + // name + String8 name = str8_cstring_capped((char*)(udt + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: + { + if (sizeof(CV_SymData32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymData32 *data32 = (CV_SymData32*)first; + + // itype, off & sec + str8_list_pushf(arena, out, " itype=%u\n off=%x\n sec=%u\n", + data32->itype, data32->off, data32->sec); + + // name + String8 name = str8_cstring_capped((char*)(data32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_PUB32: + { + if (sizeof(CV_SymPub32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymPub32 *pub32 = (CV_SymPub32*)first; + + // flags + CV_PubFlags flags = pub32->flags; + str8_list_push(arena, out, str8_lit(" flags=")); + if (flags == 0){ + str8_list_push(arena, out, str8_lit("0|")); + } + else{ + if (flags&CV_PubFlag_Code){ + str8_list_push(arena, out, str8_lit("Code|")); + } + if (flags&CV_PubFlag_Function){ + str8_list_push(arena, out, str8_lit("Function|")); + } + if (flags&CV_PubFlag_ManagedCode){ + str8_list_push(arena, out, str8_lit("ManagedCode|")); + } + if (flags&CV_PubFlag_MSIL){ + str8_list_push(arena, out, str8_lit("MSIL|")); + } + } + str8_list_push(arena, out, str8_lit("\n")); + + // off & sec + str8_list_pushf(arena, out, " off=%x\n sec=%u\n", pub32->off, pub32->sec); + + // name + String8 name = str8_cstring_capped((char*)(pub32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + if (sizeof(CV_SymProc32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymProc32 *proc32 = (CV_SymProc32*)first; + + // proc attributes + str8_list_pushf(arena, out, " parent=%x\n", proc32->parent); + str8_list_pushf(arena, out, " end=%x\n", proc32->end); + str8_list_pushf(arena, out, " next=%x\n", proc32->next); + str8_list_pushf(arena, out, " len=%u\n", proc32->len); + str8_list_pushf(arena, out, " dbg_start=%x\n", proc32->dbg_start); + str8_list_pushf(arena, out, " dbg_end=%x\n", proc32->dbg_end); + str8_list_pushf(arena, out, " itype=%u\n", proc32->itype); + str8_list_pushf(arena, out, " off=%x\n", proc32->off); + str8_list_pushf(arena, out, " sec=%u\n", proc32->sec); + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", proc32->flags); + + // name + String8 name = str8_cstring_capped((char*)(proc32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_REGREL32: + { + if (sizeof(CV_SymRegrel32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymRegrel32 *regrel32 = (CV_SymRegrel32*)first; + + // regrel attributes + str8_list_pushf(arena, out, " reg_off=%u\n", regrel32->reg_off); + str8_list_pushf(arena, out, " itype=%u\n", regrel32->itype); + + // reg + String8 reg = cv_string_from_reg(p->arch, regrel32->reg); + str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); + + // name + String8 name = str8_cstring_capped((char*)(regrel32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: + { + if (sizeof(CV_SymThread32) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymThread32 *thread32 = (CV_SymThread32*)first; + + // itype, tls_off, tls_seg + str8_list_pushf(arena, out, " itype=%u\n tls_off=%x\n tls_seg=%u\n", + thread32->itype, thread32->tls_off, thread32->tls_seg); + + // name + String8 name = str8_cstring_capped((char*)(thread32 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_COMPILE2: + { + if (sizeof(CV_SymCompile2) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymCompile2 *compile2 = (CV_SymCompile2*)first; + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", compile2->flags); + + // machine + String8 machine = cv_string_from_machine(compile2->machine); + str8_list_pushf(arena, out, " machine=%.*s\n", + str8_varg(machine)); + + // ver + str8_list_pushf(arena, out, + " ver_fe_major=%u\n ver_fe_minor=%u\n ver_fe_build=%u\n" + " ver_major=%u\n ver_minor=%u\n ver_build=%u\n", + compile2->ver_fe_major, compile2->ver_fe_minor, compile2->ver_fe_build, + compile2->ver_major, compile2->ver_minor, compile2->ver_build); + + // ver_str + String8 ver_str = str8_cstring_capped((char*)(compile2 + 1), first + cap); + str8_list_pushf(arena, out, " ver_str='%.*s'\n", str8_varg(ver_str)); + } + }break; + + case CV_SymKind_UNAMESPACE: + { + CV_SymUNamespace *unamespace = (CV_SymUNamespace*)first; + + // name + String8 name = str8_cstring_capped((char*)(unamespace), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + }break; + + case CV_SymKind_PROCREF: + case CV_SymKind_DATAREF: + case CV_SymKind_LPROCREF: + { + if (sizeof(CV_SymRef2) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymRef2 *ref2 = (CV_SymRef2*)first; + + // suc_name, sym_off & imod + str8_list_pushf(arena, out, " suc_name=%u\n sym_off=%x\n imod=%u\n", + ref2->suc_name, ref2->sym_off, ref2->imod); + + // name + String8 name = str8_cstring_capped((char*)(ref2 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_TRAMPOLINE: + { + if (sizeof(CV_SymTrampoline) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymTrampoline *trampoline = (CV_SymTrampoline*)first; + + // kind + // TODO(allen): better kind path + str8_list_pushf(arena, out, " kind=%u\n", trampoline->kind); + + // members + str8_list_pushf(arena, out, " thunk_size=%u\n", trampoline->thunk_size); + str8_list_pushf(arena, out, " thunk_sec_off=%x\n", trampoline->thunk_sec_off); + str8_list_pushf(arena, out, " target_sec_off=%x\n", trampoline->target_sec_off); + str8_list_pushf(arena, out, " thunk_sec=%u\n", trampoline->thunk_sec); + str8_list_pushf(arena, out, " target_sec=%u\n", trampoline->target_sec); + } + }break; + + case CV_SymKind_SECTION: + { + if (sizeof(CV_SymSection) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymSection *section = (CV_SymSection*)first; + + // members + str8_list_pushf(arena, out, " sec_index=%u\n", section->sec_index); + str8_list_pushf(arena, out, " align=%u\n", section->align); + str8_list_pushf(arena, out, " pad=%u\n", section->pad); + str8_list_pushf(arena, out, " rva=%x\n", section->rva); + str8_list_pushf(arena, out, " size=%u\n", section->size); + str8_list_pushf(arena, out, " characteristics=%x\n", section->characteristics); + + // name + String8 name = str8_cstring_capped((char*)(section + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_COFFGROUP: + { + if (sizeof(CV_SymCoffGroup) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymCoffGroup *coff_group = (CV_SymCoffGroup*)first; + + // members + str8_list_pushf(arena, out, " size=%u\n", coff_group->size); + str8_list_pushf(arena, out, " characteristics=%x\n", coff_group->characteristics); + str8_list_pushf(arena, out, " off=%x\n", coff_group->off); + str8_list_pushf(arena, out, " sec=%u\n", coff_group->sec); + + // name + String8 name = str8_cstring_capped((char*)(coff_group + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_CALLSITEINFO: + { + if (sizeof(CV_SymCallSiteInfo) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymCallSiteInfo *callsiteinfo = (CV_SymCallSiteInfo*)first; + + // callsite info attributes + str8_list_pushf(arena, out, " off=%x\n", callsiteinfo->off); + str8_list_pushf(arena, out, " sec=%u\n", callsiteinfo->sec); + str8_list_pushf(arena, out, " pad=%u\n", callsiteinfo->pad); + str8_list_pushf(arena, out, " itype=%u\n", callsiteinfo->itype); + } + }break; + + case CV_SymKind_FRAMECOOKIE: + { + if (sizeof(CV_SymFrameCookie) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymFrameCookie *framecookie = (CV_SymFrameCookie*)first; + + // off + str8_list_pushf(arena, out, " off=%x\n", framecookie->off); + + // reg + String8 reg = cv_string_from_reg(p->arch, framecookie->reg); + str8_list_pushf(arena, out, " reg=%.*s\n", + str8_varg(reg)); + + // kind + // TODO(allen): better kind path + str8_list_pushf(arena, out, " kind=%x\n", framecookie->kind); + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", framecookie->flags); + } + }break; + + case CV_SymKind_COMPILE3: + { + if (sizeof(CV_SymCompile3) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymCompile3 *compile3 = (CV_SymCompile3*)first; + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", compile3->flags); + + // machine + String8 machine = cv_string_from_machine(compile3->machine); + str8_list_pushf(arena, out, " machine=%.*s\n", + str8_varg(machine)); + + // ver + str8_list_pushf(arena, out, + " ver_fe_major=%u\n ver_fe_minor=%u\n ver_fe_build=%u\n" + " ver_major=%u\n ver_minor=%u\n ver_build=%u\n" + " ver_qfe=%u\n", + compile3->ver_fe_major, compile3->ver_fe_minor, compile3->ver_fe_build, + compile3->ver_major, compile3->ver_minor, compile3->ver_build); + // ver_str + String8 ver_str = str8_cstring_capped((char*)(compile3 + 1), first + cap); + str8_list_pushf(arena, out, " ver_str='%.*s'\n", str8_varg(ver_str)); + } + }break; + + case CV_SymKind_ENVBLOCK: + { + if (sizeof(CV_SymEnvBlock) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymEnvBlock *envblock = (CV_SymEnvBlock*)first; + + // flags + str8_list_pushf(arena, out, " flags=%x\n", envblock->flags); + + // name + str8_list_pushf(arena, out, " rgsz=\n"); + char *name_ptr = (char*)(envblock + 1); + for (;;){ + String8 name = str8_cstring_capped(name_ptr, first + cap); + if (name.size == 0){ + break; + } + str8_list_pushf(arena, out, " '%.*s'\n", str8_varg(name)); + name_ptr += name.size + 1; + } + } + }break; + + case CV_SymKind_LOCAL: + { + if (sizeof(CV_SymLocal) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymLocal *slocal = (CV_SymLocal*)first; + + // itype + str8_list_pushf(arena, out, " itype=%u\n", slocal->itype); + + // flags + str8_list_pushf(arena, out, " flags={\n"); + cv_stringize_local_flags(arena, out, 2, slocal->flags); + str8_list_pushf(arena, out, " }\n"); + + // name + String8 name = str8_cstring_capped((char*)(slocal + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_DEFRANGE_REGISTER: + { + if (sizeof(CV_SymDefrangeRegister) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)first; + + // reg + String8 reg = cv_string_from_reg(p->arch, defrange_register->reg); + str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); + + // range attribs + // TODO(allen): better range attribs + str8_list_pushf(arena, out, " attribs=%x\n", defrange_register->attribs); + + // addr range + str8_list_push(arena, out, str8_lit(" range=")); + cv_stringize_lvar_addr_range(arena, out, &defrange_register->range); + str8_list_push(arena, out, str8_lit("\n")); + + // gaps + cv_stringize_lvar_addr_gap_list(arena, out, defrange_register + 1, first + cap); + } + }break; + + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: + { + if (sizeof(CV_SymDefrangeFramepointerRel) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)first; + + // off + str8_list_pushf(arena, out, " off=%u\n", defrange_fprel->off); + + // addr range + str8_list_push(arena, out, str8_lit(" range=")); + cv_stringize_lvar_addr_range(arena, out, &defrange_fprel->range); + str8_list_push(arena, out, str8_lit("\n")); + + // gaps + cv_stringize_lvar_addr_gap_list(arena, out, defrange_fprel + 1, first + cap); + } + }break; + + case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: + { + if (sizeof(CV_SymDefrangeSubfieldRegister) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)first; + + // reg + String8 reg = cv_string_from_reg(p->arch, defrange_subfield_register->reg); + str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); + + // range attribs + // TODO(allen): better range attribs + str8_list_pushf(arena, out, " attribs=%x\n", defrange_subfield_register->attribs); + + // offset + str8_list_pushf(arena, out, " field_offset=%u\n", + defrange_subfield_register->field_offset); + + // addr range + str8_list_push(arena, out, str8_lit(" range=")); + cv_stringize_lvar_addr_range(arena, out, &defrange_subfield_register->range); + str8_list_push(arena, out, str8_lit("\n")); + + // gaps + cv_stringize_lvar_addr_gap_list(arena, out, defrange_subfield_register + 1, first + cap); + } + }break; + + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + { + if (sizeof(CV_SymDefrangeFramepointerRelFullScope) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = + (CV_SymDefrangeFramepointerRelFullScope*)first; + + // off + str8_list_pushf(arena, out, " off=%u\n", defrange_fprel_full_scope->off); + } + }break; + + case CV_SymKind_DEFRANGE_REGISTER_REL: + { + if (sizeof(CV_SymDefrangeRegisterRel) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)first; + + // reg + String8 reg = cv_string_from_reg(p->arch, defrange_register_rel->reg); + str8_list_pushf(arena, out, " reg=%.*s\n", str8_varg(reg)); + + // flags + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", defrange_register_rel->flags); + + // reg off + str8_list_pushf(arena, out, " reg_off=%u\n", defrange_register_rel->reg_off); + + // addr range + str8_list_push(arena, out, str8_lit(" range=")); + cv_stringize_lvar_addr_range(arena, out, &defrange_register_rel->range); + str8_list_push(arena, out, str8_lit("\n")); + + // gaps + cv_stringize_lvar_addr_gap_list(arena, out, defrange_register_rel + 1, first + cap); + } + }break; + + case CV_SymKind_BUILDINFO: + { + if (sizeof(CV_SymBuildInfo) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymBuildInfo *buildinfo = (CV_SymBuildInfo*)first; + + // item id + str8_list_pushf(arena, out, " id=%u\n", buildinfo->id); + } + }break; + + case CV_SymKind_INLINESITE: + { + if (sizeof(CV_SymInlineSite) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymInlineSite *inlinesite = (CV_SymInlineSite*)first; + + // members + str8_list_pushf(arena, out, " parent=%x\n", inlinesite->parent); + str8_list_pushf(arena, out, " end=%x\n", inlinesite->end); + str8_list_pushf(arena, out, " inlinee=%u\n", inlinesite->inlinee); + + // binary annotation + // TODO(allen): + } + }break; + + case CV_SymKind_INLINESITE_END: + { + // no contents + }break; + + case CV_SymKind_FILESTATIC: + { + if (sizeof(CV_SymFileStatic) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymFileStatic *file_static = (CV_SymFileStatic*)first; + + // members + str8_list_pushf(arena, out, " itype=%u\n", file_static->itype); + str8_list_pushf(arena, out, " mod_offset=%x\n", file_static->mod_offset); + // TODO(allen): better flags path + str8_list_pushf(arena, out, " flags=%x\n", file_static->flags); + + // name + String8 name = str8_cstring_capped((char*)(file_static + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_SymKind_CALLEES: + case CV_SymKind_CALLERS: + { + if (sizeof(CV_SymFunctionList) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymFunctionList *functions = (CV_SymFunctionList*)first; + + // count + str8_list_pushf(arena, out, " count=%u\n", functions->count); + + // functions + U32 function_count_max = (cap - sizeof(*functions))/sizeof(CV_TypeId); + U32 function_count = ClampTop(functions->count, function_count_max); + if (function_count > 0){ + str8_list_push(arena, out, str8_lit(" functions=\n")); + CV_TypeId *func = (CV_TypeId*)(functions + 1); + CV_TypeId *opl = func + function_count; + for (;func < opl; func += 1){ + str8_list_pushf(arena, out, " %u\n", *func); + } + } + + // invocations + U32 invocation_count_max = (cap - sizeof(*functions) - function_count*sizeof(CV_TypeId))/sizeof(U32); + U32 invocation_count = ClampTop(functions->count, invocation_count_max); + if (invocation_count > 0){ + str8_list_push(arena, out, str8_lit(" invocations=\n")); + U32 *inv = (CV_TypeId*)(functions + 1); + U32 *opl = inv + invocation_count; + for (;inv < opl; inv += 1){ + str8_list_pushf(arena, out, " %u\n", *inv); + } + } + } + }break; + + case CV_SymKind_HEAPALLOCSITE: + { + if (sizeof(CV_SymHeapAllocSite) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymHeapAllocSite *heap_alloc_site = (CV_SymHeapAllocSite*)first; + + // members + str8_list_pushf(arena, out, " off=%x\n", heap_alloc_site->off); + str8_list_pushf(arena, out, " sec=%u\n", heap_alloc_site->sec); + str8_list_pushf(arena, out, " call_inst_len=%u\n", heap_alloc_site->call_inst_len); + str8_list_pushf(arena, out, " itype=%u\n", heap_alloc_site->itype); + } + }break; + + case CV_SymKind_INLINEES: + { + if (sizeof(CV_SymInlinees) > cap){ + str8_list_push(arena, out, str8_lit(" bad symbol range\n")); + } + else{ + CV_SymInlinees *inlinees = (CV_SymInlinees*)first; + + // count + str8_list_pushf(arena, out, " count=%u\n", inlinees->count); + + // desc + U32 desc_count = (cap - sizeof(*inlinees))/sizeof(U32); + if (desc_count > 0){ + str8_list_pushf(arena, out, " desc=\n"); + U32 *desc = (U32*)(inlinees + 1); + U32 *desc_opl = desc + desc_count; + for (;desc < desc_opl; desc += 1){ + str8_list_pushf(arena, out, " %u\n", *desc); + } + } + } + }break; + + case CV_SymKind_REGISTER_16t: + case CV_SymKind_CONSTANT_16t: + case CV_SymKind_UDT_16t: + case CV_SymKind_SSEARCH: + case CV_SymKind_SKIP: + case CV_SymKind_CVRESERVE: + case CV_SymKind_OBJNAME_ST: + case CV_SymKind_ENDARG: + case CV_SymKind_COBOLUDT_16t: + case CV_SymKind_MANYREG_16t: + case CV_SymKind_RETURN: + case CV_SymKind_ENTRYTHIS: + case CV_SymKind_BPREL16: + case CV_SymKind_LDATA16: + case CV_SymKind_GDATA16: + case CV_SymKind_PUB16: + case CV_SymKind_LPROC16: + case CV_SymKind_GPROC16: + case CV_SymKind_THUNK16: + case CV_SymKind_BLOCK16: + case CV_SymKind_WITH16: + case CV_SymKind_LABEL16: + case CV_SymKind_CEXMODEL16: + case CV_SymKind_VFTABLE16: + case CV_SymKind_REGREL16: + case CV_SymKind_BPREL32_16t: + case CV_SymKind_LDATA32_16t: + case CV_SymKind_GDATA32_16t: + case CV_SymKind_PUB32_16t: + case CV_SymKind_LPROC32_16t: + case CV_SymKind_GPROC32_16t: + case CV_SymKind_THUNK32_ST: + case CV_SymKind_BLOCK32_ST: + case CV_SymKind_WITH32_ST: + case CV_SymKind_LABEL32_ST: + case CV_SymKind_CEXMODEL32: + case CV_SymKind_VFTABLE32_16t: + case CV_SymKind_REGREL32_16t: + case CV_SymKind_LTHREAD32_16t: + case CV_SymKind_GTHREAD32_16t: + case CV_SymKind_SLINK32: + case CV_SymKind_LPROCMIPS_16t: + case CV_SymKind_GPROCMIPS_16t: + case CV_SymKind_PROCREF_ST: + case CV_SymKind_DATAREF_ST: + case CV_SymKind_ALIGN: + case CV_SymKind_LPROCREF_ST: + case CV_SymKind_OEM: + case CV_SymKind_TI16_MAX: + case CV_SymKind_CONSTANT_ST: + case CV_SymKind_UDT_ST: + case CV_SymKind_COBOLUDT_ST: + case CV_SymKind_MANYREG_ST: + case CV_SymKind_BPREL32_ST: + case CV_SymKind_LDATA32_ST: + case CV_SymKind_GDATA32_ST: + case CV_SymKind_PUB32_ST: + case CV_SymKind_LPROC32_ST: + case CV_SymKind_GPROC32_ST: + case CV_SymKind_VFTABLE32: + case CV_SymKind_REGREL32_ST: + case CV_SymKind_LTHREAD32_ST: + case CV_SymKind_GTHREAD32_ST: + case CV_SymKind_LPROCMIPS_ST: + case CV_SymKind_GPROCMIPS_ST: + case CV_SymKind_COMPILE2_ST: + case CV_SymKind_MANYREG2_ST: + case CV_SymKind_LPROCIA64_ST: + case CV_SymKind_GPROCIA64_ST: + case CV_SymKind_LOCALSLOT_ST: + case CV_SymKind_PARAMSLOT_ST: + case CV_SymKind_ANNOTATION: + case CV_SymKind_GMANPROC_ST: + case CV_SymKind_LMANPROC_ST: + case CV_SymKind_RESERVED1: + case CV_SymKind_RESERVED2: + case CV_SymKind_RESERVED3: + case CV_SymKind_RESERVED4: + case CV_SymKind_LMANDATA_ST: + case CV_SymKind_GMANDATA_ST: + case CV_SymKind_MANFRAMEREL_ST: + case CV_SymKind_MANREGISTER_ST: + case CV_SymKind_MANSLOT_ST: + case CV_SymKind_MANMANYREG_ST: + case CV_SymKind_MANREGREL_ST: + case CV_SymKind_MANMANYREG2_ST: + case CV_SymKind_MANTYPREF: + case CV_SymKind_UNAMESPACE_ST: + case CV_SymKind_ST_MAX: + case CV_SymKind_WITH32: + case CV_SymKind_REGISTER: + case CV_SymKind_COBOLUDT: + case CV_SymKind_MANYREG: + case CV_SymKind_BPREL32: + case CV_SymKind_LPROCMIPS: + case CV_SymKind_GPROCMIPS: + case CV_SymKind_MANYREG2: + case CV_SymKind_LPROCIA64: + case CV_SymKind_GPROCIA64: + case CV_SymKind_LOCALSLOT: + case CV_SymKind_PARAMSLOT: + case CV_SymKind_LMANDATA: + case CV_SymKind_GMANDATA: + case CV_SymKind_MANFRAMEREL: + case CV_SymKind_MANREGISTER: + case CV_SymKind_MANSLOT: + case CV_SymKind_MANMANYREG: + case CV_SymKind_MANREGREL: + case CV_SymKind_MANMANYREG2: + case CV_SymKind_ANNOTATIONREF: + case CV_SymKind_TOKENREF: + case CV_SymKind_GMANPROC: + case CV_SymKind_LMANPROC: + case CV_SymKind_MANCONSTANT: + case CV_SymKind_ATTR_FRAMEREL: + case CV_SymKind_ATTR_REGISTER: + case CV_SymKind_ATTR_REGREL: + case CV_SymKind_ATTR_MANYREG: + case CV_SymKind_SEPCODE: + case CV_SymKind_DEFRANGE_2005: + case CV_SymKind_DEFRANGE2_2005: + case CV_SymKind_EXPORT: + case CV_SymKind_DISCARDED: + case CV_SymKind_DEFRANGE: + case CV_SymKind_DEFRANGE_SUBFIELD: + case CV_SymKind_LPROC32_ID: + case CV_SymKind_GPROC32_ID: + case CV_SymKind_LPROCMIPS_ID: + case CV_SymKind_GPROCMIPS_ID: + case CV_SymKind_LPROCIA64_ID: + case CV_SymKind_GPROCIA64_ID: + case CV_SymKind_PROC_ID_END: + case CV_SymKind_DEFRANGE_HLSL: + case CV_SymKind_GDATA_HLSL: + case CV_SymKind_LDATA_HLSL: + case CV_SymKind_LPROC32_DPC: + case CV_SymKind_LPROC32_DPC_ID: + case CV_SymKind_DEFRANGE_DPC_PTR_TAG: + case CV_SymKind_DPC_SYM_TAG_MAP: + case CV_SymKind_ARMSWITCHTABLE: + case CV_SymKind_POGODATA: + case CV_SymKind_INLINESITE2: + case CV_SymKind_MOD_TYPEREF: + case CV_SymKind_REF_MINIPDB: + case CV_SymKind_PDBMAP: + case CV_SymKind_GDATA_HLSL32: + case CV_SymKind_LDATA_HLSL32: + case CV_SymKind_GDATA_HLSL32_EX: + case CV_SymKind_LDATA_HLSL32_EX: + case CV_SymKind_FASTLINK: + { + str8_list_push(arena, out, str8_lit(" no stringizer path\n")); + }break; + } + } +} + +static void +cv_stringize_sym_array(Arena *arena, String8List *out, + CV_RecRangeArray *ranges, String8 data, + CV_StringizeSymParams *p){ + CV_RecRange *ptr = ranges->ranges; + CV_RecRange *opl = ranges->ranges + ranges->count; + for (;ptr < opl; ptr += 1){ + cv_stringize_sym_range(arena, out, ptr, data, p); + str8_list_push(arena, out, str8_lit("\n")); + } +} + +//////////////////////////////// +//~ CodeView Leaf Stringize Functions + +static void +cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf){ + CV_StringizeLeafParams params = {0}; + + cv_stringize_leaf_array(arena, out, &leaf->leaf_ranges, leaf->itype_first, + leaf->data, ¶ms); +} + +static void +cv_stringize_leaf_range(Arena *arena, String8List *out, + CV_RecRange *range, CV_TypeId itype, String8 data, + CV_StringizeLeafParams *p){ + U64 opl_off = range->off + range->hdr.size; + if (opl_off > data.size){ + str8_list_push(arena, out, str8_lit("bad leaf range\n")); + } + + if (opl_off <= data.size){ + // [off] (itype): kind + { + String8 kind_str = cv_string_from_leaf_kind(range->hdr.kind); + str8_list_pushf(arena, out, "[%06x] (%u): %.*s\n", + range->off + 2, itype, str8_varg(kind_str)); + } + + // details + U8 *first = data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + + switch (range->hdr.kind){ + case CV_LeafKind_VTSHAPE: + { + if (sizeof(CV_LeafVTShape) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafVTShape *vtshape = (CV_LeafVTShape*)first; + + str8_list_pushf(arena, out, " count=%u\n", vtshape->count); + + str8_list_push(arena, out, str8_lit(" shapes=\n")); + U8 *shapes = (U8*)(vtshape + 1); + U32 max_count = (cap - sizeof(*vtshape))*2; + U32 clamped_count = ClampTop(vtshape->count, max_count); + for (U32 i = 0; i < clamped_count; i += 1){ + U32 j = (i >> 1); + U8 s = shapes[j]; + if (j & 1){ + s >>= 4; + } + CV_VirtualTableShape shape = (s & 0xF); + // TODO(allen): better shape path + str8_list_pushf(arena, out, " %u\n", shape); + } + } + }break; + + case CV_LeafKind_LABEL: + { + if (sizeof(CV_LeafLabel) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafLabel *label = (CV_LeafLabel*)first; + + // TODO(allen): better LabelKind path + str8_list_pushf(arena, out, " kind=%x\n", label->kind); + } + }break; + + case CV_LeafKind_MODIFIER: + { + if (sizeof(CV_LeafModifier) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafModifier *modifier = (CV_LeafModifier*)first; + + str8_list_pushf(arena, out, " itype=%u\n", modifier->itype); + str8_list_pushf(arena, out, " flags={\n"); + cv_stringize_modifier_flags(arena, out, 2, modifier->flags); + str8_list_pushf(arena, out, " }\n"); + } + }break; + + case CV_LeafKind_POINTER: + { + if (sizeof(CV_LeafPointer) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafPointer *pointer = (CV_LeafPointer*)first; + + str8_list_pushf(arena, out, " itype=%u\n", pointer->itype); + str8_list_pushf(arena, out, " attribs={\n"); + cv_stringize_pointer_attribs(arena, out, 2, pointer->attribs); + str8_list_pushf(arena, out, " }\n"); + } + }break; + + case CV_LeafKind_PROCEDURE: + { + if (sizeof(CV_LeafProcedure) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafProcedure *procedure = (CV_LeafProcedure*)first; + + str8_list_pushf(arena, out, " ret_itype=%u\n", procedure->ret_itype); + // TODO(allen): better CallKind path + str8_list_pushf(arena, out, " call_kind=%u\n", procedure->call_kind); + // TODO(allen): better flags path + str8_list_pushf(arena, out, " attribs=%x\n", procedure->attribs); + str8_list_pushf(arena, out, " arg_count=%u\n", procedure->arg_count); + str8_list_pushf(arena, out, " arg_itype=%u\n", procedure->arg_itype); + } + }break; + + case CV_LeafKind_MFUNCTION: + { + if (sizeof(CV_LeafMFunction) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafMFunction *mfunction = (CV_LeafMFunction*)first; + + str8_list_pushf(arena, out, " ret_itype=%u\n", mfunction->ret_itype); + str8_list_pushf(arena, out, " class_itype=%u\n", mfunction->class_itype); + str8_list_pushf(arena, out, " this_itype=%u\n", mfunction->this_itype); + // TODO(allen): better CallKind path + str8_list_pushf(arena, out, " call_kind=%u\n", mfunction->call_kind); + // TODO(allen): better flags path + str8_list_pushf(arena, out, " attribs=%x\n", mfunction->attribs); + str8_list_pushf(arena, out, " arg_count=%u\n", mfunction->arg_count); + str8_list_pushf(arena, out, " arg_itype=%u\n", mfunction->arg_itype); + str8_list_pushf(arena, out, " this_adjust=%d\n", mfunction->this_adjust); + } + }break; + + case CV_LeafKind_ARGLIST: + { + if (sizeof(CV_LeafArgList) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafArgList *arg_list = (CV_LeafArgList*)first; + + str8_list_pushf(arena, out, " count=%u\n", arg_list->count); + str8_list_push(arena, out, str8_lit(" itypes=\n")); + + CV_TypeId *itypes = (CV_TypeId*)(arg_list + 1); + U32 max_count = (cap - sizeof(*arg_list))/sizeof(U32); + U32 clamped_count = ClampTop(arg_list->count, max_count); + for (U32 i = 0; i < clamped_count; i += 1){ + str8_list_pushf(arena, out, " %u\n", itypes[i]); + } + } + }break; + + case CV_LeafKind_FIELDLIST: + { + U64 cursor = 0; + for (;cursor + sizeof(CV_LeafKind) <= cap;){ + CV_LeafKind field_kind = *(CV_LeafKind*)(first + cursor); + String8 field_kind_str = cv_string_from_leaf_kind(field_kind); + + str8_list_pushf(arena, out, " field kind: %.*s\n", + str8_varg(field_kind_str)); + + U64 list_item_off = cursor + 2; + + // if we hit an error or forget to set next cursor for a case + // default to exiting the loop + U64 list_item_opl_off = cap; + + switch (field_kind){ + default: + { + str8_list_push(arena, out, str8_lit(" unexpected field kind\n")); + }break; + + case CV_LeafKind_MEMBER: + { + if (list_item_off + sizeof(CV_LeafMember) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafMember *member = (CV_LeafMember*)(first + list_item_off); + + U64 num_off = list_item_off + sizeof(*member); + CV_NumericParsed num = cv_numeric_from_data_range(first + num_off, first + cap); + + U64 name_off = num_off + num.encoded_size; + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // print data + // TODO(allen): better flags path + str8_list_pushf(arena, out, " attribs=%x\n", member->attribs); + str8_list_pushf(arena, out, " itype=%u\n", member->itype); + str8_list_push(arena, out, str8_lit(" offset=")); + cv_stringize_numeric(arena, out, &num); + str8_list_push(arena, out, str8_lit("\n")); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafKind_STMEMBER: + { + if (list_item_off + sizeof(CV_LeafStMember) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafStMember *stmember = (CV_LeafStMember*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*stmember); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // print data + // TODO(allen): better flags path + str8_list_pushf(arena, out, " attribs=%x\n", stmember->attribs); + str8_list_pushf(arena, out, " itype=%u\n", stmember->itype); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafKind_METHOD: + { + if (list_item_off + sizeof(CV_LeafMethod) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafMethod *method = (CV_LeafMethod*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*method); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // print data + str8_list_pushf(arena, out, " count=%u\n", method->count); + str8_list_pushf(arena, out, " list_itype=%u\n", method->list_itype); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafKind_ONEMETHOD: + { + if (list_item_off + sizeof(CV_LeafOneMethod) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafOneMethod *one_method = (CV_LeafOneMethod*)(first + list_item_off); + + U64 vbaseoff_off = list_item_off + sizeof(*one_method); + U64 vbaseoff_opl_off = vbaseoff_off; + U32 vbaseoff = 0; + { + CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(one_method->attribs); + if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ + vbaseoff = *(U32*)(first + vbaseoff_off); + vbaseoff_opl_off += sizeof(vbaseoff); + } + } + + U64 name_off = vbaseoff_opl_off; + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // print data + // TODO(allen): better flags path + str8_list_pushf(arena, out, " attribs=%x\n", one_method->attribs); + str8_list_pushf(arena, out, " itype=%u\n", one_method->itype); + str8_list_pushf(arena, out, " vbaseoff=%u\n", vbaseoff); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafKind_ENUMERATE: + { + if (list_item_off + sizeof(CV_LeafEnumerate) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafEnumerate *enumerate = (CV_LeafEnumerate*)(first + list_item_off); + + U64 num_off = list_item_off + sizeof(*enumerate); + CV_NumericParsed num = cv_numeric_from_data_range(first + num_off, first + cap); + + U64 name_off = num_off + num.encoded_size; + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // print data + // TODO(allen): better flags path + str8_list_pushf(arena, out, " attribs=%x\n", enumerate->attribs); + str8_list_push(arena, out, str8_lit(" val=")); + cv_stringize_numeric(arena, out, &num); + str8_list_push(arena, out, str8_lit("\n")); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafKind_NESTTYPE: + { + if (list_item_off + sizeof(CV_LeafNestType) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafNestType *nest_type = (CV_LeafNestType*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*nest_type); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // print data + str8_list_pushf(arena, out, " itype=%u\n", nest_type->itype); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafKind_NESTTYPEEX: + { + if (list_item_off + sizeof(CV_LeafNestTypeEx) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafNestTypeEx *nest_type = (CV_LeafNestTypeEx*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*nest_type); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // print data + // TODO(allen): better flags printing + str8_list_pushf(arena, out, " attribs=%x\n", nest_type->attribs); + str8_list_pushf(arena, out, " itype=%u\n", nest_type->itype); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafKind_BCLASS: + { + if (list_item_off + sizeof(CV_LeafBClass) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafBClass *bclass = (CV_LeafBClass*)(first + list_item_off); + + U64 num_off = list_item_off + sizeof(*bclass); + CV_NumericParsed num = cv_numeric_from_data_range(first + num_off, first + cap); + + list_item_opl_off = num_off + num.encoded_size; + + // print data + // TODO(allen): better flags printing + str8_list_pushf(arena, out, " attribs=%x\n", bclass->attribs); + str8_list_pushf(arena, out, " itype=%u\n", bclass->itype); + str8_list_push(arena, out, str8_lit(" offset=")); + cv_stringize_numeric(arena, out, &num); + str8_list_push(arena, out, str8_lit("\n")); + } + }break; + + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: + { + if (list_item_off + sizeof(CV_LeafVBClass) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafVBClass *vbclass = (CV_LeafVBClass*)(first + list_item_off); + + U64 num1_off = list_item_off + sizeof(*vbclass); + CV_NumericParsed num1 = cv_numeric_from_data_range(first + num1_off, first + cap); + + U64 num2_off = num1_off + num1.encoded_size; + CV_NumericParsed num2 = cv_numeric_from_data_range(first + num2_off, first + cap); + + list_item_opl_off = num2_off + num2.encoded_size; + + // print data + // TODO(allen): better flags printing + str8_list_pushf(arena, out, " attribs=%x\n", vbclass->attribs); + str8_list_pushf(arena, out, " itype=%u\n", vbclass->itype); + str8_list_pushf(arena, out, " vbptr_itype=%u\n", vbclass->vbptr_itype); + str8_list_push(arena, out, str8_lit(" vbptr_off=")); + cv_stringize_numeric(arena, out, &num1); + str8_list_push(arena, out, str8_lit("\n")); + str8_list_push(arena, out, str8_lit(" vtable_off=")); + cv_stringize_numeric(arena, out, &num2); + str8_list_push(arena, out, str8_lit("\n")); + } + }break; + + case CV_LeafKind_INDEX: + { + if (list_item_off + sizeof(CV_LeafIndex) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafIndex *index = (CV_LeafIndex*)(first + list_item_off); + + list_item_opl_off = list_item_off + sizeof(*index); + + // print data + str8_list_pushf(arena, out, " itype=%u\n", index->itype); + } + }break; + + case CV_LeafKind_VFUNCTAB: + { + if (list_item_off + sizeof(CV_LeafVFuncTab) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafVFuncTab *vfunctab = (CV_LeafVFuncTab*)(first + list_item_off); + + list_item_opl_off = list_item_off + sizeof(*vfunctab); + + // print data + str8_list_pushf(arena, out, " itype=%u\n", vfunctab->itype); + } + }break; + + case CV_LeafKind_VFUNCOFF: + { + if (list_item_off + sizeof(CV_LeafVFuncOff) > cap){ + str8_list_push(arena, out, str8_lit(" bad field list range\n")); + } + else{ + // compute whole layout + CV_LeafVFuncOff *vfuncoff = (CV_LeafVFuncOff*)(first + list_item_off); + + list_item_opl_off = list_item_off + sizeof(*vfuncoff); + + // print data + str8_list_pushf(arena, out, " itype=%u\n", vfuncoff->itype); + str8_list_pushf(arena, out, " off=%u\n", vfuncoff->off); + } + }break; + } + + // update cursor + U64 next_cursor = AlignPow2(list_item_opl_off, 4); + cursor = next_cursor; + } + }break; + + case CV_LeafKind_BITFIELD: + { + if (sizeof(CV_LeafBitField) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafBitField *bit_field = (CV_LeafBitField*)first; + + str8_list_pushf(arena, out, " itype=%u\n", bit_field->itype); + str8_list_pushf(arena, out, " len=%u\n", bit_field->len); + str8_list_pushf(arena, out, " pos=%u\n", bit_field->pos); + } + }break; + + case CV_LeafKind_METHODLIST: + { + U64 cursor = 0; + for (;cursor + sizeof(CV_LeafMethodListMember) <= cap;){ + CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)(first + cursor); + + // extract vbaseoff + U64 next_cursor = cursor + sizeof(*method); + U32 vbaseoff = 0; + { + CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(method->attribs); + if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ + if (cursor + sizeof(*method) + 4 <= cap){ + vbaseoff = *(U32*)(method + 1); + } + next_cursor += 4; + } + } + + // print + // TODO(allen): better flags path + str8_list_pushf(arena, out, " method\n", method->attribs); + str8_list_pushf(arena, out, " attribs=%x\n", method->attribs); + str8_list_pushf(arena, out, " itype=%u\n", method->itype); + str8_list_pushf(arena, out, " vbaseoff=%u\n", vbaseoff); + + // update cursor + cursor = next_cursor; + } + }break; + + case CV_LeafKind_ARRAY: + { + if (sizeof(CV_LeafArray) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafArray *array = (CV_LeafArray*)first; + + str8_list_pushf(arena, out, " entry_itype=%u\n", array->entry_itype); + str8_list_pushf(arena, out, " index_itype=%u\n", array->index_itype); + + // count + U8 *numeric_ptr = (U8*)(array + 1); + CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, first + cap); + str8_list_pushf(arena, out, " count="); + cv_stringize_numeric(arena, out, &array_count); + str8_list_push(arena, out, str8_lit("\n")); + } + }break; + + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + if (sizeof(CV_LeafStruct) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; + + str8_list_pushf(arena, out, " count=%u\n", lf_struct->count); + str8_list_pushf(arena, out, " props=%x (\n", lf_struct->props); + cv_stringize_type_props(arena, out, 2, lf_struct->props); + str8_list_pushf(arena, out, " )\n"); + str8_list_pushf(arena, out, " field_itype=%u\n", lf_struct->field_itype); + str8_list_pushf(arena, out, " derived_itype=%u\n", lf_struct->derived_itype); + str8_list_pushf(arena, out, " vshape_itype=%u\n", lf_struct->vshape_itype); + + U8 *numeric_ptr = (U8*)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + str8_list_pushf(arena, out, " size="); + cv_stringize_numeric(arena, out, &size); + str8_list_push(arena, out, str8_lit("\n")); + + String8 name = str8_cstring_capped((U8*)(numeric_ptr + size.encoded_size), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + + String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); + str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); + } + }break; + + case CV_LeafKind_UNION: + { + if (sizeof(CV_LeafUnion) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafUnion *lf_union = (CV_LeafUnion*)first; + + str8_list_pushf(arena, out, " count=%u\n", lf_union->count); + str8_list_pushf(arena, out, " props=%x (\n", lf_union->props); + cv_stringize_type_props(arena, out, 2, lf_union->props); + str8_list_pushf(arena, out, " )\n"); + str8_list_pushf(arena, out, " field_itype=%u\n", lf_union->field_itype); + + U8 *numeric_ptr = (U8*)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + str8_list_pushf(arena, out, " size="); + cv_stringize_numeric(arena, out, &size); + str8_list_push(arena, out, str8_lit("\n")); + + String8 name = str8_cstring_capped((U8*)(numeric_ptr + size.encoded_size), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + + String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); + str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); + } + }break; + + case CV_LeafKind_ENUM: + { + if (sizeof(CV_LeafEnum) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; + + str8_list_pushf(arena, out, " count=%u\n", lf_enum->count); + str8_list_pushf(arena, out, " props=%x (\n", lf_enum->props); + cv_stringize_type_props(arena, out, 2, lf_enum->props); + str8_list_pushf(arena, out, " )\n"); + str8_list_pushf(arena, out, " base_itype=%u\n", lf_enum->base_itype); + str8_list_pushf(arena, out, " field_itype=%u\n", lf_enum->field_itype); + + String8 name = str8_cstring_capped((U8*)(lf_enum + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + + String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); + str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); + } + }break; + + case CV_LeafKind_VFTABLE: + { + if (sizeof(CV_LeafVFTable) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafVFTable *vftable = (CV_LeafVFTable*)first; + + str8_list_pushf(arena, out, " owner_itype=%u\n", vftable->owner_itype); + str8_list_pushf(arena, out, " base_table_itype=%u\n", vftable->base_table_itype); + str8_list_pushf(arena, out, " offset_in_object_layout=%u\n", + vftable->offset_in_object_layout); + str8_list_pushf(arena, out, " names_len=%u\n", vftable->names_len); + + U64 names_cap = Min(sizeof(*vftable) + vftable->names_len, cap); + + str8_list_push(arena, out, str8_lit(" names=\n")); + U8 *ptr = (U8*)(vftable + 1); + U8 *opl = first + names_cap; + for (;ptr < opl;){ + String8 name = str8_cstring_capped(ptr, opl); + str8_list_pushf(arena, out, " '%.*s'\n", str8_varg(name)); + ptr += name.size + 1; + } + } + }break; + + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + if (sizeof(CV_LeafStruct2) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafStruct2 *struct2 = (CV_LeafStruct2*)first; + + str8_list_pushf(arena, out, " props=%x (\n", struct2->props); + cv_stringize_type_props(arena, out, 2, struct2->props); + str8_list_pushf(arena, out, " )\n"); + str8_list_pushf(arena, out, " unknown1=%u\n", struct2->unknown1); + str8_list_pushf(arena, out, " field_itype=%u\n", struct2->field_itype); + str8_list_pushf(arena, out, " derived_itype=%u\n", struct2->derived_itype); + str8_list_pushf(arena, out, " vshape_itype=%u\n", struct2->vshape_itype); + str8_list_pushf(arena, out, " unknown2=0x%x\n", struct2->unknown2); + str8_list_pushf(arena, out, " size=%u\n", struct2->size); + + String8 name = str8_cstring_capped((U8*)(struct2 + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + + String8 unique_name = str8_cstring_capped(name.str + name.size + 1, first + cap); + str8_list_pushf(arena, out, " unique_name='%.*s'\n", str8_varg(unique_name)); + } + }break; + + case CV_LeafIDKind_FUNC_ID: + { + if (sizeof(CV_LeafFuncId) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafFuncId *func_id = (CV_LeafFuncId*)first; + + str8_list_pushf(arena, out, " scope_string_id=%u\n", func_id->scope_string_id); + str8_list_pushf(arena, out, " itype=%u\n", func_id->itype); + + String8 name = str8_cstring_capped((U8*)(func_id + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafIDKind_MFUNC_ID: + { + if (sizeof(CV_LeafMFuncId) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)first; + + str8_list_pushf(arena, out, " owner_itype=%u\n", mfunc_id->owner_itype); + str8_list_pushf(arena, out, " itype=%u\n", mfunc_id->itype); + + String8 name = str8_cstring_capped((U8*)(mfunc_id + 1), first + cap); + str8_list_pushf(arena, out, " name='%.*s'\n", str8_varg(name)); + } + }break; + + case CV_LeafIDKind_BUILDINFO: + { + if (sizeof(CV_LeafBuildInfo) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafBuildInfo *build_info = (CV_LeafBuildInfo*)first; + + str8_list_pushf(arena, out, " count=%u\n", build_info->count); + + CV_ItemId *item_ids = (CV_ItemId*)(build_info + 1); + str8_list_pushf(arena, out, " items=\n"); + U32 max_count = (cap - sizeof(*build_info))/sizeof(CV_ItemId); + U32 clamped_count = ClampTop(build_info->count, max_count); + for (U32 i = 0; i < clamped_count; i += 1){ + CV_ItemId item_id = item_ids[i]; + str8_list_pushf(arena, out, " %u\n", item_id); + } + } + }break; + + case CV_LeafIDKind_SUBSTR_LIST: + { + if (sizeof(CV_LeafSubstrList) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafSubstrList *substr_list = (CV_LeafSubstrList*)first; + + str8_list_pushf(arena, out, " count=%u\n", substr_list->count); + + str8_list_pushf(arena, out, " items=\n"); + U32 max_count = (cap - sizeof(CV_LeafSubstrList))/sizeof(CV_ItemId); + CV_ItemId *item_ids = (CV_ItemId*)(substr_list + 1); + U32 clamped_count = ClampTop(substr_list->count, max_count); + for (U32 i = 0; i < clamped_count; i += 1){ + CV_ItemId item_id = item_ids[i]; + str8_list_pushf(arena, out, " %u\n", item_id); + } + } + }break; + + case CV_LeafIDKind_STRING_ID: + { + if (sizeof(CV_LeafStringId) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafStringId *string_id = (CV_LeafStringId*)first; + + str8_list_pushf(arena, out, " substr_list_id=%u\n", string_id->substr_list_id); + + String8 string = str8_cstring_capped((U8*)(string_id + 1), first + cap); + str8_list_pushf(arena, out, " string='%.*s'\n", str8_varg(string)); + } + }break; + + case CV_LeafIDKind_UDT_SRC_LINE: + { + if (sizeof(CV_LeafUDTSrcLine) > cap){ + str8_list_push(arena, out, str8_lit(" bad leaf range\n")); + } + else{ + CV_LeafUDTSrcLine *udt_src_line = (CV_LeafUDTSrcLine*)first; + + str8_list_pushf(arena, out, " udt_itype=%u\n", udt_src_line->udt_itype); + str8_list_pushf(arena, out, " src_string_id=%u\n", udt_src_line->src_string_id); + str8_list_pushf(arena, out, " line=%u\n", udt_src_line->line); + } + }break; + + + default: + + // Leaf Kinds + case CV_LeafKind_MODIFIER_16t: + case CV_LeafKind_POINTER_16t: + case CV_LeafKind_ARRAY_16t: + case CV_LeafKind_CLASS_16t: + case CV_LeafKind_STRUCTURE_16t: + case CV_LeafKind_UNION_16t: + case CV_LeafKind_ENUM_16t: + case CV_LeafKind_PROCEDURE_16t: + case CV_LeafKind_MFUNCTION_16t: + //case CV_LeafKind_VTSHAPE: + case CV_LeafKind_COBOL0_16t: + case CV_LeafKind_COBOL1: + case CV_LeafKind_BARRAY_16t: + //case CV_LeafKind_LABEL: + case CV_LeafKind_NULL: + case CV_LeafKind_NOTTRAN: + case CV_LeafKind_DIMARRAY_16t: + case CV_LeafKind_VFTPATH_16t: + case CV_LeafKind_PRECOMP_16t: + case CV_LeafKind_ENDPRECOMP: + case CV_LeafKind_OEM_16t: + case CV_LeafKind_TYPESERVER_ST: + case CV_LeafKind_SKIP_16t: + case CV_LeafKind_ARGLIST_16t: + case CV_LeafKind_DEFARG_16t: + case CV_LeafKind_LIST: + case CV_LeafKind_FIELDLIST_16t: + case CV_LeafKind_DERIVED_16t: + case CV_LeafKind_BITFIELD_16t: + case CV_LeafKind_METHODLIST_16t: + case CV_LeafKind_DIMCONU_16t: + case CV_LeafKind_DIMCONLU_16t: + case CV_LeafKind_DIMVARU_16t: + case CV_LeafKind_DIMVARLU_16t: + case CV_LeafKind_REFSYM: + case CV_LeafKind_BCLASS_16t: + case CV_LeafKind_VBCLASS_16t: + case CV_LeafKind_IVBCLASS_16t: + case CV_LeafKind_ENUMERATE_ST: + case CV_LeafKind_FRIENDFCN_16t: + case CV_LeafKind_INDEX_16t: + case CV_LeafKind_MEMBER_16t: + case CV_LeafKind_STMEMBER_16t: + case CV_LeafKind_METHOD_16t: + case CV_LeafKind_NESTTYPE_16t: + case CV_LeafKind_VFUNCTAB_16t: + case CV_LeafKind_FRIENDCLS_16t: + case CV_LeafKind_ONEMETHOD_16t: + case CV_LeafKind_VFUNCOFF_16t: + case CV_LeafKind_TI16_MAX: + //case CV_LeafKind_MODIFIER: + //case CV_LeafKind_POINTER: + case CV_LeafKind_ARRAY_ST: + case CV_LeafKind_CLASS_ST: + case CV_LeafKind_STRUCTURE_ST: + case CV_LeafKind_UNION_ST: + case CV_LeafKind_ENUM_ST: + //case CV_LeafKind_PROCEDURE: + //case CV_LeafKind_MFUNCTION: + case CV_LeafKind_COBOL0: + case CV_LeafKind_BARRAY: + case CV_LeafKind_DIMARRAY_ST: + case CV_LeafKind_VFTPATH: + case CV_LeafKind_PRECOMP_ST: + case CV_LeafKind_OEM: + case CV_LeafKind_ALIAS_ST: + case CV_LeafKind_OEM2: + case CV_LeafKind_SKIP: + //case CV_LeafKind_ARGLIST: + case CV_LeafKind_DEFARG_ST: + //case CV_LeafKind_FIELDLIST: + case CV_LeafKind_DERIVED: + //case CV_LeafKind_BITFIELD: + //case CV_LeafKind_METHODLIST: + case CV_LeafKind_DIMCONU: + case CV_LeafKind_DIMCONLU: + case CV_LeafKind_DIMVARU: + case CV_LeafKind_DIMVARLU: + case CV_LeafKind_BCLASS: + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: + case CV_LeafKind_FRIENDFCN_ST: + //case CV_LeafKind_INDEX: + case CV_LeafKind_MEMBER_ST: + case CV_LeafKind_STMEMBER_ST: + case CV_LeafKind_METHOD_ST: + case CV_LeafKind_NESTTYPE_ST: + case CV_LeafKind_VFUNCTAB: + case CV_LeafKind_FRIENDCLS: + case CV_LeafKind_ONEMETHOD_ST: + case CV_LeafKind_VFUNCOFF: + case CV_LeafKind_NESTTYPEEX_ST: + case CV_LeafKind_MEMBERMODIFY_ST: + case CV_LeafKind_MANAGED_ST: + case CV_LeafKind_ST_MAX: + case CV_LeafKind_TYPESERVER: + case CV_LeafKind_ENUMERATE: + //case CV_LeafKind_ARRAY: + //case CV_LeafKind_CLASS: + //case CV_LeafKind_STRUCTURE: + //case CV_LeafKind_UNION: + //case CV_LeafKind_ENUM: + case CV_LeafKind_DIMARRAY: + case CV_LeafKind_PRECOMP: + case CV_LeafKind_ALIAS: + case CV_LeafKind_DEFARG: + case CV_LeafKind_FRIENDFCN: + case CV_LeafKind_MEMBER: + case CV_LeafKind_STMEMBER: + case CV_LeafKind_METHOD: + case CV_LeafKind_NESTTYPE: + case CV_LeafKind_ONEMETHOD: + case CV_LeafKind_NESTTYPEEX: + case CV_LeafKind_MEMBERMODIFY: + case CV_LeafKind_MANAGED: + case CV_LeafKind_TYPESERVER2: + case CV_LeafKind_STRIDED_ARRAY: + case CV_LeafKind_HLSL: + case CV_LeafKind_MODIFIER_EX: + case CV_LeafKind_INTERFACE: + case CV_LeafKind_BINTERFACE: + case CV_LeafKind_VECTOR: + case CV_LeafKind_MATRIX: + //case CV_LeafKind_VFTABLE: + + // Leaf ID Kinds + //case CV_LeafIDKind_FUNC_ID: + //case CV_LeafIDKind_MFUNC_ID: + //case CV_LeafIDKind_BUILDINFO: + //case CV_LeafIDKind_SUBSTR_LIST: + //case CV_LeafIDKind_STRING_ID: + //case CV_LeafIDKind_UDT_SRC_LINE: + case CV_LeafIDKind_UDT_MOD_SRC_LINE: + + { + str8_list_push(arena, out, str8_lit(" no stringizer path\n")); + }break; + } + } +} + +static void +cv_stringize_leaf_array(Arena *arena, String8List *out, + CV_RecRangeArray *ranges, CV_TypeId itype_first, String8 data, + CV_StringizeLeafParams *p){ + CV_RecRange *ptr = ranges->ranges; + CV_RecRange *opl = ranges->ranges + ranges->count; + CV_TypeId itype = itype_first; + for (;ptr < opl; ptr += 1, itype += 1){ + cv_stringize_leaf_range(arena, out, ptr, itype, data, p); + str8_list_push(arena, out, str8_lit("\n")); + } +} + +//////////////////////////////// +//~ CodeView C13 Stringize Functions + +static void +cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13){ + for (CV_C13SubSectionNode *node = c13->first_sub_section; + node != 0; + node = node->next){ + String8 kind_str = cv_string_from_c13_sub_section_kind(node->kind); + str8_list_pushf(arena, out, "C13 Sub Section [%llx] (%.*s):\n", + node->off, str8_varg(kind_str)); + + switch (node->kind){ + case CV_C13_SubSectionKind_Lines: + { + CV_C13LinesParsed *lines = node->lines; + if (lines == 0){ + str8_list_push(arena, out, str8_lit(" failed to extract info\n")); + } + else{ + str8_list_pushf(arena, out, " section: %u\n", lines->sec_idx); + str8_list_pushf(arena, out, " file off: %u\n", lines->file_off); + str8_list_pushf(arena, out, " file name: %.*s\n", str8_varg(lines->file_name)); + str8_list_pushf(arena, out, " line count: %u\n", lines->line_count); + + U64 base_off = lines->secrel_base_off; + U64 *line_offs = lines->voffs; + U32 *line_nums = lines->line_nums; + + U32 line_count = lines->line_count; + for (U32 i = 0; i < line_count; i += 1){ + str8_list_pushf(arena, out, " {secrel_off=%llx, line_num=%u}\n", + line_offs[i], line_nums[i]); + } + + str8_list_pushf(arena, out, " {secrel_off=%x, ender}\n", line_offs[line_count]); + } + }break; + + case CV_C13_SubSectionKind_FileChksms: + { + str8_list_push(arena, out, str8_lit(" no stringizer path\n")); + }break; + + case CV_C13_SubSectionKind_InlineeLines: + { + str8_list_push(arena, out, str8_lit(" no stringizer path\n")); + }break; + + default: + { + str8_list_push(arena, out, str8_lit(" no stringizer path\n")); + }break; + } + + str8_list_push(arena, out, str8_lit("\n")); + } +} diff --git a/src/raddbg_convert/pdb/raddbg_codeview_stringize.h b/src/raddbg_convert/pdb/raddbg_codeview_stringize.h new file mode 100644 index 00000000..6b59ec1f --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_codeview_stringize.h @@ -0,0 +1,86 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_CODEVIEW_STRINGIZE_H +#define RADDBG_CODEVIEW_STRINGIZE_H + +//////////////////////////////// +//~ CodeView Stringize Helper Types + +typedef struct CV_StringizeSymParams{ + CV_Arch arch; +} CV_StringizeSymParams; + +typedef struct CV_StringizeLeafParams{ + U32 dummy; +} CV_StringizeLeafParams; + +//////////////////////////////// +//~ CodeView Common Stringize Functions + +static void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num); + +static void cv_stringize_lvar_addr_range(Arena *arena, String8List *out, + CV_LvarAddrRange *range); +static void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap); +static void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, + void *first, void *opl); + +static String8 cv_string_from_sym_kind(CV_SymKind kind); +static String8 cv_string_from_basic_type(CV_BasicType basic_type); +static String8 cv_string_from_leaf_kind(CV_LeafKind kind); +static String8 cv_string_from_numeric_kind(CV_NumericKind kind); +static String8 cv_string_from_c13_sub_section_kind(CV_C13_SubSectionKind kind); +static String8 cv_string_from_machine(CV_Arch arch); +static String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg); +static String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind); +static String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode); +static String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind); +static String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind); + +//////////////////////////////// +//~ CodeView Flags Stringize Functions + +static void cv_stringize_modifier_flags(Arena *arena, String8List *out, + U32 indent, CV_ModifierFlags flags); + +static void cv_stringize_type_props(Arena *arena, String8List *out, + U32 indent, CV_TypeProps props); + +static void cv_stringize_pointer_attribs(Arena *arena, String8List *out, + U32 indent, CV_PointerAttribs attribs); + +static void cv_stringize_local_flags(Arena *arena, String8List *out, + U32 indent, CV_LocalFlags flags); + +//////////////////////////////// +//~ CodeView Sym Stringize Functions + +static void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym); + +static void cv_stringize_sym_range(Arena *arena, String8List *out, + CV_RecRange *range, String8 data, + CV_StringizeSymParams *p); +static void cv_stringize_sym_array(Arena *arena, String8List *out, + CV_RecRangeArray *ranges, String8 data, + CV_StringizeSymParams *p); + +//////////////////////////////// +//~ CodeView Leaf Stringize Functions + +static void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf); + +static void cv_stringize_leaf_range(Arena *arena, String8List *out, + CV_RecRange *range, CV_TypeId itype, String8 data, + CV_StringizeLeafParams *p); +static void cv_stringize_leaf_array(Arena *arena, String8List *out, + CV_RecRangeArray *ranges, CV_TypeId itype_first, + String8 data, + CV_StringizeLeafParams *p); + +//////////////////////////////// +//~ CodeView C13 Stringize Functions + +static void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13); + +#endif //RADDBG_CODEVIEW_STRINGIZE_H diff --git a/src/raddbg_convert/pdb/raddbg_coff.h b/src/raddbg_convert/pdb/raddbg_coff.h new file mode 100644 index 00000000..6078654e --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_coff.h @@ -0,0 +1,52 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_COFF_H +#define RADDBG_COFF_H + +//////////////////////////////// +//~ COFF Format Types + +typedef struct COFF_Guid{ + U32 data1; + U16 data2; + U16 data3; + U32 data4; + U32 data5; +} COFF_Guid; + +#define COFF_ArchXList(X)\ +X(UNKNOWN, 0x0)\ +X(X86, 0x14c)\ +X(X64, 0x8664)\ +X(ARM33, 0x1d3)\ +X(ARM, 0x1c0)\ +X(ARM64, 0xaa64)\ +X(ARMNT, 0x1c4)\ +X(EBC, 0xebc)\ +X(IA64, 0x200)\ +X(M32R, 0x9041)\ +X(MIPS16, 0x266)\ +X(MIPSFPU, 0x366)\ +X(MIPSFPU16, 0x466)\ +X(POWERPC, 0x1f0)\ +X(POWERPCFP, 0x1f1)\ +X(R4000, 0x166)\ +X(RISCV32, 0x5032)\ +X(RISCV64, 0x5064)\ +X(RISCV128, 0x5128)\ +X(SH3, 0x1a2)\ +X(SH3DSP, 0x1a3)\ +X(SH4, 0x1a6)\ +X(SH5, 0x1a8)\ +X(THUMB, 0x1c2)\ +X(WCEMIPSV2, 0x169) + +typedef U16 COFF_Arch; +enum{ +#define X(N,c) COFF_Arch_##N = c, + COFF_ArchXList(X) +#undef X +}; + +#endif //COFF_H diff --git a/src/raddbg_convert/pdb/raddbg_coff_conversion.c b/src/raddbg_convert/pdb/raddbg_coff_conversion.c new file mode 100644 index 00000000..f5c25c8b --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_coff_conversion.c @@ -0,0 +1,22 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ COFF Conversion Functions + +static RADDBG_BinarySectionFlags +raddbg_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags){ + RADDBG_BinarySectionFlags result = 0; + + if (flags & COFF_SectionFlag_MEM_READ){ + result |= RADDBG_BinarySectionFlag_Read; + } + if (flags & COFF_SectionFlag_MEM_WRITE){ + result |= RADDBG_BinarySectionFlag_Write; + } + if (flags & COFF_SectionFlag_MEM_EXECUTE){ + result |= RADDBG_BinarySectionFlag_Execute; + } + + return(result); +} diff --git a/src/raddbg_convert/pdb/raddbg_coff_conversion.h b/src/raddbg_convert/pdb/raddbg_coff_conversion.h new file mode 100644 index 00000000..3036768c --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_coff_conversion.h @@ -0,0 +1,13 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_COFF_CONVERSION_H +#define RADDBG_COFF_CONVERSION_H + +//////////////////////////////// +//~ COFF Conversion Functions + +static RADDBG_BinarySectionFlags +raddbg_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); + +#endif //RADDBG_COFF_CONVERSION_H diff --git a/src/raddbg_convert/pdb/raddbg_from_pdb.c b/src/raddbg_convert/pdb/raddbg_from_pdb.c new file mode 100644 index 00000000..07db1170 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_from_pdb.c @@ -0,0 +1,3433 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ Program Parameters Parser + +static PDBCONV_Params* +pdb_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline){ + PDBCONV_Params *result = push_array(arena, PDBCONV_Params, 1); + + // get input pdb + { + String8 input_name = cmd_line_string(cmdline, str8_lit("pdb")); + if (input_name.size == 0){ + str8_list_push(arena, &result->errors, + str8_lit("missing required parameter '--pdb:'")); + } + + if (input_name.size > 0){ + String8 input_data = os_data_from_file_path(arena, input_name); + + if (input_data.size == 0){ + str8_list_pushf(arena, &result->errors, + "could not load input file '%.*s'", str8_varg(input_name)); + } + + if (input_data.size != 0){ + result->input_pdb_name = input_name; + result->input_pdb_data = input_data; + } + } + } + + // get input exe + { + String8 input_name = cmd_line_string(cmdline, str8_lit("exe")); + if (input_name.size > 0){ + String8 input_data = os_data_from_file_path(arena, input_name); + + if (input_data.size == 0){ + str8_list_pushf(arena, &result->errors, + "could not load input file '%.*s'", str8_varg(input_name)); + } + + if (input_data.size != 0){ + result->input_exe_name = input_name; + result->input_exe_data = input_data; + } + } + } + + // get output name + { + result->output_name = cmd_line_string(cmdline, str8_lit("out")); + } + + // error options + if (cmd_line_has_flag(cmdline, str8_lit("hide_errors"))){ + String8List vals = cmd_line_strings(cmdline, str8_lit("hide_errors")); + + // if no values - set all to hidden + if (vals.node_count == 0){ + B8 *ptr = (B8*)&result->hide_errors; + B8 *opl = ptr + sizeof(result->hide_errors); + for (;ptr < opl; ptr += 1){ + *ptr = 1; + } + } + + // for each explicit value set the corresponding flag to hidden + for (String8Node *node = vals.first; + node != 0; + node = node->next){ + if (str8_match(node->string, str8_lit("input"), 0)){ + result->hide_errors.input = 1; + } + else if (str8_match(node->string, str8_lit("output"), 0)){ + result->hide_errors.output = 1; + } + else if (str8_match(node->string, str8_lit("parsing"), 0)){ + result->hide_errors.parsing = 1; + } + else if (str8_match(node->string, str8_lit("converting"), 0)){ + result->hide_errors.converting = 1; + } + } + + } + + // dump options + if (cmd_line_has_flag(cmdline, str8_lit("dump"))){ + result->dump = 1; + + String8List vals = cmd_line_strings(cmdline, str8_lit("dump")); + if (vals.first == 0){ + B8 *ptr = &result->dump__first; + for (; ptr < &result->dump__last; ptr += 1){ + *ptr = 1; + } + } + else{ + for (String8Node *node = vals.first; + node != 0; + node = node->next){ + if (str8_match(node->string, str8_lit("coff_sections"), 0)){ + result->dump_coff_sections = 1; + } + else if (str8_match(node->string, str8_lit("msf"), 0)){ + result->dump_msf = 1; + } + else if (str8_match(node->string, str8_lit("sym"), 0)){ + result->dump_sym = 1; + } + else if (str8_match(node->string, str8_lit("tpi_hash"), 0)){ + result->dump_tpi_hash = 1; + } + else if (str8_match(node->string, str8_lit("leaf"), 0)){ + result->dump_leaf = 1; + } + else if (str8_match(node->string, str8_lit("c13"), 0)){ + result->dump_c13 = 1; + } + else if (str8_match(node->string, str8_lit("contributions"), 0)){ + result->dump_contributions = 1; + } + } + } + } + + return(result); +} + +//////////////////////////////// +//~ PDB Type & Symbol Info Translation Helpers + +//- pdb types and symbols + +static void +pdbconv_types_and_symbols(PDBCONV_TypesSymbolsParams *params, CONS_Root *out_root){ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + + // setup a pdb conversion context + PDBCONV_Ctx *pdb_ctx = push_array(scratch.arena, PDBCONV_Ctx, 1); + pdb_ctx->arch = params->architecture; + // TODO(allen): actually infer addr_size from arch + pdb_ctx->addr_size = 8; + pdb_ctx->hash = params->tpi_hash; + pdb_ctx->leaf = params->tpi_leaf; + pdb_ctx->sections = params->sections->sections; + pdb_ctx->section_count = params->sections->count; + pdb_ctx->root = out_root; + pdb_ctx->temp_arena = arena_alloc(); + + // convert types + pdbconv_type_cons_main_passes(pdb_ctx); + if (params->sym != 0){ + pdbconv_gather_link_names(pdb_ctx, params->sym); + pdbconv_symbol_cons(pdb_ctx, params->sym, 0); + } + U64 unit_count = params->unit_count; + for (U64 i = 0; i < unit_count; i += 1){ + CV_SymParsed *unit_sym = params->sym_for_unit[i]; + pdbconv_symbol_cons(pdb_ctx, unit_sym, 1 + i); + } + + scratch_end(scratch); + ProfEnd(); +} + +//- decoding helpers + +static U32 +pdbconv_u32_from_numeric(PDBCONV_Ctx *ctx, CV_NumericParsed *num){ + U64 n_u64 = cv_u64_from_numeric(num); + U32 n_u32 = (U32)n_u64; + if (n_u64 > 0xFFFFFFFF){ + cons_errorf(ctx->root, "constant too large"); + n_u32 = 0; + } + return(n_u32); +} + +static COFF_SectionHeader* +pdbconv_sec_header_from_sec_num(PDBCONV_Ctx *ctx, U32 sec_num){ + COFF_SectionHeader *result = 0; + if (0 < sec_num && sec_num <= ctx->section_count){ + result = ctx->sections + sec_num - 1; + } + return(result); +} + +//- type info + +static void +pdbconv_type_cons_main_passes(PDBCONV_Ctx *ctx){ + ProfBeginFunction(); + CV_TypeId itype_first = ctx->leaf->itype_first; + CV_TypeId itype_opl = ctx->leaf->itype_opl; + + // setup variadic itype -> node + ProfScope("setup variadic itype -> node") + { + CONS_Type *variadic_type = cons_type_variadic(ctx->root); + CONS_Reservation *res = cons_type_reserve_id(ctx->root, CV_TypeId_Variadic); + cons_type_fill_id(ctx->root, res, variadic_type); + } + + // resolve forward references + ProfScope("resolve forward references") + { + for (CV_TypeId itype = itype_first; itype < itype_opl; itype += 1){ + pdbconv_type_resolve_fwd(ctx, itype); + } + } + + // construct type info + ProfScope("construct type info") + { + for (CV_TypeId itype = itype_first; itype < itype_opl; itype += 1){ + pdbconv_type_resolve_itype(ctx, itype); + } + } + + // construct member info + ProfScope("construct member info") + { + for (PDBCONV_TypeRev *rev = ctx->member_revisit_first; + rev != 0; + rev = rev->next){ + pdbconv_type_equip_members(ctx, rev->owner_type, rev->field_itype); + } + } + + // construct enum info + ProfScope("construct enum info") + { + for (PDBCONV_TypeRev *rev = ctx->enum_revisit_first; + rev != 0; + rev = rev->next){ + pdbconv_type_equip_enumerates(ctx, rev->owner_type, rev->field_itype); + } + } + + // TODO(allen): equip udts with location information + ProfEnd(); +} + +static CV_TypeId +pdbconv_type_resolve_fwd(PDBCONV_Ctx *ctx, CV_TypeId itype){ + Assert(ctx->leaf->itype_first <= itype && itype < ctx->leaf->itype_opl); + + CV_TypeId result = 0; + + CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[itype - ctx->leaf->itype_first]; + String8 data = ctx->leaf->data; + if (range->off + range->hdr.size <= data.size){ + U8 *first = data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + + // figure out if this itype resolves to another + switch (range->hdr.kind){ + default:break; + + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + // TODO(allen): error if bad range + if (sizeof(CV_LeafStruct) <= cap){ + CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; + + // size + U8 *numeric_ptr = (U8*)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, first + cap); + + // unique name + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, first + cap); + + if (lf_struct->props & CV_TypeProp_FwdRef){ + B32 do_unique_name_lookup = ((lf_struct->props & CV_TypeProp_Scoped) != 0) && + ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0); + if (do_unique_name_lookup){ + result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, unique_name, 1); + } + else{ + result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); + } + } + } + }break; + + case CV_LeafKind_UNION: + { + // TODO(allen): error if bad range + if (sizeof(CV_LeafUnion) <= cap){ + CV_LeafUnion *lf_union = (CV_LeafUnion*)first; + + // size + U8 *numeric_ptr = (U8*)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, first + cap); + + // unique name + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, first + cap); + + if (lf_union->props & CV_TypeProp_FwdRef){ + B32 do_unique_name_lookup = ((lf_union->props & CV_TypeProp_Scoped) != 0) && + ((lf_union->props & CV_TypeProp_HasUniqueName) != 0); + if (do_unique_name_lookup){ + result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, unique_name, 1); + } + else{ + result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); + } + } + } + }break; + + case CV_LeafKind_ENUM: + { + // TODO(allen): error if bad range + if (sizeof(CV_LeafEnum) <= cap){ + CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; + + // name + U8 *name_ptr = (U8*)(lf_enum + 1); + String8 name = str8_cstring_capped((char*)name_ptr, first + cap); + + // unique name + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, first + cap); + + if (lf_enum->props & CV_TypeProp_FwdRef){ + B32 do_unique_name_lookup = ((lf_enum->props & CV_TypeProp_Scoped) != 0) && + ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0); + if (do_unique_name_lookup){ + result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, unique_name, 1); + } + else{ + result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); + } + } + } + }break; + } + } + + // save in map + if (result != 0){ + pdbconv_type_fwd_map_set(ctx->temp_arena, &ctx->fwd_map, itype, result); + } + + return(result); +} + +static CONS_Type* +pdbconv_type_resolve_itype(PDBCONV_Ctx *ctx, CV_TypeId itype){ + ProfBeginFunction(); + + // convert fwd references to real types + CV_TypeId resolved_itype = pdbconv_type_fwd_map_get(&ctx->fwd_map, itype); + if (resolved_itype != 0){ + itype = resolved_itype; + } + + // type handle from id + CONS_Type *result = cons_type_from_id(ctx->root, itype); + + // basic type + if (result == 0){ + if (itype < 0x1000){ + result = pdbconv_type_cons_basic(ctx, itype); + } + } + + // leaf decode + if (result == 0){ + if (ctx->leaf->itype_first <= itype && itype < ctx->leaf->itype_opl){ + result = pdbconv_type_cons_leaf_record(ctx, itype); + } + } + + // never return null, return "nil" instead + if (result == 0){ + result = cons_type_nil(ctx->root); + } + + ProfEnd(); + return(result); +} + +static void +pdbconv_type_equip_members(PDBCONV_Ctx *ctx, CONS_Type *owner_type, CV_TypeId field_itype){ + Temp scratch = scratch_begin(0, 0); + + String8 data = ctx->leaf->data; + + // field stack + // TODO(allen): add notes about field tasks + struct FieldTask{ + struct FieldTask *next; + CV_TypeId itype; + }; + struct FieldTask *handled = 0; + struct FieldTask *todo = 0; + { + struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); + SLLStackPush(todo, task); + task->itype = field_itype; + } + + for (;;){ + // exit condition + if (todo == 0){ + break; + } + + // determine itype + CV_TypeId field_itype = todo->itype; + { + struct FieldTask *task = todo; + SLLStackPop(todo); + SLLStackPush(handled, task); + } + + // get leaf range + // TODO(allen): error if this itype is bad + U8 *first = 0; + U64 cap = 0; + if (ctx->leaf->itype_first <= field_itype && field_itype < ctx->leaf->itype_opl){ + CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[field_itype - ctx->leaf->itype_first]; + // check valid arglist + if (range->hdr.kind == CV_LeafKind_FIELDLIST && + range->off + range->hdr.size <= data.size){ + first = data.str + range->off + 2; + cap = range->hdr.size - 2; + } + } + + U64 cursor = 0; + for (;cursor + sizeof(CV_LeafKind) <= cap;){ + CV_LeafKind field_kind = *(CV_LeafKind*)(first + cursor); + + U64 list_item_off = cursor + 2; + // if we hit an error or forget to set next cursor for a case + // default to exiting the loop + U64 list_item_opl_off = cap; + + switch (field_kind){ + case CV_LeafKind_INDEX: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafIndex) <= cap){ + // compute whole layout + CV_LeafIndex *index = (CV_LeafIndex*)(first + list_item_off); + + list_item_opl_off = list_item_off + sizeof(*index); + + // create new todo task + CV_TypeId new_itype = index->itype; + B32 is_new = 1; + for (struct FieldTask *task = handled; + task != 0; + task = task->next){ + if (task->itype == new_itype){ + is_new = 0; + break; + } + } + if (is_new){ + struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); + SLLStackPush(todo, task); + task->itype = new_itype; + } + } + }break; + + case CV_LeafKind_MEMBER: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafMember) <= cap){ + // compute whole layout + CV_LeafMember *member = (CV_LeafMember*)(first + list_item_off); + + U64 offset_off = list_item_off + sizeof(*member); + CV_NumericParsed offset = cv_numeric_from_data_range(first + offset_off, first + cap); + + U64 name_off = offset_off + offset.encoded_size; + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // emit member + CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, member->itype); + U32 offset_u32 = pdbconv_u32_from_numeric(ctx, &offset); + cons_type_add_member_data_field(ctx->root, owner_type, name, mem_type, offset_u32); + } + }break; + + case CV_LeafKind_STMEMBER: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafStMember) <= cap){ + // compute whole layout + CV_LeafStMember *stmember = (CV_LeafStMember*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*stmember); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // TODO(allen): handle attribs + + // emit member + CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, stmember->itype); + cons_type_add_member_static_data(ctx->root, owner_type, name, mem_type); + } + }break; + + case CV_LeafKind_METHOD: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafMethod) <= cap){ + // compute whole layout + CV_LeafMethod *method = (CV_LeafMethod*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*method); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // extract method list + U8 *first = 0; + U64 cap = 0; + + // TODO(allen): error if bad itype + CV_TypeId methodlist_itype = method->list_itype; + if (ctx->leaf->itype_first <= methodlist_itype && + methodlist_itype < ctx->leaf->itype_opl){ + CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[methodlist_itype - ctx->leaf->itype_first]; + + // check valid methodlist + if (range->hdr.kind == CV_LeafKind_METHODLIST && + range->off + range->hdr.size <= data.size){ + first = data.str + range->off + 2; + cap = range->hdr.size - 2; + } + } + + // emit loop + U64 cursor = 0; + for (;cursor + sizeof(CV_LeafMethodListMember) <= cap;){ + CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)(first + cursor); + + CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(method->attribs); + + // TODO(allen): PROBLEM + // We only get offsets for virtual functions (the "vbaseoff") from + // "Intro" and "PureIntro". In C++ inheritance, when we have a chain + // of inheritance (let's just talk single inheritance for now) the + // first class in the chain that introduces a new virtual function + // has this "Intro" method. If a later class in the chain redefines + // the virtual function it only has a "Virtual" method which does + // not update the offset. There is a "Virtual" and "PureVirtual" + // variant of "Virtual". The "Pure" in either case means there + // is no concrete procedure. When there is no "Pure" the method + // should have a corresponding procedure symbol id. + // + // The issue is we will want to mark all of our virtual methods as + // virtual and give them an offset, but that means we have to do + // some extra figuring to propogate offsets from "Intro" methods + // to "Virtual" methods in inheritance trees. That is - IF we want + // to start preserving the offsets of virtuals. There is room in + // the method struct to make this work, but for now I've just + // decided to drop this information. It is not urgently useful to + // us and greatly complicates matters. + + // extract vbaseoff + U64 next_cursor = cursor + sizeof(*method); + U32 vbaseoff = 0; + if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ + if (cursor + sizeof(*method) + 4 <= cap){ + vbaseoff = *(U32*)(method + 1); + } + next_cursor += 4; + } + + // update cursor + cursor = next_cursor; + + // TODO(allen): handle attribs + + // emit + CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, method->itype); + + switch (prop){ + default: + { + cons_type_add_member_method(ctx->root, owner_type, name, mem_type); + }break; + + case CV_MethodProp_Static: + { + cons_type_add_member_static_method(ctx->root, owner_type, name, mem_type); + }break; + + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + cons_type_add_member_virtual_method(ctx->root, owner_type, name, mem_type); + }break; + } + } + + } + }break; + + case CV_LeafKind_ONEMETHOD: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafOneMethod) <= cap){ + // compute whole layout + CV_LeafOneMethod *one_method = (CV_LeafOneMethod*)(first + list_item_off); + + CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(one_method->attribs); + + U64 vbaseoff_off = list_item_off + sizeof(*one_method); + U64 vbaseoff_opl_off = vbaseoff_off; + U32 vbaseoff = 0; + if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ + vbaseoff = *(U32*)(first + vbaseoff_off); + vbaseoff_opl_off += sizeof(vbaseoff); + } + + U64 name_off = vbaseoff_opl_off; + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // TODO(allen): handle attribs + + // emit + CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, one_method->itype); + + switch (prop){ + default: + { + cons_type_add_member_method(ctx->root, owner_type, name, mem_type); + }break; + + case CV_MethodProp_Static: + { + cons_type_add_member_static_method(ctx->root, owner_type, name, mem_type); + }break; + + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + cons_type_add_member_virtual_method(ctx->root, owner_type, name, mem_type); + }break; + } + } + }break; + + case CV_LeafKind_NESTTYPE: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafNestType) <= cap){ + // compute whole layout + CV_LeafNestType *nest_type = (CV_LeafNestType*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*nest_type); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // emit member + CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, nest_type->itype); + cons_type_add_member_nested_type(ctx->root, owner_type, mem_type); + } + }break; + + case CV_LeafKind_NESTTYPEEX: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafNestTypeEx) <= cap){ + // compute whole layout + CV_LeafNestTypeEx *nest_type = (CV_LeafNestTypeEx*)(first + list_item_off); + + U64 name_off = list_item_off + sizeof(*nest_type); + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // TODO(allen): handle attribs + + // emit member + CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, nest_type->itype); + cons_type_add_member_nested_type(ctx->root, owner_type, mem_type); + } + }break; + + case CV_LeafKind_BCLASS: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafBClass) <= cap){ + // compute whole layout + CV_LeafBClass *bclass = (CV_LeafBClass*)(first + list_item_off); + + U64 offset_off = list_item_off + sizeof(*bclass); + CV_NumericParsed offset = cv_numeric_from_data_range(first + offset_off, first + cap); + + list_item_opl_off = offset_off + offset.encoded_size; + + // TODO(allen): handle attribs + + // emit member + CONS_Type *base_type = pdbconv_type_resolve_itype(ctx, bclass->itype); + U32 offset_u32 = pdbconv_u32_from_numeric(ctx, &offset); + cons_type_add_member_base(ctx->root, owner_type, base_type, offset_u32); + } + }break; + + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafVBClass) <= cap){ + // compute whole layout + CV_LeafVBClass *vbclass = (CV_LeafVBClass*)(first + list_item_off); + + U64 num1_off = list_item_off + sizeof(*vbclass); + CV_NumericParsed num1 = cv_numeric_from_data_range(first + num1_off, first + cap); + + U64 num2_off = num1_off + num1.encoded_size; + CV_NumericParsed num2 = cv_numeric_from_data_range(first + num2_off, first + cap); + + list_item_opl_off = num2_off + num2.encoded_size; + + // TODO(allen): handle attribs + + // emit member + CONS_Type *base_type = pdbconv_type_resolve_itype(ctx, vbclass->itype); + U32 vbptr_offset_u32 = pdbconv_u32_from_numeric(ctx, &num1); + U32 vtable_offset_u32 = pdbconv_u32_from_numeric(ctx, &num2); + cons_type_add_member_virtual_base(ctx->root, owner_type, base_type, + vbptr_offset_u32, vtable_offset_u32); + } + }break; + + // discard cases - we don't currently do anything with these + case CV_LeafKind_VFUNCTAB: + {}break; + + // unhandled or invalid cases + default: + { + String8 kind_str = cv_string_from_leaf_kind(field_kind); + cons_errorf(ctx->root, "unhandled/invalid case: equip_members -> %.*s", + str8_varg(kind_str)); + }break; + } + + // update cursor + U64 next_cursor = AlignPow2(list_item_opl_off, 4); + cursor = next_cursor; + } + } + + scratch_end(scratch); +} + +static void +pdbconv_type_equip_enumerates(PDBCONV_Ctx *ctx, CONS_Type *owner_type, CV_TypeId field_itype){ + Temp scratch = scratch_begin(0, 0); + + String8 data = ctx->leaf->data; + + // field stack + // TODO(allen): add notes about field tasks + struct FieldTask{ + struct FieldTask *next; + CV_TypeId itype; + }; + struct FieldTask *handled = 0; + struct FieldTask *todo = 0; + { + struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); + SLLStackPush(todo, task); + task->itype = field_itype; + } + + for (;;){ + // exit condition + if (todo == 0){ + break; + } + + // determine itype + CV_TypeId field_itype = todo->itype; + { + struct FieldTask *task = todo; + SLLStackPop(todo); + SLLStackPush(handled, task); + } + + // get leaf range + // TODO(allen): error if this itype is bad + U8 *first = 0; + U64 cap = 0; + if (ctx->leaf->itype_first <= field_itype && field_itype < ctx->leaf->itype_opl){ + CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[field_itype - ctx->leaf->itype_first]; + // check valid arglist + if (range->hdr.kind == CV_LeafKind_FIELDLIST && + range->off + range->hdr.size <= data.size){ + first = data.str + range->off + 2; + cap = range->hdr.size - 2; + } + } + + U64 cursor = 0; + for (;cursor + sizeof(CV_LeafKind) <= cap;){ + CV_LeafKind field_kind = *(CV_LeafKind*)(first + cursor); + + U64 list_item_off = cursor + 2; + // if we hit an error or forget to set next cursor for a case + // default to exiting the loop + U64 list_item_opl_off = cap; + + switch (field_kind){ + case CV_LeafKind_INDEX: + { + // TODO(allen): error if bad range + if (list_item_off + sizeof(CV_LeafIndex) <= cap){ + // compute whole layout + CV_LeafIndex *index = (CV_LeafIndex*)(first + list_item_off); + + list_item_opl_off = list_item_off + sizeof(*index); + + // create new todo task + CV_TypeId new_itype = index->itype; + B32 is_new = 1; + for (struct FieldTask *task = handled; + task != 0; + task = task->next){ + if (task->itype == new_itype){ + is_new = 0; + break; + } + } + if (is_new){ + struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); + SLLStackPush(todo, task); + task->itype = new_itype; + } + } + }break; + + case CV_LeafKind_ENUMERATE: + { + // compute whole layout + CV_LeafEnumerate *enumerate = (CV_LeafEnumerate*)(first + list_item_off); + + U64 val_off = list_item_off + sizeof(*enumerate); + CV_NumericParsed val = cv_numeric_from_data_range(first + val_off, first + cap); + + U64 name_off = val_off + val.encoded_size; + String8 name = str8_cstring_capped(first + name_off, first + cap); + + list_item_opl_off = name_off + name.size + 1; + + // TODO(allen): handle attribs + + // emit enum val + U64 val_u64 = cv_u64_from_numeric(&val); + cons_type_add_enum_val(ctx->root, owner_type, name, val_u64); + }break; + + // unhandled or invalid cases + default: + { + String8 kind_str = cv_string_from_leaf_kind(field_kind); + cons_errorf(ctx->root, "unhandled/invalid case: equip_enumerates -> %.*s", + str8_varg(kind_str)); + }break; + } + + // update cursor + U64 next_cursor = AlignPow2(list_item_opl_off, 4); + cursor = next_cursor; + } + } + + scratch_end(scratch); +} + +static CONS_Type* +pdbconv_type_cons_basic(PDBCONV_Ctx *ctx, CV_TypeId itype){ + ProfBeginFunction(); + Assert(itype < 0x1000); + + CV_BasicPointerKind basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); + CV_BasicType basic_type_code = CV_BasicTypeFromTypeId(itype); + + CONS_Reservation *basic_res = cons_type_reserve_id(ctx->root, basic_type_code); + + CONS_Type *basic_type = 0; + switch (basic_type_code){ + case CV_BasicType_VOID: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Void, str8_lit("void")); + }break; + + case CV_BasicType_HRESULT: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Handle, str8_lit("HRESULT")); + }break; + + case CV_BasicType_RCHAR: + case CV_BasicType_CHAR: + case CV_BasicType_CHAR8: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Char8, str8_lit("char")); + }break; + + case CV_BasicType_UCHAR: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_UChar8, str8_lit("UCHAR")); + }break; + + case CV_BasicType_WCHAR: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_UChar16, str8_lit("WCHAR")); + }break; + + case CV_BasicType_CHAR16: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Char16, str8_lit("CHAR16")); + }break; + + case CV_BasicType_CHAR32: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Char32, str8_lit("CHAR32")); + }break; + + case CV_BasicType_BOOL8: + case CV_BasicType_INT8: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S8, str8_lit("S8")); + }break; + + case CV_BasicType_BOOL16: + case CV_BasicType_INT16: + case CV_BasicType_SHORT: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S16, str8_lit("S16")); + }break; + + case CV_BasicType_BOOL32: + case CV_BasicType_INT32: + case CV_BasicType_LONG: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S32, str8_lit("S32")); + }break; + + case CV_BasicType_BOOL64: + case CV_BasicType_INT64: + case CV_BasicType_QUAD: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S64, str8_lit("S64")); + }break; + + case CV_BasicType_INT128: + case CV_BasicType_OCT: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S128, str8_lit("S128")); + }break; + + case CV_BasicType_UINT8: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U8, str8_lit("U8")); + }break; + + case CV_BasicType_UINT16: + case CV_BasicType_USHORT: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U16, str8_lit("U16")); + }break; + + case CV_BasicType_UINT32: + case CV_BasicType_ULONG: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U32, str8_lit("U32")); + }break; + + case CV_BasicType_UINT64: + case CV_BasicType_UQUAD: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U64, str8_lit("U64")); + }break; + + case CV_BasicType_UINT128: + case CV_BasicType_UOCT: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U128, str8_lit("U128")); + }break; + + case CV_BasicType_FLOAT16: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F16, str8_lit("F16")); + }break; + + case CV_BasicType_FLOAT32: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F32, str8_lit("F32")); + }break; + + case CV_BasicType_FLOAT32PP: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F32PP, str8_lit("F32PP")); + }break; + + case CV_BasicType_FLOAT48: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F48, str8_lit("F48")); + }break; + + case CV_BasicType_FLOAT64: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F64, str8_lit("F64")); + }break; + + case CV_BasicType_FLOAT80: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F80, str8_lit("F80")); + }break; + + case CV_BasicType_FLOAT128: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F128, str8_lit("F128")); + }break; + + case CV_BasicType_COMPLEX32: + { + basic_type = + cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF32, str8_lit("ComplexF32")); + }break; + + case CV_BasicType_COMPLEX64: + { + basic_type = + cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF64, str8_lit("ComplexF64")); + }break; + + case CV_BasicType_COMPLEX80: + { + basic_type = + cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF80, str8_lit("ComplexF80")); + }break; + + case CV_BasicType_COMPLEX128: + { + basic_type = + cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF128, str8_lit("ComplexF128")); + }break; + + case CV_BasicType_PTR: + { + basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Handle, str8_lit("PTR")); + }break; + } + + // basic resolve + cons_type_fill_id(ctx->root, basic_res, basic_type); + + // wrap in constructed type + CONS_Type *constructed_type = 0; + if (basic_ptr_kind != 0 && basic_type != 0){ + CONS_Reservation *constructed_res = cons_type_reserve_id(ctx->root, itype); + + switch (basic_ptr_kind){ + case CV_BasicPointerKind_16BIT: + case CV_BasicPointerKind_FAR_16BIT: + case CV_BasicPointerKind_HUGE_16BIT: + case CV_BasicPointerKind_32BIT: + case CV_BasicPointerKind_16_32BIT: + case CV_BasicPointerKind_64BIT: + { + constructed_type = cons_type_pointer(ctx->root, basic_type, RADDBG_TypeKind_Ptr); + }break; + } + + // constructed resolve + cons_type_fill_id(ctx->root, constructed_res, constructed_type); + } + + // select output + CONS_Type *result = basic_type; + if (basic_ptr_kind != 0){ + result = constructed_type; + } + + ProfEnd(); + return(result); +} + +static CONS_Type* +pdbconv_type_cons_leaf_record(PDBCONV_Ctx *ctx, CV_TypeId itype){ + ProfBeginFunction(); + Assert(ctx->leaf->itype_first <= itype && itype < ctx->leaf->itype_opl); + + CONS_Reservation *res = cons_type_reserve_id(ctx->root, itype); + + CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[itype - ctx->leaf->itype_first]; + String8 data = ctx->leaf->data; + + CONS_Type *result = 0; + if (range->off + range->hdr.size <= data.size){ + U8 *first = data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + + switch (range->hdr.kind){ + case CV_LeafKind_MODIFIER: + { + ProfBegin("CV_LeafKind_MODIFIER"); + + // TODO(allen): error if bad range + if (sizeof(CV_LeafModifier) <= cap){ + CV_LeafModifier *modifier = (CV_LeafModifier*)first; + + RADDBG_TypeModifierFlags flags = 0; + if (modifier->flags & CV_ModifierFlag_Const){ + flags |= RADDBG_TypeModifierFlag_Const; + } + if (modifier->flags & CV_ModifierFlag_Volatile){ + flags |= RADDBG_TypeModifierFlag_Volatile; + } + + CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, modifier->itype); + if (flags != 0){ + result = cons_type_modifier(ctx->root, direct_type, flags); + } + else{ + result = direct_type; + } + } + + ProfEnd(); + }break; + + case CV_LeafKind_POINTER: + { + ProfBegin("CV_LeafKind_POINTER"); + + // TODO(allen): error if bad range + if (sizeof(CV_LeafPointer) <= cap){ + CV_LeafPointer *pointer = (CV_LeafPointer*)first; + + CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(pointer->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(pointer->attribs); + U32 ptr_size = CV_PointerAttribs_ExtractSize(pointer->attribs); + + // TODO(allen): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead + + // extract modifier flags + RADDBG_TypeModifierFlags modifier_flags = 0; + if (pointer->attribs & CV_PointerAttrib_Const){ + modifier_flags |= RADDBG_TypeModifierFlag_Const; + } + if (pointer->attribs & CV_PointerAttrib_Volatile){ + modifier_flags |= RADDBG_TypeModifierFlag_Volatile; + } + + // determine type kind + RADDBG_TypeKind type_kind = RADDBG_TypeKind_Ptr; + if (pointer->attribs & CV_PointerAttrib_LRef){ + type_kind = RADDBG_TypeKind_LRef; + } + else if (pointer->attribs & CV_PointerAttrib_RRef){ + type_kind = RADDBG_TypeKind_RRef; + } + if (ptr_mode == CV_PointerMode_LRef){ + type_kind = RADDBG_TypeKind_LRef; + } + else if (ptr_mode == CV_PointerMode_RRef){ + type_kind = RADDBG_TypeKind_RRef; + } + + CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, pointer->itype); + CONS_Type *ptr_type = cons_type_pointer(ctx->root, direct_type, type_kind); + + result = ptr_type; + if (modifier_flags != 0){ + result = cons_type_modifier(ctx->root, ptr_type, modifier_flags); + } + } + + ProfEnd(); + }break; + + case CV_LeafKind_PROCEDURE: + { + ProfBegin("CV_LeafKind_PROCEDURE"); + + // TODO(allen): error if bad range + if (sizeof(CV_LeafProcedure) <= cap){ + CV_LeafProcedure *procedure = (CV_LeafProcedure*)first; + + Temp scratch = scratch_begin(0, 0); + + // TODO(allen): handle call_kind & attribs + + CONS_Type *ret_type = pdbconv_type_resolve_and_check(ctx, procedure->ret_itype); + + CONS_TypeList param_list = {0}; + pdbconv_type_resolve_arglist(scratch.arena, ¶m_list, ctx, procedure->arg_itype); + + result = cons_type_proc(ctx->root, ret_type, ¶m_list); + + scratch_end(scratch); + } + + ProfEnd(); + }break; + + case CV_LeafKind_MFUNCTION: + { + ProfBegin("CV_LeafKind_MFUNCTION"); + + // TODO(allen): error if bad range + if (sizeof(CV_LeafMFunction) <= cap){ + CV_LeafMFunction *mfunction = (CV_LeafMFunction*)first; + + Temp scratch = scratch_begin(0, 0); + + // TODO(allen): handle call_kind & attribs + // TODO(allen): preserve "this_adjust" + + CONS_Type *ret_type = pdbconv_type_resolve_and_check(ctx, mfunction->ret_itype); + + CONS_TypeList param_list = {0}; + pdbconv_type_resolve_arglist(scratch.arena, ¶m_list, ctx, mfunction->arg_itype); + + CONS_Type *this_type = 0; + if (mfunction->this_itype != 0){ + this_type = pdbconv_type_resolve_and_check(ctx, mfunction->this_itype); + result = cons_type_method(ctx->root, this_type, ret_type, ¶m_list); + } + else{ + result = cons_type_proc(ctx->root, ret_type, ¶m_list); + } + + scratch_end(scratch); + } + + ProfEnd(); + }break; + + case CV_LeafKind_BITFIELD: + { + ProfBegin("CV_LeafKind_BITFIELD"); + // TODO(allen): error if bad range + if (sizeof(CV_LeafBitField) <= cap){ + CV_LeafBitField *bit_field = (CV_LeafBitField*)first; + CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, bit_field->itype); + result = cons_type_bitfield(ctx->root, direct_type, bit_field->pos, bit_field->len); + } + ProfEnd(); + }break; + + case CV_LeafKind_ARRAY: + { + ProfBegin("CV_LeafKind_ARRAY"); + // TODO(allen): error if bad range + if (sizeof(CV_LeafArray) <= cap){ + CV_LeafArray *array = (CV_LeafArray*)first; + + // parse count + U8 *numeric_ptr = (U8*)(array + 1); + CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, first + cap); + + U64 full_size = cv_u64_from_numeric(&array_count); + + CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, array->entry_itype); + U64 count = full_size; + if (direct_type != 0 && direct_type->byte_size != 0){ + count /= direct_type->byte_size; + } + + // build type + result = cons_type_array(ctx->root, direct_type, count); + } + ProfEnd(); + }break; + + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + ProfBegin("CV_LeafKind_CLASS/CV_LeafKind_STRUCTURE"); + // TODO(allen): error if bad range + if (sizeof(CV_LeafStruct) <= cap){ + CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; + + // TODO(allen): handle props + + // size + U8 *numeric_ptr = (U8*)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + U64 size_u64 = cv_u64_from_numeric(&size); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, first + cap); + + // incomplete type + if (lf_struct->props & CV_TypeProp_FwdRef){ + RADDBG_TypeKind type_kind = RADDBG_TypeKind_IncompleteStruct; + if (range->hdr.kind == CV_LeafKind_CLASS){ + type_kind = RADDBG_TypeKind_IncompleteClass; + } + result = cons_type_incomplete(ctx->root, type_kind, name); + } + + // complete type + else{ + RADDBG_TypeKind type_kind = RADDBG_TypeKind_Struct; + if (range->hdr.kind == CV_LeafKind_CLASS){ + type_kind = RADDBG_TypeKind_Class; + } + result = cons_type_udt(ctx->root, type_kind, name, size_u64); + + // remember to revisit this for members + { + PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); + rev->owner_type = result; + rev->field_itype = lf_struct->field_itype; + SLLQueuePush(ctx->member_revisit_first, ctx->member_revisit_last, rev); + } + } + } + ProfEnd(); + }break; + + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + ProfBegin("CV_LeafKind_CLASS2/CV_LeafKind_STRUCT2"); + // TODO(allen): error if bad range + if (sizeof(CV_LeafStruct2) <= cap){ + CV_LeafStruct2 *lf_struct = (CV_LeafStruct2*)first; + + // TODO(allen): handle props + + // name + U8 *name_ptr = (U8*)(lf_struct + 1); + String8 name = str8_cstring_capped((char*)name_ptr, first + cap); + + // incomplete type + if (lf_struct->props & CV_TypeProp_FwdRef){ + RADDBG_TypeKind type_kind = RADDBG_TypeKind_IncompleteStruct; + if (range->hdr.kind == CV_LeafKind_CLASS2){ + type_kind = RADDBG_TypeKind_IncompleteClass; + } + result = cons_type_incomplete(ctx->root, type_kind, name); + } + + // complete type + else{ + RADDBG_TypeKind type_kind = RADDBG_TypeKind_Struct; + if (range->hdr.kind == CV_LeafKind_CLASS2){ + type_kind = RADDBG_TypeKind_Class; + } + result = cons_type_udt(ctx->root, type_kind, name, lf_struct->size); + + // remember to revisit this for members + { + PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); + rev->owner_type = result; + rev->field_itype = lf_struct->field_itype; + SLLQueuePush(ctx->member_revisit_first, ctx->member_revisit_last, rev); + } + } + } + ProfEnd(); + }break; + + case CV_LeafKind_UNION: + { + ProfBegin("CV_LeafKind_UNION"); + // TODO(allen): error if bad range + if (sizeof(CV_LeafUnion) <= cap){ + CV_LeafUnion *lf_union = (CV_LeafUnion*)first; + + // TODO(allen): handle props + + // size + U8 *numeric_ptr = (U8*)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + U64 size_u64 = cv_u64_from_numeric(&size); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, first + cap); + + // incomplete type + if (lf_union->props & CV_TypeProp_FwdRef){ + result = + cons_type_incomplete(ctx->root, RADDBG_TypeKind_IncompleteUnion, name); + } + + // complete type + else{ + result = cons_type_udt(ctx->root, RADDBG_TypeKind_Union, name, size_u64); + + // remember to revisit this for members + { + PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); + rev->owner_type = result; + rev->field_itype = lf_union->field_itype; + SLLQueuePush(ctx->member_revisit_first, ctx->member_revisit_last, rev); + } + } + } + ProfEnd(); + }break; + + case CV_LeafKind_ENUM: + { + ProfBegin("CV_LeafKind_ENUM"); + // TODO(allen): error if bad range + if (sizeof(CV_LeafEnum) <= cap){ + CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; + + // TODO(allen): handle props + + // name + U8 *name_ptr = (U8*)(lf_enum + 1); + String8 name = str8_cstring_capped((char*)name_ptr, first + cap); + + // incomplete type + if (lf_enum->props & CV_TypeProp_FwdRef){ + result = cons_type_incomplete(ctx->root, RADDBG_TypeKind_IncompleteEnum, name); + } + + // complete type + else{ + CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, lf_enum->base_itype); + result = cons_type_enum(ctx->root, direct_type, name); + + // remember to revisit this for enumerates + { + PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); + rev->owner_type = result; + rev->field_itype = lf_enum->field_itype; + SLLQueuePush(ctx->enum_revisit_first, ctx->enum_revisit_last, rev); + } + } + } + ProfEnd(); + }break; + + // discard cases - we currently discard these these intentionally + // so we mark them as "handled nil" + case CV_LeafKind_VTSHAPE: + case CV_LeafKind_VFTABLE: + case CV_LeafKind_LABEL: + { + result = cons_type_handled_nil(ctx->root); + }break; + + // do nothing cases - these get handled in special passes and + // they should not be appearing as direct types + // or parameter types for any other types + // so if the input data is valid we won't get + // error messages even if they resolve to nil + case CV_LeafKind_FIELDLIST: + case CV_LeafKind_ARGLIST: + case CV_LeafKind_METHODLIST: + {}break; + + // Leaf Kinds + case CV_LeafKind_MODIFIER_16t: + case CV_LeafKind_POINTER_16t: + case CV_LeafKind_ARRAY_16t: + case CV_LeafKind_CLASS_16t: + case CV_LeafKind_STRUCTURE_16t: + case CV_LeafKind_UNION_16t: + case CV_LeafKind_ENUM_16t: + case CV_LeafKind_PROCEDURE_16t: + case CV_LeafKind_MFUNCTION_16t: + //case CV_LeafKind_VTSHAPE: + case CV_LeafKind_COBOL0_16t: + case CV_LeafKind_COBOL1: + case CV_LeafKind_BARRAY_16t: + //case CV_LeafKind_LABEL: + case CV_LeafKind_NULL: + case CV_LeafKind_NOTTRAN: + case CV_LeafKind_DIMARRAY_16t: + case CV_LeafKind_VFTPATH_16t: + case CV_LeafKind_PRECOMP_16t: + case CV_LeafKind_ENDPRECOMP: + case CV_LeafKind_OEM_16t: + case CV_LeafKind_TYPESERVER_ST: + case CV_LeafKind_SKIP_16t: + case CV_LeafKind_ARGLIST_16t: + case CV_LeafKind_DEFARG_16t: + case CV_LeafKind_LIST: + case CV_LeafKind_FIELDLIST_16t: + case CV_LeafKind_DERIVED_16t: + case CV_LeafKind_BITFIELD_16t: + case CV_LeafKind_METHODLIST_16t: + case CV_LeafKind_DIMCONU_16t: + case CV_LeafKind_DIMCONLU_16t: + case CV_LeafKind_DIMVARU_16t: + case CV_LeafKind_DIMVARLU_16t: + case CV_LeafKind_REFSYM: + case CV_LeafKind_BCLASS_16t: + case CV_LeafKind_VBCLASS_16t: + case CV_LeafKind_IVBCLASS_16t: + case CV_LeafKind_ENUMERATE_ST: + case CV_LeafKind_FRIENDFCN_16t: + case CV_LeafKind_INDEX_16t: + case CV_LeafKind_MEMBER_16t: + case CV_LeafKind_STMEMBER_16t: + case CV_LeafKind_METHOD_16t: + case CV_LeafKind_NESTTYPE_16t: + case CV_LeafKind_VFUNCTAB_16t: + case CV_LeafKind_FRIENDCLS_16t: + case CV_LeafKind_ONEMETHOD_16t: + case CV_LeafKind_VFUNCOFF_16t: + case CV_LeafKind_TI16_MAX: + //case CV_LeafKind_MODIFIER: + //case CV_LeafKind_POINTER: + case CV_LeafKind_ARRAY_ST: + case CV_LeafKind_CLASS_ST: + case CV_LeafKind_STRUCTURE_ST: + case CV_LeafKind_UNION_ST: + case CV_LeafKind_ENUM_ST: + //case CV_LeafKind_PROCEDURE: + //case CV_LeafKind_MFUNCTION: + case CV_LeafKind_COBOL0: + case CV_LeafKind_BARRAY: + case CV_LeafKind_DIMARRAY_ST: + case CV_LeafKind_VFTPATH: + case CV_LeafKind_PRECOMP_ST: + case CV_LeafKind_OEM: + case CV_LeafKind_ALIAS_ST: + case CV_LeafKind_OEM2: + case CV_LeafKind_SKIP: + //case CV_LeafKind_ARGLIST: + case CV_LeafKind_DEFARG_ST: + //case CV_LeafKind_FIELDLIST: + case CV_LeafKind_DERIVED: + //case CV_LeafKind_BITFIELD: + //case CV_LeafKind_METHODLIST: + case CV_LeafKind_DIMCONU: + case CV_LeafKind_DIMCONLU: + case CV_LeafKind_DIMVARU: + case CV_LeafKind_DIMVARLU: + case CV_LeafKind_BCLASS: + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: + case CV_LeafKind_FRIENDFCN_ST: + case CV_LeafKind_INDEX: + case CV_LeafKind_MEMBER_ST: + case CV_LeafKind_STMEMBER_ST: + case CV_LeafKind_METHOD_ST: + case CV_LeafKind_NESTTYPE_ST: + case CV_LeafKind_VFUNCTAB: + case CV_LeafKind_FRIENDCLS: + case CV_LeafKind_ONEMETHOD_ST: + case CV_LeafKind_VFUNCOFF: + case CV_LeafKind_NESTTYPEEX_ST: + case CV_LeafKind_MEMBERMODIFY_ST: + case CV_LeafKind_MANAGED_ST: + case CV_LeafKind_ST_MAX: + case CV_LeafKind_TYPESERVER: + case CV_LeafKind_ENUMERATE: + //case CV_LeafKind_ARRAY: + //case CV_LeafKind_CLASS: + //case CV_LeafKind_STRUCTURE: + //case CV_LeafKind_UNION: + //case CV_LeafKind_ENUM: + case CV_LeafKind_DIMARRAY: + case CV_LeafKind_PRECOMP: + case CV_LeafKind_ALIAS: + case CV_LeafKind_DEFARG: + case CV_LeafKind_FRIENDFCN: + case CV_LeafKind_MEMBER: + case CV_LeafKind_STMEMBER: + case CV_LeafKind_METHOD: + case CV_LeafKind_NESTTYPE: + case CV_LeafKind_ONEMETHOD: + case CV_LeafKind_NESTTYPEEX: + case CV_LeafKind_MEMBERMODIFY: + case CV_LeafKind_MANAGED: + case CV_LeafKind_TYPESERVER2: + case CV_LeafKind_STRIDED_ARRAY: + case CV_LeafKind_HLSL: + case CV_LeafKind_MODIFIER_EX: + case CV_LeafKind_INTERFACE: + case CV_LeafKind_BINTERFACE: + case CV_LeafKind_VECTOR: + case CV_LeafKind_MATRIX: + //case CV_LeafKind_VFTABLE: + default: + { + String8 kind_str = cv_string_from_leaf_kind(range->hdr.kind); + cons_errorf(ctx->root, "pdbconv: unhandled leaf case %.*s (0x%x)", + str8_varg(kind_str), range->hdr.kind); + }break; + } + } + + cons_type_fill_id(ctx->root, res, result); + + ProfEnd(); + return(result); +} + +static CONS_Type* +pdbconv_type_resolve_and_check(PDBCONV_Ctx *ctx, CV_TypeId itype){ + CONS_Type *result = pdbconv_type_resolve_itype(ctx, itype); + if (cons_type_is_unhandled_nil(ctx->root, result)){ + cons_errorf(ctx->root, "pdbconv: could not resolve itype (itype = %u)", itype); + } + return(result); +} + +static void +pdbconv_type_resolve_arglist(Arena *arena, CONS_TypeList *out, + PDBCONV_Ctx *ctx, CV_TypeId arglist_itype){ + ProfBeginFunction(); + + // get leaf range + if (ctx->leaf->itype_first <= arglist_itype && arglist_itype < ctx->leaf->itype_opl){ + CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[arglist_itype - ctx->leaf->itype_first]; + + // check valid arglist + String8 data = ctx->leaf->data; + if (range->hdr.kind == CV_LeafKind_ARGLIST && + range->off + range->hdr.size <= data.size){ + U8 *first = data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + if (sizeof(CV_LeafArgList) <= cap){ + + // resolve parameters + CV_LeafArgList *arglist = (CV_LeafArgList*)first; + CV_TypeId *itypes = (CV_TypeId*)(arglist + 1); + U32 max_count = (cap - sizeof(*arglist))/sizeof(CV_TypeId); + U32 clamped_count = ClampTop(arglist->count, max_count); + for (U32 i = 0; i < clamped_count; i += 1){ + CONS_Type *param_type = pdbconv_type_resolve_and_check(ctx, itypes[i]); + cons_type_list_push(arena, out, param_type); + } + + } + } + } + + ProfEnd(); +} + +static CONS_Type* +pdbconv_type_from_name(PDBCONV_Ctx *ctx, String8 name){ + // TODO(rjf): no idea if this is correct + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); + CONS_Type *result = cons_type_from_id(ctx->root, cv_type_id); + return(result); +} + +static void +pdbconv_type_fwd_map_set(Arena *arena, PDBCONV_FwdMap *map, CV_TypeId key, CV_TypeId val){ + U64 bucket_idx = key%ArrayCount(map->buckets); + + // search for an existing match + PDBCONV_FwdNode *match = 0; + for (PDBCONV_FwdNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->key == key){ + match = node; + break; + } + } + + // create a new node if no match + if (match == 0){ + match = push_array(arena, PDBCONV_FwdNode, 1); + SLLStackPush(map->buckets[bucket_idx], match); + match->key = key; + } + + // set node's val + match->val = val; +} + +static CV_TypeId +pdbconv_type_fwd_map_get(PDBCONV_FwdMap *map, CV_TypeId key){ + ProfBeginFunction(); + U64 bucket_idx = key%ArrayCount(map->buckets); + + // search for an existing match + PDBCONV_FwdNode *match = 0; + for (PDBCONV_FwdNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->key == key){ + match = node; + break; + } + } + + // extract result + CV_TypeId result = 0; + if (match != 0){ + result = match->val; + } + + ProfEnd(); + return(result); +} + +//- symbols + +static void +pdbconv_symbol_cons(PDBCONV_Ctx *ctx, CV_SymParsed *sym, U32 sym_unique_id){ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + + // extract important values from parameters + String8 data = sym->data; + U64 user_id_base = (((U64)sym_unique_id) << 32); + + // PASS 1: map out data associations + ProfScope("map out data associations") + { + // state variables + CONS_Symbol *current_proc = 0; + + // loop + CV_RecRange *rec_range = sym->sym_ranges.ranges; + CV_RecRange *opl = rec_range + sym->sym_ranges.count; + for (;rec_range < opl; rec_range += 1){ + // symbol data range + U64 opl_off_raw = rec_range->off + rec_range->hdr.size; + U64 opl_off = ClampTop(opl_off_raw, data.size); + + U64 off_raw = rec_range->off + 2; + U64 off = ClampTop(off_raw, opl_off); + + U8 *first = data.str + off; + U64 cap = (opl_off - off); + + CV_SymKind kind = rec_range->hdr.kind; + switch (kind){ + default: break; + + case CV_SymKind_FRAMEPROC: + { + if (sizeof(CV_SymFrameproc) > cap){ + // TODO(allen): error + } + else{ + CV_SymFrameproc *frameproc = (CV_SymFrameproc*)first; + if (current_proc == 0){ + // TODO(allen): error + } + else{ + PDBCONV_FrameProcData data = {0}; + data.frame_size = frameproc->frame_size; + data.flags = frameproc->flags; + pdbconv_symbol_frame_proc_write(ctx, current_proc, &data); + } + } + }break; + + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + U64 user_id = user_id_base + off; + current_proc = cons_symbol_handle_from_user_id(ctx->root, user_id); + }break; + } + } + } + + // PASS 2: main symbol construction pass + ProfScope("main symbol construction pass") + { + // state variables + CONS_LocationSet *defrange_target = 0; + B32 defrange_target_is_param = 0; + + // loop + CV_RecRange *rec_range = sym->sym_ranges.ranges; + CV_RecRange *opl = rec_range + sym->sym_ranges.count; + for (;rec_range < opl; rec_range += 1){ + // symbol data range + U64 opl_off_raw = rec_range->off + rec_range->hdr.size; + U64 opl_off = ClampTop(opl_off_raw, data.size); + + U64 off_raw = rec_range->off + 2; + U64 off = ClampTop(off_raw, opl_off); + + U8 *first = data.str + off; + U64 cap = (opl_off - off); + + // current state + CONS_Scope *current_scope = pdbconv_symbol_current_scope(ctx); + CONS_Symbol *current_procedure = 0; + if (current_scope != 0){ + current_procedure = current_scope->symbol; + } + + CV_SymKind kind = rec_range->hdr.kind; + switch (kind){ + default:break; + + case CV_SymKind_END: + { + // pop scope stack + pdbconv_symbol_pop_scope(ctx); + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + case CV_SymKind_FRAMEPROC: + { + if (sizeof(CV_SymFrameproc) > cap){ + // TODO(allen): error + } + else{ + // do nothing (handled in 'association map' pass) + } + }break; + + case CV_SymKind_BLOCK32: + { + if (sizeof(CV_SymBlock32) > cap){ + // TODO(allen): error + } + else{ + CV_SymBlock32 *block32 = (CV_SymBlock32*)first; + + // scope + U64 user_id = user_id_base + off; + CONS_Scope *block_scope = cons_scope_handle_from_user_id(ctx->root, user_id); + cons_scope_set_parent(ctx->root, block_scope, current_scope); + pdbconv_symbol_push_scope(ctx, block_scope, current_procedure); + + // set voff range + COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, block32->sec); + if (section != 0){ + U64 voff_first = section->voff + block32->off; + U64 voff_last = voff_first + block32->len; + cons_scope_add_voff_range(ctx->root, block_scope, voff_first, voff_last); + } + } + }break; + + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: + { + if (sizeof(CV_SymData32) > cap){ + // TODO(allen): error + } + else{ + CV_SymData32 *data32 = (CV_SymData32*)first; + + // name + String8 name = str8_cstring_capped((char*)(data32 + 1), first + cap); + + // determine voff + COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, data32->sec); + U64 voff = ((section != 0)?section->voff:0) + data32->off; + + // deduplicate global variable symbols with the same name & offset + // * PDB likes to have duplicates of these spread across + // * different symbol streams so we deduplicate across the + // * entire translation context. + if (!pdbconv_known_global_lookup(&ctx->known_globals, name, voff)){ + pdbconv_known_global_insert(ctx->temp_arena, &ctx->known_globals, name, voff); + + // type of variable + CONS_Type *type = pdbconv_type_resolve_itype(ctx, data32->itype); + + // container type + CONS_Type *container_type = 0; + U64 container_name_opl = pdbconv_end_of_cplusplus_container_name(name); + if (container_name_opl > 2){ + String8 container_name = str8(name.str, container_name_opl - 2); + container_type = pdbconv_type_from_name(ctx, container_name); + } + + // container symbol + CONS_Symbol *container_symbol = 0; + if (container_type == 0){ + container_symbol = current_procedure; + } + + // determine link kind + B32 is_extern = (kind == CV_SymKind_GDATA32); + + // cons this symbol + U64 user_id = user_id_base + off; + CONS_Symbol *symbol = cons_symbol_handle_from_user_id(ctx->root, user_id); + + CONS_SymbolInfo info = zero_struct; + info.kind = CONS_SymbolKind_GlobalVariable; + info.name = name; + info.type = type; + info.is_extern = is_extern; + info.offset = voff; + info.container_type = container_type; + info.container_symbol = container_symbol; + + cons_symbol_set_info(ctx->root, symbol, &info); + } + } + }break; + + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + if (sizeof(CV_SymProc32) > cap){ + // TODO(allen): error + } + else{ + CV_SymProc32 *proc32 = (CV_SymProc32*)first; + + // name + String8 name = str8_cstring_capped((char*)(proc32 + 1), first + cap); + + // type of procedure + CONS_Type *type = pdbconv_type_resolve_itype(ctx, proc32->itype); + + // container type + CONS_Type *container_type = 0; + U64 container_name_opl = pdbconv_end_of_cplusplus_container_name(name); + if (container_name_opl > 2){ + String8 container_name = str8(name.str, container_name_opl - 2); + container_type = pdbconv_type_from_name(ctx, container_name); + } + + // container symbol + CONS_Symbol *container_symbol = 0; + if (container_type == 0){ + container_symbol = current_procedure; + } + + // get this symbol handle + U64 user_id = user_id_base + off; + CONS_Symbol *proc_symbol = cons_symbol_handle_from_user_id(ctx->root, user_id); + + // scope + + // NOTE: even if there could be a containing scope at this point (which should be + // illegal in C/C++ but not necessarily in another language) we would not pass + // it here because these scopes refer to the ranges of code that make up a + // procedure *not* the namespaces, so a procedure's root scope always has + // no parent. + CONS_Scope *root_scope = cons_scope_handle_from_user_id(ctx->root, user_id); + pdbconv_symbol_push_scope(ctx, root_scope, proc_symbol); + + // set voff range + U64 voff = 0; + COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, proc32->sec); + if (section != 0){ + U64 voff_first = section->voff + proc32->off; + U64 voff_last = voff_first + proc32->len; + cons_scope_add_voff_range(ctx->root, root_scope, voff_first, voff_last); + + voff = voff_first; + } + + // link name + String8 link_name = {0}; + if (voff != 0){ + link_name = pdbconv_link_name_find(&ctx->link_names, voff); + } + + // determine link kind + B32 is_extern = (kind == CV_SymKind_GPROC32); + + // set symbol info + CONS_SymbolInfo info = zero_struct; + info.kind = CONS_SymbolKind_Procedure; + info.name = name; + info.link_name = link_name; + info.type = type; + info.is_extern = is_extern; + info.container_type = container_type; + info.container_symbol = container_symbol; + info.root_scope = root_scope; + + cons_symbol_set_info(ctx->root, proc_symbol, &info); + } + }break; + + case CV_SymKind_REGREL32: + { + if (sizeof(CV_SymRegrel32) > cap){ + // TODO(allen): error + } + else{ + // TODO(allen): hide this when it's redundant with better information + // from a CV_SymKind_LOCAL record. + + CV_SymRegrel32 *regrel32 = (CV_SymRegrel32*)first; + + // name + String8 name = str8_cstring_capped((char*)(regrel32 + 1), first + cap); + + // type of variable + CONS_Type *type = pdbconv_type_resolve_itype(ctx, regrel32->itype); + + // extract regrel's info + CV_Reg cv_reg = regrel32->reg; + U32 var_off = regrel32->reg_off; + + // need arch for analyzing register stuff + RADDBG_Arch arch = ctx->arch; + U64 addr_size = ctx->addr_size; + + // determine if this is a parameter + RADDBG_LocalKind local_kind = RADDBG_LocalKind_Variable; + { + B32 is_stack_reg = 0; + switch (arch){ + case RADDBG_Arch_X86: is_stack_reg = (cv_reg == CV_Regx86_ESP); break; + case RADDBG_Arch_X64: is_stack_reg = (cv_reg == CV_Regx64_RSP); break; + } + if (is_stack_reg){ + U32 frame_size = 0xFFFFFFFF; + if (current_procedure != 0){ + PDBCONV_FrameProcData *frameproc = + pdbconv_symbol_frame_proc_read(ctx, current_procedure); + frame_size = frameproc->frame_size; + } + if (var_off > frame_size){ + local_kind = RADDBG_LocalKind_Parameter; + } + } + } + + // emit local + U64 user_id = user_id_base + off; + CONS_Local *local_var = cons_local_handle_from_user_id(ctx->root, user_id); + + CONS_LocalInfo info = {0}; + info.kind = local_kind; + info.scope = current_scope; + info.name = name; + info.type = type; + + cons_local_set_basic_info(ctx->root, local_var, &info); + + // add location to local + { + // will there be an extra indirection to the value + B32 extra_indirection_to_value = 0; + switch (arch){ + case RADDBG_Arch_X86: + { + if (local_kind == RADDBG_LocalKind_Parameter && + (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))){ + extra_indirection_to_value = 1; + } + }break; + + case RADDBG_Arch_X64: + { + if (local_kind == RADDBG_LocalKind_Parameter && + (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))){ + extra_indirection_to_value = 1; + } + }break; + } + + // get raddbg register code + RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); + // TODO(allen): real byte_size & byte_pos from cv_reg goes here + U32 byte_size = 8; + U32 byte_pos = 0; + + // set location case + CONS_Location *loc = + pdbconv_location_from_addr_reg_off(ctx, register_code, byte_size, byte_pos, + var_off, extra_indirection_to_value); + + CONS_LocationSet *locset = cons_location_set_from_local(ctx->root, local_var); + cons_location_set_add_case(ctx->root, locset, 0, max_U64, loc); + } + } + }break; + + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: + { + if (sizeof(CV_SymThread32) > cap){ + // TODO(allen): error + } + else{ + CV_SymThread32 *thread32 = (CV_SymThread32*)first; + + // name + String8 name = str8_cstring_capped((char*)(thread32 + 1), first + cap); + + // determine tls off + U32 tls_off = thread32->tls_off; + + // type of variable + CONS_Type *type = pdbconv_type_resolve_itype(ctx, thread32->itype); + + // container type + CONS_Type *container_type = 0; + U64 container_name_opl = pdbconv_end_of_cplusplus_container_name(name); + if (container_name_opl > 2){ + String8 container_name = str8(name.str, container_name_opl - 2); + container_type = pdbconv_type_from_name(ctx, container_name); + } + + // container symbol + CONS_Symbol *container_symbol = 0; + if (container_type == 0){ + container_symbol = current_procedure; + } + + // determine link kind + B32 is_extern = (kind == CV_SymKind_GTHREAD32); + + // setup symbol + U64 user_id = user_id_base + off; + CONS_Symbol *symbol = cons_symbol_handle_from_user_id(ctx->root, user_id); + + CONS_SymbolInfo info = zero_struct; + info.kind = CONS_SymbolKind_ThreadVariable; + info.name = name; + info.type = type; + info.is_extern = is_extern; + info.offset = tls_off; + info.container_type = container_type; + info.container_symbol = container_symbol; + + cons_symbol_set_info(ctx->root, symbol, &info); + } + }break; + + case CV_SymKind_LOCAL: + { + if (sizeof(CV_SymLocal) > cap){ + // TODO(allen): error + } + else{ + CV_SymLocal *slocal = (CV_SymLocal*)first; + + // name + String8 name = str8_cstring_capped((char*)(slocal + 1), first + cap); + + // type of variable + CONS_Type *type = pdbconv_type_resolve_itype(ctx, slocal->itype); + + // determine how to handle + B32 begin_a_global_modification = 0; + if ((slocal->flags & CV_LocalFlag_Global) || + (slocal->flags & CV_LocalFlag_Static)){ + begin_a_global_modification = 1; + } + + // emit a global modification + if (begin_a_global_modification){ + // TODO(allen): add global modification symbols + defrange_target = 0; + defrange_target_is_param = 0; + } + + // emit a local variable + else{ + // local kind + RADDBG_LocalKind local_kind = RADDBG_LocalKind_Variable; + if (slocal->flags & CV_LocalFlag_Param){ + local_kind = RADDBG_LocalKind_Parameter; + } + + // emit local + U64 user_id = user_id_base + off; + CONS_Local *local_var = cons_local_handle_from_user_id(ctx->root, user_id); + + CONS_LocalInfo info = {0}; + info.kind = local_kind; + info.scope = current_scope; + info.name = name; + info.type = type; + + cons_local_set_basic_info(ctx->root, local_var, &info); + + defrange_target = cons_location_set_from_local(ctx->root, local_var); + defrange_target_is_param = (local_kind == RADDBG_LocalKind_Parameter); + } + } + }break; + + case CV_SymKind_DEFRANGE_REGISTER: + { + if (sizeof(CV_SymDefrangeRegister) > cap){ + // TODO(allen): error + } + else{ + if (defrange_target == 0){ + // TODO(allen): error + } + else{ + CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)first; + + // TODO(allen): offset & size from cv_reg code + RADDBG_Arch arch = ctx->arch; + CV_Reg cv_reg = defrange_register->reg; + RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); + + // setup location + CONS_Location *location = cons_location_val_reg(ctx->root, register_code); + + // extract range info + CV_LvarAddrRange *range = &defrange_register->range; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register + 1); + U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); + + // emit locations + pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, + range, gaps, gap_count); + } + } + }break; + + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: + { + if (sizeof(CV_SymDefrangeFramepointerRel) > cap){ + // TODO(allen): error + } + else{ + if (defrange_target == 0){ + // TODO(allen): error + } + else{ + CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)first; + + // select frame pointer register + CV_EncodedFramePtrReg encoded_fp_reg = + pdbconv_cv_encoded_fp_reg_from_proc(ctx, current_procedure, defrange_target_is_param); + RADDBG_RegisterCode fp_register_code = + pdbconv_reg_code_from_arch_encoded_fp_reg(ctx->arch, encoded_fp_reg); + + // setup location + B32 extra_indirection = 0; + U32 byte_size = ctx->addr_size; + U32 byte_pos = 0; + U64 var_off = defrange_fprel->off; + CONS_Location *location = + pdbconv_location_from_addr_reg_off(ctx, fp_register_code, byte_size, byte_pos, + var_off, extra_indirection); + + + // extract range info + CV_LvarAddrRange *range = &defrange_fprel->range; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); + U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); + + // emit locations + pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, + range, gaps, gap_count); + } + } + }break; + + case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: + { + if (sizeof(CV_SymDefrangeSubfieldRegister) > cap){ + // TODO(allen): error + } + else{ + if (defrange_target == 0){ + // TODO(allen): error + } + else{ + CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)first; + + // TODO(allen): full "subfield" location system + if (defrange_subfield_register->field_offset == 0){ + + // TODO(allen): offset & size from cv_reg code + RADDBG_Arch arch = ctx->arch; + CV_Reg cv_reg = defrange_subfield_register->reg; + RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); + + // setup location + CONS_Location *location = cons_location_val_reg(ctx->root, register_code); + + // extract range info + CV_LvarAddrRange *range = &defrange_subfield_register->range; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); + U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); + + // emit locations + pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, + range, gaps, gap_count); + } + } + } + }break; + + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + { + if (sizeof(CV_SymDefrangeFramepointerRelFullScope) > cap){ + // TODO(allen): error + } + else{ + if (defrange_target == 0){ + // TODO(allen): error + } + else{ + CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = + (CV_SymDefrangeFramepointerRelFullScope*)first; + + // select frame pointer register + CV_EncodedFramePtrReg encoded_fp_reg = + pdbconv_cv_encoded_fp_reg_from_proc(ctx, current_procedure, defrange_target_is_param); + RADDBG_RegisterCode fp_register_code = + pdbconv_reg_code_from_arch_encoded_fp_reg(ctx->arch, encoded_fp_reg); + + // setup location + B32 extra_indirection = 0; + U32 byte_size = ctx->addr_size; + U32 byte_pos = 0; + U64 var_off = defrange_fprel_full_scope->off; + CONS_Location *location = + pdbconv_location_from_addr_reg_off(ctx, fp_register_code, byte_size, byte_pos, + var_off, extra_indirection); + + + // emit location + cons_location_set_add_case(ctx->root, defrange_target, 0, max_U64, location); + } + } + }break; + + case CV_SymKind_DEFRANGE_REGISTER_REL: + { + if (sizeof(CV_SymDefrangeRegisterRel) > cap){ + // TODO(allen): error + } + else{ + CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)first; + if(defrange_target == 0) + { + // TODO(rjf): error + } + else + { + // TODO(allen): offset & size from cv_reg code + RADDBG_Arch arch = ctx->arch; + CV_Reg cv_reg = defrange_register_rel->reg; + RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); + U32 byte_size = ctx->addr_size; + U32 byte_pos = 0; + + B32 extra_indirection_to_value = 0; + U64 var_off = defrange_register_rel->reg_off; + + // setup location + CONS_Location *location = + pdbconv_location_from_addr_reg_off(ctx, register_code, byte_size, byte_pos, + var_off, extra_indirection_to_value); + + // extract range info + CV_LvarAddrRange *range = &defrange_register_rel->range; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); + U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); + + + // emit locations + pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, + range, gaps, gap_count); + } + } + }break; + + case CV_SymKind_FILESTATIC: + { + if (sizeof(CV_SymFileStatic) > cap){ + // TODO(allen): error + } + else{ + CV_SymFileStatic *file_static = (CV_SymFileStatic*)first; + + // name + String8 name = str8_cstring_capped((char*)(file_static + 1), first + cap); + + // type of variable + CONS_Type *type = pdbconv_type_resolve_itype(ctx, file_static->itype); + + // TODO(allen): emit a global modifier symbol + + // defrange records from this point attach to this location information + defrange_target = 0; + defrange_target_is_param = 0; + } + }break; + } + } + + // if scope stack isn't empty emit an error + { + CONS_Scope* scope = pdbconv_symbol_current_scope(ctx); + if (scope != 0){ + // TODO(allen): emit error + } + } + + // clear the scope stack + pdbconv_symbol_clear_scope_stack(ctx); + } + + scratch_end(scratch); + ProfEnd(); +} + +static void +pdbconv_gather_link_names(PDBCONV_Ctx *ctx, CV_SymParsed *sym){ + ProfBeginFunction(); + // extract important values from parameters + String8 data = sym->data; + + // loop + CV_RecRange *rec_range = sym->sym_ranges.ranges; + CV_RecRange *opl = rec_range + sym->sym_ranges.count; + for (;rec_range < opl; rec_range += 1){ + // symbol data range + U64 opl_off_raw = rec_range->off + rec_range->hdr.size; + U64 opl_off = ClampTop(opl_off_raw, data.size); + + U64 off_raw = rec_range->off + 2; + U64 off = ClampTop(off_raw, opl_off); + + U8 *first = data.str + off; + U64 cap = (opl_off - off); + + CV_SymKind kind = rec_range->hdr.kind; + switch (kind){ + default: break; + + case CV_SymKind_PUB32: + { + if (sizeof(CV_SymPub32) > cap){ + // TODO(allen): error + } + else{ + CV_SymPub32 *pub32 = (CV_SymPub32*)first; + + // name + String8 name = str8_cstring_capped((char*)(pub32 + 1), first + cap); + + // calculate voff + U64 voff = 0; + COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, pub32->sec); + if (section != 0){ + voff = section->voff + pub32->off; + } + + // save link name + pdbconv_link_name_save(ctx->temp_arena, &ctx->link_names, voff, name); + } + }break; + } + } + ProfEnd(); +} + +// "frameproc" map + +static void +pdbconv_symbol_frame_proc_write(PDBCONV_Ctx *ctx,CONS_Symbol *key,PDBCONV_FrameProcData *data){ + U64 key_int = IntFromPtr(key); + PDBCONV_FrameProcMap *map = &ctx->frame_proc_map; + U32 bucket_idx = key_int%ArrayCount(map->buckets); + + // find match + PDBCONV_FrameProcNode *match = 0; + for (PDBCONV_FrameProcNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->key == key){ + match = node; + break; + } + } + + // if there is already a match emit error + if (match != 0){ + // TODO(allen): error + } + + // insert new association if no match + if (match == 0){ + match = push_array(ctx->temp_arena, PDBCONV_FrameProcNode, 1); + SLLStackPush(map->buckets[bucket_idx], match); + match->key = key; + MemoryCopyStruct(&match->data, data); + } +} + +static PDBCONV_FrameProcData* +pdbconv_symbol_frame_proc_read(PDBCONV_Ctx *ctx, CONS_Symbol *key){ + U64 key_int = IntFromPtr(key); + PDBCONV_FrameProcMap *map = &ctx->frame_proc_map; + U32 bucket_idx = key_int%ArrayCount(map->buckets); + + // find match + PDBCONV_FrameProcData *result = 0; + for (PDBCONV_FrameProcNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->key == key){ + result = &node->data; + break; + } + } + + return(result); +} + +// scope stack +static void +pdbconv_symbol_push_scope(PDBCONV_Ctx *ctx, CONS_Scope *scope, CONS_Symbol *symbol){ + PDBCONV_ScopeNode *node = ctx->scope_node_free; + if (node == 0){ + node = push_array(ctx->temp_arena, PDBCONV_ScopeNode, 1); + } + else{ + SLLStackPop(ctx->scope_node_free); + } + SLLStackPush(ctx->scope_stack, node); + node->scope = scope; + node->symbol = symbol; +} + +static void +pdbconv_symbol_pop_scope(PDBCONV_Ctx *ctx){ + PDBCONV_ScopeNode *node = ctx->scope_stack; + if (node != 0){ + SLLStackPop(ctx->scope_stack); + SLLStackPush(ctx->scope_node_free, node); + } +} + +static void +pdbconv_symbol_clear_scope_stack(PDBCONV_Ctx *ctx){ + for (;;){ + PDBCONV_ScopeNode *node = ctx->scope_stack; + if (node == 0){ + break; + } + SLLStackPop(ctx->scope_stack); + SLLStackPush(ctx->scope_node_free, node); + } +} + +// PDB/C++ name parsing helper + +static U64 +pdbconv_end_of_cplusplus_container_name(String8 str){ + // NOTE: This finds the index one past the last "::" contained in str. + // if no "::" is contained in str, then the returned index is 0. + // The intent is that [0,clamp_bot(0,result - 2)) gives the + // "container name" and [result,str.size) gives the leaf name. + U64 result = 0; + if (str.size >= 2){ + for (U64 i = str.size; i >= 2; i -= 1){ + if (str.str[i - 2] == ':' && str.str[i - 1] == ':'){ + result = i; + break; + } + } + } + return(result); +} + +// known global set + +static U64 +pdbconv_known_global_hash(String8 name, U64 voff){ + U64 result = 5381 ^ voff; + U8 *ptr = name.str; + U8 *opl = ptr + name.size; + for (; ptr < opl; ptr += 1){ + result = ((result << 5) + result) + *ptr; + } + return(result); +} + +static B32 +pdbconv_known_global_lookup(PDBCONV_KnownGlobalSet *set, String8 name, U64 voff){ + U64 hash = pdbconv_known_global_hash(name, voff); + U64 bucket_idx = hash%ArrayCount(set->buckets); + + PDBCONV_KnownGlobalNode *match = 0; + for (PDBCONV_KnownGlobalNode *node = set->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->hash == hash && + node->key_voff == voff && + str8_match(node->key_name, name, 0)){ + match = node; + break; + } + } + + B32 result = (match != 0); + return(result); +} + +static void +pdbconv_known_global_insert(Arena *arena, PDBCONV_KnownGlobalSet *set, String8 name, U64 voff){ + U64 hash = pdbconv_known_global_hash(name, voff); + U64 bucket_idx = hash%ArrayCount(set->buckets); + + PDBCONV_KnownGlobalNode *match = 0; + for (PDBCONV_KnownGlobalNode *node = set->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->hash == hash && + node->key_voff == voff && + str8_match(node->key_name, name, 0)){ + match = node; + break; + } + } + + if (match == 0){ + PDBCONV_KnownGlobalNode *node = push_array(arena, PDBCONV_KnownGlobalNode, 1); + SLLStackPush(set->buckets[bucket_idx], node); + node->key_name = push_str8_copy(arena, name); + node->key_voff = voff; + node->hash = hash; + } +} + +// location info helpers + +static CONS_Location* +pdbconv_location_from_addr_reg_off(PDBCONV_Ctx *ctx, + RADDBG_RegisterCode reg_code, + U32 reg_byte_pos, + U32 reg_byte_size, + U64 offset, + B32 extra_indirection){ + CONS_Location *result = 0; + if (offset <= max_U16){ + if (extra_indirection){ + result = cons_location_addr_addr_reg_plus_u16(ctx->root, reg_code, offset); + } + else{ + result = cons_location_addr_reg_plus_u16(ctx->root, reg_code, offset); + } + } + else{ + Arena *arena = ctx->temp_arena; + + CONS_EvalBytecode bytecode = {0}; + U32 regread_param = RADDBG_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); + cons_bytecode_push_op(arena, &bytecode, RADDBG_EvalOp_RegRead, regread_param); + cons_bytecode_push_uconst(arena, &bytecode, offset); + cons_bytecode_push_op(arena, &bytecode, RADDBG_EvalOp_Add, 0); + if (extra_indirection){ + cons_bytecode_push_op(arena, &bytecode, RADDBG_EvalOp_MemRead, ctx->addr_size); + } + + result = cons_location_addr_bytecode_stream(ctx->root, &bytecode); + } + + return(result); +} + +static CV_EncodedFramePtrReg +pdbconv_cv_encoded_fp_reg_from_proc(PDBCONV_Ctx *ctx, CONS_Symbol *proc, B32 param_base){ + CV_EncodedFramePtrReg result = 0; + if (proc != 0){ + PDBCONV_FrameProcData *frame_proc = pdbconv_symbol_frame_proc_read(ctx, proc); + CV_FrameprocFlags flags = frame_proc->flags; + if (param_base){ + result = CV_FrameprocFlags_ExtractParamBasePointer(flags); + } + else{ + result = CV_FrameprocFlags_ExtractLocalBasePointer(flags); + } + } + return(result); +} + +static RADDBG_RegisterCode +pdbconv_reg_code_from_arch_encoded_fp_reg(RADDBG_Arch arch, CV_EncodedFramePtrReg encoded_reg){ + RADDBG_RegisterCode result = 0; + + switch (arch){ + case RADDBG_Arch_X86: + { + switch (encoded_reg){ + case CV_EncodedFramePtrReg_StackPtr: + { + // TODO(allen): support CV_AllReg_VFRAME + // TODO(allen): error + }break; + case CV_EncodedFramePtrReg_FramePtr: + { + result = RADDBG_RegisterCode_X86_ebp; + }break; + case CV_EncodedFramePtrReg_BasePtr: + { + result = RADDBG_RegisterCode_X86_ebx; + }break; + } + }break; + + case RADDBG_Arch_X64: + { + switch (encoded_reg){ + case CV_EncodedFramePtrReg_StackPtr: + { + result = RADDBG_RegisterCode_X64_rsp; + }break; + case CV_EncodedFramePtrReg_FramePtr: + { + result = RADDBG_RegisterCode_X64_rbp; + }break; + case CV_EncodedFramePtrReg_BasePtr: + { + result = RADDBG_RegisterCode_X64_r13; + }break; + } + }break; + } + + return(result); +} + +static void +pdbconv_location_over_lvar_addr_range(PDBCONV_Ctx *ctx, + CONS_LocationSet *locset, + CONS_Location *location, + CV_LvarAddrRange *range, + CV_LvarAddrGap *gaps, U64 gap_count){ + // extract range info + U64 voff_first = 0; + U64 voff_opl = 0; + { + COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, range->sec); + if (section != 0){ + voff_first = section->voff + range->off; + voff_opl = voff_first + range->len; + } + } + + // emit ranges + CV_LvarAddrGap *gap_ptr = gaps; + U64 voff_cursor = voff_first; + for (U64 i = 0; i < gap_count; i += 1, gap_ptr += 1){ + U64 voff_gap_first = voff_first + gap_ptr->off; + U64 voff_gap_opl = voff_gap_first + gap_ptr->len; + if (voff_cursor < voff_gap_first){ + cons_location_set_add_case(ctx->root, locset, voff_cursor, voff_gap_first, location); + } + voff_cursor = voff_gap_opl; + } + + if (voff_cursor < voff_opl){ + cons_location_set_add_case(ctx->root, locset, voff_cursor, voff_opl, location); + } +} + +// link names + +static void +pdbconv_link_name_save(Arena *arena, PDBCONV_LinkNameMap *map, U64 voff, String8 name){ + U64 hash = (voff >> 3) ^ ((7 & voff) << 6); + U64 bucket_idx = hash%ArrayCount(map->buckets); + + PDBCONV_LinkNameNode *node = push_array(arena, PDBCONV_LinkNameNode, 1); + SLLStackPush(map->buckets[bucket_idx], node); + node->voff = voff; + node->name = push_str8_copy(arena, name); +} + +static String8 +pdbconv_link_name_find(PDBCONV_LinkNameMap *map, U64 voff){ + U64 hash = (voff >> 3) ^ ((7 & voff) << 6); + U64 bucket_idx = hash%ArrayCount(map->buckets); + + String8 result = {0}; + for (PDBCONV_LinkNameNode *node = map->buckets[bucket_idx]; + node != 0; + node = node->next){ + if (node->voff == voff){ + result = node->name; + break; + } + } + + return(result); +} + +//////////////////////////////// +//~ Conversion Path + +static PDBCONV_Out * +pdbconv_convert(Arena *arena, PDBCONV_Params *params) +{ + PDBCONV_Out *out = push_array(arena, PDBCONV_Out, 1); + out->good_parse = 1; + + // will we try to parse an input file? + B32 try_parse_input = (params->errors.node_count == 0); + +#define PARSE_CHECK_ERROR(p,fmt,...) do{ if ((p) == 0){\ +out->good_parse = 0;\ +str8_list_pushf(arena, &out->errors, fmt, __VA_ARGS__);\ +} }while(0) + + // parse msf file + MSF_Parsed *msf = 0; + if (try_parse_input) ProfScope("parse msf"){ + msf = msf_parsed_from_data(arena, params->input_pdb_data); + PARSE_CHECK_ERROR(msf, "MSF"); + } + + // parse pdb info + PDB_NamedStreamTable *named_streams = 0; + COFF_Guid auth_guid = {0}; + if (msf != 0) ProfScope("parse pdb info"){ + Temp scratch = scratch_begin(&arena, 1); + + String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_PdbInfo); + PDB_Info *info = pdb_info_from_data(scratch.arena, info_data); + named_streams = pdb_named_stream_table_from_info(arena, info); + MemoryCopyStruct(&auth_guid, &info->auth_guid); + + scratch_end(scratch); + + PARSE_CHECK_ERROR(named_streams, "named streams from pdb info"); + } + + // parse strtbl + PDB_Strtbl *strtbl = 0; + if (named_streams != 0) ProfScope("parse strtbl"){ + MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_STRTABLE]; + String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); + strtbl = pdb_strtbl_from_data(arena, strtbl_data); + + PARSE_CHECK_ERROR(strtbl, "string table"); + } + + // parse dbi + PDB_DbiParsed *dbi = 0; + if (msf != 0) ProfScope("parse dbi"){ + String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); + dbi = pdb_dbi_from_data(arena, dbi_data); + + PARSE_CHECK_ERROR(dbi, "DBI"); + } + + // parse tpi + PDB_TpiParsed *tpi = 0; + if (msf != 0) ProfScope("parse tpi"){ + String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); + tpi = pdb_tpi_from_data(arena, tpi_data); + + PARSE_CHECK_ERROR(tpi, "TPI"); + } + + // parse ipi + PDB_TpiParsed *ipi = 0; + if (msf != 0) ProfScope("parse ipi"){ + String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); + ipi = pdb_tpi_from_data(arena, ipi_data); + + PARSE_CHECK_ERROR(ipi, "IPI"); + } + + // parse coff sections + PDB_CoffSectionArray *coff_sections = 0; + U64 coff_section_count = 0; + if (dbi != 0) ProfScope("parse coff sections"){ + MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; + String8 section_data = msf_data_from_stream(msf, section_stream); + coff_sections = pdb_coff_section_array_from_data(arena, section_data); + coff_section_count = coff_sections->count; + + PARSE_CHECK_ERROR(coff_sections, "coff sections"); + } + + // parse gsi + PDB_GsiParsed *gsi = 0; + if (dbi != 0) ProfScope("parse gsi"){ + String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); + gsi = pdb_gsi_from_data(arena, gsi_data); + + PARSE_CHECK_ERROR(gsi, "GSI"); + } + + // parse psi + PDB_GsiParsed *psi_gsi_part = 0; + if (dbi != 0) ProfScope("parse psi"){ + String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); + String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), + psi_data.str + psi_data.size); + psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); + + PARSE_CHECK_ERROR(psi_gsi_part, "PSI"); + } + + // parse tpi hash + PDB_TpiHashParsed *tpi_hash = 0; + if (tpi != 0) ProfScope("parse tpi hash"){ + String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); + String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); + tpi_hash = pdb_tpi_hash_from_data(arena, tpi, hash_data, aux_data); + + PARSE_CHECK_ERROR(tpi_hash, "TPI hash table"); + } + + // parse tpi leaves + CV_LeafParsed *tpi_leaf = 0; + if (tpi != 0) ProfScope("parse tpi leaves"){ + String8 leaf_data = pdb_leaf_data_from_tpi(tpi); + tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); + + PARSE_CHECK_ERROR(tpi_hash, "TPI leaf data"); + } + + // parse ipi hash + PDB_TpiHashParsed *ipi_hash = 0; + if (ipi != 0) ProfScope("parse ipi hash"){ + String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); + String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); + ipi_hash = pdb_tpi_hash_from_data(arena, ipi, hash_data, aux_data); + + PARSE_CHECK_ERROR(tpi_hash, "IPI hash table"); + } + + // parse ipi leaves + CV_LeafParsed *ipi_leaf = 0; + if (ipi != 0) ProfScope("parse ipi leaves"){ + String8 leaf_data = pdb_leaf_data_from_tpi(ipi); + ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); + + PARSE_CHECK_ERROR(tpi_hash, "IPI leaf data"); + } + + // parse sym + CV_SymParsed *sym = 0; + if (dbi != 0) ProfScope("parse sym"){ + String8 sym_data = msf_data_from_stream(msf, dbi->sym_sn); + sym = cv_sym_from_data(arena, sym_data, 4); + + PARSE_CHECK_ERROR(tpi_hash, "public SYM data"); + } + + // parse compilation units + PDB_CompUnitArray *comp_units = 0; + U64 comp_unit_count = 0; + if (dbi != 0) ProfScope("parse compilation units"){ + String8 mod_info_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); + comp_units = pdb_comp_unit_array_from_data(arena, mod_info_data); + comp_unit_count = comp_units->count; + + PARSE_CHECK_ERROR(comp_units, "module info"); + } + + // parse dbi's section contributions + PDB_CompUnitContributionArray *comp_unit_contributions = 0; + U64 comp_unit_contribution_count = 0; + if (dbi != 0 && coff_sections != 0) ProfScope("parse dbi section contributions"){ + String8 section_contribution_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); + comp_unit_contributions = + pdb_comp_unit_contribution_array_from_data(arena, section_contribution_data, coff_sections); + comp_unit_contribution_count = comp_unit_contributions->count; + + PARSE_CHECK_ERROR(comp_unit_contributions, "module contributions"); + } + + // parse syms for each compilation unit + CV_SymParsed **sym_for_unit = push_array(arena, CV_SymParsed*, comp_unit_count); + if (comp_units != 0) ProfScope("parse symbols"){ + PDB_CompUnit **unit_ptr = comp_units->units; + for (U64 i = 0; i < comp_unit_count; i += 1, unit_ptr += 1){ + CV_SymParsed *unit_sym = 0; + { + String8 sym_data = pdb_data_from_unit_range(msf, *unit_ptr, PDB_DbiCompUnitRange_Symbols); + unit_sym = cv_sym_from_data(arena, sym_data, 4); + } + PARSE_CHECK_ERROR(unit_sym, "module (i=%llu) SYM data", i); + + sym_for_unit[i] = unit_sym; + } + } + + // parse c13 for each compilation unit + CV_C13Parsed **c13_for_unit = push_array(arena, CV_C13Parsed*, comp_unit_count); + if (comp_units != 0) ProfScope("parse c13s"){ + PDB_CompUnit **unit_ptr = comp_units->units; + for (U64 i = 0; i < comp_unit_count; i += 1, unit_ptr += 1){ + CV_C13Parsed *unit_c13 = 0; + { + String8 c13_data = pdb_data_from_unit_range(msf, *unit_ptr, PDB_DbiCompUnitRange_C13); + unit_c13 = cv_c13_from_data(arena, c13_data, strtbl, coff_sections); + } + PARSE_CHECK_ERROR(unit_c13, "module (i=%llu) C13 line info", i); + + c13_for_unit[i] = unit_c13; + } + } + + // parsing error + if (try_parse_input && !out->good_parse && + !params->hide_errors.parsing){ + str8_list_pushf(arena, &out->errors, "error(parsing): '%S' as a PDB\n", params->input_pdb_name); + } + + // exe hash + U64 exe_hash = 0; + if (out->good_parse && params->input_exe_data.size > 0) ProfScope("hash exe"){ + exe_hash = raddbg_hash(params->input_exe_data.str, params->input_exe_data.size); + } + + // dump + if (params->dump) ProfScope("dump"){ + String8List dump = {0}; + + // EXE + if (out->good_parse){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "EXE INFO:\n")); + { + str8_list_pushf(arena, &dump, "HASH: %016llX\n", exe_hash); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // MSF + if (params->dump_msf){ + if (msf != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "MSF:\n")); + + str8_list_pushf(arena, &dump, " block_size=%llu\n", msf->block_size); + str8_list_pushf(arena, &dump, " block_count=%llu\n", msf->block_count); + str8_list_pushf(arena, &dump, " stream_count=%llu\n", msf->stream_count); + + String8 *stream_ptr = msf->streams; + U64 stream_count = msf->stream_count; + for (U64 i = 0; i < stream_count; i += 1, stream_ptr += 1){ + str8_list_pushf(arena, &dump, " stream[%u].size=%llu\n", + i, stream_ptr->size); + } + + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + // DBI + if (params->dump_sym){ + if (sym != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "DBI SYM:\n")); + cv_stringize_sym_parsed(arena, &dump, sym); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + // TPI + if (params->dump_tpi_hash){ + if (tpi_hash != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "TPI HASH:\n")); + pdb_stringize_tpi_hash(arena, &dump, tpi_hash); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + if (ipi_hash != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "IPI HASH:\n")); + pdb_stringize_tpi_hash(arena, &dump, ipi_hash); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + // LEAF + if (params->dump_leaf){ + if (tpi_leaf != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "TPI LEAF:\n")); + cv_stringize_leaf_parsed(arena, &dump, tpi_leaf); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + if (ipi_leaf != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "IPI LEAF:\n")); + cv_stringize_leaf_parsed(arena, &dump, ipi_leaf); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + // BINARY SECTIONS + if (params->dump_coff_sections){ + if (coff_sections != 0){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "COFF SECTIONS:\n")); + COFF_SectionHeader *section_ptr = coff_sections->sections; + for (U64 i = 0; i < coff_section_count; i += 1, section_ptr += 1){ + // TODO(allen): probably should pull this out into a separate stringize path + // for the coff section type + char *first = (char*)section_ptr->name; + char *opl = first + sizeof(section_ptr->name); + String8 name = str8_cstring_capped(first, opl); + str8_list_pushf(arena, &dump, " %.*s:\n", str8_varg(name)); + str8_list_pushf(arena, &dump, " vsize=%u\n", section_ptr->vsize); + str8_list_pushf(arena, &dump, " voff =0x%x\n", section_ptr->voff); + str8_list_pushf(arena, &dump, " fsize=%u\n", section_ptr->fsize); + str8_list_pushf(arena, &dump, " foff =0x%x\n", section_ptr->foff); + str8_list_pushf(arena, &dump, " relocs_foff=0x%x\n", section_ptr->relocs_foff); + str8_list_pushf(arena, &dump, " lines_foff =0x%x\n", section_ptr->lines_foff); + str8_list_pushf(arena, &dump, " reloc_count=%u\n", section_ptr->reloc_count); + str8_list_pushf(arena, &dump, " line_count =%u\n", section_ptr->line_count); + // TODO(allen): better flags + str8_list_pushf(arena, &dump, " flags=%x\n", section_ptr->flags); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + } + + // UNITS + if (comp_units != 0){ + B32 dump_sym = params->dump_sym; + B32 dump_c13 = params->dump_c13; + + B32 dump_units = (dump_sym || dump_c13); + + if (dump_units){ + PDB_CompUnit **unit_ptr = comp_units->units; + for (U64 i = 0; i < comp_unit_count; i += 1, unit_ptr += 1){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n")); + String8 name = (*unit_ptr)->obj_name; + String8 group_name = (*unit_ptr)->group_name; + str8_list_pushf(arena, &dump, "[%llu] %.*s\n(%.*s):\n", + i, str8_varg(name), str8_varg(group_name)); + if (dump_sym){ + cv_stringize_sym_parsed(arena, &dump, sym_for_unit[i]); + } + if (dump_c13){ + cv_stringize_c13_parsed(arena, &dump, c13_for_unit[i]); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + } + + // UNIT CONTRIBUTIONS + if (comp_unit_contributions != 0){ + if (params->dump_contributions){ + str8_list_push(arena, &dump, + str8_lit("################################" + "################################\n" + "UNIT CONTRIBUTIONS:\n")); + PDB_CompUnitContribution *contrib_ptr = comp_unit_contributions->contributions; + for (U64 i = 0; i < comp_unit_contribution_count; i += 1, contrib_ptr += 1){ + str8_list_pushf(arena, &dump, + " { mod = %5u; voff_first = %08llx; voff_opl = %08llx; }\n", + contrib_ptr->mod, contrib_ptr->voff_first, contrib_ptr->voff_opl); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + + out->dump = dump; + } + + // output generation + if (params->output_name.size > 0){ + + // determine arch + RADDBG_Arch architecture = RADDBG_Arch_NULL; + // TODO(rjf): in some cases, the first compilation unit has a zero + // architecture, as it's sometimes used as a "nil" unit. this causes bugs + // in later stages of conversion - particularly, this was detected via + // busted location info. so i've converted this to a scan-until-we-find-an- + // architecture. however, this is still fundamentally insufficient, because + // Nick has informed me that x86 units can be linked with x64 units, + // meaning the appropriate architecture at any point in time is not a top- + // level concept, and is rather dependent on to which compilation unit + // particular symbols belong. so in the future, to support that (odd) case, + // we'll need to not only have this be a top-level "contextual" piece of + // info, but to use the appropriate compilation unit's architecture when + // possible. + // + for(U64 comp_unit_idx = 0; comp_unit_idx < comp_unit_count; comp_unit_idx += 1) + { + if(sym_for_unit[comp_unit_idx] != 0) + { + architecture = raddbg_arch_from_cv_arch(sym_for_unit[0]->info.arch); + if(architecture != 0) + { + break; + } + } + } + U64 addr_size = raddbg_addr_size_from_arch(architecture); + + + // predict symbol counts + U64 symbol_count_prediction = 0; + { + U64 rec_range_count = 0; + if (sym != 0){ + rec_range_count += sym->sym_ranges.count; + } + for (U64 i = 0; i < comp_unit_count; i += 1){ + CV_SymParsed *unit_sym = sym_for_unit[i]; + rec_range_count += unit_sym->sym_ranges.count; + } + symbol_count_prediction = rec_range_count/8; + if (symbol_count_prediction < 128){ + symbol_count_prediction = 128; + } + } + + + // setup root + CONS_RootParams root_params = {0}; + root_params.addr_size = addr_size; + + root_params.bucket_count_units = comp_unit_count; + root_params.bucket_count_symbols = symbol_count_prediction; + root_params.bucket_count_scopes = symbol_count_prediction; + root_params.bucket_count_locals = symbol_count_prediction; + root_params.bucket_count_types = tpi->itype_opl; + + CONS_Root *root = cons_root_new(&root_params); + out->root = root; + + // top level info + { + // calculate voff max + U64 voff_max = 0; + { + COFF_SectionHeader *coff_sec_ptr = coff_sections->sections; + COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_section_count; + for (;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1){ + U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; + voff_max = Max(voff_max, sec_voff_max); + } + } + + // set top level info + CONS_TopLevelInfo tli = {0}; + tli.architecture = architecture; + tli.exe_name = params->input_exe_name; + tli.exe_hash = exe_hash; + tli.voff_max = voff_max; + + cons_set_top_level_info(root, &tli); + } + + + // setup binary sections + { + COFF_SectionHeader *coff_ptr = coff_sections->sections; + COFF_SectionHeader *coff_opl = coff_ptr + coff_section_count; + for (;coff_ptr < coff_opl; coff_ptr += 1){ + char *name_first = (char*)coff_ptr->name; + char *name_opl = name_first + sizeof(coff_ptr->name); + String8 name = str8_cstring_capped(name_first, name_opl); + RADDBG_BinarySectionFlags flags = + raddbg_binary_section_flags_from_coff_section_flags(coff_ptr->flags); + cons_add_binary_section(root, name, flags, + coff_ptr->voff, coff_ptr->voff + coff_ptr->vsize, + coff_ptr->foff, coff_ptr->foff + coff_ptr->fsize); + } + } + + + // setup compilation units + { + PDB_CompUnit **units = comp_units->units; + for (U64 i = 0; i < comp_unit_count; i += 1){ + PDB_CompUnit *unit = units[i]; + CV_SymParsed *unit_sym = sym_for_unit[i]; + CV_C13Parsed *unit_c13 = c13_for_unit[i]; + + // resolve names + String8 raw_name = unit->obj_name; + + String8 unit_name = raw_name; + { + U64 first_after_slashes = 0; + for (S64 i = unit_name.size - 1; i >= 0; i -= 1){ + if (unit_name.str[i] == '/' || unit_name.str[i] == '\\'){ + first_after_slashes = i + 1; + break; + } + } + unit_name = str8_range(raw_name.str + first_after_slashes, + raw_name.str + raw_name.size); + } + + String8 obj_name = raw_name; + if (str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), + StringMatchFlag_RightSideSloppy)){ + MemoryZeroStruct(&obj_name); + } + + String8 compiler_name = unit_sym->info.compiler_name; + String8 archive_file = unit->group_name; + + // extract langauge + RADDBG_Language lang = raddbg_language_from_cv_language(sym->info.language); + + // basic per unit info + CONS_Unit *unit_handle = cons_unit_handle_from_user_id(root, i); + + CONS_UnitInfo info = {0}; + info.unit_name = unit_name; + info.compiler_name = compiler_name; + info.object_file = obj_name; + info.archive_file = archive_file; + info.language = lang; + + cons_unit_set_info(root, unit_handle, &info); + + // unit's line info + for (CV_C13SubSectionNode *node = unit_c13->first_sub_section; + node != 0; + node = node->next){ + if (node->kind == CV_C13_SubSectionKind_Lines){ + CV_C13LinesParsed *lines = node->lines; + if (lines != 0){ + CONS_LineSequence seq = {0}; + seq.file_name = lines->file_name; + seq.voffs = lines->voffs; + seq.line_nums = lines->line_nums; + seq.col_nums = lines->col_nums; + seq.line_count = lines->line_count; + cons_unit_add_line_sequence(root, unit_handle, &seq); + } + } + } + } + } + + + // unit vmap ranges + { + PDB_CompUnitContribution *contrib_ptr = comp_unit_contributions->contributions; + PDB_CompUnitContribution *contrib_opl = contrib_ptr + comp_unit_contribution_count; + for (;contrib_ptr < contrib_opl; contrib_ptr += 1){ + if (contrib_ptr->mod < root->unit_count){ + CONS_Unit *unit_handle = cons_unit_handle_from_user_id(root, contrib_ptr->mod); + cons_unit_vmap_add_range(root, unit_handle, + contrib_ptr->voff_first, + contrib_ptr->voff_opl); + } + } + } + + + // types & symbols + { + PDBCONV_TypesSymbolsParams pdb_params = {0}; + pdb_params.architecture = architecture; + pdb_params.sym = sym; + pdb_params.sym_for_unit = sym_for_unit; + pdb_params.unit_count = comp_unit_count; + pdb_params.tpi_hash = tpi_hash; + pdb_params.tpi_leaf = tpi_leaf; + pdb_params.sections = coff_sections; + + pdbconv_types_and_symbols(&pdb_params, root); + } + + + // conversion errors + if (!params->hide_errors.converting){ + for (CONS_Error *error = cons_get_first_error(root); + error != 0; + error = error->next){ + str8_list_push(arena, &out->errors, error->msg); + } + } + } + + return out; +} diff --git a/src/raddbg_convert/pdb/raddbg_from_pdb.h b/src/raddbg_convert/pdb/raddbg_from_pdb.h new file mode 100644 index 00000000..fbd39381 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_from_pdb.h @@ -0,0 +1,262 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_FROM_PDB_H +#define RADDBG_FROM_PDB_H + +//////////////////////////////// +//~ Program Parameters Type + +typedef struct PDBCONV_Params{ + String8 input_pdb_name; + String8 input_pdb_data; + + String8 input_exe_name; + String8 input_exe_data; + + String8 output_name; + + struct{ + B8 input; + B8 output; + B8 parsing; + B8 converting; + } hide_errors; + + B8 dump; + B8 dump__first; + B8 dump_coff_sections; + B8 dump_msf; + B8 dump_sym; + B8 dump_tpi_hash; + B8 dump_leaf; + B8 dump_c13; + B8 dump_contributions; + B8 dump__last; + + String8List errors; +} PDBCONV_Params; + +//////////////////////////////// +//~ Program Parameters Parser + +static PDBCONV_Params *pdb_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline); + +//////////////////////////////// +//~ PDB Type & Symbol Info Translation Helpers + +//- translation helper types +typedef struct PDBCONV_FwdNode{ + struct PDBCONV_FwdNode *next; + CV_TypeId key; + CV_TypeId val; +} PDBCONV_FwdNode; + +typedef struct PDBCONV_FwdMap{ + PDBCONV_FwdNode *buckets[1<<24]; +} PDBCONV_FwdMap; + +typedef struct PDBCONV_TypeRev{ + struct PDBCONV_TypeRev *next; + CONS_Type *owner_type; + CV_TypeId field_itype; +} PDBCONV_TypeRev; + +typedef struct PDBCONV_FrameProcData{ + U32 frame_size; + CV_FrameprocFlags flags; +} PDBCONV_FrameProcData; + +typedef struct PDBCONV_FrameProcNode{ + struct PDBCONV_FrameProcNode *next; + CONS_Symbol *key; + PDBCONV_FrameProcData data; +} PDBCONV_FrameProcNode; + +typedef struct PDBCONV_FrameProcMap{ + PDBCONV_FrameProcNode *buckets[1<<24]; +} PDBCONV_FrameProcMap; + +typedef struct PDBCONV_ScopeNode{ + struct PDBCONV_ScopeNode *next; + CONS_Scope *scope; + CONS_Symbol *symbol; +} PDBCONV_ScopeNode; + +typedef struct PDBCONV_KnownGlobalNode{ + struct PDBCONV_KnownGlobalNode *next; + String8 key_name; + U64 key_voff; + U64 hash; +} PDBCONV_KnownGlobalNode; + +typedef struct PDBCONV_KnownGlobalSet{ + PDBCONV_KnownGlobalNode *buckets[1<<24]; +} PDBCONV_KnownGlobalSet; + +typedef struct PDBCONV_TypesSymbolsParams{ + RADDBG_Arch architecture; + CV_SymParsed *sym; + CV_SymParsed **sym_for_unit; + U64 unit_count; + PDB_TpiHashParsed *tpi_hash; + CV_LeafParsed *tpi_leaf; + PDB_CoffSectionArray *sections; +} PDBCONV_TypesSymbolsParams; + +typedef struct PDBCONV_LinkNameNode{ + struct PDBCONV_LinkNameNode *next; + U64 voff; + String8 name; +} PDBCONV_LinkNameNode; + +typedef struct PDBCONV_LinkNameMap{ + PDBCONV_LinkNameNode *buckets[1<<24]; +} PDBCONV_LinkNameMap; + +typedef struct PDBCONV_Ctx{ + // INPUT data + RADDBG_Arch arch; + U64 addr_size; + PDB_TpiHashParsed *hash; + CV_LeafParsed *leaf; + COFF_SectionHeader *sections; + U64 section_count; + + // OUTPUT data + CONS_Root *root; + + // TEMPORARY STATE + Arena *temp_arena; + PDBCONV_FwdMap fwd_map; + PDBCONV_TypeRev *member_revisit_first; + PDBCONV_TypeRev *member_revisit_last; + PDBCONV_TypeRev *enum_revisit_first; + PDBCONV_TypeRev *enum_revisit_last; + PDBCONV_FrameProcMap frame_proc_map; + PDBCONV_ScopeNode *scope_stack; + PDBCONV_ScopeNode *scope_node_free; + PDBCONV_KnownGlobalSet known_globals; + PDBCONV_LinkNameMap link_names; +} PDBCONV_Ctx; + +//- pdb types and symbols +static void pdbconv_types_and_symbols(PDBCONV_TypesSymbolsParams *params, CONS_Root *out_root); + +//- decoding helpers +static U32 pdbconv_u32_from_numeric(PDBCONV_Ctx *ctx, CV_NumericParsed *num); +static COFF_SectionHeader* pdbconv_sec_header_from_sec_num(PDBCONV_Ctx *ctx, U32 sec_num); + +//- type info + +// TODO(allen): explain the overarching pattern of PDB type info translation here +// 1. main passes (out of order necessity) & after +// 2. resolve forward +// 3. cons type info +// 4. "resolve itype" +// 5. equipping members & enumerates +// 6. equipping source coordinates + +// type info construction passes +static void pdbconv_type_cons_main_passes(PDBCONV_Ctx *ctx); + +static CV_TypeId pdbconv_type_resolve_fwd(PDBCONV_Ctx *ctx, CV_TypeId itype); +static CONS_Type* pdbconv_type_resolve_itype(PDBCONV_Ctx *ctx, CV_TypeId itype); +static void pdbconv_type_equip_members(PDBCONV_Ctx *ctx, CONS_Type *owern_type, + CV_TypeId field_itype); +static void pdbconv_type_equip_enumerates(PDBCONV_Ctx *ctx, CONS_Type *owner_type, + CV_TypeId field_itype); + +// type info construction helpers +static CONS_Type* pdbconv_type_cons_basic(PDBCONV_Ctx *ctx, CV_TypeId itype); +static CONS_Type* pdbconv_type_cons_leaf_record(PDBCONV_Ctx *ctx, CV_TypeId itype); +static CONS_Type* pdbconv_type_resolve_and_check(PDBCONV_Ctx *ctx, CV_TypeId itype); +static void pdbconv_type_resolve_arglist(Arena *arena, CONS_TypeList *out, + PDBCONV_Ctx *ctx, CV_TypeId arglist_itype); + +// type info resolution helpers +static CONS_Type* pdbconv_type_from_name(PDBCONV_Ctx *ctx, String8 name); + +// type fwd map +static void pdbconv_type_fwd_map_set(Arena *arena, PDBCONV_FwdMap *map, + CV_TypeId key, CV_TypeId val); +static CV_TypeId pdbconv_type_fwd_map_get(PDBCONV_FwdMap *map, CV_TypeId key); + + +//- symbol info + +// symbol info construction +static void pdbconv_symbol_cons(PDBCONV_Ctx *ctx, CV_SymParsed *sym, U32 sym_unique_id); +static void pdbconv_gather_link_names(PDBCONV_Ctx *ctx, CV_SymParsed *sym); + +// "frameproc" map +static void pdbconv_symbol_frame_proc_write(PDBCONV_Ctx *ctx,CONS_Symbol *key, + PDBCONV_FrameProcData *data); +static PDBCONV_FrameProcData* pdbconv_symbol_frame_proc_read(PDBCONV_Ctx *ctx, CONS_Symbol *key); + +// scope stack +static void pdbconv_symbol_push_scope(PDBCONV_Ctx *ctx, CONS_Scope *scope, CONS_Symbol *symbol); +static void pdbconv_symbol_pop_scope(PDBCONV_Ctx *ctx); +static void pdbconv_symbol_clear_scope_stack(PDBCONV_Ctx *ctx); + +#define pdbconv_symbol_current_scope(ctx) \ +((ctx)->scope_stack == 0)?0:((ctx)->scope_stack->scope) + +#define pdbconv_symbol_current_symbol(ctx) \ +((ctx)->scope_stack == 0)?0:((ctx)->scope_stack->symbol) + +// PDB/C++ name parsing helper +static U64 pdbconv_end_of_cplusplus_container_name(String8 str); + +// global deduplication +static U64 pdbconv_known_global_hash(String8 name, U64 voff); + +static B32 pdbconv_known_global_lookup(PDBCONV_KnownGlobalSet *set, String8 name, U64 voff); +static void pdbconv_known_global_insert(Arena *arena, PDBCONV_KnownGlobalSet *set, + String8 name, U64 voff); + + +// location info helpers +static CONS_Location* pdbconv_location_from_addr_reg_off(PDBCONV_Ctx *ctx, + RADDBG_RegisterCode reg_code, + U32 reg_byte_pos, + U32 reg_byte_size, + U64 offset, + B32 extra_indirection); + +static CV_EncodedFramePtrReg pdbconv_cv_encoded_fp_reg_from_proc(PDBCONV_Ctx *ctx, + CONS_Symbol *proc, + B32 param_base); + +static RADDBG_RegisterCode pdbconv_reg_code_from_arch_encoded_fp_reg(RADDBG_Arch arch, + CV_EncodedFramePtrReg encoded_reg); + +static void pdbconv_location_over_lvar_addr_range(PDBCONV_Ctx *ctx, + CONS_LocationSet *locset, + CONS_Location *location, + CV_LvarAddrRange *range, + CV_LvarAddrGap *gaps, U64 gap_count); + +// link names +static void pdbconv_link_name_save(Arena *arena, PDBCONV_LinkNameMap *map, + U64 voff, String8 name); +static String8 pdbconv_link_name_find(PDBCONV_LinkNameMap *map, U64 voff); + +//////////////////////////////// +//~ Conversion Output Type + +typedef struct PDBCONV_Out PDBCONV_Out; +struct PDBCONV_Out +{ + B32 good_parse; + CONS_Root *root; + String8List dump; + String8List errors; +}; + +//////////////////////////////// +//~ Conversion Path + +static PDBCONV_Out *pdbconv_convert(Arena *arena, PDBCONV_Params *params); + +#endif //RADDBG_FROM_PDB_H diff --git a/src/raddbg_convert/pdb/raddbg_from_pdb_main.c b/src/raddbg_convert/pdb/raddbg_from_pdb_main.c new file mode 100644 index 00000000..2ce33e5c --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_from_pdb_main.c @@ -0,0 +1,116 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "coff/coff.h" +#include "raddbg_format/raddbg_format.h" +#include "raddbg_cons/raddbg_cons.h" + +#include "raddbg_coff.h" +#include "raddbg_codeview.h" +#include "raddbg_msf.h" +#include "raddbg_pdb.h" +#include "raddbg_coff_conversion.h" +#include "raddbg_codeview_conversion.h" + +#include "raddbg_codeview_stringize.h" +#include "raddbg_pdb_stringize.h" + +#include "raddbg_from_pdb.h" + +#include "base/base_inc.c" +#include "coff/coff.c" +#include "os/os_inc.c" +#include "raddbg_format/raddbg_format.c" +#include "raddbg_cons/raddbg_cons.c" + +#include "raddbg_msf.c" +#include "raddbg_codeview.c" +#include "raddbg_pdb.c" +#include "raddbg_coff_conversion.c" +#include "raddbg_codeview_conversion.c" + +#include "raddbg_codeview_stringize.c" +#include "raddbg_pdb_stringize.c" + +#include "raddbg_from_pdb.c" + +int +main(int argc, char **argv){ + local_persist TCTX main_thread_tctx = {0}; + tctx_init_and_equip(&main_thread_tctx); +#if PROFILE_TELEMETRY + U64 tm_data_size = GB(1); + U8 *tm_data = os_reserve(tm_data_size); + os_commit(tm_data, tm_data_size); + tmLoadLibrary(TM_RELEASE); + tmSetMaxThreadCount(1024); + tmInitialize(tm_data_size, tm_data); +#endif + + ThreadName("[main]"); + + Arena *arena = arena_alloc(); + String8List args = os_string_list_from_argcv(arena, argc, argv); + CmdLine cmdline = cmd_line_from_string_list(arena, args); + + ProfBeginCapture("raddbg_from_pdb"); + + //- rjf: parse arguments + PDBCONV_Params *params = pdb_convert_params_from_cmd_line(arena, &cmdline); + + //- rjf: show input errors + if (params->errors.node_count > 0 && + !params->hide_errors.input){ + for (String8Node *node = params->errors.first; + node != 0; + node = node->next){ + fprintf(stderr, "error(input): %.*s\n", str8_varg(node->string)); + } + } + + //- rjf: open output file + String8 output_name = push_str8_copy(arena, params->output_name); + FILE *out_file = fopen((char*)output_name.str, "wb"); + if(out_file == 0 && !params->hide_errors.output) + { + fprintf(stderr, "error(output): could not open output file\n"); + } + + //- rjf: convert + PDBCONV_Out *out = 0; + if(out_file != 0) + { + out = pdbconv_convert(arena, params); + } + + //- rjf: print dump + if(out != 0) + { + for(String8Node *node = out->dump.first; node != 0; node = node->next) + { + fwrite(node->string.str, 1, node->string.size, stdout); + } + } + + //- rjf: bake file + if(out != 0 && out->good_parse && params->output_name.size > 0 && out->good_parse) + { + String8List baked = {0}; + cons_bake_file(arena, out->root, &baked); + for(String8Node *node = baked.first; node != 0; node = node->next) + { + fwrite(node->string.str, node->string.size, 1, out_file); + } + } + + //- rjf: close output file + if(out_file != 0) + { + fclose(out_file); + } + + ProfEndCapture(); + return(0); +} diff --git a/src/raddbg_convert/pdb/raddbg_msf.c b/src/raddbg_convert/pdb/raddbg_msf.c new file mode 100644 index 00000000..39b01999 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_msf.c @@ -0,0 +1,284 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ MSF Parser Function + +static MSF_Parsed* +msf_parsed_from_data(Arena *arena, String8 msf_data){ + ProfBegin("msf_parsed_from_data"); + + Temp scratch = scratch_begin(&arena, 1); + + MSF_Parsed *result = 0; + + //- determine msf type + U32 index_size = 0; + if (msf_data.size >= MSF_MIN_SIZE){ + if (str8_match(msf_data, str8_lit(msf_msf20_magic), + StringMatchFlag_RightSideSloppy)){ + index_size = 2; + } + else if (str8_match(msf_data, str8_lit(msf_msf70_magic), + StringMatchFlag_RightSideSloppy)){ + index_size = 4; + } + } + + if (index_size == 2 || index_size == 4){ + + //- extract info from header + U32 block_size_raw = 0; + U32 whole_file_block_count_raw = 0; + U32 directory_size_raw = 0; + U32 directory_super_map_raw = 0; + if (index_size == 2){ + MSF_Header20 *header = (MSF_Header20*)(msf_data.str + MSF_MSF20_MAGIC_SIZE); + block_size_raw = header->block_size; + whole_file_block_count_raw = header->block_count; + directory_size_raw = header->directory_size; + } + else if (index_size == 4){ + MSF_Header70 *header = (MSF_Header70*)(msf_data.str + MSF_MSF70_MAGIC_SIZE); + block_size_raw = header->block_size; + whole_file_block_count_raw = header->block_count; + directory_size_raw = header->directory_size; + directory_super_map_raw = header->directory_super_map; + } + + //- setup important sizes & counts + + // (blocks) + U32 block_size = ClampTop(block_size_raw, msf_data.size); + + // (whole file block count) + U32 whole_file_block_count_max = CeilIntegerDiv(msf_data.size, block_size); + U32 whole_file_block_count = ClampTop(whole_file_block_count_raw, whole_file_block_count_max); + + // (directory) + U32 directory_size = ClampTop(directory_size_raw, msf_data.size); + U32 block_count_in_directory = CeilIntegerDiv(directory_size, block_size); + + // (map) + U32 directory_map_size = block_count_in_directory*index_size; + U32 block_count_in_directory_map = CeilIntegerDiv(directory_map_size, block_size); + + // Layout of the "directory": + // + // super map: [s1, s2, s3, ...] + // map: s1 -> [i1, i2, i3, ...]; s2 -> [...]; s3 -> [...]; ... + // directory: i1 -> [data]; i2 -> [data]; i3 -> [data]; ... i1 -> [data]; ... + // + // The "data" in the directory describes streams: + // PDB20: + // struct Pdb20StreamSize{ + // U32 size; + // U32 unknown; // looks like kind codes or revision counters or something + // } + // struct{ + // U32 stream_count; + // Pdb20StreamSize stream_sizes[stream_count]; + // U16 stream_indices[stream_count][...]; + // } + // + // PDB70: + // struct{ + // U32 stream_count; + // U32 stream_sizes[stream_count]; + // U32 stream_indices[stream_count][...]; + // } + + //- parse stream directory + U8 *directory_buf = push_array(scratch.arena, U8, directory_size); + B32 got_directory = 1; + + { + U32 directory_super_map_dummy = 0; + U32 *directory_super_map = 0; + U32 directory_map_block_skip_size = 0; + if (index_size == 2){ + directory_super_map = &directory_super_map_dummy; + directory_map_block_skip_size = + MSF_MSF20_MAGIC_SIZE + OffsetOf(MSF_Header20, directory_map); + } + else{ + U64 super_map_off = + MSF_MSF70_MAGIC_SIZE + OffsetOf(MSF_Header70, directory_super_map); + directory_super_map = (U32*)(msf_data.str + super_map_off); + } + + U32 max_index_count_in_map_block = (block_size - directory_map_block_skip_size)/index_size; + + // for each index in super map ... + U8 *out_ptr = directory_buf; + U32 *super_map_ptr = directory_super_map; + for (U32 i = 0; i < block_count_in_directory_map; i += 1, super_map_ptr += 1){ + U32 directory_map_block_index = *super_map_ptr; + if (directory_map_block_index >= whole_file_block_count){ + got_directory = 0; + goto parse_directory_done; + } + + U64 directory_map_block_off = (U64)(directory_map_block_index)*block_size; + U8 *directory_map_block_base = (msf_data.str + directory_map_block_off); + + // clamp index count by end of directory + U32 index_count = 0; + { + U32 directory_pos = (U32)(out_ptr - directory_buf); + U32 remaining_size = directory_size - directory_pos; + U32 remaining_map_block_count = CeilIntegerDiv(remaining_size, block_size); + index_count = ClampTop(max_index_count_in_map_block, remaining_map_block_count); + } + + // for each index in map ... + U8 *map_ptr = directory_map_block_base + directory_map_block_skip_size; + for (U32 j = 0; j < index_count; j += 1, map_ptr += index_size){ + + // read index + U32 directory_block_index = 0; + if (index_size == 4){ + directory_block_index = *(U32*)(map_ptr); + } + else{ + directory_block_index = *(U16*)(map_ptr); + } + if (directory_block_index >= whole_file_block_count){ + got_directory = 0; + goto parse_directory_done; + } + + U64 directory_block_off = (U64)(directory_block_index)*block_size; + U8 *directory_block_base = (msf_data.str + directory_block_off); + + // clamp copy size by end of directory + U32 copy_size = 0; + { + U32 directory_pos = (U32)(out_ptr - directory_buf); + U32 remaining_size = directory_size - directory_pos; + copy_size = ClampTop(block_size, remaining_size); + } + + // copy block data + MemoryCopy(out_ptr, directory_block_base, copy_size); + out_ptr += copy_size; + } + + } + + parse_directory_done:; + } + + //- parse streams from directory + U32 stream_count = 0; + B32 got_streams = 0; + String8 *streams = 0; + + if (got_directory){ + got_streams = 1; + + // read stream count + U32 stream_count_raw = *(U32*)(directory_buf); + + // setup counts, sizes, and offsets + U32 size_of_stream_entry = 4; + if (index_size == 2){ + size_of_stream_entry = 8; + } + U32 stream_count_max = (directory_size - 4)/size_of_stream_entry; + U32 stream_count__inner = ClampTop(stream_count_raw, stream_count_max); + U32 all_stream_entries_off = 4; + U32 all_indices_off = all_stream_entries_off + stream_count__inner*size_of_stream_entry; + + // set output buffer and count + stream_count = stream_count__inner; + streams = push_array(arena, String8, stream_count); + + // iterate sizes and indices in lock step + U32 entry_cursor = all_stream_entries_off; + U32 index_cursor = all_indices_off; + String8 *stream_ptr = streams; + for (U32 i = 0; i < stream_count; i += 1){ + // read stream size + U32 stream_size_raw = *(U32*)(directory_buf + entry_cursor); + if (stream_size_raw == 0xffffffff){ + stream_size_raw = 0; + } + + // compute block count + U32 stream_block_count_raw = CeilIntegerDiv(stream_size_raw, block_size); + U32 stream_block_count_max = (directory_size - index_cursor)/index_size;; + U32 stream_block_count = ClampTop(stream_block_count_raw, stream_block_count_max); + U32 stream_size = ClampTop(stream_size_raw, stream_block_count*block_size); + + // copy stream data + U8 *stream_buf = push_array(arena, U8, stream_size); + stream_ptr->str = stream_buf; + stream_ptr->size = stream_size; + + U32 sub_index_cursor = index_cursor; + U8 *stream_out_ptr = stream_buf; + for (U32 i = 0; i < stream_block_count; i += 1, sub_index_cursor += index_size){ + + // read index + U32 stream_block_index = 0; + if (index_size == 4){ + stream_block_index = *(U32*)(directory_buf + sub_index_cursor); + } + else{ + stream_block_index = *(U16*)(directory_buf + sub_index_cursor); + } + if (stream_block_index >= whole_file_block_count){ + got_streams = 0; + goto parse_streams_done; + } + + U64 stream_block_off = (U64)(stream_block_index)*block_size; + U8 *stream_block_base = (msf_data.str + stream_block_off); + + // clamp copy size by end of stream + U32 copy_size = 0; + { + U32 stream_pos = (U32)(stream_out_ptr - stream_buf); + U32 remaining_size = stream_size - stream_pos; + copy_size = ClampTop(block_size, remaining_size); + } + + // copy block data + MemoryCopy(stream_out_ptr, stream_block_base, copy_size); + stream_out_ptr += copy_size; + } + + // advance cursors + entry_cursor += size_of_stream_entry; + index_cursor = sub_index_cursor; + stream_ptr += 1; + } + + parse_streams_done:; + } + + if (got_streams){ + result = push_array(arena, MSF_Parsed, 1); + result->streams = streams; + result->stream_count = stream_count; + result->block_size = block_size; + result->block_count = whole_file_block_count; + } + } + + scratch_end(scratch); + + ProfEnd(); + + return(result); +} + +static String8 +msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn){ + String8 result = {0}; + if (sn < msf->stream_count){ + result = msf->streams[sn]; + } + return(result); +} diff --git a/src/raddbg_convert/pdb/raddbg_msf.h b/src/raddbg_convert/pdb/raddbg_msf.h new file mode 100644 index 00000000..62f671fd --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_msf.h @@ -0,0 +1,60 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_MSF_H +#define RADDBG_MSF_H + +//////////////////////////////// +//~ MSF Format Types + +#define MSF_INVALID_STREAM_NUMBER 0xFFFF +typedef U16 MSF_StreamNumber; + +static char msf_msf20_magic[] = "Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"; +static char msf_msf70_magic[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"; + +#define MSF_MSF20_MAGIC_SIZE 44 +#define MSF_MSF70_MAGIC_SIZE 32 +#define MSF_MAX_MAGIC_SIZE 44 + +typedef struct MSF_Header20{ + U32 block_size; + U16 free_block_map_block; + U16 block_count; + U32 directory_size; + U32 unknown; + U16 directory_map; +} MSF_Header20; + +typedef struct MSF_Header70{ + U32 block_size; + U32 free_block_map_block; + U32 block_count; + U32 directory_size; + U32 unknown; + U32 directory_super_map; +} MSF_Header70; + +// magic(20) + header(20) = 44 + 20 = 64 +// magic(70) + header(70) = 32 + 24 = 56 + +#define MSF_MIN_SIZE 64 + +//////////////////////////////// +//~ MSF Parser Helper Types + +typedef struct MSF_Parsed{ + String8 *streams; + U64 stream_count; + + U64 block_size; + U64 block_count; +} MSF_Parsed; + +//////////////////////////////// +//~ MSF Parser Function + +static MSF_Parsed* msf_parsed_from_data(Arena *arena, String8 msf_data); +static String8 msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn); + +#endif //RADDBG_MSF_H diff --git a/src/raddbg_convert/pdb/raddbg_pdb.c b/src/raddbg_convert/pdb/raddbg_pdb.c new file mode 100644 index 00000000..df9fb761 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_pdb.c @@ -0,0 +1,908 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ PDB Parser Functions + +static PDB_Info* +pdb_info_from_data(Arena *arena, String8 data){ + ProfBegin("pdb_info_from_data"); + + // get header + PDB_InfoHeader *header = 0; + if (data.size >= sizeof(*header)){ + header = (PDB_InfoHeader*)data.str; + } + + PDB_Info *result = 0; + if (header != 0){ + // read guid + COFF_Guid *auth_guid = 0; + U32 after_auth_guid_off = sizeof(*header); + switch (header->version){ + case PDB_Version_VC70_DEP: + case PDB_Version_VC70: + case PDB_Version_VC80: + case PDB_Version_VC110: + case PDB_Version_VC140: + { + auth_guid = (COFF_Guid*)(data.str + after_auth_guid_off); + after_auth_guid_off = sizeof(*header) + sizeof(*auth_guid); + }break; + + default: + {}break; + } + + if (header->version != 0){ + // table layout: names + U32 names_len_off = after_auth_guid_off; + U32 names_len = 0; + if (names_len_off + 4 <= data.size){ + names_len = *(U32*)(data.str + names_len_off); + } + + U32 names_base_off = names_len_off + 4; + U32 names_base_opl = names_base_off + names_len; + + // table layout: hash table + U32 hash_table_count_off = names_base_opl; + U32 hash_table_max_off = hash_table_count_off + 4; + + U32 hash_table_count = 0; + U32 hash_table_max = 0; + if (hash_table_max_off + 4 <= data.size){ + hash_table_count = *(U32*)(data.str + hash_table_count_off); + hash_table_max = *(U32*)(data.str + hash_table_max_off); + } + + // table layout: words + U32 num_present_words_off = hash_table_max_off + 4; + U32 num_present_words = 0; + if (hash_table_max_off + 4 <= data.size){ + num_present_words = *(U32*)(data.str + num_present_words_off); + } + U32 present_words_array_off = num_present_words_off + 4; + + U32 num_deleted_words_off = present_words_array_off + num_present_words*sizeof(U32); + U32 num_deleted_words = 0; + if (num_deleted_words_off + 4 <= data.size){ + num_deleted_words = *(U32*)(data.str + num_deleted_words_off); + } + U32 deleted_words_array_off = num_deleted_words_off + 4; + + // table layout: epilogue + U32 epilogue_base_off = deleted_words_array_off + num_deleted_words*sizeof(U32); + + // read table + if (hash_table_count > 0 && epilogue_base_off <= data.size){ + PDB_InfoNode *first = 0; + PDB_InfoNode *last = 0; + + U32 record_off = epilogue_base_off; + for (U32 i = 0; i < hash_table_count; i += 1, record_off += 8){ + U32 *record = (U32*)(data.str + record_off); + U32 relative_name_off = record[0]; + MSF_StreamNumber sn = (MSF_StreamNumber)record[1]; + + U32 name_off = names_base_off + relative_name_off; + String8 name = str8_cstring_capped((char*)(data.str + name_off), + (char*)(data.str + names_base_opl)); + + // push info node + PDB_InfoNode *node = push_array(arena, PDB_InfoNode, 1); + SLLQueuePush(first, last, node); + node->string = name; + node->sn = sn; + } + + result = push_array(arena, PDB_Info, 1); + result->first = first; + result->last = last; + result->auth_guid = *auth_guid; + } + + } + } + + ProfEnd(); + + return(result); +} + +static PDB_NamedStreamTable* +pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info){ + ProfBegin("pdb_named_stream_table_from_info"); + + // mapping "NamedStream" indexes to strings + struct StreamNameIndexPair{ + PDB_NamedStream index; + String8 name; + }; + struct StreamNameIndexPair pairs[] = { + {PDB_NamedStream_HEADER_BLOCK, str8_lit("/src/headerblock")}, + {PDB_NamedStream_STRTABLE , str8_lit("/names")}, + {PDB_NamedStream_LINK_INFO , str8_lit("/LinkInfo")}, + }; + + // build baked table + PDB_NamedStreamTable *result = push_array(arena, PDB_NamedStreamTable, 1); + struct StreamNameIndexPair *p = pairs; + for (U64 i = 0; i < ArrayCount(pairs); i += 1, p += 1){ + String8 name = p->name; + + // get info node with this name + PDB_InfoNode *match = 0; + for (PDB_InfoNode *node = info->first; + node != 0; + node = node->next){ + if (str8_match(name, node->string, 0)){ + match = node; + break; + } + } + + // if match found save stream number + if (match != 0){ + result->sn[p->index] = match->sn; + } + else{ + result->sn[p->index] = 0xFFFF; + } + } + + ProfEnd(); + + return(result); +} + +static PDB_Strtbl* +pdb_strtbl_from_data(Arena *arena, String8 data){ + ProfBegin("pdb_strtbl_from_data"); + + // get header + PDB_StrtblHeader *header = 0; + if (sizeof(*header) <= data.size){ + header = (PDB_StrtblHeader*)data.str; + } + + PDB_Strtbl *result = 0; + if (header != 0 && header->magic == PDB_StrtblHeader_MAGIC && header->version == 1){ + U32 strblock_size_off = sizeof(*header); + U32 strblock_size = 0; + if (strblock_size_off + 4 <= data.size){ + strblock_size = *(U32*)(data.str + strblock_size_off); + } + U32 strblock_off = strblock_size_off + 4; + + U32 bucket_count_off = strblock_off + strblock_size; + U32 bucket_count = 0; + if (bucket_count_off + 4 <= data.size){ + bucket_count = *(U32*)(data.str + bucket_count_off); + } + + U32 bucket_array_off = bucket_count_off + 4; + U32 bucket_array_size = bucket_count*sizeof(PDB_StringIndex); + + if (bucket_array_off + bucket_array_size <= data.size){ + result = push_array(arena, PDB_Strtbl, 1); + result->data = data; + result->bucket_count = bucket_count; + result->strblock_min = strblock_off; + result->strblock_max = strblock_off + strblock_size; + result->buckets_min = bucket_array_off; + result->buckets_min = bucket_array_off + bucket_array_size; + } + } + + ProfEnd(); + + return(result); +} + +static PDB_DbiParsed* +pdb_dbi_from_data(Arena *arena, String8 data){ + ProfBegin("pdb_dbi_from_data"); + + // get header + PDB_DbiHeader *header = 0; + if (sizeof(*header) <= data.size){ + header = (PDB_DbiHeader*)data.str; + } + + PDB_DbiParsed *result = 0; + if (header != 0 && header->sig == PDB_DbiHeaderSignature_V1){ + // extract range sizes + U64 range_size[PDB_DbiRange_COUNT]; + range_size[PDB_DbiRange_ModuleInfo] = header->module_info_size; + range_size[PDB_DbiRange_SecCon] = header->sec_con_size; + range_size[PDB_DbiRange_SecMap] = header->sec_map_size; + range_size[PDB_DbiRange_FileInfo] = header->file_info_size; + range_size[PDB_DbiRange_TSM] = header->tsm_size; + range_size[PDB_DbiRange_EcInfo] = header->ec_info_size; + range_size[PDB_DbiRange_DbgHeader] = header->dbg_header_size; + + // fill result + result = push_array(arena, PDB_DbiParsed, 1); + result->data = data; + result->arch = header->machine; + result->gsi_sn = header->gsi_sn; + result->psi_sn = header->psi_sn; + result->sym_sn = header->sym_sn; + + + // fill result's range offsets + { + U64 cursor = sizeof(*header); + for (U64 i = 0; i < (U64)(PDB_DbiRange_COUNT); i += 1){ + result->range_off[i] = cursor; + cursor += range_size[i]; + cursor = ClampTop(cursor, data.size); + } + result->range_off[PDB_DbiRange_COUNT] = cursor; + } + + // fill result's debug streams + U64 dbg_streams_min = result->range_off[PDB_DbiRange_DbgHeader]; + U64 dbg_streams_max = result->range_off[PDB_DbiRange_DbgHeader + 1]; + U64 dbg_streams_size_raw = dbg_streams_max - dbg_streams_min; + U64 dbg_streams_size = ClampTop(dbg_streams_size_raw, sizeof(result->dbg_streams)); + MemoryCopy(result->dbg_streams, data.str + dbg_streams_min, dbg_streams_size); + if (dbg_streams_size < sizeof(result->dbg_streams)){ + U64 filled_count = dbg_streams_size/sizeof(MSF_StreamNumber); + MemorySet(result->dbg_streams + filled_count, 0xff, + (ArrayCount(result->dbg_streams) - filled_count)*sizeof(MSF_StreamNumber)); + } + } + + ProfEnd(); + + return(result); +} + +static PDB_TpiParsed* +pdb_tpi_from_data(Arena *arena, String8 data){ + ProfBegin("pdb_tpi_from_data"); + + // get header + PDB_TpiHeader *header = 0; + if (sizeof(*header) <= data.size){ + header = (PDB_TpiHeader*)data.str; + } + + PDB_TpiParsed *result = 0; + if (header != 0 && header->version == PDB_TpiVersion_IMPV80){ + U64 leaf_first_raw = header->header_size; + U64 leaf_first = ClampTop(leaf_first_raw, data.size); + U64 leaf_opl_raw = leaf_first + header->leaf_data_size; + U64 leaf_opl = ClampTop(leaf_opl_raw, data.size); + + result = push_array(arena, PDB_TpiParsed, 1); + result->data = data; + + result->leaf_first = leaf_first; + result->leaf_opl = leaf_opl; + result->itype_first = header->ti_lo; + result->itype_opl = header->ti_hi; + + result->hash_sn = header->hash_sn; + result->hash_sn_aux = header->hash_sn_aux; + result->hash_key_size = header->hash_key_size; + result->hash_bucket_count = header->hash_bucket_count; + result->hash_vals_off = header->hash_vals_off; + result->hash_vals_size = header->hash_vals_size; + result->itype_off = header->itype_off; + result->itype_size = header->itype_size; + result->hash_adj_off = header->hash_adj_off; + result->hash_adj_size = header->hash_adj_size; + } + + ProfEnd(); + + return(result); +} + +static PDB_TpiHashParsed* +pdb_tpi_hash_from_data(Arena *arena, PDB_TpiParsed *tpi, String8 data, String8 aux_data){ + ProfBegin("pdb_tpi_hash_from_data"); + + PDB_TpiHashParsed *result = 0; + + U32 stride = tpi->hash_key_size; + U32 bucket_count = tpi->hash_bucket_count; + if (1 <= stride && stride <= 8 && bucket_count > 0){ + + // allocate buckets + PDB_TpiHashBlock **buckets = push_array(arena, PDB_TpiHashBlock*, bucket_count); + + // extract "hash" array + U8 *hashes = data.str + tpi->hash_vals_off; + U8 *hash_opl = hashes + tpi->hash_vals_size; + + // for each index in the array... + CV_TypeId itype = tpi->itype_first; + U8 *hash_cursor = hashes; + for (;hash_cursor + stride <= hash_opl;){ + + // read index + U64 bucket_idx = 0; + MemoryCopy(&bucket_idx, hash_cursor, stride); + + // save to map + if (bucket_idx < bucket_count){ + PDB_TpiHashBlock *block = buckets[bucket_idx]; + if (block == 0 || block->local_count == ArrayCount(block->itypes)){ + block = push_array(arena, PDB_TpiHashBlock, 1); + SLLStackPush(buckets[bucket_idx], block); + } + block->itypes[block->local_count] = itype; + block->local_count += 1; + } + + // advance cursor + hash_cursor += stride; + itype += 1; + } + + // fill result + result = push_array(arena, PDB_TpiHashParsed, 1); + result->data = data; + result->aux_data = aux_data; + result->buckets = buckets; + result->bucket_count = bucket_count; + if (IsPow2OrZero(bucket_count)){ + result->bucket_mask = bucket_count - 1; + } + } + + ProfEnd(); + + return(result); +} + +static PDB_GsiParsed* +pdb_gsi_from_data(Arena *arena, String8 data){ + ProfBegin("pdb_gsi_from_data"); + + // get header + PDB_GsiHeader *header = 0; + if (sizeof(*header) <= data.size){ + header = (PDB_GsiHeader*)data.str; + } + + PDB_GsiParsed *result = 0; + if (header != 0 && header->signature == PDB_GsiSignature_Basic && + header->version == PDB_GsiVersion_V70 && header->num_buckets != 0){ + Temp scratch = scratch_begin(&arena, 1); + + // hash offset + U32 hash_record_array_off = sizeof(*header); + + // bucket count + U32 slot_count = 4097; + + // array offsets + U32 bitmask_u32_count = CeilIntegerDiv(slot_count, 32); + U32 bitmask_byte_size = bitmask_u32_count*4; + U32 bitmask_off = hash_record_array_off + header->hr_len; + U32 offsets_off = bitmask_off + bitmask_byte_size; + + // get bitmask & packed offset arrays + U8 *bitmasks = 0; + U8 *packed_offsets = 0; + if (bitmask_off + bitmask_byte_size <= data.size){ + bitmasks = (data.str + bitmask_off); + packed_offsets = (data.str + offsets_off); + } + U32 packed_offset_count = (data.size - offsets_off)/4; + + // unpack + U32 *unpacked_offsets = 0; + if (packed_offsets != 0){ + unpacked_offsets = push_array(scratch.arena, U32, slot_count); + + U32 *bitmask_ptr = (U32*)bitmasks; + U32 *bitmask_opl = bitmask_ptr + bitmask_u32_count; + U32 *src_ptr = (U32*)packed_offsets; + U32 *src_opl = src_ptr + packed_offset_count; + U32 *dst_ptr = unpacked_offsets; + U32 *dst_opl = dst_ptr + slot_count; + for (; bitmask_ptr < bitmask_opl && src_ptr < src_opl; bitmask_ptr += 1){ + U32 bits = *bitmask_ptr; + U32 src_max = (U32)(src_opl - src_ptr); + U32 dst_max = (U32)(dst_opl - dst_ptr); + U32 k_max0 = ClampTop(32, dst_max); + U32 k_max = ClampTop(k_max0, src_max); + for (U32 k = 0; k < k_max; k += 1){ + if ((bits & 1) == 1){ + *dst_ptr = *src_ptr; + src_ptr += 1; + } + else{ + *dst_ptr = 0xFFFFFFFF; + } + dst_ptr += 1; + bits >>= 1; + } + } + for (; dst_ptr < dst_opl; dst_ptr += 1){ + *dst_ptr = 0xFFFFFFFF; + } + } + + // construct table + B32 bad_table = 0; + if (unpacked_offsets != 0){ + result = push_array(arena, PDB_GsiParsed, 1); + + // hash records + PDB_GsiHashRecord *hash_records = (PDB_GsiHashRecord*)(data.str + hash_record_array_off); + U32 hash_record_count = header->hr_len/sizeof(PDB_GsiHashRecord); + + // * We unpack hash records into the the table by scanning backwards through the + // * hash records. Neighboring values in unpacked_offsets *sort of* form counts, but we + // * have to skip the max-U32s (sloppy PDB nonsense). + + // * PDBs put one extra slot at the beginning of the encoded buckets that is mean + // * to be padding for modifying the buffer in place. After decoding there are 4096 buckets, + // * in the encoded buckets there are 4097. We are meant to drop the first one. + + // build table + PDB_GsiHashRecord *hash_record_ptr = hash_records + hash_record_count - 1; + U32 prev_n = hash_record_count; + for (U32 i = slot_count; i > 1;){ + i -= 1; + if (unpacked_offsets[i] != 0xFFFFFFFF){ + // determine hash record range to use + // * The "12" here is the result of some really sloppy PDB magic. + U32 n = unpacked_offsets[i]/12; + if (n > prev_n){ + bad_table = 1; + break; + } + U32 num_steps = prev_n - n; + + // fill this bucket + arena_push_align(arena, 4); + U32 *bucket_offs = push_array_no_zero(arena, U32, num_steps); + for (U32 j = num_steps; j > 0;){ + j -= 1; + // * The "- 1" is more sloppy PDB magic. + bucket_offs[j] = hash_record_ptr->symbol_off - 1; + hash_record_ptr -= 1; + } + PDB_GsiBucket *bucket = &result->buckets[i - 1]; + bucket->count = num_steps; + bucket->offs = bucket_offs; + + // update prev_n + prev_n = n; + } + } + } + + scratch_end(scratch); + } + + ProfEnd(); + + return(result); +} + +static PDB_CoffSectionArray* +pdb_coff_section_array_from_data(Arena *arena, String8 data){ + U64 count = data.size/sizeof(COFF_SectionHeader); + + PDB_CoffSectionArray *result = push_array(arena, PDB_CoffSectionArray, 1); + result->sections = (COFF_SectionHeader*)data.str; + result->count = count; + return(result); +} + +static PDB_CompUnitArray* +pdb_comp_unit_array_from_data(Arena *arena, String8 data){ + PDB_CompUnitNode *first = 0; + PDB_CompUnitNode *last = 0; + U64 count = 0; + + U64 cursor = 0; + for (;cursor + sizeof(PDB_DbiCompUnitHeader) <= data.size;){ + // get header + PDB_DbiCompUnitHeader *header = (PDB_DbiCompUnitHeader*)(data.str + cursor); + + // get names + U64 name_off = cursor + sizeof(*header); + String8 name = str8_cstring_capped((char *)(data.str + name_off), (char *)(data.str + data.size)); + + U64 name2_off = name_off + name.size + 1; + String8 name2 = str8_cstring_capped((char *)(data.str + name2_off), (char *)(data.str + data.size)); + + U64 after_name2_off = name2_off + name2.size + 1; + + // save mod info + PDB_CompUnitNode *node = push_array_no_zero(arena, PDB_CompUnitNode, 1); + SLLQueuePush(first, last, node); + count += 1; + node->unit.sn = header->sn; + node->unit.obj_name = name; + node->unit.group_name = name2; + + // fill range offsets + U32 *range_buf = node->unit.range_off; + { + // fill the buffer with size of each range + range_buf[PDB_DbiCompUnitRange_Symbols] = header->symbols_size; + range_buf[PDB_DbiCompUnitRange_C11] = header->c11_lines_size; + range_buf[PDB_DbiCompUnitRange_C13] = header->c13_lines_size; + Assert(PDB_DbiCompUnitRange_C13 + 1 == PDB_DbiCompUnitRange_COUNT); + + // in-place sizes -> offs conversion + U64 i = 0; + U32 range_cursor = 0; + for (; i < (U64)(PDB_DbiCompUnitRange_COUNT); i += 1){ + U64 adv = range_buf[i]; + range_buf[i] = range_cursor; + range_cursor += adv; + } + range_buf[i] = range_cursor; + + // skip 4 byte signature in symbols range + if (range_buf[1] >= 4){ + range_buf[0] += 4; + } + } + + // update cursor + cursor = AlignPow2(after_name2_off, 4); + } + + + // fill result + PDB_CompUnit **units = push_array_no_zero(arena, PDB_CompUnit*, count); + { + U64 idx = 0; + for (PDB_CompUnitNode *node = first; + node != 0; + node = node->next, idx += 1){ + units[idx] = &node->unit; + } + } + + PDB_CompUnitArray *result = push_array(arena, PDB_CompUnitArray, 1); + result->units = units; + result->count = count; + + return(result); +} + +static PDB_CompUnitContributionArray* +pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, + PDB_CoffSectionArray *sections){ + PDB_CompUnitContribution *contributions = 0; + U64 count = 0; + if (data.size >= sizeof(PDB_DbiSectionContribVersion)){ + PDB_DbiSectionContribVersion *version = (PDB_DbiSectionContribVersion*)data.str; + + // determine array layout from version + U32 item_size = 0; + U32 array_off = 0; + switch (*version){ + default: + { + // TODO(allen): do we have a test case for this? + item_size = sizeof(PDB_DbiSectionContrib40); + }break; + case PDB_DbiSectionContribVersion_1: + { + item_size = sizeof(PDB_DbiSectionContrib); + array_off = sizeof(*version); + }break; + case PDB_DbiSectionContribVersion_2: + { + item_size = sizeof(PDB_DbiSectionContrib2); + array_off = sizeof(*version); + }break; + } + + // allocate ranges + U64 max_count = (data.size - array_off)/item_size; + contributions = push_array_no_zero(arena, PDB_CompUnitContribution, max_count); + + // binary section info + U64 section_count = sections->count; + COFF_SectionHeader* section_headers = sections->sections; + + // fill array + PDB_CompUnitContribution *contribution_ptr = contributions; + U64 cursor = array_off; + for (; cursor + item_size <= data.size; cursor += item_size){ + PDB_DbiSectionContrib40 *sc = (PDB_DbiSectionContrib40*)(data.str + cursor); + if (sc->size > 0 && 1 <= sc->sec && sc->sec <= section_count){ + U64 voff = section_headers[sc->sec - 1].voff + sc->sec_off; + + contribution_ptr->mod = sc->mod; + contribution_ptr->voff_first = voff; + contribution_ptr->voff_opl = voff + sc->size; + contribution_ptr += 1; + } + } + count = (U64)(contribution_ptr - contributions); + } + + // fill result + PDB_CompUnitContributionArray *result = push_array(arena, PDB_CompUnitContributionArray, 1); + result->contributions = contributions; + result->count = count; + + return(result); +} + + +//////////////////////////////// +//~ PDB Definition Functions + +static U32 +pdb_string_hash1(String8 string){ + U32 result = 0; + U8 *ptr = string.str; + U8 *opl = ptr + (string.size&(~3)); + for (; ptr < opl; ptr += 4){ result ^= *(U32*)ptr; } + if ((string.size&2) != 0){ result ^= *(U16*)ptr; ptr += 2; } + if ((string.size&1) != 0){ result ^= *ptr; } + result |= 0x20202020; + result ^= (result >> 11); + result ^= (result >> 16); + return(result); +} + + +//////////////////////////////// +//~ PDB Dbi Functions + +static String8 +pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range){ + String8 result = {0}; + if (range < PDB_DbiRange_COUNT){ + U64 first = dbi->range_off[range]; + U64 opl = dbi->range_off[range + 1]; + result.str = dbi->data.str + first; + result.size = opl - first; + } + return(result); +} + +static String8 +pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit, PDB_DbiCompUnitRange range){ + String8 result = {0}; + if (range < PDB_DbiCompUnitRange_COUNT){ + String8 full_stream_data = msf_data_from_stream(msf, unit->sn); + + U64 first_raw = unit->range_off[range]; + U64 opl_raw = unit->range_off[range + 1]; + U64 opl = ClampTop(opl_raw, full_stream_data.size); + U64 first = ClampTop(first_raw, opl); + + result.str = full_stream_data.str + first; + result.size = opl - first; + } + return(result); +} + +//////////////////////////////// +//~ PDB Tpi Functions + +static String8 +pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi){ + String8 data = tpi->data; + U8 *first = data.str + tpi->leaf_first; + U8 *opl = data.str + tpi->leaf_opl; + String8 result = str8_range(first, opl); + return(result); +} + +static CV_TypeIdArray +pdb_tpi_itypes_from_name(Arena *arena, PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *leaf, + String8 name, B32 compare_unique_name, U32 output_cap){ + ProfBegin("pdb_tpi_itypes_from_name"); + + U32 hash = pdb_string_hash1(name); + U32 bucket_idx = ((tpi_hash->bucket_mask != 0) ? + hash&tpi_hash->bucket_mask : + hash%tpi_hash->bucket_count); + + CV_TypeId itype_first = leaf->itype_first; + CV_TypeId itype_opl = leaf->itype_opl; + String8 data = leaf->data; + + Temp scratch = scratch_begin(&arena, 1); + struct Chain{ + struct Chain *next; + CV_TypeId itype; + }; + struct Chain *first = 0; + struct Chain *last = 0; + U32 count = 0; + + for (PDB_TpiHashBlock *block = tpi_hash->buckets[bucket_idx]; + block != 0; + block = block->next){ + U32 local_count = block->local_count; + CV_TypeId *itype_ptr = block->itypes; + for (U32 i = 0; i < local_count; i += 1, itype_ptr += 1){ + + String8 extracted_name = {0}; + + CV_TypeId itype = *itype_ptr; + if (itype_first <= itype && itype < itype_opl){ + CV_RecRange *range = &leaf->leaf_ranges.ranges[itype - leaf->itype_first]; + if (range->off + range->hdr.size <= data.size){ + U8 *first = data.str + range->off + 2; + U64 cap = range->hdr.size - 2; + + switch (range->hdr.kind){ + default:break; + + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + if (sizeof(CV_LeafStruct) <= cap){ + CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; + + if (!(lf_struct->props & CV_TypeProp_FwdRef)){ + // size + U8 *numeric_ptr = (U8*)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + + // unique name + if (compare_unique_name){ + if (lf_struct->props & CV_TypeProp_HasUniqueName) { + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); + extracted_name = unique_name; + } + } + else{ + extracted_name = name; + } + } + } + }break; + + case CV_LeafKind_UNION: + { + if (sizeof(CV_LeafUnion) <= cap){ + CV_LeafUnion *lf_union = (CV_LeafUnion*)first; + + if (!(lf_union->props & CV_TypeProp_FwdRef)){ + // size + U8 *numeric_ptr = (U8*)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + + // unique name + if (compare_unique_name){ + if (lf_union->props & CV_TypeProp_HasUniqueName) { + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); + extracted_name = unique_name; + } + } + else{ + extracted_name = name; + } + } + } + }break; + + case CV_LeafKind_ENUM: + { + if (sizeof(CV_LeafEnum) <= cap){ + CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; + + if (!(lf_enum->props & CV_TypeProp_FwdRef)){ + // name + U8 *name_ptr = (U8*)(lf_enum + 1); + String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + + // unique name + if (compare_unique_name){ + if (lf_enum->props & CV_TypeProp_HasUniqueName) { + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); + extracted_name = unique_name; + } + } + else{ + extracted_name = name; + } + } + } + }break; + } + } + } + + if (str8_match(extracted_name, name, 0)){ + struct Chain *chain = push_array(scratch.arena, struct Chain, 1); + SLLQueuePush(first, last, chain); + count += 1; + chain->itype = itype; + if (count == output_cap){ + goto dblbreak; + } + } + } + } + + dblbreak:; + + + // assemble result + CV_TypeId *itypes = push_array(arena, CV_TypeId, count); + { + CV_TypeId *itype_ptr = itypes; + for (struct Chain *node = first; + node != 0; + node = node->next, itype_ptr += 1){ + *itype_ptr = node->itype; + } + } + CV_TypeIdArray result = {0}; + result.itypes = itypes; + result.count = count; + + scratch_end(scratch); + + ProfEnd(); + + return(result); +} + +static CV_TypeId +pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *tpi_leaf, + String8 name, B32 compare_unique_name){ + ProfBegin("pdb_tpi_first_itype_from_name"); + + Temp scratch = scratch_begin(0, 0); + CV_TypeIdArray array = pdb_tpi_itypes_from_name(scratch.arena, tpi_hash, tpi_leaf, + name, compare_unique_name, 1); + CV_TypeId result = 0; + if (array.count > 0){ + result = array.itypes[0]; + } + + scratch_end(scratch); + ProfEnd(); + + return(result); +} + +//////////////////////////////// +//~ PDB Strtbl Functions + +static String8 +pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off){ + U32 strblock_max = strtbl->strblock_max; + U32 full_off_raw = strtbl->strblock_min + off; + U32 full_off = ClampTop(full_off_raw, strblock_max); + String8 result = str8_cstring_capped((char*)(strtbl->data.str + full_off), + (char*)(strtbl->data.str + strblock_max)); + return(result); +} + +static String8 +pdb_strtbl_string_from_index(PDB_Strtbl *strtbl, PDB_StringIndex idx){ + String8 result = {0}; + if (idx < strtbl->bucket_count){ + U32 off = *(U32*)(strtbl->data.str + strtbl->buckets_min + idx*4); + result = pdb_strtbl_string_from_off(strtbl, off); + } + return(result); +} diff --git a/src/raddbg_convert/pdb/raddbg_pdb.h b/src/raddbg_convert/pdb/raddbg_pdb.h new file mode 100644 index 00000000..e09d27fc --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_pdb.h @@ -0,0 +1,461 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_PDB_H +#define RADDBG_PDB_H + +// https://github.com/microsoft/microsoft-pdb/tree/master/PDB + +//////////////////////////////// +//~ PDB Format Types + +typedef U32 PDB_Version; +enum{ + PDB_Version_VC2 = 19941610, + PDB_Version_VC4 = 19950623, + PDB_Version_VC41 = 19950814, + PDB_Version_VC50 = 19960307, + PDB_Version_VC98 = 19970604, + PDB_Version_VC70_DEP = 19990604, + PDB_Version_VC70 = 20000404, + PDB_Version_VC80 = 20030901, + PDB_Version_VC110 = 20091201, + PDB_Version_VC140 = 20140508 +}; + +typedef U16 PDB_ModIndex; +typedef U32 PDB_StringIndex; + +typedef enum PDB_FixedStream{ + PDB_FixedStream_PdbInfo = 1, + PDB_FixedStream_Tpi = 2, + PDB_FixedStream_Dbi = 3, + PDB_FixedStream_Ipi = 4 +} PDB_FixedStream; + +typedef enum PDB_NamedStream{ + PDB_NamedStream_HEADER_BLOCK, + PDB_NamedStream_STRTABLE, + PDB_NamedStream_LINK_INFO, + PDB_NamedStream_COUNT +} PDB_NamedStream; + +typedef struct PDB_InfoHeader{ + PDB_Version version; + U32 time; + U32 age; +} PDB_InfoHeader; + +enum{ + PDB_StrtblHeader_MAGIC = 0xEFFEEFFE +}; + +typedef struct PDB_StrtblHeader{ + U32 magic; + U32 version; +} PDB_StrtblHeader; + +//////////////////////////////// +//~ PDB Format DBI Types + +typedef U32 PDB_DbiStream; +enum{ + PDB_DbiStream_FPO, + PDB_DbiStream_EXCEPTION, + PDB_DbiStream_FIXUP, + PDB_DbiStream_OMAP_TO_SRC, + PDB_DbiStream_OMAP_FROM_SRC, + PDB_DbiStream_SECTION_HEADER, + PDB_DbiStream_TOKEN_RDI_MAP, + PDB_DbiStream_XDATA, + PDB_DbiStream_PDATA, + PDB_DbiStream_NEW_FPO, + PDB_DbiStream_SECTION_HEADER_ORIG, + PDB_DbiStream_COUNT +}; + +typedef U32 PDB_DbiHeaderSignature; +enum{ + PDB_DbiHeaderSignature_V1 = 0xFFFFFFFF +}; + +typedef U32 PDB_DbiVersion; +enum{ + PDB_DbiVersion_41 = 930803, + PDB_DbiVersion_50 = 19960307, + PDB_DbiVersion_60 = 19970606, + PDB_DbiVersion_70 = 19990903, + PDB_DbiVersion_110 = 20091201, +}; + +typedef U16 PDB_DbiBuildNumber; +#define PDB_DbiBuildNumberNewFormatFlag 0x8000 +#define PDB_DbiBuildNumberMinor(bn) ((bn)&0xFF) +#define PDB_DbiBuildNumberMajor(bn) (((bn) >> 8)&0x7F) +#define PDB_DbiBuildNumberNewFormat(bn) (!!((bn)&PDB_DbiBuildNumberNewFormatFlag)) +#define PDB_DbiBuildNumber(maj, min) \ +(PDB_DbiBuildNumberNewFormatFlag | ((min)&0xFF) | (((maj)&0x7F) << 16)) + +typedef U16 PDB_DbiHeaderFlags; +enum{ + PDB_DbiHeaderFlag_Incremental = 0x1, + PDB_DbiHeaderFlag_Stripped = 0x2, + PDB_DbiHeaderFlag_CTypes = 0x4 +}; + +typedef struct PDB_DbiHeader{ + PDB_DbiHeaderSignature sig; + PDB_DbiVersion version; + U32 age; + MSF_StreamNumber gsi_sn; + PDB_DbiBuildNumber build_number; + + MSF_StreamNumber psi_sn; + U16 pdb_version; + + MSF_StreamNumber sym_sn; + U16 pdb_version2; + + U32 module_info_size; + U32 sec_con_size; + U32 sec_map_size; + U32 file_info_size; + + U32 tsm_size; + U32 mfc_index; + U32 dbg_header_size; + U32 ec_info_size; + + PDB_DbiHeaderFlags flags; + COFF_Arch machine; + + U32 reserved; +} PDB_DbiHeader; + +// (this is not "literally" defined by the format - but helpful to have) +typedef enum PDB_DbiRange{ + PDB_DbiRange_ModuleInfo, + PDB_DbiRange_SecCon, + PDB_DbiRange_SecMap, + PDB_DbiRange_FileInfo, + PDB_DbiRange_TSM, + PDB_DbiRange_EcInfo, + PDB_DbiRange_DbgHeader, + PDB_DbiRange_COUNT +} PDB_DbiRange; + +// "ModuleInfo" DBI range + +typedef U32 PDB_DbiSectionContribVersion; +#define PDB_DbiSectionContribVersion_1 (0xeffe0000u + 19970605u) +#define PDB_DbiSectionContribVersion_2 (0xeffe0000u + 20140516u) + +typedef struct PDB_DbiSectionContrib40{ + CV_SectionIndex sec; + U32 sec_off; + U32 size; + U32 flags; + PDB_ModIndex mod; +} PDB_DbiSectionContrib40; + +typedef struct PDB_DbiSectionContrib{ + PDB_DbiSectionContrib40 base; + U32 data_crc; + U32 reloc_crc; +} PDB_DbiSectionContrib; + +typedef struct PDB_DbiSectionContrib2{ + PDB_DbiSectionContrib40 base; + U32 data_crc; + U32 reloc_crc; + U32 sec_coff; +} PDB_DbiSectionContrib2; + +typedef struct PDB_DbiCompUnitHeader{ + U32 unused; + PDB_DbiSectionContrib contribution; + U16 flags; // unknown + + MSF_StreamNumber sn; + U32 symbols_size; + U32 c11_lines_size; + U32 c13_lines_size; + + U16 num_contrib_files; + U16 unused2; + U32 file_names_offset; + + PDB_StringIndex src_file; + PDB_StringIndex pdb_file; + + // U8[] module_name (null terminated) + // U8[] obj_name (null terminated) +} PDB_DbiCompUnitHeader; + +// (this is not "literally" defined by the format - but helpful to have) +typedef enum{ + PDB_DbiCompUnitRange_Symbols, + PDB_DbiCompUnitRange_C11, + PDB_DbiCompUnitRange_C13, + PDB_DbiCompUnitRange_COUNT +} PDB_DbiCompUnitRange; + +//////////////////////////////// +//~ PDB Format TPI Types + +typedef U32 PDB_TpiVersion; +enum{ + PDB_TpiVersion_INTV_VC2 = 920924, + PDB_TpiVersion_IMPV40 = 19950410, + PDB_TpiVersion_IMPV41 = 19951122, + PDB_TpiVersion_IMPV50_INTERIM = 19960307, + PDB_TpiVersion_IMPV50 = 19961031, + PDB_TpiVersion_IMPV70 = 19990903, + PDB_TpiVersion_IMPV80 = 20040203, +}; + +typedef struct PDB_TpiHeader{ + // (HDR) + PDB_TpiVersion version; + U32 header_size; + U32 ti_lo; + U32 ti_hi; + U32 leaf_data_size; + + // (PdbTpiHash) + MSF_StreamNumber hash_sn; + MSF_StreamNumber hash_sn_aux; + U32 hash_key_size; + U32 hash_bucket_count; + U32 hash_vals_off; + U32 hash_vals_size; + U32 itype_off; + U32 itype_size; + U32 hash_adj_off; + U32 hash_adj_size; +} PDB_TpiHeader; + +typedef struct PDB_TpiOffHint{ + CV_TypeId itype; + U32 off; +} PDB_TpiOffHint; + + +//////////////////////////////// +//~ PDB Format GSI Types + +typedef U32 PDB_GsiSignature; +enum{ + PDB_GsiSignature_Basic = 0xffffffff, +}; + +typedef U32 PDB_GsiVersion; +enum{ + PDB_GsiVersion_V70 = 0xeffe0000 + 19990810, +}; + +typedef struct PDB_GsiHeader{ + PDB_GsiSignature signature; + PDB_GsiVersion version; + U32 hr_len; + U32 num_buckets; +} PDB_GsiHeader; + +typedef struct PDB_GsiHashRecord{ + U32 symbol_off; + U32 cref; +} PDB_GsiHashRecord; + +typedef struct PDB_PsiHeader{ + U32 sym_hash_size; + U32 addr_map_size; + U32 thunk_count; + U32 thunk_size; + CV_SectionIndex isec_thunk_table; + U16 padding; + U32 sec_thunk_table_off; + U32 sec_count; +} PDB_PsiHeader; + +//////////////////////////////// +//~ PDB Parser Types + +typedef struct PDB_InfoNode{ + struct PDB_InfoNode *next; + String8 string; + MSF_StreamNumber sn; +} PDB_InfoNode; + +typedef struct PDB_Info{ + PDB_InfoNode *first; + PDB_InfoNode *last; + COFF_Guid auth_guid; +} PDB_Info; + +typedef struct PDB_NamedStreamTable{ + MSF_StreamNumber sn[PDB_NamedStream_COUNT]; +} PDB_NamedStreamTable; + +typedef struct PDB_Strtbl{ + String8 data; + U32 bucket_count; + U32 strblock_min; + U32 strblock_max; + U32 buckets_min; + U32 buckets_max; +} PDB_Strtbl; + +typedef struct PDB_DbiParsed{ + String8 data; + COFF_Arch arch; + MSF_StreamNumber gsi_sn; + MSF_StreamNumber psi_sn; + MSF_StreamNumber sym_sn; + + U64 range_off[(U64)(PDB_DbiRange_COUNT) + 1]; + MSF_StreamNumber dbg_streams[PDB_DbiStream_COUNT]; +} PDB_DbiParsed; + +typedef struct PDB_TpiParsed{ + String8 data; + + // leaf info + U64 leaf_first; + U64 leaf_opl; + U32 itype_first; + U32 itype_opl; + + // hash info + MSF_StreamNumber hash_sn; + MSF_StreamNumber hash_sn_aux; + U32 hash_key_size; + U32 hash_bucket_count; + U32 hash_vals_off; + U32 hash_vals_size; + U32 itype_off; + U32 itype_size; + U32 hash_adj_off; + U32 hash_adj_size; + +} PDB_TpiParsed; + +typedef struct PDB_TpiHashBlock{ + struct PDB_TpiHashBlock *next; + U32 local_count; + CV_TypeId itypes[13]; // 13 = (64 - 12)/4 +} PDB_TpiHashBlock; + +typedef struct PDB_TpiHashParsed{ + String8 data; + String8 aux_data; + + PDB_TpiHashBlock **buckets; + U32 bucket_count; + U32 bucket_mask; +} PDB_TpiHashParsed; + +typedef struct PDB_GsiBucket{ + U32 *offs; + U64 count; +} PDB_GsiBucket; + +typedef struct PDB_GsiParsed{ + PDB_GsiBucket buckets[4096]; +} PDB_GsiParsed; + +typedef struct PDB_CompUnit{ + MSF_StreamNumber sn; + U32 range_off[(U32)(PDB_DbiCompUnitRange_COUNT) + 1]; + + String8 obj_name; + String8 group_name; +} PDB_CompUnit; + +typedef struct PDB_CoffSectionArray{ + COFF_SectionHeader *sections; + U64 count; +} PDB_CoffSectionArray; + +typedef struct PDB_CompUnitNode{ + struct PDB_CompUnitNode *next; + PDB_CompUnit unit; +} PDB_CompUnitNode; + +typedef struct PDB_CompUnitArray{ + PDB_CompUnit **units; + U64 count; +} PDB_CompUnitArray; + +typedef struct PDB_CompUnitContribution{ + U32 mod; + U64 voff_first; + U64 voff_opl; +} PDB_CompUnitContribution; + +typedef struct PDB_CompUnitContributionArray{ + PDB_CompUnitContribution *contributions; + U64 count; +} PDB_CompUnitContributionArray; + +//////////////////////////////// +//~ PDB Parser Functions + +static PDB_Info* pdb_info_from_data(Arena *arena, String8 pdb_info_data); +static PDB_NamedStreamTable*pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info); +static PDB_Strtbl* pdb_strtbl_from_data(Arena *arena, String8 strtbl_data); + +static PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 dbi_data); +static PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 tpi_data); +static PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena, + PDB_TpiParsed *tpi, + String8 tpi_hash_data, + String8 tpi_hash_aux_data); +static PDB_GsiParsed* pdb_gsi_from_data(Arena *arena, String8 gsi_data); + +static PDB_CoffSectionArray*pdb_coff_section_array_from_data(Arena *arena, + String8 section_data); + +static PDB_CompUnitArray* pdb_comp_unit_array_from_data(Arena *arena, + String8 module_info_data); + +static PDB_CompUnitContributionArray* +pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 seccontrib_data, + PDB_CoffSectionArray *sections); + +//////////////////////////////// +//~ PDB Definition Functions + +static U32 pdb_string_hash1(String8 string); + +//////////////////////////////// +//~ PDB Dbi Functions + +static String8 pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range); +static String8 pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit, + PDB_DbiCompUnitRange range); + +//////////////////////////////// +//~ PDB Tpi Functions + +static String8 pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi); + +static CV_TypeIdArray pdb_tpi_itypes_from_name(Arena *arena, + PDB_TpiHashParsed *tpi_hash, + CV_LeafParsed *tpi_leaf, + String8 name, + B32 compare_unique_name, + U32 output_cap); + +static CV_TypeId pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, + CV_LeafParsed *tpi_leaf, + String8 name, + B32 compare_unique_name); + +//////////////////////////////// +//~ PDB Strtbl Functions + +static String8 pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off); +static String8 pdb_strtbl_string_from_index(PDB_Strtbl *strtbl, + PDB_StringIndex idx); + +#endif //RADDBG_PDB_H diff --git a/src/raddbg_convert/pdb/raddbg_pdb_stringize.c b/src/raddbg_convert/pdb/raddbg_pdb_stringize.c new file mode 100644 index 00000000..a1726d28 --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_pdb_stringize.c @@ -0,0 +1,26 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ PDB Stringize Functions + +static void +pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash){ + U32 bucket_count = hash->bucket_count; + str8_list_pushf(arena, out, "bucket_count=%u\n\n", bucket_count); + for (U32 i = 0; i < bucket_count; i += 1){ + if (hash->buckets[i] != 0){ + str8_list_pushf(arena, out, "bucket[%u]:\n", i); + for (PDB_TpiHashBlock *block = hash->buckets[i]; + block != 0; + block = block->next){ + U32 local_count = block->local_count; + CV_TypeId *itype_ptr = block->itypes; + for (U32 j = 0; j < local_count; j += 1, itype_ptr += 1){ + str8_list_pushf(arena, out, " %u\n", *itype_ptr); + } + } + str8_list_push(arena, out, str8_lit("\n")); + } + } +} diff --git a/src/raddbg_convert/pdb/raddbg_pdb_stringize.h b/src/raddbg_convert/pdb/raddbg_pdb_stringize.h new file mode 100644 index 00000000..6b222afa --- /dev/null +++ b/src/raddbg_convert/pdb/raddbg_pdb_stringize.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_PDB_STRINGIZE_H +#define RADDBG_PDB_STRINGIZE_H + +//////////////////////////////// +//~ PDB Stringize Functions + +static void pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash); + +#endif //RADDBG_PDB_STRINGIZE_H diff --git a/src/raddbg_dump/raddbg_dump.c b/src/raddbg_dump/raddbg_dump.c new file mode 100644 index 00000000..96b42364 --- /dev/null +++ b/src/raddbg_dump/raddbg_dump.c @@ -0,0 +1,428 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "raddbg_format/raddbg_format.h" +#include "raddbg_format/raddbg_format_parse.h" +#include "raddbg_stringize.h" + +#include "raddbg_dump.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "raddbg_format/raddbg_format.c" +#include "raddbg_format/raddbg_format_parse.c" +#include "raddbg_stringize.c" + +//////////////////////////////// +//~ Program Parameters Parser + +static DUMP_Params* +dump_params_from_cmd_line(Arena *arena, CmdLine *cmdline){ + DUMP_Params *result = push_array(arena, DUMP_Params, 1); + + // get input raddbg + { + String8 input_name = cmd_line_string(cmdline, str8_lit("raddbg")); + if (input_name.size == 0){ + str8_list_push(arena, &result->errors, + str8_lit("missing required parameter '--raddbg:'")); + } + + if (input_name.size > 0){ + String8 input_data = os_data_from_file_path(arena, input_name); + + if (input_data.size == 0){ + str8_list_pushf(arena, &result->errors, + "could not load input file '%.*s'", str8_varg(input_name)); + } + + if (input_data.size != 0){ + result->input_name = input_name; + result->input_data = input_data; + } + } + } + + // error options + if (cmd_line_has_flag(cmdline, str8_lit("hide_errors"))){ + String8List vals = cmd_line_strings(cmdline, str8_lit("hide_errors")); + + // if no values - set all to hidden + if (vals.node_count == 0){ + B8 *ptr = (B8*)&result->hide_errors; + B8 *opl = ptr + sizeof(result->hide_errors); + for (;ptr < opl; ptr += 1){ + *ptr = 1; + } + } + + // for each explicit value set the corresponding flag to hidden + for (String8Node *node = vals.first; + node != 0; + node = node->next){ + if (str8_match(node->string, str8_lit("input"), 0)){ + result->hide_errors.input = 1; + } + } + } + + // dump options + { + String8List vals = cmd_line_strings(cmdline, str8_lit("dump")); + if (vals.first == 0){ + B8 *ptr = &result->dump__first; + for (; ptr < &result->dump__last; ptr += 1){ + *ptr = 1; + } + } + else{ + for (String8Node *node = vals.first; + node != 0; + node = node->next){ + if (str8_match(node->string, str8_lit("data_sections"), 0)){ + result->dump_data_sections = 1; + } + else if (str8_match(node->string, str8_lit("top_level_info"), 0)){ + result->dump_top_level_info = 1; + } + else if (str8_match(node->string, str8_lit("binary_sections"), 0)){ + result->dump_binary_sections = 1; + } + else if (str8_match(node->string, str8_lit("file_paths"), 0)){ + result->dump_file_paths = 1; + } + else if (str8_match(node->string, str8_lit("source_files"), 0)){ + result->dump_source_files = 1; + } + else if (str8_match(node->string, str8_lit("units"), 0)){ + result->dump_units = 1; + } + else if (str8_match(node->string, str8_lit("unit_vmap"), 0)){ + result->dump_unit_vmap = 1; + } + else if (str8_match(node->string, str8_lit("type_nodes"), 0)){ + result->dump_type_nodes = 1; + } + else if (str8_match(node->string, str8_lit("udt_data"), 0)){ + result->dump_udt_data = 1; + } + else if (str8_match(node->string, str8_lit("global_variables"), 0)){ + result->dump_global_variables = 1; + } + else if (str8_match(node->string, str8_lit("global_vmap"), 0)){ + result->dump_global_vmap = 1; + } + else if (str8_match(node->string, str8_lit("thread_variables"), 0)){ + result->dump_thread_variables = 1; + } + else if (str8_match(node->string, str8_lit("procedures"), 0)){ + result->dump_procedures = 1; + } + else if (str8_match(node->string, str8_lit("scopes"), 0)){ + result->dump_scopes = 1; + } + else if (str8_match(node->string, str8_lit("scope_vmap"), 0)){ + result->dump_scope_vmap = 1; + } + } + } + } + + return(result); +} + +//////////////////////////////// +//~ Entry Point + +int +main(int argc, char **argv){ + local_persist TCTX main_thread_tctx = {0}; + tctx_init_and_equip(&main_thread_tctx); + Arena *arena = arena_alloc(); + String8List args = os_string_list_from_argcv(arena, argc, argv); + CmdLine cmdline = cmd_line_from_string_list(arena, args); + + DUMP_Params *params = dump_params_from_cmd_line(arena, &cmdline); + + // show input errors + if (params->errors.node_count > 0 && + !params->hide_errors.input){ + for (String8Node *node = params->errors.first; + node != 0; + node = node->next){ + fprintf(stderr, "error(input): %.*s\n", str8_varg(node->string)); + } + } + + // will we try to parse an input file + B32 try_parse_input = (params->errors.node_count == 0); + + RADDBG_ParseStatus parse_status = RADDBG_ParseStatus_Good; + RADDBG_Parsed raddbg__ = {0}; + RADDBG_Parsed *raddbg = 0; + if (try_parse_input){ + parse_status = raddbg_parse(params->input_data.str, params->input_data.size, &raddbg__); + if (parse_status == RADDBG_ParseStatus_Good){ + raddbg = &raddbg__; + } + } + + if (raddbg == 0){ + // TODO(allen): improve this by looking at parse status. + fprintf(stderr, "error(parsing): error trying to parse the input file\n"); + } + + // dump + { + String8List dump = {0}; + + // DATA SECTIONS + if (raddbg->dsecs != 0 && params->dump_data_sections){ + str8_list_pushf(arena, &dump, "# DATA SECTIONS:\n"); + raddbg_stringize_data_sections(arena, &dump, raddbg, 1); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // TOP LEVEL INFO + if (raddbg->top_level_info != 0 && params->dump_top_level_info){ + str8_list_pushf(arena, &dump, "# TOP LEVEL INFO:\n"); + raddbg_stringize_top_level_info(arena, &dump, raddbg, raddbg->top_level_info, 1); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // BINARY SECTIONS + if (raddbg->binary_sections != 0 && params->dump_binary_sections){ + str8_list_pushf(arena, &dump, "# BINARY SECTIONS:\n"); + RADDBG_BinarySection *ptr = raddbg->binary_sections; + for (U32 i = 0; i < raddbg->binary_section_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " section[%u]:\n", i); + raddbg_stringize_binary_section(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // FILE PATHS + if (raddbg->file_paths != 0 && params->dump_file_paths){ + RADDBG_FilePathBundle file_path_bundle = {0}; + { + file_path_bundle.file_paths = raddbg->file_paths; + file_path_bundle.file_path_count = raddbg->file_path_count; + } + + str8_list_pushf(arena, &dump, "# FILE PATHS\n"); + RADDBG_FilePathNode *ptr = raddbg->file_paths; + for (U32 i = 0; i < raddbg->file_path_count; i += 1, ptr += 1){ + if (ptr->parent_path_node == 0){ + raddbg_stringize_file_path(arena, &dump, raddbg, &file_path_bundle, ptr, 1); + } + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // SOURCE FILES + if (raddbg->source_files != 0 && params->dump_source_files){ + str8_list_pushf(arena, &dump, "# SOURCE FILES\n"); + RADDBG_SourceFile *ptr = raddbg->source_files; + for (U32 i = 0; i < raddbg->source_file_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " source_file[%u]:\n", i); + raddbg_stringize_source_file(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // UNITS + if (raddbg->units != 0 && params->dump_units){ + str8_list_pushf(arena, &dump, "# UNITS\n"); + RADDBG_Unit *ptr = raddbg->units; + for (U32 i = 0; i < raddbg->unit_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + raddbg_stringize_unit(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // UNIT VMAP + if (raddbg->unit_vmap != 0 && params->dump_unit_vmap){ + str8_list_pushf(arena, &dump, "# UNIT VMAP\n"); + RADDBG_VMapEntry *ptr = raddbg->unit_vmap; + for (U32 i = 0; i < raddbg->unit_vmap_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // TYPE NODES + if (raddbg->type_nodes != 0 && params->dump_type_nodes){ + str8_list_pushf(arena, &dump, "# TYPE NODES:\n"); + RADDBG_TypeNode *ptr = raddbg->type_nodes; + for (U32 i = 0; i < raddbg->type_node_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " type[%u]:\n", i); + raddbg_stringize_type_node(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // UDT DATA + if (raddbg->udts != 0 && params->dump_udt_data){ + RADDBG_UDTMemberBundle member_bundle = {0}; + { + member_bundle.members = raddbg->members; + member_bundle.enum_members = raddbg->enum_members; + member_bundle.member_count = raddbg->member_count; + member_bundle.enum_member_count = raddbg->enum_member_count; + } + + str8_list_pushf(arena, &dump, "# UDTS:\n"); + RADDBG_UDT *ptr = raddbg->udts; + for (U32 i = 0; i < raddbg->udt_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " udt[%u]:\n", i); + raddbg_stringize_udt(arena, &dump, raddbg, &member_bundle, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // GLOBAL VARIABLES + if (raddbg->global_variables != 0 && params->dump_global_variables){ + str8_list_pushf(arena, &dump, "# GLOBAL VARIABLES:\n"); + RADDBG_GlobalVariable *ptr = raddbg->global_variables; + for (U32 i = 0; i < raddbg->global_variable_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " global_variable[%u]:\n", i); + raddbg_stringize_global_variable(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // GLOBAL VMAP + if (raddbg->global_vmap != 0 && params->dump_global_vmap){ + str8_list_pushf(arena, &dump, "# GLOBAL VMAP:\n"); + RADDBG_VMapEntry *ptr = raddbg->global_vmap; + for (U32 i = 0; i < raddbg->global_vmap_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // THREAD LOCAL VARIABLES + if (raddbg->thread_variables != 0 && params->dump_thread_variables){ + str8_list_pushf(arena, &dump, "# THREAD VARIABLES:\n"); + RADDBG_ThreadVariable *ptr = raddbg->thread_variables; + for (U32 i = 0; i < raddbg->thread_variable_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " thread_variable[%u]:\n", i); + raddbg_stringize_thread_variable(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // PROCEDURES + if (raddbg->procedures != 0 && params->dump_procedures){ + str8_list_pushf(arena, &dump, "# PROCEDURES:\n"); + RADDBG_Procedure *ptr = raddbg->procedures; + for (U32 i = 0; i < raddbg->procedure_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " procedure[%u]:\n", i); + raddbg_stringize_procedure(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // SCOPES + if (raddbg->scopes != 0 && params->dump_scopes){ + RADDBG_ScopeBundle scope_bundle = {0}; + { + scope_bundle.scopes = raddbg->scopes; + scope_bundle.scope_count = raddbg->scope_count; + scope_bundle.scope_voffs = raddbg->scope_voffs; + scope_bundle.scope_voff_count = raddbg->scope_voff_count; + scope_bundle.locals = raddbg->locals; + scope_bundle.local_count = raddbg->local_count; + scope_bundle.location_blocks = raddbg->location_blocks; + scope_bundle.location_block_count = raddbg->location_block_count; + scope_bundle.location_data = raddbg->location_data; + scope_bundle.location_data_size = raddbg->location_data_size; + } + + str8_list_pushf(arena, &dump, "# SCOPES:\n"); + RADDBG_Scope *ptr = raddbg->scopes; + for (U32 i = 0; i < raddbg->scope_count; i += 1, ptr += 1){ + if (ptr->parent_scope_idx == 0){ + raddbg_stringize_scope(arena, &dump, raddbg, &scope_bundle, ptr, 1); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // SCOPE VMAP + if (raddbg->scope_vmap != 0 && params->dump_scope_vmap){ + str8_list_pushf(arena, &dump, "# SCOPE VMAP:\n"); + RADDBG_VMapEntry *ptr = raddbg->scope_vmap; + for (U32 i = 0; i < raddbg->scope_vmap_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // NAME MAPS + if (raddbg->name_maps != 0 && params->dump_name_map){ + str8_list_pushf(arena, &dump, "# NAME MAP:\n"); + RADDBG_NameMap *ptr = raddbg->name_maps; + for (U32 i = 0; i < raddbg->name_map_count; i += 1, ptr += 1){ + str8_list_pushf(arena, &dump, " name_map[%u]:\n", i); + + RADDBG_ParsedNameMap name_map = {0}; + raddbg_name_map_parse(raddbg, ptr, &name_map); + + RADDBG_NameMapBucket *bucket = name_map.buckets; + for (U32 j = 0; j < name_map.bucket_count; j += 1, bucket += 1){ + if (bucket->node_count > 0){ + str8_list_pushf(arena, &dump, " bucket[%u]:\n", j); + RADDBG_NameMapNode *node = name_map.nodes + bucket->first_node; + RADDBG_NameMapNode *node_opl = node + bucket->node_count; + for (; node < node_opl; node += 1){ + String8 string = {0}; + string.str = raddbg_string_from_idx(raddbg, node->string_idx, &string.size); + str8_list_pushf(arena, &dump, " match \"%.*s\": ", str8_varg(string)); + if (node->match_count == 1){ + str8_list_pushf(arena, &dump, "%u", node->match_idx_or_idx_run_first); + } + else{ + RADDBG_U32 idx_count = 0; + RADDBG_U32 *idx_run = + raddbg_idx_run_from_first_count(raddbg, node->match_idx_or_idx_run_first, + node->match_count, &idx_count); + if (idx_count > 0){ + RADDBG_U32 last = idx_count - 1; + for (U32 k = 0; k < last; k += 1){ + str8_list_pushf(arena, &dump, "%u, ", idx_run[k]); + } + str8_list_pushf(arena, &dump, "%u", idx_run[last]); + } + } + str8_list_pushf(arena, &dump, "\n"); + } + } + } + + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + // print dump + for(String8Node *node = dump.first; node != 0; node = node->next) + { + fwrite(node->string.str, 1, node->string.size, stdout); + } + } + + return(0); +} diff --git a/src/raddbg_dump/raddbg_dump.h b/src/raddbg_dump/raddbg_dump.h new file mode 100644 index 00000000..62ca2ce4 --- /dev/null +++ b/src/raddbg_dump/raddbg_dump.h @@ -0,0 +1,45 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_DUMP_H +#define RADDBG_DUMP_H + +//////////////////////////////// +//~ Program Parameters Type + +typedef struct DUMP_Params{ + String8 input_name; + String8 input_data; + + struct{ + B8 input; + } hide_errors; + + B8 dump__first; + B8 dump_data_sections; + B8 dump_top_level_info; + B8 dump_binary_sections; + B8 dump_file_paths; + B8 dump_source_files; + B8 dump_units; + B8 dump_unit_vmap; + B8 dump_type_nodes; + B8 dump_udt_data; + B8 dump_global_variables; + B8 dump_global_vmap; + B8 dump_thread_variables; + B8 dump_procedures; + B8 dump_scopes; + B8 dump_scope_vmap; + B8 dump_name_map; + B8 dump__last; + + String8List errors; +} DUMP_Params; + +//////////////////////////////// +//~ Program Parameters Parser + +static DUMP_Params *dump_params_from_cmd_line(Arena *arena, CmdLine *cmdline); + +#endif //RADDBG_DUMP_H diff --git a/src/raddbg_dump/raddbg_stringize.c b/src/raddbg_dump/raddbg_stringize.c new file mode 100644 index 00000000..6bc06597 --- /dev/null +++ b/src/raddbg_dump/raddbg_stringize.c @@ -0,0 +1,776 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ RADDBG Common Stringize Functions + +static String8 +raddbg_string_from_data_section_tag(RADDBG_DataSectionTag tag){ + String8 result = {0}; + switch (tag){ +#define X(N,C) case C: result = str8_lit(#N); break; +#define Y(N) + RADDBG_DataSectionTagXList(X,Y) +#undef X +#undef Y + } + return(result); +} + +static String8 +raddbg_string_from_arch(RADDBG_Arch arch){ + String8 result = {0}; + switch (arch){ + default: result = str8_lit(""); break; + case RADDBG_Arch_X86: result = str8_lit("x86"); break; + case RADDBG_Arch_X64: result = str8_lit("x64"); break; + } + return(result); +} + +static String8 +raddbg_string_from_language(RADDBG_Language language){ + String8 result = {0}; + switch (language){ +#define X(name,code) case code: result = str8_lit(#name); break; + RADDBG_LanguageXList(X) +#undef X + } + return(result); +} + +static String8 +raddbg_string_from_type_kind(RADDBG_TypeKind type_kind){ + String8 result = {0}; + switch (type_kind){ + default: result = str8_lit(""); break; +#define X(name,code) case code: result = str8_lit(#name); break; +#define XZ(name,code,size) X(name,code) +#define Y(a,n) + RADDBG_TypeKindXList(X,XZ,Y) +#undef X +#undef XZ +#undef Y + } + return(result); +} + +static String8 +raddbg_string_from_member_kind(RADDBG_MemberKind member_kind){ + String8 result = {0}; + switch (member_kind){ + default: result = str8_lit(""); break; +#define X(N,C) case C: result = str8_lit(#N); break; + RADDBG_MemberKindXList(X) +#undef X + } + return(result); +} + +static String8 +raddbg_string_from_local_kind(RADDBG_LocalKind local_kind){ + String8 result = {0}; + switch (local_kind){ + default: result = str8_lit(""); break; + case RADDBG_LocalKind_Parameter: result = str8_lit("Parameter"); break; + case RADDBG_LocalKind_Variable: result = str8_lit("Variable"); break; + } + return(result); +} + + +//////////////////////////////// +//~ RADDBG Flags Stringize Functions + +static void +raddbg_stringize_binary_section_flags(Arena *arena, String8List *out, + RADDBG_BinarySectionFlags flags){ + if (flags == 0){ + str8_list_push(arena, out, str8_lit("0")); + } + if (flags & RADDBG_BinarySectionFlag_Read){ + str8_list_push(arena, out, str8_lit("Read ")); + } + if (flags & RADDBG_BinarySectionFlag_Write){ + str8_list_push(arena, out, str8_lit("Write ")); + } + if (flags & RADDBG_BinarySectionFlag_Execute){ + str8_list_push(arena, out, str8_lit("Execute ")); + } +} + +static void +raddbg_stringize_type_modifier_flags(Arena *arena, String8List *out, + RADDBG_TypeModifierFlags flags){ + if (flags == 0){ + str8_list_push(arena, out, str8_lit("0")); + } + if (flags & RADDBG_TypeModifierFlag_Const){ + str8_list_push(arena, out, str8_lit("Const ")); + } + if (flags & RADDBG_TypeModifierFlag_Volatile){ + str8_list_push(arena, out, str8_lit("Volatile ")); + } +} + +static void +raddbg_stringize_user_defined_type_flags(Arena *arena, String8List *out, + RADDBG_UserDefinedTypeFlags flags){ + if (flags == 0){ + str8_list_push(arena, out, str8_lit("0")); + } + if (flags & RADDBG_UserDefinedTypeFlag_EnumMembers){ + str8_list_push(arena, out, str8_lit("EnumMembers ")); + } +} + +static void +raddbg_stringize_link_flags(Arena *arena, String8List *out, RADDBG_LinkFlags flags){ + if (flags == 0){ + str8_list_push(arena, out, str8_lit("0")); + } + if (flags & RADDBG_LinkFlag_External){ + str8_list_push(arena, out, str8_lit("External ")); + } + if (flags & RADDBG_LinkFlag_TypeScoped){ + str8_list_push(arena, out, str8_lit("TypeScoped ")); + } + if (flags & RADDBG_LinkFlag_ProcScoped){ + str8_list_push(arena, out, str8_lit("ProcScoped ")); + } +} + + +//////////////////////////////// +//~ RADDBG Compound Stringize Functions + +static char raddbg_stringize_spaces[] = " "; + +static void +raddbg_stringize_data_sections(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + U32 indent_level){ + U64 data_section_count = parsed->dsec_count; + RADDBG_DataSection *ptr = parsed->dsecs; + for (U64 i = 0; i < data_section_count; i += 1, ptr += 1){ + String8 tag_str = raddbg_string_from_data_section_tag(ptr->tag); + str8_list_pushf(arena, out, "%.*sdata_section[%5u] = {0x%08llx, %7u, %7u} %.*s\n", + indent_level, raddbg_stringize_spaces, + i, ptr->off, ptr->encoded_size, ptr->unpacked_size, str8_varg(tag_str)); + } +} + +static void +raddbg_stringize_top_level_info(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_TopLevelInfo *tli, U32 indent_level){ + String8 arch_str = raddbg_string_from_arch(tli->architecture); + String8 exe_name = {0}; + exe_name.str = raddbg_string_from_idx(parsed, tli->exe_name_string_idx, &exe_name.size); + + str8_list_pushf(arena, out, "%.*sarchitecture=%.*s\n", + indent_level, raddbg_stringize_spaces, str8_varg(arch_str)); + str8_list_pushf(arena, out, "%.*sexe_name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(exe_name)); + str8_list_pushf(arena, out, "%.*svoff_max=0x%08llx\n", + indent_level, raddbg_stringize_spaces, tli->voff_max); +} + +static void +raddbg_stringize_binary_section(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_BinarySection *bin_section, U32 indent_level){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, bin_section->name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*sname='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + + str8_list_pushf(arena, out, "%.*sflags=", indent_level, raddbg_stringize_spaces); + raddbg_stringize_binary_section_flags(arena, out, bin_section->flags); + str8_list_pushf(arena, out, "\n"); + + str8_list_pushf(arena, out, "%.*svoff_first=0x%08x\n", + indent_level, raddbg_stringize_spaces, bin_section->voff_first); + str8_list_pushf(arena, out, "%.*svoff_opl =0x%08x\n", + indent_level, raddbg_stringize_spaces, bin_section->voff_opl); + str8_list_pushf(arena, out, "%.*sfoff_first=0x%08x\n", + indent_level, raddbg_stringize_spaces, bin_section->foff_first); + str8_list_pushf(arena, out, "%.*sfoff_opl =0x%08x\n", + indent_level, raddbg_stringize_spaces, bin_section->foff_opl); +} + +static void +raddbg_stringize_file_path(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_FilePathBundle *bundle, RADDBG_FilePathNode *file_path, + U32 indent_level){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, file_path->name_string_idx, &name.size); + + U32 this_idx = (U32)(file_path - bundle->file_paths); + + if (file_path->source_file_idx == 0){ + str8_list_pushf(arena, out, "%.*s[%u] '%.*s'\n", + indent_level, raddbg_stringize_spaces, + this_idx, str8_varg(name)); + } + else{ + str8_list_pushf(arena, out, "%.*s[%u] '%.*s'; source_file=%u\n", + indent_level, raddbg_stringize_spaces, + this_idx, str8_varg(name), file_path->source_file_idx); + } + + for (U32 child = file_path->first_child; + child != 0;){ + // get node for child + RADDBG_FilePathNode *child_node = 0; + if (child < bundle->file_path_count){ + child_node = bundle->file_paths + child; + } + if (child_node == 0){ + break; + } + + // stringize child + raddbg_stringize_file_path(arena, out, parsed, bundle, child_node, indent_level + 1); + + // increment iterator + child = child_node->next_sibling; + } +} + +static void +raddbg_stringize_source_file(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_SourceFile *source_file, U32 indent_level){ + // extract line map data + RADDBG_ParsedLineMap line_map = {0}; + raddbg_line_map_from_source_file(parsed, source_file, &line_map); + + // stringize line map data + str8_list_pushf(arena, out, "%.*slines:\n", indent_level, raddbg_stringize_spaces); + + for (U32 i = 0; i < line_map.count; i += 1){ + U32 line_num = line_map.nums[i]; + + U32 digit_count = 1; + if (line_num > 0){ + U32 x = line_num; + for (;;){ + x /= 10; + if (x == 0){ + break; + } + digit_count += 1; + } + } + + str8_list_pushf(arena, out, "%.*s %u: ", + indent_level, raddbg_stringize_spaces, line_num); + + U32 first = line_map.ranges[i]; + U32 opl_raw = line_map.ranges[i + 1]; + U32 opl = ClampTop(opl_raw, line_map.voff_count); + for (U32 j = first; j < opl; j += 1){ + if (j == first){ + str8_list_pushf(arena, out, "0x%08x\n", line_map.voffs[j]); + } + else{ + str8_list_pushf(arena, out, "%.*s0x%08x\n", + indent_level + digit_count + 3, raddbg_stringize_spaces, + line_map.voffs[j]); + } + } + } +} + +static void +raddbg_stringize_unit(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_Unit *unit, U32 indent_level){ + String8 unit_name = {0}; + unit_name.str = raddbg_string_from_idx(parsed, unit->unit_name_string_idx, &unit_name.size); + String8 compiler_name = {0}; + compiler_name.str = raddbg_string_from_idx(parsed, unit->compiler_name_string_idx, + &compiler_name.size); + + str8_list_pushf(arena, out, "%.*sunit_name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(unit_name)); + str8_list_pushf(arena, out, "%.*scompiler_name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(compiler_name)); + + str8_list_pushf(arena, out, "%.*ssource_file_path=%u\n", + indent_level, raddbg_stringize_spaces, unit->source_file_path_node); + str8_list_pushf(arena, out, "%.*sobject_file_path=%u\n", + indent_level, raddbg_stringize_spaces, unit->object_file_path_node); + str8_list_pushf(arena, out, "%.*sarchive_file_path=%u\n", + indent_level, raddbg_stringize_spaces, unit->archive_file_path_node); + str8_list_pushf(arena, out, "%.*sbuild_path=%u\n", + indent_level, raddbg_stringize_spaces, unit->build_path_node); + + String8 language_str = raddbg_string_from_language(unit->language); + str8_list_pushf(arena, out, "%.*slanguage=%.*s\n", + indent_level, raddbg_stringize_spaces, str8_varg(language_str)); + + // extract line info data + RADDBG_ParsedLineInfo line_info = {0}; + raddbg_line_info_from_unit(parsed, unit, &line_info); + + + // stringize line info + str8_list_pushf(arena, out, "%.*slines:\n", indent_level, raddbg_stringize_spaces); + + for (U32 i = 0; i < line_info.count; i += 1){ + U64 first = line_info.voffs[i]; + U64 opl = line_info.voffs[i + 1]; + RADDBG_Line *line = line_info.lines + i; + RADDBG_Column *col = 0; + if (i < line_info.col_count){ + col = line_info.cols + i; + } + + if (col == 0){ + str8_list_pushf(arena, out, "%.*s [0x%08llx,0x%08llx) file=%u; line=%u\n", + indent_level, raddbg_stringize_spaces, + first, opl, line->file_idx, line->line_num); + } + else{ + str8_list_pushf(arena, out, "%.*s [0x%08llx,0x%08llx) file=%u; line=%u; columns=[%u,%u)\n", + indent_level, raddbg_stringize_spaces, + first, opl, line->file_idx, line->line_num, + col->col_first, col->col_opl); + } + } +} + +static void +raddbg_stringize_type_node(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_TypeNode *type, U32 indent_level){ + RADDBG_TypeKind kind = type->kind; + String8 type_kind_str = raddbg_string_from_type_kind(kind); + + str8_list_pushf(arena, out, "%.*skind=%.*s\n", + indent_level, raddbg_stringize_spaces, str8_varg(type_kind_str)); + + switch (type->kind){ + case RADDBG_TypeKind_Modifier: + { + str8_list_pushf(arena, out, "%.*sflags=", indent_level, raddbg_stringize_spaces); + raddbg_stringize_type_modifier_flags(arena, out, type->flags); + str8_list_push(arena, out, str8_lit("\n")); + }break; + + default: + { + if (type->flags != 0){ + str8_list_pushf(arena, out, "%.*sflags=%x (missing stringizer path)", + indent_level, raddbg_stringize_spaces, type->flags); + } + }break; + } + + str8_list_pushf(arena, out, "%.*sbyte_size=%u\n", + indent_level, raddbg_stringize_spaces, type->byte_size); + + if (RADDBG_TypeKind_FirstBuiltIn <= kind && + kind <= RADDBG_TypeKind_LastBuiltIn){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, type->built_in.name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*sbuilt_in.name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + } + + else if (RADDBG_TypeKind_FirstConstructed <= kind && + kind <= RADDBG_TypeKind_LastConstructed){ + str8_list_pushf(arena, out, "%.*sconstructed.direct_type=%u\n", + indent_level, raddbg_stringize_spaces, type->constructed.direct_type_idx); + + if (type->kind == RADDBG_TypeKind_Array){ + str8_list_pushf(arena, out, "%.*sconstructed.array_count=%u\n", + indent_level, raddbg_stringize_spaces, type->constructed.count); + } + + if (type->kind == RADDBG_TypeKind_Function || + type->kind == RADDBG_TypeKind_Method){ + U32 run_first = type->constructed.param_idx_run_first; + U32 run_count_raw = type->constructed.count; + + U32 run_count = 0; + U32 *run = raddbg_idx_run_from_first_count(parsed, run_first, run_count_raw, &run_count); + + U32 this_type_idx = 0; + if (run_count > 0 && type->kind == RADDBG_TypeKind_Method){ + this_type_idx = run[0]; + run += 1; + run_count -= 1; + } + + if (this_type_idx != 0){ + str8_list_pushf(arena, out, "%.*sconstructed.this_type=%u\n", + indent_level, raddbg_stringize_spaces, this_type_idx); + } + + str8_list_pushf(arena, out, "%.*sconstructed.params={", + indent_level, raddbg_stringize_spaces); + + if (run_count > 0){ + U32 last = run_count - 1; + for (U32 j = 0; j < last; j += 1){ + str8_list_pushf(arena, out, " %u,", run[j]); + } + str8_list_pushf(arena, out, " %u ", run[last]); + } + + str8_list_push(arena, out, str8_lit("}\n")); + } + } + + else if (RADDBG_TypeKind_FirstUserDefined <= kind && + kind <= RADDBG_TypeKind_LastUserDefined){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, type->user_defined.name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*suser_defined.name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + str8_list_pushf(arena, out, "%.*suser_defined.direct_type=%u\n", + indent_level, raddbg_stringize_spaces, + type->user_defined.direct_type_idx); + str8_list_pushf(arena, out, "%.*suser_defined.udt=%u\n", + indent_level, raddbg_stringize_spaces, + type->user_defined.udt_idx); + } + + else if (kind == RADDBG_TypeKind_Bitfield){ + str8_list_pushf(arena, out, "%.*sbitfield.off=%u\n", + indent_level, raddbg_stringize_spaces, type->bitfield.off); + str8_list_pushf(arena, out, "%.*sbitfield.size=%u\n", + indent_level, raddbg_stringize_spaces, type->bitfield.size); + } +} + +static void +raddbg_stringize_udt(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_UDTMemberBundle *member_bundle, RADDBG_UDT *udt, + U32 indent_level){ + str8_list_pushf(arena, out, "%.*sself_type=%u\n", + indent_level, raddbg_stringize_spaces, udt->self_type_idx); + + str8_list_pushf(arena, out, "%.*sflags=", indent_level, raddbg_stringize_spaces); + raddbg_stringize_user_defined_type_flags(arena, out, udt->flags); + str8_list_push(arena, out, str8_lit("\n")); + + if (udt->file_idx != 0){ + str8_list_pushf(arena, out, "%.*sloc={file=%u; line=%u; col=%u}\n", + indent_level, raddbg_stringize_spaces, + udt->file_idx, udt->line, udt->col); + } + + // enum members + if (udt->flags & RADDBG_UserDefinedTypeFlag_EnumMembers){ + U32 first_raw = udt->member_first; + U32 opl_raw = first_raw + udt->member_count; + U32 opl = ClampTop(opl_raw, member_bundle->enum_member_count); + U32 first = ClampTop(first_raw, opl); + + if (first < opl){ + str8_list_pushf(arena, out, "%.*smembers={\n", indent_level, raddbg_stringize_spaces); + RADDBG_EnumMember *enum_member = member_bundle->enum_members + first; + for (U32 i = first; i < opl; i += 1, enum_member += 1){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, enum_member->name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*s '%.*s' %llu\n", + indent_level, raddbg_stringize_spaces, + str8_varg(name), enum_member->val); + } + str8_list_pushf(arena, out, "%.*s}\n", indent_level, raddbg_stringize_spaces); + } + } + + // field members + else{ + U32 first_raw = udt->member_first; + U32 opl_raw = first_raw + udt->member_count; + U32 opl = ClampTop(opl_raw, member_bundle->member_count); + U32 first = ClampTop(first_raw, opl); + + if (first < opl){ + str8_list_pushf(arena, out, "%.*smembers={\n", indent_level, raddbg_stringize_spaces); + RADDBG_Member *member = member_bundle->members + first; + for (U32 i = first; i < opl; i += 1, member += 1){ + str8_list_pushf(arena, out, "%.*s {\n", indent_level, raddbg_stringize_spaces); + + String8 kind_str = raddbg_string_from_member_kind(member->kind); + str8_list_pushf(arena, out, "%.*s kind=%.*s\n", + indent_level, raddbg_stringize_spaces, str8_varg(kind_str)); + + if (member->name_string_idx != 0){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, member->name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*s name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + } + + str8_list_pushf(arena, out, "%.*s type=%u\n", + indent_level, raddbg_stringize_spaces, member->type_idx); + str8_list_pushf(arena, out, "%.*s off=%u\n", + indent_level, raddbg_stringize_spaces, member->off); + + str8_list_pushf(arena, out, "%.*s }\n", indent_level, raddbg_stringize_spaces); + } + str8_list_pushf(arena, out, "%.*s}\n", indent_level, raddbg_stringize_spaces); + } + } +} + +static void +raddbg_stringize_global_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_GlobalVariable *global_variable, U32 indent_level){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, global_variable->name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*sname='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + + str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, raddbg_stringize_spaces); + raddbg_stringize_link_flags(arena, out, global_variable->link_flags); + str8_list_push(arena, out, str8_lit("\n")); + + str8_list_pushf(arena, out, "%.*svoff=0x%08llx\n", + indent_level, raddbg_stringize_spaces, global_variable->voff); + + str8_list_pushf(arena, out, "%.*stype_idx=%u\n", + indent_level, raddbg_stringize_spaces, global_variable->type_idx); + + str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", + indent_level, raddbg_stringize_spaces, global_variable->container_idx); +} + +static void +raddbg_stringize_thread_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_ThreadVariable *thread_var, + U32 indent_level){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, thread_var->name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*sname='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + + str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, raddbg_stringize_spaces); + raddbg_stringize_link_flags(arena, out, thread_var->link_flags); + str8_list_push(arena, out, str8_lit("\n")); + + str8_list_pushf(arena, out, "%.*stls_off=0x%08x\n", + indent_level, raddbg_stringize_spaces, thread_var->tls_off); + + str8_list_pushf(arena, out, "%.*stype_idx=%u\n", + indent_level, raddbg_stringize_spaces, thread_var->type_idx); + + str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", + indent_level, raddbg_stringize_spaces, thread_var->container_idx); +} + +static void +raddbg_stringize_procedure(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_Procedure *proc, U32 indent_level){ + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, proc->name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*sname='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + + String8 link_name = {0}; + link_name.str = raddbg_string_from_idx(parsed, proc->link_name_string_idx, &link_name.size); + str8_list_pushf(arena, out, "%.*slink_name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(link_name)); + + str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, raddbg_stringize_spaces); + raddbg_stringize_link_flags(arena, out, proc->link_flags); + str8_list_push(arena, out, str8_lit("\n")); + + str8_list_pushf(arena, out, "%.*stype_idx=%u\n", + indent_level, raddbg_stringize_spaces, proc->type_idx); + + str8_list_pushf(arena, out, "%.*sroot_scope_idx=%u\n", + indent_level, raddbg_stringize_spaces, proc->root_scope_idx); + + str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", + indent_level, raddbg_stringize_spaces, proc->container_idx); +} + +static void +raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_ScopeBundle *bundle, RADDBG_Scope *scope, U32 indent_level){ + + U32 this_idx = (U32)(scope - bundle->scopes); + + str8_list_pushf(arena, out, "%.*s[%u]\n", + indent_level, raddbg_stringize_spaces, this_idx); + + str8_list_pushf(arena, out, "%.*s proc_idx=%u\n", + indent_level, raddbg_stringize_spaces, scope->proc_idx); + + // voff ranges + { + U32 voff_range_first_raw = scope->voff_range_first; + U32 voff_range_opl_raw = scope->voff_range_opl; + U32 voff_range_opl_clamped = ClampTop(voff_range_opl_raw, bundle->scope_voff_count); + U32 voff_range_first = ClampTop(voff_range_first_raw, voff_range_opl_clamped); + U32 voff_range_opl = voff_range_opl_clamped; + if ((voff_range_opl - voff_range_first) % 2 == 1){ + voff_range_opl -= 1; + } + + U64 *voff_ptr = bundle->scope_voffs + voff_range_first; + + if (voff_range_opl - voff_range_first > 2){ + str8_list_pushf(arena, out, "%.*s voff_ranges={\n", + indent_level, raddbg_stringize_spaces); + for (U32 i = voff_range_first; i < voff_range_opl; i += 2, voff_ptr += 2){ + str8_list_pushf(arena, out, "%.*s [0x%08llx, 0x%08llx)\n", + indent_level, raddbg_stringize_spaces, + voff_ptr[0], voff_ptr[1]); + } + str8_list_pushf(arena, out, "%.*s }\n", + indent_level, raddbg_stringize_spaces); + } + else if (voff_range_opl - voff_range_first == 2){ + str8_list_pushf(arena, out, "%.*s voff_range=[0x%08llx, 0x%08llx)\n", + indent_level, raddbg_stringize_spaces, + voff_ptr[0], voff_ptr[1]); + } + } + + // locals + { + U32 local_first = scope->local_first; + U32 local_opl_raw = local_first + scope->local_count; + U32 local_opl = ClampTop(local_opl_raw, bundle->local_count); + + if (local_first < local_opl){ + RADDBG_Local *local_ptr = bundle->locals + local_first; + for (U32 i = local_first; i < local_opl; i += 1, local_ptr += 1){ + str8_list_pushf(arena, out, "%.*s local[%u]\n", + indent_level, raddbg_stringize_spaces, i); + + String8 local_kind_str = raddbg_string_from_local_kind(local_ptr->kind); + str8_list_pushf(arena, out, "%.*s kind=%.*s\n", + indent_level, raddbg_stringize_spaces, str8_varg(local_kind_str)); + + String8 name = {0}; + name.str = raddbg_string_from_idx(parsed, local_ptr->name_string_idx, &name.size); + str8_list_pushf(arena, out, "%.*s name='%.*s'\n", + indent_level, raddbg_stringize_spaces, str8_varg(name)); + + str8_list_pushf(arena, out, "%.*s type_idx=%u\n", + indent_level, raddbg_stringize_spaces, local_ptr->type_idx); + + U32 location_first = local_ptr->location_first; + U32 location_opl_raw = local_ptr->location_opl; + U32 location_opl = ClampTop(location_opl_raw, bundle->location_block_count); + + if (location_first < location_opl){ + str8_list_pushf(arena, out, "%.*s locations:\n", indent_level, raddbg_stringize_spaces); + RADDBG_LocationBlock *block_ptr = bundle->location_blocks + location_first; + for (U32 j = location_first; j < location_opl; j += 1, block_ptr += 1){ + if (block_ptr->scope_off_first == 0 && block_ptr->scope_off_opl == max_U32){ + str8_list_pushf(arena, out, "%.*s case *always*:\n", indent_level, raddbg_stringize_spaces); + } + else{ + str8_list_pushf(arena, out, "%.*s case [0x%08x, 0x%08x):\n", + indent_level, raddbg_stringize_spaces, + block_ptr->scope_off_first, block_ptr->scope_off_opl); + } + + if (block_ptr->location_data_off >= bundle->location_data_size){ + str8_list_pushf(arena, out, "%.*s \n", + indent_level, raddbg_stringize_spaces); + } + else{ + str8_list_pushf(arena, out, "%.*s ", indent_level, raddbg_stringize_spaces); + + U8 *loc_data_opl = bundle->location_data + bundle->location_data_size; + U8 *loc_base_ptr = bundle->location_data + block_ptr->location_data_off; + RADDBG_LocationKind kind = (RADDBG_LocationKind)*loc_base_ptr; + switch (kind){ + default: + { + str8_list_pushf(arena, out, "\n"); + }break; + + case RADDBG_LocationKind_AddrBytecodeStream: + { + str8_list_pushf(arena, out, "AddrBytecodeStream\n"); + str8_list_pushf(arena, out, "%.*s ", indent_level, raddbg_stringize_spaces); + U8 *bytecode_ptr = loc_base_ptr + 1; + for (;bytecode_ptr < loc_data_opl && *bytecode_ptr != 0; bytecode_ptr += 1){ + str8_list_pushf(arena, out, "%02x ", *bytecode_ptr); + } + str8_list_pushf(arena, out, "\n"); + }break; + + case RADDBG_LocationKind_ValBytecodeStream: + { + str8_list_pushf(arena, out, "ValBytecodeStream\n"); + str8_list_pushf(arena, out, "%.*s ", indent_level, raddbg_stringize_spaces); + U8 *bytecode_ptr = loc_base_ptr + 1; + for (;bytecode_ptr < loc_data_opl && *bytecode_ptr != 0; bytecode_ptr += 1){ + str8_list_pushf(arena, out, "%02x ", *bytecode_ptr); + } + str8_list_pushf(arena, out, "\n"); + }break; + + case RADDBG_LocationKind_AddrRegisterPlusU16: + { + if (loc_base_ptr + sizeof(RADDBG_LocationRegisterPlusU16) > loc_data_opl){ + str8_list_pushf(arena, out, "AddrRegisterPlusU16( )\n"); + } + else{ + RADDBG_LocationRegisterPlusU16 *loc = (RADDBG_LocationRegisterPlusU16*)loc_base_ptr; + str8_list_pushf(arena, out, "AddrRegisterPlusU16(reg: %u, off: %u)\n", + loc->register_code, loc->offset); + } + }break; + + case RADDBG_LocationKind_AddrAddrRegisterPlusU16: + { + if (loc_base_ptr + sizeof(RADDBG_LocationRegisterPlusU16) > loc_data_opl){ + str8_list_pushf(arena, out, "AddrAddrRegisterPlusU16( )\n"); + } + else{ + RADDBG_LocationRegisterPlusU16 *loc = (RADDBG_LocationRegisterPlusU16*)loc_base_ptr; + str8_list_pushf(arena, out, "AddrAddrRegisterPlusU16(reg: %u, off: %u)\n", + loc->register_code, loc->offset); + } + }break; + + case RADDBG_LocationKind_ValRegister: + { + if (loc_base_ptr + sizeof(RADDBG_LocationRegister) > loc_data_opl){ + str8_list_pushf(arena, out, "ValRegister( )\n"); + } + else{ + RADDBG_LocationRegister *loc = (RADDBG_LocationRegister*)loc_base_ptr; + str8_list_pushf(arena, out, "ValRegister(reg: %u)\n", loc->register_code); + } + }break; + } + } + } + } + } + } + } + + // TODO(allen): static locals + + for (U32 child = scope->first_child_scope_idx; + child != 0;){ + // get scope for child + RADDBG_Scope *child_scope = 0; + if (child < bundle->scope_count){ + child_scope = bundle->scopes + child; + } + if (child_scope == 0){ + break; + } + + // stringize child + raddbg_stringize_scope(arena, out, parsed, bundle, child_scope, indent_level + 1); + + // increment iterator + child = child_scope->next_sibling_scope_idx; + } + + str8_list_pushf(arena, out, "%.*s[/%u]\n", + indent_level, raddbg_stringize_spaces, this_idx); +} diff --git a/src/raddbg_dump/raddbg_stringize.h b/src/raddbg_dump/raddbg_stringize.h new file mode 100644 index 00000000..6385b156 --- /dev/null +++ b/src/raddbg_dump/raddbg_stringize.h @@ -0,0 +1,120 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_STRINGIZE_H +#define RADDBG_STRINGIZE_H + +// TODO(allen): this depends on types from our base layer. +// we need to decide if we want this to be included in the "format" layer +// and therefore lifted off of the base layer, or if we want to put it in +// "base" or "dump" layers or something like that so that it can +// rely on Arena, String8, and String8List from the "base" layer. + +//////////////////////////////// +//~ RADDBG Stringize Helper Types + +typedef struct RADDBG_FilePathBundle{ + RADDBG_FilePathNode *file_paths; + U32 file_path_count; +} RADDBG_FilePathBundle; + +typedef struct RADDBG_UDTMemberBundle{ + RADDBG_Member *members; + RADDBG_EnumMember *enum_members; + U32 member_count; + U32 enum_member_count; +} RADDBG_UDTMemberBundle; + +typedef struct RADDBG_ScopeBundle{ + RADDBG_Scope *scopes; + U64 *scope_voffs; + RADDBG_Local *locals; + RADDBG_LocationBlock *location_blocks; + U8 *location_data; + U32 scope_count; + U32 scope_voff_count; + U32 local_count; + U32 location_block_count; + U32 location_data_size; +} RADDBG_ScopeBundle; + +//////////////////////////////// +//~ RADDBG Common Stringize Functions + +static String8 raddbg_string_from_data_section_tag(RADDBG_DataSectionTag tag); +static String8 raddbg_string_from_arch(RADDBG_Arch arch); +static String8 raddbg_string_from_language(RADDBG_Language language); +static String8 raddbg_string_from_type_kind(RADDBG_TypeKind type_kind); +static String8 raddbg_string_from_member_kind(RADDBG_MemberKind member_kind); +static String8 raddbg_string_from_local_kind(RADDBG_LocalKind local_kind); + +//////////////////////////////// +//~ RADDBG Flags Stringize Functions + +static void raddbg_stringize_binary_section_flags(Arena *arena, String8List *out, + RADDBG_BinarySectionFlags flags); + +static void raddbg_stringize_type_modifier_flags(Arena *arena, String8List *out, + RADDBG_TypeModifierFlags flags); + +static void raddbg_stringize_user_defined_type_flags(Arena *arena, String8List *out, + RADDBG_UserDefinedTypeFlags flags); + +static void raddbg_stringize_link_flags(Arena *arena, String8List *out, + RADDBG_LinkFlags flags); + +//////////////////////////////// +//~ RADDBG Compound Stringize Functions + +static void +raddbg_stringize_data_sections(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + U32 indent_level); + +static void +raddbg_stringize_top_level_info(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_TopLevelInfo *tli, U32 indent_level); + +static void +raddbg_stringize_binary_section(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_BinarySection *bin_section, U32 indent_level); + +static void +raddbg_stringize_file_path(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_FilePathBundle *bundle, RADDBG_FilePathNode *file_path, + U32 indent_level); + +static void +raddbg_stringize_source_file(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_SourceFile *source_file, U32 indent_level); + +static void +raddbg_stringize_unit(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_Unit *unit, U32 indent_level); + +static void +raddbg_stringize_type_node(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_TypeNode *type, U32 indent_level); + +static void +raddbg_stringize_udt(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_UDTMemberBundle *bundle, RADDBG_UDT *udt, + U32 indent_level); + +static void +raddbg_stringize_global_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_GlobalVariable *global_variable, U32 indent_level); + +static void +raddbg_stringize_thread_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_ThreadVariable *thread_var, + U32 indent_level); + +static void +raddbg_stringize_procedure(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_Procedure *proc, U32 indent_level); + +static void +raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, + RADDBG_ScopeBundle *bundle, RADDBG_Scope *scope, U32 indent_level); + +#endif //RADDBG_STRINGIZE_H diff --git a/src/raddbg_format/raddbg_format.c b/src/raddbg_format/raddbg_format.c new file mode 100644 index 00000000..10382bc4 --- /dev/null +++ b/src/raddbg_format/raddbg_format.c @@ -0,0 +1,97 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// Functions + +RADDBG_PROC RADDBG_U64 +raddbg_hash(RADDBG_U8 *ptr, RADDBG_U64 size){ + RADDBG_U64 result = 5381; + RADDBG_U8 *opl = ptr + size; + for (; ptr < opl; ptr += 1){ + result = ((result << 5) + result) + *ptr; + } + return(result); +} + +RADDBG_PROC RADDBG_U32 +raddbg_size_from_basic_type_kind(RADDBG_TypeKind kind){ + RADDBG_U32 result = 0; + switch (kind){ +#define X(N,C) +#define XZ(N,C,Z) case C: result = Z; break; +#define Y(A,N) + RADDBG_TypeKindXList(X,XZ,Y) +#undef X +#undef XZ +#undef Y + } + return(result); +} + +RADDBG_PROC RADDBG_U32 +raddbg_addr_size_from_arch(RADDBG_Arch arch){ + RADDBG_U32 result = 0; + switch (arch){ +#define X(N,C,Z) case C: result = Z; break; + RADDBG_ArchXList(X) +#undef X + } + return(result); +} + +//- eval helpers + +RADDBG_PROC RADDBG_EvalConversionKind +raddbg_eval_conversion_rule(RADDBG_EvalTypeGroup in, RADDBG_EvalTypeGroup out){ + RADDBG_EvalConversionKind result = 0; + switch (in + (out << 8)){ +#define Y(i,o) case ((RADDBG_EvalTypeGroup_##i) + ((RADDBG_EvalTypeGroup_##o) << 8)): +#define Xb(c) +#define Xe(c) result = RADDBG_EvalConversionKind_##c; break; + RADDBG_EvalConversionKindFromTypeGroupPairMap(Y,Xb,Xe) +#undef Xe +#undef Xb +#undef Y + } + return(result); +} + +RADDBG_PROC RADDBG_U8* +raddbg_eval_conversion_message(RADDBG_EvalConversionKind conversion_kind, RADDBG_U64 *lenout){ + RADDBG_U8 *result = 0; + switch (conversion_kind){ +#define X(N,msg) \ +case RADDBG_EvalConversionKind_##N: result = (RADDBG_U8*)msg; *lenout = sizeof(msg) - 1; break; + RADDBG_EvalConversionKindXList(X) +#undef X + } + return(result); +} + +RADDBG_PROC RADDBG_S32 +raddbg_eval_opcode_type_compatible(RADDBG_EvalOp op, RADDBG_EvalTypeGroup group){ + RADDBG_S32 result = 0; + switch (op){ + case RADDBG_EvalOp_Neg: case RADDBG_EvalOp_Add: case RADDBG_EvalOp_Sub: + case RADDBG_EvalOp_Mul: case RADDBG_EvalOp_Div: + case RADDBG_EvalOp_EqEq:case RADDBG_EvalOp_NtEq: + case RADDBG_EvalOp_LsEq:case RADDBG_EvalOp_GrEq: + case RADDBG_EvalOp_Less:case RADDBG_EvalOp_Grtr: + { + if (group != RADDBG_EvalTypeGroup_Other){ + result = 1; + } + }break; + case RADDBG_EvalOp_Mod:case RADDBG_EvalOp_LShift:case RADDBG_EvalOp_RShift: + case RADDBG_EvalOp_BitNot:case RADDBG_EvalOp_BitAnd:case RADDBG_EvalOp_BitXor: + case RADDBG_EvalOp_BitOr:case RADDBG_EvalOp_LogNot:case RADDBG_EvalOp_LogAnd: + case RADDBG_EvalOp_LogOr: + { + if (group == RADDBG_EvalTypeGroup_S || group == RADDBG_EvalTypeGroup_U){ + result = 1; + } + }break; + } + return(result); +} diff --git a/src/raddbg_format/raddbg_format.h b/src/raddbg_format/raddbg_format.h new file mode 100644 index 00000000..0dd4fa0d --- /dev/null +++ b/src/raddbg_format/raddbg_format.h @@ -0,0 +1,923 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_FORMAT_H +#define RADDBG_FORMAT_H + +//////////////////////////////////////////////////////////////// +// Overridable procedure decoration + +#if !defined(RADDBG_PROC) +# define RADDBG_PROC static +#endif + +//////////////////////////////////////////////////////////////// +// Overridable integer types + +#if !defined(RADDBG_U8) +# define RADDBG_U8 RADDBG_U8 +# define RADDBG_U16 RADDBG_U16 +# define RADDBG_U32 RADDBG_U32 +# define RADDBG_U64 RADDBG_U64 +# define RADDBG_S8 RADDBG_S8 +# define RADDBG_S16 RADDBG_S16 +# define RADDBG_S32 RADDBG_S32 +# define RADDBG_S64 RADDBG_S64 + +#include +typedef uint8_t RADDBG_U8; +typedef uint16_t RADDBG_U16; +typedef uint32_t RADDBG_U32; +typedef uint64_t RADDBG_U64; +typedef int8_t RADDBG_S8; +typedef int16_t RADDBG_S16; +typedef int32_t RADDBG_S32; +typedef int64_t RADDBG_S64; +#endif + +//////////////////////////////////////////////////////////////// +// Architecture Constants + +#define RADDBG_ArchXList(X)\ +X(NULL, 0, 0)\ +X(X86, 1, 4)\ +X(X64, 2, 8) + +typedef RADDBG_U32 RADDBG_Arch; +typedef enum RADDBG_ArchEnum{ +#define X(N,C,Z) RADDBG_Arch_##N = C, + RADDBG_ArchXList(X) +#undef X +} RADDBG_ArchEnum; + + +typedef RADDBG_U8 RADDBG_RegisterCode; + +// x86 registers +#define RADDBG_RegisterCode_X86_XList(X) \ +X(nil, 0) \ +X(eax, 1) \ +X(ecx, 2) \ +X(edx, 3) \ +X(ebx, 4) \ +X(esp, 5) \ +X(ebp, 6) \ +X(esi, 7) \ +X(edi, 8) \ +X(fsbase, 9) \ +X(gsbase, 10) \ +X(eflags, 11) \ +X(eip, 12) \ +X(dr0, 13) \ +X(dr1, 14) \ +X(dr2, 15) \ +X(dr3, 16) \ +X(dr4, 17) \ +X(dr5, 18) \ +X(dr6, 19) \ +X(dr7, 20) \ +X(fpr0, 21) \ +X(fpr1, 22) \ +X(fpr2, 23) \ +X(fpr3, 24) \ +X(fpr4, 25) \ +X(fpr5, 26) \ +X(fpr6, 27) \ +X(fpr7, 28) \ +X(st0, 29) \ +X(st1, 30) \ +X(st2, 31) \ +X(st3, 32) \ +X(st4, 33) \ +X(st5, 34) \ +X(st6, 35) \ +X(st7, 36) \ +X(fcw, 37) \ +X(fsw, 38) \ +X(ftw, 39) \ +X(fop, 40) \ +X(fcs, 41) \ +X(fds, 42) \ +X(fip, 43) \ +X(fdp, 44) \ +X(mxcsr, 45) \ +X(mxcsr_mask, 46) \ +X(ss, 47) \ +X(cs, 48) \ +X(ds, 49) \ +X(es, 50) \ +X(fs, 51) \ +X(gs, 52) \ +X(ymm0, 53) \ +X(ymm1, 54) \ +X(ymm2, 55) \ +X(ymm3, 56) \ +X(ymm4, 57) \ +X(ymm5, 58) \ +X(ymm6, 59) \ +X(ymm7, 60) \ +X(COUNT, 61) + +typedef enum RADDBG_RegisterCode_X86_Enum{ +#define X(N,C) RADDBG_RegisterCode_X86_##N = C, + RADDBG_RegisterCode_X86_XList(X) +#undef X +} RADDBG_RegisterCode_X86_Enum; + +// x64 registers +#define RADDBG_RegisterCode_X64_XList(X) \ +X(nil, 0) \ +X(rax, 1) \ +X(rcx, 2) \ +X(rdx, 3) \ +X(rbx, 4) \ +X(rsp, 5) \ +X(rbp, 6) \ +X(rsi, 7) \ +X(rdi, 8) \ +X(r8, 9) \ +X(r9, 10) \ +X(r10, 11) \ +X(r11, 12) \ +X(r12, 13) \ +X(r13, 14) \ +X(r14, 15) \ +X(r15, 16) \ +X(es, 17) \ +X(cs, 18) \ +X(ss, 19) \ +X(ds, 20) \ +X(fs, 21) \ +X(gs, 22) \ +X(rip, 23) \ +X(rflags, 24) \ +X(dr0, 25) \ +X(dr1, 26) \ +X(dr2, 27) \ +X(dr3, 28) \ +X(dr4, 29) \ +X(dr5, 30) \ +X(dr6, 31) \ +X(dr7, 32) \ +X(st0, 33) \ +X(st1, 34) \ +X(st2, 35) \ +X(st3, 36) \ +X(st4, 37) \ +X(st5, 38) \ +X(st6, 39) \ +X(st7, 40) \ +X(fpr0, 41) \ +X(fpr1, 42) \ +X(fpr2, 43) \ +X(fpr3, 44) \ +X(fpr4, 45) \ +X(fpr5, 46) \ +X(fpr6, 47) \ +X(fpr7, 48) \ +X(ymm0, 49) \ +X(ymm1, 50) \ +X(ymm2, 51) \ +X(ymm3, 52) \ +X(ymm4, 53) \ +X(ymm5, 54) \ +X(ymm6, 55) \ +X(ymm7, 56) \ +X(ymm8, 57) \ +X(ymm9, 58) \ +X(ymm10, 59) \ +X(ymm11, 60) \ +X(ymm12, 61) \ +X(ymm13, 62) \ +X(ymm14, 63) \ +X(ymm15, 64) \ +X(mxcsr, 65) \ +X(fsbase, 66) \ +X(gsbase, 67) \ +X(fcw, 68) \ +X(fsw, 69) \ +X(ftw, 70) \ +X(fop, 71) \ +X(fcs, 72) \ +X(fds, 73) \ +X(fip, 74) \ +X(fdp, 75) \ +X(mxcsr_mask, 76) \ +X(COUNT, 77) + +typedef enum RADDBG_RegisterCode_X64_Enum{ +#define X(N,C) RADDBG_RegisterCode_X64_##N = C, + RADDBG_RegisterCode_X64_XList(X) +#undef X +} RADDBG_RegisterCode_X64_Enum; + + +//////////////////////////////////////////////////////////////// +// Format types + +// "raddbg\0\0" +#define RADDBG_MAGIC_CONSTANT 0x0000676264646172 +#define RADDBG_ENCODING_VERSION 1 + +#define RADDBG_LanguageXList(X) \ +X(NULL, 0) \ +X(C, 1) \ +X(CPlusPlus, 2) + +typedef RADDBG_U32 RADDBG_Language; +typedef enum RADDBG_LanguageEnum{ +#define X(N,C) RADDBG_Language_##N = C, + RADDBG_LanguageXList(X) +#undef X +} RADDBG_LanguageEnum; + +typedef struct RADDBG_Header{ + // identification + RADDBG_U64 magic; + RADDBG_U32 encoding_version; + + // data sections + RADDBG_U32 data_section_off; + RADDBG_U32 data_section_count; +} RADDBG_Header; + + +//- data sections + +#define RADDBG_DataSectionTag_SECONDARY 0x80000000 + +#define RADDBG_DataSectionTagXList(X,Y) \ +X(NULL, 0x0000)\ +X(TopLevelInfo, 0x0001)\ +X(StringData, 0x0002)\ +X(StringTable, 0x0003)\ +X(IndexRuns, 0x0004)\ +X(BinarySections, 0x0005)\ +X(FilePathNodes, 0x0006)\ +X(SourceFiles, 0x0007)\ +X(Units, 0x0008)\ +X(UnitVmap, 0x0009)\ +X(TypeNodes, 0x000A)\ +X(UDTs, 0x000B)\ +X(Members, 0x000C)\ +X(EnumMembers, 0x000D)\ +X(GlobalVariables, 0x000E)\ +X(GlobalVmap, 0x000F)\ +X(ThreadVariables, 0x0010)\ +X(Procedures, 0x0011)\ +X(Scopes, 0x0012)\ +X(ScopeVoffData, 0x0013)\ +X(ScopeVmap, 0x0014)\ +X(Locals, 0x0015)\ +X(LocationBlocks, 0x0016)\ +X(LocationData, 0x0017)\ +X(NameMaps, 0x0018)\ +Y(PRIMARY_COUNT)\ +X(SKIP, RADDBG_DataSectionTag_SECONDARY|0x0000)\ +X(LineInfoVoffs, RADDBG_DataSectionTag_SECONDARY|0x0001)\ +X(LineInfoData, RADDBG_DataSectionTag_SECONDARY|0x0002)\ +X(LineInfoColumns, RADDBG_DataSectionTag_SECONDARY|0x0003)\ +X(LineMapNumbers, RADDBG_DataSectionTag_SECONDARY|0x0004)\ +X(LineMapRanges, RADDBG_DataSectionTag_SECONDARY|0x0005)\ +X(LineMapVoffs, RADDBG_DataSectionTag_SECONDARY|0x0006)\ +X(NameMapBuckets, RADDBG_DataSectionTag_SECONDARY|0x0007)\ +X(NameMapNodes, RADDBG_DataSectionTag_SECONDARY|0x0008) + +typedef RADDBG_U32 RADDBG_DataSectionTag; +typedef enum RADDBG_DataSectionTagEnum{ +#define X(N,C) RADDBG_DataSectionTag_##N = C, +#define Y(N) RADDBG_DataSectionTag_##N, + RADDBG_DataSectionTagXList(X,Y) +#undef X +#undef Y +} RADDBG_DataSectionTagEnum; + + +#define RADDBG_DataSectionEncodingXList(X) \ +X(Unpacked, 0) + +typedef RADDBG_U32 RADDBG_DataSectionEncoding; +typedef enum RADDBG_DataSectionEncodingEnum{ +#define X(N,C) RADDBG_DataSectionEncoding_##N = C, + RADDBG_DataSectionEncodingXList(X) +#undef X +} RADDBG_DataSectionEncodingEnum; + +typedef struct RADDBG_DataSection{ + RADDBG_DataSectionTag tag; + RADDBG_DataSectionEncoding encoding; + RADDBG_U64 off; + RADDBG_U64 encoded_size; + RADDBG_U64 unpacked_size; +} RADDBG_DataSection; + + +//- common types +typedef struct RADDBG_VMapEntry{ + RADDBG_U64 voff; + RADDBG_U64 idx; +} RADDBG_VMapEntry; + +//- top level info +typedef struct RADDBG_TopLevelInfo{ + RADDBG_Arch architecture; + RADDBG_U32 exe_name_string_idx; + RADDBG_U64 exe_hash; + RADDBG_U64 voff_max; +} RADDBG_TopLevelInfo; + +//- binary sections +typedef RADDBG_U32 RADDBG_BinarySectionFlags; +typedef enum RADDBG_BinarySectionFlagsEnum{ + RADDBG_BinarySectionFlag_Read = (1 << 0), + RADDBG_BinarySectionFlag_Write = (1 << 1), + RADDBG_BinarySectionFlag_Execute = (1 << 2) +} RADDBG_BinarySectionFlagsEnum; + +typedef struct RADDBG_BinarySection{ + RADDBG_U32 name_string_idx; + RADDBG_BinarySectionFlags flags; + RADDBG_U64 voff_first; + RADDBG_U64 voff_opl; + RADDBG_U64 foff_first; + RADDBG_U64 foff_opl; +} RADDBG_BinarySection; + +//- file & file system info +typedef struct RADDBG_FilePathNode{ + RADDBG_U32 name_string_idx; + RADDBG_U32 parent_path_node; + RADDBG_U32 first_child; + RADDBG_U32 next_sibling; + RADDBG_U32 source_file_idx; +} RADDBG_FilePathNode; + +typedef struct RADDBG_SourceFile{ + RADDBG_U32 file_path_node_idx; + + RADDBG_U32 normal_full_path_string_idx; + + // usage of line map to go from a line number to an array of voffs + // (line_map_nums * line_number) -> (nil | index) + // (line_map_data * index) -> (range) + // (line_map_voff_data * range) -> (array(voff)) + + RADDBG_U32 line_map_count; + RADDBG_U32 line_map_nums_data_idx; // U32[line_map_count] (sorted - not closed ranges) + RADDBG_U32 line_map_range_data_idx; // U32[line_map_count + 1] (pairs form ranges) + RADDBG_U32 line_map_voff_data_idx; // U64[...] (idx by line_map_range_data) +} RADDBG_SourceFile; + + +//- units & line info +typedef struct RADDBG_Unit{ + RADDBG_U32 unit_name_string_idx; + RADDBG_U32 compiler_name_string_idx; + RADDBG_U32 source_file_path_node; + RADDBG_U32 object_file_path_node; + RADDBG_U32 archive_file_path_node; + RADDBG_U32 build_path_node; + RADDBG_Language language; + + // usage of line info to go from voff to file & line number: + // (line_info_voffs * voff) -> (nil + index) + // (line_info_data * index) -> (RADDBG_Line = (file_idx * line_number)) + + RADDBG_U32 line_info_voffs_data_idx; // U64[line_info_count + 1] (sorted ranges) + RADDBG_U32 line_info_data_idx; // RADDBG_Line[line_info_count] + RADDBG_U32 line_info_col_data_idx; // RADDBG_Col[line_info_count] + RADDBG_U32 line_info_count; +} RADDBG_Unit; + +typedef struct RADDBG_Line{ + RADDBG_U32 file_idx; + RADDBG_U32 line_num; +} RADDBG_Line; + +typedef struct RADDBG_Column{ + RADDBG_U16 col_first; + RADDBG_U16 col_opl; +} RADDBG_Column; + + +//- type info + +// X(name,code) - defines a primary code +// XZ(name,code size) - defines a primary code & associates a size +// Y(alias_name,name) - defines an alias for bookends +#define RADDBG_TypeKindXList(X,XZ,Y)\ +X(NULL, 0x0000) \ +\ +XZ(Void, 0x0001, 0) Y(FirstBuiltIn, Void) \ +XZ(Handle, 0x0002, 0xFFFFFFFF) \ +XZ(Char8, 0x0003, 1)\ +XZ(Char16, 0x0004, 2) \ +XZ(Char32, 0x0005, 4) \ +XZ(UChar8, 0x0006, 1) \ +XZ(UChar16, 0x0007, 2) \ +XZ(UChar32, 0x0008, 4) \ +XZ(U8, 0x0009, 1) \ +XZ(U16, 0x000A, 2) \ +XZ(U32, 0x000B, 4) \ +XZ(U64, 0x000C, 8) \ +XZ(U128, 0x000D, 16) \ +XZ(U256, 0x000E, 32) \ +XZ(U512, 0x000F, 64) \ +XZ(S8, 0x0010, 1) \ +XZ(S16, 0x0011, 2) \ +XZ(S32, 0x0012, 4) \ +XZ(S64, 0x0013, 8) \ +XZ(S128, 0x0014, 16) \ +XZ(S256, 0x0015, 32) \ +XZ(S512, 0x0016, 64) \ +XZ(Bool, 0x0017, 1) \ +XZ(F16, 0x0018, 2) \ +XZ(F32, 0x0019, 4) \ +XZ(F32PP, 0x001A, 4) \ +XZ(F48, 0x001B, 6) \ +XZ(F64, 0x001C, 8) \ +XZ(F80, 0x001D, 10) \ +XZ(F128, 0x001E, 16) \ +XZ(ComplexF32, 0x001F, 8) \ +XZ(ComplexF64, 0x0020, 16) \ +XZ(ComplexF80, 0x0021, 20) \ +XZ(ComplexF128, 0x0022, 32) Y(LastBuiltIn, ComplexF128) \ +\ +X(Modifier, 0x1000) Y(FirstConstructed, Modifier) \ +X(Ptr, 0x1001) \ +X(LRef, 0x1002) \ +X(RRef, 0x1003) \ +X(Array, 0x1004) \ +X(Function, 0x1005) \ +X(Method, 0x1006) \ +X(MemberPtr, 0x1007) Y(LastConstructed, MemberPtr) \ +\ +X(Struct, 0x2000) Y(FirstUserDefined, Struct) Y(FirstRecord, Struct) \ +X(Class, 0x2001) \ +X(Union, 0x2002) Y(LastRecord, Union) \ +X(Enum, 0x2003) \ +X(Alias, 0x2004) \ +X(IncompleteStruct, 0x2005) Y(FirstIncomplete, IncompleteStruct) \ +X(IncompleteUnion, 0x2006) \ +X(IncompleteClass, 0x2007) \ +X(IncompleteEnum, 0x2008) Y(LastIncomplete, IncompleteEnum) \ +Y(LastUserDefined, IncompleteEnum) \ +\ +X(Bitfield, 0xF000) \ +X(Variadic, 0xF001) + +typedef RADDBG_U16 RADDBG_TypeKind; +typedef enum RADDBG_TypeKindEnum{ + +#define X(name,code) RADDBG_TypeKind_##name = code, +#define XZ(name,code,size) X(name,code) +#define Y(alias_name,name) RADDBG_TypeKind_##alias_name = RADDBG_TypeKind_##name, + RADDBG_TypeKindXList(X,XZ,Y) +#undef X +#undef XZ +#undef Y + +} RADDBG_TypeKindEnum; + +typedef RADDBG_U16 RADDBG_TypeModifierFlags; +enum{ + RADDBG_TypeModifierFlag_Const = (1 << 0), + RADDBG_TypeModifierFlag_Volatile = (1 << 1), +}; + +// IMPORTANT NOTE: All type nodes in a valid raddbg are *topologically sorted*. +// That means any time a type node refers to another type node, the type node +// it refers to has an index less than or equal to the index of the node that +// is doing the referring. It is never the case that a type node depends on a +// node that comes later in the type node array. +// This restriction does not apply to the members of a type that are +// attached through a "UDT" though. + +typedef struct RADDBG_TypeNode{ + RADDBG_TypeKind kind; + // when kind is 'Modifier' -> RADDBG_TypeModifierFlags + RADDBG_U16 flags; + + RADDBG_U32 byte_size; + + union{ + // kind is 'built-in' + struct{ + RADDBG_U32 name_string_idx; + } built_in; + + // kind is 'constructed' + struct{ + RADDBG_U32 direct_type_idx; + RADDBG_U32 count; + union{ + // when kind is 'Function' or 'Method' + RADDBG_U32 param_idx_run_first; + // when kind is 'MemberPtr' + RADDBG_U32 owner_type_idx; + }; + } constructed; + + // kind is 'user defined' + struct{ + RADDBG_U32 name_string_idx; + RADDBG_U32 direct_type_idx; + RADDBG_U32 udt_idx; + } user_defined; + + // (kind = Bitfield) + struct{ + RADDBG_U32 off; + RADDBG_U32 size; + } bitfield; + }; +} RADDBG_TypeNode; + +typedef RADDBG_U32 RADDBG_UserDefinedTypeFlags; +enum{ + RADDBG_UserDefinedTypeFlag_EnumMembers = (1 << 0), +}; + +typedef struct RADDBG_UDT{ + RADDBG_U32 self_type_idx; + RADDBG_UserDefinedTypeFlags flags; + + // when EnumMembers flag is set, indexes into enum "enum_members" instead of "members" + RADDBG_U32 member_first; + RADDBG_U32 member_count; + + RADDBG_U32 file_idx; + RADDBG_U32 line; + RADDBG_U32 col; +} RADDBG_UDT; + +#define RADDBG_MemberKindXList(X) \ +X(NULL, 0x0000) \ +X(DataField, 0x0001) \ +X(StaticData, 0x0002) \ +X(Method, 0x0100) \ +X(StaticMethod, 0x0101) \ +X(VirtualMethod, 0x0102) \ +X(VTablePtr, 0x0200) \ +X(Base, 0x0201) \ +X(VirtualBase, 0x0202) \ +X(NestedType, 0x0300) + +typedef RADDBG_U16 RADDBG_MemberKind; +typedef enum RADDBG_MemberKindEnum{ +#define X(N,C) RADDBG_MemberKind_##N = C, + RADDBG_MemberKindXList(X) +#undef X +} RADDBG_MemberKindEnum; + +// TODO(allen): need a way to equip methods and some virtual methods +// with procedure symbol information. I'm thinking a seperate data +// array of (MemberIdx,ProcSymbolIdx) sorted by MemberIdx. Or just a +// parallel array. Putting them right into this struct looks like it +// would complicate the converters because we tend to want an API +// like 'associate_method_to_proc' that can be used *after* both the +// method and proc are known, rather than one that forces us to know +// the association when constructing the member data. +typedef struct RADDBG_Member{ + RADDBG_MemberKind kind; + RADDBG_U16 __unused__; + + RADDBG_U32 name_string_idx; + RADDBG_U32 type_idx; + RADDBG_U32 off; +} RADDBG_Member; + +typedef struct RADDBG_EnumMember{ + RADDBG_U32 name_string_idx; + RADDBG_U32 __unused__; + RADDBG_U64 val; +} RADDBG_EnumMember; + + +//- symbol info +typedef RADDBG_U32 RADDBG_LinkFlags; +enum{ + RADDBG_LinkFlag_External = (1 << 0), + // NOTE: Scope flags are mutually exclusive. + // A symbol is either global scoped, type scoped, or procedure scoped. + RADDBG_LinkFlag_TypeScoped = (1 << 1), + RADDBG_LinkFlag_ProcScoped = (1 << 2), +}; + +typedef struct RADDBG_GlobalVariable{ + RADDBG_U32 name_string_idx; + // NOTE: "global variables" can be scoped in *any* way. The scope flags here refer to + // *namespace* scoping. "global variables" are all in the data section of the + // final exe/dll type file, so they are "global" in the life-time sense of the + // word. In the namespace sense of the word, they can be scoped globally, by type, + // or by procedure. + RADDBG_LinkFlags link_flags; + RADDBG_U64 voff; + RADDBG_U32 type_idx; + + // container_idx: UDT for "TypeScoped", Procedure for "ProcScoped" + RADDBG_U32 container_idx; +} RADDBG_GlobalVariable; + +typedef struct RADDBG_ThreadVariable{ + RADDBG_U32 name_string_idx; + // NOTE: See the note in GlobalVariable regarding scoping. The same concept applies here. + RADDBG_LinkFlags link_flags; + RADDBG_U32 tls_off; + RADDBG_U32 type_idx; + + // container_idx: UDT for "TypeScoped", Procedure for "ProcScoped" + RADDBG_U32 container_idx; +} RADDBG_ThreadVariable; + +typedef struct RADDBG_Procedure{ + RADDBG_U32 name_string_idx; + RADDBG_U32 link_name_string_idx; + // NOTE: See the note in GlobalVariable regarding scoping. The same concept applies here. + RADDBG_LinkFlags link_flags; + RADDBG_U32 type_idx; + RADDBG_U32 root_scope_idx; + + // container_idx: UDT for "TypeScoped", Procedure for "ProcScoped" + RADDBG_U32 container_idx; +} RADDBG_Procedure; + +typedef struct RADDBG_Scope{ + RADDBG_U32 proc_idx; + RADDBG_U32 parent_scope_idx; + RADDBG_U32 first_child_scope_idx; + RADDBG_U32 next_sibling_scope_idx; + + RADDBG_U32 voff_range_first; + RADDBG_U32 voff_range_opl; + + // indexes into "locals" + RADDBG_U32 local_first; + RADDBG_U32 local_count; + + RADDBG_U32 static_local_idx_run_first; + RADDBG_U32 static_local_count; + + // TODO(allen): attach less common scope-relevant info +} RADDBG_Scope; + +typedef RADDBG_U32 RADDBG_LocalKind; +typedef enum{ + RADDBG_LocalKind_NULL, + RADDBG_LocalKind_Parameter, + RADDBG_LocalKind_Variable, + RADDBG_LocalKind_COUNT +} RADDBG_LocalKindEnum; + +typedef struct RADDBG_Local{ + RADDBG_LocalKind kind; + RADDBG_U32 name_string_idx; + RADDBG_U64 type_idx; + // indexes into "location_blocks" + RADDBG_U32 location_first; + RADDBG_U32 location_opl; +} RADDBG_Local; + +typedef struct RADDBG_LocationBlock{ + RADDBG_U32 scope_off_first; + RADDBG_U32 scope_off_opl; + RADDBG_U32 location_data_off; +} RADDBG_LocationBlock; + +typedef RADDBG_U8 RADDBG_LocationKind; +typedef enum{ + RADDBG_LocationKind_NULL, + RADDBG_LocationKind_AddrBytecodeStream, + RADDBG_LocationKind_ValBytecodeStream, + RADDBG_LocationKind_AddrRegisterPlusU16, + RADDBG_LocationKind_AddrAddrRegisterPlusU16, + RADDBG_LocationKind_ValRegister, + RADDBG_LocationKind_COUNT +} RADDBG_LocationKindEnum; + +typedef struct RADDBG_LocationBytecodeStream{ + RADDBG_LocationKind kind; + // [... 0] null terminated byte sequence RADDBG_EvalBytecodeStream +} RADDBG_LocationBytecodeStream; + +typedef struct RADDBG_LocationRegisterPlusU16{ + RADDBG_LocationKind kind; + RADDBG_RegisterCode register_code; + RADDBG_U16 offset; +} RADDBG_LocationRegisterPlusU16; + +typedef struct RADDBG_LocationRegister{ + RADDBG_LocationKind kind; + RADDBG_RegisterCode register_code; +} RADDBG_LocationRegister; + +//- name map types +#define RADDBG_NameMapXList(X)\ +X(NULL, 0)\ +X(GlobalVariables, 1)\ +X(ThreadVariables, 2)\ +X(Procedures, 3)\ +X(Types, 4)\ +X(LinkNameProcedures, 5)\ +X(NormalSourcePaths, 6) + +typedef RADDBG_U32 RADDBG_NameMapKind; +typedef enum RADDBG_NameMapKindEnum{ +#define X(N,C) RADDBG_NameMapKind_##N = C, + RADDBG_NameMapXList(X) +#undef X + + RADDBG_NameMapKind_COUNT +} RADDBG_NameMapKindEnum; + +// TODO(allen): documentation here for the hashing and probing strategy for this table + +typedef struct RADDBG_NameMap{ + RADDBG_NameMapKind kind; + RADDBG_U32 bucket_data_idx; + RADDBG_U32 node_data_idx; +} RADDBG_NameMap; + +typedef struct RADDBG_NameMapBucket{ + RADDBG_U32 first_node; + RADDBG_U32 node_count; +} RADDBG_NameMapBucket; + +typedef struct RADDBG_NameMapNode{ + RADDBG_U32 string_idx; + RADDBG_U32 match_count; + // NOTE: if (match_count == 1) then this is the index of the matching item + // if (match_count > 1) then this is the first for an index run of all the matches + RADDBG_U32 match_idx_or_idx_run_first; +} RADDBG_NameMapNode; + + +//////////////////////////////// +// Eval Bytecode + +// (Name, decodeN, popN, pushN) +#define RADDBG_EvalOpXList(X)\ +X(Stop, 0, 0, 0)\ +X(Noop, 0, 0, 0)\ +X(Cond, 1, 1, 0)\ +X(Skip, 1, 0, 0)\ +X(MemRead, 1, 1, 1)\ +X(RegRead, 4, 0, 1)\ +X(RegReadDyn, 0, 1, 1)\ +X(FrameOff, 1, 0, 1)\ +X(ModuleOff, 4, 0, 1)\ +X(TLSOff, 4, 0, 1)\ +X(ObjectOff, 0, 0, 0)\ +X(CFA, 0, 0, 0)\ +X(ConstU8, 1, 0, 1)\ +X(ConstU16, 2, 0, 1)\ +X(ConstU32, 4, 0, 1)\ +X(ConstU64, 8, 0, 1)\ +X(Abs, 1, 1, 1)\ +X(Neg, 1, 1, 1)\ +X(Add, 1, 2, 1)\ +X(Sub, 1, 2, 1)\ +X(Mul, 1, 2, 1)\ +X(Div, 1, 2, 1)\ +X(Mod, 1, 2, 1)\ +X(LShift, 1, 2, 1)\ +X(RShift, 1, 2, 1)\ +X(BitAnd, 1, 2, 1)\ +X(BitOr, 1, 2, 1)\ +X(BitXor, 1, 2, 1)\ +X(BitNot, 1, 1, 1)\ +X(LogAnd, 1, 2, 1)\ +X(LogOr, 1, 2, 1)\ +X(LogNot, 1, 1, 1)\ +X(EqEq, 1, 2, 1)\ +X(NtEq, 1, 2, 1)\ +X(LsEq, 1, 2, 1)\ +X(GrEq, 1, 2, 1)\ +X(Less, 1, 2, 1)\ +X(Grtr, 1, 2, 1)\ +X(Trunc, 1, 1, 1)\ +X(TruncSigned, 1, 1, 1)\ +X(Convert, 2, 1, 1)\ +X(Pick, 1, 0, 1)\ +X(Pop, 0, 1, 0)\ +X(Insert, 1, 0, 0) + +// (Name) +#define RADDBG_EvalTypeGroupXList(X)\ +X(Other)\ +X(U)\ +X(S)\ +X(F32)\ +X(F64) + +// (Name, error-message) +#define RADDBG_EvalConversionKindXList(X)\ +X(Noop, "")\ +X(Legal, "")\ +X(OtherToOther, "cannot convert between these types")\ +X(ToOther, "cannot convert to this type")\ +X(FromOther, "cannot convert this type") + +// Xb(EvalTypeGroup) Y(TypeKind) Xe(EvalTypeGroup) +#define RADDBG_EvalTypeGroupFromKindMap(Y,Xb,Xe)\ +\ +Xb(U) Y(U8) Y(U16) Y(U32) Y(U64) Y(Bool) Y(Ptr) Y(Enum)\ +Xe(U)\ +\ +Xb(S) Y(S8) Y(S16) Y(S32) Y(S64)\ +Xe(S)\ +\ +Xb(F32) Y(F32)\ +Xe(F32)\ +\ +Xb(F64) Y(F64)\ +Xe(F64) + +// Xb(EvalConversionKind) Y(EvalTypeGroup, EvalTypeGroup) Xe(EvalConversionKind) +#define RADDBG_EvalConversionKindFromTypeGroupPairMap(Y,Xb,Xe)\ +\ +Xb(Noop) Y(U, U) Y(S, S) Y(F32, F32) Y(F64, F64) Y(U, S) Y(S, U)\ +Xe(Noop)\ +\ +Xb(Legal)\ +Y(U, F32) Y(S, F32) Y(F32, U) Y(F32, S)\ +Y(U, F64) Y(S, F64) Y(F64, U) Y(F64, S)\ +Y(F32, F64) Y(F64, F32)\ +Xe(Legal)\ +\ +Xb(OtherToOther) Y(Other, Other)\ +Xe(OtherToOther)\ +\ +Xb(ToOther) Y(U, Other) Y(S, Other) Y(F32, Other) Y(F64, Other)\ +Xe(ToOther)\ +\ +Xb(FromOther) Y(Other, U) Y(Other, S) Y(Other, F32) Y(Other, F64)\ +Xe(FromOther) + +// eval interpretation macros +#define RADDBG_EncodeRegReadParam(reg,bytesize,bytepos) ((reg)|((bytesize)<<8)|((bytepos)<<16)) + + +// eval enums +typedef RADDBG_U8 RADDBG_EvalOp; + +typedef enum RADDBG_EvalOpEnum{ +#define X(N,dec,pop,push) RADDBG_EvalOp_##N, + RADDBG_EvalOpXList(X) +#undef X + + RADDBG_EvalOp_COUNT +} RADDBG_EvalOpEnum; + + +typedef RADDBG_U8 RADDBG_EvalTypeGroup; + +typedef enum RADDBG_EvalTypeGroupEnum{ +#define X(N) RADDBG_EvalTypeGroup_##N, + RADDBG_EvalTypeGroupXList(X) +#undef X + RADDBG_EvalTypeGroup_COUNT, +} RADDBG_EvalTypeGroupEnum; + + +typedef RADDBG_U8 RADDBG_EvalConversionKind; + +typedef enum RADDBG_EvalConversionKindEnum{ +#define X(N,msg) RADDBG_EvalConversionKind_##N, + RADDBG_EvalConversionKindXList(X) +#undef X + RADDBG_EvalConversionKind_COUNT, +} RADDBG_EvalConversionKindEnum; + + +//- eval data tables + +#define RADDBG_EVAL_CTRLBITS(decodeN,popN,pushN) ((decodeN) | ((popN) << 4) | ((pushN) << 6)) +#define RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits) ((ctrlbits) & 0xf) +#define RADDBG_POPN_FROM_CTRLBITS(ctrlbits) (((ctrlbits) >> 4) & 0x3) +#define RADDBG_PUSHN_FROM_CTRLBITS(ctrlbits) (((ctrlbits) >> 6) & 0x3) + +static RADDBG_U8 raddbg_eval_opcode_ctrlbits[] = { +#define X(Name, decodeN, popN, pushN) RADDBG_EVAL_CTRLBITS(decodeN,popN,pushN), + RADDBG_EvalOpXList(X) +#undef X +}; + +//////////////////////////////// +// Functions + +RADDBG_PROC RADDBG_U64 raddbg_hash(RADDBG_U8 *ptr, RADDBG_U64 size); +RADDBG_PROC RADDBG_U32 raddbg_size_from_basic_type_kind(RADDBG_TypeKind kind); +RADDBG_PROC RADDBG_U32 raddbg_addr_size_from_arch(RADDBG_Arch arch); + +//- eval helpers +RADDBG_PROC RADDBG_EvalConversionKind +raddbg_eval_conversion_rule(RADDBG_EvalTypeGroup in, RADDBG_EvalTypeGroup out); + +RADDBG_PROC RADDBG_U8* +raddbg_eval_conversion_message(RADDBG_EvalConversionKind conversion_kind, RADDBG_U64 *lennout); + +RADDBG_PROC RADDBG_S32 +raddbg_eval_opcode_type_compatible(RADDBG_EvalOp op, RADDBG_EvalTypeGroup group); + +#endif // RADDBG_FORMAT_H diff --git a/src/raddbg_format/raddbg_format_parse.c b/src/raddbg_format/raddbg_format_parse.c new file mode 100644 index 00000000..015f3cba --- /dev/null +++ b/src/raddbg_format/raddbg_format_parse.c @@ -0,0 +1,537 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ RADDBG Parse API + +RADDBG_PROC RADDBG_ParseStatus +raddbg_parse(RADDBG_U8 *data, RADDBG_U64 size, RADDBG_Parsed *out){ + RADDBG_ParseStatus result = RADDBG_ParseStatus_Good; + + // out header + RADDBG_Header *hdr = 0; + { + if (sizeof(*hdr) <= size){ + hdr = (RADDBG_Header*)data; + } + + // (errors) + if (hdr == 0 || hdr->magic != RADDBG_MAGIC_CONSTANT){ + hdr = 0; + result = RADDBG_ParseStatus_HeaderDoesNotMatch; + } + if (hdr != 0 && hdr->encoding_version != 1){ + hdr = 0; + result = RADDBG_ParseStatus_UnsupportedVersionNumber; + } + } + + // out data sections + RADDBG_DataSection *dsecs = 0; + RADDBG_U32 dsec_count = 0; + if (hdr != 0){ + RADDBG_U64 opl = (RADDBG_U64)hdr->data_section_off + (RADDBG_U64)hdr->data_section_count*sizeof(*dsecs); + if (opl <= size){ + dsecs = (RADDBG_DataSection*)(data + hdr->data_section_off); + dsec_count = hdr->data_section_count; + } + + // (errors) + if (dsecs == 0){ + result = RADDBG_ParseStatus_InvalidDataSecionLayout; + } + } + + // extract primary data section indexes + RADDBG_U32 dsec_idx[RADDBG_DataSectionTag_PRIMARY_COUNT] = {0}; + if (result == RADDBG_ParseStatus_Good){ + RADDBG_DataSection *sec_ptr = dsecs; + for (RADDBG_U32 i = 0; i < dsec_count; i += 1, sec_ptr += 1){ + if (sec_ptr->tag < RADDBG_DataSectionTag_PRIMARY_COUNT){ + dsec_idx[sec_ptr->tag] = i; + } + } + } + + // fill out data block (part 1) + if (result == RADDBG_ParseStatus_Good){ + out->raw_data = data; + out->raw_data_size = size; + out->dsecs = dsecs; + out->dsec_count = dsec_count; + for (RADDBG_U32 i = 0; i < RADDBG_DataSectionTag_PRIMARY_COUNT; i += 1){ + out->dsec_idx[i] = dsec_idx[i]; + } + } + + // out string table + RADDBG_U8 *string_data = 0; + RADDBG_U64 string_opl = 0; + RADDBG_U32 *string_offs = 0; + RADDBG_U64 string_count = 0; + if (result == RADDBG_ParseStatus_Good){ + raddbg_parse__extract_primary(out, string_data, &string_opl, + RADDBG_DataSectionTag_StringData); + + RADDBG_U64 table_entry_count = 0; + raddbg_parse__extract_primary(out, string_offs, &table_entry_count, + RADDBG_DataSectionTag_StringTable); + if (table_entry_count > 0){ + string_count = table_entry_count - 1; + } + + // (errors) + if (string_data == 0){ + result = RADDBG_ParseStatus_MissingStringDataSection; + } + else if (string_offs == 0){ + result = RADDBG_ParseStatus_MissingStringTableSection; + } + } + + // out index runs + RADDBG_U32 *idx_run_data = 0; + RADDBG_U64 idx_run_count = 0; + if (result == RADDBG_ParseStatus_Good){ + raddbg_parse__extract_primary(out, idx_run_data, &idx_run_count, + RADDBG_DataSectionTag_IndexRuns); + + // (errors) + if (idx_run_data == 0){ + result = RADDBG_ParseStatus_MissingIndexRunSection; + } + } + + if (result == RADDBG_ParseStatus_Good){ + // fill out primary data structures (part 2) + out->string_data = string_data; + out->string_offs = string_offs; + out->string_data_size = string_opl; + out->string_count = string_count; + out->idx_run_data = idx_run_data; + out->idx_run_count = idx_run_count; + + { + RADDBG_TopLevelInfo *tli = 0; + RADDBG_U64 dummy = 0; + raddbg_parse__extract_primary(out, tli, &dummy, RADDBG_DataSectionTag_TopLevelInfo); + if (dummy != 1){ + tli = 0; + } + out->top_level_info = tli; + } + + raddbg_parse__extract_primary(out, out->binary_sections, &out->binary_section_count, + RADDBG_DataSectionTag_BinarySections); + + raddbg_parse__extract_primary(out, out->file_paths, &out->file_path_count, + RADDBG_DataSectionTag_FilePathNodes); + + raddbg_parse__extract_primary(out, out->source_files, &out->source_file_count, + RADDBG_DataSectionTag_SourceFiles); + + raddbg_parse__extract_primary(out, out->units, &out->unit_count, + RADDBG_DataSectionTag_Units); + + raddbg_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, + RADDBG_DataSectionTag_UnitVmap); + + raddbg_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, + RADDBG_DataSectionTag_UnitVmap); + + raddbg_parse__extract_primary(out, out->type_nodes, &out->type_node_count, + RADDBG_DataSectionTag_TypeNodes); + + raddbg_parse__extract_primary(out, out->udts, &out->udt_count, + RADDBG_DataSectionTag_UDTs); + + raddbg_parse__extract_primary(out, out->members, &out->member_count, + RADDBG_DataSectionTag_Members); + + raddbg_parse__extract_primary(out, out->enum_members, &out->enum_member_count, + RADDBG_DataSectionTag_EnumMembers); + + raddbg_parse__extract_primary(out, out->global_variables, &out->global_variable_count, + RADDBG_DataSectionTag_GlobalVariables); + + raddbg_parse__extract_primary(out, out->global_vmap, &out->global_vmap_count, + RADDBG_DataSectionTag_GlobalVmap); + + raddbg_parse__extract_primary(out, out->thread_variables, &out->thread_variable_count, + RADDBG_DataSectionTag_ThreadVariables); + + raddbg_parse__extract_primary(out, out->procedures, &out->procedure_count, + RADDBG_DataSectionTag_Procedures); + + raddbg_parse__extract_primary(out, out->scopes, &out->scope_count, + RADDBG_DataSectionTag_Scopes); + + raddbg_parse__extract_primary(out, out->scope_voffs, &out->scope_voff_count, + RADDBG_DataSectionTag_ScopeVoffData); + + raddbg_parse__extract_primary(out, out->scope_vmap, &out->scope_vmap_count, + RADDBG_DataSectionTag_ScopeVmap); + + raddbg_parse__extract_primary(out, out->locals, &out->local_count, + RADDBG_DataSectionTag_Locals); + + raddbg_parse__extract_primary(out, out->location_blocks, &out->location_block_count, + RADDBG_DataSectionTag_LocationBlocks); + + raddbg_parse__extract_primary(out, out->location_data, &out->location_data_size, + RADDBG_DataSectionTag_LocationData); + + { + raddbg_parse__extract_primary(out, out->name_maps, &out->name_map_count, + RADDBG_DataSectionTag_NameMaps); + + RADDBG_NameMap *name_map_ptr = out->name_maps; + RADDBG_NameMap *name_map_opl = out->name_maps + out->name_map_count; + for (; name_map_ptr < name_map_opl; name_map_ptr += 1){ + if (out->name_maps_by_kind[name_map_ptr->kind] == 0){ + out->name_maps_by_kind[name_map_ptr->kind] = name_map_ptr; + } + } + } + + } + + return(result); +} + +RADDBG_PROC RADDBG_U8* +raddbg_string_from_idx(RADDBG_Parsed *parsed, RADDBG_U32 idx, RADDBG_U64 *len_out){ + RADDBG_U8 *result = 0; + RADDBG_U64 len_result = 0; + if (idx < parsed->string_count){ + RADDBG_U32 off_raw = parsed->string_offs[idx]; + RADDBG_U32 opl_raw = parsed->string_offs[idx + 1]; + RADDBG_U32 opl = raddbg_parse__min(opl_raw, parsed->string_data_size); + RADDBG_U32 off = raddbg_parse__min(off_raw, opl); + result = parsed->string_data + off; + len_result = opl - off; + } + *len_out = len_result; + return(result); +} + +RADDBG_PROC RADDBG_U32* +raddbg_idx_run_from_first_count(RADDBG_Parsed *parsed, + RADDBG_U32 raw_first, RADDBG_U32 raw_count, + RADDBG_U32 *n_out){ + RADDBG_U32 raw_opl = raw_first + raw_count; + RADDBG_U32 opl = raddbg_parse__min(raw_opl, parsed->idx_run_count); + RADDBG_U32 first = raddbg_parse__min(raw_first, opl); + + RADDBG_U32 *result = 0; + if (first < parsed->idx_run_count){ + result = parsed->idx_run_data + first; + } + *n_out = opl - first; + return(result); +} + +//- line info + +RADDBG_PROC void +raddbg_line_info_from_unit(RADDBG_Parsed *p, RADDBG_Unit *unit, RADDBG_ParsedLineInfo *out){ + RADDBG_U64 line_info_voff_count = 0; + RADDBG_U64 *voffs = (RADDBG_U64*) + raddbg_data_from_dsec(p, unit->line_info_voffs_data_idx, sizeof(RADDBG_U64), + RADDBG_DataSectionTag_LineInfoVoffs, + &line_info_voff_count); + + RADDBG_U64 line_info_count_raw = 0; + RADDBG_Line *lines = (RADDBG_Line*) + raddbg_data_from_dsec(p, unit->line_info_data_idx, sizeof(RADDBG_Line), + RADDBG_DataSectionTag_LineInfoData, + &line_info_count_raw); + + RADDBG_U64 column_info_count_raw = 0; + RADDBG_Column *cols = (RADDBG_Column*) + raddbg_data_from_dsec(p, unit->line_info_col_data_idx, sizeof(RADDBG_Column), + RADDBG_DataSectionTag_LineInfoColumns, + &column_info_count_raw); + + RADDBG_U32 line_info_count_a = (line_info_voff_count > 0)?line_info_voff_count - 1:0; + RADDBG_U32 line_info_count = raddbg_parse__min(line_info_count_a, line_info_count_raw); + RADDBG_U32 column_info_count = raddbg_parse__min(column_info_count_raw, line_info_count); + + out->voffs = voffs; + out->lines = lines; + out->cols = cols; + out->count = line_info_count; + out->col_count = column_info_count; +} + +RADDBG_PROC RADDBG_U64 +raddbg_line_info_idx_from_voff(RADDBG_ParsedLineInfo *line_info, RADDBG_U64 voff) +{ + RADDBG_U64 result = 0; + if (line_info->count > 0 && line_info->voffs[0] <= voff && voff < line_info->voffs[line_info->count - 1]){ + // assuming: (i < j) -> (vmap[i].voff < vmap[j].voff) + // find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff) + RADDBG_U32 first = 0; + RADDBG_U32 opl = line_info->count; + for (;;){ + RADDBG_U32 mid = (first + opl)/2; + if (line_info->voffs[mid] < voff){ + first = mid; + } + else if (line_info->voffs[mid] > voff){ + opl = mid; + } + else{ + first = mid; + break; + } + if (opl - first <= 1){ + break; + } + } + result = (RADDBG_U64)first; + } + return(result); +} + +RADDBG_PROC void +raddbg_line_map_from_source_file(RADDBG_Parsed *p, RADDBG_SourceFile *srcfile, + RADDBG_ParsedLineMap *out){ + RADDBG_U64 num_count = 0; + RADDBG_U32 *nums = (RADDBG_U32*) + raddbg_data_from_dsec(p, srcfile->line_map_nums_data_idx, sizeof(RADDBG_U32), + RADDBG_DataSectionTag_LineMapNumbers, + &num_count); + + RADDBG_U64 range_count = 0; + RADDBG_U32 *ranges = (RADDBG_U32*) + raddbg_data_from_dsec(p, srcfile->line_map_range_data_idx, sizeof(RADDBG_U32), + RADDBG_DataSectionTag_LineMapRanges, + &range_count); + + RADDBG_U64 voff_count = 0; + RADDBG_U64 *voffs = (RADDBG_U64*) + raddbg_data_from_dsec(p, srcfile->line_map_voff_data_idx, sizeof(RADDBG_U64), + RADDBG_DataSectionTag_LineMapVoffs, + &voff_count); + + RADDBG_U32 count_a = (range_count > 0)?(range_count - 1):0; + RADDBG_U32 count_b = raddbg_parse__min(count_a, num_count); + RADDBG_U32 count = raddbg_parse__min(count_b, srcfile->line_map_count); + + out->nums = nums; + out->ranges = ranges; + out->voffs = voffs; + out->count = count; + out->voff_count = voff_count; +} + +RADDBG_PROC RADDBG_U64* +raddbg_line_voffs_from_num(RADDBG_ParsedLineMap *map, RADDBG_U32 linenum, RADDBG_U32 *n_out){ + RADDBG_U64 *result = 0; + *n_out = 0; + + RADDBG_U32 closest_i = 0; + if (map->count > 0 && map->nums[0] <= linenum){ + // assuming: (i < j) -> (nums[i] < nums[j]) + // find i such that: (nums[i] <= linenum) && (linenum < nums[i + 1]) + RADDBG_U32 *nums = map->nums; + RADDBG_U32 first = 0; + RADDBG_U32 opl = map->count; + for (;;){ + RADDBG_U32 mid = (first + opl)/2; + if (nums[mid] < linenum){ + first = mid; + } + else if (nums[mid] > linenum){ + opl = mid; + } + else{ + first = mid; + break; + } + if (opl - first <= 1){ + break; + } + } + closest_i = first; + } + + // round up instead of down if possible + if (closest_i + 1 < map->count && + map->nums[closest_i] < linenum){ + closest_i += 1; + } + + // set result if possible + if (closest_i < map->count){ + RADDBG_U32 first = map->ranges[closest_i]; + RADDBG_U32 opl = map->ranges[closest_i + 1]; + if (opl < map->voff_count){ + result = map->voffs + first; + *n_out = opl - first; + } + } + + return(result); +} + + +//- vmaps + +RADDBG_PROC RADDBG_U64 +raddbg_vmap_idx_from_voff(RADDBG_VMapEntry *vmap, RADDBG_U32 vmap_count, RADDBG_U64 voff){ + RADDBG_U64 result = 0; + if (vmap_count > 0 && vmap[0].voff <= voff && voff < vmap[vmap_count - 1].voff){ + // assuming: (i < j) -> (vmap[i].voff < vmap[j].voff) + // find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff) + RADDBG_U32 first = 0; + RADDBG_U32 opl = vmap_count; + for (;;){ + RADDBG_U32 mid = (first + opl)/2; + if (vmap[mid].voff < voff){ + first = mid; + } + else if (vmap[mid].voff > voff){ + opl = mid; + } + else{ + first = mid; + break; + } + if (opl - first <= 1){ + break; + } + } + result = (RADDBG_U64)vmap[first].idx; + } + return(result); +} + +//- name maps + +RADDBG_PROC RADDBG_NameMap* +raddbg_name_map_from_kind(RADDBG_Parsed *p, RADDBG_NameMapKind kind){ + RADDBG_NameMap *result = 0; + if (0 < kind && kind < RADDBG_NameMapKind_COUNT){ + result = p->name_maps_by_kind[kind]; + } + return(result); +} + +RADDBG_PROC void +raddbg_name_map_parse(RADDBG_Parsed *p, RADDBG_NameMap *mapptr, RADDBG_ParsedNameMap *out){ + out->buckets = 0; + out->bucket_count = 0; + if (mapptr != 0){ + out->buckets = (RADDBG_NameMapBucket*) + raddbg_data_from_dsec(p, mapptr->bucket_data_idx, sizeof(RADDBG_NameMapBucket), + RADDBG_DataSectionTag_NameMapBuckets, &out->bucket_count); + out->nodes = (RADDBG_NameMapNode*) + raddbg_data_from_dsec(p, mapptr->node_data_idx, sizeof(RADDBG_NameMapNode), + RADDBG_DataSectionTag_NameMapNodes, &out->node_count); + } +} + +RADDBG_PROC RADDBG_NameMapNode* +raddbg_name_map_lookup(RADDBG_Parsed *p, RADDBG_ParsedNameMap *map, + RADDBG_U8 *str, RADDBG_U64 len){ + RADDBG_NameMapNode *result = 0; + if (map->bucket_count > 0){ + RADDBG_NameMapBucket *buckets = map->buckets; + RADDBG_U64 bucket_count = map->bucket_count; + RADDBG_U64 hash = raddbg_hash(str, len); + RADDBG_U64 bucket_index = hash%bucket_count; + RADDBG_NameMapBucket *bucket = map->buckets + bucket_index; + + RADDBG_NameMapNode *node = map->nodes + bucket->first_node; + RADDBG_NameMapNode *node_opl = node + bucket->node_count; + for (;node < node_opl; node += 1){ + // extract a string from this node + RADDBG_U64 nlen = 0; + RADDBG_U8 *nstr = raddbg_string_from_idx(p, node->string_idx, &nlen); + + // compare this to the needle string + RADDBG_S32 match = 0; + if (nlen == len){ + RADDBG_U8 *a = str; + RADDBG_U8 *aopl = str + len; + RADDBG_U8 *b = nstr; + for (;a < aopl && *a == *b; a += 1, b += 1); + match = (a == aopl); + } + + // stop with a matching node in result + if (match){ + result = node; + break; + } + + } + } + return(result); +} + +RADDBG_PROC RADDBG_U32* +raddbg_matches_from_map_node(RADDBG_Parsed *p, RADDBG_NameMapNode *node, + RADDBG_U32 *n_out){ + RADDBG_U32 *result = 0; + *n_out = 0; + if (node != 0){ + if (node->match_count == 1){ + result = &node->match_idx_or_idx_run_first; + *n_out = 1; + } + else{ + result = raddbg_idx_run_from_first_count(p, node->match_idx_or_idx_run_first, + node->match_count, n_out); + } + } + return(result); +} + +//- common helpers + +RADDBG_PROC RADDBG_U64 +raddbg_first_voff_from_proc(RADDBG_Parsed *p, RADDBG_U32 proc_id){ + RADDBG_U64 result = 0; + if (0 < proc_id && proc_id < p->procedure_count){ + RADDBG_Procedure *proc = p->procedures + proc_id; + RADDBG_U32 scope_id = proc->root_scope_idx; + if (0 < scope_id && scope_id < p->scope_count){ + RADDBG_Scope *scope = p->scopes + scope_id; + if (scope->voff_range_first < scope->voff_range_opl && + scope->voff_range_first < p->scope_voff_count){ + result = p->scope_voffs[scope->voff_range_first]; + } + } + } + return(result); +} + +//////////////////////////////// +//~ RADDBG Parsing Helpers + +RADDBG_PROC void* +raddbg_data_from_dsec(RADDBG_Parsed *parsed, RADDBG_U32 idx, RADDBG_U32 item_size, + RADDBG_DataSectionTag expected_tag, + RADDBG_U64 *count_out){ + void *result = 0; + RADDBG_U32 count_result = 0; + + // TODO(allen): need a version of this that works with encodings other than "Unpacked" + + if (0 < idx && idx < parsed->dsec_count){ + RADDBG_DataSection *ds = parsed->dsecs + idx; + if (ds->tag == expected_tag){ + RADDBG_U64 opl = ds->off + ds->encoded_size; + if (opl <= parsed->raw_data_size){ + count_result = ds->encoded_size/item_size; + result = (parsed->raw_data + ds->off); + } + } + } + + *count_out = count_result; + return(result); +} diff --git a/src/raddbg_format/raddbg_format_parse.h b/src/raddbg_format/raddbg_format_parse.h new file mode 100644 index 00000000..f2cf3074 --- /dev/null +++ b/src/raddbg_format/raddbg_format_parse.h @@ -0,0 +1,196 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_PARSE_H +#define RADDBG_PARSE_H + +//////////////////////////////// +//~ RADDBG Parsing Helpers + +typedef struct RADDBG_Parsed{ + // raw data & data sections (part 1) + RADDBG_U8 *raw_data; + RADDBG_U64 raw_data_size; + RADDBG_DataSection *dsecs; + RADDBG_U64 dsec_count; + RADDBG_U32 dsec_idx[RADDBG_DataSectionTag_PRIMARY_COUNT]; + + // primary data structures (part 2) + + // handled by helper APIs + RADDBG_U8* string_data; + RADDBG_U64 string_data_size; + RADDBG_U32* string_offs; + RADDBG_U64 string_count; + RADDBG_U32* idx_run_data; + RADDBG_U32 idx_run_count; + + // directly readable by users + // (any of these may be empty and null even in a successful parse) + RADDBG_TopLevelInfo* top_level_info; + + RADDBG_BinarySection* binary_sections; + RADDBG_U64 binary_section_count; + RADDBG_FilePathNode* file_paths; + RADDBG_U64 file_path_count; + RADDBG_SourceFile* source_files; + RADDBG_U64 source_file_count; + RADDBG_Unit* units; + RADDBG_U64 unit_count; + RADDBG_VMapEntry* unit_vmap; + RADDBG_U64 unit_vmap_count; + RADDBG_TypeNode* type_nodes; + RADDBG_U64 type_node_count; + RADDBG_UDT* udts; + RADDBG_U64 udt_count; + RADDBG_Member* members; + RADDBG_U64 member_count; + RADDBG_EnumMember* enum_members; + RADDBG_U64 enum_member_count; + RADDBG_GlobalVariable* global_variables; + RADDBG_U64 global_variable_count; + RADDBG_VMapEntry* global_vmap; + RADDBG_U64 global_vmap_count; + RADDBG_ThreadVariable* thread_variables; + RADDBG_U64 thread_variable_count; + RADDBG_Procedure* procedures; + RADDBG_U64 procedure_count; + RADDBG_Scope* scopes; + RADDBG_U64 scope_count; + RADDBG_U64* scope_voffs; + RADDBG_U64 scope_voff_count; + RADDBG_VMapEntry* scope_vmap; + RADDBG_U64 scope_vmap_count; + RADDBG_Local* locals; + RADDBG_U64 local_count; + RADDBG_LocationBlock* location_blocks; + RADDBG_U64 location_block_count; + RADDBG_U8* location_data; + RADDBG_U64 location_data_size; + RADDBG_NameMap* name_maps; + RADDBG_U64 name_map_count; + + // other helpers + + RADDBG_NameMap* name_maps_by_kind[RADDBG_NameMapKind_COUNT]; + +} RADDBG_Parsed; + +typedef enum{ + RADDBG_ParseStatus_Good = 0, + RADDBG_ParseStatus_HeaderDoesNotMatch = 1, + RADDBG_ParseStatus_UnsupportedVersionNumber = 2, + RADDBG_ParseStatus_InvalidDataSecionLayout = 3, + RADDBG_ParseStatus_MissingStringDataSection = 4, + RADDBG_ParseStatus_MissingStringTableSection = 5, + RADDBG_ParseStatus_MissingIndexRunSection = 6, +} RADDBG_ParseStatus; + +typedef struct RADDBG_ParsedLineInfo{ + // NOTE: Mapping VOFF -> LINE_INFO + // + // * [ voff[i], voff[i + 1] ) forms the voff range + // * for the line info at lines[i] (and cols[i] if i < col_count) + + RADDBG_U64* voffs; // [count + 1] sorted + RADDBG_Line* lines; // [count] + RADDBG_Column* cols; // [col_count] + RADDBG_U64 count; + RADDBG_U64 col_count; +} RADDBG_ParsedLineInfo; + +typedef struct RADDBG_ParsedLineMap{ + // NOTE: Mapping LINE_NUMBER -> VOFFs + // + // * nums[i] gives a line number + // * that line number has one or more associated voffs + // + // * to find all associated voffs for the line number nums[i] : + // * let k span over the range [ ranges[i], ranges[i + 1] ) + // * voffs[k] gives the associated voffs + + RADDBG_U32* nums; // [count] sorted + RADDBG_U32* ranges; // [count + 1] + RADDBG_U64* voffs; // [voff_count] + RADDBG_U64 count; + RADDBG_U64 voff_count; +} RADDBG_ParsedLineMap; + + +typedef struct RADDBG_ParsedNameMap{ + RADDBG_NameMapBucket *buckets; + RADDBG_NameMapNode *nodes; + RADDBG_U64 bucket_count; + RADDBG_U64 node_count; +} RADDBG_ParsedNameMap; + + +//////////////////////////////// +//~ RADDBG Parse API + +RADDBG_PROC RADDBG_ParseStatus +raddbg_parse(RADDBG_U8 *data, RADDBG_U64 size, RADDBG_Parsed *out); + +RADDBG_PROC RADDBG_U8* +raddbg_string_from_idx(RADDBG_Parsed *parsed, RADDBG_U32 idx, RADDBG_U64 *len_out); + +RADDBG_PROC RADDBG_U32* +raddbg_idx_run_from_first_count(RADDBG_Parsed *parsed, RADDBG_U32 first, RADDBG_U32 raw_count, + RADDBG_U32 *n_out); + + +//- line info +RADDBG_PROC void +raddbg_line_info_from_unit(RADDBG_Parsed *p, RADDBG_Unit *unit, RADDBG_ParsedLineInfo *out); + +RADDBG_PROC RADDBG_U64 +raddbg_line_info_idx_from_voff(RADDBG_ParsedLineInfo *line_info, RADDBG_U64 voff); + +RADDBG_PROC void +raddbg_line_map_from_source_file(RADDBG_Parsed *p, RADDBG_SourceFile *srcfile, + RADDBG_ParsedLineMap *out); + +RADDBG_PROC RADDBG_U64* +raddbg_line_voffs_from_num(RADDBG_ParsedLineMap *map, RADDBG_U32 linenum, RADDBG_U32 *n_out); + + +//- vmaps +RADDBG_PROC RADDBG_U64 +raddbg_vmap_idx_from_voff(RADDBG_VMapEntry *vmap, RADDBG_U32 vmap_count, RADDBG_U64 voff); + + +//- name maps +RADDBG_PROC RADDBG_NameMap* +raddbg_name_map_from_kind(RADDBG_Parsed *p, RADDBG_NameMapKind kind); + +RADDBG_PROC void +raddbg_name_map_parse(RADDBG_Parsed* p, RADDBG_NameMap *mapptr, RADDBG_ParsedNameMap *out); + +RADDBG_PROC RADDBG_NameMapNode* +raddbg_name_map_lookup(RADDBG_Parsed *p, RADDBG_ParsedNameMap *map, + RADDBG_U8 *str, RADDBG_U64 len); + +RADDBG_PROC RADDBG_U32* +raddbg_matches_from_map_node(RADDBG_Parsed *p, RADDBG_NameMapNode *node, RADDBG_U32 *n_out); + + +//- common helpers +RADDBG_PROC RADDBG_U64 +raddbg_first_voff_from_proc(RADDBG_Parsed *p, RADDBG_U32 proc_id); + + + +//////////////////////////////// +//~ RADDBG Parsing Helpers + +#define raddbg_parse__extract_primary(p,outptr,outn,pritag) \ +( (*(void**)&(outptr)) = \ +raddbg_data_from_dsec((p),(p)->dsec_idx[pritag],sizeof(*(outptr)),(pritag),(outn)) ) + +RADDBG_PROC void* +raddbg_data_from_dsec(RADDBG_Parsed *p, RADDBG_U32 idx, RADDBG_U32 item_size, + RADDBG_DataSectionTag expected_tag, RADDBG_U64 *n_out); + +#define raddbg_parse__min(a,b) (((a)<(b))?(a):(b)) + +#endif //RADDBG_PARSE_H diff --git a/src/raddbg_markup/raddbg_markup.h b/src/raddbg_markup/raddbg_markup.h new file mode 100644 index 00000000..66b0fa31 --- /dev/null +++ b/src/raddbg_markup/raddbg_markup.h @@ -0,0 +1,78 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_MARKUP_H +#define RADDBG_MARKUP_H + +//////////////////////////////// +//~ Usage Macros + +#define raddbg_is_attached(...) raddbg_is_attached__impl() +#define raddbg_thread_name(fmt, ...) raddbg_thread_name__impl((fmt), __VA_ARGS__) +#define raddbg_thread_color_hex(hexcode) raddbg_thread_color__impl((hexcode)) +#define raddbg_thread_color_rgba(r, g, b, a) raddbg_thread_color__impl((unsigned int)(((r)*255) << 24) | (unsigned int)(((g)*255) << 16) | (unsigned int)(((b)*255) << 8) | (unsigned int)((a)*255)) +#define raddbg_break(...) raddbg_break__impl() +#define raddbg_break_if(expr, ...) ((expr) ? raddbg_break__impl() : (void)0) +#define raddbg_watch(fmt, ...) raddbg_watch__impl((fmt), __VA_ARGS__) +#define raddbg_pin(expr, ...) /* NOTE(rjf): inspected by debugger ui - does not change program execution */ +#define raddbg_log(fmt, ...) raddbg_log__impl((fmt), __VA_ARGS__) + +//////////////////////////////// +//~ Win32 Implementations + +#if defined(_WIN32) + +//- types + +typedef unsigned long DWORD; +typedef char const *LPCSTR; + +#pragma pack(push, 8) +typedef struct THREADNAME_INFO THREADNAME_INFO; +struct THREADNAME_INFO +{ + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; +}; +#pragma pack(pop) + +//- implementations + +static inline int +raddbg_is_attached__impl(void) +{ + // TODO(rjf) + return 0; +} + +static inline void +raddbg_thread_name__impl(char *fmt, ...) +{ + // TODO(rjf) +} + +static inline void +raddbg_thread_color__impl(unsigned int hexcode) +{ + // TODO(rjf) +} + +#define raddbg_break__impl() (__debugbreak()) + +static inline void +raddbg_watch__impl(char *fmt, ...) +{ + // TODO(rjf) +} + +static inline void +raddbg_log__impl(char *fmt, ...) +{ + // TODO(rjf) +} + +#endif // defined(_WIN32) + +#endif // RADDBG_MARKUP_H diff --git a/src/regs/generated/regs.meta.c b/src/regs/generated/regs.meta.c new file mode 100644 index 00000000..ee37e616 --- /dev/null +++ b/src/regs/generated/regs.meta.c @@ -0,0 +1,104 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +internal U64 regs_block_size_from_architecture(Architecture arch) +{ +U64 result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = sizeof(REGS_RegBlockX64);}break; +case Architecture_x86:{result = sizeof(REGS_RegBlockX86);}break; +} +return result; +} +internal U64 regs_reg_code_count_from_architecture(Architecture arch) +{ +U64 result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = REGS_RegCodeX64_COUNT;}break; +case Architecture_x86:{result = REGS_RegCodeX86_COUNT;}break; +} +return result; +} +internal U64 regs_alias_code_count_from_architecture(Architecture arch) +{ +U64 result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = REGS_AliasCodeX64_COUNT;}break; +case Architecture_x86:{result = REGS_AliasCodeX86_COUNT;}break; +} +return result; +} +internal String8 *regs_reg_code_string_table_from_architecture(Architecture arch) +{ +String8 *result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = regs_g_reg_code_x64_string_table;}break; +case Architecture_x86:{result = regs_g_reg_code_x86_string_table;}break; +} +return result; +} +internal String8 *regs_alias_code_string_table_from_architecture(Architecture arch) +{ +String8 *result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = regs_g_alias_code_x64_string_table;}break; +case Architecture_x86:{result = regs_g_alias_code_x86_string_table;}break; +} +return result; +} +internal REGS_Rng *regs_reg_code_rng_table_from_architecture(Architecture arch) +{ +REGS_Rng *result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = regs_g_reg_code_x64_rng_table;}break; +case Architecture_x86:{result = regs_g_reg_code_x86_rng_table;}break; +} +return result; +} +internal REGS_Slice *regs_alias_code_slice_table_from_architecture(Architecture arch) +{ +REGS_Slice *result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = regs_g_alias_code_x64_slice_table;}break; +case Architecture_x86:{result = regs_g_alias_code_x86_slice_table;}break; +} +return result; +} +internal REGS_UsageKind *regs_reg_code_usage_kind_table_from_architecture(Architecture arch) +{ +REGS_UsageKind *result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = regs_g_reg_code_x64_usage_kind_table;}break; +case Architecture_x86:{result = regs_g_reg_code_x86_usage_kind_table;}break; +} +return result; +} +internal REGS_UsageKind *regs_alias_code_usage_kind_table_from_architecture(Architecture arch) +{ +REGS_UsageKind *result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64:{result = regs_g_alias_code_x64_usage_kind_table;}break; +case Architecture_x86:{result = regs_g_alias_code_x86_usage_kind_table;}break; +} +return result; +} diff --git a/src/regs/generated/regs.meta.h b/src/regs/generated/regs.meta.h new file mode 100644 index 00000000..f1661343 --- /dev/null +++ b/src/regs/generated/regs.meta.h @@ -0,0 +1,1240 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef REGS_META_H +#define REGS_META_H + +typedef enum REGS_RegCodeX64 +{ +REGS_RegCodeX64_NULL, +REGS_RegCodeX64_rax, +REGS_RegCodeX64_rcx, +REGS_RegCodeX64_rdx, +REGS_RegCodeX64_rbx, +REGS_RegCodeX64_rsp, +REGS_RegCodeX64_rbp, +REGS_RegCodeX64_rsi, +REGS_RegCodeX64_rdi, +REGS_RegCodeX64_r8, +REGS_RegCodeX64_r9, +REGS_RegCodeX64_r10, +REGS_RegCodeX64_r11, +REGS_RegCodeX64_r12, +REGS_RegCodeX64_r13, +REGS_RegCodeX64_r14, +REGS_RegCodeX64_r15, +REGS_RegCodeX64_fsbase, +REGS_RegCodeX64_gsbase, +REGS_RegCodeX64_rip, +REGS_RegCodeX64_rflags, +REGS_RegCodeX64_dr0, +REGS_RegCodeX64_dr1, +REGS_RegCodeX64_dr2, +REGS_RegCodeX64_dr3, +REGS_RegCodeX64_dr4, +REGS_RegCodeX64_dr5, +REGS_RegCodeX64_dr6, +REGS_RegCodeX64_dr7, +REGS_RegCodeX64_fpr0, +REGS_RegCodeX64_fpr1, +REGS_RegCodeX64_fpr2, +REGS_RegCodeX64_fpr3, +REGS_RegCodeX64_fpr4, +REGS_RegCodeX64_fpr5, +REGS_RegCodeX64_fpr6, +REGS_RegCodeX64_fpr7, +REGS_RegCodeX64_st0, +REGS_RegCodeX64_st1, +REGS_RegCodeX64_st2, +REGS_RegCodeX64_st3, +REGS_RegCodeX64_st4, +REGS_RegCodeX64_st5, +REGS_RegCodeX64_st6, +REGS_RegCodeX64_st7, +REGS_RegCodeX64_fcw, +REGS_RegCodeX64_fsw, +REGS_RegCodeX64_ftw, +REGS_RegCodeX64_fop, +REGS_RegCodeX64_fcs, +REGS_RegCodeX64_fds, +REGS_RegCodeX64_fip, +REGS_RegCodeX64_fdp, +REGS_RegCodeX64_mxcsr, +REGS_RegCodeX64_mxcsr_mask, +REGS_RegCodeX64_ss, +REGS_RegCodeX64_cs, +REGS_RegCodeX64_ds, +REGS_RegCodeX64_es, +REGS_RegCodeX64_fs, +REGS_RegCodeX64_gs, +REGS_RegCodeX64_ymm0, +REGS_RegCodeX64_ymm1, +REGS_RegCodeX64_ymm2, +REGS_RegCodeX64_ymm3, +REGS_RegCodeX64_ymm4, +REGS_RegCodeX64_ymm5, +REGS_RegCodeX64_ymm6, +REGS_RegCodeX64_ymm7, +REGS_RegCodeX64_ymm8, +REGS_RegCodeX64_ymm9, +REGS_RegCodeX64_ymm10, +REGS_RegCodeX64_ymm11, +REGS_RegCodeX64_ymm12, +REGS_RegCodeX64_ymm13, +REGS_RegCodeX64_ymm14, +REGS_RegCodeX64_ymm15, +REGS_RegCodeX64_COUNT +} REGS_RegCodeX64; + +typedef enum REGS_AliasCodeX64 +{ +REGS_AliasCodeX64_NULL, +REGS_AliasCodeX64_eax, +REGS_AliasCodeX64_ecx, +REGS_AliasCodeX64_edx, +REGS_AliasCodeX64_ebx, +REGS_AliasCodeX64_esp, +REGS_AliasCodeX64_ebp, +REGS_AliasCodeX64_esi, +REGS_AliasCodeX64_edi, +REGS_AliasCodeX64_r8d, +REGS_AliasCodeX64_r9d, +REGS_AliasCodeX64_r10d, +REGS_AliasCodeX64_r11d, +REGS_AliasCodeX64_r12d, +REGS_AliasCodeX64_r13d, +REGS_AliasCodeX64_r14d, +REGS_AliasCodeX64_r15d, +REGS_AliasCodeX64_eip, +REGS_AliasCodeX64_eflags, +REGS_AliasCodeX64_ax, +REGS_AliasCodeX64_cx, +REGS_AliasCodeX64_dx, +REGS_AliasCodeX64_bx, +REGS_AliasCodeX64_si, +REGS_AliasCodeX64_di, +REGS_AliasCodeX64_sp, +REGS_AliasCodeX64_bp, +REGS_AliasCodeX64_ip, +REGS_AliasCodeX64_r8w, +REGS_AliasCodeX64_r9w, +REGS_AliasCodeX64_r10w, +REGS_AliasCodeX64_r11w, +REGS_AliasCodeX64_r12w, +REGS_AliasCodeX64_r13w, +REGS_AliasCodeX64_r14w, +REGS_AliasCodeX64_r15w, +REGS_AliasCodeX64_al, +REGS_AliasCodeX64_cl, +REGS_AliasCodeX64_dl, +REGS_AliasCodeX64_bl, +REGS_AliasCodeX64_sil, +REGS_AliasCodeX64_dil, +REGS_AliasCodeX64_bpl, +REGS_AliasCodeX64_spl, +REGS_AliasCodeX64_r8b, +REGS_AliasCodeX64_r9b, +REGS_AliasCodeX64_r10b, +REGS_AliasCodeX64_r11b, +REGS_AliasCodeX64_r12b, +REGS_AliasCodeX64_r13b, +REGS_AliasCodeX64_r14b, +REGS_AliasCodeX64_r15b, +REGS_AliasCodeX64_ah, +REGS_AliasCodeX64_ch, +REGS_AliasCodeX64_dh, +REGS_AliasCodeX64_bh, +REGS_AliasCodeX64_xmm0, +REGS_AliasCodeX64_xmm1, +REGS_AliasCodeX64_xmm2, +REGS_AliasCodeX64_xmm3, +REGS_AliasCodeX64_xmm4, +REGS_AliasCodeX64_xmm5, +REGS_AliasCodeX64_xmm6, +REGS_AliasCodeX64_xmm7, +REGS_AliasCodeX64_xmm8, +REGS_AliasCodeX64_xmm9, +REGS_AliasCodeX64_xmm10, +REGS_AliasCodeX64_xmm11, +REGS_AliasCodeX64_xmm12, +REGS_AliasCodeX64_xmm13, +REGS_AliasCodeX64_xmm14, +REGS_AliasCodeX64_xmm15, +REGS_AliasCodeX64_mm0, +REGS_AliasCodeX64_mm1, +REGS_AliasCodeX64_mm2, +REGS_AliasCodeX64_mm3, +REGS_AliasCodeX64_mm4, +REGS_AliasCodeX64_mm5, +REGS_AliasCodeX64_mm6, +REGS_AliasCodeX64_mm7, +REGS_AliasCodeX64_COUNT +} REGS_AliasCodeX64; + +typedef enum REGS_RegCodeX86 +{ +REGS_RegCodeX86_NULL, +REGS_RegCodeX86_eax, +REGS_RegCodeX86_ecx, +REGS_RegCodeX86_edx, +REGS_RegCodeX86_ebx, +REGS_RegCodeX86_esp, +REGS_RegCodeX86_ebp, +REGS_RegCodeX86_esi, +REGS_RegCodeX86_edi, +REGS_RegCodeX86_fsbase, +REGS_RegCodeX86_gsbase, +REGS_RegCodeX86_eflags, +REGS_RegCodeX86_eip, +REGS_RegCodeX86_dr0, +REGS_RegCodeX86_dr1, +REGS_RegCodeX86_dr2, +REGS_RegCodeX86_dr3, +REGS_RegCodeX86_dr4, +REGS_RegCodeX86_dr5, +REGS_RegCodeX86_dr6, +REGS_RegCodeX86_dr7, +REGS_RegCodeX86_fpr0, +REGS_RegCodeX86_fpr1, +REGS_RegCodeX86_fpr2, +REGS_RegCodeX86_fpr3, +REGS_RegCodeX86_fpr4, +REGS_RegCodeX86_fpr5, +REGS_RegCodeX86_fpr6, +REGS_RegCodeX86_fpr7, +REGS_RegCodeX86_st0, +REGS_RegCodeX86_st1, +REGS_RegCodeX86_st2, +REGS_RegCodeX86_st3, +REGS_RegCodeX86_st4, +REGS_RegCodeX86_st5, +REGS_RegCodeX86_st6, +REGS_RegCodeX86_st7, +REGS_RegCodeX86_fcw, +REGS_RegCodeX86_fsw, +REGS_RegCodeX86_ftw, +REGS_RegCodeX86_fop, +REGS_RegCodeX86_fcs, +REGS_RegCodeX86_fds, +REGS_RegCodeX86_fip, +REGS_RegCodeX86_fdp, +REGS_RegCodeX86_mxcsr, +REGS_RegCodeX86_mxcsr_mask, +REGS_RegCodeX86_ss, +REGS_RegCodeX86_cs, +REGS_RegCodeX86_ds, +REGS_RegCodeX86_es, +REGS_RegCodeX86_fs, +REGS_RegCodeX86_gs, +REGS_RegCodeX86_ymm0, +REGS_RegCodeX86_ymm1, +REGS_RegCodeX86_ymm2, +REGS_RegCodeX86_ymm3, +REGS_RegCodeX86_ymm4, +REGS_RegCodeX86_ymm5, +REGS_RegCodeX86_ymm6, +REGS_RegCodeX86_ymm7, +REGS_RegCodeX86_COUNT +} REGS_RegCodeX86; + +typedef enum REGS_AliasCodeX86 +{ +REGS_AliasCodeX86_NULL, +REGS_AliasCodeX86_ax, +REGS_AliasCodeX86_cx, +REGS_AliasCodeX86_bx, +REGS_AliasCodeX86_dx, +REGS_AliasCodeX86_sp, +REGS_AliasCodeX86_bp, +REGS_AliasCodeX86_si, +REGS_AliasCodeX86_di, +REGS_AliasCodeX86_ip, +REGS_AliasCodeX86_ah, +REGS_AliasCodeX86_ch, +REGS_AliasCodeX86_dh, +REGS_AliasCodeX86_bh, +REGS_AliasCodeX86_al, +REGS_AliasCodeX86_cl, +REGS_AliasCodeX86_dl, +REGS_AliasCodeX86_bl, +REGS_AliasCodeX86_bpl, +REGS_AliasCodeX86_spl, +REGS_AliasCodeX86_xmm0, +REGS_AliasCodeX86_xmm1, +REGS_AliasCodeX86_xmm2, +REGS_AliasCodeX86_xmm3, +REGS_AliasCodeX86_xmm4, +REGS_AliasCodeX86_xmm5, +REGS_AliasCodeX86_xmm6, +REGS_AliasCodeX86_xmm7, +REGS_AliasCodeX86_mm0, +REGS_AliasCodeX86_mm1, +REGS_AliasCodeX86_mm2, +REGS_AliasCodeX86_mm3, +REGS_AliasCodeX86_mm4, +REGS_AliasCodeX86_mm5, +REGS_AliasCodeX86_mm6, +REGS_AliasCodeX86_mm7, +REGS_AliasCodeX86_COUNT +} REGS_AliasCodeX86; + +typedef struct REGS_RegBlockX64 REGS_RegBlockX64; +struct REGS_RegBlockX64 +{ +REGS_Reg64 rax; +REGS_Reg64 rcx; +REGS_Reg64 rdx; +REGS_Reg64 rbx; +REGS_Reg64 rsp; +REGS_Reg64 rbp; +REGS_Reg64 rsi; +REGS_Reg64 rdi; +REGS_Reg64 r8; +REGS_Reg64 r9; +REGS_Reg64 r10; +REGS_Reg64 r11; +REGS_Reg64 r12; +REGS_Reg64 r13; +REGS_Reg64 r14; +REGS_Reg64 r15; +REGS_Reg64 fsbase; +REGS_Reg64 gsbase; +REGS_Reg64 rip; +REGS_Reg64 rflags; +REGS_Reg32 dr0; +REGS_Reg32 dr1; +REGS_Reg32 dr2; +REGS_Reg32 dr3; +REGS_Reg32 dr4; +REGS_Reg32 dr5; +REGS_Reg32 dr6; +REGS_Reg32 dr7; +REGS_Reg80 fpr0; +REGS_Reg80 fpr1; +REGS_Reg80 fpr2; +REGS_Reg80 fpr3; +REGS_Reg80 fpr4; +REGS_Reg80 fpr5; +REGS_Reg80 fpr6; +REGS_Reg80 fpr7; +REGS_Reg80 st0; +REGS_Reg80 st1; +REGS_Reg80 st2; +REGS_Reg80 st3; +REGS_Reg80 st4; +REGS_Reg80 st5; +REGS_Reg80 st6; +REGS_Reg80 st7; +REGS_Reg16 fcw; +REGS_Reg16 fsw; +REGS_Reg16 ftw; +REGS_Reg16 fop; +REGS_Reg16 fcs; +REGS_Reg16 fds; +REGS_Reg32 fip; +REGS_Reg32 fdp; +REGS_Reg32 mxcsr; +REGS_Reg32 mxcsr_mask; +REGS_Reg16 ss; +REGS_Reg16 cs; +REGS_Reg16 ds; +REGS_Reg16 es; +REGS_Reg16 fs; +REGS_Reg16 gs; +REGS_Reg256 ymm0; +REGS_Reg256 ymm1; +REGS_Reg256 ymm2; +REGS_Reg256 ymm3; +REGS_Reg256 ymm4; +REGS_Reg256 ymm5; +REGS_Reg256 ymm6; +REGS_Reg256 ymm7; +REGS_Reg256 ymm8; +REGS_Reg256 ymm9; +REGS_Reg256 ymm10; +REGS_Reg256 ymm11; +REGS_Reg256 ymm12; +REGS_Reg256 ymm13; +REGS_Reg256 ymm14; +REGS_Reg256 ymm15; +}; + +typedef struct REGS_RegBlockX86 REGS_RegBlockX86; +struct REGS_RegBlockX86 +{ +REGS_Reg32 eax; +REGS_Reg32 ecx; +REGS_Reg32 edx; +REGS_Reg32 ebx; +REGS_Reg32 esp; +REGS_Reg32 ebp; +REGS_Reg32 esi; +REGS_Reg32 edi; +REGS_Reg32 fsbase; +REGS_Reg32 gsbase; +REGS_Reg32 eflags; +REGS_Reg32 eip; +REGS_Reg32 dr0; +REGS_Reg32 dr1; +REGS_Reg32 dr2; +REGS_Reg32 dr3; +REGS_Reg32 dr4; +REGS_Reg32 dr5; +REGS_Reg32 dr6; +REGS_Reg32 dr7; +REGS_Reg80 fpr0; +REGS_Reg80 fpr1; +REGS_Reg80 fpr2; +REGS_Reg80 fpr3; +REGS_Reg80 fpr4; +REGS_Reg80 fpr5; +REGS_Reg80 fpr6; +REGS_Reg80 fpr7; +REGS_Reg80 st0; +REGS_Reg80 st1; +REGS_Reg80 st2; +REGS_Reg80 st3; +REGS_Reg80 st4; +REGS_Reg80 st5; +REGS_Reg80 st6; +REGS_Reg80 st7; +REGS_Reg16 fcw; +REGS_Reg16 fsw; +REGS_Reg16 ftw; +REGS_Reg16 fop; +REGS_Reg16 fcs; +REGS_Reg16 fds; +REGS_Reg32 fip; +REGS_Reg32 fdp; +REGS_Reg32 mxcsr; +REGS_Reg32 mxcsr_mask; +REGS_Reg16 ss; +REGS_Reg16 cs; +REGS_Reg16 ds; +REGS_Reg16 es; +REGS_Reg16 fs; +REGS_Reg16 gs; +REGS_Reg256 ymm0; +REGS_Reg256 ymm1; +REGS_Reg256 ymm2; +REGS_Reg256 ymm3; +REGS_Reg256 ymm4; +REGS_Reg256 ymm5; +REGS_Reg256 ymm6; +REGS_Reg256 ymm7; +}; + +REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +REGS_UsageKind regs_g_alias_code_x64_usage_kind_table[] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +String8 regs_g_reg_code_x64_string_table[] = +{ +str8_lit_comp(""), +str8_lit_comp("rax"), +str8_lit_comp("rcx"), +str8_lit_comp("rdx"), +str8_lit_comp("rbx"), +str8_lit_comp("rsp"), +str8_lit_comp("rbp"), +str8_lit_comp("rsi"), +str8_lit_comp("rdi"), +str8_lit_comp("r8"), +str8_lit_comp("r9"), +str8_lit_comp("r10"), +str8_lit_comp("r11"), +str8_lit_comp("r12"), +str8_lit_comp("r13"), +str8_lit_comp("r14"), +str8_lit_comp("r15"), +str8_lit_comp("fsbase"), +str8_lit_comp("gsbase"), +str8_lit_comp("rip"), +str8_lit_comp("rflags"), +str8_lit_comp("dr0"), +str8_lit_comp("dr1"), +str8_lit_comp("dr2"), +str8_lit_comp("dr3"), +str8_lit_comp("dr4"), +str8_lit_comp("dr5"), +str8_lit_comp("dr6"), +str8_lit_comp("dr7"), +str8_lit_comp("fpr0"), +str8_lit_comp("fpr1"), +str8_lit_comp("fpr2"), +str8_lit_comp("fpr3"), +str8_lit_comp("fpr4"), +str8_lit_comp("fpr5"), +str8_lit_comp("fpr6"), +str8_lit_comp("fpr7"), +str8_lit_comp("st0"), +str8_lit_comp("st1"), +str8_lit_comp("st2"), +str8_lit_comp("st3"), +str8_lit_comp("st4"), +str8_lit_comp("st5"), +str8_lit_comp("st6"), +str8_lit_comp("st7"), +str8_lit_comp("fcw"), +str8_lit_comp("fsw"), +str8_lit_comp("ftw"), +str8_lit_comp("fop"), +str8_lit_comp("fcs"), +str8_lit_comp("fds"), +str8_lit_comp("fip"), +str8_lit_comp("fdp"), +str8_lit_comp("mxcsr"), +str8_lit_comp("mxcsr_mask"), +str8_lit_comp("ss"), +str8_lit_comp("cs"), +str8_lit_comp("ds"), +str8_lit_comp("es"), +str8_lit_comp("fs"), +str8_lit_comp("gs"), +str8_lit_comp("ymm0"), +str8_lit_comp("ymm1"), +str8_lit_comp("ymm2"), +str8_lit_comp("ymm3"), +str8_lit_comp("ymm4"), +str8_lit_comp("ymm5"), +str8_lit_comp("ymm6"), +str8_lit_comp("ymm7"), +str8_lit_comp("ymm8"), +str8_lit_comp("ymm9"), +str8_lit_comp("ymm10"), +str8_lit_comp("ymm11"), +str8_lit_comp("ymm12"), +str8_lit_comp("ymm13"), +str8_lit_comp("ymm14"), +str8_lit_comp("ymm15"), +}; + +String8 regs_g_alias_code_x64_string_table[] = +{ +str8_lit_comp(""), +str8_lit_comp("eax"), +str8_lit_comp("ecx"), +str8_lit_comp("edx"), +str8_lit_comp("ebx"), +str8_lit_comp("esp"), +str8_lit_comp("ebp"), +str8_lit_comp("esi"), +str8_lit_comp("edi"), +str8_lit_comp("r8d"), +str8_lit_comp("r9d"), +str8_lit_comp("r10d"), +str8_lit_comp("r11d"), +str8_lit_comp("r12d"), +str8_lit_comp("r13d"), +str8_lit_comp("r14d"), +str8_lit_comp("r15d"), +str8_lit_comp("eip"), +str8_lit_comp("eflags"), +str8_lit_comp("ax"), +str8_lit_comp("cx"), +str8_lit_comp("dx"), +str8_lit_comp("bx"), +str8_lit_comp("si"), +str8_lit_comp("di"), +str8_lit_comp("sp"), +str8_lit_comp("bp"), +str8_lit_comp("ip"), +str8_lit_comp("r8w"), +str8_lit_comp("r9w"), +str8_lit_comp("r10w"), +str8_lit_comp("r11w"), +str8_lit_comp("r12w"), +str8_lit_comp("r13w"), +str8_lit_comp("r14w"), +str8_lit_comp("r15w"), +str8_lit_comp("al"), +str8_lit_comp("cl"), +str8_lit_comp("dl"), +str8_lit_comp("bl"), +str8_lit_comp("sil"), +str8_lit_comp("dil"), +str8_lit_comp("bpl"), +str8_lit_comp("spl"), +str8_lit_comp("r8b"), +str8_lit_comp("r9b"), +str8_lit_comp("r10b"), +str8_lit_comp("r11b"), +str8_lit_comp("r12b"), +str8_lit_comp("r13b"), +str8_lit_comp("r14b"), +str8_lit_comp("r15b"), +str8_lit_comp("ah"), +str8_lit_comp("ch"), +str8_lit_comp("dh"), +str8_lit_comp("bh"), +str8_lit_comp("xmm0"), +str8_lit_comp("xmm1"), +str8_lit_comp("xmm2"), +str8_lit_comp("xmm3"), +str8_lit_comp("xmm4"), +str8_lit_comp("xmm5"), +str8_lit_comp("xmm6"), +str8_lit_comp("xmm7"), +str8_lit_comp("xmm8"), +str8_lit_comp("xmm9"), +str8_lit_comp("xmm10"), +str8_lit_comp("xmm11"), +str8_lit_comp("xmm12"), +str8_lit_comp("xmm13"), +str8_lit_comp("xmm14"), +str8_lit_comp("xmm15"), +str8_lit_comp("mm0"), +str8_lit_comp("mm1"), +str8_lit_comp("mm2"), +str8_lit_comp("mm3"), +str8_lit_comp("mm4"), +str8_lit_comp("mm5"), +str8_lit_comp("mm6"), +str8_lit_comp("mm7"), +}; + +REGS_Rng regs_g_reg_code_x64_rng_table[] = +{ +{0}, +{(U16)OffsetOf(REGS_RegBlockX64, rax), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rcx), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rdx), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rbx), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rsp), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rbp), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rsi), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rdi), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r8), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r9), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r10), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r11), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r12), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r13), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r14), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r15), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, fsbase), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, gsbase), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rip), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rflags), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr0), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr1), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr2), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr3), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr4), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr5), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr6), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr7), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr0), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr1), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr2), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr3), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr4), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr5), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr6), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr7), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st0), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st1), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st2), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st3), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st4), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st5), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st6), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st7), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fcw), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fsw), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, ftw), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fop), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fcs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fds), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fip), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, fdp), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, mxcsr), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, mxcsr_mask), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, ss), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, cs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, ds), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, es), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, gs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm0), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm1), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm2), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm3), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm4), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm5), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm6), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm7), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm8), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm9), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm10), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm11), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm12), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm13), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm14), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm15), 32}, +}; + +REGS_Slice regs_g_alias_code_x64_slice_table[] = +{ +{0}, +{REGS_RegCodeX64_rax, 0, 4}, +{REGS_RegCodeX64_rcx, 0, 4}, +{REGS_RegCodeX64_rdx, 0, 4}, +{REGS_RegCodeX64_rbx, 0, 4}, +{REGS_RegCodeX64_rsp, 0, 4}, +{REGS_RegCodeX64_rbp, 0, 4}, +{REGS_RegCodeX64_rsi, 0, 4}, +{REGS_RegCodeX64_rdi, 0, 4}, +{REGS_RegCodeX64_r8, 0, 4}, +{REGS_RegCodeX64_r9, 0, 4}, +{REGS_RegCodeX64_r10, 0, 4}, +{REGS_RegCodeX64_r11, 0, 4}, +{REGS_RegCodeX64_r12, 0, 4}, +{REGS_RegCodeX64_r13, 0, 4}, +{REGS_RegCodeX64_r14, 0, 4}, +{REGS_RegCodeX64_r15, 0, 4}, +{REGS_RegCodeX64_rip, 0, 4}, +{REGS_RegCodeX64_rflags, 0, 4}, +{REGS_RegCodeX64_rax, 0, 2}, +{REGS_RegCodeX64_rcx, 0, 2}, +{REGS_RegCodeX64_rdx, 0, 2}, +{REGS_RegCodeX64_rbx, 0, 2}, +{REGS_RegCodeX64_rsi, 0, 2}, +{REGS_RegCodeX64_rdi, 0, 2}, +{REGS_RegCodeX64_rsp, 0, 2}, +{REGS_RegCodeX64_rbp, 0, 2}, +{REGS_RegCodeX64_rip, 0, 2}, +{REGS_RegCodeX64_r8, 0, 2}, +{REGS_RegCodeX64_r9, 0, 2}, +{REGS_RegCodeX64_r10, 0, 2}, +{REGS_RegCodeX64_r11, 0, 2}, +{REGS_RegCodeX64_r12, 0, 2}, +{REGS_RegCodeX64_r13, 0, 2}, +{REGS_RegCodeX64_r14, 0, 2}, +{REGS_RegCodeX64_r15, 0, 2}, +{REGS_RegCodeX64_rax, 0, 1}, +{REGS_RegCodeX64_rcx, 0, 1}, +{REGS_RegCodeX64_rdx, 0, 1}, +{REGS_RegCodeX64_rbx, 0, 1}, +{REGS_RegCodeX64_rsi, 0, 1}, +{REGS_RegCodeX64_rdi, 0, 1}, +{REGS_RegCodeX64_rbp, 0, 1}, +{REGS_RegCodeX64_rsp, 0, 1}, +{REGS_RegCodeX64_r8, 0, 1}, +{REGS_RegCodeX64_r9, 0, 1}, +{REGS_RegCodeX64_r10, 0, 1}, +{REGS_RegCodeX64_r11, 0, 1}, +{REGS_RegCodeX64_r12, 0, 1}, +{REGS_RegCodeX64_r13, 0, 1}, +{REGS_RegCodeX64_r14, 0, 1}, +{REGS_RegCodeX64_r15, 0, 1}, +{REGS_RegCodeX64_rax, 1, 1}, +{REGS_RegCodeX64_rcx, 1, 1}, +{REGS_RegCodeX64_rdx, 1, 1}, +{REGS_RegCodeX64_rbx, 1, 1}, +{REGS_RegCodeX64_ymm0, 0, 16}, +{REGS_RegCodeX64_ymm1, 0, 16}, +{REGS_RegCodeX64_ymm2, 0, 16}, +{REGS_RegCodeX64_ymm3, 0, 16}, +{REGS_RegCodeX64_ymm4, 0, 16}, +{REGS_RegCodeX64_ymm5, 0, 16}, +{REGS_RegCodeX64_ymm6, 0, 16}, +{REGS_RegCodeX64_ymm7, 0, 16}, +{REGS_RegCodeX64_ymm8, 0, 16}, +{REGS_RegCodeX64_ymm9, 0, 16}, +{REGS_RegCodeX64_ymm10, 0, 16}, +{REGS_RegCodeX64_ymm11, 0, 16}, +{REGS_RegCodeX64_ymm12, 0, 16}, +{REGS_RegCodeX64_ymm13, 0, 16}, +{REGS_RegCodeX64_ymm14, 0, 16}, +{REGS_RegCodeX64_ymm15, 0, 16}, +{REGS_RegCodeX64_fpr0, 0, 8}, +{REGS_RegCodeX64_fpr1, 0, 8}, +{REGS_RegCodeX64_fpr2, 0, 8}, +{REGS_RegCodeX64_fpr3, 0, 8}, +{REGS_RegCodeX64_fpr4, 0, 8}, +{REGS_RegCodeX64_fpr5, 0, 8}, +{REGS_RegCodeX64_fpr6, 0, 8}, +{REGS_RegCodeX64_fpr7, 0, 8}, +}; + +REGS_UsageKind regs_g_reg_code_x86_usage_kind_table[] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +REGS_UsageKind regs_g_alias_code_x86_usage_kind_table[] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +String8 regs_g_reg_code_x86_string_table[] = +{ +str8_lit_comp(""), +str8_lit_comp("eax"), +str8_lit_comp("ecx"), +str8_lit_comp("edx"), +str8_lit_comp("ebx"), +str8_lit_comp("esp"), +str8_lit_comp("ebp"), +str8_lit_comp("esi"), +str8_lit_comp("edi"), +str8_lit_comp("fsbase"), +str8_lit_comp("gsbase"), +str8_lit_comp("eflags"), +str8_lit_comp("eip"), +str8_lit_comp("dr0"), +str8_lit_comp("dr1"), +str8_lit_comp("dr2"), +str8_lit_comp("dr3"), +str8_lit_comp("dr4"), +str8_lit_comp("dr5"), +str8_lit_comp("dr6"), +str8_lit_comp("dr7"), +str8_lit_comp("fpr0"), +str8_lit_comp("fpr1"), +str8_lit_comp("fpr2"), +str8_lit_comp("fpr3"), +str8_lit_comp("fpr4"), +str8_lit_comp("fpr5"), +str8_lit_comp("fpr6"), +str8_lit_comp("fpr7"), +str8_lit_comp("st0"), +str8_lit_comp("st1"), +str8_lit_comp("st2"), +str8_lit_comp("st3"), +str8_lit_comp("st4"), +str8_lit_comp("st5"), +str8_lit_comp("st6"), +str8_lit_comp("st7"), +str8_lit_comp("fcw"), +str8_lit_comp("fsw"), +str8_lit_comp("ftw"), +str8_lit_comp("fop"), +str8_lit_comp("fcs"), +str8_lit_comp("fds"), +str8_lit_comp("fip"), +str8_lit_comp("fdp"), +str8_lit_comp("mxcsr"), +str8_lit_comp("mxcsr_mask"), +str8_lit_comp("ss"), +str8_lit_comp("cs"), +str8_lit_comp("ds"), +str8_lit_comp("es"), +str8_lit_comp("fs"), +str8_lit_comp("gs"), +str8_lit_comp("ymm0"), +str8_lit_comp("ymm1"), +str8_lit_comp("ymm2"), +str8_lit_comp("ymm3"), +str8_lit_comp("ymm4"), +str8_lit_comp("ymm5"), +str8_lit_comp("ymm6"), +str8_lit_comp("ymm7"), +}; + +String8 regs_g_alias_code_x86_string_table[] = +{ +str8_lit_comp(""), +str8_lit_comp("ax"), +str8_lit_comp("cx"), +str8_lit_comp("bx"), +str8_lit_comp("dx"), +str8_lit_comp("sp"), +str8_lit_comp("bp"), +str8_lit_comp("si"), +str8_lit_comp("di"), +str8_lit_comp("ip"), +str8_lit_comp("ah"), +str8_lit_comp("ch"), +str8_lit_comp("dh"), +str8_lit_comp("bh"), +str8_lit_comp("al"), +str8_lit_comp("cl"), +str8_lit_comp("dl"), +str8_lit_comp("bl"), +str8_lit_comp("bpl"), +str8_lit_comp("spl"), +str8_lit_comp("xmm0"), +str8_lit_comp("xmm1"), +str8_lit_comp("xmm2"), +str8_lit_comp("xmm3"), +str8_lit_comp("xmm4"), +str8_lit_comp("xmm5"), +str8_lit_comp("xmm6"), +str8_lit_comp("xmm7"), +str8_lit_comp("mm0"), +str8_lit_comp("mm1"), +str8_lit_comp("mm2"), +str8_lit_comp("mm3"), +str8_lit_comp("mm4"), +str8_lit_comp("mm5"), +str8_lit_comp("mm6"), +str8_lit_comp("mm7"), +}; + +REGS_Rng regs_g_reg_code_x86_rng_table[] = +{ +{0}, +{(U16)OffsetOf(REGS_RegBlockX86, eax), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ecx), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, edx), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ebx), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, esp), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ebp), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, esi), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, edi), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, fsbase), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, gsbase), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, eflags), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, eip), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr0), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr1), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr2), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr3), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr4), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr5), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr6), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr7), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr0), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr1), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr2), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr3), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr4), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr5), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr6), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr7), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st0), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st1), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st2), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st3), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st4), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st5), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st6), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st7), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fcw), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fsw), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, ftw), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fop), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fcs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fds), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fip), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, fdp), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, mxcsr), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, mxcsr_mask), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ss), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, cs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, ds), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, es), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, gs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm0), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm1), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm2), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm3), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm4), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm5), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm6), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm7), 32}, +}; + +REGS_Slice regs_g_alias_code_x86_slice_table[] = +{ +{0}, +{REGS_RegCodeX86_eax, 0, 2}, +{REGS_RegCodeX86_ecx, 0, 2}, +{REGS_RegCodeX86_ebx, 0, 2}, +{REGS_RegCodeX86_edx, 0, 2}, +{REGS_RegCodeX86_esp, 0, 2}, +{REGS_RegCodeX86_ebp, 0, 2}, +{REGS_RegCodeX86_esi, 0, 2}, +{REGS_RegCodeX86_edi, 0, 2}, +{REGS_RegCodeX86_eip, 0, 2}, +{REGS_RegCodeX86_eax, 1, 1}, +{REGS_RegCodeX86_ecx, 1, 1}, +{REGS_RegCodeX86_edx, 1, 1}, +{REGS_RegCodeX86_ebx, 1, 1}, +{REGS_RegCodeX86_eax, 0, 1}, +{REGS_RegCodeX86_ecx, 0, 1}, +{REGS_RegCodeX86_edx, 0, 1}, +{REGS_RegCodeX86_ebx, 0, 1}, +{REGS_RegCodeX86_ebp, 0, 1}, +{REGS_RegCodeX86_esp, 0, 1}, +{REGS_RegCodeX86_ymm0, 0, 16}, +{REGS_RegCodeX86_ymm1, 0, 16}, +{REGS_RegCodeX86_ymm2, 0, 16}, +{REGS_RegCodeX86_ymm3, 0, 16}, +{REGS_RegCodeX86_ymm4, 0, 16}, +{REGS_RegCodeX86_ymm5, 0, 16}, +{REGS_RegCodeX86_ymm6, 0, 16}, +{REGS_RegCodeX86_ymm7, 0, 16}, +{REGS_RegCodeX86_fpr0, 0, 8}, +{REGS_RegCodeX86_fpr1, 0, 8}, +{REGS_RegCodeX86_fpr2, 0, 8}, +{REGS_RegCodeX86_fpr3, 0, 8}, +{REGS_RegCodeX86_fpr4, 0, 8}, +{REGS_RegCodeX86_fpr5, 0, 8}, +{REGS_RegCodeX86_fpr6, 0, 8}, +{REGS_RegCodeX86_fpr7, 0, 8}, +}; + + +#endif // REGS_META_H diff --git a/src/regs/generated/regs_raddbg.meta.c b/src/regs/generated/regs_raddbg.meta.c new file mode 100644 index 00000000..8b322f55 --- /dev/null +++ b/src/regs/generated/regs_raddbg.meta.c @@ -0,0 +1,322 @@ +// generated +#ifndef _REGS_RADDBG_META_C +#define _REGS_RADDBG_META_C + +internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code) +{ +RADDBG_RegisterCode result = 0; +switch(arch) +{ +case Architecture_x64: +{ +switch(code) +{ +default:{}break; +case REGS_RegCodeX64_rax:{result = RADDBG_RegisterCode_X64_rax;}break; +case REGS_RegCodeX64_rcx:{result = RADDBG_RegisterCode_X64_rcx;}break; +case REGS_RegCodeX64_rdx:{result = RADDBG_RegisterCode_X64_rdx;}break; +case REGS_RegCodeX64_rbx:{result = RADDBG_RegisterCode_X64_rbx;}break; +case REGS_RegCodeX64_rsp:{result = RADDBG_RegisterCode_X64_rsp;}break; +case REGS_RegCodeX64_rbp:{result = RADDBG_RegisterCode_X64_rbp;}break; +case REGS_RegCodeX64_rsi:{result = RADDBG_RegisterCode_X64_rsi;}break; +case REGS_RegCodeX64_rdi:{result = RADDBG_RegisterCode_X64_rdi;}break; +case REGS_RegCodeX64_r8:{result = RADDBG_RegisterCode_X64_r8;}break; +case REGS_RegCodeX64_r9:{result = RADDBG_RegisterCode_X64_r9;}break; +case REGS_RegCodeX64_r10:{result = RADDBG_RegisterCode_X64_r10;}break; +case REGS_RegCodeX64_r11:{result = RADDBG_RegisterCode_X64_r11;}break; +case REGS_RegCodeX64_r12:{result = RADDBG_RegisterCode_X64_r12;}break; +case REGS_RegCodeX64_r13:{result = RADDBG_RegisterCode_X64_r13;}break; +case REGS_RegCodeX64_r14:{result = RADDBG_RegisterCode_X64_r14;}break; +case REGS_RegCodeX64_r15:{result = RADDBG_RegisterCode_X64_r15;}break; +case REGS_RegCodeX64_fsbase:{result = RADDBG_RegisterCode_X64_fsbase;}break; +case REGS_RegCodeX64_gsbase:{result = RADDBG_RegisterCode_X64_gsbase;}break; +case REGS_RegCodeX64_rip:{result = RADDBG_RegisterCode_X64_rip;}break; +case REGS_RegCodeX64_rflags:{result = RADDBG_RegisterCode_X64_rflags;}break; +case REGS_RegCodeX64_dr0:{result = RADDBG_RegisterCode_X64_dr0;}break; +case REGS_RegCodeX64_dr1:{result = RADDBG_RegisterCode_X64_dr1;}break; +case REGS_RegCodeX64_dr2:{result = RADDBG_RegisterCode_X64_dr2;}break; +case REGS_RegCodeX64_dr3:{result = RADDBG_RegisterCode_X64_dr3;}break; +case REGS_RegCodeX64_dr4:{result = RADDBG_RegisterCode_X64_dr4;}break; +case REGS_RegCodeX64_dr5:{result = RADDBG_RegisterCode_X64_dr5;}break; +case REGS_RegCodeX64_dr6:{result = RADDBG_RegisterCode_X64_dr6;}break; +case REGS_RegCodeX64_dr7:{result = RADDBG_RegisterCode_X64_dr7;}break; +case REGS_RegCodeX64_fpr0:{result = RADDBG_RegisterCode_X64_fpr0;}break; +case REGS_RegCodeX64_fpr1:{result = RADDBG_RegisterCode_X64_fpr1;}break; +case REGS_RegCodeX64_fpr2:{result = RADDBG_RegisterCode_X64_fpr2;}break; +case REGS_RegCodeX64_fpr3:{result = RADDBG_RegisterCode_X64_fpr3;}break; +case REGS_RegCodeX64_fpr4:{result = RADDBG_RegisterCode_X64_fpr4;}break; +case REGS_RegCodeX64_fpr5:{result = RADDBG_RegisterCode_X64_fpr5;}break; +case REGS_RegCodeX64_fpr6:{result = RADDBG_RegisterCode_X64_fpr6;}break; +case REGS_RegCodeX64_fpr7:{result = RADDBG_RegisterCode_X64_fpr7;}break; +case REGS_RegCodeX64_st0:{result = RADDBG_RegisterCode_X64_st0;}break; +case REGS_RegCodeX64_st1:{result = RADDBG_RegisterCode_X64_st1;}break; +case REGS_RegCodeX64_st2:{result = RADDBG_RegisterCode_X64_st2;}break; +case REGS_RegCodeX64_st3:{result = RADDBG_RegisterCode_X64_st3;}break; +case REGS_RegCodeX64_st4:{result = RADDBG_RegisterCode_X64_st4;}break; +case REGS_RegCodeX64_st5:{result = RADDBG_RegisterCode_X64_st5;}break; +case REGS_RegCodeX64_st6:{result = RADDBG_RegisterCode_X64_st6;}break; +case REGS_RegCodeX64_st7:{result = RADDBG_RegisterCode_X64_st7;}break; +case REGS_RegCodeX64_fcw:{result = RADDBG_RegisterCode_X64_fcw;}break; +case REGS_RegCodeX64_fsw:{result = RADDBG_RegisterCode_X64_fsw;}break; +case REGS_RegCodeX64_ftw:{result = RADDBG_RegisterCode_X64_ftw;}break; +case REGS_RegCodeX64_fop:{result = RADDBG_RegisterCode_X64_fop;}break; +case REGS_RegCodeX64_fcs:{result = RADDBG_RegisterCode_X64_fcs;}break; +case REGS_RegCodeX64_fds:{result = RADDBG_RegisterCode_X64_fds;}break; +case REGS_RegCodeX64_fip:{result = RADDBG_RegisterCode_X64_fip;}break; +case REGS_RegCodeX64_fdp:{result = RADDBG_RegisterCode_X64_fdp;}break; +case REGS_RegCodeX64_mxcsr:{result = RADDBG_RegisterCode_X64_mxcsr;}break; +case REGS_RegCodeX64_mxcsr_mask:{result = RADDBG_RegisterCode_X64_mxcsr_mask;}break; +case REGS_RegCodeX64_ss:{result = RADDBG_RegisterCode_X64_ss;}break; +case REGS_RegCodeX64_cs:{result = RADDBG_RegisterCode_X64_cs;}break; +case REGS_RegCodeX64_ds:{result = RADDBG_RegisterCode_X64_ds;}break; +case REGS_RegCodeX64_es:{result = RADDBG_RegisterCode_X64_es;}break; +case REGS_RegCodeX64_fs:{result = RADDBG_RegisterCode_X64_fs;}break; +case REGS_RegCodeX64_gs:{result = RADDBG_RegisterCode_X64_gs;}break; +case REGS_RegCodeX64_ymm0:{result = RADDBG_RegisterCode_X64_ymm0;}break; +case REGS_RegCodeX64_ymm1:{result = RADDBG_RegisterCode_X64_ymm1;}break; +case REGS_RegCodeX64_ymm2:{result = RADDBG_RegisterCode_X64_ymm2;}break; +case REGS_RegCodeX64_ymm3:{result = RADDBG_RegisterCode_X64_ymm3;}break; +case REGS_RegCodeX64_ymm4:{result = RADDBG_RegisterCode_X64_ymm4;}break; +case REGS_RegCodeX64_ymm5:{result = RADDBG_RegisterCode_X64_ymm5;}break; +case REGS_RegCodeX64_ymm6:{result = RADDBG_RegisterCode_X64_ymm6;}break; +case REGS_RegCodeX64_ymm7:{result = RADDBG_RegisterCode_X64_ymm7;}break; +case REGS_RegCodeX64_ymm8:{result = RADDBG_RegisterCode_X64_ymm8;}break; +case REGS_RegCodeX64_ymm9:{result = RADDBG_RegisterCode_X64_ymm9;}break; +case REGS_RegCodeX64_ymm10:{result = RADDBG_RegisterCode_X64_ymm10;}break; +case REGS_RegCodeX64_ymm11:{result = RADDBG_RegisterCode_X64_ymm11;}break; +case REGS_RegCodeX64_ymm12:{result = RADDBG_RegisterCode_X64_ymm12;}break; +case REGS_RegCodeX64_ymm13:{result = RADDBG_RegisterCode_X64_ymm13;}break; +case REGS_RegCodeX64_ymm14:{result = RADDBG_RegisterCode_X64_ymm14;}break; +case REGS_RegCodeX64_ymm15:{result = RADDBG_RegisterCode_X64_ymm15;}break; +} +}break; +case Architecture_x86: +{ +switch(code) +{ +default:{}break; +case REGS_RegCodeX86_eax:{result = RADDBG_RegisterCode_X86_eax;}break; +case REGS_RegCodeX86_ecx:{result = RADDBG_RegisterCode_X86_ecx;}break; +case REGS_RegCodeX86_edx:{result = RADDBG_RegisterCode_X86_edx;}break; +case REGS_RegCodeX86_ebx:{result = RADDBG_RegisterCode_X86_ebx;}break; +case REGS_RegCodeX86_esp:{result = RADDBG_RegisterCode_X86_esp;}break; +case REGS_RegCodeX86_ebp:{result = RADDBG_RegisterCode_X86_ebp;}break; +case REGS_RegCodeX86_esi:{result = RADDBG_RegisterCode_X86_esi;}break; +case REGS_RegCodeX86_edi:{result = RADDBG_RegisterCode_X86_edi;}break; +case REGS_RegCodeX86_fsbase:{result = RADDBG_RegisterCode_X86_fsbase;}break; +case REGS_RegCodeX86_gsbase:{result = RADDBG_RegisterCode_X86_gsbase;}break; +case REGS_RegCodeX86_eflags:{result = RADDBG_RegisterCode_X86_eflags;}break; +case REGS_RegCodeX86_eip:{result = RADDBG_RegisterCode_X86_eip;}break; +case REGS_RegCodeX86_dr0:{result = RADDBG_RegisterCode_X86_dr0;}break; +case REGS_RegCodeX86_dr1:{result = RADDBG_RegisterCode_X86_dr1;}break; +case REGS_RegCodeX86_dr2:{result = RADDBG_RegisterCode_X86_dr2;}break; +case REGS_RegCodeX86_dr3:{result = RADDBG_RegisterCode_X86_dr3;}break; +case REGS_RegCodeX86_dr4:{result = RADDBG_RegisterCode_X86_dr4;}break; +case REGS_RegCodeX86_dr5:{result = RADDBG_RegisterCode_X86_dr5;}break; +case REGS_RegCodeX86_dr6:{result = RADDBG_RegisterCode_X86_dr6;}break; +case REGS_RegCodeX86_dr7:{result = RADDBG_RegisterCode_X86_dr7;}break; +case REGS_RegCodeX86_fpr0:{result = RADDBG_RegisterCode_X86_fpr0;}break; +case REGS_RegCodeX86_fpr1:{result = RADDBG_RegisterCode_X86_fpr1;}break; +case REGS_RegCodeX86_fpr2:{result = RADDBG_RegisterCode_X86_fpr2;}break; +case REGS_RegCodeX86_fpr3:{result = RADDBG_RegisterCode_X86_fpr3;}break; +case REGS_RegCodeX86_fpr4:{result = RADDBG_RegisterCode_X86_fpr4;}break; +case REGS_RegCodeX86_fpr5:{result = RADDBG_RegisterCode_X86_fpr5;}break; +case REGS_RegCodeX86_fpr6:{result = RADDBG_RegisterCode_X86_fpr6;}break; +case REGS_RegCodeX86_fpr7:{result = RADDBG_RegisterCode_X86_fpr7;}break; +case REGS_RegCodeX86_st0:{result = RADDBG_RegisterCode_X86_st0;}break; +case REGS_RegCodeX86_st1:{result = RADDBG_RegisterCode_X86_st1;}break; +case REGS_RegCodeX86_st2:{result = RADDBG_RegisterCode_X86_st2;}break; +case REGS_RegCodeX86_st3:{result = RADDBG_RegisterCode_X86_st3;}break; +case REGS_RegCodeX86_st4:{result = RADDBG_RegisterCode_X86_st4;}break; +case REGS_RegCodeX86_st5:{result = RADDBG_RegisterCode_X86_st5;}break; +case REGS_RegCodeX86_st6:{result = RADDBG_RegisterCode_X86_st6;}break; +case REGS_RegCodeX86_st7:{result = RADDBG_RegisterCode_X86_st7;}break; +case REGS_RegCodeX86_fcw:{result = RADDBG_RegisterCode_X86_fcw;}break; +case REGS_RegCodeX86_fsw:{result = RADDBG_RegisterCode_X86_fsw;}break; +case REGS_RegCodeX86_ftw:{result = RADDBG_RegisterCode_X86_ftw;}break; +case REGS_RegCodeX86_fop:{result = RADDBG_RegisterCode_X86_fop;}break; +case REGS_RegCodeX86_fcs:{result = RADDBG_RegisterCode_X86_fcs;}break; +case REGS_RegCodeX86_fds:{result = RADDBG_RegisterCode_X86_fds;}break; +case REGS_RegCodeX86_fip:{result = RADDBG_RegisterCode_X86_fip;}break; +case REGS_RegCodeX86_fdp:{result = RADDBG_RegisterCode_X86_fdp;}break; +case REGS_RegCodeX86_mxcsr:{result = RADDBG_RegisterCode_X86_mxcsr;}break; +case REGS_RegCodeX86_mxcsr_mask:{result = RADDBG_RegisterCode_X86_mxcsr_mask;}break; +case REGS_RegCodeX86_ss:{result = RADDBG_RegisterCode_X86_ss;}break; +case REGS_RegCodeX86_cs:{result = RADDBG_RegisterCode_X86_cs;}break; +case REGS_RegCodeX86_ds:{result = RADDBG_RegisterCode_X86_ds;}break; +case REGS_RegCodeX86_es:{result = RADDBG_RegisterCode_X86_es;}break; +case REGS_RegCodeX86_fs:{result = RADDBG_RegisterCode_X86_fs;}break; +case REGS_RegCodeX86_gs:{result = RADDBG_RegisterCode_X86_gs;}break; +case REGS_RegCodeX86_ymm0:{result = RADDBG_RegisterCode_X86_ymm0;}break; +case REGS_RegCodeX86_ymm1:{result = RADDBG_RegisterCode_X86_ymm1;}break; +case REGS_RegCodeX86_ymm2:{result = RADDBG_RegisterCode_X86_ymm2;}break; +case REGS_RegCodeX86_ymm3:{result = RADDBG_RegisterCode_X86_ymm3;}break; +case REGS_RegCodeX86_ymm4:{result = RADDBG_RegisterCode_X86_ymm4;}break; +case REGS_RegCodeX86_ymm5:{result = RADDBG_RegisterCode_X86_ymm5;}break; +case REGS_RegCodeX86_ymm6:{result = RADDBG_RegisterCode_X86_ymm6;}break; +case REGS_RegCodeX86_ymm7:{result = RADDBG_RegisterCode_X86_ymm7;}break; +} +}break; +} +return result; +} +internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode code) +{ +REGS_RegCode result = 0; +switch(arch) +{ +case Architecture_x64: +{ +switch(code) +{ +default:{}break; +case RADDBG_RegisterCode_X64_rax:{result = REGS_RegCodeX64_rax;}break; +case RADDBG_RegisterCode_X64_rcx:{result = REGS_RegCodeX64_rcx;}break; +case RADDBG_RegisterCode_X64_rdx:{result = REGS_RegCodeX64_rdx;}break; +case RADDBG_RegisterCode_X64_rbx:{result = REGS_RegCodeX64_rbx;}break; +case RADDBG_RegisterCode_X64_rsp:{result = REGS_RegCodeX64_rsp;}break; +case RADDBG_RegisterCode_X64_rbp:{result = REGS_RegCodeX64_rbp;}break; +case RADDBG_RegisterCode_X64_rsi:{result = REGS_RegCodeX64_rsi;}break; +case RADDBG_RegisterCode_X64_rdi:{result = REGS_RegCodeX64_rdi;}break; +case RADDBG_RegisterCode_X64_r8:{result = REGS_RegCodeX64_r8;}break; +case RADDBG_RegisterCode_X64_r9:{result = REGS_RegCodeX64_r9;}break; +case RADDBG_RegisterCode_X64_r10:{result = REGS_RegCodeX64_r10;}break; +case RADDBG_RegisterCode_X64_r11:{result = REGS_RegCodeX64_r11;}break; +case RADDBG_RegisterCode_X64_r12:{result = REGS_RegCodeX64_r12;}break; +case RADDBG_RegisterCode_X64_r13:{result = REGS_RegCodeX64_r13;}break; +case RADDBG_RegisterCode_X64_r14:{result = REGS_RegCodeX64_r14;}break; +case RADDBG_RegisterCode_X64_r15:{result = REGS_RegCodeX64_r15;}break; +case RADDBG_RegisterCode_X64_fsbase:{result = REGS_RegCodeX64_fsbase;}break; +case RADDBG_RegisterCode_X64_gsbase:{result = REGS_RegCodeX64_gsbase;}break; +case RADDBG_RegisterCode_X64_rip:{result = REGS_RegCodeX64_rip;}break; +case RADDBG_RegisterCode_X64_rflags:{result = REGS_RegCodeX64_rflags;}break; +case RADDBG_RegisterCode_X64_dr0:{result = REGS_RegCodeX64_dr0;}break; +case RADDBG_RegisterCode_X64_dr1:{result = REGS_RegCodeX64_dr1;}break; +case RADDBG_RegisterCode_X64_dr2:{result = REGS_RegCodeX64_dr2;}break; +case RADDBG_RegisterCode_X64_dr3:{result = REGS_RegCodeX64_dr3;}break; +case RADDBG_RegisterCode_X64_dr4:{result = REGS_RegCodeX64_dr4;}break; +case RADDBG_RegisterCode_X64_dr5:{result = REGS_RegCodeX64_dr5;}break; +case RADDBG_RegisterCode_X64_dr6:{result = REGS_RegCodeX64_dr6;}break; +case RADDBG_RegisterCode_X64_dr7:{result = REGS_RegCodeX64_dr7;}break; +case RADDBG_RegisterCode_X64_fpr0:{result = REGS_RegCodeX64_fpr0;}break; +case RADDBG_RegisterCode_X64_fpr1:{result = REGS_RegCodeX64_fpr1;}break; +case RADDBG_RegisterCode_X64_fpr2:{result = REGS_RegCodeX64_fpr2;}break; +case RADDBG_RegisterCode_X64_fpr3:{result = REGS_RegCodeX64_fpr3;}break; +case RADDBG_RegisterCode_X64_fpr4:{result = REGS_RegCodeX64_fpr4;}break; +case RADDBG_RegisterCode_X64_fpr5:{result = REGS_RegCodeX64_fpr5;}break; +case RADDBG_RegisterCode_X64_fpr6:{result = REGS_RegCodeX64_fpr6;}break; +case RADDBG_RegisterCode_X64_fpr7:{result = REGS_RegCodeX64_fpr7;}break; +case RADDBG_RegisterCode_X64_st0:{result = REGS_RegCodeX64_st0;}break; +case RADDBG_RegisterCode_X64_st1:{result = REGS_RegCodeX64_st1;}break; +case RADDBG_RegisterCode_X64_st2:{result = REGS_RegCodeX64_st2;}break; +case RADDBG_RegisterCode_X64_st3:{result = REGS_RegCodeX64_st3;}break; +case RADDBG_RegisterCode_X64_st4:{result = REGS_RegCodeX64_st4;}break; +case RADDBG_RegisterCode_X64_st5:{result = REGS_RegCodeX64_st5;}break; +case RADDBG_RegisterCode_X64_st6:{result = REGS_RegCodeX64_st6;}break; +case RADDBG_RegisterCode_X64_st7:{result = REGS_RegCodeX64_st7;}break; +case RADDBG_RegisterCode_X64_fcw:{result = REGS_RegCodeX64_fcw;}break; +case RADDBG_RegisterCode_X64_fsw:{result = REGS_RegCodeX64_fsw;}break; +case RADDBG_RegisterCode_X64_ftw:{result = REGS_RegCodeX64_ftw;}break; +case RADDBG_RegisterCode_X64_fop:{result = REGS_RegCodeX64_fop;}break; +case RADDBG_RegisterCode_X64_fcs:{result = REGS_RegCodeX64_fcs;}break; +case RADDBG_RegisterCode_X64_fds:{result = REGS_RegCodeX64_fds;}break; +case RADDBG_RegisterCode_X64_fip:{result = REGS_RegCodeX64_fip;}break; +case RADDBG_RegisterCode_X64_fdp:{result = REGS_RegCodeX64_fdp;}break; +case RADDBG_RegisterCode_X64_mxcsr:{result = REGS_RegCodeX64_mxcsr;}break; +case RADDBG_RegisterCode_X64_mxcsr_mask:{result = REGS_RegCodeX64_mxcsr_mask;}break; +case RADDBG_RegisterCode_X64_ss:{result = REGS_RegCodeX64_ss;}break; +case RADDBG_RegisterCode_X64_cs:{result = REGS_RegCodeX64_cs;}break; +case RADDBG_RegisterCode_X64_ds:{result = REGS_RegCodeX64_ds;}break; +case RADDBG_RegisterCode_X64_es:{result = REGS_RegCodeX64_es;}break; +case RADDBG_RegisterCode_X64_fs:{result = REGS_RegCodeX64_fs;}break; +case RADDBG_RegisterCode_X64_gs:{result = REGS_RegCodeX64_gs;}break; +case RADDBG_RegisterCode_X64_ymm0:{result = REGS_RegCodeX64_ymm0;}break; +case RADDBG_RegisterCode_X64_ymm1:{result = REGS_RegCodeX64_ymm1;}break; +case RADDBG_RegisterCode_X64_ymm2:{result = REGS_RegCodeX64_ymm2;}break; +case RADDBG_RegisterCode_X64_ymm3:{result = REGS_RegCodeX64_ymm3;}break; +case RADDBG_RegisterCode_X64_ymm4:{result = REGS_RegCodeX64_ymm4;}break; +case RADDBG_RegisterCode_X64_ymm5:{result = REGS_RegCodeX64_ymm5;}break; +case RADDBG_RegisterCode_X64_ymm6:{result = REGS_RegCodeX64_ymm6;}break; +case RADDBG_RegisterCode_X64_ymm7:{result = REGS_RegCodeX64_ymm7;}break; +case RADDBG_RegisterCode_X64_ymm8:{result = REGS_RegCodeX64_ymm8;}break; +case RADDBG_RegisterCode_X64_ymm9:{result = REGS_RegCodeX64_ymm9;}break; +case RADDBG_RegisterCode_X64_ymm10:{result = REGS_RegCodeX64_ymm10;}break; +case RADDBG_RegisterCode_X64_ymm11:{result = REGS_RegCodeX64_ymm11;}break; +case RADDBG_RegisterCode_X64_ymm12:{result = REGS_RegCodeX64_ymm12;}break; +case RADDBG_RegisterCode_X64_ymm13:{result = REGS_RegCodeX64_ymm13;}break; +case RADDBG_RegisterCode_X64_ymm14:{result = REGS_RegCodeX64_ymm14;}break; +case RADDBG_RegisterCode_X64_ymm15:{result = REGS_RegCodeX64_ymm15;}break; +} +}break; +case Architecture_x86: +{ +switch(code) +{ +default:{}break; +case RADDBG_RegisterCode_X86_eax:{result = REGS_RegCodeX86_eax;}break; +case RADDBG_RegisterCode_X86_ecx:{result = REGS_RegCodeX86_ecx;}break; +case RADDBG_RegisterCode_X86_edx:{result = REGS_RegCodeX86_edx;}break; +case RADDBG_RegisterCode_X86_ebx:{result = REGS_RegCodeX86_ebx;}break; +case RADDBG_RegisterCode_X86_esp:{result = REGS_RegCodeX86_esp;}break; +case RADDBG_RegisterCode_X86_ebp:{result = REGS_RegCodeX86_ebp;}break; +case RADDBG_RegisterCode_X86_esi:{result = REGS_RegCodeX86_esi;}break; +case RADDBG_RegisterCode_X86_edi:{result = REGS_RegCodeX86_edi;}break; +case RADDBG_RegisterCode_X86_fsbase:{result = REGS_RegCodeX86_fsbase;}break; +case RADDBG_RegisterCode_X86_gsbase:{result = REGS_RegCodeX86_gsbase;}break; +case RADDBG_RegisterCode_X86_eflags:{result = REGS_RegCodeX86_eflags;}break; +case RADDBG_RegisterCode_X86_eip:{result = REGS_RegCodeX86_eip;}break; +case RADDBG_RegisterCode_X86_dr0:{result = REGS_RegCodeX86_dr0;}break; +case RADDBG_RegisterCode_X86_dr1:{result = REGS_RegCodeX86_dr1;}break; +case RADDBG_RegisterCode_X86_dr2:{result = REGS_RegCodeX86_dr2;}break; +case RADDBG_RegisterCode_X86_dr3:{result = REGS_RegCodeX86_dr3;}break; +case RADDBG_RegisterCode_X86_dr4:{result = REGS_RegCodeX86_dr4;}break; +case RADDBG_RegisterCode_X86_dr5:{result = REGS_RegCodeX86_dr5;}break; +case RADDBG_RegisterCode_X86_dr6:{result = REGS_RegCodeX86_dr6;}break; +case RADDBG_RegisterCode_X86_dr7:{result = REGS_RegCodeX86_dr7;}break; +case RADDBG_RegisterCode_X86_fpr0:{result = REGS_RegCodeX86_fpr0;}break; +case RADDBG_RegisterCode_X86_fpr1:{result = REGS_RegCodeX86_fpr1;}break; +case RADDBG_RegisterCode_X86_fpr2:{result = REGS_RegCodeX86_fpr2;}break; +case RADDBG_RegisterCode_X86_fpr3:{result = REGS_RegCodeX86_fpr3;}break; +case RADDBG_RegisterCode_X86_fpr4:{result = REGS_RegCodeX86_fpr4;}break; +case RADDBG_RegisterCode_X86_fpr5:{result = REGS_RegCodeX86_fpr5;}break; +case RADDBG_RegisterCode_X86_fpr6:{result = REGS_RegCodeX86_fpr6;}break; +case RADDBG_RegisterCode_X86_fpr7:{result = REGS_RegCodeX86_fpr7;}break; +case RADDBG_RegisterCode_X86_st0:{result = REGS_RegCodeX86_st0;}break; +case RADDBG_RegisterCode_X86_st1:{result = REGS_RegCodeX86_st1;}break; +case RADDBG_RegisterCode_X86_st2:{result = REGS_RegCodeX86_st2;}break; +case RADDBG_RegisterCode_X86_st3:{result = REGS_RegCodeX86_st3;}break; +case RADDBG_RegisterCode_X86_st4:{result = REGS_RegCodeX86_st4;}break; +case RADDBG_RegisterCode_X86_st5:{result = REGS_RegCodeX86_st5;}break; +case RADDBG_RegisterCode_X86_st6:{result = REGS_RegCodeX86_st6;}break; +case RADDBG_RegisterCode_X86_st7:{result = REGS_RegCodeX86_st7;}break; +case RADDBG_RegisterCode_X86_fcw:{result = REGS_RegCodeX86_fcw;}break; +case RADDBG_RegisterCode_X86_fsw:{result = REGS_RegCodeX86_fsw;}break; +case RADDBG_RegisterCode_X86_ftw:{result = REGS_RegCodeX86_ftw;}break; +case RADDBG_RegisterCode_X86_fop:{result = REGS_RegCodeX86_fop;}break; +case RADDBG_RegisterCode_X86_fcs:{result = REGS_RegCodeX86_fcs;}break; +case RADDBG_RegisterCode_X86_fds:{result = REGS_RegCodeX86_fds;}break; +case RADDBG_RegisterCode_X86_fip:{result = REGS_RegCodeX86_fip;}break; +case RADDBG_RegisterCode_X86_fdp:{result = REGS_RegCodeX86_fdp;}break; +case RADDBG_RegisterCode_X86_mxcsr:{result = REGS_RegCodeX86_mxcsr;}break; +case RADDBG_RegisterCode_X86_mxcsr_mask:{result = REGS_RegCodeX86_mxcsr_mask;}break; +case RADDBG_RegisterCode_X86_ss:{result = REGS_RegCodeX86_ss;}break; +case RADDBG_RegisterCode_X86_cs:{result = REGS_RegCodeX86_cs;}break; +case RADDBG_RegisterCode_X86_ds:{result = REGS_RegCodeX86_ds;}break; +case RADDBG_RegisterCode_X86_es:{result = REGS_RegCodeX86_es;}break; +case RADDBG_RegisterCode_X86_fs:{result = REGS_RegCodeX86_fs;}break; +case RADDBG_RegisterCode_X86_gs:{result = REGS_RegCodeX86_gs;}break; +case RADDBG_RegisterCode_X86_ymm0:{result = REGS_RegCodeX86_ymm0;}break; +case RADDBG_RegisterCode_X86_ymm1:{result = REGS_RegCodeX86_ymm1;}break; +case RADDBG_RegisterCode_X86_ymm2:{result = REGS_RegCodeX86_ymm2;}break; +case RADDBG_RegisterCode_X86_ymm3:{result = REGS_RegCodeX86_ymm3;}break; +case RADDBG_RegisterCode_X86_ymm4:{result = REGS_RegCodeX86_ymm4;}break; +case RADDBG_RegisterCode_X86_ymm5:{result = REGS_RegCodeX86_ymm5;}break; +case RADDBG_RegisterCode_X86_ymm6:{result = REGS_RegCodeX86_ymm6;}break; +case RADDBG_RegisterCode_X86_ymm7:{result = REGS_RegCodeX86_ymm7;}break; +} +}break; +} +return result; +} + +#endif diff --git a/src/regs/raddbg/generated/regs_raddbg.meta.c b/src/regs/raddbg/generated/regs_raddbg.meta.c new file mode 100644 index 00000000..c52e08b2 --- /dev/null +++ b/src/regs/raddbg/generated/regs_raddbg.meta.c @@ -0,0 +1,323 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code) +{ +RADDBG_RegisterCode result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64: +{ +switch(code) +{ +default:{}break; +case REGS_RegCodeX64_rax:{result = RADDBG_RegisterCode_X64_rax;}break; +case REGS_RegCodeX64_rcx:{result = RADDBG_RegisterCode_X64_rcx;}break; +case REGS_RegCodeX64_rdx:{result = RADDBG_RegisterCode_X64_rdx;}break; +case REGS_RegCodeX64_rbx:{result = RADDBG_RegisterCode_X64_rbx;}break; +case REGS_RegCodeX64_rsp:{result = RADDBG_RegisterCode_X64_rsp;}break; +case REGS_RegCodeX64_rbp:{result = RADDBG_RegisterCode_X64_rbp;}break; +case REGS_RegCodeX64_rsi:{result = RADDBG_RegisterCode_X64_rsi;}break; +case REGS_RegCodeX64_rdi:{result = RADDBG_RegisterCode_X64_rdi;}break; +case REGS_RegCodeX64_r8:{result = RADDBG_RegisterCode_X64_r8;}break; +case REGS_RegCodeX64_r9:{result = RADDBG_RegisterCode_X64_r9;}break; +case REGS_RegCodeX64_r10:{result = RADDBG_RegisterCode_X64_r10;}break; +case REGS_RegCodeX64_r11:{result = RADDBG_RegisterCode_X64_r11;}break; +case REGS_RegCodeX64_r12:{result = RADDBG_RegisterCode_X64_r12;}break; +case REGS_RegCodeX64_r13:{result = RADDBG_RegisterCode_X64_r13;}break; +case REGS_RegCodeX64_r14:{result = RADDBG_RegisterCode_X64_r14;}break; +case REGS_RegCodeX64_r15:{result = RADDBG_RegisterCode_X64_r15;}break; +case REGS_RegCodeX64_fsbase:{result = RADDBG_RegisterCode_X64_fsbase;}break; +case REGS_RegCodeX64_gsbase:{result = RADDBG_RegisterCode_X64_gsbase;}break; +case REGS_RegCodeX64_rip:{result = RADDBG_RegisterCode_X64_rip;}break; +case REGS_RegCodeX64_rflags:{result = RADDBG_RegisterCode_X64_rflags;}break; +case REGS_RegCodeX64_dr0:{result = RADDBG_RegisterCode_X64_dr0;}break; +case REGS_RegCodeX64_dr1:{result = RADDBG_RegisterCode_X64_dr1;}break; +case REGS_RegCodeX64_dr2:{result = RADDBG_RegisterCode_X64_dr2;}break; +case REGS_RegCodeX64_dr3:{result = RADDBG_RegisterCode_X64_dr3;}break; +case REGS_RegCodeX64_dr4:{result = RADDBG_RegisterCode_X64_dr4;}break; +case REGS_RegCodeX64_dr5:{result = RADDBG_RegisterCode_X64_dr5;}break; +case REGS_RegCodeX64_dr6:{result = RADDBG_RegisterCode_X64_dr6;}break; +case REGS_RegCodeX64_dr7:{result = RADDBG_RegisterCode_X64_dr7;}break; +case REGS_RegCodeX64_fpr0:{result = RADDBG_RegisterCode_X64_fpr0;}break; +case REGS_RegCodeX64_fpr1:{result = RADDBG_RegisterCode_X64_fpr1;}break; +case REGS_RegCodeX64_fpr2:{result = RADDBG_RegisterCode_X64_fpr2;}break; +case REGS_RegCodeX64_fpr3:{result = RADDBG_RegisterCode_X64_fpr3;}break; +case REGS_RegCodeX64_fpr4:{result = RADDBG_RegisterCode_X64_fpr4;}break; +case REGS_RegCodeX64_fpr5:{result = RADDBG_RegisterCode_X64_fpr5;}break; +case REGS_RegCodeX64_fpr6:{result = RADDBG_RegisterCode_X64_fpr6;}break; +case REGS_RegCodeX64_fpr7:{result = RADDBG_RegisterCode_X64_fpr7;}break; +case REGS_RegCodeX64_st0:{result = RADDBG_RegisterCode_X64_st0;}break; +case REGS_RegCodeX64_st1:{result = RADDBG_RegisterCode_X64_st1;}break; +case REGS_RegCodeX64_st2:{result = RADDBG_RegisterCode_X64_st2;}break; +case REGS_RegCodeX64_st3:{result = RADDBG_RegisterCode_X64_st3;}break; +case REGS_RegCodeX64_st4:{result = RADDBG_RegisterCode_X64_st4;}break; +case REGS_RegCodeX64_st5:{result = RADDBG_RegisterCode_X64_st5;}break; +case REGS_RegCodeX64_st6:{result = RADDBG_RegisterCode_X64_st6;}break; +case REGS_RegCodeX64_st7:{result = RADDBG_RegisterCode_X64_st7;}break; +case REGS_RegCodeX64_fcw:{result = RADDBG_RegisterCode_X64_fcw;}break; +case REGS_RegCodeX64_fsw:{result = RADDBG_RegisterCode_X64_fsw;}break; +case REGS_RegCodeX64_ftw:{result = RADDBG_RegisterCode_X64_ftw;}break; +case REGS_RegCodeX64_fop:{result = RADDBG_RegisterCode_X64_fop;}break; +case REGS_RegCodeX64_fcs:{result = RADDBG_RegisterCode_X64_fcs;}break; +case REGS_RegCodeX64_fds:{result = RADDBG_RegisterCode_X64_fds;}break; +case REGS_RegCodeX64_fip:{result = RADDBG_RegisterCode_X64_fip;}break; +case REGS_RegCodeX64_fdp:{result = RADDBG_RegisterCode_X64_fdp;}break; +case REGS_RegCodeX64_mxcsr:{result = RADDBG_RegisterCode_X64_mxcsr;}break; +case REGS_RegCodeX64_mxcsr_mask:{result = RADDBG_RegisterCode_X64_mxcsr_mask;}break; +case REGS_RegCodeX64_ss:{result = RADDBG_RegisterCode_X64_ss;}break; +case REGS_RegCodeX64_cs:{result = RADDBG_RegisterCode_X64_cs;}break; +case REGS_RegCodeX64_ds:{result = RADDBG_RegisterCode_X64_ds;}break; +case REGS_RegCodeX64_es:{result = RADDBG_RegisterCode_X64_es;}break; +case REGS_RegCodeX64_fs:{result = RADDBG_RegisterCode_X64_fs;}break; +case REGS_RegCodeX64_gs:{result = RADDBG_RegisterCode_X64_gs;}break; +case REGS_RegCodeX64_ymm0:{result = RADDBG_RegisterCode_X64_ymm0;}break; +case REGS_RegCodeX64_ymm1:{result = RADDBG_RegisterCode_X64_ymm1;}break; +case REGS_RegCodeX64_ymm2:{result = RADDBG_RegisterCode_X64_ymm2;}break; +case REGS_RegCodeX64_ymm3:{result = RADDBG_RegisterCode_X64_ymm3;}break; +case REGS_RegCodeX64_ymm4:{result = RADDBG_RegisterCode_X64_ymm4;}break; +case REGS_RegCodeX64_ymm5:{result = RADDBG_RegisterCode_X64_ymm5;}break; +case REGS_RegCodeX64_ymm6:{result = RADDBG_RegisterCode_X64_ymm6;}break; +case REGS_RegCodeX64_ymm7:{result = RADDBG_RegisterCode_X64_ymm7;}break; +case REGS_RegCodeX64_ymm8:{result = RADDBG_RegisterCode_X64_ymm8;}break; +case REGS_RegCodeX64_ymm9:{result = RADDBG_RegisterCode_X64_ymm9;}break; +case REGS_RegCodeX64_ymm10:{result = RADDBG_RegisterCode_X64_ymm10;}break; +case REGS_RegCodeX64_ymm11:{result = RADDBG_RegisterCode_X64_ymm11;}break; +case REGS_RegCodeX64_ymm12:{result = RADDBG_RegisterCode_X64_ymm12;}break; +case REGS_RegCodeX64_ymm13:{result = RADDBG_RegisterCode_X64_ymm13;}break; +case REGS_RegCodeX64_ymm14:{result = RADDBG_RegisterCode_X64_ymm14;}break; +case REGS_RegCodeX64_ymm15:{result = RADDBG_RegisterCode_X64_ymm15;}break; +} +}break; +case Architecture_x86: +{ +switch(code) +{ +default:{}break; +case REGS_RegCodeX86_eax:{result = RADDBG_RegisterCode_X86_eax;}break; +case REGS_RegCodeX86_ecx:{result = RADDBG_RegisterCode_X86_ecx;}break; +case REGS_RegCodeX86_edx:{result = RADDBG_RegisterCode_X86_edx;}break; +case REGS_RegCodeX86_ebx:{result = RADDBG_RegisterCode_X86_ebx;}break; +case REGS_RegCodeX86_esp:{result = RADDBG_RegisterCode_X86_esp;}break; +case REGS_RegCodeX86_ebp:{result = RADDBG_RegisterCode_X86_ebp;}break; +case REGS_RegCodeX86_esi:{result = RADDBG_RegisterCode_X86_esi;}break; +case REGS_RegCodeX86_edi:{result = RADDBG_RegisterCode_X86_edi;}break; +case REGS_RegCodeX86_fsbase:{result = RADDBG_RegisterCode_X86_fsbase;}break; +case REGS_RegCodeX86_gsbase:{result = RADDBG_RegisterCode_X86_gsbase;}break; +case REGS_RegCodeX86_eflags:{result = RADDBG_RegisterCode_X86_eflags;}break; +case REGS_RegCodeX86_eip:{result = RADDBG_RegisterCode_X86_eip;}break; +case REGS_RegCodeX86_dr0:{result = RADDBG_RegisterCode_X86_dr0;}break; +case REGS_RegCodeX86_dr1:{result = RADDBG_RegisterCode_X86_dr1;}break; +case REGS_RegCodeX86_dr2:{result = RADDBG_RegisterCode_X86_dr2;}break; +case REGS_RegCodeX86_dr3:{result = RADDBG_RegisterCode_X86_dr3;}break; +case REGS_RegCodeX86_dr4:{result = RADDBG_RegisterCode_X86_dr4;}break; +case REGS_RegCodeX86_dr5:{result = RADDBG_RegisterCode_X86_dr5;}break; +case REGS_RegCodeX86_dr6:{result = RADDBG_RegisterCode_X86_dr6;}break; +case REGS_RegCodeX86_dr7:{result = RADDBG_RegisterCode_X86_dr7;}break; +case REGS_RegCodeX86_fpr0:{result = RADDBG_RegisterCode_X86_fpr0;}break; +case REGS_RegCodeX86_fpr1:{result = RADDBG_RegisterCode_X86_fpr1;}break; +case REGS_RegCodeX86_fpr2:{result = RADDBG_RegisterCode_X86_fpr2;}break; +case REGS_RegCodeX86_fpr3:{result = RADDBG_RegisterCode_X86_fpr3;}break; +case REGS_RegCodeX86_fpr4:{result = RADDBG_RegisterCode_X86_fpr4;}break; +case REGS_RegCodeX86_fpr5:{result = RADDBG_RegisterCode_X86_fpr5;}break; +case REGS_RegCodeX86_fpr6:{result = RADDBG_RegisterCode_X86_fpr6;}break; +case REGS_RegCodeX86_fpr7:{result = RADDBG_RegisterCode_X86_fpr7;}break; +case REGS_RegCodeX86_st0:{result = RADDBG_RegisterCode_X86_st0;}break; +case REGS_RegCodeX86_st1:{result = RADDBG_RegisterCode_X86_st1;}break; +case REGS_RegCodeX86_st2:{result = RADDBG_RegisterCode_X86_st2;}break; +case REGS_RegCodeX86_st3:{result = RADDBG_RegisterCode_X86_st3;}break; +case REGS_RegCodeX86_st4:{result = RADDBG_RegisterCode_X86_st4;}break; +case REGS_RegCodeX86_st5:{result = RADDBG_RegisterCode_X86_st5;}break; +case REGS_RegCodeX86_st6:{result = RADDBG_RegisterCode_X86_st6;}break; +case REGS_RegCodeX86_st7:{result = RADDBG_RegisterCode_X86_st7;}break; +case REGS_RegCodeX86_fcw:{result = RADDBG_RegisterCode_X86_fcw;}break; +case REGS_RegCodeX86_fsw:{result = RADDBG_RegisterCode_X86_fsw;}break; +case REGS_RegCodeX86_ftw:{result = RADDBG_RegisterCode_X86_ftw;}break; +case REGS_RegCodeX86_fop:{result = RADDBG_RegisterCode_X86_fop;}break; +case REGS_RegCodeX86_fcs:{result = RADDBG_RegisterCode_X86_fcs;}break; +case REGS_RegCodeX86_fds:{result = RADDBG_RegisterCode_X86_fds;}break; +case REGS_RegCodeX86_fip:{result = RADDBG_RegisterCode_X86_fip;}break; +case REGS_RegCodeX86_fdp:{result = RADDBG_RegisterCode_X86_fdp;}break; +case REGS_RegCodeX86_mxcsr:{result = RADDBG_RegisterCode_X86_mxcsr;}break; +case REGS_RegCodeX86_mxcsr_mask:{result = RADDBG_RegisterCode_X86_mxcsr_mask;}break; +case REGS_RegCodeX86_ss:{result = RADDBG_RegisterCode_X86_ss;}break; +case REGS_RegCodeX86_cs:{result = RADDBG_RegisterCode_X86_cs;}break; +case REGS_RegCodeX86_ds:{result = RADDBG_RegisterCode_X86_ds;}break; +case REGS_RegCodeX86_es:{result = RADDBG_RegisterCode_X86_es;}break; +case REGS_RegCodeX86_fs:{result = RADDBG_RegisterCode_X86_fs;}break; +case REGS_RegCodeX86_gs:{result = RADDBG_RegisterCode_X86_gs;}break; +case REGS_RegCodeX86_ymm0:{result = RADDBG_RegisterCode_X86_ymm0;}break; +case REGS_RegCodeX86_ymm1:{result = RADDBG_RegisterCode_X86_ymm1;}break; +case REGS_RegCodeX86_ymm2:{result = RADDBG_RegisterCode_X86_ymm2;}break; +case REGS_RegCodeX86_ymm3:{result = RADDBG_RegisterCode_X86_ymm3;}break; +case REGS_RegCodeX86_ymm4:{result = RADDBG_RegisterCode_X86_ymm4;}break; +case REGS_RegCodeX86_ymm5:{result = RADDBG_RegisterCode_X86_ymm5;}break; +case REGS_RegCodeX86_ymm6:{result = RADDBG_RegisterCode_X86_ymm6;}break; +case REGS_RegCodeX86_ymm7:{result = RADDBG_RegisterCode_X86_ymm7;}break; +} +}break; +} +return result; +} +internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode code) +{ +REGS_RegCode result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64: +{ +switch(code) +{ +default:{}break; +case RADDBG_RegisterCode_X64_rax:{result = REGS_RegCodeX64_rax;}break; +case RADDBG_RegisterCode_X64_rcx:{result = REGS_RegCodeX64_rcx;}break; +case RADDBG_RegisterCode_X64_rdx:{result = REGS_RegCodeX64_rdx;}break; +case RADDBG_RegisterCode_X64_rbx:{result = REGS_RegCodeX64_rbx;}break; +case RADDBG_RegisterCode_X64_rsp:{result = REGS_RegCodeX64_rsp;}break; +case RADDBG_RegisterCode_X64_rbp:{result = REGS_RegCodeX64_rbp;}break; +case RADDBG_RegisterCode_X64_rsi:{result = REGS_RegCodeX64_rsi;}break; +case RADDBG_RegisterCode_X64_rdi:{result = REGS_RegCodeX64_rdi;}break; +case RADDBG_RegisterCode_X64_r8:{result = REGS_RegCodeX64_r8;}break; +case RADDBG_RegisterCode_X64_r9:{result = REGS_RegCodeX64_r9;}break; +case RADDBG_RegisterCode_X64_r10:{result = REGS_RegCodeX64_r10;}break; +case RADDBG_RegisterCode_X64_r11:{result = REGS_RegCodeX64_r11;}break; +case RADDBG_RegisterCode_X64_r12:{result = REGS_RegCodeX64_r12;}break; +case RADDBG_RegisterCode_X64_r13:{result = REGS_RegCodeX64_r13;}break; +case RADDBG_RegisterCode_X64_r14:{result = REGS_RegCodeX64_r14;}break; +case RADDBG_RegisterCode_X64_r15:{result = REGS_RegCodeX64_r15;}break; +case RADDBG_RegisterCode_X64_fsbase:{result = REGS_RegCodeX64_fsbase;}break; +case RADDBG_RegisterCode_X64_gsbase:{result = REGS_RegCodeX64_gsbase;}break; +case RADDBG_RegisterCode_X64_rip:{result = REGS_RegCodeX64_rip;}break; +case RADDBG_RegisterCode_X64_rflags:{result = REGS_RegCodeX64_rflags;}break; +case RADDBG_RegisterCode_X64_dr0:{result = REGS_RegCodeX64_dr0;}break; +case RADDBG_RegisterCode_X64_dr1:{result = REGS_RegCodeX64_dr1;}break; +case RADDBG_RegisterCode_X64_dr2:{result = REGS_RegCodeX64_dr2;}break; +case RADDBG_RegisterCode_X64_dr3:{result = REGS_RegCodeX64_dr3;}break; +case RADDBG_RegisterCode_X64_dr4:{result = REGS_RegCodeX64_dr4;}break; +case RADDBG_RegisterCode_X64_dr5:{result = REGS_RegCodeX64_dr5;}break; +case RADDBG_RegisterCode_X64_dr6:{result = REGS_RegCodeX64_dr6;}break; +case RADDBG_RegisterCode_X64_dr7:{result = REGS_RegCodeX64_dr7;}break; +case RADDBG_RegisterCode_X64_fpr0:{result = REGS_RegCodeX64_fpr0;}break; +case RADDBG_RegisterCode_X64_fpr1:{result = REGS_RegCodeX64_fpr1;}break; +case RADDBG_RegisterCode_X64_fpr2:{result = REGS_RegCodeX64_fpr2;}break; +case RADDBG_RegisterCode_X64_fpr3:{result = REGS_RegCodeX64_fpr3;}break; +case RADDBG_RegisterCode_X64_fpr4:{result = REGS_RegCodeX64_fpr4;}break; +case RADDBG_RegisterCode_X64_fpr5:{result = REGS_RegCodeX64_fpr5;}break; +case RADDBG_RegisterCode_X64_fpr6:{result = REGS_RegCodeX64_fpr6;}break; +case RADDBG_RegisterCode_X64_fpr7:{result = REGS_RegCodeX64_fpr7;}break; +case RADDBG_RegisterCode_X64_st0:{result = REGS_RegCodeX64_st0;}break; +case RADDBG_RegisterCode_X64_st1:{result = REGS_RegCodeX64_st1;}break; +case RADDBG_RegisterCode_X64_st2:{result = REGS_RegCodeX64_st2;}break; +case RADDBG_RegisterCode_X64_st3:{result = REGS_RegCodeX64_st3;}break; +case RADDBG_RegisterCode_X64_st4:{result = REGS_RegCodeX64_st4;}break; +case RADDBG_RegisterCode_X64_st5:{result = REGS_RegCodeX64_st5;}break; +case RADDBG_RegisterCode_X64_st6:{result = REGS_RegCodeX64_st6;}break; +case RADDBG_RegisterCode_X64_st7:{result = REGS_RegCodeX64_st7;}break; +case RADDBG_RegisterCode_X64_fcw:{result = REGS_RegCodeX64_fcw;}break; +case RADDBG_RegisterCode_X64_fsw:{result = REGS_RegCodeX64_fsw;}break; +case RADDBG_RegisterCode_X64_ftw:{result = REGS_RegCodeX64_ftw;}break; +case RADDBG_RegisterCode_X64_fop:{result = REGS_RegCodeX64_fop;}break; +case RADDBG_RegisterCode_X64_fcs:{result = REGS_RegCodeX64_fcs;}break; +case RADDBG_RegisterCode_X64_fds:{result = REGS_RegCodeX64_fds;}break; +case RADDBG_RegisterCode_X64_fip:{result = REGS_RegCodeX64_fip;}break; +case RADDBG_RegisterCode_X64_fdp:{result = REGS_RegCodeX64_fdp;}break; +case RADDBG_RegisterCode_X64_mxcsr:{result = REGS_RegCodeX64_mxcsr;}break; +case RADDBG_RegisterCode_X64_mxcsr_mask:{result = REGS_RegCodeX64_mxcsr_mask;}break; +case RADDBG_RegisterCode_X64_ss:{result = REGS_RegCodeX64_ss;}break; +case RADDBG_RegisterCode_X64_cs:{result = REGS_RegCodeX64_cs;}break; +case RADDBG_RegisterCode_X64_ds:{result = REGS_RegCodeX64_ds;}break; +case RADDBG_RegisterCode_X64_es:{result = REGS_RegCodeX64_es;}break; +case RADDBG_RegisterCode_X64_fs:{result = REGS_RegCodeX64_fs;}break; +case RADDBG_RegisterCode_X64_gs:{result = REGS_RegCodeX64_gs;}break; +case RADDBG_RegisterCode_X64_ymm0:{result = REGS_RegCodeX64_ymm0;}break; +case RADDBG_RegisterCode_X64_ymm1:{result = REGS_RegCodeX64_ymm1;}break; +case RADDBG_RegisterCode_X64_ymm2:{result = REGS_RegCodeX64_ymm2;}break; +case RADDBG_RegisterCode_X64_ymm3:{result = REGS_RegCodeX64_ymm3;}break; +case RADDBG_RegisterCode_X64_ymm4:{result = REGS_RegCodeX64_ymm4;}break; +case RADDBG_RegisterCode_X64_ymm5:{result = REGS_RegCodeX64_ymm5;}break; +case RADDBG_RegisterCode_X64_ymm6:{result = REGS_RegCodeX64_ymm6;}break; +case RADDBG_RegisterCode_X64_ymm7:{result = REGS_RegCodeX64_ymm7;}break; +case RADDBG_RegisterCode_X64_ymm8:{result = REGS_RegCodeX64_ymm8;}break; +case RADDBG_RegisterCode_X64_ymm9:{result = REGS_RegCodeX64_ymm9;}break; +case RADDBG_RegisterCode_X64_ymm10:{result = REGS_RegCodeX64_ymm10;}break; +case RADDBG_RegisterCode_X64_ymm11:{result = REGS_RegCodeX64_ymm11;}break; +case RADDBG_RegisterCode_X64_ymm12:{result = REGS_RegCodeX64_ymm12;}break; +case RADDBG_RegisterCode_X64_ymm13:{result = REGS_RegCodeX64_ymm13;}break; +case RADDBG_RegisterCode_X64_ymm14:{result = REGS_RegCodeX64_ymm14;}break; +case RADDBG_RegisterCode_X64_ymm15:{result = REGS_RegCodeX64_ymm15;}break; +} +}break; +case Architecture_x86: +{ +switch(code) +{ +default:{}break; +case RADDBG_RegisterCode_X86_eax:{result = REGS_RegCodeX86_eax;}break; +case RADDBG_RegisterCode_X86_ecx:{result = REGS_RegCodeX86_ecx;}break; +case RADDBG_RegisterCode_X86_edx:{result = REGS_RegCodeX86_edx;}break; +case RADDBG_RegisterCode_X86_ebx:{result = REGS_RegCodeX86_ebx;}break; +case RADDBG_RegisterCode_X86_esp:{result = REGS_RegCodeX86_esp;}break; +case RADDBG_RegisterCode_X86_ebp:{result = REGS_RegCodeX86_ebp;}break; +case RADDBG_RegisterCode_X86_esi:{result = REGS_RegCodeX86_esi;}break; +case RADDBG_RegisterCode_X86_edi:{result = REGS_RegCodeX86_edi;}break; +case RADDBG_RegisterCode_X86_fsbase:{result = REGS_RegCodeX86_fsbase;}break; +case RADDBG_RegisterCode_X86_gsbase:{result = REGS_RegCodeX86_gsbase;}break; +case RADDBG_RegisterCode_X86_eflags:{result = REGS_RegCodeX86_eflags;}break; +case RADDBG_RegisterCode_X86_eip:{result = REGS_RegCodeX86_eip;}break; +case RADDBG_RegisterCode_X86_dr0:{result = REGS_RegCodeX86_dr0;}break; +case RADDBG_RegisterCode_X86_dr1:{result = REGS_RegCodeX86_dr1;}break; +case RADDBG_RegisterCode_X86_dr2:{result = REGS_RegCodeX86_dr2;}break; +case RADDBG_RegisterCode_X86_dr3:{result = REGS_RegCodeX86_dr3;}break; +case RADDBG_RegisterCode_X86_dr4:{result = REGS_RegCodeX86_dr4;}break; +case RADDBG_RegisterCode_X86_dr5:{result = REGS_RegCodeX86_dr5;}break; +case RADDBG_RegisterCode_X86_dr6:{result = REGS_RegCodeX86_dr6;}break; +case RADDBG_RegisterCode_X86_dr7:{result = REGS_RegCodeX86_dr7;}break; +case RADDBG_RegisterCode_X86_fpr0:{result = REGS_RegCodeX86_fpr0;}break; +case RADDBG_RegisterCode_X86_fpr1:{result = REGS_RegCodeX86_fpr1;}break; +case RADDBG_RegisterCode_X86_fpr2:{result = REGS_RegCodeX86_fpr2;}break; +case RADDBG_RegisterCode_X86_fpr3:{result = REGS_RegCodeX86_fpr3;}break; +case RADDBG_RegisterCode_X86_fpr4:{result = REGS_RegCodeX86_fpr4;}break; +case RADDBG_RegisterCode_X86_fpr5:{result = REGS_RegCodeX86_fpr5;}break; +case RADDBG_RegisterCode_X86_fpr6:{result = REGS_RegCodeX86_fpr6;}break; +case RADDBG_RegisterCode_X86_fpr7:{result = REGS_RegCodeX86_fpr7;}break; +case RADDBG_RegisterCode_X86_st0:{result = REGS_RegCodeX86_st0;}break; +case RADDBG_RegisterCode_X86_st1:{result = REGS_RegCodeX86_st1;}break; +case RADDBG_RegisterCode_X86_st2:{result = REGS_RegCodeX86_st2;}break; +case RADDBG_RegisterCode_X86_st3:{result = REGS_RegCodeX86_st3;}break; +case RADDBG_RegisterCode_X86_st4:{result = REGS_RegCodeX86_st4;}break; +case RADDBG_RegisterCode_X86_st5:{result = REGS_RegCodeX86_st5;}break; +case RADDBG_RegisterCode_X86_st6:{result = REGS_RegCodeX86_st6;}break; +case RADDBG_RegisterCode_X86_st7:{result = REGS_RegCodeX86_st7;}break; +case RADDBG_RegisterCode_X86_fcw:{result = REGS_RegCodeX86_fcw;}break; +case RADDBG_RegisterCode_X86_fsw:{result = REGS_RegCodeX86_fsw;}break; +case RADDBG_RegisterCode_X86_ftw:{result = REGS_RegCodeX86_ftw;}break; +case RADDBG_RegisterCode_X86_fop:{result = REGS_RegCodeX86_fop;}break; +case RADDBG_RegisterCode_X86_fcs:{result = REGS_RegCodeX86_fcs;}break; +case RADDBG_RegisterCode_X86_fds:{result = REGS_RegCodeX86_fds;}break; +case RADDBG_RegisterCode_X86_fip:{result = REGS_RegCodeX86_fip;}break; +case RADDBG_RegisterCode_X86_fdp:{result = REGS_RegCodeX86_fdp;}break; +case RADDBG_RegisterCode_X86_mxcsr:{result = REGS_RegCodeX86_mxcsr;}break; +case RADDBG_RegisterCode_X86_mxcsr_mask:{result = REGS_RegCodeX86_mxcsr_mask;}break; +case RADDBG_RegisterCode_X86_ss:{result = REGS_RegCodeX86_ss;}break; +case RADDBG_RegisterCode_X86_cs:{result = REGS_RegCodeX86_cs;}break; +case RADDBG_RegisterCode_X86_ds:{result = REGS_RegCodeX86_ds;}break; +case RADDBG_RegisterCode_X86_es:{result = REGS_RegCodeX86_es;}break; +case RADDBG_RegisterCode_X86_fs:{result = REGS_RegCodeX86_fs;}break; +case RADDBG_RegisterCode_X86_gs:{result = REGS_RegCodeX86_gs;}break; +case RADDBG_RegisterCode_X86_ymm0:{result = REGS_RegCodeX86_ymm0;}break; +case RADDBG_RegisterCode_X86_ymm1:{result = REGS_RegCodeX86_ymm1;}break; +case RADDBG_RegisterCode_X86_ymm2:{result = REGS_RegCodeX86_ymm2;}break; +case RADDBG_RegisterCode_X86_ymm3:{result = REGS_RegCodeX86_ymm3;}break; +case RADDBG_RegisterCode_X86_ymm4:{result = REGS_RegCodeX86_ymm4;}break; +case RADDBG_RegisterCode_X86_ymm5:{result = REGS_RegCodeX86_ymm5;}break; +case RADDBG_RegisterCode_X86_ymm6:{result = REGS_RegCodeX86_ymm6;}break; +case RADDBG_RegisterCode_X86_ymm7:{result = REGS_RegCodeX86_ymm7;}break; +} +}break; +} +return result; +} diff --git a/src/regs/raddbg/generated/regs_raddbg.meta.h b/src/regs/raddbg/generated/regs_raddbg.meta.h new file mode 100644 index 00000000..6e1c7f59 --- /dev/null +++ b/src/regs/raddbg/generated/regs_raddbg.meta.h @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef REGS_RADDBG_META_H +#define REGS_RADDBG_META_H + + +#endif // REGS_RADDBG_META_H diff --git a/src/regs/raddbg/regs_raddbg.c b/src/regs/raddbg/regs_raddbg.c new file mode 100644 index 00000000..399ec8d3 --- /dev/null +++ b/src/regs/raddbg/regs_raddbg.c @@ -0,0 +1,4 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "regs/raddbg/generated/regs_raddbg.meta.c" diff --git a/src/regs/raddbg/regs_raddbg.h b/src/regs/raddbg/regs_raddbg.h new file mode 100644 index 00000000..77f9a25d --- /dev/null +++ b/src/regs/raddbg/regs_raddbg.h @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef REGS_RADDBG_H +#define REGS_RADDBG_H + +internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code); +internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode reg); + +#endif //REGS_RADDBG_H diff --git a/src/regs/raddbg/regs_raddbg.mc b/src/regs/raddbg/regs_raddbg.mc new file mode 100644 index 00000000..ce76ed45 --- /dev/null +++ b/src/regs/raddbg/regs_raddbg.mc @@ -0,0 +1,63 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: RADDBG Converter Helper Implementation Generators + +@table_gen @c_file +{ + `internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code)`; + `{`; + `RADDBG_RegisterCode result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + `case Architecture_x64:`; + `{`; + `switch(code)` + `{`; + `default:{}break;`; + @expand(REGS_RegTableX64 a) `case REGS_RegCodeX64_$(a.name):{result = RADDBG_RegisterCode_X64_$(a.name);}break;`; + `}`; + `}break;`; + `case Architecture_x86:`; + `{`; + `switch(code)` + `{`; + `default:{}break;`; + @expand(REGS_RegTableX86 a) `case REGS_RegCodeX86_$(a.name):{result = RADDBG_RegisterCode_X86_$(a.name);}break;`; + `}`; + `}break;`; + `}`; + `return result;`; + `}`; +} + +@table_gen @c_file +{ + `internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode code)`; + `{`; + `REGS_RegCode result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + `case Architecture_x64:`; + `{`; + `switch(code)` + `{`; + `default:{}break;`; + @expand(REGS_RegTableX64 a) `case RADDBG_RegisterCode_X64_$(a.name):{result = REGS_RegCodeX64_$(a.name);}break;`; + `}`; + `}break;`; + `case Architecture_x86:`; + `{`; + `switch(code)` + `{`; + `default:{}break;`; + @expand(REGS_RegTableX86 a) `case RADDBG_RegisterCode_X86_$(a.name):{result = REGS_RegCodeX86_$(a.name);}break;`; + `}`; + `}break;`; + `}`; + `return result;`; + `}`; +} diff --git a/src/regs/regs.c b/src/regs/regs.c new file mode 100644 index 00000000..028cd559 --- /dev/null +++ b/src/regs/regs.c @@ -0,0 +1,58 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Generated Code + +#include "regs/generated/regs.meta.c" + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 +regs_rip_from_arch_block(Architecture arch, void *block) +{ + U64 result = 0; + switch(arch) + { + default:{}break; + case Architecture_x64:{result = ((REGS_RegBlockX64 *)block)->rip.u64;}break; + case Architecture_x86:{result = (U64)((REGS_RegBlockX86 *)block)->eip.u32;}break; + } + return result; +} + +internal U64 +regs_rsp_from_arch_block(Architecture arch, void *block) +{ + U64 result = 0; + switch(arch) + { + default:{}break; + case Architecture_x64:{result = ((REGS_RegBlockX64 *)block)->rsp.u64;}break; + case Architecture_x86:{result = (U64)((REGS_RegBlockX86 *)block)->esp.u32;}break; + } + return result; +} + +internal void +regs_arch_block_write_rip(Architecture arch, void *block, U64 rip) +{ + switch(arch) + { + default:{}break; + case Architecture_x64:{((REGS_RegBlockX64 *)block)->rip.u64 = rip;}break; + case Architecture_x86:{((REGS_RegBlockX86 *)block)->eip.u32 = (U32)rip;}break; + } +} + +internal void +regs_arch_block_write_rsp(Architecture arch, void *block, U64 rsp) +{ + switch(arch) + { + default:{}break; + case Architecture_x64:{((REGS_RegBlockX64 *)block)->rsp.u64 = rsp;}break; + case Architecture_x86:{((REGS_RegBlockX86 *)block)->esp.u32 = (U32)rsp;}break; + } +} diff --git a/src/regs/regs.h b/src/regs/regs.h new file mode 100644 index 00000000..9875ad2a --- /dev/null +++ b/src/regs/regs.h @@ -0,0 +1,115 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef REGS_H +#define REGS_H + +//////////////////////////////// +//~ rjf: Register Usage Kinds + +typedef enum REGS_UsageKind +{ + REGS_UsageKind_Normal, + REGS_UsageKind_Vector, +} +REGS_UsageKind; + +//////////////////////////////// +//~ rjf: Register Types + +typedef U8 REGS_RegCode; +typedef U8 REGS_AliasCode; + +typedef union REGS_Reg16 REGS_Reg16; +union REGS_Reg16 +{ + U8 v[2]; + U16 u16; +}; + +typedef union REGS_Reg32 REGS_Reg32; +union REGS_Reg32 +{ + U8 v[4]; + U32 u32; + F32 f32; +}; + +typedef union REGS_Reg64 REGS_Reg64; +union REGS_Reg64 +{ + U8 v[8]; + U64 u64; + F64 f64; +}; + +#pragma pack(push, 1) +typedef struct REGS_Reg80 REGS_Reg80; +struct REGS_Reg80 +{ + U64 int1_frac63; + U16 sign1_exp15; +}; +#pragma pack(pop) + +typedef union REGS_Reg128 REGS_Reg128; +union REGS_Reg128 +{ + U8 v[16]; + U32 u32[4]; + F32 f32[4]; + U64 u64[2]; + F64 f64[2]; +}; + +typedef union REGS_Reg256 REGS_Reg256; +union REGS_Reg256 +{ + U8 v[32]; + U32 u32[8]; + F32 f32[8]; + U64 u64[4]; + F64 f64[4]; +}; + +//////////////////////////////// +//~ rjf: Register Slicing Types + +typedef struct REGS_Rng REGS_Rng; +struct REGS_Rng +{ + U16 byte_off; + U16 byte_size; +}; + +typedef struct REGS_Slice REGS_Slice; +struct REGS_Slice +{ + U16 code; + U8 byte_off; + U8 byte_size; +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "regs/generated/regs.meta.h" + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 regs_block_size_from_architecture(Architecture arch); +internal U64 regs_reg_code_count_from_architecture(Architecture arch); +internal U64 regs_alias_code_count_from_architecture(Architecture arch); +internal String8 *regs_reg_code_string_table_from_architecture(Architecture arch); +internal String8 *regs_alias_code_string_table_from_architecture(Architecture arch); +internal REGS_Rng *regs_reg_code_rng_table_from_architecture(Architecture arch); +internal REGS_Slice *regs_alias_code_slice_table_from_architecture(Architecture arch); +internal REGS_UsageKind *regs_reg_code_usage_kind_table_from_architecture(Architecture arch); +internal REGS_UsageKind *regs_alias_code_usage_kind_table_from_architecture(Architecture arch); +internal U64 regs_rip_from_arch_block(Architecture arch, void *block); +internal U64 regs_rsp_from_arch_block(Architecture arch, void *block); +internal void regs_arch_block_write_rip(Architecture arch, void *block, U64 rip); +internal void regs_arch_block_write_rsp(Architecture arch, void *block, U64 rsp); + +#endif // REGS_H diff --git a/src/regs/regs.mc b/src/regs/regs.mc new file mode 100644 index 00000000..5c5e7f59 --- /dev/null +++ b/src/regs/regs.mc @@ -0,0 +1,556 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: X64 Tables + +@table(name size usage) +REGS_RegTableX64: +{ + {rax 64 Normal} + {rcx 64 Normal} + {rdx 64 Normal} + {rbx 64 Normal} + {rsp 64 Normal} + {rbp 64 Normal} + {rsi 64 Normal} + {rdi 64 Normal} + {r8 64 Normal} + {r9 64 Normal} + {r10 64 Normal} + {r11 64 Normal} + {r12 64 Normal} + {r13 64 Normal} + {r14 64 Normal} + {r15 64 Normal} + {fsbase 64 Normal} + {gsbase 64 Normal} + {rip 64 Normal} + {rflags 64 Normal} + {dr0 32 Normal} + {dr1 32 Normal} + {dr2 32 Normal} + {dr3 32 Normal} + {dr4 32 Normal} + {dr5 32 Normal} + {dr6 32 Normal} + {dr7 32 Normal} + {fpr0 80 Normal} + {fpr1 80 Normal} + {fpr2 80 Normal} + {fpr3 80 Normal} + {fpr4 80 Normal} + {fpr5 80 Normal} + {fpr6 80 Normal} + {fpr7 80 Normal} + {st0 80 Normal} + {st1 80 Normal} + {st2 80 Normal} + {st3 80 Normal} + {st4 80 Normal} + {st5 80 Normal} + {st6 80 Normal} + {st7 80 Normal} + {fcw 16 Normal} + {fsw 16 Normal} + {ftw 16 Normal} + {fop 16 Normal} + {fcs 16 Normal} + {fds 16 Normal} + {fip 32 Normal} + {fdp 32 Normal} + {mxcsr 32 Normal} + {mxcsr_mask 32 Normal} + {ss 16 Normal} + {cs 16 Normal} + {ds 16 Normal} + {es 16 Normal} + {fs 16 Normal} + {gs 16 Normal} + {ymm0 256 Normal} + {ymm1 256 Normal} + {ymm2 256 Normal} + {ymm3 256 Normal} + {ymm4 256 Normal} + {ymm5 256 Normal} + {ymm6 256 Normal} + {ymm7 256 Normal} + {ymm8 256 Normal} + {ymm9 256 Normal} + {ymm10 256 Normal} + {ymm11 256 Normal} + {ymm12 256 Normal} + {ymm13 256 Normal} + {ymm14 256 Normal} + {ymm15 256 Normal} +} + +@table(name base off size usage) +REGS_AliasTableX64: +{ + {eax rax 0 32 Normal} + {ecx rcx 0 32 Normal} + {edx rdx 0 32 Normal} + {ebx rbx 0 32 Normal} + {esp rsp 0 32 Normal} + {ebp rbp 0 32 Normal} + {esi rsi 0 32 Normal} + {edi rdi 0 32 Normal} + {r8d r8 0 32 Normal} + {r9d r9 0 32 Normal} + {r10d r10 0 32 Normal} + {r11d r11 0 32 Normal} + {r12d r12 0 32 Normal} + {r13d r13 0 32 Normal} + {r14d r14 0 32 Normal} + {r15d r15 0 32 Normal} + + // TODO(allen): figure this one out; visual studio disagrees + {eip rip 0 32 Normal} + + {eflags rflags 0 32 Normal} + {ax rax 0 16 Normal} + {cx rcx 0 16 Normal} + {dx rdx 0 16 Normal} + {bx rbx 0 16 Normal} + {si rsi 0 16 Normal} + {di rdi 0 16 Normal} + {sp rsp 0 16 Normal} + {bp rbp 0 16 Normal} + {ip rip 0 16 Normal} + {r8w r8 0 16 Normal} + {r9w r9 0 16 Normal} + {r10w r10 0 16 Normal} + {r11w r11 0 16 Normal} + {r12w r12 0 16 Normal} + {r13w r13 0 16 Normal} + {r14w r14 0 16 Normal} + {r15w r15 0 16 Normal} + {al rax 0 8 Normal} + {cl rcx 0 8 Normal} + {dl rdx 0 8 Normal} + {bl rbx 0 8 Normal} + {sil rsi 0 8 Normal} + {dil rdi 0 8 Normal} + {bpl rbp 0 8 Normal} + {spl rsp 0 8 Normal} + {r8b r8 0 8 Normal} + {r9b r9 0 8 Normal} + {r10b r10 0 8 Normal} + {r11b r11 0 8 Normal} + {r12b r12 0 8 Normal} + {r13b r13 0 8 Normal} + {r14b r14 0 8 Normal} + {r15b r15 0 8 Normal} + {ah rax 8 8 Normal} + {ch rcx 8 8 Normal} + {dh rdx 8 8 Normal} + {bh rbx 8 8 Normal} + {xmm0 ymm0 0 128 Normal} + {xmm1 ymm1 0 128 Normal} + {xmm2 ymm2 0 128 Normal} + {xmm3 ymm3 0 128 Normal} + {xmm4 ymm4 0 128 Normal} + {xmm5 ymm5 0 128 Normal} + {xmm6 ymm6 0 128 Normal} + {xmm7 ymm7 0 128 Normal} + {xmm8 ymm8 0 128 Normal} + {xmm9 ymm9 0 128 Normal} + {xmm10 ymm10 0 128 Normal} + {xmm11 ymm11 0 128 Normal} + {xmm12 ymm12 0 128 Normal} + {xmm13 ymm13 0 128 Normal} + {xmm14 ymm14 0 128 Normal} + {xmm15 ymm15 0 128 Normal} + {mm0 fpr0 0 64 Normal} + {mm1 fpr1 0 64 Normal} + {mm2 fpr2 0 64 Normal} + {mm3 fpr3 0 64 Normal} + {mm4 fpr4 0 64 Normal} + {mm5 fpr5 0 64 Normal} + {mm6 fpr6 0 64 Normal} + {mm7 fpr7 0 64 Normal} +} + +//////////////////////////////// +//~ rjf: X86 Tables + +@table(name size usage) +REGS_RegTableX86: +{ + {eax 32 Normal} + {ecx 32 Normal} + {edx 32 Normal} + {ebx 32 Normal} + {esp 32 Normal} + {ebp 32 Normal} + {esi 32 Normal} + {edi 32 Normal} + {fsbase 32 Normal} + {gsbase 32 Normal} + {eflags 32 Normal} + {eip 32 Normal} + {dr0 32 Normal} + {dr1 32 Normal} + {dr2 32 Normal} + {dr3 32 Normal} + {dr4 32 Normal} + {dr5 32 Normal} + {dr6 32 Normal} + {dr7 32 Normal} + // FSave registers + // TODO(allen): I am suspicious of this stuff here. + // Are fpr0-7 and st0-7 actually different things? Visual studio doesn't show + // frp0-7. Not sure if the mm0-7 aliases are setup the right way either. + {fpr0 80 Normal} + {fpr1 80 Normal} + {fpr2 80 Normal} + {fpr3 80 Normal} + {fpr4 80 Normal} + {fpr5 80 Normal} + {fpr6 80 Normal} + {fpr7 80 Normal} + {st0 80 Normal} + {st1 80 Normal} + {st2 80 Normal} + {st3 80 Normal} + {st4 80 Normal} + {st5 80 Normal} + {st6 80 Normal} + {st7 80 Normal} + {fcw 16 Normal} + {fsw 16 Normal} + {ftw 16 Normal} + {fop 16 Normal} + {fcs 16 Normal} + {fds 16 Normal} + {fip 32 Normal} + {fdp 32 Normal} + {mxcsr 32 Normal} + // TODO(allen): I don't think this is really a "register" - think about this... + {mxcsr_mask 32 Normal} + {ss 16 Normal} + {cs 16 Normal} + {ds 16 Normal} + {es 16 Normal} + {fs 16 Normal} + {gs 16 Normal} + // SIMD REGISTERS + {ymm0 256 Normal} + {ymm1 256 Normal} + {ymm2 256 Normal} + {ymm3 256 Normal} + {ymm4 256 Normal} + {ymm5 256 Normal} + {ymm6 256 Normal} + {ymm7 256 Normal} +} + +@table(name base off size usage) +REGS_AliasTableX86: +{ + {ax eax 0 16 Normal} + {cx ecx 0 16 Normal} + {bx ebx 0 16 Normal} + {dx edx 0 16 Normal} + {sp esp 0 16 Normal} + {bp ebp 0 16 Normal} + {si esi 0 16 Normal} + {di edi 0 16 Normal} + {ip eip 0 16 Normal} + {ah eax 8 8 Normal} + {ch ecx 8 8 Normal} + {dh edx 8 8 Normal} + {bh ebx 8 8 Normal} + {al eax 0 8 Normal} + {cl ecx 0 8 Normal} + {dl edx 0 8 Normal} + {bl ebx 0 8 Normal} + {bpl ebp 0 8 Normal} + {spl esp 0 8 Normal} + {xmm0 ymm0 0 128 Normal} + {xmm1 ymm1 0 128 Normal} + {xmm2 ymm2 0 128 Normal} + {xmm3 ymm3 0 128 Normal} + {xmm4 ymm4 0 128 Normal} + {xmm5 ymm5 0 128 Normal} + {xmm6 ymm6 0 128 Normal} + {xmm7 ymm7 0 128 Normal} + {mm0 fpr0 0 64 Normal} + {mm1 fpr1 0 64 Normal} + {mm2 fpr2 0 64 Normal} + {mm3 fpr3 0 64 Normal} + {mm4 fpr4 0 64 Normal} + {mm5 fpr5 0 64 Normal} + {mm6 fpr6 0 64 Normal} + {mm7 fpr7 0 64 Normal} +} + +//////////////////////////////// +//~ rjf: Architecture Tables + +@table(name, name_lower) +REGS_ArchTable: +{ + {X64 x64} + {X86 x86} +} + +//////////////////////////////// +//~ rjf: X64 Generators + +@table_gen_enum REGS_RegCodeX64: +{ + `REGS_RegCodeX64_NULL,`; + @expand(REGS_RegTableX64 a) `REGS_RegCodeX64_$(a.name),`; + `REGS_RegCodeX64_COUNT`; +} + +@table_gen_enum REGS_AliasCodeX64: +{ + `REGS_AliasCodeX64_NULL,`; + @expand(REGS_AliasTableX64 a) `REGS_AliasCodeX64_$(a.name),`; + `REGS_AliasCodeX64_COUNT`; +} + +@table_gen_struct +REGS_RegBlockX64: +{ + @expand(REGS_RegTableX64 a) `REGS_Reg$(a.size) $(a.name);`; +} + +@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) +regs_g_reg_code_x64_usage_kind_table: +{ + `REGS_UsageKind_Normal,`; + @expand(REGS_RegTableX64 a) `REGS_UsageKind_$(a.usage),`; +} + +@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) +regs_g_alias_code_x64_usage_kind_table: +{ + `REGS_UsageKind_Normal,`; + @expand(REGS_AliasTableX64 a) `REGS_UsageKind_$(a.usage),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +regs_g_reg_code_x64_string_table: +{ + `str8_lit_comp(""),`; + @expand(REGS_RegTableX64 a) `str8_lit_comp("$(a.name)"),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +regs_g_alias_code_x64_string_table: +{ + `str8_lit_comp(""),`; + @expand(REGS_AliasTableX64 a) `str8_lit_comp("$(a.name)"),`; +} + +@table_gen_data(type: REGS_Rng, fallback: `{0}`) +regs_g_reg_code_x64_rng_table: +{ + `{0},`; + @expand(REGS_RegTableX64 a) `{(U16)OffsetOf(REGS_RegBlockX64, $(a.name)), $(a.size/8)},`, +} + +@table_gen_data(type: REGS_Slice, fallback: `{0}`) +regs_g_alias_code_x64_slice_table: +{ + `{0},`; + @expand(REGS_AliasTableX64 a) `{REGS_RegCodeX64_$(a.base), $(a.off/8), $(a.size/8)},`, +} + +//////////////////////////////// +//~ rjf: X86 Generators + +@table_gen_enum REGS_RegCodeX86: +{ + `REGS_RegCodeX86_NULL,`; + @expand(REGS_RegTableX86 a) `REGS_RegCodeX86_$(a.name),`; + `REGS_RegCodeX86_COUNT`; +} + +@table_gen_enum REGS_AliasCodeX86: +{ + `REGS_AliasCodeX86_NULL,`; + @expand(REGS_AliasTableX86 a) `REGS_AliasCodeX86_$(a.name),`; + `REGS_AliasCodeX86_COUNT`; +} + +@table_gen_struct +REGS_RegBlockX86: +{ + @expand(REGS_RegTableX86 a) `REGS_Reg$(a.size) $(a.name);`; +} + +@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) +regs_g_reg_code_x86_usage_kind_table: +{ + `REGS_UsageKind_Normal,`; + @expand(REGS_RegTableX86 a) `REGS_UsageKind_$(a.usage),`; +} + +@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) +regs_g_alias_code_x86_usage_kind_table: +{ + `REGS_UsageKind_Normal,`; + @expand(REGS_AliasTableX86 a) `REGS_UsageKind_$(a.usage),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +regs_g_reg_code_x86_string_table: +{ + `str8_lit_comp(""),`; + @expand(REGS_RegTableX86 a) `str8_lit_comp("$(a.name)"),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +regs_g_alias_code_x86_string_table: +{ + `str8_lit_comp(""),`; + @expand(REGS_AliasTableX86 a) `str8_lit_comp("$(a.name)"),`; +} + +@table_gen_data(type: REGS_Rng, fallback: `{0}`) +regs_g_reg_code_x86_rng_table: +{ + `{0},`; + @expand(REGS_RegTableX86 a) `{(U16)OffsetOf(REGS_RegBlockX86, $(a.name)), $(a.size/8)},`, +} + +@table_gen_data(type: REGS_Slice, fallback: `{0}`) +regs_g_alias_code_x86_slice_table: +{ + `{0},`; + @expand(REGS_AliasTableX86 a) `{REGS_RegCodeX86_$(a.base), $(a.off/8), $(a.size/8)},`, +} + +//////////////////////////////// +//~ rjf: Architecture-Dynamic Helper Implementation Generators + +@c_file @table_gen +{ + `internal U64 regs_block_size_from_architecture(Architecture arch)`; + `{`; + `U64 result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = sizeof(REGS_RegBlock$(a.name));}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal U64 regs_reg_code_count_from_architecture(Architecture arch)`; + `{`; + `U64 result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = REGS_RegCode$(a.name)_COUNT;}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal U64 regs_alias_code_count_from_architecture(Architecture arch)`; + `{`; + `U64 result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = REGS_AliasCode$(a.name)_COUNT;}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal String8 *regs_reg_code_string_table_from_architecture(Architecture arch)`; + `{`; + `String8 *result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = regs_g_reg_code_$(a.name_lower)_string_table;}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal String8 *regs_alias_code_string_table_from_architecture(Architecture arch)`; + `{`; + `String8 *result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = regs_g_alias_code_$(a.name_lower)_string_table;}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal REGS_Rng *regs_reg_code_rng_table_from_architecture(Architecture arch)`; + `{`; + `REGS_Rng *result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = regs_g_reg_code_$(a.name_lower)_rng_table;}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal REGS_Slice *regs_alias_code_slice_table_from_architecture(Architecture arch)`; + `{`; + `REGS_Slice *result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = regs_g_alias_code_$(a.name_lower)_slice_table;}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal REGS_UsageKind *regs_reg_code_usage_kind_table_from_architecture(Architecture arch)`; + `{`; + `REGS_UsageKind *result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = regs_g_reg_code_$(a.name_lower)_usage_kind_table;}break;`; + `}`; + `return result;`; + `}`; +} + +@c_file @table_gen +{ + `internal REGS_UsageKind *regs_alias_code_usage_kind_table_from_architecture(Architecture arch)`; + `{`; + `REGS_UsageKind *result = 0;`; + `switch(arch)`; + `{`; + `default:{}break;`; + @expand(REGS_ArchTable a) `case Architecture_$(a.name_lower):{result = regs_g_alias_code_$(a.name_lower)_usage_kind_table;}break;`; + `}`; + `return result;`; + `}`; +} diff --git a/src/render/d3d11/generated/render_d3d11.meta.c b/src/render/d3d11/generated/render_d3d11.meta.c new file mode 100644 index 00000000..8969f2d6 --- /dev/null +++ b/src/render/d3d11/generated/render_d3d11.meta.c @@ -0,0 +1,66 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +String8 r_d3d11_g_vshad_kind_source_table[] = +{ +r_d3d11_g_rect_shader_src, +r_d3d11_g_blur_shader_src, +r_d3d11_g_mesh_shader_src, +r_d3d11_g_geo3dcomposite_shader_src, +r_d3d11_g_finalize_shader_src, +}; + +String8 r_d3d11_g_vshad_kind_source_name_table[] = +{ +str8_lit_comp("r_d3d11_g_rect_shader_src"), +str8_lit_comp("r_d3d11_g_blur_shader_src"), +str8_lit_comp("r_d3d11_g_mesh_shader_src"), +str8_lit_comp("r_d3d11_g_geo3dcomposite_shader_src"), +str8_lit_comp("r_d3d11_g_finalize_shader_src"), +}; + +D3D11_INPUT_ELEMENT_DESC * r_d3d11_g_vshad_kind_elements_ptr_table[] = +{ +r_d3d11_g_rect_ilay_elements, +0, +r_d3d11_g_mesh_ilay_elements, +0, +0, +}; + +U64 r_d3d11_g_vshad_kind_elements_count_table[] = +{ +ArrayCount(r_d3d11_g_rect_ilay_elements) , + 0, +ArrayCount(r_d3d11_g_mesh_ilay_elements) , + 0, + 0, +}; + +String8 r_d3d11_g_pshad_kind_source_table[] = +{ +r_d3d11_g_rect_shader_src, +r_d3d11_g_blur_shader_src, +r_d3d11_g_mesh_shader_src, +r_d3d11_g_geo3dcomposite_shader_src, +r_d3d11_g_finalize_shader_src, +}; + +String8 r_d3d11_g_pshad_kind_source_name_table[] = +{ +str8_lit_comp("r_d3d11_g_rect_shader_src"), +str8_lit_comp("r_d3d11_g_blur_shader_src"), +str8_lit_comp("r_d3d11_g_mesh_shader_src"), +str8_lit_comp("r_d3d11_g_geo3dcomposite_shader_src"), +str8_lit_comp("r_d3d11_g_finalize_shader_src"), +}; + +U64 r_d3d11_g_uniform_type_kind_size_table[] = +{ +sizeof(R_D3D11_Uniforms_Rect), +sizeof(R_D3D11_Uniforms_Blur), +sizeof(R_D3D11_Uniforms_Mesh), +}; + diff --git a/src/render/d3d11/generated/render_d3d11.meta.h b/src/render/d3d11/generated/render_d3d11.meta.h new file mode 100644 index 00000000..d1f9afb7 --- /dev/null +++ b/src/render/d3d11/generated/render_d3d11.meta.h @@ -0,0 +1,464 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef RENDER_D3D11_META_H +#define RENDER_D3D11_META_H + +typedef enum R_D3D11_VShadKind +{ +R_D3D11_VShadKind_Rect, +R_D3D11_VShadKind_Blur, +R_D3D11_VShadKind_Mesh, +R_D3D11_VShadKind_Geo3DComposite, +R_D3D11_VShadKind_Finalize, +R_D3D11_VShadKind_COUNT +} R_D3D11_VShadKind; + +typedef enum R_D3D11_PShadKind +{ +R_D3D11_PShadKind_Rect, +R_D3D11_PShadKind_Blur, +R_D3D11_PShadKind_Mesh, +R_D3D11_PShadKind_Geo3DComposite, +R_D3D11_PShadKind_Finalize, +R_D3D11_PShadKind_COUNT +} R_D3D11_PShadKind; + +typedef enum R_D3D11_UniformTypeKind +{ +R_D3D11_UniformTypeKind_Rect, +R_D3D11_UniformTypeKind_Blur, +R_D3D11_UniformTypeKind_Mesh, +R_D3D11_UniformTypeKind_COUNT +} R_D3D11_UniformTypeKind; + +read_only global String8 r_d3d11_g_rect_shader_src = +str8_lit_comp( +"" +"\n" +"cbuffer Globals : register(b0)\n" +"{\n" +" float2 viewport_size_px;\n" +" float opacity;\n" +" row_major float4x4 texture_sample_channel_map;\n" +" float2 texture_t2d_size_px;\n" +" row_major float3x3 xform;\n" +" float2 xform_scale;\n" +"}\n" +"\n" +"struct CPU2Vertex\n" +"{\n" +" float4 dst_rect_px : POS;\n" +" float4 src_rect_px : TEX;\n" +" float4 color00 : COL0;\n" +" float4 color01 : COL1;\n" +" float4 color10 : COL2;\n" +" float4 color11 : COL3;\n" +" float4 corner_radii_px : CRAD;\n" +" float4 style_params : STY; // x: border_thickness_px, y: softness_px, z: omit_texture, w: unused\n" +" uint vertex_id : SV_VertexID;\n" +"};\n" +"\n" +"struct Vertex2Pixel\n" +"{\n" +" float4 position : SV_POSITION;\n" +" float2 rect_half_size_px : PSIZE;\n" +" float2 texcoord_pct : TEX;\n" +" float2 cornercoord_pct : COLC;\n" +" float4 color00 : COL0;\n" +" float4 color01 : COL1;\n" +" float4 color10 : COL2;\n" +" float4 color11 : COL3;\n" +" float corner_radius_px : CRAD;\n" +" float border_thickness_px : BTHC;\n" +" float softness_px : SFT;\n" +" float omit_texture : OTX;\n" +"};\n" +"\n" +"Texture2D main_t2d : register(t0);\n" +"SamplerState main_sampler : register(s0);\n" +"\n" +"float rect_sdf(float2 sample_pos, float2 rect_half_size, float r)\n" +"{\n" +" return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;\n" +"}\n" +"\n" +"//- rjf: vertex shader\n" +"\n" +"Vertex2Pixel\n" +"vs_main(CPU2Vertex cpu2vertex)\n" +"{\n" +" //- rjf: unpack & xform rectangle src/dst vertices\n" +" float2 dst_p0_px = cpu2vertex.dst_rect_px.xy;\n" +" float2 dst_p1_px = cpu2vertex.dst_rect_px.zw;\n" +" float2 src_p0_px = cpu2vertex.src_rect_px.xy;\n" +" float2 src_p1_px = cpu2vertex.src_rect_px.zw;\n" +" float2 dst_size_px = abs(dst_p1_px - dst_p0_px);\n" +" \n" +" //- rjf: unpack style params\n" +" float border_thickness_px = cpu2vertex.style_params.x;\n" +" float softness_px = cpu2vertex.style_params.y;\n" +" float omit_texture = cpu2vertex.style_params.z;\n" +" \n" +" //- rjf: prep per-vertex arrays to sample from (p: position, t: texcoord, c: colorcoord, r: cornerradius)\n" +" float2 dst_p_verts_px[] =\n" +" {\n" +" mul(xform, float3(dst_p0_px.x, dst_p1_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y),\n" +" mul(xform, float3(dst_p0_px.x, dst_p0_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y),\n" +" mul(xform, float3(dst_p1_px.x, dst_p1_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y),\n" +" mul(xform, float3(dst_p1_px.x, dst_p0_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y),\n" +" };\n" +" float2 src_p_verts_pct[] =\n" +" {\n" +" float2(src_p0_px.x/texture_t2d_size_px.x, src_p1_px.y/texture_t2d_size_px.y),\n" +" float2(src_p0_px.x/texture_t2d_size_px.x, src_p0_px.y/texture_t2d_size_px.y),\n" +" float2(src_p1_px.x/texture_t2d_size_px.x, src_p1_px.y/texture_t2d_size_px.y),\n" +" float2(src_p1_px.x/texture_t2d_size_px.x, src_p0_px.y/texture_t2d_size_px.y),\n" +" };\n" +" float2 dst_c_verts_pct[] =\n" +" {\n" +" float2(0, 1),\n" +" float2(0, 0),\n" +" float2(1, 1),\n" +" float2(1, 0),\n" +" };\n" +" float dst_r_verts_px[] =\n" +" {\n" +" cpu2vertex.corner_radii_px.y,\n" +" cpu2vertex.corner_radii_px.x,\n" +" cpu2vertex.corner_radii_px.w,\n" +" cpu2vertex.corner_radii_px.z,\n" +" };\n" +" \n" +" // rjf: fill vertex -> pixel data\n" +" Vertex2Pixel vertex2pixel;\n" +" {\n" +" vertex2pixel.position.x = 2 * dst_p_verts_px[cpu2vertex.vertex_id].x / viewport_size_px.x - 1.f;\n" +" vertex2pixel.position.y = 2 * dst_p_verts_px[cpu2vertex.vertex_id].y / viewport_size_px.y - 1.f;\n" +" vertex2pixel.position.z = 0.f;\n" +" vertex2pixel.position.w = 1.f;\n" +" vertex2pixel.rect_half_size_px = dst_size_px/2 * xform_scale;\n" +" vertex2pixel.texcoord_pct = src_p_verts_pct[cpu2vertex.vertex_id];\n" +" vertex2pixel.cornercoord_pct = dst_c_verts_pct[cpu2vertex.vertex_id];\n" +" vertex2pixel.color00 = cpu2vertex.color00;\n" +" vertex2pixel.color01 = cpu2vertex.color01;\n" +" vertex2pixel.color10 = cpu2vertex.color10;\n" +" vertex2pixel.color11 = cpu2vertex.color11;\n" +" vertex2pixel.corner_radius_px = dst_r_verts_px[cpu2vertex.vertex_id];\n" +" vertex2pixel.border_thickness_px = border_thickness_px;\n" +" vertex2pixel.softness_px = softness_px;\n" +" vertex2pixel.omit_texture = omit_texture;\n" +" }\n" +" return vertex2pixel;\n" +"}\n" +"\n" +"//- rjf: pixel shader\n" +"\n" +"float4\n" +"ps_main(Vertex2Pixel vertex2pixel) : SV_TARGET\n" +"{\n" +" // rjf: blend corner colors to produce final tint\n" +" float4 top_color = (1-vertex2pixel.cornercoord_pct.x)*vertex2pixel.color00 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color10;\n" +" float4 bot_color = (1-vertex2pixel.cornercoord_pct.x)*vertex2pixel.color01 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color11;\n" +" float4 tint = (1-vertex2pixel.cornercoord_pct.y)*top_color + (vertex2pixel.cornercoord_pct.y)*bot_color;\n" +" \n" +" // rjf: sample texture\n" +" float4 albedo_sample = float4(1, 1, 1, 1);\n" +" if(vertex2pixel.omit_texture < 1)\n" +" {\n" +" albedo_sample = mul(main_t2d.Sample(main_sampler, vertex2pixel.texcoord_pct), texture_sample_channel_map);\n" +" }\n" +" \n" +" // rjf: determine SDF sample position\n" +" float2 sdf_sample_pos = float2((2*vertex2pixel.cornercoord_pct.x-1)*vertex2pixel.rect_half_size_px.x,\n" +" (2*vertex2pixel.cornercoord_pct.y-1)*vertex2pixel.rect_half_size_px.y);\n" +" \n" +" // rjf: sample for corners\n" +" float corner_sdf_s = rect_sdf(sdf_sample_pos,\n" +" vertex2pixel.rect_half_size_px - float2(vertex2pixel.softness_px*2.f, vertex2pixel.softness_px*2.f),\n" +" vertex2pixel.corner_radius_px);\n" +" float corner_sdf_t = 1-smoothstep(0, 2*vertex2pixel.softness_px, corner_sdf_s);\n" +" \n" +" // rjf: sample for borders\n" +" float border_sdf_s = rect_sdf(sdf_sample_pos,\n" +" vertex2pixel.rect_half_size_px - float2(vertex2pixel.softness_px*2.f, vertex2pixel.softness_px*2.f) - vertex2pixel.border_thickness_px,\n" +" max(vertex2pixel.corner_radius_px-vertex2pixel.border_thickness_px, 0));\n" +" float border_sdf_t = smoothstep(0, 2*vertex2pixel.softness_px, border_sdf_s);\n" +" if(vertex2pixel.border_thickness_px == 0)\n" +" {\n" +" border_sdf_t = 1;\n" +" }\n" +" \n" +" // rjf: form+return final color\n" +" float4 final_color = albedo_sample;\n" +" final_color *= tint;\n" +" final_color *= opacity;\n" +" final_color.a *= corner_sdf_t;\n" +" final_color.a *= border_sdf_t;\n" +" return final_color;\n" +"}\n" +"" +); + +read_only global String8 r_d3d11_g_blur_shader_src = +str8_lit_comp( +"" +"\n" +"cbuffer Globals : register(b0)\n" +"{\n" +" float4 rect;\n" +" float2 viewport_size;\n" +" float blur_size;\n" +" float is_vertical;\n" +" float4 corner_radii_px;\n" +" float4 kernel[32];\n" +"}\n" +"\n" +"struct CPU2Vertex\n" +"{\n" +" uint vertex_id : SV_VertexID;\n" +"};\n" +"\n" +"struct Vertex2Pixel\n" +"{\n" +" float4 position : SV_POSITION;\n" +" float2 texcoord : TEX;\n" +" float2 cornercoord : CRN;\n" +" float corner_radius : RAD;\n" +"};\n" +"\n" +"Texture2D stage_t2d : register(t0);\n" +"SamplerState stage_sampler : register(s0);\n" +"\n" +"float rect_sdf(float2 sample_pos, float2 rect_half_size, float r)\n" +"{\n" +" return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;\n" +"}\n" +"\n" +"//- rjf: vertex shader\n" +"\n" +"Vertex2Pixel\n" +"vs_main(CPU2Vertex c2v)\n" +"{\n" +" float4 vertex_positions__scrn[] =\n" +" {\n" +" float4(rect.x, rect.w, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0),\n" +" float4(rect.x, rect.y, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0),\n" +" float4(rect.z, rect.w, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0),\n" +" float4(rect.z, rect.y, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0),\n" +" };\n" +" float corner_radii__px[] =\n" +" {\n" +" corner_radii_px.y,\n" +" corner_radii_px.x,\n" +" corner_radii_px.w,\n" +" corner_radii_px.z,\n" +" };\n" +" float2 cornercoords__pct[] =\n" +" {\n" +" float2(0, 1),\n" +" float2(0, 0),\n" +" float2(1, 1),\n" +" float2(1, 0),\n" +" };\n" +" float4 vertex_position__scrn = vertex_positions__scrn[c2v.vertex_id];\n" +" float4 vertex_position__clip = float4(2*vertex_position__scrn.x/viewport_size.x - 1,\n" +" 2*vertex_position__scrn.y/viewport_size.y - 1,\n" +" 0, 1);\n" +" Vertex2Pixel v2p;\n" +" {\n" +" v2p.position = vertex_position__clip;\n" +" v2p.texcoord = float2(vertex_position__scrn.x/viewport_size.x, 1 - vertex_position__scrn.y/viewport_size.y);\n" +" v2p.cornercoord = cornercoords__pct[c2v.vertex_id];\n" +" v2p.corner_radius = corner_radii__px[c2v.vertex_id];\n" +" }\n" +" return v2p;\n" +"}\n" +"\n" +"//- rjf: pixel shader\n" +"\n" +"float4\n" +"ps_main(Vertex2Pixel v2p) : SV_TARGET\n" +"{\n" +" // rjf: blend weighted texture samples into color\n" +" float4 color = stage_t2d.Sample(stage_sampler, v2p.texcoord) * kernel[0].x;\n" +" color.a = kernel[0].x;\n" +" for(float i = 1; i < blur_size; i += 1)\n" +" {\n" +" float weight = ((float[4])kernel[uint(i)/4])[uint(i)%4];\n" +" float4 min_sample = stage_t2d.Sample(stage_sampler, v2p.texcoord - float2(!is_vertical*i/viewport_size.x, is_vertical*i/viewport_size.y));\n" +" float4 max_sample = stage_t2d.Sample(stage_sampler, v2p.texcoord + float2(!is_vertical*i/viewport_size.x, is_vertical*i/viewport_size.y));\n" +" min_sample.a = 1;\n" +" max_sample.a = 1;\n" +" color += min_sample*weight;\n" +" color += max_sample*weight;\n" +" }\n" +" \n" +" // rjf: determine SDF sample position\n" +" float2 rect_half_size = float2((rect.z-rect.x)/2, (rect.w-rect.y)/2);\n" +" float2 sdf_sample_pos = float2((2*v2p.cornercoord.x-1)*rect_half_size.x,\n" +" (2*v2p.cornercoord.y-1)*rect_half_size.y);\n" +" \n" +" // rjf: sample for corners\n" +" float corner_sdf_s = rect_sdf(sdf_sample_pos, rect_half_size - float2(2.f, 2.f), v2p.corner_radius);\n" +" float corner_sdf_t = 1-smoothstep(0, 2, corner_sdf_s);\n" +" \n" +" // rjf: weight output color by sdf\n" +" color.a *= corner_sdf_t;\n" +" \n" +" return color;\n" +"}\n" +"" +); + +read_only global String8 r_d3d11_g_mesh_shader_src = +str8_lit_comp( +"" +"\n" +"cbuffer Uniforms : register(b0)\n" +"{\n" +" row_major float4x4 xform;\n" +"}\n" +"\n" +"struct CPU2Vertex\n" +"{\n" +" float3 position : POS;\n" +" float3 normal : NOR;\n" +" float2 texcoord : TEX;\n" +" float3 color : COL;\n" +"};\n" +"\n" +"struct Vertex2Pixel\n" +"{\n" +" float4 position : SV_POSITION;\n" +" float2 texcoord : TEX;\n" +" float4 color : COL;\n" +"};\n" +"\n" +"Vertex2Pixel vs_main(CPU2Vertex c2v)\n" +"{\n" +" Vertex2Pixel v2p;\n" +" v2p.position = mul(float4(c2v.position, 1.f), xform);\n" +" v2p.texcoord = c2v.texcoord;\n" +" v2p.color = float4(c2v.color, 1.f);\n" +" return v2p;\n" +"}\n" +"\n" +"float4 ps_main(Vertex2Pixel v2p) : SV_TARGET\n" +"{\n" +" return v2p.color;\n" +"}\n" +"" +); + +read_only global String8 r_d3d11_g_geo3dcomposite_shader_src = +str8_lit_comp( +"" +"\n" +"struct CPU2Vertex\n" +"{\n" +" uint vertex_id : SV_VertexID;\n" +"};\n" +"\n" +"struct Vertex2Pixel\n" +"{\n" +" float4 position : SV_POSITION;\n" +" float2 texcoord : TEX;\n" +"};\n" +"\n" +"Texture2D stage_t2d : register(t0);\n" +"SamplerState stage_sampler : register(s0);\n" +"\n" +"//- rjf: vertex shader\n" +"\n" +"Vertex2Pixel\n" +"vs_main(CPU2Vertex c2v)\n" +"{\n" +" float4 vertex_positions__modl[] =\n" +" {\n" +" float4(0, 0, 0, 1),\n" +" float4(0, 1, 0, 1),\n" +" float4(1, 0, 0, 1),\n" +" float4(1, 1, 0, 1),\n" +" };\n" +" float4 vertex_position__modl = vertex_positions__modl[c2v.vertex_id];\n" +" float4 vertex_position__clip = float4(2*vertex_position__modl.x - 1, 2*vertex_position__modl.y - 1, 0, 1);\n" +" float2 texcoord = float2(vertex_position__modl.x, vertex_position__modl.y);\n" +" texcoord.y = 1-texcoord.y;\n" +" Vertex2Pixel v2p;\n" +" {\n" +" v2p.position = vertex_position__clip;\n" +" v2p.texcoord = texcoord;\n" +" }\n" +" return v2p;\n" +"}\n" +"\n" +"//- rjf: pixel shader\n" +"\n" +"float4\n" +"ps_main(Vertex2Pixel v2p) : SV_TARGET\n" +"{\n" +" float4 final_color = stage_t2d.Sample(stage_sampler, v2p.texcoord);\n" +" return final_color;\n" +"}\n" +"" +); + +read_only global String8 r_d3d11_g_finalize_shader_src = +str8_lit_comp( +"" +"\n" +"struct CPU2Vertex\n" +"{\n" +" uint vertex_id : SV_VertexID;\n" +"};\n" +"\n" +"struct Vertex2Pixel\n" +"{\n" +" float4 position : SV_POSITION;\n" +" float2 texcoord : TEX;\n" +"};\n" +"\n" +"Texture2D stage_t2d : register(t0);\n" +"SamplerState stage_sampler : register(s0);\n" +"\n" +"//- rjf: vertex shader\n" +"\n" +"Vertex2Pixel\n" +"vs_main(CPU2Vertex c2v)\n" +"{\n" +" float4 vertex_positions__modl[] =\n" +" {\n" +" float4(0, 0, 0, 1),\n" +" float4(0, 1, 0, 1),\n" +" float4(1, 0, 0, 1),\n" +" float4(1, 1, 0, 1),\n" +" };\n" +" float4 vertex_position__modl = vertex_positions__modl[c2v.vertex_id];\n" +" float4 vertex_position__clip = float4(2*vertex_position__modl.x - 1, 2*vertex_position__modl.y - 1, 0, 1);\n" +" float2 texcoord = float2(vertex_position__modl.x, vertex_position__modl.y);\n" +" texcoord.y = 1-texcoord.y;\n" +" Vertex2Pixel v2p;\n" +" {\n" +" v2p.position = vertex_position__clip;\n" +" v2p.texcoord = texcoord;\n" +" }\n" +" return v2p;\n" +"}\n" +"\n" +"//- rjf: pixel shader\n" +"\n" +"float4\n" +"ps_main(Vertex2Pixel v2p) : SV_TARGET\n" +"{\n" +" float4 final_color = stage_t2d.Sample(stage_sampler, v2p.texcoord);\n" +" final_color.a = 1;\n" +" return final_color;\n" +"}\n" +"" +); + + +#endif // RENDER_D3D11_META_H diff --git a/src/render/d3d11/render_d3d11.cpp b/src/render/d3d11/render_d3d11.cpp new file mode 100644 index 00000000..09a9f15c --- /dev/null +++ b/src/render/d3d11/render_d3d11.cpp @@ -0,0 +1,1379 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#undef RADDBG_LAYER_COLOR +#define RADDBG_LAYER_COLOR 0.80f, 0.60f, 0.20f + +//////////////////////////////// +//~ rjf: Input Layout Element Tables + +global D3D11_INPUT_ELEMENT_DESC r_d3d11_g_rect_ilay_elements[] = +{ + { "POS", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, + { "TEX", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, + { "COL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, + { "COL", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, + { "COL", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, + { "COL", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, + { "CRAD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, + { "STY", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, +}; + +global D3D11_INPUT_ELEMENT_DESC r_d3d11_g_mesh_ilay_elements[] = +{ + { "POS", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "NOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEX", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/render_d3d11.meta.c" + +//////////////////////////////// +//~ rjf: Helpers + +internal R_D3D11_Window * +r_d3d11_window_from_handle(R_Handle handle) +{ + R_D3D11_Window *window = (R_D3D11_Window *)handle.u64[0]; + if(window->generation != handle.u64[1]) + { + window = &r_d3d11_window_nil; + } + return window; +} + +internal R_Handle +r_d3d11_handle_from_window(R_D3D11_Window *window) +{ + R_Handle handle = {0}; + handle.u64[0] = (U64)window; + handle.u64[1] = window->generation; + return handle; +} + +internal R_D3D11_Tex2D * +r_d3d11_tex2d_from_handle(R_Handle handle) +{ + R_D3D11_Tex2D *texture = (R_D3D11_Tex2D *)handle.u64[0]; + if(texture == 0 || texture->generation != handle.u64[1]) + { + texture = &r_d3d11_tex2d_nil; + } + return texture; +} + +internal R_Handle +r_d3d11_handle_from_tex2d(R_D3D11_Tex2D *texture) +{ + R_Handle handle = {0}; + handle.u64[0] = (U64)texture; + handle.u64[1] = texture->generation; + return handle; +} + +internal R_D3D11_Buffer * +r_d3d11_buffer_from_handle(R_Handle handle) +{ + R_D3D11_Buffer *buffer = (R_D3D11_Buffer *)handle.u64[0]; + if(buffer == 0 || buffer->generation != handle.u64[1]) + { + buffer = &r_d3d11_buffer_nil; + } + return buffer; +} + +internal R_Handle +r_d3d11_handle_from_buffer(R_D3D11_Buffer *buffer) +{ + R_Handle handle = {0}; + handle.u64[0] = (U64)buffer; + handle.u64[1] = buffer->generation; + return handle; +} + +internal ID3D11Buffer * +r_d3d11_instance_buffer_from_size(U64 size) +{ + ID3D11Buffer *buffer = r_d3d11_state->instance_scratch_buffer_64kb; + if(size > KB(64)) + { + U64 flushed_buffer_size = size; + flushed_buffer_size += MB(1)-1; + flushed_buffer_size -= flushed_buffer_size%MB(1); + + // rjf: build buffer + { + D3D11_BUFFER_DESC desc = {0}; + { + desc.ByteWidth = flushed_buffer_size; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } + HRESULT error = r_d3d11_state->device->CreateBuffer(&desc, 0, &buffer); + } + + // rjf: push buffer to flush list + R_D3D11_FlushBuffer *n = push_array(r_d3d11_state->buffer_flush_arena, R_D3D11_FlushBuffer, 1); + n->buffer = buffer; + SLLQueuePush(r_d3d11_state->first_buffer_to_flush, r_d3d11_state->last_buffer_to_flush, n); + } + return buffer; +} + +//////////////////////////////// +//~ rjf: Backend Hook Implementations + +//- rjf: top-level layer initialization + +r_hook void +r_init(void) +{ + ProfBeginFunction(); + HRESULT error = 0; + Arena *arena = arena_alloc(); + r_d3d11_state = push_array(arena, R_D3D11_State, 1); + r_d3d11_state->arena = arena; + r_d3d11_state->device_rw_mutex = os_rw_mutex_alloc(); + + //- rjf: create base device + UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; +#if !defined(NDEBUG) + creation_flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_0 }; + error = D3D11CreateDevice(0, + D3D_DRIVER_TYPE_HARDWARE, + 0, + creation_flags, + feature_levels, ArrayCount(feature_levels), + D3D11_SDK_VERSION, + &r_d3d11_state->base_device, 0, &r_d3d11_state->base_device_ctx); + + //- rjf: enable break-on-error +#if !defined(NDEBUG) + ID3D11InfoQueue *info = 0; + error = r_d3d11_state->base_device->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)(&info)); + error = info->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, TRUE); + error = info->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE); + info->Release(); +#endif + + //- rjf: get main device + error = r_d3d11_state->base_device->QueryInterface(__uuidof(ID3D11Device1), (void **)(&r_d3d11_state->device)); + error = r_d3d11_state->base_device_ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)(&r_d3d11_state->device_ctx)); + + //- rjf: get dxgi device/adapter/factory + error = r_d3d11_state->device->QueryInterface(__uuidof(IDXGIDevice1), (void **)(&r_d3d11_state->dxgi_device)); + error = r_d3d11_state->dxgi_device->GetAdapter(&r_d3d11_state->dxgi_adapter); + error = r_d3d11_state->dxgi_adapter->GetParent(__uuidof(IDXGIFactory2), (void **)(&r_d3d11_state->dxgi_factory)); + + //- rjf: create main rasterizer + { + D3D11_RASTERIZER_DESC1 desc = {D3D11_FILL_SOLID}; + { + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = D3D11_CULL_BACK; + desc.ScissorEnable = 1; + } + error = r_d3d11_state->device->CreateRasterizerState1(&desc, &r_d3d11_state->main_rasterizer); + } + + //- rjf: create main blend state + { + D3D11_BLEND_DESC desc = {0}; + { + desc.RenderTarget[0].BlendEnable = 1; + desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + } + error = r_d3d11_state->device->CreateBlendState(&desc, &r_d3d11_state->main_blend_state); + } + + //- rjf: create nearest-neighbor sampler + { + D3D11_SAMPLER_DESC desc = zero_struct; + { + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + desc.ComparisonFunc = D3D11_COMPARISON_NEVER; + } + error = r_d3d11_state->device->CreateSamplerState(&desc, &r_d3d11_state->samplers[R_Tex2DSampleKind_Nearest]); + } + + //- rjf: create bilinear sampler + { + D3D11_SAMPLER_DESC desc = zero_struct; + { + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + desc.ComparisonFunc = D3D11_COMPARISON_NEVER; + } + error = r_d3d11_state->device->CreateSamplerState(&desc, &r_d3d11_state->samplers[R_Tex2DSampleKind_Linear]); + } + + //- rjf: create noop depth/stencil state + { + D3D11_DEPTH_STENCIL_DESC desc = {0}; + { + desc.DepthEnable = FALSE; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + desc.DepthFunc = D3D11_COMPARISON_LESS; + } + error = r_d3d11_state->device->CreateDepthStencilState(&desc, &r_d3d11_state->noop_depth_stencil); + } + + //- rjf: create plain depth/stencil state + { + D3D11_DEPTH_STENCIL_DESC desc = {0}; + { + desc.DepthEnable = TRUE; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + desc.DepthFunc = D3D11_COMPARISON_LESS; + } + error = r_d3d11_state->device->CreateDepthStencilState(&desc, &r_d3d11_state->plain_depth_stencil); + } + + //- rjf: create buffers + { + D3D11_BUFFER_DESC desc = {0}; + { + desc.ByteWidth = KB(64); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } + error = r_d3d11_state->device->CreateBuffer(&desc, 0, &r_d3d11_state->instance_scratch_buffer_64kb); + } + + //- rjf: build vertex shaders & input layouts + for(R_D3D11_VShadKind kind = (R_D3D11_VShadKind)0; + kind < R_D3D11_VShadKind_COUNT; + kind = (R_D3D11_VShadKind)(kind+1)) + { + String8 source = r_d3d11_g_vshad_kind_source_table[kind]; + String8 source_name = r_d3d11_g_vshad_kind_source_name_table[kind]; + D3D11_INPUT_ELEMENT_DESC *ilay_elements = r_d3d11_g_vshad_kind_elements_ptr_table[kind]; + U64 ilay_elements_count = r_d3d11_g_vshad_kind_elements_count_table[kind]; + + // rjf: compile vertex shader + ID3DBlob *vshad_source_blob = 0; + ID3DBlob *vshad_source_errors = 0; + ID3D11VertexShader *vshad = 0; + { + error = D3DCompile(source.str, + source.size, + (char *)source_name.str, + 0, + 0, + "vs_main", + "vs_5_0", + 0, + 0, + &vshad_source_blob, + &vshad_source_errors); + String8 errors = {0}; + if(vshad_source_errors) + { + errors = str8((U8 *)vshad_source_errors->GetBufferPointer(), + (U64)vshad_source_errors->GetBufferSize()); + os_graphical_message(1, str8_lit("Vertex Shader Compilation Failure"), errors); + } + else + { + error = r_d3d11_state->device->CreateVertexShader(vshad_source_blob->GetBufferPointer(), vshad_source_blob->GetBufferSize(), 0, &vshad); + } + } + + // rjf: make input layout + ID3D11InputLayout *ilay = 0; + if(ilay_elements != 0) + { + error = r_d3d11_state->device->CreateInputLayout(ilay_elements, ilay_elements_count, + vshad_source_blob->GetBufferPointer(), + vshad_source_blob->GetBufferSize(), + &ilay); + } + + // rjf: store + r_d3d11_state->vshads[kind] = vshad; + r_d3d11_state->ilays[kind] = ilay; + } + + //- rjf: build pixel shaders + for(R_D3D11_PShadKind kind = (R_D3D11_PShadKind)0; + kind < R_D3D11_PShadKind_COUNT; + kind = (R_D3D11_PShadKind)(kind+1)) + { + String8 source = r_d3d11_g_pshad_kind_source_table[kind]; + String8 source_name = r_d3d11_g_pshad_kind_source_name_table[kind]; + + // rjf: compile pixel shader + ID3DBlob *pshad_source_blob = 0; + ID3DBlob *pshad_source_errors = 0; + ID3D11PixelShader *pshad = 0; + { + error = D3DCompile(source.str, + source.size, + (char *)source_name.str, + 0, + 0, + "ps_main", + "ps_5_0", + 0, + 0, + &pshad_source_blob, + &pshad_source_errors); + String8 errors = {0}; + if(pshad_source_errors) + { + errors = str8((U8 *)pshad_source_errors->GetBufferPointer(), + (U64)pshad_source_errors->GetBufferSize()); + os_graphical_message(1, str8_lit("Pixel Shader Compilation Failure"), errors); + } + else + { + error = r_d3d11_state->device->CreatePixelShader(pshad_source_blob->GetBufferPointer(), pshad_source_blob->GetBufferSize(), 0, &pshad); + } + } + + // rjf: store + r_d3d11_state->pshads[kind] = pshad; + } + + //- rjf: build uniform type buffers + for(R_D3D11_UniformTypeKind kind = (R_D3D11_UniformTypeKind)0; + kind < R_D3D11_UniformTypeKind_COUNT; + kind = (R_D3D11_UniformTypeKind)(kind+1)) + { + ID3D11Buffer *buffer = 0; + { + D3D11_BUFFER_DESC desc = {0}; + { + desc.ByteWidth = r_d3d11_g_uniform_type_kind_size_table[kind]; + desc.ByteWidth += 15; + desc.ByteWidth -= desc.ByteWidth % 16; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } + r_d3d11_state->device->CreateBuffer(&desc, 0, &buffer); + } + r_d3d11_state->uniform_type_kind_buffers[kind] = buffer; + } + + //- rjf: create backup texture + { + U32 backup_texture_data[] = + { + 0xff00ffff, 0x330033ff, + 0x330033ff, 0xff00ffff, + }; + r_d3d11_state->backup_texture = r_tex2d_alloc(R_Tex2DKind_Static, v2s32(2, 2), R_Tex2DFormat_RGBA8, backup_texture_data); + } + + //- rjf: initialize buffer flush state + { + r_d3d11_state->buffer_flush_arena = arena_alloc(); + } + + ProfEnd(); +} + +//- rjf: window setup/teardown + +r_hook R_Handle +r_window_equip(OS_Handle handle) +{ + ProfBeginFunction(); + R_Handle result = {0}; + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + //- rjf: allocate per-window-state + R_D3D11_Window *window = r_d3d11_state->first_free_window; + { + if(window == 0) + { + window = push_array(r_d3d11_state->arena, R_D3D11_Window, 1); + } + else + { + U64 gen = window->generation; + SLLStackPop(r_d3d11_state->first_free_window); + MemoryZeroStruct(window); + window->generation = gen; + } + window->generation += 1; + } + + //- rjf: map os window handle -> hwnd + HWND hwnd = {0}; + { + W32_Window *w32_layer_window = w32_window_from_os_window(handle); + hwnd = w32_hwnd_from_window(w32_layer_window); + } + + //- rjf: create swapchain + DXGI_SWAP_CHAIN_DESC1 swapchain_desc = {0}; + { + swapchain_desc.Width = 0; // NOTE(rjf): use window width + swapchain_desc.Height = 0; // NOTE(rjf): use window height + swapchain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + swapchain_desc.Stereo = FALSE; + swapchain_desc.SampleDesc.Count = 1; + swapchain_desc.SampleDesc.Quality = 0; + swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapchain_desc.BufferCount = 2; + swapchain_desc.Scaling = DXGI_SCALING_STRETCH; + swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + swapchain_desc.Flags = 0; + } + r_d3d11_state->dxgi_factory->CreateSwapChainForHwnd(r_d3d11_state->device, hwnd, &swapchain_desc, 0, 0, &window->swapchain); + + //- rjf: create framebuffer & view + window->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&window->framebuffer)); + r_d3d11_state->device->CreateRenderTargetView(window->framebuffer, 0, &window->framebuffer_rtv); + + result = r_d3d11_handle_from_window(window); + } + ProfEnd(); + return result; +} + +r_hook void +r_window_unequip(OS_Handle handle, R_Handle equip_handle) +{ + ProfBeginFunction(); + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + R_D3D11_Window *window = r_d3d11_window_from_handle(equip_handle); + window->stage_color_srv->Release(); + window->stage_color_rtv->Release(); + window->stage_color->Release(); + window->stage_scratch_color_srv->Release(); + window->stage_scratch_color_rtv->Release(); + window->stage_scratch_color->Release(); + window->framebuffer_rtv->Release(); + window->framebuffer->Release(); + window->swapchain->Release(); + window->generation += 1; + SLLStackPush(r_d3d11_state->first_free_window, window); + } + ProfEnd(); +} + +//- rjf: textures + +r_hook R_Handle +r_tex2d_alloc(R_Tex2DKind kind, Vec2S32 size, R_Tex2DFormat format, void *data) +{ + ProfBeginFunction(); + + //- rjf: allocate + R_D3D11_Tex2D *texture = 0; + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + texture = r_d3d11_state->first_free_tex2d; + if(texture == 0) + { + texture = push_array(r_d3d11_state->arena, R_D3D11_Tex2D, 1); + } + else + { + U64 gen = texture->generation; + SLLStackPop(r_d3d11_state->first_free_tex2d); + MemoryZeroStruct(texture); + texture->generation = gen; + } + texture->generation += 1; + } + + //- rjf: kind * initial_data -> usage * cpu access flags + D3D11_USAGE d3d11_usage = D3D11_USAGE_IMMUTABLE; + UINT cpu_access_flags = 0; + { + switch(kind) + { + default: + case R_Tex2DKind_Static: + { + if(data == 0) + { + d3d11_usage = D3D11_USAGE_DYNAMIC; + cpu_access_flags = D3D11_CPU_ACCESS_WRITE; + } + }break; + case R_Tex2DKind_Dynamic: + { + d3d11_usage = D3D11_USAGE_DEFAULT; + cpu_access_flags = D3D11_CPU_ACCESS_WRITE; + }break; + } + } + + //- rjf: format -> dxgi format + DXGI_FORMAT dxgi_format = DXGI_FORMAT_R8G8B8A8_UNORM; + { + switch(format) + { + default:{}break; + case R_Tex2DFormat_R8:{dxgi_format = DXGI_FORMAT_R8_UNORM;}break; + case R_Tex2DFormat_RGBA8:{}break; + case R_Tex2DFormat_BGRA8:{dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM;}break; + } + } + + //- rjf: prep initial data, if passed + D3D11_SUBRESOURCE_DATA initial_data_ = {0}; + D3D11_SUBRESOURCE_DATA *initial_data = 0; + if(data != 0) + { + initial_data = &initial_data_; + initial_data->pSysMem = data; + initial_data->SysMemPitch = r_tex2d_format_bytes_per_pixel_table[format] * size.x; + } + + //- rjf: create texture + D3D11_TEXTURE2D_DESC texture_desc = {0}; + { + texture_desc.Width = size.x; + texture_desc.Height = size.y; + texture_desc.MipLevels = 1; + texture_desc.ArraySize = 1; + texture_desc.Format = dxgi_format; + texture_desc.SampleDesc.Count = 1; + texture_desc.Usage = d3d11_usage; + texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texture_desc.CPUAccessFlags = cpu_access_flags; + } + r_d3d11_state->device->CreateTexture2D(&texture_desc, initial_data, &texture->texture); + + //- rjf: create texture srv + r_d3d11_state->device->CreateShaderResourceView(texture->texture, 0, &texture->view); + + //- rjf: fill basics + { + texture->kind = kind; + texture->size = size; + texture->format = format; + } + + R_Handle result = r_d3d11_handle_from_tex2d(texture); + ProfEnd(); + return result; +} + +r_hook void +r_tex2d_release(R_Handle handle) +{ + ProfBeginFunction(); + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); + SLLStackPush(r_d3d11_state->first_to_free_tex2d, texture); + } + ProfEnd(); +} + +r_hook R_Tex2DKind +r_kind_from_tex2d(R_Handle handle) +{ + R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); + return texture->kind; +} + +r_hook Vec2S32 +r_size_from_tex2d(R_Handle handle) +{ + R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); + return texture->size; +} + +r_hook R_Tex2DFormat +r_format_from_tex2d(R_Handle handle) +{ + R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); + return texture->format; +} + +r_hook void +r_fill_tex2d_region(R_Handle handle, Rng2S32 subrect, void *data) +{ + ProfBeginFunction(); + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); + U64 bytes_per_pixel = r_tex2d_format_bytes_per_pixel_table[texture->format]; + Vec2S32 dim = v2s32(subrect.x1 - subrect.x0, subrect.y1 - subrect.y0); + D3D11_BOX dst_box = + { + (UINT)subrect.x0, (UINT)subrect.y0, 0, + (UINT)subrect.x1, (UINT)subrect.y1, 1, + }; + r_d3d11_state->device_ctx->UpdateSubresource(texture->texture, 0, &dst_box, data, dim.x*bytes_per_pixel, 0); + } + ProfEnd(); +} + +//- rjf: buffers + +r_hook R_Handle +r_buffer_alloc(R_BufferKind kind, U64 size, void *data) +{ + ProfBeginFunction(); + + //- rjf: allocate + R_D3D11_Buffer *buffer = 0; + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + buffer = r_d3d11_state->first_free_buffer; + if(buffer == 0) + { + buffer = push_array(r_d3d11_state->arena, R_D3D11_Buffer, 1); + } + else + { + U64 gen = buffer->generation; + SLLStackPop(r_d3d11_state->first_free_buffer); + MemoryZeroStruct(buffer); + buffer->generation = gen; + } + buffer->generation += 1; + } + + //- rjf: kind * initial_data -> usage * cpu access flags + D3D11_USAGE d3d11_usage = D3D11_USAGE_IMMUTABLE; + UINT cpu_access_flags = 0; + { + switch(kind) + { + default: + case R_BufferKind_Static: + { + if(data == 0) + { + d3d11_usage = D3D11_USAGE_DYNAMIC; + cpu_access_flags = D3D11_CPU_ACCESS_WRITE; + } + }break; + case R_BufferKind_Dynamic: + { + d3d11_usage = D3D11_USAGE_DEFAULT; + cpu_access_flags = D3D11_CPU_ACCESS_WRITE; + }break; + } + } + + //- rjf: prep initial data, if passed + D3D11_SUBRESOURCE_DATA initial_data_ = {0}; + D3D11_SUBRESOURCE_DATA *initial_data = 0; + if(data != 0) + { + initial_data = &initial_data_; + initial_data->pSysMem = data; + } + + //- rjf: create buffer + D3D11_BUFFER_DESC desc = {0}; + { + desc.ByteWidth = size; + desc.Usage = d3d11_usage; + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER|D3D11_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = cpu_access_flags; + } + r_d3d11_state->device->CreateBuffer(&desc, initial_data, &buffer->buffer); + + //- rjf: fill basics + { + buffer->kind = kind; + buffer->size = size; + } + + R_Handle result = r_d3d11_handle_from_buffer(buffer); + ProfEnd(); + return result; +} + +r_hook void +r_buffer_release(R_Handle handle) +{ + ProfBeginFunction(); + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + R_D3D11_Buffer *buffer = r_d3d11_buffer_from_handle(handle); + SLLStackPush(r_d3d11_state->first_to_free_buffer, buffer); + } + ProfEnd(); +} + +//- rjf: frame markers + +r_hook void +r_begin_frame(void) +{ + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + // NOTE(rjf): no-op + } +} + +r_hook void +r_end_frame(void) +{ + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + for(R_D3D11_FlushBuffer *buffer = r_d3d11_state->first_buffer_to_flush; buffer != 0; buffer = buffer->next) + { + buffer->buffer->Release(); + } + for(R_D3D11_Tex2D *tex = r_d3d11_state->first_to_free_tex2d, *next = 0; + tex != 0; + tex = next) + { + next = tex->next; + tex->view->Release(); + tex->texture->Release(); + tex->generation += 1; + SLLStackPush(r_d3d11_state->first_free_tex2d, tex); + } + for(R_D3D11_Buffer *buf = r_d3d11_state->first_to_free_buffer, *next = 0; + buf != 0; + buf = next) + { + next = buf->next; + buf->buffer->Release(); + buf->generation += 1; + SLLStackPush(r_d3d11_state->first_free_buffer, buf); + } + arena_clear(r_d3d11_state->buffer_flush_arena); + r_d3d11_state->first_buffer_to_flush = r_d3d11_state->last_buffer_to_flush = 0; + r_d3d11_state->first_to_free_tex2d = 0; + r_d3d11_state->first_to_free_buffer = 0; + } +} + +r_hook void +r_window_begin_frame(OS_Handle window, R_Handle window_equip) +{ + ProfBeginFunction(); + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + R_D3D11_Window *wnd = r_d3d11_window_from_handle(window_equip); + ID3D11DeviceContext1 *d_ctx = r_d3d11_state->device_ctx; + + //- rjf: get resolution + Rng2F32 client_rect = os_client_rect_from_window(window); + Vec2S32 resolution = {(S32)(client_rect.x1 - client_rect.x0), (S32)(client_rect.y1 - client_rect.y0)}; + + //- rjf: resolution change + if(wnd->last_resolution.x != resolution.x || + wnd->last_resolution.y != resolution.y) + { + wnd->last_resolution = resolution; + + // rjf: resize swapchain & main framebuffer + wnd->framebuffer_rtv->Release(); + wnd->framebuffer->Release(); + wnd->swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0); + wnd->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&wnd->framebuffer)); + r_d3d11_state->device->CreateRenderTargetView(wnd->framebuffer, 0, &wnd->framebuffer_rtv); + + // rjf: release screen-sized render target resources, if there + if(wnd->stage_scratch_color_srv){wnd->stage_scratch_color_srv->Release();} + if(wnd->stage_scratch_color_rtv){wnd->stage_scratch_color_rtv->Release();} + if(wnd->stage_scratch_color) {wnd->stage_scratch_color->Release();} + if(wnd->stage_color_srv) {wnd->stage_color_srv->Release();} + if(wnd->stage_color_rtv) {wnd->stage_color_rtv->Release();} + if(wnd->stage_color) {wnd->stage_color->Release();} + if(wnd->geo3d_color_srv) {wnd->geo3d_color_srv->Release();} + if(wnd->geo3d_color_rtv) {wnd->geo3d_color_rtv->Release();} + if(wnd->geo3d_color) {wnd->geo3d_color->Release();} + if(wnd->geo3d_depth_srv) {wnd->geo3d_depth_srv->Release();} + if(wnd->geo3d_depth_dsv) {wnd->geo3d_depth_dsv->Release();} + if(wnd->geo3d_depth) {wnd->geo3d_depth->Release();} + + // rjf: create stage color targets + { + D3D11_TEXTURE2D_DESC color_desc = {}; + { + wnd->framebuffer->GetDesc(&color_desc); + color_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + color_desc.BindFlags = D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE; + } + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {}; + { + rtv_desc.Format = color_desc.Format; + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + } + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; + { + srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srv_desc.Texture2D.MipLevels = -1; + } + r_d3d11_state->device->CreateTexture2D(&color_desc, 0, &wnd->stage_color); + r_d3d11_state->device->CreateRenderTargetView(wnd->stage_color, &rtv_desc, &wnd->stage_color_rtv); + r_d3d11_state->device->CreateShaderResourceView(wnd->stage_color, &srv_desc, &wnd->stage_color_srv); + r_d3d11_state->device->CreateTexture2D(&color_desc, 0, &wnd->stage_scratch_color); + r_d3d11_state->device->CreateRenderTargetView(wnd->stage_scratch_color, &rtv_desc, &wnd->stage_scratch_color_rtv); + r_d3d11_state->device->CreateShaderResourceView(wnd->stage_scratch_color, &srv_desc, &wnd->stage_scratch_color_srv); + } + + // rjf: create geo3d targets + { + D3D11_TEXTURE2D_DESC color_desc = {}; + { + wnd->framebuffer->GetDesc(&color_desc); + color_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + color_desc.BindFlags = D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE; + } + D3D11_RENDER_TARGET_VIEW_DESC color_rtv_desc = {}; + { + color_rtv_desc.Format = color_desc.Format; + color_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + } + D3D11_SHADER_RESOURCE_VIEW_DESC color_srv_desc = {}; + { + color_srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + color_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + color_srv_desc.Texture2D.MipLevels = -1; + } + D3D11_TEXTURE2D_DESC depth_desc = {}; + { + wnd->framebuffer->GetDesc(&depth_desc); + depth_desc.Format = DXGI_FORMAT_R24G8_TYPELESS; + depth_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE; + } + D3D11_DEPTH_STENCIL_VIEW_DESC depth_dsv_desc = {}; + { + depth_dsv_desc.Flags = 0; + depth_dsv_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + depth_dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depth_dsv_desc.Texture2D.MipSlice = 0; + } + D3D11_SHADER_RESOURCE_VIEW_DESC depth_srv_desc = {}; + { + depth_srv_desc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + depth_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + depth_srv_desc.Texture2D.MostDetailedMip = 0; + depth_srv_desc.Texture2D.MipLevels = -1; + } + r_d3d11_state->device->CreateTexture2D(&color_desc, 0, &wnd->geo3d_color); + r_d3d11_state->device->CreateRenderTargetView(wnd->geo3d_color, &color_rtv_desc, &wnd->geo3d_color_rtv); + r_d3d11_state->device->CreateShaderResourceView(wnd->geo3d_color, &color_srv_desc, &wnd->geo3d_color_srv); + r_d3d11_state->device->CreateTexture2D(&depth_desc, 0, &wnd->geo3d_depth); + r_d3d11_state->device->CreateDepthStencilView(wnd->geo3d_depth, &depth_dsv_desc, &wnd->geo3d_depth_dsv); + r_d3d11_state->device->CreateShaderResourceView(wnd->geo3d_depth, &depth_srv_desc, &wnd->geo3d_depth_srv); + } + } + + //- rjf: clear framebuffers + Vec4F32 clear_color = {0, 0, 0, 0}; + d_ctx->ClearRenderTargetView(wnd->framebuffer_rtv, clear_color.v); + d_ctx->ClearRenderTargetView(wnd->stage_color_rtv, clear_color.v); + } + ProfEnd(); +} + +r_hook void +r_window_end_frame(OS_Handle window, R_Handle window_equip) +{ + ProfBeginFunction(); + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + R_D3D11_Window *wnd = r_d3d11_window_from_handle(window_equip); + ID3D11DeviceContext1 *d_ctx = r_d3d11_state->device_ctx; + + //////////////////////////// + //- rjf: finalize, by writing staging buffer out to window framebuffer + // + { + ID3D11SamplerState *sampler = r_d3d11_state->samplers[R_Tex2DSampleKind_Nearest]; + ID3D11VertexShader *vshad = r_d3d11_state->vshads[R_D3D11_VShadKind_Finalize]; + ID3D11PixelShader *pshad = r_d3d11_state->pshads[R_D3D11_PShadKind_Finalize]; + + // rjf: setup output merger + d_ctx->OMSetRenderTargets(1, &wnd->framebuffer_rtv, 0); + d_ctx->OMSetDepthStencilState(r_d3d11_state->noop_depth_stencil, 0); + d_ctx->OMSetBlendState(r_d3d11_state->main_blend_state, 0, 0xffffffff); + + // rjf: set up rasterizer + Vec2S32 resolution = wnd->last_resolution; + D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (F32)resolution.x, (F32)resolution.y, 0.0f, 1.0f }; + d_ctx->RSSetViewports(1, &viewport); + d_ctx->RSSetState(r_d3d11_state->main_rasterizer); + + // rjf: setup input assembly + d_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + d_ctx->IASetInputLayout(0); + + // rjf: setup shaders + d_ctx->VSSetShader(vshad, 0, 0); + d_ctx->PSSetShader(pshad, 0, 0); + d_ctx->PSSetShaderResources(0, 1, &wnd->stage_color_srv); + d_ctx->PSSetSamplers(0, 1, &sampler); + + // rjf: setup scissor rect + { + D3D11_RECT rect = {0}; + rect.left = 0; + rect.right = (LONG)wnd->last_resolution.x; + rect.top = 0; + rect.bottom = (LONG)wnd->last_resolution.y; + d_ctx->RSSetScissorRects(1, &rect); + } + + // rjf: draw + d_ctx->Draw(4, 0); + } + + //////////////////////////// + //- rjf: present + // + wnd->swapchain->Present(1, 0); + d_ctx->ClearState(); + } + ProfEnd(); +} + +//- rjf: render pass submission + +r_hook void +r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes) +{ + ProfBeginFunction(); + OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + { + //////////////////////////// + //- rjf: unpack arguments + // + R_D3D11_Window *wnd = r_d3d11_window_from_handle(window_equip); + ID3D11DeviceContext1 *d_ctx = r_d3d11_state->device_ctx; + + //////////////////////////// + //- rjf: do passes + // + for(R_PassNode *pass_n = passes->first; pass_n != 0; pass_n = pass_n->next) + { + R_Pass *pass = &pass_n->v; + switch(pass->kind) + { + default:{}break; + + //////////////////////// + //- rjf: ui rendering pass + // + case R_PassKind_UI: + { + //- rjf: unpack params + R_PassParams_UI *params = pass->params_ui; + R_BatchGroup2DList *rect_batch_groups = ¶ms->rects; + + //- rjf: set up rasterizer + Vec2S32 resolution = wnd->last_resolution; + D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (F32)resolution.x, (F32)resolution.y, 0.0f, 1.0f }; + d_ctx->RSSetViewports(1, &viewport); + d_ctx->RSSetState(r_d3d11_state->main_rasterizer); + + //- rjf: draw each batch group + for(R_BatchGroup2DNode *group_n = rect_batch_groups->first; group_n != 0; group_n = group_n->next) + { + R_BatchList *batches = &group_n->batches; + R_BatchGroup2DParams *group_params = &group_n->params; + + // rjf: unpack pipeline info + ID3D11SamplerState *sampler = r_d3d11_state->samplers[group_params->tex_sample_kind]; + ID3D11VertexShader *vshad = r_d3d11_state->vshads[R_D3D11_VShadKind_Rect]; + ID3D11InputLayout *ilay = r_d3d11_state->ilays[R_D3D11_VShadKind_Rect]; + ID3D11PixelShader *pshad = r_d3d11_state->pshads[R_D3D11_PShadKind_Rect]; + ID3D11Buffer *uniforms_buffer = r_d3d11_state->uniform_type_kind_buffers[R_D3D11_UniformTypeKind_Rect]; + + // rjf: get & fill buffer + ID3D11Buffer *buffer = r_d3d11_instance_buffer_from_size(batches->byte_count); + { + D3D11_MAPPED_SUBRESOURCE sub_rsrc = {0}; + r_d3d11_state->device_ctx->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &sub_rsrc); + U8 *dst_ptr = (U8 *)sub_rsrc.pData; + U64 off = 0; + for(R_BatchNode *batch_n = batches->first; batch_n != 0; batch_n = batch_n->next) + { + MemoryCopy(dst_ptr+off, batch_n->v.v, batch_n->v.byte_count); + off += batch_n->v.byte_count; + } + r_d3d11_state->device_ctx->Unmap(buffer, 0); + } + + // rjf: get texture + R_Handle texture_handle = group_params->tex; + if(r_handle_match(texture_handle, r_handle_zero())) + { + texture_handle = r_d3d11_state->backup_texture; + } + R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(texture_handle); + + // rjf: get texture sample map matrix, based on format + Vec4F32 texture_sample_channel_map[] = + { + {1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1}, + }; + switch(texture->format) + { + default: break; + case R_Tex2DFormat_R8: + { + MemoryZeroArray(texture_sample_channel_map); + texture_sample_channel_map[0] = v4f32(1, 1, 1, 1); + }break; + } + + // rjf: upload uniforms + R_D3D11_Uniforms_Rect uniforms = {0}; + { + uniforms.viewport_size = v2f32(resolution.x, resolution.y); + uniforms.opacity = 1-group_params->transparency; + MemoryCopyArray(uniforms.texture_sample_channel_map, texture_sample_channel_map); + uniforms.texture_t2d_size = v2f32(texture->size.x, texture->size.y); + uniforms.xform[0] = v4f32(group_params->xform.v[0][0], group_params->xform.v[1][0], group_params->xform.v[2][0], 0); + uniforms.xform[1] = v4f32(group_params->xform.v[0][1], group_params->xform.v[1][1], group_params->xform.v[2][1], 0); + uniforms.xform[2] = v4f32(group_params->xform.v[0][2], group_params->xform.v[1][2], group_params->xform.v[2][2], 0); + Vec2F32 xform_2x2_col0 = v2f32(uniforms.xform[0].x, uniforms.xform[1].x); + Vec2F32 xform_2x2_col1 = v2f32(uniforms.xform[0].y, uniforms.xform[1].y); + uniforms.xform_scale.x = length_2f32(xform_2x2_col0); + uniforms.xform_scale.y = length_2f32(xform_2x2_col1); + } + { + D3D11_MAPPED_SUBRESOURCE sub_rsrc = {0}; + r_d3d11_state->device_ctx->Map(uniforms_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &sub_rsrc); + MemoryCopy((U8 *)sub_rsrc.pData, &uniforms, sizeof(uniforms)); + r_d3d11_state->device_ctx->Unmap(uniforms_buffer, 0); + } + + // rjf: setup output merger + d_ctx->OMSetRenderTargets(1, &wnd->stage_color_rtv, 0); + d_ctx->OMSetDepthStencilState(r_d3d11_state->noop_depth_stencil, 0); + d_ctx->OMSetBlendState(r_d3d11_state->main_blend_state, 0, 0xffffffff); + + // rjf: setup input assembly + U32 stride = batches->bytes_per_inst; + U32 offset = 0; + d_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + d_ctx->IASetInputLayout(ilay); + d_ctx->IASetVertexBuffers(0, 1, &buffer, &stride, &offset); + + // rjf: setup shaders + d_ctx->VSSetShader(vshad, 0, 0); + d_ctx->VSSetConstantBuffers(0, 1, &uniforms_buffer); + d_ctx->PSSetShader(pshad, 0, 0); + d_ctx->PSSetConstantBuffers(0, 1, &uniforms_buffer); + d_ctx->PSSetShaderResources(0, 1, &texture->view); + d_ctx->PSSetSamplers(0, 1, &sampler); + + // rjf: setup scissor rect + { + Rng2F32 clip = group_params->clip; + D3D11_RECT rect = {0}; + { + if(clip.x0 == 0 && clip.y0 == 0 && clip.x1 == 0 && clip.y1 == 0) + { + rect.left = 0; + rect.right = (LONG)wnd->last_resolution.x; + rect.top = 0; + rect.bottom = (LONG)wnd->last_resolution.y; + } + else if(clip.x0 > clip.x1 || clip.y0 > clip.y1) + { + rect.left = 0; + rect.right = 0; + rect.top = 0; + rect.bottom = 0; + } + else + { + rect.left = (LONG)clip.x0; + rect.right = (LONG)clip.x1; + rect.top = (LONG)clip.y0; + rect.bottom = (LONG)clip.y1; + } + } + d_ctx->RSSetScissorRects(1, &rect); + } + + // rjf: draw + d_ctx->DrawInstanced(4, batches->byte_count / batches->bytes_per_inst, 0, 0); + } + }break; + + //////////////////////// + //- rjf: blur rendering pass + // + case R_PassKind_Blur: + { + R_PassParams_Blur *params = pass->params_blur; + ID3D11SamplerState *sampler = r_d3d11_state->samplers[R_Tex2DSampleKind_Nearest]; + ID3D11VertexShader *vshad = r_d3d11_state->vshads[R_D3D11_VShadKind_Blur]; + ID3D11PixelShader *pshad = r_d3d11_state->pshads[R_D3D11_PShadKind_Blur]; + ID3D11Buffer *uniforms_buffer = r_d3d11_state->uniform_type_kind_buffers[R_D3D11_VShadKind_Blur]; + + //- rjf: perform blur on each axis + ID3D11RenderTargetView *rtvs[Axis2_COUNT] = + { + wnd->stage_scratch_color_rtv, + wnd->stage_color_rtv, + }; + ID3D11ShaderResourceView *srvs[Axis2_COUNT] = + { + wnd->stage_color_srv, + wnd->stage_scratch_color_srv, + }; + for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis+1)) + { + // rjf: setup output merger + d_ctx->OMSetRenderTargets(1, &rtvs[axis], 0); + d_ctx->OMSetDepthStencilState(r_d3d11_state->noop_depth_stencil, 0); + d_ctx->OMSetBlendState(r_d3d11_state->main_blend_state, 0, 0xffffffff); + + // rjf: set up viewport + Vec2S32 resolution = wnd->last_resolution; + D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (F32)resolution.x, (F32)resolution.y, 0.0f, 1.0f }; + d_ctx->RSSetViewports(1, &viewport); + d_ctx->RSSetState(r_d3d11_state->main_rasterizer); + + // rjf: setup input assembly + d_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + d_ctx->IASetInputLayout(0); + + // rjf: set up uniforms + { + F32 stdev = (params->blur_size-1.f)/2.f; + F32 one_over_root_2pi_stdev2 = 1/sqrt_f32(2*pi32*stdev*stdev); + F32 euler32 = 2.718281828459045f; + R_D3D11_Uniforms_Blur uniforms = {0}; + uniforms.viewport_size = v2f32(resolution.x, resolution.y); + uniforms.rect = params->rect; + uniforms.blur_size = params->blur_size; + uniforms.is_vertical = (F32)!!axis; + MemoryCopyArray(uniforms.corner_radii.v, params->corner_radii); + F32 kernel_x = 0; + uniforms.kernel[0].v[0] = 1.f; + if(stdev > 0.f) + { + for(U64 idx = 0; idx < ArrayCount(uniforms.kernel); idx += 1) + { + for(U64 v_idx = 0; v_idx < ArrayCount(uniforms.kernel[idx].v); v_idx += 1) + { + uniforms.kernel[idx].v[v_idx] = one_over_root_2pi_stdev2*pow_f32(euler32, -kernel_x*kernel_x/(2.f*stdev*stdev)); + kernel_x += 1; + } + } + } + if(uniforms.kernel[0].v[0] > 1.f) + { + MemoryZeroArray(uniforms.kernel); + uniforms.kernel[0].v[0] = 1.f; + } + D3D11_MAPPED_SUBRESOURCE sub_rsrc = {0}; + r_d3d11_state->device_ctx->Map(uniforms_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &sub_rsrc); + MemoryCopy((U8 *)sub_rsrc.pData, &uniforms, sizeof(uniforms)); + r_d3d11_state->device_ctx->Unmap(uniforms_buffer, 0); + } + + // rjf: setup shaders + d_ctx->VSSetShader(vshad, 0, 0); + d_ctx->VSSetConstantBuffers(0, 1, &uniforms_buffer); + d_ctx->PSSetShader(pshad, 0, 0); + d_ctx->PSSetConstantBuffers(0, 1, &uniforms_buffer); + d_ctx->PSSetShaderResources(0, 1, &srvs[axis]); + d_ctx->PSSetSamplers(0, 1, &sampler); + + // rjf: setup scissor rect + { + D3D11_RECT rect = {0}; + rect.left = 0; + rect.right = (LONG)wnd->last_resolution.x; + rect.top = 0; + rect.bottom = (LONG)wnd->last_resolution.y; + d_ctx->RSSetScissorRects(1, &rect); + } + + // rjf: draw + d_ctx->Draw(4, 0); + + // rjf: unset srv + ID3D11ShaderResourceView *srv = 0; + d_ctx->PSSetShaderResources(0, 1, &srv); + } + }break; + + + //////////////////////// + //- rjf: 3d geometry rendering pass + // + case R_PassKind_Geo3D: + { + //- rjf: unpack params + R_PassParams_Geo3D *params = pass->params_geo3d; + R_BatchGroup3DMap *mesh_group_map = ¶ms->mesh_batches; + + //- rjf: set up rasterizer + Vec2F32 viewport_dim = dim_2f32(params->viewport); + D3D11_VIEWPORT viewport = { params->viewport.x0, params->viewport.y0, viewport_dim.x, viewport_dim.y, 0.f, 1.f }; + d_ctx->RSSetViewports(1, &viewport); + d_ctx->RSSetState(r_d3d11_state->main_rasterizer); + + //- rjf: clear render targets + { + Vec4F32 bg_color = v4f32(0, 0, 0, 0); + d_ctx->ClearRenderTargetView(wnd->geo3d_color_rtv, bg_color.v); + d_ctx->ClearDepthStencilView(wnd->geo3d_depth_dsv, D3D11_CLEAR_DEPTH, 1.f, 0); + } + + //- rjf: draw mesh batches + { + // rjf: grab pipeline info + ID3D11VertexShader *vshad = r_d3d11_state->vshads[R_D3D11_VShadKind_Mesh]; + ID3D11InputLayout *ilay = r_d3d11_state->ilays[R_D3D11_VShadKind_Mesh]; + ID3D11PixelShader *pshad = r_d3d11_state->pshads[R_D3D11_PShadKind_Mesh]; + ID3D11Buffer *uniforms_buffer = r_d3d11_state->uniform_type_kind_buffers[R_D3D11_VShadKind_Mesh]; + + // rjf: setup output merger + d_ctx->OMSetRenderTargets(1, &wnd->geo3d_color_rtv, wnd->geo3d_depth_dsv); + d_ctx->OMSetDepthStencilState(r_d3d11_state->plain_depth_stencil, 0); + d_ctx->OMSetBlendState(r_d3d11_state->main_blend_state, 0, 0xffffffff); + + // rjf: draw all batches + for(U64 slot_idx = 0; slot_idx < mesh_group_map->slots_count; slot_idx += 1) + { + for(R_BatchGroup3DMapNode *n = mesh_group_map->slots[slot_idx]; n != 0; n = n->next) + { + // rjf: unpack group params + R_BatchList *batches = &n->batches; + R_BatchGroup3DParams *group_params = &n->params; + R_D3D11_Buffer *mesh_vertices = r_d3d11_buffer_from_handle(group_params->mesh_vertices); + R_D3D11_Buffer *mesh_indices = r_d3d11_buffer_from_handle(group_params->mesh_indices); + + // rjf: setup input assembly + U32 stride = 11 * sizeof(F32); + U32 offset = 0; + d_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + d_ctx->IASetInputLayout(ilay); + d_ctx->IASetVertexBuffers(0, 1, &mesh_vertices->buffer, &stride, &offset); + d_ctx->IASetIndexBuffer(mesh_indices->buffer, DXGI_FORMAT_R32_UINT, 0); + + // rjf: setup uniforms buffer + R_D3D11_Uniforms_Mesh uniforms = {0}; + { + uniforms.xform = mul_4x4f32(params->projection, params->view); + } + { + D3D11_MAPPED_SUBRESOURCE sub_rsrc = {0}; + r_d3d11_state->device_ctx->Map(uniforms_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &sub_rsrc); + MemoryCopy((U8 *)sub_rsrc.pData, &uniforms, sizeof(uniforms)); + r_d3d11_state->device_ctx->Unmap(uniforms_buffer, 0); + } + + + // rjf: setup shaders + d_ctx->VSSetShader(vshad, 0, 0); + d_ctx->VSSetConstantBuffers(0, 1, &uniforms_buffer); + d_ctx->PSSetShader(pshad, 0, 0); + d_ctx->PSSetConstantBuffers(0, 1, &uniforms_buffer); + + // rjf: setup scissor rect + { + D3D11_RECT rect = {0}; + { + rect.left = 0; + rect.right = (LONG)wnd->last_resolution.x; + rect.top = 0; + rect.bottom = (LONG)wnd->last_resolution.y; + } + d_ctx->RSSetScissorRects(1, &rect); + } + + // rjf: draw + d_ctx->DrawIndexed(mesh_indices->size/sizeof(U32), 0, 0); + } + } + } + + //- rjf: composite to main staging buffer + { + ID3D11SamplerState *sampler = r_d3d11_state->samplers[R_Tex2DSampleKind_Nearest]; + ID3D11VertexShader *vshad = r_d3d11_state->vshads[R_D3D11_VShadKind_Geo3DComposite]; + ID3D11PixelShader *pshad = r_d3d11_state->pshads[R_D3D11_PShadKind_Geo3DComposite]; + + // rjf: setup output merger + d_ctx->OMSetRenderTargets(1, &wnd->stage_color_rtv, 0); + d_ctx->OMSetDepthStencilState(r_d3d11_state->noop_depth_stencil, 0); + d_ctx->OMSetBlendState(r_d3d11_state->main_blend_state, 0, 0xffffffff); + + // rjf: set up rasterizer + Vec2S32 resolution = wnd->last_resolution; + D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (F32)resolution.x, (F32)resolution.y, 0.0f, 1.0f }; + d_ctx->RSSetViewports(1, &viewport); + d_ctx->RSSetState(r_d3d11_state->main_rasterizer); + + // rjf: setup input assembly + d_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + d_ctx->IASetInputLayout(0); + + // rjf: setup shaders + d_ctx->VSSetShader(vshad, 0, 0); + d_ctx->PSSetShader(pshad, 0, 0); + d_ctx->PSSetShaderResources(0, 1, &wnd->geo3d_color_srv); + d_ctx->PSSetSamplers(0, 1, &sampler); + + // rjf: setup scissor rect + { + D3D11_RECT rect = {0}; + Rng2F32 clip = params->clip; + if(clip.x0 == 0 && clip.y0 == 0 && clip.x1 == 0 && clip.y1 == 0) + { + rect.left = 0; + rect.right = (LONG)wnd->last_resolution.x; + rect.top = 0; + rect.bottom = (LONG)wnd->last_resolution.y; + } + else if(clip.x0 > clip.x1 || clip.y0 > clip.y1) + { + rect.left = 0; + rect.right = 0; + rect.top = 0; + rect.bottom = 0; + } + else + { + rect.left = (LONG)clip.x0; + rect.right = (LONG)clip.x1; + rect.top = (LONG)clip.y0; + rect.bottom = (LONG)clip.y1; + } + d_ctx->RSSetScissorRects(1, &rect); + } + + // rjf: draw + d_ctx->Draw(4, 0); + } + }break; + } + } + } + ProfEnd(); +} diff --git a/src/render/d3d11/render_d3d11.h b/src/render/d3d11/render_d3d11.h new file mode 100644 index 00000000..565928e6 --- /dev/null +++ b/src/render/d3d11/render_d3d11.h @@ -0,0 +1,169 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_D3D11_H +#define RENDER_D3D11_H + +#include +#include +#include + +#pragma comment(lib, "user32") +#pragma comment(lib, "d3d11") +#pragma comment(lib, "d3dcompiler") + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/render_d3d11.meta.h" + +//////////////////////////////// +//~ rjf: C-side Shader Types + +struct R_D3D11_Uniforms_Rect +{ + Vec2F32 viewport_size; + F32 opacity; + F32 _padding0_; + Vec4F32 texture_sample_channel_map[4]; + Vec2F32 texture_t2d_size; + Vec2F32 translate; + Vec4F32 xform[3]; + Vec2F32 xform_scale; +}; + +struct R_D3D11_Uniforms_Blur +{ + Rng2F32 rect; + Vec2F32 viewport_size; + F32 blur_size; + F32 is_vertical; + Vec4F32 corner_radii; + Vec4F32 kernel[32]; +}; + +struct R_D3D11_Uniforms_Mesh +{ + Mat4x4F32 xform; +}; + +//////////////////////////////// +//~ rjf: Main State Types + +struct R_D3D11_Tex2D +{ + R_D3D11_Tex2D *next; + U64 generation; + ID3D11Texture2D *texture; + ID3D11ShaderResourceView *view; + R_Tex2DKind kind; + Vec2S32 size; + R_Tex2DFormat format; +}; + +struct R_D3D11_Buffer +{ + R_D3D11_Buffer *next; + U64 generation; + ID3D11Buffer *buffer; + R_BufferKind kind; + U64 size; +}; + +struct R_D3D11_Window +{ + R_D3D11_Window *next; + U64 generation; + + // rjf: swapchain/framebuffer + IDXGISwapChain1 *swapchain; + ID3D11Texture2D *framebuffer; + ID3D11RenderTargetView *framebuffer_rtv; + + // rjf: staging buffer + ID3D11Texture2D *stage_color; + ID3D11RenderTargetView *stage_color_rtv; + ID3D11ShaderResourceView *stage_color_srv; + ID3D11Texture2D *stage_scratch_color; + ID3D11RenderTargetView *stage_scratch_color_rtv; + ID3D11ShaderResourceView *stage_scratch_color_srv; + + // rjf: geo3d buffer + ID3D11Texture2D *geo3d_color; + ID3D11RenderTargetView *geo3d_color_rtv; + ID3D11ShaderResourceView *geo3d_color_srv; + ID3D11Texture2D *geo3d_depth; + ID3D11DepthStencilView *geo3d_depth_dsv; + ID3D11ShaderResourceView *geo3d_depth_srv; + + // rjf: last state + Vec2S32 last_resolution; +}; + +struct R_D3D11_FlushBuffer +{ + R_D3D11_FlushBuffer *next; + ID3D11Buffer *buffer; +}; + +struct R_D3D11_State +{ + // rjf: state + Arena *arena; + R_D3D11_Window *first_free_window; + R_D3D11_Tex2D *first_free_tex2d; + R_D3D11_Buffer *first_free_buffer; + R_D3D11_Tex2D *first_to_free_tex2d; + R_D3D11_Buffer *first_to_free_buffer; + OS_Handle device_rw_mutex; + + // rjf: base d3d11 objects + ID3D11Device *base_device; + ID3D11DeviceContext *base_device_ctx; + ID3D11Device1 *device; + ID3D11DeviceContext1 *device_ctx; + IDXGIDevice1 *dxgi_device; + IDXGIAdapter *dxgi_adapter; + IDXGIFactory2 *dxgi_factory; + ID3D11RasterizerState1 *main_rasterizer; + ID3D11BlendState *main_blend_state; + ID3D11SamplerState *samplers[R_Tex2DSampleKind_COUNT]; + ID3D11DepthStencilState *noop_depth_stencil; + ID3D11DepthStencilState *plain_depth_stencil; + ID3D11Buffer *instance_scratch_buffer_64kb; + + // rjf: backups + R_Handle backup_texture; + + // rjf: vertex shaders + ID3D11VertexShader *vshads[R_D3D11_VShadKind_COUNT]; + ID3D11InputLayout *ilays[R_D3D11_VShadKind_COUNT]; + ID3D11PixelShader *pshads[R_D3D11_PShadKind_COUNT]; + ID3D11Buffer *uniform_type_kind_buffers[R_D3D11_UniformTypeKind_COUNT]; + + // rjf: buffers to flush at subsequent frame + Arena *buffer_flush_arena; + R_D3D11_FlushBuffer *first_buffer_to_flush; + R_D3D11_FlushBuffer *last_buffer_to_flush; +}; + +//////////////////////////////// +//~ rjf: Globals + +global R_D3D11_State *r_d3d11_state = 0; +global R_D3D11_Window r_d3d11_window_nil = {&r_d3d11_window_nil}; +global R_D3D11_Tex2D r_d3d11_tex2d_nil = {&r_d3d11_tex2d_nil}; +global R_D3D11_Buffer r_d3d11_buffer_nil = {&r_d3d11_buffer_nil}; + +//////////////////////////////// +//~ rjf: Helpers + +internal R_D3D11_Window *r_d3d11_window_from_handle(R_Handle handle); +internal R_Handle r_d3d11_handle_from_window(R_D3D11_Window *window); +internal R_D3D11_Tex2D *r_d3d11_tex2d_from_handle(R_Handle handle); +internal R_Handle r_d3d11_handle_from_tex2d(R_D3D11_Tex2D *texture); +internal R_D3D11_Buffer *r_d3d11_buffer_from_handle(R_Handle handle); +internal R_Handle r_d3d11_handle_from_buffer(R_D3D11_Buffer *buffer); +internal ID3D11Buffer *r_d3d11_instance_buffer_from_size(U64 size); + +#endif // RENDER_D3D11_H diff --git a/src/render/d3d11/render_d3d11.mc b/src/render/d3d11/render_d3d11.mc new file mode 100644 index 00000000..65778805 --- /dev/null +++ b/src/render/d3d11/render_d3d11.mc @@ -0,0 +1,525 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Pipeline Tables + +@table(name, source, ilay_table) +R_D3D11_VShadTable: +{ + {Rect r_d3d11_g_rect_shader_src r_d3d11_g_rect_ilay_elements } + {Blur r_d3d11_g_blur_shader_src 0 } + {Mesh r_d3d11_g_mesh_shader_src r_d3d11_g_mesh_ilay_elements } + {Geo3DComposite r_d3d11_g_geo3dcomposite_shader_src 0 } + {Finalize r_d3d11_g_finalize_shader_src 0 } +} + +@table(name, source) +R_D3D11_PShadTable: +{ + {Rect r_d3d11_g_rect_shader_src } + {Blur r_d3d11_g_blur_shader_src } + {Mesh r_d3d11_g_mesh_shader_src } + {Geo3DComposite r_d3d11_g_geo3dcomposite_shader_src } + {Finalize r_d3d11_g_finalize_shader_src } +} + +@table(name) +R_D3D11_UniformTypeTable: +{ + {Rect} + {Blur} + {Mesh} +} + +//////////////////////////////// +//~ rjf: UI Rectangle Shaders + +@embed_string r_d3d11_g_rect_shader_src: +""" +cbuffer Globals : register(b0) +{ + float2 viewport_size_px; + float opacity; + row_major float4x4 texture_sample_channel_map; + float2 texture_t2d_size_px; + row_major float3x3 xform; + float2 xform_scale; +} + +struct CPU2Vertex +{ + float4 dst_rect_px : POS; + float4 src_rect_px : TEX; + float4 color00 : COL0; + float4 color01 : COL1; + float4 color10 : COL2; + float4 color11 : COL3; + float4 corner_radii_px : CRAD; + float4 style_params : STY; // x: border_thickness_px, y: softness_px, z: omit_texture, w: unused + uint vertex_id : SV_VertexID; +}; + +struct Vertex2Pixel +{ + float4 position : SV_POSITION; + float2 rect_half_size_px : PSIZE; + float2 texcoord_pct : TEX; + float2 cornercoord_pct : COLC; + float4 color00 : COL0; + float4 color01 : COL1; + float4 color10 : COL2; + float4 color11 : COL3; + float corner_radius_px : CRAD; + float border_thickness_px : BTHC; + float softness_px : SFT; + float omit_texture : OTX; +}; + +Texture2D main_t2d : register(t0); +SamplerState main_sampler : register(s0); + +float rect_sdf(float2 sample_pos, float2 rect_half_size, float r) +{ + return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r; +} + +//- rjf: vertex shader + +Vertex2Pixel +vs_main(CPU2Vertex cpu2vertex) +{ + //- rjf: unpack & xform rectangle src/dst vertices + float2 dst_p0_px = cpu2vertex.dst_rect_px.xy; + float2 dst_p1_px = cpu2vertex.dst_rect_px.zw; + float2 src_p0_px = cpu2vertex.src_rect_px.xy; + float2 src_p1_px = cpu2vertex.src_rect_px.zw; + float2 dst_size_px = abs(dst_p1_px - dst_p0_px); + + //- rjf: unpack style params + float border_thickness_px = cpu2vertex.style_params.x; + float softness_px = cpu2vertex.style_params.y; + float omit_texture = cpu2vertex.style_params.z; + + //- rjf: prep per-vertex arrays to sample from (p: position, t: texcoord, c: colorcoord, r: cornerradius) + float2 dst_p_verts_px[] = + { + mul(xform, float3(dst_p0_px.x, dst_p1_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y), + mul(xform, float3(dst_p0_px.x, dst_p0_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y), + mul(xform, float3(dst_p1_px.x, dst_p1_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y), + mul(xform, float3(dst_p1_px.x, dst_p0_px.y, 1)).xy * float2(1, -1) + float2(0, viewport_size_px.y), + }; + float2 src_p_verts_pct[] = + { + float2(src_p0_px.x/texture_t2d_size_px.x, src_p1_px.y/texture_t2d_size_px.y), + float2(src_p0_px.x/texture_t2d_size_px.x, src_p0_px.y/texture_t2d_size_px.y), + float2(src_p1_px.x/texture_t2d_size_px.x, src_p1_px.y/texture_t2d_size_px.y), + float2(src_p1_px.x/texture_t2d_size_px.x, src_p0_px.y/texture_t2d_size_px.y), + }; + float2 dst_c_verts_pct[] = + { + float2(0, 1), + float2(0, 0), + float2(1, 1), + float2(1, 0), + }; + float dst_r_verts_px[] = + { + cpu2vertex.corner_radii_px.y, + cpu2vertex.corner_radii_px.x, + cpu2vertex.corner_radii_px.w, + cpu2vertex.corner_radii_px.z, + }; + + // rjf: fill vertex -> pixel data + Vertex2Pixel vertex2pixel; + { + vertex2pixel.position.x = 2 * dst_p_verts_px[cpu2vertex.vertex_id].x / viewport_size_px.x - 1.f; + vertex2pixel.position.y = 2 * dst_p_verts_px[cpu2vertex.vertex_id].y / viewport_size_px.y - 1.f; + vertex2pixel.position.z = 0.f; + vertex2pixel.position.w = 1.f; + vertex2pixel.rect_half_size_px = dst_size_px/2 * xform_scale; + vertex2pixel.texcoord_pct = src_p_verts_pct[cpu2vertex.vertex_id]; + vertex2pixel.cornercoord_pct = dst_c_verts_pct[cpu2vertex.vertex_id]; + vertex2pixel.color00 = cpu2vertex.color00; + vertex2pixel.color01 = cpu2vertex.color01; + vertex2pixel.color10 = cpu2vertex.color10; + vertex2pixel.color11 = cpu2vertex.color11; + vertex2pixel.corner_radius_px = dst_r_verts_px[cpu2vertex.vertex_id]; + vertex2pixel.border_thickness_px = border_thickness_px; + vertex2pixel.softness_px = softness_px; + vertex2pixel.omit_texture = omit_texture; + } + return vertex2pixel; +} + +//- rjf: pixel shader + +float4 +ps_main(Vertex2Pixel vertex2pixel) : SV_TARGET +{ + // rjf: blend corner colors to produce final tint + float4 top_color = (1-vertex2pixel.cornercoord_pct.x)*vertex2pixel.color00 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color10; + float4 bot_color = (1-vertex2pixel.cornercoord_pct.x)*vertex2pixel.color01 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color11; + float4 tint = (1-vertex2pixel.cornercoord_pct.y)*top_color + (vertex2pixel.cornercoord_pct.y)*bot_color; + + // rjf: sample texture + float4 albedo_sample = float4(1, 1, 1, 1); + if(vertex2pixel.omit_texture < 1) + { + albedo_sample = mul(main_t2d.Sample(main_sampler, vertex2pixel.texcoord_pct), texture_sample_channel_map); + } + + // rjf: determine SDF sample position + float2 sdf_sample_pos = float2((2*vertex2pixel.cornercoord_pct.x-1)*vertex2pixel.rect_half_size_px.x, + (2*vertex2pixel.cornercoord_pct.y-1)*vertex2pixel.rect_half_size_px.y); + + // rjf: sample for corners + float corner_sdf_s = rect_sdf(sdf_sample_pos, + vertex2pixel.rect_half_size_px - float2(vertex2pixel.softness_px*2.f, vertex2pixel.softness_px*2.f), + vertex2pixel.corner_radius_px); + float corner_sdf_t = 1-smoothstep(0, 2*vertex2pixel.softness_px, corner_sdf_s); + + // rjf: sample for borders + float border_sdf_s = rect_sdf(sdf_sample_pos, + vertex2pixel.rect_half_size_px - float2(vertex2pixel.softness_px*2.f, vertex2pixel.softness_px*2.f) - vertex2pixel.border_thickness_px, + max(vertex2pixel.corner_radius_px-vertex2pixel.border_thickness_px, 0)); + float border_sdf_t = smoothstep(0, 2*vertex2pixel.softness_px, border_sdf_s); + if(vertex2pixel.border_thickness_px == 0) + { + border_sdf_t = 1; + } + + // rjf: form+return final color + float4 final_color = albedo_sample; + final_color *= tint; + final_color *= opacity; + final_color.a *= corner_sdf_t; + final_color.a *= border_sdf_t; + return final_color; +} +""" + +//////////////////////////////// +//~ rjf: Blur Shaders + +@embed_string r_d3d11_g_blur_shader_src: +""" +cbuffer Globals : register(b0) +{ + float4 rect; + float2 viewport_size; + float blur_size; + float is_vertical; + float4 corner_radii_px; + float4 kernel[32]; +} + +struct CPU2Vertex +{ + uint vertex_id : SV_VertexID; +}; + +struct Vertex2Pixel +{ + float4 position : SV_POSITION; + float2 texcoord : TEX; + float2 cornercoord : CRN; + float corner_radius : RAD; +}; + +Texture2D stage_t2d : register(t0); +SamplerState stage_sampler : register(s0); + +float rect_sdf(float2 sample_pos, float2 rect_half_size, float r) +{ + return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r; +} + +//- rjf: vertex shader + +Vertex2Pixel +vs_main(CPU2Vertex c2v) +{ + float4 vertex_positions__scrn[] = + { + float4(rect.x, rect.w, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0), + float4(rect.x, rect.y, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0), + float4(rect.z, rect.w, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0), + float4(rect.z, rect.y, 0, 1) * float4(1, -1, 1, 1) + float4(0, viewport_size.y, 0, 0), + }; + float corner_radii__px[] = + { + corner_radii_px.y, + corner_radii_px.x, + corner_radii_px.w, + corner_radii_px.z, + }; + float2 cornercoords__pct[] = + { + float2(0, 1), + float2(0, 0), + float2(1, 1), + float2(1, 0), + }; + float4 vertex_position__scrn = vertex_positions__scrn[c2v.vertex_id]; + float4 vertex_position__clip = float4(2*vertex_position__scrn.x/viewport_size.x - 1, + 2*vertex_position__scrn.y/viewport_size.y - 1, + 0, 1); + Vertex2Pixel v2p; + { + v2p.position = vertex_position__clip; + v2p.texcoord = float2(vertex_position__scrn.x/viewport_size.x, 1 - vertex_position__scrn.y/viewport_size.y); + v2p.cornercoord = cornercoords__pct[c2v.vertex_id]; + v2p.corner_radius = corner_radii__px[c2v.vertex_id]; + } + return v2p; +} + +//- rjf: pixel shader + +float4 +ps_main(Vertex2Pixel v2p) : SV_TARGET +{ + // rjf: blend weighted texture samples into color + float4 color = stage_t2d.Sample(stage_sampler, v2p.texcoord) * kernel[0].x; + color.a = kernel[0].x; + for(float i = 1; i < blur_size; i += 1) + { + float weight = ((float[4])kernel[uint(i)/4])[uint(i)%4]; + float4 min_sample = stage_t2d.Sample(stage_sampler, v2p.texcoord - float2(!is_vertical*i/viewport_size.x, is_vertical*i/viewport_size.y)); + float4 max_sample = stage_t2d.Sample(stage_sampler, v2p.texcoord + float2(!is_vertical*i/viewport_size.x, is_vertical*i/viewport_size.y)); + min_sample.a = 1; + max_sample.a = 1; + color += min_sample*weight; + color += max_sample*weight; + } + + // rjf: determine SDF sample position + float2 rect_half_size = float2((rect.z-rect.x)/2, (rect.w-rect.y)/2); + float2 sdf_sample_pos = float2((2*v2p.cornercoord.x-1)*rect_half_size.x, + (2*v2p.cornercoord.y-1)*rect_half_size.y); + + // rjf: sample for corners + float corner_sdf_s = rect_sdf(sdf_sample_pos, rect_half_size - float2(2.f, 2.f), v2p.corner_radius); + float corner_sdf_t = 1-smoothstep(0, 2, corner_sdf_s); + + // rjf: weight output color by sdf + color.a *= corner_sdf_t; + + return color; +} +""" + +//////////////////////////////// +//~ rjf: Mesh Shaders + +@embed_string r_d3d11_g_mesh_shader_src: +""" +cbuffer Uniforms : register(b0) +{ + row_major float4x4 xform; +} + +struct CPU2Vertex +{ + float3 position : POS; + float3 normal : NOR; + float2 texcoord : TEX; + float3 color : COL; +}; + +struct Vertex2Pixel +{ + float4 position : SV_POSITION; + float2 texcoord : TEX; + float4 color : COL; +}; + +Vertex2Pixel vs_main(CPU2Vertex c2v) +{ + Vertex2Pixel v2p; + v2p.position = mul(float4(c2v.position, 1.f), xform); + v2p.texcoord = c2v.texcoord; + v2p.color = float4(c2v.color, 1.f); + return v2p; +} + +float4 ps_main(Vertex2Pixel v2p) : SV_TARGET +{ + return v2p.color; +} +"""; + +//////////////////////////////// +//~ rjf: Geo3D Composition Shaders + +@embed_string r_d3d11_g_geo3dcomposite_shader_src: +""" +struct CPU2Vertex +{ + uint vertex_id : SV_VertexID; +}; + +struct Vertex2Pixel +{ + float4 position : SV_POSITION; + float2 texcoord : TEX; +}; + +Texture2D stage_t2d : register(t0); +SamplerState stage_sampler : register(s0); + +//- rjf: vertex shader + +Vertex2Pixel +vs_main(CPU2Vertex c2v) +{ + float4 vertex_positions__modl[] = + { + float4(0, 0, 0, 1), + float4(0, 1, 0, 1), + float4(1, 0, 0, 1), + float4(1, 1, 0, 1), + }; + float4 vertex_position__modl = vertex_positions__modl[c2v.vertex_id]; + float4 vertex_position__clip = float4(2*vertex_position__modl.x - 1, 2*vertex_position__modl.y - 1, 0, 1); + float2 texcoord = float2(vertex_position__modl.x, vertex_position__modl.y); + texcoord.y = 1-texcoord.y; + Vertex2Pixel v2p; + { + v2p.position = vertex_position__clip; + v2p.texcoord = texcoord; + } + return v2p; +} + +//- rjf: pixel shader + +float4 +ps_main(Vertex2Pixel v2p) : SV_TARGET +{ + float4 final_color = stage_t2d.Sample(stage_sampler, v2p.texcoord); + return final_color; +} +""" + +//////////////////////////////// +//~ rjf: Finalize Shaders + +@embed_string r_d3d11_g_finalize_shader_src: +""" +struct CPU2Vertex +{ + uint vertex_id : SV_VertexID; +}; + +struct Vertex2Pixel +{ + float4 position : SV_POSITION; + float2 texcoord : TEX; +}; + +Texture2D stage_t2d : register(t0); +SamplerState stage_sampler : register(s0); + +//- rjf: vertex shader + +Vertex2Pixel +vs_main(CPU2Vertex c2v) +{ + float4 vertex_positions__modl[] = + { + float4(0, 0, 0, 1), + float4(0, 1, 0, 1), + float4(1, 0, 0, 1), + float4(1, 1, 0, 1), + }; + float4 vertex_position__modl = vertex_positions__modl[c2v.vertex_id]; + float4 vertex_position__clip = float4(2*vertex_position__modl.x - 1, 2*vertex_position__modl.y - 1, 0, 1); + float2 texcoord = float2(vertex_position__modl.x, vertex_position__modl.y); + texcoord.y = 1-texcoord.y; + Vertex2Pixel v2p; + { + v2p.position = vertex_position__clip; + v2p.texcoord = texcoord; + } + return v2p; +} + +//- rjf: pixel shader + +float4 +ps_main(Vertex2Pixel v2p) : SV_TARGET +{ + float4 final_color = stage_t2d.Sample(stage_sampler, v2p.texcoord); + final_color.a = 1; + return final_color; +} +""" + +//////////////////////////////// +//~ rjf: Table Generators + +@table_gen_enum +R_D3D11_VShadKind: +{ + @expand(R_D3D11_VShadTable a) `R_D3D11_VShadKind_$(a.name),`; + `R_D3D11_VShadKind_COUNT`; +} + +@table_gen_enum +R_D3D11_PShadKind: +{ + @expand(R_D3D11_PShadTable a) `R_D3D11_PShadKind_$(a.name),`; + `R_D3D11_PShadKind_COUNT`; +} + +@table_gen_enum +R_D3D11_UniformTypeKind: +{ + @expand(R_D3D11_UniformTypeTable a) `R_D3D11_UniformTypeKind_$(a.name),`; + `R_D3D11_UniformTypeKind_COUNT`; +} + +@c_file @table_gen_data(type:String8, fallback:`{0}`) +r_d3d11_g_vshad_kind_source_table: +{ + @expand(R_D3D11_VShadTable a) `$(a.source),`; +} + +@c_file @table_gen_data(type:String8, fallback:`{0}`) +r_d3d11_g_vshad_kind_source_name_table: +{ + @expand(R_D3D11_VShadTable a) `str8_lit_comp("$(a.source)"),`; +} + +@c_file @table_gen_data(type:`D3D11_INPUT_ELEMENT_DESC *`, fallback:`0`) +r_d3d11_g_vshad_kind_elements_ptr_table: +{ + @expand(R_D3D11_VShadTable a) `$(a.ilay_table),`; +} + +@c_file @table_gen_data(type:U64, fallback:`0`) +r_d3d11_g_vshad_kind_elements_count_table: +{ + @expand(R_D3D11_VShadTable a) `$(a.ilay_table != 0 -> "ArrayCount("..a.ilay_table..")") $(a.ilay_table == 0 -> "0"),`; +} + +@c_file @table_gen_data(type:String8, fallback:`{0}`) +r_d3d11_g_pshad_kind_source_table: +{ + @expand(R_D3D11_PShadTable a) `$(a.source),`; +} + +@c_file @table_gen_data(type:String8, fallback:`{0}`) +r_d3d11_g_pshad_kind_source_name_table: +{ + @expand(R_D3D11_PShadTable a) `str8_lit_comp("$(a.source)"),`; +} + +@c_file @table_gen_data(type:U64, fallback:`0`) +r_d3d11_g_uniform_type_kind_size_table: +{ + @expand(R_D3D11_UniformTypeTable a) `sizeof(R_D3D11_Uniforms_$(a.name)),`; +} diff --git a/src/render/d3d11/render_d3d11_main.cpp b/src/render/d3d11/render_d3d11_main.cpp new file mode 100644 index 00000000..94367153 --- /dev/null +++ b/src/render/d3d11/render_d3d11_main.cpp @@ -0,0 +1,16 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define SUPPLEMENT_UNIT 1 +#define OS_FEATURE_GRAPHICAL 1 + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "render/render_core.h" + +#include "render_d3d11.h" +#include "render_d3d11.cpp" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "render/render_core.c" diff --git a/src/render/generated/render.meta.c b/src/render/generated/render.meta.c new file mode 100644 index 00000000..3c6ec07e --- /dev/null +++ b/src/render/generated/render.meta.c @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +U64 r_pass_kind_params_size_table[] = +{ +sizeof(R_PassParams_UI), +sizeof(R_PassParams_Blur), +sizeof(R_PassParams_Geo3D), +}; + diff --git a/src/render/generated/render.meta.h b/src/render/generated/render.meta.h new file mode 100644 index 00000000..350e44a0 --- /dev/null +++ b/src/render/generated/render.meta.h @@ -0,0 +1,96 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef RENDER_META_H +#define RENDER_META_H + +typedef enum R_Tex2DFormat +{ +R_Tex2DFormat_R8, +R_Tex2DFormat_RGBA8, +R_Tex2DFormat_BGRA8, +R_Tex2DFormat_COUNT +} R_Tex2DFormat; + +typedef enum R_Tex2DKind +{ +R_Tex2DKind_Static, +R_Tex2DKind_Dynamic, +R_Tex2DKind_COUNT +} R_Tex2DKind; + +typedef enum R_Tex2DSampleKind +{ +R_Tex2DSampleKind_Nearest, +R_Tex2DSampleKind_Linear, +R_Tex2DSampleKind_COUNT +} R_Tex2DSampleKind; + +typedef enum R_GeoTopologyKind +{ +R_GeoTopologyKind_Lines, +R_GeoTopologyKind_LineStrip, +R_GeoTopologyKind_Triangles, +R_GeoTopologyKind_TriangleStrip, +R_GeoTopologyKind_COUNT +} R_GeoTopologyKind; + +typedef enum R_BufferKind +{ +R_BufferKind_Static, +R_BufferKind_Dynamic, +R_BufferKind_COUNT +} R_BufferKind; + +typedef enum R_PassKind +{ +R_PassKind_UI, +R_PassKind_Blur, +R_PassKind_Geo3D, +R_PassKind_COUNT +} R_PassKind; + +String8 r_tex2d_format_display_string_table[] = +{ +str8_lit_comp("R8"), +str8_lit_comp("RGBA8"), +str8_lit_comp("BGRA8"), +}; + +U8 r_tex2d_format_bytes_per_pixel_table[] = +{ +1, +4, +4, +}; + +String8 r_tex2d_kind_display_string_table[] = +{ +str8_lit_comp("Static"), +str8_lit_comp("Dynamic"), +}; + +String8 r_tex2d_sample_kind_display_string_table[] = +{ +str8_lit_comp("Nearest"), +str8_lit_comp("Linear"), +}; + +String8 r_pass_kind_display_string_table[] = +{ +str8_lit_comp("UI"), +str8_lit_comp("Blur"), +str8_lit_comp("Geo3D"), +}; + +U8 r_pass_kind_batch_table[] = +{ +1, +0, +1, +}; + + +#endif // RENDER_META_H diff --git a/src/render/render_core.c b/src/render/render_core.c new file mode 100644 index 00000000..40e0f537 --- /dev/null +++ b/src/render/render_core.c @@ -0,0 +1,77 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/render.meta.c" + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal R_Handle +r_handle_zero(void) +{ + R_Handle handle = {0}; + return handle; +} + +internal B32 +r_handle_match(R_Handle a, R_Handle b) +{ + return a.u64[0] == b.u64[0] && a.u64[1] == b.u64[1]; +} + +//////////////////////////////// +//~ rjf: Batch Type Functions + +internal R_BatchList +r_batch_list_make(U64 instance_size) +{ + R_BatchList list = {0}; + list.bytes_per_inst = instance_size; + return list; +} + +internal void * +r_batch_list_push_inst(Arena *arena, R_BatchList *list, U64 batch_inst_cap) +{ + void *inst = 0; + { + R_BatchNode *n = list->last; + if(n == 0 || n->v.byte_count+list->bytes_per_inst > n->v.byte_cap) + { + n = push_array(arena, R_BatchNode, 1); + n->v.byte_cap = batch_inst_cap*list->bytes_per_inst; + n->v.v = push_array_no_zero(arena, U8, n->v.byte_cap); + SLLQueuePush(list->first, list->last, n); + list->batch_count += 1; + } + inst = n->v.v + n->v.byte_count; + n->v.byte_count += list->bytes_per_inst; + list->byte_count += list->bytes_per_inst; + } + return inst; +} + +//////////////////////////////// +//~ rjf: Pass Type Functions + +internal R_Pass * +r_pass_from_kind(Arena *arena, R_PassList *list, R_PassKind kind) +{ + R_PassNode *n = list->last; + if(!r_pass_kind_batch_table[kind]) + { + n = 0; + } + if(n == 0 || n->v.kind != kind) + { + n = push_array(arena, R_PassNode, 1); + SLLQueuePush(list->first, list->last, n); + list->count += 1; + n->v.kind = kind; + n->v.params = push_array(arena, U8, r_pass_kind_params_size_table[kind]); + } + return &n->v; +} diff --git a/src/render/render_core.h b/src/render/render_core.h new file mode 100644 index 00000000..f6068185 --- /dev/null +++ b/src/render/render_core.h @@ -0,0 +1,299 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_CORE_H +#define RENDER_CORE_H + +#define r_hook C_LINKAGE + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/render.meta.h" + +//////////////////////////////// +//~ rjf: Enums + +typedef U32 R_GeoVertexFlags; +enum +{ + R_GeoVertexFlag_TexCoord = (1<<0), + R_GeoVertexFlag_Normals = (1<<1), + R_GeoVertexFlag_RGB = (1<<2), + R_GeoVertexFlag_RGBA = (1<<3), +}; + +//////////////////////////////// +//~ rjf: Handle Type + +typedef union R_Handle R_Handle; +union R_Handle +{ + U64 u64[2]; + U32 u32[4]; + U16 u16[8]; +}; + +//////////////////////////////// +//~ rjf: Instance Types + +typedef struct R_Rect2DInst R_Rect2DInst; +struct R_Rect2DInst +{ + Rng2F32 dst; + Rng2F32 src; + Vec4F32 colors[Corner_COUNT]; + F32 corner_radii[Corner_COUNT]; + F32 border_thickness; + F32 edge_softness; + F32 white_texture_override; + F32 _unused_[1]; +}; + +typedef struct R_Mesh3DInst R_Mesh3DInst; +struct R_Mesh3DInst +{ + Mat4x4F32 xform; +}; + +//////////////////////////////// +//~ rjf: Batch Types + +typedef struct R_Batch R_Batch; +struct R_Batch +{ + U8 *v; + U64 byte_count; + U64 byte_cap; +}; + +typedef struct R_BatchNode R_BatchNode; +struct R_BatchNode +{ + R_BatchNode *next; + R_Batch v; +}; + +typedef struct R_BatchList R_BatchList; +struct R_BatchList +{ + R_BatchNode *first; + R_BatchNode *last; + U64 batch_count; + U64 byte_count; + U64 bytes_per_inst; +}; + +typedef struct R_BatchGroup2DParams R_BatchGroup2DParams; +struct R_BatchGroup2DParams +{ + R_Handle tex; + R_Tex2DSampleKind tex_sample_kind; + Mat3x3F32 xform; + Rng2F32 clip; + F32 transparency; +}; + +typedef struct R_BatchGroup2DNode R_BatchGroup2DNode; +struct R_BatchGroup2DNode +{ + R_BatchGroup2DNode *next; + R_BatchList batches; + R_BatchGroup2DParams params; +}; + +typedef struct R_BatchGroup2DList R_BatchGroup2DList; +struct R_BatchGroup2DList +{ + R_BatchGroup2DNode *first; + R_BatchGroup2DNode *last; + U64 count; +}; + +typedef struct R_BatchGroup3DParams R_BatchGroup3DParams; +struct R_BatchGroup3DParams +{ + R_Handle mesh_vertices; + R_Handle mesh_indices; + R_GeoTopologyKind mesh_geo_topology; + R_GeoVertexFlags mesh_geo_vertex_flags; + R_Handle albedo_tex; + R_Tex2DSampleKind albedo_tex_sample_kind; + Mat4x4F32 xform; +}; + +typedef struct R_BatchGroup3DMapNode R_BatchGroup3DMapNode; +struct R_BatchGroup3DMapNode +{ + R_BatchGroup3DMapNode *next; + U64 hash; + R_BatchList batches; + R_BatchGroup3DParams params; +}; + +typedef struct R_BatchGroup3DMap R_BatchGroup3DMap; +struct R_BatchGroup3DMap +{ + R_BatchGroup3DMapNode **slots; + U64 slots_count; +}; + +//////////////////////////////// +//~ rjf: Pass Types + +typedef struct R_PassParams_UI R_PassParams_UI; +struct R_PassParams_UI +{ + R_BatchGroup2DList rects; +}; + +typedef struct R_PassParams_Blur R_PassParams_Blur; +struct R_PassParams_Blur +{ + Rng2F32 rect; + F32 blur_size; + F32 corner_radii[Corner_COUNT]; +}; + +typedef struct R_PassParams_Geo3D R_PassParams_Geo3D; +struct R_PassParams_Geo3D +{ + Rng2F32 viewport; + Rng2F32 clip; + Mat4x4F32 view; + Mat4x4F32 projection; + R_BatchGroup3DMap mesh_batches; +}; + +typedef struct R_Pass R_Pass; +struct R_Pass +{ + R_PassKind kind; + union + { + void *params; + R_PassParams_UI *params_ui; + R_PassParams_Blur *params_blur; + R_PassParams_Geo3D *params_geo3d; + }; +}; + +typedef struct R_PassNode R_PassNode; +struct R_PassNode +{ + R_PassNode *next; + R_Pass v; +}; + +typedef struct R_PassList R_PassList; +struct R_PassList +{ + R_PassNode *first; + R_PassNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: 2D Rendering Types + +typedef enum R2_CmdKind +{ + R2_CmdKind_Null, + R2_CmdKind_Rects, + R2_CmdKind_COUNT +} +R2_CmdKind; + +typedef struct R2_CmdInst_Rect R2_CmdInst_Rect; +struct R2_CmdInst_Rect +{ + Rng2F32 dst; + Rng2F32 src; + Vec4F32 colors[Corner_COUNT]; + F32 corner_radii[Corner_COUNT]; + F32 border_thickness; + F32 edge_softness; + F32 white_texture_override; + F32 _unused_[1]; +}; + +typedef struct R2_Cmd R2_Cmd; +struct R2_Cmd +{ + R2_CmdKind kind; + R_Handle texture; + Rng2F32 clip; + Vec2F32 translate; + F32 transparency; + U64 count; + union + { + void *data; + R2_CmdInst_Rect *data__rect; + }; +}; + +typedef struct R2_CmdNode R2_CmdNode; +struct R2_CmdNode +{ + R2_CmdNode *next; + R2_Cmd cmd; +}; + +typedef struct R2_CmdList R2_CmdList; +struct R2_CmdList +{ + R2_CmdNode *first; + R2_CmdNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Handle Type Functions + +internal R_Handle r_handle_zero(void); +internal B32 r_handle_match(R_Handle a, R_Handle b); + +//////////////////////////////// +//~ rjf: Batch Type Functions + +internal R_BatchList r_batch_list_make(U64 instance_size); +internal void *r_batch_list_push_inst(Arena *arena, R_BatchList *list, U64 batch_inst_cap); + +//////////////////////////////// +//~ rjf: Pass Type Functions + +internal R_Pass *r_pass_from_kind(Arena *arena, R_PassList *list, R_PassKind kind); + +//////////////////////////////// +//~ rjf: Backend Hooks + +//- rjf: top-level layer initialization +r_hook void r_init(void); + +//- rjf: window setup/teardown +r_hook R_Handle r_window_equip(OS_Handle window); +r_hook void r_window_unequip(OS_Handle window, R_Handle window_equip); + +//- rjf: textures +r_hook R_Handle r_tex2d_alloc(R_Tex2DKind kind, Vec2S32 size, R_Tex2DFormat format, void *data); +r_hook void r_tex2d_release(R_Handle texture); +r_hook R_Tex2DKind r_kind_from_tex2d(R_Handle texture); +r_hook Vec2S32 r_size_from_tex2d(R_Handle texture); +r_hook R_Tex2DFormat r_format_from_tex2d(R_Handle texture); +r_hook void r_fill_tex2d_region(R_Handle texture, Rng2S32 subrect, void *data); + +//- rjf: buffers +r_hook R_Handle r_buffer_alloc(R_BufferKind kind, U64 size, void *data); +r_hook void r_buffer_release(R_Handle buffer); + +//- rjf: frame markers +r_hook void r_begin_frame(void); +r_hook void r_end_frame(void); +r_hook void r_window_begin_frame(OS_Handle window, R_Handle window_equip); +r_hook void r_window_end_frame(OS_Handle window, R_Handle window_equip); + +//- rjf: render pass submission +r_hook void r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes); + +#endif // RENDER_CORE_H diff --git a/src/render/render_core.mc b/src/render/render_core.mc new file mode 100644 index 00000000..00a25c14 --- /dev/null +++ b/src/render/render_core.mc @@ -0,0 +1,125 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Tables + +@table(name, display_string, bytes_per_pixel) +R_Tex2DFormatTable: +{ + {R8 "R8" 1} + {RGBA8 "RGBA8" 4} + {BGRA8 "BGRA8" 4} +} + +@table(name, display_string) +R_Tex2DKindTable: +{ + {Static "Static" } + {Dynamic "Dynamic"} +} + +@table(name, display_string) +R_Tex2DSampleKindTable: +{ + {Nearest "Nearest" } + {Linear "Linear" } +} + +@table(name, display_string) +R_GeoTopologyKindTable: +{ + {Lines "Lines" } + {LineStrip "Line Strip" } + {Triangles "Triangles" } + {TriangleStrip "Triangle Strip" } +} + +@table(name, display_string) +R_BufferKindTable: +{ + {Static "Static" } + {Dynamic "Dynamic"} +} + +@table(name, batch, display_string) +R_PassKindTable: +{ + {UI 1 "UI" } + {Blur 0 "Blur" } + {Geo3D 1 "Geo3D" } +} + +//////////////////////////////// +//~ rjf: Generators + +@table_gen_enum R_Tex2DFormat: +{ + @expand(R_Tex2DFormatTable a) `R_Tex2DFormat_$(a.name),`; + `R_Tex2DFormat_COUNT`; +} + +@table_gen_enum R_Tex2DKind: +{ + @expand(R_Tex2DKindTable a) `R_Tex2DKind_$(a.name),`; + `R_Tex2DKind_COUNT`; +} + +@table_gen_enum R_Tex2DSampleKind: +{ + @expand(R_Tex2DSampleKindTable a) `R_Tex2DSampleKind_$(a.name),`; + `R_Tex2DSampleKind_COUNT`; +} + +@table_gen_enum R_GeoTopologyKind: +{ + @expand(R_GeoTopologyKindTable a) `R_GeoTopologyKind_$(a.name),`; + `R_GeoTopologyKind_COUNT`; +} + +@table_gen_enum R_BufferKind: +{ + @expand(R_BufferKindTable a) `R_BufferKind_$(a.name),`; + `R_BufferKind_COUNT`; +} + +@table_gen_enum R_PassKind: +{ + @expand(R_PassKindTable a) `R_PassKind_$(a.name),`; + `R_PassKind_COUNT`; +} + +@table_gen_data(type:String8) r_tex2d_format_display_string_table: +{ + @expand(R_Tex2DFormatTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type:U8) r_tex2d_format_bytes_per_pixel_table: +{ + @expand(R_Tex2DFormatTable a) `$(a.bytes_per_pixel),`; +} + +@table_gen_data(type:String8) r_tex2d_kind_display_string_table: +{ + @expand(R_Tex2DKindTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type:String8) r_tex2d_sample_kind_display_string_table: +{ + @expand(R_Tex2DSampleKindTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type:String8) r_pass_kind_display_string_table: +{ + @expand(R_PassKindTable a) `str8_lit_comp("$(a.display_string)"),`; +} + +@table_gen_data(type:U8) r_pass_kind_batch_table: +{ + @expand(R_PassKindTable a) `$(a.batch),`; +} + +@table_gen_data(type:U64) @c_file r_pass_kind_params_size_table: +{ + @expand(R_PassKindTable a) `sizeof(R_PassParams_$(a.name)),`; +} diff --git a/src/render/render_inc.c b/src/render/render_inc.c new file mode 100644 index 00000000..33cc6fbf --- /dev/null +++ b/src/render/render_inc.c @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "render_core.c" + +#if LANG_CPP +# if R_BACKEND == R_BACKEND_D3D11 +# include "d3d11/render_d3d11.cpp" +# else +# error Renderer backend not specified. +# endif +#endif diff --git a/src/render/render_inc.h b/src/render/render_inc.h new file mode 100644 index 00000000..ef45228a --- /dev/null +++ b/src/render/render_inc.h @@ -0,0 +1,35 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_INC_H +#define RENDER_INC_H + +//////////////////////////////// +//~ rjf: Backend Constants + +#define R_BACKEND_D3D11 1 + +//////////////////////////////// +//~ rjf: Decide On Backend + +#if !defined(R_BACKEND) && OS_WINDOWS +# define R_BACKEND R_BACKEND_D3D11 +#endif + +//////////////////////////////// +//~ rjf: Main Includes + +#include "render_core.h" + +//////////////////////////////// +//~ rjf: Backend Includes + +#if LANG_CPP +# if R_BACKEND == R_BACKEND_D3D11 +# include "d3d11/render_d3d11.h" +# else +# error Renderer backend not specified. +# endif +#endif + +#endif // RENDER_INC_H diff --git a/src/scratch/look_at_raddbg.c b/src/scratch/look_at_raddbg.c new file mode 100644 index 00000000..9e3c7313 --- /dev/null +++ b/src/scratch/look_at_raddbg.c @@ -0,0 +1,59 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +// build with: +// cl /Zi /nologo look_at_raddbg.c + +#include +#include +#include "raddbg_format/raddbg_format.h" +#include "raddbg_format/raddbg_format_parse.h" +#include "raddbg_format/raddbg_format.c" +#include "raddbg_format/raddbg_format_parse.c" + +int main(int argument_count, char **arguments) +{ + // map raddbg file into address space + HANDLE file = CreateFileA("UnrealEditorFortnite.raddbg", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + DWORD size_hi32 = 0; + DWORD size_lo32 = GetFileSize(file, &size_hi32); + HANDLE map = CreateFileMappingA(file, 0, PAGE_READONLY, 0, 0, 0); + uint64_t data_size = (size_lo32 | ((uint64_t)size_hi32 << 32)); + uint8_t *data = (uint8_t *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, data_size); + + // parse raw data as raddbg + RADDBG_Parsed rdbg = {0}; + RADDBG_ParseStatus parse_status = raddbg_parse(data, data_size, &rdbg); + + // usage example: print out all procedure symbol names +#if 1 + for(uint64_t procedure_idx = 0; procedure_idx < rdbg.procedure_count; procedure_idx += 1) + { + RADDBG_Procedure *procedure = &rdbg.procedures[procedure_idx]; + uint64_t name_size = 0; + uint8_t *name = raddbg_string_from_idx(&rdbg, procedure->name_string_idx, &name_size); + printf("[%I64u] %.*s\n", procedure_idx, (int)name_size, name); + } +#endif + + // usage example: print out all user-defined-type names +#if 0 + for(uint64_t udt_idx = 0; udt_idx < rdbg.udt_count; udt_idx += 1) + { + RADDBG_UDT *udt = &rdbg.udts[udt_idx]; + RADDBG_TypeNode *type = &rdbg.type_nodes[udt->self_type_idx]; + uint64_t name_size = 0; + uint8_t *name = raddbg_string_from_idx(&rdbg, type->user_defined.name_string_idx, &name_size); + printf("[%I64u] %.*s\n", udt_idx, (int)name_size, name); + } +#endif + + // for getting more info, look at the `RADDBG_Parsed` structure. all data is + // represented as a bunch of flat plain-old-data tables. data which must + // reference other data uses indices into that other data's table. for + // example, given a `type_idx`, I will index into `rdbg.type_nodes`. given a + // `udt_idx`, I will index into `rdbg.udts`. given a `scope_idx`, I will + // index into `rdbg.scopes`. and so on. + + return 0; +} diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c new file mode 100644 index 00000000..d789d8fe --- /dev/null +++ b/src/scratch/ryan_scratch.c @@ -0,0 +1,307 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "mdesk/mdesk.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "mdesk/mdesk.c" + +typedef enum MG_StrExprOpKind +{ + MG_StrExprOpKind_Null, + MG_StrExprOpKind_Prefix, + MG_StrExprOpKind_Postfix, + MG_StrExprOpKind_Binary, + MG_StrExprOpKind_COUNT +} +MG_StrExprOpKind; + +typedef enum MG_StrExprOp +{ + MG_StrExprOp_Null, + +#define MG_StrExprOp_FirstString MG_StrExprOp_Dot + MG_StrExprOp_Dot, + MG_StrExprOp_ExpandIfTrue, + MG_StrExprOp_Concat, + MG_StrExprOp_BumpToColumn, +#define MG_StrExprOp_LastString MG_StrExprOp_BumpToColumn + +#define MG_StrExprOp_FirstNumeric MG_StrExprOp_Add + MG_StrExprOp_Add, + MG_StrExprOp_Subtract, + MG_StrExprOp_Multiply, + MG_StrExprOp_Divide, + MG_StrExprOp_Modulo, + MG_StrExprOp_LeftShift, + MG_StrExprOp_RightShift, + MG_StrExprOp_BitwiseAnd, + MG_StrExprOp_BitwiseOr, + MG_StrExprOp_BitwiseXor, + MG_StrExprOp_BitwiseNegate, + MG_StrExprOp_BooleanAnd, + MG_StrExprOp_BooleanOr, + MG_StrExprOp_BooleanNot, + MG_StrExprOp_Equals, + MG_StrExprOp_DoesNotEqual, +#define MG_StrExprOp_LastNumeric MG_StrExprOp_DoesNotEqual + + MG_StrExprOp_COUNT, +} +MG_StrExprOp; + +read_only global String8 mg_str_expr_op_symbol_string_table[MG_StrExprOp_COUNT] = +{ + str8_lit_comp(""), + str8_lit_comp("."), // MG_StrExprOp_Dot + str8_lit_comp("->"), // MG_StrExprOp_ExpandIfTrue + str8_lit_comp(".."), // MG_StrExprOp_Concat + str8_lit_comp("=>"), // MG_StrExprOp_BumpToColumn + str8_lit_comp("+"), // MG_StrExprOp_Add + str8_lit_comp("-"), // MG_StrExprOp_Subtract + str8_lit_comp("*"), // MG_StrExprOp_Multiply + str8_lit_comp("/"), // MG_StrExprOp_Divide + str8_lit_comp("%"), // MG_StrExprOp_Modulo + str8_lit_comp("<<"), // MG_StrExprOp_LeftShift + str8_lit_comp(">>"), // MG_StrExprOp_RightShift + str8_lit_comp("&"), // MG_StrExprOp_BitwiseAnd + str8_lit_comp("|"), // MG_StrExprOp_BitwiseOr + str8_lit_comp("^"), // MG_StrExprOp_BitwiseXor + str8_lit_comp("~"), // MG_StrExprOp_BitwiseNegate + str8_lit_comp("&&"), // MG_StrExprOp_BooleanAnd + str8_lit_comp("||"), // MG_StrExprOp_BooleanOr + str8_lit_comp("!"), // MG_StrExprOp_BooleanNot + str8_lit_comp("=="), // MG_StrExprOp_Equals + str8_lit_comp("!="), // MG_StrExprOp_DoesNotEqual +}; + +read_only global S8 mg_str_expr_op_precedence_table[MG_StrExprOp_COUNT] = +{ + 0, + 20, // MG_StrExprOp_Dot + 1, // MG_StrExprOp_ExpandIfTrue + 2, // MG_StrExprOp_Concat + 12, // MG_StrExprOp_BumpToColumn + 5, // MG_StrExprOp_Add + 5, // MG_StrExprOp_Subtract + 6, // MG_StrExprOp_Multiply + 6, // MG_StrExprOp_Divide + 6, // MG_StrExprOp_Modulo + 7, // MG_StrExprOp_LeftShift + 7, // MG_StrExprOp_RightShift + 8, // MG_StrExprOp_BitwiseAnd + 10, // MG_StrExprOp_BitwiseOr + 9, // MG_StrExprOp_BitwiseXor + 11, // MG_StrExprOp_BitwiseNegate + 3, // MG_StrExprOp_BooleanAnd + 3, // MG_StrExprOp_BooleanOr + 11, // MG_StrExprOp_BooleanNot + 4, // MG_StrExprOp_Equals + 4, // MG_StrExprOp_DoesNotEqual +}; + +read_only global MG_StrExprOpKind mg_str_expr_op_kind_table[MG_StrExprOp_COUNT] = +{ + MG_StrExprOpKind_Null, + MG_StrExprOpKind_Binary, // MG_StrExprOp_Dot + MG_StrExprOpKind_Binary, // MG_StrExprOp_ExpandIfTrue + MG_StrExprOpKind_Binary, // MG_StrExprOp_Concat + MG_StrExprOpKind_Prefix, // MG_StrExprOp_BumpToColumn + MG_StrExprOpKind_Binary, // MG_StrExprOp_Add + MG_StrExprOpKind_Binary, // MG_StrExprOp_Subtract + MG_StrExprOpKind_Binary, // MG_StrExprOp_Multiply + MG_StrExprOpKind_Binary, // MG_StrExprOp_Divide + MG_StrExprOpKind_Binary, // MG_StrExprOp_Modulo + MG_StrExprOpKind_Binary, // MG_StrExprOp_LeftShift + MG_StrExprOpKind_Binary, // MG_StrExprOp_RightShift + MG_StrExprOpKind_Binary, // MG_StrExprOp_BitwiseAnd + MG_StrExprOpKind_Binary, // MG_StrExprOp_BitwiseOr + MG_StrExprOpKind_Binary, // MG_StrExprOp_BitwiseXor + MG_StrExprOpKind_Prefix, // MG_StrExprOp_BitwiseNegate + MG_StrExprOpKind_Binary, // MG_StrExprOp_BooleanAnd + MG_StrExprOpKind_Binary, // MG_StrExprOp_BooleanOr + MG_StrExprOpKind_Prefix, // MG_StrExprOp_BooleanNot + MG_StrExprOpKind_Binary, // MG_StrExprOp_Equals + MG_StrExprOpKind_Binary, // MG_StrExprOp_DoesNotEqual +}; + +typedef struct MG_StrExpr MG_StrExpr; +struct MG_StrExpr +{ + MG_StrExpr *parent; + MG_StrExpr *left; + MG_StrExpr *right; + MG_StrExprOp op; + MD_Node *node; +}; + +typedef struct MG_StrExprParseResult MG_StrExprParseResult; +struct MG_StrExprParseResult +{ + MG_StrExpr *root; + MD_MsgList msgs; + MD_Node *next_node; +}; + +global MG_StrExpr mg_str_expr_nil = {&mg_str_expr_nil, &mg_str_expr_nil, &mg_str_expr_nil}; + +internal MG_StrExpr * +mg_push_str_expr(Arena *arena, MG_StrExprOp op, MD_Node *node) +{ + MG_StrExpr *expr = push_array(arena, MG_StrExpr, 1); + MemoryCopyStruct(expr, &mg_str_expr_nil); + expr->op = op; + expr->node = node; + return expr; +} + +internal MG_StrExprParseResult +mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node *opl, S8 min_prec) +{ + MG_StrExprParseResult parse = {&mg_str_expr_nil}; + { + MD_Node *it = first; + + //- rjf: consume prefix operators + MG_StrExpr *leafmost_op = &mg_str_expr_nil; + for(;it < opl && !md_node_is_nil(it);) + { + MG_StrExprOp found_op = MG_StrExprOp_Null; + for(MG_StrExprOp op = (MG_StrExprOp)(MG_StrExprOp_Null+1); + op < MG_StrExprOp_COUNT; + op = (MG_StrExprOp)(op+1)) + { + if(mg_str_expr_op_kind_table[op] == MG_StrExprOpKind_Prefix && + str8_match(it->string, mg_str_expr_op_symbol_string_table[op], 0) && + mg_str_expr_op_precedence_table[op] >= min_prec) + { + found_op = op; + break; + } + } + if(found_op != MG_StrExprOp_Null) + { + MG_StrExpr *op_expr = mg_push_str_expr(arena, found_op, it); + if(leafmost_op == &mg_str_expr_nil) + { + leafmost_op = op_expr; + } + op_expr->left = parse.root; + parse.root = op_expr; + it = it->next; + } + else + { + break; + } + } + + //- rjf: parse atom + { + MG_StrExpr *atom = &mg_str_expr_nil; + if(it->flags & MD_NodeFlag_Identifier|MD_NodeFlag_Numeric|MD_NodeFlag_StringLiteral && + md_node_is_nil(it->first)) + { + atom = mg_push_str_expr(arena, MG_StrExprOp_Null, it); + it = it->next; + } + else if(!md_node_is_nil(it->first)) + { + MG_StrExprParseResult subparse = mg_str_expr_parse_from_first_opl__min_prec(arena, it->first, &md_nil_node, 0); + atom = subparse.root; + md_msg_list_concat_in_place(&parse.msgs, &subparse.msgs); + it = it->next; + } + if(leafmost_op != &mg_str_expr_nil) + { + leafmost_op->left = atom; + } + else + { + parse.root = atom; + } + } + + //- rjf: parse binary operator extensions at this precedence level + for(;it < opl && !md_node_is_nil(it);) + { + // rjf: find binary op kind of `it` + MG_StrExprOp found_op = MG_StrExprOp_Null; + for(MG_StrExprOp op = (MG_StrExprOp)(MG_StrExprOp_Null+1); + op < MG_StrExprOp_COUNT; + op = (MG_StrExprOp)(op+1)) + { + if(mg_str_expr_op_kind_table[op] == MG_StrExprOpKind_Binary && + str8_match(it->string, mg_str_expr_op_symbol_string_table[op], 0) && + mg_str_expr_op_precedence_table[op] >= min_prec) + { + found_op = op; + break; + } + } + + // rjf: good found_op -> build binary expr + if(found_op != MG_StrExprOp_Null) + { + MG_StrExpr *op_expr = mg_push_str_expr(arena, found_op, it); + if(leafmost_op == &mg_str_expr_nil) + { + leafmost_op = op_expr; + } + op_expr->left = parse.root; + parse.root = op_expr; + it = it->next; + } + else + { + break; + } + + // rjf: parse right hand side of binary operator + MG_StrExprParseResult subparse = mg_str_expr_parse_from_first_opl__min_prec(arena, it, opl, mg_str_expr_op_precedence_table[found_op]+1); + parse.root->right = subparse.root; + md_msg_list_concat_in_place(&parse.msgs, &subparse.msgs); + if(subparse.root == &mg_str_expr_nil) + { + md_msg_list_pushf(arena, &parse.msgs, it, MD_MsgKind_Error, "Missing right-hand-side of '%S'.", mg_str_expr_op_symbol_string_table[found_op]); + } + it = subparse.next_node; + } + + // rjf: store next node for more caller-side parsing + parse.next_node = it; + } + return parse; +} + +internal MG_StrExprParseResult +mg_str_expr_parse_from_first_opl(Arena *arena, MD_Node *first, MD_Node *opl) +{ + MG_StrExprParseResult parse = mg_str_expr_parse_from_first_opl__min_prec(arena, first, opl, 0); + return parse; +} + +internal MG_StrExprParseResult +mg_str_expr_parse_from_root(Arena *arena, MD_Node *root) +{ + MG_StrExprParseResult parse = mg_str_expr_parse_from_first_opl__min_prec(arena, root->first, &md_nil_node, 0); + return parse; +} + +int main(int argument_count, char **arguments) +{ + static TCTX main_thread_tctx = {0}; + tctx_init_and_equip(&main_thread_tctx); + os_init(argument_count, arguments); + + Arena *arena = arena_alloc(); + String8 text = str8_lit("(a.vr == \"x\" -> \"DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_DEF(\" .. a.name_lower .. \");\")"); + MD_TokenizeResult tokenize = md_tokenize_from_text(arena, text); + MD_ParseResult base_parse = md_parse_from_text_tokens(arena, str8_lit(""), text, tokenize.tokens); + MG_StrExprParseResult strexpr_parse = mg_str_expr_parse_from_root(arena, base_parse.root->first); + + return 0; +} diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c new file mode 100644 index 00000000..82c2504b --- /dev/null +++ b/src/text_cache/text_cache.c @@ -0,0 +1,914 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal TXT_LangKind +txt_lang_kind_from_extension(String8 extension) +{ + TXT_LangKind kind = TXT_LangKind_Null; + if(str8_match(extension, str8_lit("c"), 0) || + str8_match(extension, str8_lit("h"), 0)) + { + kind = TXT_LangKind_C; + } + else if(str8_match(extension, str8_lit("cpp"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cxx"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cc"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("c++"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("C"), 0) || + str8_match(extension, str8_lit("hpp"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("hxx"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("hh"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("h++"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("H"), 0)) + { + kind = TXT_LangKind_CPlusPlus; + } + return kind; +} + +//////////////////////////////// +//~ rjf: Token Type Functions + +internal void +txt_token_chunk_list_push(Arena *arena, TXT_TokenChunkList *list, U64 cap, TXT_Token *token) +{ + TXT_TokenChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, TXT_TokenChunkNode, 1); + SLLQueuePush(list->first, list->last, node); + node->cap = cap; + node->v = push_array_no_zero(arena, TXT_Token, node->cap); + list->chunk_count += 1; + } + MemoryCopyStruct(&node->v[node->count], token); + node->count += 1; + list->token_count += 1; +} + +internal void +txt_token_list_push(Arena *arena, TXT_TokenList *list, TXT_Token *token) +{ + TXT_TokenNode *node = push_array(arena, TXT_TokenNode, 1); + MemoryCopyStruct(&node->v, token); + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal TXT_TokenArray +txt_token_array_from_chunk_list(Arena *arena, TXT_TokenChunkList *list) +{ + TXT_TokenArray array = {0}; + array.count = list->token_count; + array.v = push_array_no_zero(arena, TXT_Token, array.count); + U64 idx = 0; + for(TXT_TokenChunkNode *n = list->first; n != 0; n = n->next) + { + MemoryCopy(array.v+idx, n->v, n->count*sizeof(TXT_Token)); + idx += n->count; + } + return array; +} + +internal TXT_TokenArray +txt_token_array_from_list(Arena *arena, TXT_TokenList *list) +{ + TXT_TokenArray array = {0}; + array.count = list->count; + array.v = push_array_no_zero(arena, TXT_Token, array.count); + U64 idx = 0; + for(TXT_TokenNode *n = list->first; n != 0; n = n->next) + { + MemoryCopyStruct(array.v+idx, &n->v); + idx += 1; + } + return array; +} + +//////////////////////////////// +//~ rjf: Lexing Functions + +internal TXT_TokenArray +txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: generate token list + TXT_TokenChunkList tokens = {0}; + { + B32 comment_is_single_line = 0; + B32 string_is_char = 0; + TXT_TokenKind active_token_kind = TXT_TokenKind_Null; + U64 active_token_start_idx = 0; + B32 escaped = 0; + B32 next_escaped = 0; + U64 byte_process_start_idx = 0; + for(U64 idx = 0; idx <= string.size;) + { + U8 byte = (idx+0 < string.size) ? (string.str[idx+0]) : 0; + U8 next_byte = (idx+1 < string.size) ? (string.str[idx+1]) : 0; + + // rjf: update counter + if(bytes_processed_counter != 0 && ((idx-byte_process_start_idx) >= 1000 || idx == string.size)) + { + ins_atomic_u64_add_eval(bytes_processed_counter, (idx-byte_process_start_idx)); + byte_process_start_idx = idx; + } + + // rjf: escaping + if(escaped && (byte != '\r' && byte != '\n')) + { + next_escaped = 0; + } + else if(!escaped && byte == '\\') + { + next_escaped = 1; + } + + // rjf: take starter, determine active token kind + if(active_token_kind == TXT_TokenKind_Null) + { + // rjf: use next bytes to start a new token + if(0){} + else if(char_is_space(byte)) { active_token_kind = TXT_TokenKind_Whitespace; } + else if(byte == '_' || + byte == '$' || + char_is_alpha(byte)) { active_token_kind = TXT_TokenKind_Identifier; } + else if(char_is_digit(byte, 10) || + (byte == '.' && + char_is_digit(next_byte, 10))) { active_token_kind = TXT_TokenKind_Numeric; } + else if(byte == '"') { active_token_kind = TXT_TokenKind_String; string_is_char = 0; } + else if(byte == '\'') { active_token_kind = TXT_TokenKind_String; string_is_char = 1; } + else if(byte == '/' && next_byte == '/') { active_token_kind = TXT_TokenKind_Comment; comment_is_single_line = 1; } + else if(byte == '/' && next_byte == '*') { active_token_kind = TXT_TokenKind_Comment; comment_is_single_line = 0; } + else if(byte == '~' || byte == '!' || + byte == '%' || byte == '^' || + byte == '&' || byte == '*' || + byte == '(' || byte == ')' || + byte == '-' || byte == '=' || + byte == '+' || byte == '[' || + byte == ']' || byte == '{' || + byte == '}' || byte == ':' || + byte == ';' || byte == ',' || + byte == '.' || byte == '<' || + byte == '>' || byte == '/' || + byte == '?' || byte == '|') { active_token_kind = TXT_TokenKind_Symbol; } + else if(byte == '#') { active_token_kind = TXT_TokenKind_Meta; } + + // rjf: start new token + if(active_token_kind != TXT_TokenKind_Null) + { + active_token_start_idx = idx; + } + + // rjf: invalid token kind -> emit error + else + { + TXT_Token token = {TXT_TokenKind_Error, r1u64(idx, idx+1)}; + txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + } + } + + // rjf: look for ender + U64 ender_pad = 0; + B32 ender_found = 0; + if(active_token_kind != TXT_TokenKind_Null && idx>active_token_start_idx) + { + if(idx == string.size) + { + ender_pad = 0; + ender_found = 1; + } + else switch(active_token_kind) + { + default:break; + case TXT_TokenKind_Whitespace: + { + ender_found = !char_is_space(byte); + }break; + case TXT_TokenKind_Identifier: + { + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + }break; + case TXT_TokenKind_Numeric: + { + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '.'); + }break; + case TXT_TokenKind_String: + { + ender_found = (!escaped && ((!string_is_char && byte == '"') || (string_is_char && byte == '\''))); + ender_pad += 1; + }break; + case TXT_TokenKind_Symbol: + { + ender_found = (byte != '~' && byte != '!' && + byte != '%' && byte != '^' && + byte != '&' && byte != '*' && + byte != '(' && byte != ')' && + byte != '-' && byte != '=' && + byte != '+' && byte != '[' && + byte != ']' && byte != '{' && + byte != '}' && byte != ':' && + byte != ';' && byte != ',' && + byte != '.' && byte != '<' && + byte != '>' && byte != '/' && + byte != '?' && byte != '|'); + }break; + case TXT_TokenKind_Comment: + { + if(comment_is_single_line) + { + ender_found = (!escaped && (byte == '\r' || byte == '\n')); + } + else + { + ender_found = (active_token_start_idx+1 < idx && byte == '*' && next_byte == '/'); + ender_pad += 2; + } + }break; + case TXT_TokenKind_Meta: + { + ender_found = (!escaped && (byte == '\r' || byte == '\n')); + }break; + } + } + + // rjf: next byte is ender => emit token + if(ender_found) + { + TXT_Token token = {active_token_kind, r1u64(active_token_start_idx, idx+ender_pad)}; + active_token_kind = TXT_TokenKind_Null; + + // rjf: identifier -> keyword in special cases + if(token.kind == TXT_TokenKind_Identifier) + { + read_only local_persist String8 cpp_keywords[] = + { + str8_lit_comp("alignas"), + str8_lit_comp("alignof"), + str8_lit_comp("and"), + str8_lit_comp("and_eq"), + str8_lit_comp("asm"), + str8_lit_comp("atomic_cancel"), + str8_lit_comp("atomic_commit"), + str8_lit_comp("atomic_noexcept"), + str8_lit_comp("auto"), + str8_lit_comp("bitand"), + str8_lit_comp("bitor"), + str8_lit_comp("bool"), + str8_lit_comp("break"), + str8_lit_comp("case"), + str8_lit_comp("catch"), + str8_lit_comp("char"), + str8_lit_comp("char8_t"), + str8_lit_comp("char16_t"), + str8_lit_comp("char32_t"), + str8_lit_comp("class"), + str8_lit_comp("compl"), + str8_lit_comp("concept"), + str8_lit_comp("const"), + str8_lit_comp("consteval"), + str8_lit_comp("constexpr"), + str8_lit_comp("constinit"), + str8_lit_comp("const_cast"), + str8_lit_comp("continue"), + str8_lit_comp("co_await"), + str8_lit_comp("co_return"), + str8_lit_comp("co_yield"), + str8_lit_comp("decltype"), + str8_lit_comp("default"), + str8_lit_comp("delete"), + str8_lit_comp("do"), + str8_lit_comp("double"), + str8_lit_comp("dynamic_cast"), + str8_lit_comp("else"), + str8_lit_comp("enum"), + str8_lit_comp("explicit"), + str8_lit_comp("export"), + str8_lit_comp("extern"), + str8_lit_comp("false"), + str8_lit_comp("float"), + str8_lit_comp("for"), + str8_lit_comp("friend"), + str8_lit_comp("goto"), + str8_lit_comp("if"), + str8_lit_comp("inline"), + str8_lit_comp("int"), + str8_lit_comp("long"), + str8_lit_comp("mutable"), + str8_lit_comp("namespace"), + str8_lit_comp("new"), + str8_lit_comp("noexcept"), + str8_lit_comp("not"), + str8_lit_comp("not_eq"), + str8_lit_comp("nullptr"), + str8_lit_comp("operator"), + str8_lit_comp("or"), + str8_lit_comp("or_eq"), + str8_lit_comp("private"), + str8_lit_comp("protected"), + str8_lit_comp("public"), + str8_lit_comp("reflexpr"), + str8_lit_comp("register"), + str8_lit_comp("reinterpret_cast"), + str8_lit_comp("requires"), + str8_lit_comp("return"), + str8_lit_comp("short"), + str8_lit_comp("signed"), + str8_lit_comp("sizeof"), + str8_lit_comp("static"), + str8_lit_comp("static_assert"), + str8_lit_comp("static_cast"), + str8_lit_comp("struct"), + str8_lit_comp("switch"), + str8_lit_comp("synchronized"), + str8_lit_comp("template"), + str8_lit_comp("this"), + str8_lit_comp("thread_local"), + str8_lit_comp("throw"), + str8_lit_comp("true"), + str8_lit_comp("try"), + str8_lit_comp("typedef"), + str8_lit_comp("typeid"), + str8_lit_comp("typename"), + str8_lit_comp("union"), + str8_lit_comp("unsigned"), + str8_lit_comp("using"), + str8_lit_comp("virtual"), + str8_lit_comp("void"), + str8_lit_comp("volatile"), + str8_lit_comp("wchar_t"), + str8_lit_comp("while"), + str8_lit_comp("xor"), + str8_lit_comp("xor_eq"), + }; + String8 token_string = str8_substr(string, r1u64(active_token_start_idx, idx+ender_pad)); + for(U64 keyword_idx = 0; keyword_idx < ArrayCount(cpp_keywords); keyword_idx += 1) + { + if(str8_match(cpp_keywords[keyword_idx], token_string, 0)) + { + token.kind = TXT_TokenKind_Keyword; + break; + } + } + } + + // rjf: push + txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + + // rjf: increment by ender padding + idx += ender_pad; + } + + // rjf: advance by 1 byte if we haven't found an ender + if(!ender_found) + { + idx += 1; + } + escaped = next_escaped; + } + } + + //- rjf: token list -> token array + TXT_TokenArray result = txt_token_array_from_chunk_list(arena, &tokens); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +txt_init(void) +{ + Arena *arena = arena_alloc(); + txt_shared = push_array(arena, TXT_Shared, 1); + txt_shared->arena = arena; + txt_shared->slots_count = 1024; + txt_shared->slots = push_array(arena, TXT_Slot, txt_shared->slots_count); + txt_shared->stripes_count = 64; + txt_shared->stripes = push_array(arena, TXT_Stripe, txt_shared->stripes_count); + txt_shared->stripes_free_nodes = push_array(arena, TXT_Node *, txt_shared->stripes_count); + for(U64 idx = 0; idx < txt_shared->stripes_count; idx += 1) + { + txt_shared->stripes[idx].arena = arena_alloc(); + txt_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + txt_shared->stripes[idx].cv = os_condition_variable_alloc(); + } + txt_shared->fallback_slots_count = 256; + txt_shared->fallback_stripes_count = 16; + txt_shared->fallback_slots = push_array(arena, TXT_KeyFallbackSlot, txt_shared->fallback_slots_count); + txt_shared->fallback_stripes = push_array(arena, TXT_Stripe, txt_shared->fallback_stripes_count); + for(U64 idx = 0; idx < txt_shared->fallback_stripes_count; idx += 1) + { + txt_shared->fallback_stripes[idx].arena = arena_alloc(); + txt_shared->fallback_stripes[idx].rw_mutex = os_rw_mutex_alloc(); + txt_shared->fallback_stripes[idx].cv = os_condition_variable_alloc(); + } + txt_shared->u2p_ring_size = KB(64); + txt_shared->u2p_ring_base = push_array_no_zero(arena, U8, txt_shared->u2p_ring_size); + txt_shared->u2p_ring_cv = os_condition_variable_alloc(); + txt_shared->u2p_ring_mutex = os_mutex_alloc(); + txt_shared->parse_thread_count = Min(4, os_logical_core_count()-1); + txt_shared->parse_threads = push_array(arena, OS_Handle, txt_shared->parse_thread_count); + for(U64 idx = 0; idx < txt_shared->parse_thread_count; idx += 1) + { + txt_shared->parse_threads[idx] = os_launch_thread(txt_parse_thread__entry_point, (void *)idx, 0); + } + txt_shared->evictor_thread = os_launch_thread(txt_evictor_thread__entry_point, 0, 0); +} + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void +txt_tctx_ensure_inited(void) +{ + if(txt_tctx == 0) + { + Arena *arena = arena_alloc(); + txt_tctx = push_array(arena, TXT_TCTX, 1); + txt_tctx->arena = arena; + } +} + +//////////////////////////////// +//~ rjf: User Clock + +internal void +txt_user_clock_tick(void) +{ + ins_atomic_u64_inc_eval(&txt_shared->user_clock_idx); +} + +internal U64 +txt_user_clock_idx(void) +{ + return ins_atomic_u64_eval(&txt_shared->user_clock_idx); +} + +//////////////////////////////// +//~ rjf: Scoped Access + +internal TXT_Scope * +txt_scope_open(void) +{ + txt_tctx_ensure_inited(); + TXT_Scope *scope = txt_tctx->free_scope; + if(scope) + { + SLLStackPop(txt_tctx->free_scope); + } + else + { + scope = push_array_no_zero(txt_tctx->arena, TXT_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +txt_scope_close(TXT_Scope *scope) +{ + for(TXT_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) + { + U128 hash = touch->hash; + next = touch->next; + U64 slot_idx = hash.u64[1]%txt_shared->slots_count; + U64 stripe_idx = slot_idx%txt_shared->stripes_count; + TXT_Slot *slot = &txt_shared->slots[slot_idx]; + TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TXT_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_dec_eval(&n->scope_ref_count); + break; + } + } + } + SLLStackPush(txt_tctx->free_touch, touch); + } + SLLStackPush(txt_tctx->free_scope, scope); +} + +internal void +txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node *node) +{ + TXT_Touch *touch = txt_tctx->free_touch; + ins_atomic_u64_inc_eval(&node->scope_ref_count); + ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, txt_user_clock_idx()); + if(touch != 0) + { + SLLStackPop(txt_tctx->free_touch); + } + else + { + touch = push_array_no_zero(txt_tctx->arena, TXT_Touch, 1); + } + MemoryZeroStruct(touch); + touch->hash = node->hash; + SLLStackPush(scope->top_touch, touch); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal TXT_TextInfo +txt_text_info_from_key_hash_lang(TXT_Scope *scope, U128 key, U128 hash, TXT_LangKind lang) +{ + TXT_TextInfo info = {0}; + if(!u128_match(hash, u128_zero())) + { + U64 slot_idx = hash.u64[1]%txt_shared->slots_count; + U64 stripe_idx = slot_idx%txt_shared->stripes_count; + TXT_Slot *slot = &txt_shared->slots[slot_idx]; + TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; + B32 found = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TXT_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && n->lang == lang) + { + MemoryCopyStruct(&info, &n->info); + found = 1; + txt_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + B32 node_is_new = 0; + if(!found) + { + OS_MutexScopeW(stripe->rw_mutex) + { + TXT_Node *node = 0; + for(TXT_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && n->lang == lang) + { + node = n; + break; + } + } + if(node == 0) + { + node = txt_shared->stripes_free_nodes[stripe_idx]; + if(node) + { + SLLStackPop(txt_shared->stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array_no_zero(stripe->arena, TXT_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->hash = hash; + node->lang = lang; + node_is_new = 1; + } + } + } + if(node_is_new) + { + txt_u2p_enqueue_req(key, hash, lang, max_U64); + } + if(!found) + { + U128 fallback_hash = {0}; + TXT_LangKind fallback_lang = TXT_LangKind_Null; + U64 fallback_slot_idx = key.u64[1]%txt_shared->fallback_slots_count; + U64 fallback_stripe_idx = fallback_slot_idx%txt_shared->fallback_stripes_count; + TXT_KeyFallbackSlot *fallback_slot = &txt_shared->fallback_slots[fallback_slot_idx]; + TXT_Stripe *fallback_stripe = &txt_shared->fallback_stripes[fallback_stripe_idx]; + OS_MutexScopeR(fallback_stripe->rw_mutex) for(TXT_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) + { + if(u128_match(key, n->key)) + { + fallback_hash = n->hash; + break; + } + } + if(!u128_match(fallback_hash, u128_zero())) + { + U64 retry_slot_idx = fallback_hash.u64[1]%txt_shared->slots_count; + U64 retry_stripe_idx = retry_slot_idx%txt_shared->stripes_count; + TXT_Slot *retry_slot = &txt_shared->slots[retry_slot_idx]; + TXT_Stripe *retry_stripe = &txt_shared->stripes[retry_stripe_idx]; + OS_MutexScopeR(retry_stripe->rw_mutex) + { + for(TXT_Node *n = retry_slot->first; n != 0; n = n->next) + { + if(u128_match(fallback_hash, n->hash) && fallback_lang == n->lang) + { + MemoryCopyStruct(&info, &n->info); + txt_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + } + } + } + return info; +} + +//////////////////////////////// +//~ rjf: Transfer Threads + +internal B32 +txt_u2p_enqueue_req(U128 key, U128 hash, TXT_LangKind lang, U64 endt_us) +{ + B32 good = 0; + OS_MutexScope(txt_shared->u2p_ring_mutex) for(;;) + { + U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; + U64 available_size = txt_shared->u2p_ring_size - unconsumed_size; + if(available_size >= sizeof(key)+sizeof(hash)) + { + good = 1; + txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &key); + txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &hash); + txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &lang); + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, endt_us); + } + if(good) + { + os_condition_variable_broadcast(txt_shared->u2p_ring_cv); + } + return good; +} + +internal void +txt_u2p_dequeue_req(U128 *key_out, U128 *hash_out, TXT_LangKind *lang_out) +{ + OS_MutexScope(txt_shared->u2p_ring_mutex) for(;;) + { + U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; + if(unconsumed_size >= sizeof(*key_out) + sizeof(*hash_out)) + { + txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, key_out); + txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, hash_out); + txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, lang_out); + break; + } + os_condition_variable_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, max_U64); + } + os_condition_variable_broadcast(txt_shared->u2p_ring_cv); +} + +internal void +txt_parse_thread__entry_point(void *p) +{ + TCTX tctx_ = {0}; + tctx_init_and_equip(&tctx_); + for(;;) + { + HS_Scope *scope = hs_scope_open(); + + //- rjf: get next key + U128 key = {0}; + U128 hash = {0}; + TXT_LangKind lang = TXT_LangKind_Null; + txt_u2p_dequeue_req(&key, &hash, &lang); + + //- rjf: unpack hash + U64 slot_idx = hash.u64[1]%txt_shared->slots_count; + U64 stripe_idx = slot_idx%txt_shared->stripes_count; + TXT_Slot *slot = &txt_shared->slots[slot_idx]; + TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; + + //- rjf: take task + B32 got_task = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TXT_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); + break; + } + } + } + + //- rjf: hash -> data + String8 data = {0}; + if(got_task) + { + data = hs_data_from_hash(scope, hash); + } + + //- rjf: data -> text info + Arena *info_arena = 0; + TXT_TextInfo info = {0}; + if(got_task && data.size != 0) + { + info_arena = arena_alloc(); + + //- rjf: detect line end kind + TXT_LineEndKind line_end_kind = TXT_LineEndKind_Null; + { + U64 lf_count = 0; + U64 cr_count = 0; + for(U64 idx = 0; idx < data.size && idx < 1024; idx += 1) + { + if(data.str[idx] == '\r') + { + cr_count += 1; + } + if(data.str[idx] == '\n') + { + lf_count += 1; + } + } + if(cr_count >= lf_count/2 && lf_count >= 1) + { + line_end_kind = TXT_LineEndKind_CRLF; + } + else if(lf_count >= 1) + { + line_end_kind = TXT_LineEndKind_LF; + } + info.line_end_kind = line_end_kind; + } + + //- rjf: count # of lines + U64 line_count = 1; + U64 byte_process_start_idx = 0; + for(U64 idx = 0; idx < data.size; idx += 1) + { + if(data.str[idx] == '\n' || data.str[idx] == '\r') + { + line_count += 1; + if(data.str[idx] == '\r') + { + idx += 1; + } + } + } + + //- rjf: allocate & store line ranges + info.lines_count = line_count; + info.lines_ranges = push_array_no_zero(info_arena, Rng1U64, info.lines_count); + U64 line_idx = 0; + U64 line_start_idx = 0; + for(U64 idx = 0; idx <= data.size; idx += 1) + { + if(idx == data.size || data.str[idx] == '\n' || data.str[idx] == '\r') + { + Rng1U64 line_range = r1u64(line_start_idx, idx); + U64 line_size = dim_1u64(line_range); + info.lines_ranges[line_idx] = line_range; + info.lines_max_size = Max(info.lines_max_size, line_size); + line_idx += 1; + line_start_idx = idx+1; + if(idx < data.size && data.str[idx] == '\r') + { + line_start_idx += 1; + idx += 1; + } + } + } + + //- rjf: lang -> lex function + TXT_LangLexFunctionType *lex_function = 0; + switch(lang) + { + default:{}break; + case TXT_LangKind_C: + case TXT_LangKind_CPlusPlus: + { + lex_function = txt_token_array_from_string__c_cpp; + }break; + } + + //- rjf: lex function * data -> tokens + TXT_TokenArray tokens = {0}; + if(lex_function != 0) + { + tokens = lex_function(info_arena, 0, data); + } + info.tokens = tokens; + } + + //- rjf: commit results to cache + if(got_task) OS_MutexScopeW(stripe->rw_mutex) + { + for(TXT_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + n->arena = info_arena; + MemoryCopyStruct(&n->info, &info); + ins_atomic_u32_eval_assign(&n->is_working, 0); + ins_atomic_u64_inc_eval(&n->load_count); + break; + } + } + } + + //- rjf: commit this key/hash pair to fallback cache + if(got_task && !u128_match(key, u128_zero()) && !u128_match(hash, u128_zero())) + { + U64 fallback_slot_idx = key.u64[1]%txt_shared->fallback_slots_count; + U64 fallback_stripe_idx = fallback_slot_idx%txt_shared->fallback_stripes_count; + TXT_KeyFallbackSlot *fallback_slot = &txt_shared->fallback_slots[fallback_slot_idx]; + TXT_Stripe *fallback_stripe = &txt_shared->fallback_stripes[fallback_stripe_idx]; + OS_MutexScopeW(fallback_stripe->rw_mutex) + { + TXT_KeyFallbackNode *node = 0; + for(TXT_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(fallback_stripe->arena, TXT_KeyFallbackNode, 1); + SLLQueuePush(fallback_slot->first, fallback_slot->last, node); + } + node->key = key; + node->hash = hash; + } + } + + hs_scope_close(scope); + } +} + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void +txt_evictor_thread__entry_point(void *p) +{ + for(;;) + { + U64 check_time_us = os_now_microseconds(); + U64 check_time_user_clocks = txt_user_clock_idx(); + U64 evict_threshold_us = 10*1000000; + U64 evict_threshold_user_clocks = 10; + for(U64 slot_idx = 0; slot_idx < txt_shared->slots_count; slot_idx += 1) + { + U64 stripe_idx = slot_idx%txt_shared->stripes_count; + TXT_Slot *slot = &txt_shared->slots[slot_idx]; + TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; + B32 slot_has_work = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TXT_Node *n = slot->first; n != 0; n = n->next) + { + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + n->load_count != 0 && + n->is_working == 0) + { + slot_has_work = 1; + break; + } + } + } + if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + { + for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + n->load_count != 0 && + n->is_working == 0) + { + DLLRemove(slot->first, slot->last, n); + if(n->arena != 0) + { + arena_release(n->arena); + } + SLLStackPush(txt_shared->stripes_free_nodes[stripe_idx], n); + } + } + } + os_sleep_milliseconds(5); + } + os_sleep_milliseconds(1000); + } +} diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h new file mode 100644 index 00000000..3bced5bb --- /dev/null +++ b/src/text_cache/text_cache.h @@ -0,0 +1,291 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef TEXT_CACHE_H +#define TEXT_CACHE_H + +//////////////////////////////// +//~ rjf: Value Types + +typedef enum TXT_LineEndKind +{ + TXT_LineEndKind_Null, + TXT_LineEndKind_LF, + TXT_LineEndKind_CRLF, + TXT_LineEndKind_COUNT +} +TXT_LineEndKind; + +typedef enum TXT_TokenKind +{ + TXT_TokenKind_Null, + TXT_TokenKind_Error, + TXT_TokenKind_Whitespace, + TXT_TokenKind_Keyword, + TXT_TokenKind_Identifier, + TXT_TokenKind_Numeric, + TXT_TokenKind_String, + TXT_TokenKind_Symbol, + TXT_TokenKind_Comment, + TXT_TokenKind_Meta, // preprocessor, etc. + TXT_TokenKind_COUNT +} +TXT_TokenKind; + +typedef enum TXT_LangKind +{ + TXT_LangKind_Null, + TXT_LangKind_C, + TXT_LangKind_CPlusPlus, + TXT_LangKind_COUNT +} +TXT_LangKind; + +typedef struct TXT_Token TXT_Token; +struct TXT_Token +{ + TXT_TokenKind kind; + Rng1U64 range; +}; + +typedef struct TXT_TokenChunkNode TXT_TokenChunkNode; +struct TXT_TokenChunkNode +{ + TXT_TokenChunkNode *next; + U64 count; + U64 cap; + TXT_Token *v; +}; + +typedef struct TXT_TokenChunkList TXT_TokenChunkList; +struct TXT_TokenChunkList +{ + TXT_TokenChunkNode *first; + TXT_TokenChunkNode *last; + U64 chunk_count; + U64 token_count; +}; + +typedef struct TXT_TokenNode TXT_TokenNode; +struct TXT_TokenNode +{ + TXT_TokenNode *next; + TXT_Token v; +}; + +typedef struct TXT_TokenList TXT_TokenList; +struct TXT_TokenList +{ + TXT_TokenNode *first; + TXT_TokenNode *last; + U64 count; +}; + +typedef struct TXT_TokenArray TXT_TokenArray; +struct TXT_TokenArray +{ + U64 count; + TXT_Token *v; +}; + +typedef struct TXT_TokenArrayArray TXT_TokenArrayArray; +struct TXT_TokenArrayArray +{ + U64 count; + TXT_TokenArray *v; +}; + +typedef struct TXT_TextInfo TXT_TextInfo; +struct TXT_TextInfo +{ + U64 lines_count; + Rng1U64 *lines_ranges; + U64 lines_max_size; + TXT_LineEndKind line_end_kind; + TXT_TokenArray tokens; +}; + +typedef TXT_TokenArray TXT_LangLexFunctionType(Arena *arena, U64 *bytes_processed_counter, String8 string); + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct TXT_KeyFallbackNode TXT_KeyFallbackNode; +struct TXT_KeyFallbackNode +{ + TXT_KeyFallbackNode *next; + U128 key; + U128 hash; +}; + +typedef struct TXT_KeyFallbackSlot TXT_KeyFallbackSlot; +struct TXT_KeyFallbackSlot +{ + TXT_KeyFallbackNode *first; + TXT_KeyFallbackNode *last; +}; + +typedef struct TXT_Node TXT_Node; +struct TXT_Node +{ + TXT_Node *next; + TXT_Node *prev; + U128 hash; + TXT_LangKind lang; + Arena *arena; + TXT_TextInfo info; + B32 is_working; + U64 scope_ref_count; + U64 last_time_touched_us; + U64 last_user_clock_idx_touched; + U64 load_count; +}; + +typedef struct TXT_Slot TXT_Slot; +struct TXT_Slot +{ + TXT_Node *first; + TXT_Node *last; +}; + +typedef struct TXT_Stripe TXT_Stripe; +struct TXT_Stripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access + +typedef struct TXT_Touch TXT_Touch; +struct TXT_Touch +{ + TXT_Touch *next; + U128 hash; +}; + +typedef struct TXT_Scope TXT_Scope; +struct TXT_Scope +{ + TXT_Scope *next; + TXT_Touch *top_touch; +}; + +//////////////////////////////// +//~ rjf: Thread Context + +typedef struct TXT_TCTX TXT_TCTX; +struct TXT_TCTX +{ + Arena *arena; + TXT_Scope *free_scope; + TXT_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State + +typedef struct TXT_Shared TXT_Shared; +struct TXT_Shared +{ + Arena *arena; + + // rjf: user clock + U64 user_clock_idx; + + // rjf: cache + U64 slots_count; + U64 stripes_count; + TXT_Slot *slots; + TXT_Stripe *stripes; + TXT_Node **stripes_free_nodes; + + // rjf: fallback cache + U64 fallback_slots_count; + U64 fallback_stripes_count; + TXT_KeyFallbackSlot *fallback_slots; + TXT_Stripe *fallback_stripes; + + // rjf: user -> parse thread + U64 u2p_ring_size; + U8 *u2p_ring_base; + U64 u2p_ring_write_pos; + U64 u2p_ring_read_pos; + OS_Handle u2p_ring_cv; + OS_Handle u2p_ring_mutex; + + // rjf: parse threads + U64 parse_thread_count; + OS_Handle *parse_threads; + + // rjf: evictor thread + OS_Handle evictor_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +thread_static TXT_TCTX *txt_tctx = 0; +global TXT_Shared *txt_shared = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal TXT_LangKind txt_lang_kind_from_extension(String8 extension); + +//////////////////////////////// +//~ rjf: Token Type Functions + +internal void txt_token_chunk_list_push(Arena *arena, TXT_TokenChunkList *list, U64 cap, TXT_Token *token); +internal void txt_token_list_push(Arena *arena, TXT_TokenList *list, TXT_Token *token); +internal TXT_TokenArray txt_token_array_from_chunk_list(Arena *arena, TXT_TokenChunkList *list); +internal TXT_TokenArray txt_token_array_from_list(Arena *arena, TXT_TokenList *list); + +//////////////////////////////// +//~ rjf: Lexing Functions + +internal TXT_TokenArray txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, String8 string); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void txt_init(void); + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void txt_tctx_ensure_inited(void); + +//////////////////////////////// +//~ rjf: User Clock + +internal void txt_user_clock_tick(void); +internal U64 txt_user_clock_idx(void); + +//////////////////////////////// +//~ rjf: Scoped Access + +internal TXT_Scope *txt_scope_open(void); +internal void txt_scope_close(TXT_Scope *scope); +internal void txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node *node); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal TXT_TextInfo txt_text_info_from_key_hash_lang(TXT_Scope *scope, U128 key, U128 hash, TXT_LangKind lang); + +//////////////////////////////// +//~ rjf: Transfer Threads + +internal B32 txt_u2p_enqueue_req(U128 key, U128 hash, TXT_LangKind lang, U64 endt_us); +internal void txt_u2p_dequeue_req(U128 *key_out, U128 *hash_out, TXT_LangKind *lang_out); +internal void txt_parse_thread__entry_point(void *p); + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void txt_evictor_thread__entry_point(void *p); + +#endif //TEXT_CACHE_H diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c new file mode 100644 index 00000000..6118d0f1 --- /dev/null +++ b/src/texture_cache/texture_cache.c @@ -0,0 +1,464 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal TEX_Topology +tex_topology_make(Vec2S32 dim, R_Tex2DFormat fmt) +{ + TEX_Topology top = {0}; + top.dim.x = (S16)dim.x; + top.dim.y = (S16)dim.y; + top.fmt = fmt; + return top; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +tex_init(void) +{ + Arena *arena = arena_alloc(); + tex_shared = push_array(arena, TEX_Shared, 1); + tex_shared->arena = arena; + tex_shared->slots_count = 1024; + tex_shared->stripes_count = 64; + tex_shared->slots = push_array(arena, TEX_Slot, tex_shared->slots_count); + tex_shared->stripes = push_array(arena, TEX_Stripe, tex_shared->stripes_count); + tex_shared->stripes_free_nodes = push_array(arena, TEX_Node *, tex_shared->stripes_count); + for(U64 idx = 0; idx < tex_shared->stripes_count; idx += 1) + { + tex_shared->stripes[idx].arena = arena_alloc(); + tex_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + tex_shared->stripes[idx].cv = os_condition_variable_alloc(); + } + tex_shared->fallback_slots_count = 1024; + tex_shared->fallback_stripes_count = 64; + tex_shared->fallback_slots = push_array(arena, TEX_KeyFallbackSlot, tex_shared->fallback_slots_count); + tex_shared->fallback_stripes = push_array(arena, TEX_Stripe, tex_shared->fallback_stripes_count); + for(U64 idx = 0; idx < tex_shared->fallback_stripes_count; idx += 1) + { + tex_shared->fallback_stripes[idx].arena = arena_alloc(); + tex_shared->fallback_stripes[idx].rw_mutex = os_rw_mutex_alloc(); + tex_shared->fallback_stripes[idx].cv = os_condition_variable_alloc(); + } + tex_shared->u2x_ring_size = KB(64); + tex_shared->u2x_ring_base = push_array_no_zero(arena, U8, tex_shared->u2x_ring_size); + tex_shared->u2x_ring_cv = os_condition_variable_alloc(); + tex_shared->u2x_ring_mutex = os_mutex_alloc(); + tex_shared->xfer_thread_count = Min(4, os_logical_core_count()-1); + tex_shared->xfer_threads = push_array(arena, OS_Handle, tex_shared->xfer_thread_count); + for(U64 idx = 0; idx < tex_shared->xfer_thread_count; idx += 1) + { + tex_shared->xfer_threads[idx] = os_launch_thread(tex_xfer_thread__entry_point, (void *)idx, 0); + } + tex_shared->evictor_thread = os_launch_thread(tex_evictor_thread__entry_point, 0, 0); +} + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void +tex_tctx_ensure_inited(void) +{ + if(tex_tctx == 0) + { + Arena *arena = arena_alloc(); + tex_tctx = push_array(arena, TEX_TCTX, 1); + tex_tctx->arena = arena; + } +} + +//////////////////////////////// +//~ rjf: User Clock + +internal void +tex_user_clock_tick(void) +{ + ins_atomic_u64_inc_eval(&tex_shared->user_clock_idx); +} + +internal U64 +tex_user_clock_idx(void) +{ + return ins_atomic_u64_eval(&tex_shared->user_clock_idx); +} + +//////////////////////////////// +//~ rjf: Scoped Access + +internal TEX_Scope * +tex_scope_open(void) +{ + tex_tctx_ensure_inited(); + TEX_Scope *scope = tex_tctx->free_scope; + if(scope) + { + SLLStackPop(tex_tctx->free_scope); + } + else + { + scope = push_array_no_zero(tex_tctx->arena, TEX_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +tex_scope_close(TEX_Scope *scope) +{ + for(TEX_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) + { + U128 hash = touch->hash; + next = touch->next; + U64 slot_idx = hash.u64[1]%tex_shared->slots_count; + U64 stripe_idx = slot_idx%tex_shared->stripes_count; + TEX_Slot *slot = &tex_shared->slots[slot_idx]; + TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TEX_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && MemoryMatchStruct(&touch->topology, &n->topology)) + { + ins_atomic_u64_dec_eval(&n->scope_ref_count); + break; + } + } + } + SLLStackPush(tex_tctx->free_touch, touch); + } + SLLStackPush(tex_tctx->free_scope, scope); +} + +internal void +tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node *node) +{ + TEX_Touch *touch = tex_tctx->free_touch; + ins_atomic_u64_inc_eval(&node->scope_ref_count); + ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, tex_user_clock_idx()); + if(touch != 0) + { + SLLStackPop(tex_tctx->free_touch); + } + else + { + touch = push_array_no_zero(tex_tctx->arena, TEX_Touch, 1); + } + MemoryZeroStruct(touch); + touch->hash = node->hash; + touch->topology = node->topology; + SLLStackPush(scope->top_touch, touch); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal R_Handle +tex_texture_from_key_hash_topology(TEX_Scope *scope, U128 key, U128 hash, TEX_Topology topology) +{ + R_Handle handle = {0}; + if(!u128_match(u128_zero(), hash)) + { + U64 slot_idx = hash.u64[1]%tex_shared->slots_count; + U64 stripe_idx = slot_idx%tex_shared->stripes_count; + TEX_Slot *slot = &tex_shared->slots[slot_idx]; + TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; + B32 found = 0; + B32 stale = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TEX_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) + { + handle = n->texture; + found = !r_handle_match(r_handle_zero(), handle); + tex_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + B32 node_is_new = 0; + if(!found) + { + OS_MutexScopeW(stripe->rw_mutex) + { + TEX_Node *node = 0; + for(TEX_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) + { + node = n; + break; + } + } + if(node == 0) + { + node = tex_shared->stripes_free_nodes[stripe_idx]; + if(node) + { + SLLStackPop(tex_shared->stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array_no_zero(stripe->arena, TEX_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->hash = hash; + MemoryCopyStruct(&node->topology, &topology); + node_is_new = 1; + } + } + } + if(node_is_new) + { + tex_u2x_enqueue_req(key, hash, topology, max_U64); + } + if(r_handle_match(handle, r_handle_zero())) + { + U128 fallback_hash = {0}; + U64 fallback_slot_idx = key.u64[1]%tex_shared->fallback_slots_count; + U64 fallback_stripe_idx = fallback_slot_idx%tex_shared->fallback_stripes_count; + TEX_KeyFallbackSlot *fallback_slot = &tex_shared->fallback_slots[fallback_slot_idx]; + TEX_Stripe *fallback_stripe = &tex_shared->fallback_stripes[fallback_stripe_idx]; + OS_MutexScopeR(fallback_stripe->rw_mutex) for(TEX_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) + { + if(u128_match(key, n->key)) + { + fallback_hash = n->hash; + break; + } + } + if(!u128_match(fallback_hash, u128_zero())) + { + U64 retry_slot_idx = fallback_hash.u64[1]%tex_shared->slots_count; + U64 retry_stripe_idx = retry_slot_idx%tex_shared->stripes_count; + TEX_Slot *retry_slot = &tex_shared->slots[retry_slot_idx]; + TEX_Stripe *retry_stripe = &tex_shared->stripes[retry_stripe_idx]; + OS_MutexScopeR(retry_stripe->rw_mutex) + { + for(TEX_Node *n = retry_slot->first; n != 0; n = n->next) + { + if(u128_match(fallback_hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) + { + handle = n->texture; + tex_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + } + } + } + return handle; +} + +//////////////////////////////// +//~ rjf: Transfer Threads + +internal B32 +tex_u2x_enqueue_req(U128 key, U128 hash, TEX_Topology top, U64 endt_us) +{ + B32 good = 0; + OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) + { + U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; + U64 available_size = tex_shared->u2x_ring_size-unconsumed_size; + if(available_size >= sizeof(key)+sizeof(hash)+sizeof(top)) + { + good = 1; + tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &key); + tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &hash); + tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &top); + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, endt_us); + } + if(good) + { + os_condition_variable_broadcast(tex_shared->u2x_ring_cv); + } + return good; +} + +internal void +tex_u2x_dequeue_req(U128 *key_out, U128 *hash_out, TEX_Topology *top_out) +{ + OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) + { + U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; + if(unconsumed_size >= sizeof(*key_out)+sizeof(*hash_out)+sizeof(*top_out)) + { + tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, key_out); + tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, hash_out); + tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, top_out); + break; + } + os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, max_U64); + } + os_condition_variable_broadcast(tex_shared->u2x_ring_cv); +} + +internal void +tex_xfer_thread__entry_point(void *p) +{ + TCTX tctx_ = {0}; + tctx_init_and_equip(&tctx_); + for(;;) + { + HS_Scope *scope = hs_scope_open(); + + //- rjf: decode + U128 key = {0}; + U128 hash = {0}; + TEX_Topology top = {0}; + tex_u2x_dequeue_req(&key, &hash, &top); + + //- rjf: unpack hash + U64 slot_idx = hash.u64[1]%tex_shared->slots_count; + U64 stripe_idx = slot_idx%tex_shared->stripes_count; + TEX_Slot *slot = &tex_shared->slots[slot_idx]; + TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; + + //- rjf: take task + B32 got_task = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TEX_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) + { + got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); + break; + } + } + } + + //- rjf: hash -> data + String8 data = {0}; + if(got_task) + { + data = hs_data_from_hash(scope, hash); + } + + //- rjf: data * topology -> texture + R_Handle texture = {0}; + if(got_task && top.dim.x != 0 && top.dim.y != 0 && data.size >= (U64)top.dim.x*(U64)top.dim.y*r_tex2d_format_bytes_per_pixel_table[top.fmt]) + { + texture = r_tex2d_alloc(R_Tex2DKind_Static, v2s32(top.dim.x, top.dim.y), top.fmt, data.str); + } + + //- rjf: commit results to cache + if(got_task) OS_MutexScopeW(stripe->rw_mutex) + { + for(TEX_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) + { + n->texture = texture; + ins_atomic_u32_eval_assign(&n->is_working, 0); + ins_atomic_u64_inc_eval(&n->load_count); + break; + } + } + } + + //- rjf: commit this key/hash pair to fallback cache + if(got_task && !u128_match(key, u128_zero()) && !u128_match(hash, u128_zero())) + { + U64 fallback_slot_idx = key.u64[1]%tex_shared->fallback_slots_count; + U64 fallback_stripe_idx = fallback_slot_idx%tex_shared->fallback_stripes_count; + TEX_KeyFallbackSlot *fallback_slot = &tex_shared->fallback_slots[fallback_slot_idx]; + TEX_Stripe *fallback_stripe = &tex_shared->fallback_stripes[fallback_stripe_idx]; + OS_MutexScopeW(fallback_stripe->rw_mutex) + { + TEX_KeyFallbackNode *node = 0; + for(TEX_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(fallback_stripe->arena, TEX_KeyFallbackNode, 1); + SLLQueuePush(fallback_slot->first, fallback_slot->last, node); + } + node->key = key; + node->hash = hash; + } + } + + hs_scope_close(scope); + } +} + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void +tex_evictor_thread__entry_point(void *p) +{ + for(;;) + { + U64 check_time_us = os_now_microseconds(); + U64 check_time_user_clocks = tex_user_clock_idx(); + U64 evict_threshold_us = 10*1000000; + U64 evict_threshold_user_clocks = 10; + for(U64 slot_idx = 0; slot_idx < tex_shared->slots_count; slot_idx += 1) + { + U64 stripe_idx = slot_idx%tex_shared->stripes_count; + TEX_Slot *slot = &tex_shared->slots[slot_idx]; + TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; + B32 slot_has_work = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TEX_Node *n = slot->first; n != 0; n = n->next) + { + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + n->load_count != 0 && + n->is_working == 0) + { + slot_has_work = 1; + break; + } + } + } + if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + { + for(TEX_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + n->load_count != 0 && + n->is_working == 0) + { + DLLRemove(slot->first, slot->last, n); + if(!r_handle_match(n->texture, r_handle_zero())) + { + r_tex2d_release(n->texture); + } + SLLStackPush(tex_shared->stripes_free_nodes[stripe_idx], n); + } + } + } + os_sleep_milliseconds(5); + } + os_sleep_milliseconds(1000); + } +} diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h new file mode 100644 index 00000000..8245ccdd --- /dev/null +++ b/src/texture_cache/texture_cache.h @@ -0,0 +1,185 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef TEXTURE_CACHE_H +#define TEXTURE_CACHE_H + +//////////////////////////////// +//~ rjf: Texture Topology + +typedef struct TEX_Topology TEX_Topology; +struct TEX_Topology +{ + Vec2S16 dim; + R_Tex2DFormat fmt; +}; + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct TEX_KeyFallbackNode TEX_KeyFallbackNode; +struct TEX_KeyFallbackNode +{ + TEX_KeyFallbackNode *next; + U128 key; + U128 hash; +}; + +typedef struct TEX_KeyFallbackSlot TEX_KeyFallbackSlot; +struct TEX_KeyFallbackSlot +{ + TEX_KeyFallbackNode *first; + TEX_KeyFallbackNode *last; +}; + +typedef struct TEX_Node TEX_Node; +struct TEX_Node +{ + TEX_Node *next; + TEX_Node *prev; + U128 hash; + TEX_Topology topology; + R_Handle texture; + B32 is_working; + U64 scope_ref_count; + U64 last_time_touched_us; + U64 last_user_clock_idx_touched; + U64 load_count; +}; + +typedef struct TEX_Slot TEX_Slot; +struct TEX_Slot +{ + TEX_Node *first; + TEX_Node *last; +}; + +typedef struct TEX_Stripe TEX_Stripe; +struct TEX_Stripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access + +typedef struct TEX_Touch TEX_Touch; +struct TEX_Touch +{ + TEX_Touch *next; + U128 hash; + TEX_Topology topology; +}; + +typedef struct TEX_Scope TEX_Scope; +struct TEX_Scope +{ + TEX_Scope *next; + TEX_Touch *top_touch; +}; + +//////////////////////////////// +//~ rjf: Thread Context + +typedef struct TEX_TCTX TEX_TCTX; +struct TEX_TCTX +{ + Arena *arena; + TEX_Scope *free_scope; + TEX_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State + +typedef struct TEX_Shared TEX_Shared; +struct TEX_Shared +{ + Arena *arena; + + // rjf: user clock + U64 user_clock_idx; + + // rjf: cache + U64 slots_count; + U64 stripes_count; + TEX_Slot *slots; + TEX_Stripe *stripes; + TEX_Node **stripes_free_nodes; + + // rjf: fallback cache + U64 fallback_slots_count; + U64 fallback_stripes_count; + TEX_KeyFallbackSlot *fallback_slots; + TEX_Stripe *fallback_stripes; + + // rjf: user -> xfer thread + U64 u2x_ring_size; + U8 *u2x_ring_base; + U64 u2x_ring_write_pos; + U64 u2x_ring_read_pos; + OS_Handle u2x_ring_cv; + OS_Handle u2x_ring_mutex; + + // rjf: transfer threads + U64 xfer_thread_count; + OS_Handle *xfer_threads; + + // rjf: evictor thread + OS_Handle evictor_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +thread_static TEX_TCTX *tex_tctx = 0; +global TEX_Shared *tex_shared = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal TEX_Topology tex_topology_make(Vec2S32 dim, R_Tex2DFormat fmt); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void tex_init(void); + +//////////////////////////////// +//~ rjf: Thread Context Initialization + +internal void tex_tctx_ensure_inited(void); + +//////////////////////////////// +//~ rjf: User Clock + +internal void tex_user_clock_tick(void); +internal U64 tex_user_clock_idx(void); + +//////////////////////////////// +//~ rjf: Scoped Access + +internal TEX_Scope *tex_scope_open(void); +internal void tex_scope_close(TEX_Scope *scope); +internal void tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node *node); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal R_Handle tex_texture_from_key_hash_topology(TEX_Scope *scope, U128 key, U128 hash, TEX_Topology topology); + +//////////////////////////////// +//~ rjf: Transfer Threads + +internal B32 tex_u2x_enqueue_req(U128 key, U128 hash, TEX_Topology top, U64 endt_us); +internal void tex_u2x_dequeue_req(U128 *key_out, U128 *hash_out, TEX_Topology *top_out); +internal void tex_xfer_thread__entry_point(void *p); + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void tex_evictor_thread__entry_point(void *p); + +#endif //TEXTURE_CACHE_H diff --git a/src/third_party/blake2/blake2-config.h b/src/third_party/blake2/blake2-config.h new file mode 100644 index 00000000..a524aa95 --- /dev/null +++ b/src/third_party/blake2/blake2-config.h @@ -0,0 +1,72 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_CONFIG_H +#define BLAKE2_CONFIG_H + +/* These don't work everywhere */ +#if defined(__SSE2__) || defined(__x86_64__) || defined(__amd64__) +#define HAVE_SSE2 +#endif + +#if defined(__SSSE3__) +#define HAVE_SSSE3 +#endif + +#if defined(__SSE4_1__) +#define HAVE_SSE41 +#endif + +#if defined(__AVX__) +#define HAVE_AVX +#endif + +#if defined(__XOP__) +#define HAVE_XOP +#endif + + +#ifdef HAVE_AVX2 +#ifndef HAVE_AVX +#define HAVE_AVX +#endif +#endif + +#ifdef HAVE_XOP +#ifndef HAVE_AVX +#define HAVE_AVX +#endif +#endif + +#ifdef HAVE_AVX +#ifndef HAVE_SSE41 +#define HAVE_SSE41 +#endif +#endif + +#ifdef HAVE_SSE41 +#ifndef HAVE_SSSE3 +#define HAVE_SSSE3 +#endif +#endif + +#ifdef HAVE_SSSE3 +#define HAVE_SSE2 +#endif + +#if !defined(HAVE_SSE2) +#error "This code requires at least SSE2." +#endif + +#endif diff --git a/src/third_party/blake2/blake2-impl.h b/src/third_party/blake2/blake2-impl.h new file mode 100644 index 00000000..c1df82e0 --- /dev/null +++ b/src/third_party/blake2/blake2-impl.h @@ -0,0 +1,160 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_IMPL_H +#define BLAKE2_IMPL_H + +#include +#include + +#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) + #if defined(_MSC_VER) + #define BLAKE2_INLINE __inline + #elif defined(__GNUC__) + #define BLAKE2_INLINE __inline__ + #else + #define BLAKE2_INLINE + #endif +#else + #define BLAKE2_INLINE inline +#endif + +static BLAKE2_INLINE uint32_t load32( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8) | + (( uint32_t )( p[2] ) << 16) | + (( uint32_t )( p[3] ) << 24) ; +#endif +} + +static BLAKE2_INLINE uint64_t load64( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) | + (( uint64_t )( p[6] ) << 48) | + (( uint64_t )( p[7] ) << 56) ; +#endif +} + +static BLAKE2_INLINE uint16_t load16( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint16_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return ( uint16_t )((( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8)); +#endif +} + +static BLAKE2_INLINE void store16( void *dst, uint16_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static BLAKE2_INLINE void store32( void *dst, uint32_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); +#endif +} + +static BLAKE2_INLINE void store64( void *dst, uint64_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); + p[6] = (uint8_t)(w >> 48); + p[7] = (uint8_t)(w >> 56); +#endif +} + +static BLAKE2_INLINE uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) ; +} + +static BLAKE2_INLINE void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); +} + +static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) +{ + static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/src/third_party/blake2/blake2.h b/src/third_party/blake2/blake2.h new file mode 100644 index 00000000..ca390305 --- /dev/null +++ b/src/third_party/blake2/blake2.h @@ -0,0 +1,195 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_H +#define BLAKE2_H + +#include +#include + +#if defined(_MSC_VER) +#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) +#else +#define BLAKE2_PACKED(x) x __attribute__((packed)) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + enum blake2b_constant + { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + + typedef struct blake2s_state__ + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2s_state; + + typedef struct blake2b_state__ + { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2b_state; + + typedef struct blake2sp_state__ + { + blake2s_state S[8][1]; + blake2s_state R[1]; + uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2sp_state; + + typedef struct blake2bp_state__ + { + blake2b_state S[4][1]; + blake2b_state R[1]; + uint8_t buf[4 * BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2bp_state; + + + BLAKE2_PACKED(struct blake2s_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ + }); + + typedef struct blake2s_param__ blake2s_param; + + BLAKE2_PACKED(struct blake2b_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint32_t xof_length; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ + }); + + typedef struct blake2b_param__ blake2b_param; + + typedef struct blake2xs_state__ + { + blake2s_state S[1]; + blake2s_param P[1]; + } blake2xs_state; + + typedef struct blake2xb_state__ + { + blake2b_state S[1]; + blake2b_param P[1]; + } blake2xb_state; + + /* Padded structs result in a compile-time error */ + enum { + BLAKE2_DUMMY_1 = 1/(int)(sizeof(blake2s_param) == BLAKE2S_OUTBYTES), + BLAKE2_DUMMY_2 = 1/(int)(sizeof(blake2b_param) == BLAKE2B_OUTBYTES) + }; + + /* Streaming API */ + int blake2s_init( blake2s_state *S, size_t outlen ); + int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const void *in, size_t inlen ); + int blake2s_final( blake2s_state *S, void *out, size_t outlen ); + + int blake2b_init( blake2b_state *S, size_t outlen ); + int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); + int blake2b_update( blake2b_state *S, const void *in, size_t inlen ); + int blake2b_final( blake2b_state *S, void *out, size_t outlen ); + + int blake2sp_init( blake2sp_state *S, size_t outlen ); + int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen ); + int blake2sp_final( blake2sp_state *S, void *out, size_t outlen ); + + int blake2bp_init( blake2bp_state *S, size_t outlen ); + int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen ); + int blake2bp_final( blake2bp_state *S, void *out, size_t outlen ); + + /* Variable output length API */ + int blake2xs_init( blake2xs_state *S, const size_t outlen ); + int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ); + int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ); + int blake2xs_final(blake2xs_state *S, void *out, size_t outlen); + + int blake2xb_init( blake2xb_state *S, const size_t outlen ); + int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen ); + int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ); + int blake2xb_final(blake2xb_state *S, void *out, size_t outlen); + + /* Simple API */ + int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + /* This is simply an alias for blake2b */ + int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/third_party/blake2/blake2b-load-sse2.h b/src/third_party/blake2/blake2b-load-sse2.h new file mode 100644 index 00000000..23a8d40b --- /dev/null +++ b/src/third_party/blake2/blake2b-load-sse2.h @@ -0,0 +1,68 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2B_LOAD_SSE2_H +#define BLAKE2B_LOAD_SSE2_H + +#define LOAD_MSG_0_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_0_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_0_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_0_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_1_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_1_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_1_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_1_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7) +#define LOAD_MSG_2_1(b0, b1) b0 = _mm_set_epi64x(m12, m11); b1 = _mm_set_epi64x(m15, m5) +#define LOAD_MSG_2_2(b0, b1) b0 = _mm_set_epi64x(m0, m8); b1 = _mm_set_epi64x(m13, m2) +#define LOAD_MSG_2_3(b0, b1) b0 = _mm_set_epi64x(m3, m10); b1 = _mm_set_epi64x(m9, m7) +#define LOAD_MSG_2_4(b0, b1) b0 = _mm_set_epi64x(m6, m14); b1 = _mm_set_epi64x(m4, m1) +#define LOAD_MSG_3_1(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m13) +#define LOAD_MSG_3_2(b0, b1) b0 = _mm_set_epi64x(m1, m9); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_3_3(b0, b1) b0 = _mm_set_epi64x(m5, m2); b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_3_4(b0, b1) b0 = _mm_set_epi64x(m10, m6); b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_4_1(b0, b1) b0 = _mm_set_epi64x(m5, m9); b1 = _mm_set_epi64x(m10, m2) +#define LOAD_MSG_4_2(b0, b1) b0 = _mm_set_epi64x(m7, m0); b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_4_3(b0, b1) b0 = _mm_set_epi64x(m11, m14); b1 = _mm_set_epi64x(m3, m6) +#define LOAD_MSG_4_4(b0, b1) b0 = _mm_set_epi64x(m12, m1); b1 = _mm_set_epi64x(m13, m8) +#define LOAD_MSG_5_1(b0, b1) b0 = _mm_set_epi64x(m6, m2); b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_5_2(b0, b1) b0 = _mm_set_epi64x(m10, m12); b1 = _mm_set_epi64x(m3, m11) +#define LOAD_MSG_5_3(b0, b1) b0 = _mm_set_epi64x(m7, m4); b1 = _mm_set_epi64x(m1, m15) +#define LOAD_MSG_5_4(b0, b1) b0 = _mm_set_epi64x(m5, m13); b1 = _mm_set_epi64x(m9, m14) +#define LOAD_MSG_6_1(b0, b1) b0 = _mm_set_epi64x(m1, m12); b1 = _mm_set_epi64x(m4, m14) +#define LOAD_MSG_6_2(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m10, m13) +#define LOAD_MSG_6_3(b0, b1) b0 = _mm_set_epi64x(m6, m0); b1 = _mm_set_epi64x(m8, m9) +#define LOAD_MSG_6_4(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m2) +#define LOAD_MSG_7_1(b0, b1) b0 = _mm_set_epi64x(m7, m13); b1 = _mm_set_epi64x(m3, m12) +#define LOAD_MSG_7_2(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m9, m1) +#define LOAD_MSG_7_3(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m2, m8) +#define LOAD_MSG_7_4(b0, b1) b0 = _mm_set_epi64x(m4, m0); b1 = _mm_set_epi64x(m10, m6) +#define LOAD_MSG_8_1(b0, b1) b0 = _mm_set_epi64x(m14, m6); b1 = _mm_set_epi64x(m0, m11) +#define LOAD_MSG_8_2(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m8, m3) +#define LOAD_MSG_8_3(b0, b1) b0 = _mm_set_epi64x(m13, m12); b1 = _mm_set_epi64x(m10, m1) +#define LOAD_MSG_8_4(b0, b1) b0 = _mm_set_epi64x(m7, m2); b1 = _mm_set_epi64x(m5, m4) +#define LOAD_MSG_9_1(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m1, m7) +#define LOAD_MSG_9_2(b0, b1) b0 = _mm_set_epi64x(m4, m2); b1 = _mm_set_epi64x(m5, m6) +#define LOAD_MSG_9_3(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m13, m3) +#define LOAD_MSG_9_4(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m0, m12) +#define LOAD_MSG_10_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_10_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_10_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_10_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_11_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_11_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_11_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_11_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7) + + +#endif diff --git a/src/third_party/blake2/blake2b-load-sse41.h b/src/third_party/blake2/blake2b-load-sse41.h new file mode 100644 index 00000000..0eca8659 --- /dev/null +++ b/src/third_party/blake2/blake2b-load-sse41.h @@ -0,0 +1,402 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2B_LOAD_SSE41_H +#define BLAKE2B_LOAD_SSE41_H + +#define LOAD_MSG_0_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m1); \ +b1 = _mm_unpacklo_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_0_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m0, m1); \ +b1 = _mm_unpackhi_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_0_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m5); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_0_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m5); \ +b1 = _mm_unpackhi_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_1_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m2); \ +b1 = _mm_unpackhi_epi64(m4, m6); \ +} while(0) + + +#define LOAD_MSG_1_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_alignr_epi8(m3, m7, 8); \ +} while(0) + + +#define LOAD_MSG_1_3(b0, b1) \ +do \ +{ \ +b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ +b1 = _mm_unpackhi_epi64(m5, m2); \ +} while(0) + + +#define LOAD_MSG_1_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m1); \ +b1 = _mm_unpackhi_epi64(m3, m1); \ +} while(0) + + +#define LOAD_MSG_2_1(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m6, m5, 8); \ +b1 = _mm_unpackhi_epi64(m2, m7); \ +} while(0) + + +#define LOAD_MSG_2_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m0); \ +b1 = _mm_blend_epi16(m1, m6, 0xF0); \ +} while(0) + + +#define LOAD_MSG_2_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m5, m1, 0xF0); \ +b1 = _mm_unpackhi_epi64(m3, m4); \ +} while(0) + + +#define LOAD_MSG_2_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m3); \ +b1 = _mm_alignr_epi8(m2, m0, 8); \ +} while(0) + + +#define LOAD_MSG_3_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m3, m1); \ +b1 = _mm_unpackhi_epi64(m6, m5); \ +} while(0) + + +#define LOAD_MSG_3_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m0); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_3_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m1, m2, 0xF0); \ +b1 = _mm_blend_epi16(m2, m7, 0xF0); \ +} while(0) + + +#define LOAD_MSG_3_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m3, m5); \ +b1 = _mm_unpacklo_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_4_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m2); \ +b1 = _mm_unpacklo_epi64(m1, m5); \ +} while(0) + + +#define LOAD_MSG_4_2(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m0, m3, 0xF0); \ +b1 = _mm_blend_epi16(m2, m7, 0xF0); \ +} while(0) + + +#define LOAD_MSG_4_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m7, m5, 0xF0); \ +b1 = _mm_blend_epi16(m3, m1, 0xF0); \ +} while(0) + + +#define LOAD_MSG_4_4(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m6, m0, 8); \ +b1 = _mm_blend_epi16(m4, m6, 0xF0); \ +} while(0) + + +#define LOAD_MSG_5_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m1, m3); \ +b1 = _mm_unpacklo_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_5_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m5); \ +b1 = _mm_unpackhi_epi64(m5, m1); \ +} while(0) + + +#define LOAD_MSG_5_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m2, m3, 0xF0); \ +b1 = _mm_unpackhi_epi64(m7, m0); \ +} while(0) + + +#define LOAD_MSG_5_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m6, m2); \ +b1 = _mm_blend_epi16(m7, m4, 0xF0); \ +} while(0) + + +#define LOAD_MSG_6_1(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m6, m0, 0xF0); \ +b1 = _mm_unpacklo_epi64(m7, m2); \ +} while(0) + + +#define LOAD_MSG_6_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m2, m7); \ +b1 = _mm_alignr_epi8(m5, m6, 8); \ +} while(0) + + +#define LOAD_MSG_6_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m3); \ +b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1,0,3,2)); \ +} while(0) + + +#define LOAD_MSG_6_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m3, m1); \ +b1 = _mm_blend_epi16(m1, m5, 0xF0); \ +} while(0) + + +#define LOAD_MSG_7_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m6, m3); \ +b1 = _mm_blend_epi16(m6, m1, 0xF0); \ +} while(0) + + +#define LOAD_MSG_7_2(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m7, m5, 8); \ +b1 = _mm_unpackhi_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_7_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m2, m7); \ +b1 = _mm_unpacklo_epi64(m4, m1); \ +} while(0) + + +#define LOAD_MSG_7_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m2); \ +b1 = _mm_unpacklo_epi64(m3, m5); \ +} while(0) + + +#define LOAD_MSG_8_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m3, m7); \ +b1 = _mm_alignr_epi8(m0, m5, 8); \ +} while(0) + + +#define LOAD_MSG_8_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m7, m4); \ +b1 = _mm_alignr_epi8(m4, m1, 8); \ +} while(0) + + +#define LOAD_MSG_8_3(b0, b1) \ +do \ +{ \ +b0 = m6; \ +b1 = _mm_alignr_epi8(m5, m0, 8); \ +} while(0) + + +#define LOAD_MSG_8_4(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m1, m3, 0xF0); \ +b1 = m2; \ +} while(0) + + +#define LOAD_MSG_9_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_unpackhi_epi64(m3, m0); \ +} while(0) + + +#define LOAD_MSG_9_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m1, m2); \ +b1 = _mm_blend_epi16(m3, m2, 0xF0); \ +} while(0) + + +#define LOAD_MSG_9_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m7, m4); \ +b1 = _mm_unpackhi_epi64(m1, m6); \ +} while(0) + + +#define LOAD_MSG_9_4(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m7, m5, 8); \ +b1 = _mm_unpacklo_epi64(m6, m0); \ +} while(0) + + +#define LOAD_MSG_10_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m1); \ +b1 = _mm_unpacklo_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_10_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m0, m1); \ +b1 = _mm_unpackhi_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_10_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m5); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_10_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m5); \ +b1 = _mm_unpackhi_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_11_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m2); \ +b1 = _mm_unpackhi_epi64(m4, m6); \ +} while(0) + + +#define LOAD_MSG_11_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_alignr_epi8(m3, m7, 8); \ +} while(0) + + +#define LOAD_MSG_11_3(b0, b1) \ +do \ +{ \ +b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ +b1 = _mm_unpackhi_epi64(m5, m2); \ +} while(0) + + +#define LOAD_MSG_11_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m1); \ +b1 = _mm_unpackhi_epi64(m3, m1); \ +} while(0) + + +#endif diff --git a/src/third_party/blake2/blake2b-ref.c b/src/third_party/blake2/blake2b-ref.c new file mode 100644 index 00000000..cd38b1ba --- /dev/null +++ b/src/third_party/blake2/blake2b-ref.c @@ -0,0 +1,379 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + + +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2b_init0( blake2b_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2b_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + const uint8_t *p = ( const uint8_t * )( P ); + size_t i; + + blake2b_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; + return 0; +} + + + +int blake2b_init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + uint64_t m[16]; + uint64_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load64( block + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2b_final( blake2b_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + secure_zero_memory(buffer, sizeof(buffer)); + return 0; +} + +/* inlen, at least, should be uint64_t. Others can be size_t. */ +int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2b_init( S, outlen ) < 0 ) return -1; + } + + blake2b_update( S, ( const uint8_t * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; +} + +int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { + return blake2b(out, outlen, in, inlen, key, keylen); +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2B_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2b_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2b_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2b-round.h b/src/third_party/blake2/blake2b-round.h new file mode 100644 index 00000000..6537fff3 --- /dev/null +++ b/src/third_party/blake2/blake2b-round.h @@ -0,0 +1,157 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2B_ROUND_H +#define BLAKE2B_ROUND_H + +#define LOADU(p) _mm_loadu_si128( (const __m128i *)(p) ) +#define STOREU(p,r) _mm_storeu_si128((__m128i *)(p), r) + +#define TOF(reg) _mm_castsi128_ps((reg)) +#define TOI(reg) _mm_castps_si128((reg)) + +#define LIKELY(x) __builtin_expect((x),1) + + +/* Microarchitecture-specific macros */ +#ifndef HAVE_XOP +#ifdef HAVE_SSSE3 +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \ + : (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c)))) +#else +#define _mm_roti_epi64(r, c) _mm_xor_si128(_mm_srli_epi64( (r), -(c) ),_mm_slli_epi64( (r), 64-(-(c)) )) +#endif +#else +/* ... */ +#endif + + + +#define G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -32); \ + row4h = _mm_roti_epi64(row4h, -32); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -24); \ + row2h = _mm_roti_epi64(row2h, -24); \ + +#define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -16); \ + row4h = _mm_roti_epi64(row4h, -16); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -63); \ + row2h = _mm_roti_epi64(row2h, -63); \ + +#if defined(HAVE_SSSE3) +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2h, row2l, 8); \ + t1 = _mm_alignr_epi8(row2l, row2h, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4h, row4l, 8); \ + t1 = _mm_alignr_epi8(row4l, row4h, 8); \ + row4l = t1; \ + row4h = t0; + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2l, row2h, 8); \ + t1 = _mm_alignr_epi8(row2h, row2l, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4l, row4h, 8); \ + t1 = _mm_alignr_epi8(row4h, row4l, 8); \ + row4l = t1; \ + row4h = t0; +#else + +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row4l;\ + t1 = row2l;\ + row4l = row3l;\ + row3l = row3h;\ + row3h = row4l;\ + row4l = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t0, t0)); \ + row4h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row4h, row4h)); \ + row2l = _mm_unpackhi_epi64(row2l, _mm_unpacklo_epi64(row2h, row2h)); \ + row2h = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(t1, t1)) + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row3l;\ + row3l = row3h;\ + row3h = t0;\ + t0 = row2l;\ + t1 = row4l;\ + row2l = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(row2l, row2l)); \ + row2h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row2h, row2h)); \ + row4l = _mm_unpackhi_epi64(row4l, _mm_unpacklo_epi64(row4h, row4h)); \ + row4h = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t1, t1)) + +#endif + +#if defined(HAVE_SSE41) +#include "blake2b-load-sse41.h" +#else +#include "blake2b-load-sse2.h" +#endif + +#define ROUND(r) \ + LOAD_MSG_ ##r ##_1(b0, b1); \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + LOAD_MSG_ ##r ##_2(b0, b1); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + LOAD_MSG_ ##r ##_3(b0, b1); \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + LOAD_MSG_ ##r ##_4(b0, b1); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); + +#endif diff --git a/src/third_party/blake2/blake2b.c b/src/third_party/blake2/blake2b.c new file mode 100644 index 00000000..c8c1c5f1 --- /dev/null +++ b/src/third_party/blake2/blake2b.c @@ -0,0 +1,373 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +#include "blake2-config.h" + +#ifdef _MSC_VER +#include /* for _mm_set_epi64x */ +#endif +#include +#if defined(HAVE_SSSE3) +#include +#endif +#if defined(HAVE_SSE41) +#include +#endif +#if defined(HAVE_AVX) +#include +#endif +#if defined(HAVE_XOP) +#include +#endif + +#include "blake2b-round.h" + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +/* Some helper functions */ +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + size_t i; + /*blake2b_init0( S ); */ + const unsigned char * v = ( const unsigned char * )( blake2b_IV ); + const unsigned char * p = ( const unsigned char * )( P ); + unsigned char * h = ( unsigned char * )( S->h ); + /* IV XOR ParamBlock */ + memset( S, 0, sizeof( blake2b_state ) ); + + for( i = 0; i < BLAKE2B_OUTBYTES; ++i ) h[i] = v[i] ^ p[i]; + + S->outlen = P->digest_length; + return 0; +} + + +/* Some sort of default parameter block initialization, for sequential blake2b */ +int blake2b_init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + return blake2b_init_param( S, P ); +} + +int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( ( !keylen ) || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) + return 0; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + __m128i row1l, row1h; + __m128i row2l, row2h; + __m128i row3l, row3h; + __m128i row4l, row4h; + __m128i b0, b1; + __m128i t0, t1; +#if defined(HAVE_SSSE3) && !defined(HAVE_XOP) + const __m128i r16 = _mm_setr_epi8( 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9 ); + const __m128i r24 = _mm_setr_epi8( 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10 ); +#endif +#if defined(HAVE_SSE41) + const __m128i m0 = LOADU( block + 00 ); + const __m128i m1 = LOADU( block + 16 ); + const __m128i m2 = LOADU( block + 32 ); + const __m128i m3 = LOADU( block + 48 ); + const __m128i m4 = LOADU( block + 64 ); + const __m128i m5 = LOADU( block + 80 ); + const __m128i m6 = LOADU( block + 96 ); + const __m128i m7 = LOADU( block + 112 ); +#else + const uint64_t m0 = load64(block + 0 * sizeof(uint64_t)); + const uint64_t m1 = load64(block + 1 * sizeof(uint64_t)); + const uint64_t m2 = load64(block + 2 * sizeof(uint64_t)); + const uint64_t m3 = load64(block + 3 * sizeof(uint64_t)); + const uint64_t m4 = load64(block + 4 * sizeof(uint64_t)); + const uint64_t m5 = load64(block + 5 * sizeof(uint64_t)); + const uint64_t m6 = load64(block + 6 * sizeof(uint64_t)); + const uint64_t m7 = load64(block + 7 * sizeof(uint64_t)); + const uint64_t m8 = load64(block + 8 * sizeof(uint64_t)); + const uint64_t m9 = load64(block + 9 * sizeof(uint64_t)); + const uint64_t m10 = load64(block + 10 * sizeof(uint64_t)); + const uint64_t m11 = load64(block + 11 * sizeof(uint64_t)); + const uint64_t m12 = load64(block + 12 * sizeof(uint64_t)); + const uint64_t m13 = load64(block + 13 * sizeof(uint64_t)); + const uint64_t m14 = load64(block + 14 * sizeof(uint64_t)); + const uint64_t m15 = load64(block + 15 * sizeof(uint64_t)); +#endif + row1l = LOADU( &S->h[0] ); + row1h = LOADU( &S->h[2] ); + row2l = LOADU( &S->h[4] ); + row2h = LOADU( &S->h[6] ); + row3l = LOADU( &blake2b_IV[0] ); + row3h = LOADU( &blake2b_IV[2] ); + row4l = _mm_xor_si128( LOADU( &blake2b_IV[4] ), LOADU( &S->t[0] ) ); + row4h = _mm_xor_si128( LOADU( &blake2b_IV[6] ), LOADU( &S->f[0] ) ); + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + row1l = _mm_xor_si128( row3l, row1l ); + row1h = _mm_xor_si128( row3h, row1h ); + STOREU( &S->h[0], _mm_xor_si128( LOADU( &S->h[0] ), row1l ) ); + STOREU( &S->h[2], _mm_xor_si128( LOADU( &S->h[2] ), row1h ) ); + row2l = _mm_xor_si128( row4l, row2l ); + row2h = _mm_xor_si128( row4h, row2h ); + STOREU( &S->h[4], _mm_xor_si128( LOADU( &S->h[4] ), row2l ) ); + STOREU( &S->h[6], _mm_xor_si128( LOADU( &S->h[6] ), row2h ) ); +} + + +int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + + +int blake2b_final( blake2b_state *S, void *out, size_t outlen ) +{ + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + memcpy( out, &S->h[0], S->outlen ); + return 0; +} + + +int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + if( keylen ) + { + if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2b_init( S, outlen ) < 0 ) return -1; + } + + blake2b_update( S, ( const uint8_t * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; +} + +int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { + return blake2b(out, outlen, in, inlen, key, keylen); +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2B_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2b_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2b_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2bp-ref.c b/src/third_party/blake2/blake2bp-ref.c new file mode 100644 index 00000000..d58a1529 --- /dev/null +++ b/src/third_party/blake2/blake2bp-ref.c @@ -0,0 +1,359 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include +#include + +#if defined(_OPENMP) +#include +#endif + +#include "blake2.h" +#include "blake2-impl.h" + +#define PARALLELISM_DEGREE 4 + +/* + blake2b_init_param defaults to setting the expecting output length + from the digest_length parameter block field. + + In some cases, however, we do not want this, as the output length + of these instances is given by inner_length instead. +*/ +static int blake2bp_init_leaf_param( blake2b_state *S, const blake2b_param *P ) +{ + int err = blake2b_init_param(S, P); + S->outlen = P->inner_length; + return err; +} + +static int blake2bp_init_leaf( blake2b_state *S, size_t outlen, size_t keylen, uint64_t offset ) +{ + blake2b_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, offset ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = BLAKE2B_OUTBYTES; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2bp_init_leaf_param( S, P ); +} + +static int blake2bp_init_root( blake2b_state *S, size_t outlen, size_t keylen ) +{ + blake2b_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 1; + P->inner_length = BLAKE2B_OUTBYTES; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2bp_init( blake2bp_state *S, size_t outlen ) +{ + size_t i; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2bp_init_root( S->R, outlen, 0 ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2bp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + return 0; +} + +int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen ) +{ + size_t i; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2bp_init_root( S->R, outlen, keylen ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2bp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + + +int blake2bp_update( blake2bp_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + size_t left = S->buflen; + size_t fill = sizeof( S->buf ) - left; + size_t i; + + if( left && inlen >= fill ) + { + memcpy( S->buf + left, in, fill ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); + + in += fill; + inlen -= fill; + left = 0; + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE) +#else + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2B_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ) + { + blake2b_update( S->S[i], in__, BLAKE2B_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + } + } + + in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ); + inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + + if( inlen > 0 ) + memcpy( S->buf + left, in, inlen ); + + S->buflen = left + inlen; + return 0; +} + +int blake2bp_final( blake2bp_state *S, void *out, size_t outlen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES]; + size_t i; + + if(out == NULL || outlen < S->outlen) { + return -1; + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + { + if( S->buflen > i * BLAKE2B_BLOCKBYTES ) + { + size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES; + + if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES; + + blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left ); + } + + blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES ); + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES ); + + return blake2b_final( S->R, out, S->outlen ); +} + +int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES]; + blake2b_state S[PARALLELISM_DEGREE][1]; + blake2b_state FS[1]; + size_t i; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2bp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1; + + S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */ + + if( keylen > 0 ) + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE) +#else + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2B_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ) + { + blake2b_update( S[i], in__, BLAKE2B_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + } + + if( inlen__ > i * BLAKE2B_BLOCKBYTES ) + { + const size_t left = inlen__ - i * BLAKE2B_BLOCKBYTES; + const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES; + blake2b_update( S[i], in__, len ); + } + + blake2b_final( S[i], hash[i], BLAKE2B_OUTBYTES ); + } + + if( blake2bp_init_root( FS, outlen, keylen ) < 0 ) + return -1; + + FS->last_node = 1; /* Mark as last node */ + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES ); + + return blake2b_final( FS, out, outlen );; +} + +#if defined(BLAKE2BP_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2bp( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2bp_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2bp_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2bp_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2bp_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2bp_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2bp.c b/src/third_party/blake2/blake2bp.c new file mode 100644 index 00000000..3eb95d0b --- /dev/null +++ b/src/third_party/blake2/blake2bp.c @@ -0,0 +1,361 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include +#include + +#if defined(_OPENMP) +#include +#endif + +#include "blake2.h" +#include "blake2-impl.h" + +#define PARALLELISM_DEGREE 4 + +/* + blake2b_init_param defaults to setting the expecting output length + from the digest_length parameter block field. + + In some cases, however, we do not want this, as the output length + of these instances is given by inner_length instead. +*/ +static int blake2bp_init_leaf_param( blake2b_state *S, const blake2b_param *P ) +{ + int err = blake2b_init_param(S, P); + S->outlen = P->inner_length; + return err; +} + +static int blake2bp_init_leaf( blake2b_state *S, size_t outlen, size_t keylen, uint64_t offset ) +{ + blake2b_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + P->leaf_length = 0; + P->node_offset = offset; + P->xof_length = 0; + P->node_depth = 0; + P->inner_length = BLAKE2B_OUTBYTES; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2bp_init_leaf_param( S, P ); +} + +static int blake2bp_init_root( blake2b_state *S, size_t outlen, size_t keylen ) +{ + blake2b_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + P->leaf_length = 0; + P->node_offset = 0; + P->xof_length = 0; + P->node_depth = 1; + P->inner_length = BLAKE2B_OUTBYTES; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2bp_init( blake2bp_state *S, size_t outlen ) +{ + size_t i; + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2bp_init_root( S->R, outlen, 0 ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2bp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + return 0; +} + +int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen ) +{ + size_t i; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2bp_init_root( S->R, outlen, keylen ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2bp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + + +int blake2bp_update( blake2bp_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + size_t left = S->buflen; + size_t fill = sizeof( S->buf ) - left; + size_t i; + + if( left && inlen >= fill ) + { + memcpy( S->buf + left, in, fill ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); + + in += fill; + inlen -= fill; + left = 0; + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE) +#else + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2B_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ) + { + blake2b_update( S->S[i], in__, BLAKE2B_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + } + } + + in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ); + inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + + if( inlen > 0 ) + memcpy( S->buf + left, in, inlen ); + + S->buflen = left + inlen; + return 0; +} + + + +int blake2bp_final( blake2bp_state *S, void *out, size_t outlen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES]; + size_t i; + + if(out == NULL || outlen < S->outlen) { + return -1; + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + { + if( S->buflen > i * BLAKE2B_BLOCKBYTES ) + { + size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES; + + if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES; + + blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left ); + } + + blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES ); + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES ); + + return blake2b_final( S->R, out, S->outlen ); +} + +int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES]; + blake2b_state S[PARALLELISM_DEGREE][1]; + blake2b_state FS[1]; + size_t i; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2bp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1; + + S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */ + + if( keylen > 0 ) + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE) +#else + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2B_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES ) + { + blake2b_update( S[i], in__, BLAKE2B_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES; + } + + if( inlen__ > i * BLAKE2B_BLOCKBYTES ) + { + const size_t left = inlen__ - i * BLAKE2B_BLOCKBYTES; + const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES; + blake2b_update( S[i], in__, len ); + } + + blake2b_final( S[i], hash[i], BLAKE2B_OUTBYTES ); + } + + if( blake2bp_init_root( FS, outlen, keylen ) < 0 ) + return -1; + + FS->last_node = 1; /* Mark as last node */ + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES ); + + return blake2b_final( FS, out, outlen ); +} + + +#if defined(BLAKE2BP_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2bp( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2bp_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2bp_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2bp_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2bp_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2bp_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2s-load-sse2.h b/src/third_party/blake2/blake2s-load-sse2.h new file mode 100644 index 00000000..8359e81a --- /dev/null +++ b/src/third_party/blake2/blake2s-load-sse2.h @@ -0,0 +1,60 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2S_LOAD_SSE2_H +#define BLAKE2S_LOAD_SSE2_H + +#define LOAD_MSG_0_1(buf) buf = _mm_set_epi32(m6,m4,m2,m0) +#define LOAD_MSG_0_2(buf) buf = _mm_set_epi32(m7,m5,m3,m1) +#define LOAD_MSG_0_3(buf) buf = _mm_set_epi32(m12,m10,m8,m14) +#define LOAD_MSG_0_4(buf) buf = _mm_set_epi32(m13,m11,m9,m15) +#define LOAD_MSG_1_1(buf) buf = _mm_set_epi32(m13,m9,m4,m14) +#define LOAD_MSG_1_2(buf) buf = _mm_set_epi32(m6,m15,m8,m10) +#define LOAD_MSG_1_3(buf) buf = _mm_set_epi32(m11,m0,m1,m5) +#define LOAD_MSG_1_4(buf) buf = _mm_set_epi32(m7,m2,m12,m3) +#define LOAD_MSG_2_1(buf) buf = _mm_set_epi32(m15,m5,m12,m11) +#define LOAD_MSG_2_2(buf) buf = _mm_set_epi32(m13,m2,m0,m8) +#define LOAD_MSG_2_3(buf) buf = _mm_set_epi32(m7,m3,m10,m9) +#define LOAD_MSG_2_4(buf) buf = _mm_set_epi32(m1,m6,m14,m4) +#define LOAD_MSG_3_1(buf) buf = _mm_set_epi32(m11,m13,m3,m7) +#define LOAD_MSG_3_2(buf) buf = _mm_set_epi32(m14,m12,m1,m9) +#define LOAD_MSG_3_3(buf) buf = _mm_set_epi32(m4,m5,m2,m15) +#define LOAD_MSG_3_4(buf) buf = _mm_set_epi32(m0,m10,m6,m8) +#define LOAD_MSG_4_1(buf) buf = _mm_set_epi32(m10,m2,m5,m9) +#define LOAD_MSG_4_2(buf) buf = _mm_set_epi32(m15,m4,m7,m0) +#define LOAD_MSG_4_3(buf) buf = _mm_set_epi32(m6,m11,m14,m3) +#define LOAD_MSG_4_4(buf) buf = _mm_set_epi32(m8,m12,m1,m13) +#define LOAD_MSG_5_1(buf) buf = _mm_set_epi32(m8,m0,m6,m2) +#define LOAD_MSG_5_2(buf) buf = _mm_set_epi32(m3,m11,m10,m12) +#define LOAD_MSG_5_3(buf) buf = _mm_set_epi32(m15,m7,m4,m1) +#define LOAD_MSG_5_4(buf) buf = _mm_set_epi32(m14,m5,m13,m9) +#define LOAD_MSG_6_1(buf) buf = _mm_set_epi32(m4,m14,m1,m12) +#define LOAD_MSG_6_2(buf) buf = _mm_set_epi32(m10,m13,m15,m5) +#define LOAD_MSG_6_3(buf) buf = _mm_set_epi32(m9,m6,m0,m8) +#define LOAD_MSG_6_4(buf) buf = _mm_set_epi32(m2,m3,m7,m11) +#define LOAD_MSG_7_1(buf) buf = _mm_set_epi32(m3,m12,m7,m13) +#define LOAD_MSG_7_2(buf) buf = _mm_set_epi32(m9,m1,m14,m11) +#define LOAD_MSG_7_3(buf) buf = _mm_set_epi32(m8,m15,m5,m2) +#define LOAD_MSG_7_4(buf) buf = _mm_set_epi32(m6,m4,m0,m10) +#define LOAD_MSG_8_1(buf) buf = _mm_set_epi32(m0,m11,m14,m6) +#define LOAD_MSG_8_2(buf) buf = _mm_set_epi32(m8,m3,m9,m15) +#define LOAD_MSG_8_3(buf) buf = _mm_set_epi32(m1,m13,m12,m10) +#define LOAD_MSG_8_4(buf) buf = _mm_set_epi32(m4,m7,m2,m5) +#define LOAD_MSG_9_1(buf) buf = _mm_set_epi32(m1,m7,m8,m10) +#define LOAD_MSG_9_2(buf) buf = _mm_set_epi32(m5,m6,m4,m2) +#define LOAD_MSG_9_3(buf) buf = _mm_set_epi32(m3,m9,m15,m13) +#define LOAD_MSG_9_4(buf) buf = _mm_set_epi32(m12,m14,m11,m0) + + +#endif diff --git a/src/third_party/blake2/blake2s-load-sse41.h b/src/third_party/blake2/blake2s-load-sse41.h new file mode 100644 index 00000000..8d2b6b12 --- /dev/null +++ b/src/third_party/blake2/blake2s-load-sse41.h @@ -0,0 +1,236 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2S_LOAD_SSE41_H +#define BLAKE2S_LOAD_SSE41_H + +#define LOAD_MSG_0_1(buf) \ +buf = TOI(_mm_shuffle_ps(TOF(m0), TOF(m1), _MM_SHUFFLE(2,0,2,0))); + +#define LOAD_MSG_0_2(buf) \ +buf = TOI(_mm_shuffle_ps(TOF(m0), TOF(m1), _MM_SHUFFLE(3,1,3,1))); + +#define LOAD_MSG_0_3(buf) \ +t0 = _mm_shuffle_epi32(m2, _MM_SHUFFLE(3,2,0,1)); \ +t1 = _mm_shuffle_epi32(m3, _MM_SHUFFLE(0,1,3,2)); \ +buf = _mm_blend_epi16(t0, t1, 0xC3); + +#define LOAD_MSG_0_4(buf) \ +t0 = _mm_blend_epi16(t0, t1, 0x3C); \ +buf = _mm_shuffle_epi32(t0, _MM_SHUFFLE(2,3,0,1)); + +#define LOAD_MSG_1_1(buf) \ +t0 = _mm_blend_epi16(m1, m2, 0x0C); \ +t1 = _mm_slli_si128(m3, 4); \ +t2 = _mm_blend_epi16(t0, t1, 0xF0); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,0,3)); + +#define LOAD_MSG_1_2(buf) \ +t0 = _mm_shuffle_epi32(m2,_MM_SHUFFLE(0,0,2,0)); \ +t1 = _mm_blend_epi16(m1,m3,0xC0); \ +t2 = _mm_blend_epi16(t0, t1, 0xF0); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,3,0,1)); + +#define LOAD_MSG_1_3(buf) \ +t0 = _mm_slli_si128(m1, 4); \ +t1 = _mm_blend_epi16(m2, t0, 0x30); \ +t2 = _mm_blend_epi16(m0, t1, 0xF0); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,0,1,2)); + +#define LOAD_MSG_1_4(buf) \ +t0 = _mm_unpackhi_epi32(m0,m1); \ +t1 = _mm_slli_si128(m3, 4); \ +t2 = _mm_blend_epi16(t0, t1, 0x0C); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,0,1,2)); + +#define LOAD_MSG_2_1(buf) \ +t0 = _mm_unpackhi_epi32(m2,m3); \ +t1 = _mm_blend_epi16(m3,m1,0x0C); \ +t2 = _mm_blend_epi16(t0, t1, 0x0F); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2)); + +#define LOAD_MSG_2_2(buf) \ +t0 = _mm_unpacklo_epi32(m2,m0); \ +t1 = _mm_blend_epi16(t0, m0, 0xF0); \ +t2 = _mm_slli_si128(m3, 8); \ +buf = _mm_blend_epi16(t1, t2, 0xC0); + +#define LOAD_MSG_2_3(buf) \ +t0 = _mm_blend_epi16(m0, m2, 0x3C); \ +t1 = _mm_srli_si128(m1, 12); \ +t2 = _mm_blend_epi16(t0,t1,0x03); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(0,3,2,1)); + +#define LOAD_MSG_2_4(buf) \ +t0 = _mm_slli_si128(m3, 4); \ +t1 = _mm_blend_epi16(m0, m1, 0x33); \ +t2 = _mm_blend_epi16(t1, t0, 0xC0); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,2,3,0)); + +#define LOAD_MSG_3_1(buf) \ +t0 = _mm_unpackhi_epi32(m0,m1); \ +t1 = _mm_unpackhi_epi32(t0, m2); \ +t2 = _mm_blend_epi16(t1, m3, 0x0C); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2)); + +#define LOAD_MSG_3_2(buf) \ +t0 = _mm_slli_si128(m2, 8); \ +t1 = _mm_blend_epi16(m3,m0,0x0C); \ +t2 = _mm_blend_epi16(t1, t0, 0xC0); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,1,3)); + +#define LOAD_MSG_3_3(buf) \ +t0 = _mm_blend_epi16(m0,m1,0x0F); \ +t1 = _mm_blend_epi16(t0, m3, 0xC0); \ +buf = _mm_shuffle_epi32(t1, _MM_SHUFFLE(0,1,2,3)); + +#define LOAD_MSG_3_4(buf) \ +t0 = _mm_alignr_epi8(m0, m1, 4); \ +buf = _mm_blend_epi16(t0, m2, 0x33); + +#define LOAD_MSG_4_1(buf) \ +t0 = _mm_unpacklo_epi64(m1,m2); \ +t1 = _mm_unpackhi_epi64(m0,m2); \ +t2 = _mm_blend_epi16(t0,t1,0x33); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,1,3)); + +#define LOAD_MSG_4_2(buf) \ +t0 = _mm_unpackhi_epi64(m1,m3); \ +t1 = _mm_unpacklo_epi64(m0,m1); \ +buf = _mm_blend_epi16(t0,t1,0x33); + +#define LOAD_MSG_4_3(buf) \ +t0 = _mm_unpackhi_epi64(m3,m1); \ +t1 = _mm_unpackhi_epi64(m2,m0); \ +t2 = _mm_blend_epi16(t1,t0,0x33); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,0,3)); + +#define LOAD_MSG_4_4(buf) \ +t0 = _mm_blend_epi16(m0,m2,0x03); \ +t1 = _mm_slli_si128(t0, 8); \ +t2 = _mm_blend_epi16(t1,m3,0x0F); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,0,3,1)); + +#define LOAD_MSG_5_1(buf) \ +t0 = _mm_unpackhi_epi32(m0,m1); \ +t1 = _mm_unpacklo_epi32(m0,m2); \ +buf = _mm_unpacklo_epi64(t0,t1); + +#define LOAD_MSG_5_2(buf) \ +t0 = _mm_srli_si128(m2, 4); \ +t1 = _mm_blend_epi16(m0,m3,0x03); \ +buf = _mm_blend_epi16(t1,t0,0x3C); + +#define LOAD_MSG_5_3(buf) \ +t0 = _mm_blend_epi16(m1,m0,0x0C); \ +t1 = _mm_srli_si128(m3, 4); \ +t2 = _mm_blend_epi16(t0,t1,0x30); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,3,0,1)); + +#define LOAD_MSG_5_4(buf) \ +t0 = _mm_unpacklo_epi64(m2,m1); \ +t1 = _mm_shuffle_epi32(m3, _MM_SHUFFLE(2,0,1,0)); \ +t2 = _mm_srli_si128(t0, 4); \ +buf = _mm_blend_epi16(t1,t2,0x33); + +#define LOAD_MSG_6_1(buf) \ +t0 = _mm_slli_si128(m1, 12); \ +t1 = _mm_blend_epi16(m0,m3,0x33); \ +buf = _mm_blend_epi16(t1,t0,0xC0); + +#define LOAD_MSG_6_2(buf) \ +t0 = _mm_blend_epi16(m3,m2,0x30); \ +t1 = _mm_srli_si128(m1, 4); \ +t2 = _mm_blend_epi16(t0,t1,0x03); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,3,0)); + +#define LOAD_MSG_6_3(buf) \ +t0 = _mm_unpacklo_epi64(m0,m2); \ +t1 = _mm_srli_si128(m1, 4); \ +t2 = _mm_blend_epi16(t0,t1,0x0C); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3,1,0,2)); + +#define LOAD_MSG_6_4(buf) \ +t0 = _mm_unpackhi_epi32(m1,m2); \ +t1 = _mm_unpackhi_epi64(m0,t0); \ +buf = _mm_shuffle_epi32(t1, _MM_SHUFFLE(0,1,2,3)); + +#define LOAD_MSG_7_1(buf) \ +t0 = _mm_unpackhi_epi32(m0,m1); \ +t1 = _mm_blend_epi16(t0,m3,0x0F); \ +buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(2,0,3,1)); + +#define LOAD_MSG_7_2(buf) \ +t0 = _mm_blend_epi16(m2,m3,0x30); \ +t1 = _mm_srli_si128(m0,4); \ +t2 = _mm_blend_epi16(t0,t1,0x03); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,0,2,3)); + +#define LOAD_MSG_7_3(buf) \ +t0 = _mm_unpackhi_epi64(m0,m3); \ +t1 = _mm_unpacklo_epi64(m1,m2); \ +t2 = _mm_blend_epi16(t0,t1,0x3C); \ +buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(2,3,1,0)); + +#define LOAD_MSG_7_4(buf) \ +t0 = _mm_unpacklo_epi32(m0,m1); \ +t1 = _mm_unpackhi_epi32(m1,m2); \ +t2 = _mm_unpacklo_epi64(t0,t1); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2,1,0,3)); + +#define LOAD_MSG_8_1(buf) \ +t0 = _mm_unpackhi_epi32(m1,m3); \ +t1 = _mm_unpacklo_epi64(t0,m0); \ +t2 = _mm_blend_epi16(t1,m2,0xC0); \ +buf = _mm_shufflehi_epi16(t2,_MM_SHUFFLE(1,0,3,2)); + +#define LOAD_MSG_8_2(buf) \ +t0 = _mm_unpackhi_epi32(m0,m3); \ +t1 = _mm_blend_epi16(m2,t0,0xF0); \ +buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(0,2,1,3)); + +#define LOAD_MSG_8_3(buf) \ +t0 = _mm_unpacklo_epi64(m0,m3); \ +t1 = _mm_srli_si128(m2,8); \ +t2 = _mm_blend_epi16(t0,t1,0x03); \ +buf = _mm_shuffle_epi32(t2, _MM_SHUFFLE(1,3,2,0)); + +#define LOAD_MSG_8_4(buf) \ +t0 = _mm_blend_epi16(m1,m0,0x30); \ +buf = _mm_shuffle_epi32(t0,_MM_SHUFFLE(0,3,2,1)); + +#define LOAD_MSG_9_1(buf) \ +t0 = _mm_blend_epi16(m0,m2,0x03); \ +t1 = _mm_blend_epi16(m1,m2,0x30); \ +t2 = _mm_blend_epi16(t1,t0,0x0F); \ +buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(1,3,0,2)); + +#define LOAD_MSG_9_2(buf) \ +t0 = _mm_slli_si128(m0,4); \ +t1 = _mm_blend_epi16(m1,t0,0xC0); \ +buf = _mm_shuffle_epi32(t1,_MM_SHUFFLE(1,2,0,3)); + +#define LOAD_MSG_9_3(buf) \ +t0 = _mm_unpackhi_epi32(m0,m3); \ +t1 = _mm_unpacklo_epi32(m2,m3); \ +t2 = _mm_unpackhi_epi64(t0,t1); \ +buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(0,2,1,3)); + +#define LOAD_MSG_9_4(buf) \ +t0 = _mm_blend_epi16(m3,m2,0xC0); \ +t1 = _mm_unpacklo_epi32(m0,m3); \ +t2 = _mm_blend_epi16(t0,t1,0x0F); \ +buf = _mm_shuffle_epi32(t2,_MM_SHUFFLE(1,2,3,0)); + +#endif diff --git a/src/third_party/blake2/blake2s-load-xop.h b/src/third_party/blake2/blake2s-load-xop.h new file mode 100644 index 00000000..426edc16 --- /dev/null +++ b/src/third_party/blake2/blake2s-load-xop.h @@ -0,0 +1,191 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2S_LOAD_XOP_H +#define BLAKE2S_LOAD_XOP_H + +#define TOB(x) ((x)*4*0x01010101 + 0x03020100) /* ..or not TOB */ + +#if 0 +/* Basic VPPERM emulation, for testing purposes */ +static __m128i _mm_perm_epi8(const __m128i src1, const __m128i src2, const __m128i sel) +{ + const __m128i sixteen = _mm_set1_epi8(16); + const __m128i t0 = _mm_shuffle_epi8(src1, sel); + const __m128i s1 = _mm_shuffle_epi8(src2, _mm_sub_epi8(sel, sixteen)); + const __m128i mask = _mm_or_si128(_mm_cmpeq_epi8(sel, sixteen), + _mm_cmpgt_epi8(sel, sixteen)); /* (>=16) = 0xff : 00 */ + return _mm_blendv_epi8(t0, s1, mask); +} +#endif + +#define LOAD_MSG_0_1(buf) \ +buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(6),TOB(4),TOB(2),TOB(0)) ); + +#define LOAD_MSG_0_2(buf) \ +buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(7),TOB(5),TOB(3),TOB(1)) ); + +#define LOAD_MSG_0_3(buf) \ +buf = _mm_perm_epi8(m2, m3, _mm_set_epi32(TOB(4),TOB(2),TOB(0),TOB(6)) ); + +#define LOAD_MSG_0_4(buf) \ +buf = _mm_perm_epi8(m2, m3, _mm_set_epi32(TOB(5),TOB(3),TOB(1),TOB(7)) ); + +#define LOAD_MSG_1_1(buf) \ +t0 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(0),TOB(5),TOB(0),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(5),TOB(2),TOB(1),TOB(6)) ); + +#define LOAD_MSG_1_2(buf) \ +t1 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(2),TOB(0),TOB(4),TOB(6)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(7),TOB(1),TOB(0)) ); + +#define LOAD_MSG_1_3(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(5),TOB(0),TOB(0),TOB(1)) ); \ +buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(7),TOB(1),TOB(0),TOB(3)) ); + +#define LOAD_MSG_1_4(buf) \ +t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(3),TOB(7),TOB(2),TOB(0)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(2),TOB(1),TOB(4),TOB(3)) ); + +#define LOAD_MSG_2_1(buf) \ +t0 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(0),TOB(1),TOB(0),TOB(7)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(7),TOB(2),TOB(4),TOB(0)) ); + +#define LOAD_MSG_2_2(buf) \ +t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(2),TOB(0),TOB(4)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(5),TOB(2),TOB(1),TOB(0)) ); + +#define LOAD_MSG_2_3(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(7),TOB(3),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(2),TOB(1),TOB(6),TOB(5)) ); + +#define LOAD_MSG_2_4(buf) \ +t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(4),TOB(1),TOB(6),TOB(0)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(2),TOB(1),TOB(6),TOB(3)) ); + +#define LOAD_MSG_3_1(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(3),TOB(7)) ); \ +t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(7),TOB(2),TOB(1),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(5),TOB(1),TOB(0)) ); + +#define LOAD_MSG_3_2(buf) \ +t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(0),TOB(1),TOB(5)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(6),TOB(4),TOB(1),TOB(0)) ); + +#define LOAD_MSG_3_3(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(4),TOB(5),TOB(2)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(2),TOB(1),TOB(0),TOB(7)) ); + +#define LOAD_MSG_3_4(buf) \ +t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(0),TOB(6)) ); \ +buf = _mm_perm_epi8(t1, m2, _mm_set_epi32(TOB(2),TOB(6),TOB(0),TOB(4)) ); + +#define LOAD_MSG_4_1(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(2),TOB(5),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(6),TOB(2),TOB(1),TOB(5)) ); + +#define LOAD_MSG_4_2(buf) \ +t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(4),TOB(7),TOB(0)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(7),TOB(2),TOB(1),TOB(0)) ); + +#define LOAD_MSG_4_3(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(3),TOB(6),TOB(0),TOB(0)) ); \ +t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(2),TOB(7),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(2),TOB(1),TOB(6),TOB(3)) ); + +#define LOAD_MSG_4_4(buf) \ +t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(4),TOB(0),TOB(1)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(2),TOB(4),TOB(0),TOB(5)) ); + +#define LOAD_MSG_5_1(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(6),TOB(2)) ); \ +buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(4),TOB(2),TOB(1),TOB(0)) ); + +#define LOAD_MSG_5_2(buf) \ +t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(3),TOB(7),TOB(6),TOB(0)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(4)) ); + +#define LOAD_MSG_5_3(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(1),TOB(0),TOB(7),TOB(4)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(7),TOB(1),TOB(0),TOB(3)) ); + +#define LOAD_MSG_5_4(buf) \ +t1 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(5),TOB(0),TOB(1),TOB(0)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(6),TOB(1),TOB(5),TOB(3)) ); + +#define LOAD_MSG_6_1(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(4),TOB(0),TOB(1),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(6),TOB(1),TOB(4)) ); + +#define LOAD_MSG_6_2(buf) \ +t1 = _mm_perm_epi8(m1, m2, _mm_set_epi32(TOB(6),TOB(0),TOB(0),TOB(1)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(5),TOB(7),TOB(0)) ); + +#define LOAD_MSG_6_3(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(6),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(5),TOB(1),TOB(0),TOB(4)) ); + +#define LOAD_MSG_6_4(buf) \ +t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(2),TOB(3),TOB(7)) ); \ +buf = _mm_perm_epi8(t1, m2, _mm_set_epi32(TOB(2),TOB(1),TOB(0),TOB(7)) ); + +#define LOAD_MSG_7_1(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(3),TOB(0),TOB(7),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(4),TOB(1),TOB(5)) ); + +#define LOAD_MSG_7_2(buf) \ +t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(5),TOB(1),TOB(0),TOB(7)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(6),TOB(0)) ); + +#define LOAD_MSG_7_3(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(2),TOB(0),TOB(0),TOB(5)) ); \ +t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(4),TOB(1),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(2),TOB(7),TOB(0),TOB(3)) ); + +#define LOAD_MSG_7_4(buf) \ +t1 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(6),TOB(4),TOB(0)) ); \ +buf = _mm_perm_epi8(t1, m2, _mm_set_epi32(TOB(2),TOB(1),TOB(0),TOB(6)) ); + +#define LOAD_MSG_8_1(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(0),TOB(0),TOB(0),TOB(6)) ); \ +t0 = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(7),TOB(1),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(6),TOB(0)) ); + +#define LOAD_MSG_8_2(buf) \ +t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(4),TOB(3),TOB(5),TOB(0)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(7)) ); + +#define LOAD_MSG_8_3(buf) \ +t0 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(6),TOB(1),TOB(0),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(2),TOB(5),TOB(4),TOB(3)) ); \ + +#define LOAD_MSG_8_4(buf) \ +buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(4),TOB(7),TOB(2),TOB(5)) ); + +#define LOAD_MSG_9_1(buf) \ +t0 = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(1),TOB(7),TOB(0),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m2, _mm_set_epi32(TOB(3),TOB(2),TOB(4),TOB(6)) ); + +#define LOAD_MSG_9_2(buf) \ +buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(5),TOB(6),TOB(4),TOB(2)) ); + +#define LOAD_MSG_9_3(buf) \ +t0 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(3),TOB(5),TOB(0)) ); \ +buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(2),TOB(1),TOB(7),TOB(5)) ); + +#define LOAD_MSG_9_4(buf) \ +t1 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(0),TOB(0),TOB(0),TOB(7)) ); \ +buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(4),TOB(6),TOB(0),TOB(3)) ); + +#endif diff --git a/src/third_party/blake2/blake2s-ref.c b/src/third_party/blake2/blake2s-ref.c new file mode 100644 index 00000000..c8b035f6 --- /dev/null +++ b/src/third_party/blake2/blake2s-ref.c @@ -0,0 +1,367 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = (uint32_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2s_is_lastblock( const blake2s_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2s_init0( blake2s_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2s_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + const unsigned char *p = ( const unsigned char * )( P ); + size_t i; + + blake2s_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load32( &p[i * 4] ); + + S->outlen = P->digest_length; + return 0; +} + + +/* Sequential blake2s initialization */ +int blake2s_init( blake2s_state *S, size_t outlen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + +int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_update( S, block, BLAKE2S_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] ) +{ + uint32_t m[16]; + uint32_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load32( in + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2s_update( blake2s_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2S_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress( S, in ); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2s_final( blake2s_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2s_is_lastblock( S ) ) + return -1; + + blake2s_increment_counter( S, ( uint32_t )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, outlen ); + secure_zero_memory(buffer, sizeof(buffer)); + return 0; +} + +int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2s_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if ( NULL == key && keylen > 0) return -1; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( keylen > BLAKE2S_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2s_init( S, outlen ) < 0 ) return -1; + } + + blake2s_update( S, ( const uint8_t * )in, inlen ); + blake2s_final( S, out, outlen ); + return 0; +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2s( out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2S_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES ); + + if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2s_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2s_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2s-round.h b/src/third_party/blake2/blake2s-round.h new file mode 100644 index 00000000..b75c669c --- /dev/null +++ b/src/third_party/blake2/blake2s-round.h @@ -0,0 +1,88 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2S_ROUND_H +#define BLAKE2S_ROUND_H + +#define LOADU(p) _mm_loadu_si128( (const __m128i *)(p) ) +#define STOREU(p,r) _mm_storeu_si128((__m128i *)(p), r) + +#define TOF(reg) _mm_castsi128_ps((reg)) +#define TOI(reg) _mm_castps_si128((reg)) + +#define LIKELY(x) __builtin_expect((x),1) + + +/* Microarchitecture-specific macros */ +#ifndef HAVE_XOP +#ifdef HAVE_SSSE3 +#define _mm_roti_epi32(r, c) ( \ + (8==-(c)) ? _mm_shuffle_epi8(r,r8) \ + : (16==-(c)) ? _mm_shuffle_epi8(r,r16) \ + : _mm_xor_si128(_mm_srli_epi32( (r), -(c) ),_mm_slli_epi32( (r), 32-(-(c)) )) ) +#else +#define _mm_roti_epi32(r, c) _mm_xor_si128(_mm_srli_epi32( (r), -(c) ),_mm_slli_epi32( (r), 32-(-(c)) )) +#endif +#else +/* ... */ +#endif + + +#define G1(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = _mm_roti_epi32(row4, -16); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = _mm_roti_epi32(row2, -12); + +#define G2(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = _mm_roti_epi32(row4, -8); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = _mm_roti_epi32(row2, -7); + +#define DIAGONALIZE(row1,row2,row3,row4) \ + row1 = _mm_shuffle_epi32( row1, _MM_SHUFFLE(2,1,0,3) ); \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(1,0,3,2) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(0,3,2,1) ); + +#define UNDIAGONALIZE(row1,row2,row3,row4) \ + row1 = _mm_shuffle_epi32( row1, _MM_SHUFFLE(0,3,2,1) ); \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(1,0,3,2) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(2,1,0,3) ); + +#if defined(HAVE_XOP) +#include "blake2s-load-xop.h" +#elif defined(HAVE_SSE41) +#include "blake2s-load-sse41.h" +#else +#include "blake2s-load-sse2.h" +#endif + +#define ROUND(r) \ + LOAD_MSG_ ##r ##_1(buf1); \ + G1(row1,row2,row3,row4,buf1); \ + LOAD_MSG_ ##r ##_2(buf2); \ + G2(row1,row2,row3,row4,buf2); \ + DIAGONALIZE(row1,row2,row3,row4); \ + LOAD_MSG_ ##r ##_3(buf3); \ + G1(row1,row2,row3,row4,buf3); \ + LOAD_MSG_ ##r ##_4(buf4); \ + G2(row1,row2,row3,row4,buf4); \ + UNDIAGONALIZE(row1,row2,row3,row4); \ + +#endif diff --git a/src/third_party/blake2/blake2s.c b/src/third_party/blake2/blake2s.c new file mode 100644 index 00000000..569c210e --- /dev/null +++ b/src/third_party/blake2/blake2s.c @@ -0,0 +1,363 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +#include "blake2-config.h" + + +#include +#if defined(HAVE_SSSE3) +#include +#endif +#if defined(HAVE_SSE41) +#include +#endif +#if defined(HAVE_AVX) +#include +#endif +#if defined(HAVE_XOP) +#include +#endif + +#include "blake2s-round.h" + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +/* Some helper functions */ +static void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = (uint32_t)-1; +} + +static int blake2s_is_lastblock( const blake2s_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + uint64_t t = ( ( uint64_t )S->t[1] << 32 ) | S->t[0]; + t += inc; + S->t[0] = ( uint32_t )( t >> 0 ); + S->t[1] = ( uint32_t )( t >> 32 ); +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + size_t i; + /*blake2s_init0( S ); */ + const uint8_t * v = ( const uint8_t * )( blake2s_IV ); + const uint8_t * p = ( const uint8_t * )( P ); + uint8_t * h = ( uint8_t * )( S->h ); + /* IV XOR ParamBlock */ + memset( S, 0, sizeof( blake2s_state ) ); + + for( i = 0; i < BLAKE2S_OUTBYTES; ++i ) h[i] = v[i] ^ p[i]; + + S->outlen = P->digest_length; + return 0; +} + + +/* Some sort of default parameter block initialization, for sequential blake2s */ +int blake2s_init( blake2s_state *S, size_t outlen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + return blake2s_init_param( S, P ); +} + + +int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( ( !key ) || ( !keylen ) || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) + return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_update( S, block, BLAKE2S_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + + +static void blake2s_compress( blake2s_state *S, const uint8_t block[BLAKE2S_BLOCKBYTES] ) +{ + __m128i row1, row2, row3, row4; + __m128i buf1, buf2, buf3, buf4; +#if defined(HAVE_SSE41) + __m128i t0, t1; +#if !defined(HAVE_XOP) + __m128i t2; +#endif +#endif + __m128i ff0, ff1; +#if defined(HAVE_SSSE3) && !defined(HAVE_XOP) + const __m128i r8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 ); + const __m128i r16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 ); +#endif +#if defined(HAVE_SSE41) + const __m128i m0 = LOADU( block + 00 ); + const __m128i m1 = LOADU( block + 16 ); + const __m128i m2 = LOADU( block + 32 ); + const __m128i m3 = LOADU( block + 48 ); +#else + const uint32_t m0 = load32(block + 0 * sizeof(uint32_t)); + const uint32_t m1 = load32(block + 1 * sizeof(uint32_t)); + const uint32_t m2 = load32(block + 2 * sizeof(uint32_t)); + const uint32_t m3 = load32(block + 3 * sizeof(uint32_t)); + const uint32_t m4 = load32(block + 4 * sizeof(uint32_t)); + const uint32_t m5 = load32(block + 5 * sizeof(uint32_t)); + const uint32_t m6 = load32(block + 6 * sizeof(uint32_t)); + const uint32_t m7 = load32(block + 7 * sizeof(uint32_t)); + const uint32_t m8 = load32(block + 8 * sizeof(uint32_t)); + const uint32_t m9 = load32(block + 9 * sizeof(uint32_t)); + const uint32_t m10 = load32(block + 10 * sizeof(uint32_t)); + const uint32_t m11 = load32(block + 11 * sizeof(uint32_t)); + const uint32_t m12 = load32(block + 12 * sizeof(uint32_t)); + const uint32_t m13 = load32(block + 13 * sizeof(uint32_t)); + const uint32_t m14 = load32(block + 14 * sizeof(uint32_t)); + const uint32_t m15 = load32(block + 15 * sizeof(uint32_t)); +#endif + row1 = ff0 = LOADU( &S->h[0] ); + row2 = ff1 = LOADU( &S->h[4] ); + row3 = _mm_loadu_si128( (__m128i const *)&blake2s_IV[0] ); + row4 = _mm_xor_si128( _mm_loadu_si128( (__m128i const *)&blake2s_IV[4] ), LOADU( &S->t[0] ) ); + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + STOREU( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row1, row3 ) ) ); + STOREU( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row2, row4 ) ) ); +} + +int blake2s_update( blake2s_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2S_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress( S, in ); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2s_final( blake2s_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2s_is_lastblock( S ) ) + return -1; + + blake2s_increment_counter( S, (uint32_t)S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + secure_zero_memory( buffer, sizeof(buffer) ); + return 0; +} + +/* inlen, at least, should be uint64_t. Others can be size_t. */ +int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2s_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if ( NULL == key && keylen > 0) return -1; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( keylen > BLAKE2S_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2s_init( S, outlen ) < 0 ) return -1; + } + + blake2s_update( S, ( const uint8_t * )in, inlen ); + blake2s_final( S, out, outlen ); + return 0; +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2s( out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2S_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES ); + + if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2s_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2s_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2sp-ref.c b/src/third_party/blake2/blake2sp-ref.c new file mode 100644 index 00000000..b0e9baef --- /dev/null +++ b/src/third_party/blake2/blake2sp-ref.c @@ -0,0 +1,359 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#if defined(_OPENMP) +#include +#endif + +#include "blake2.h" +#include "blake2-impl.h" + +#define PARALLELISM_DEGREE 8 + +/* + blake2sp_init_param defaults to setting the expecting output length + from the digest_length parameter block field. + + In some cases, however, we do not want this, as the output length + of these instances is given by inner_length instead. +*/ +static int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P ) +{ + int err = blake2s_init_param(S, P); + S->outlen = P->inner_length; + return err; +} + +static int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint64_t offset ) +{ + blake2s_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, offset ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = BLAKE2S_OUTBYTES; + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2sp_init_leaf_param( S, P ); +} + +static int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen ) +{ + blake2s_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 1; + P->inner_length = BLAKE2S_OUTBYTES; + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + + +int blake2sp_init( blake2sp_state *S, size_t outlen ) +{ + size_t i; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2sp_init_root( S->R, outlen, 0 ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2sp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + return 0; +} + +int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ) +{ + size_t i; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2sp_init_root( S->R, outlen, keylen ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2sp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + + +int blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + size_t left = S->buflen; + size_t fill = sizeof( S->buf ) - left; + size_t i; + + if( left && inlen >= fill ) + { + memcpy( S->buf + left, in, fill ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); + + in += fill; + inlen -= fill; + left = 0; + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE) +#else + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2S_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) + { + blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + } + } + + in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ); + inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + + if( inlen > 0 ) + memcpy( S->buf + left, in, inlen ); + + S->buflen = left + inlen; + return 0; +} + + +int blake2sp_final( blake2sp_state *S, void *out, size_t outlen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; + size_t i; + + if(out == NULL || outlen < S->outlen) { + return -1; + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + { + if( S->buflen > i * BLAKE2S_BLOCKBYTES ) + { + size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES; + + if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES; + + blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left ); + } + + blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES ); + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES ); + + return blake2s_final( S->R, out, S->outlen ); +} + + +int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; + blake2s_state S[PARALLELISM_DEGREE][1]; + blake2s_state FS[1]; + size_t i; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if ( NULL == key && keylen > 0) return -1; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( keylen > BLAKE2S_KEYBYTES ) return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2sp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1; + + S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */ + + if( keylen > 0 ) + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE) +#else + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2S_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) + { + blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + } + + if( inlen__ > i * BLAKE2S_BLOCKBYTES ) + { + const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES; + const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES; + blake2s_update( S[i], in__, len ); + } + + blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES ); + } + + if( blake2sp_init_root( FS, outlen, keylen ) < 0 ) + return -1; + + FS->last_node = 1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES ); + + return blake2s_final( FS, out, outlen ); +} + + + +#if defined(BLAKE2SP_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES ); + + if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2sp_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2sp_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2sp_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2sp.c b/src/third_party/blake2/blake2sp.c new file mode 100644 index 00000000..ed0e1ad2 --- /dev/null +++ b/src/third_party/blake2/blake2sp.c @@ -0,0 +1,358 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#if defined(_OPENMP) +#include +#endif + +#include "blake2.h" +#include "blake2-impl.h" + +#define PARALLELISM_DEGREE 8 + +/* + blake2sp_init_param defaults to setting the expecting output length + from the digest_length parameter block field. + + In some cases, however, we do not want this, as the output length + of these instances is given by inner_length instead. +*/ +static int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P ) +{ + int err = blake2s_init_param(S, P); + S->outlen = P->inner_length; + return err; +} + +static int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint64_t offset ) +{ + blake2s_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + P->leaf_length = 0; + P->node_offset = offset; + P->xof_length = 0; + P->node_depth = 0; + P->inner_length = BLAKE2S_OUTBYTES; + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2sp_init_leaf_param( S, P ); +} + +static int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen ) +{ + blake2s_param P[1]; + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = PARALLELISM_DEGREE; + P->depth = 2; + P->leaf_length = 0; + P->node_offset = 0; + P->xof_length = 0; + P->node_depth = 1; + P->inner_length = BLAKE2S_OUTBYTES; + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + + +int blake2sp_init( blake2sp_state *S, size_t outlen ) +{ + size_t i; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2sp_init_root( S->R, outlen, 0 ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2sp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + return 0; +} + +int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ) +{ + size_t i; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + S->outlen = outlen; + + if( blake2sp_init_root( S->R, outlen, keylen ) < 0 ) + return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2sp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1; + + S->R->last_node = 1; + S->S[PARALLELISM_DEGREE - 1]->last_node = 1; + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + + +int blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + size_t left = S->buflen; + size_t fill = sizeof( S->buf ) - left; + size_t i; + + if( left && inlen >= fill ) + { + memcpy( S->buf + left, in, fill ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); + + in += fill; + inlen -= fill; + left = 0; + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE) +#else + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2S_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) + { + blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + } + } + + in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ); + inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + + if( inlen > 0 ) + memcpy( S->buf + left, in, inlen ); + + S->buflen = left + inlen; + return 0; +} + + +int blake2sp_final( blake2sp_state *S, void *out, size_t outlen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; + size_t i; + + if(out == NULL || outlen < S->outlen) { + return -1; + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + { + if( S->buflen > i * BLAKE2S_BLOCKBYTES ) + { + size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES; + + if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES; + + blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left ); + } + + blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES ); + } + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES ); + + return blake2s_final( S->R, out, S->outlen ); +} + + +int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; + blake2s_state S[PARALLELISM_DEGREE][1]; + blake2s_state FS[1]; + size_t i; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if ( NULL == key && keylen > 0) return -1; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( keylen > BLAKE2S_KEYBYTES ) return -1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + if( blake2sp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1; + + S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */ + + if( keylen > 0 ) + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES ); + + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + +#if defined(_OPENMP) + #pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE) +#else + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) +#endif + { +#if defined(_OPENMP) + size_t i = omp_get_thread_num(); +#endif + size_t inlen__ = inlen; + const unsigned char *in__ = ( const unsigned char * )in; + in__ += i * BLAKE2S_BLOCKBYTES; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) + { + blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + } + + if( inlen__ > i * BLAKE2S_BLOCKBYTES ) + { + const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES; + const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES; + blake2s_update( S[i], in__, len ); + } + + blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES ); + } + + if( blake2sp_init_root( FS, outlen, keylen ) < 0 ) + return -1; + + FS->last_node = 1; + + for( i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES ); + + return blake2s_final( FS, out, outlen ); +} + +#if defined(BLAKE2SP_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES ); + + if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2sp_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2sp_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2sp_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2xb-ref.c b/src/third_party/blake2/blake2xb-ref.c new file mode 100644 index 00000000..b369ee7c --- /dev/null +++ b/src/third_party/blake2/blake2xb-ref.c @@ -0,0 +1,241 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2016, JP Aumasson . + Copyright 2016, Samuel Neves . + + You may use this under the terms of the CC0, the OpenSSL Licence, or + the Apache Public License 2.0, at your option. The terms of these + licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +int blake2xb_init( blake2xb_state *S, const size_t outlen ) { + return blake2xb_init_key(S, outlen, NULL, 0); +} + +int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen) +{ + if ( outlen == 0 || outlen > 0xFFFFFFFFUL ) { + return -1; + } + + if (NULL != key && keylen > BLAKE2B_KEYBYTES) { + return -1; + } + + if (NULL == key && keylen > 0) { + return -1; + } + + /* Initialize parameter block */ + S->P->digest_length = BLAKE2B_OUTBYTES; + S->P->key_length = keylen; + S->P->fanout = 1; + S->P->depth = 1; + store32( &S->P->leaf_length, 0 ); + store32( &S->P->node_offset, 0 ); + store32( &S->P->xof_length, outlen ); + S->P->node_depth = 0; + S->P->inner_length = 0; + memset( S->P->reserved, 0, sizeof( S->P->reserved ) ); + memset( S->P->salt, 0, sizeof( S->P->salt ) ); + memset( S->P->personal, 0, sizeof( S->P->personal ) ); + + if( blake2b_init_param( S->S, S->P ) < 0 ) { + return -1; + } + + if (keylen > 0) { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(S->S, block, BLAKE2B_BLOCKBYTES); + secure_zero_memory(block, BLAKE2B_BLOCKBYTES); + } + return 0; +} + +int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ) { + return blake2b_update( S->S, in, inlen ); +} + +int blake2xb_final( blake2xb_state *S, void *out, size_t outlen) { + + blake2b_state C[1]; + blake2b_param P[1]; + uint32_t xof_length = load32(&S->P->xof_length); + uint8_t root[BLAKE2B_BLOCKBYTES]; + size_t i; + + if (NULL == out) { + return -1; + } + + /* outlen must match the output size defined in xof_length, */ + /* unless it was -1, in which case anything goes except 0. */ + if(xof_length == 0xFFFFFFFFUL) { + if(outlen == 0) { + return -1; + } + } else { + if(outlen != xof_length) { + return -1; + } + } + + /* Finalize the root hash */ + if (blake2b_final(S->S, root, BLAKE2B_OUTBYTES) < 0) { + return -1; + } + + /* Set common block structure values */ + /* Copy values from parent instance, and only change the ones below */ + memcpy(P, S->P, sizeof(blake2b_param)); + P->key_length = 0; + P->fanout = 0; + P->depth = 0; + store32(&P->leaf_length, BLAKE2B_OUTBYTES); + P->inner_length = BLAKE2B_OUTBYTES; + P->node_depth = 0; + + for (i = 0; outlen > 0; ++i) { + const size_t block_size = (outlen < BLAKE2B_OUTBYTES) ? outlen : BLAKE2B_OUTBYTES; + /* Initialize state */ + P->digest_length = block_size; + store32(&P->node_offset, i); + blake2b_init_param(C, P); + /* Process key if needed */ + blake2b_update(C, root, BLAKE2B_OUTBYTES); + if (blake2b_final(C, (uint8_t *)out + i * BLAKE2B_OUTBYTES, block_size) < 0 ) { + return -1; + } + outlen -= block_size; + } + secure_zero_memory(root, sizeof(root)); + secure_zero_memory(P, sizeof(P)); + secure_zero_memory(C, sizeof(C)); + /* Put blake2xb in an invalid state? cf. blake2s_is_lastblock */ + return 0; + +} + +int blake2xb(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen) +{ + blake2xb_state S[1]; + + /* Verify parameters */ + if (NULL == in && inlen > 0) + return -1; + + if (NULL == out) + return -1; + + if (NULL == key && keylen > 0) + return -1; + + if (keylen > BLAKE2B_KEYBYTES) + return -1; + + if (outlen == 0) + return -1; + + /* Initialize the root block structure */ + if (blake2xb_init_key(S, outlen, key, keylen) < 0) { + return -1; + } + + /* Absorb the input message */ + blake2xb_update(S, in, inlen); + + /* Compute the root node of the tree and the final hash using the counter construction */ + return blake2xb_final(S, out, outlen); +} + +#if defined(BLAKE2XB_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step, outlen; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) { + key[i] = ( uint8_t )i; + } + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) { + buf[i] = ( uint8_t )i; + } + + /* Testing length of outputs rather than inputs */ + /* (Test of input lengths mostly covered by blake2b tests) */ + + /* Test simple API */ + for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen ) + { + uint8_t hash[BLAKE2_KAT_LENGTH] = {0}; + if( blake2xb( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2B_KEYBYTES ) < 0 ) { + goto fail; + } + + if( 0 != memcmp( hash, blake2xb_keyed_kat[outlen-1], outlen ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) { + uint8_t hash[BLAKE2_KAT_LENGTH]; + blake2xb_state S; + uint8_t * p = buf; + size_t mlen = BLAKE2_KAT_LENGTH; + int err = 0; + + if( (err = blake2xb_init_key(&S, outlen, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2xb_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2xb_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2xb_final(&S, hash, outlen)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2xb_keyed_kat[outlen-1], outlen)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2xb.c b/src/third_party/blake2/blake2xb.c new file mode 100644 index 00000000..2da56aef --- /dev/null +++ b/src/third_party/blake2/blake2xb.c @@ -0,0 +1,241 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2016, JP Aumasson . + Copyright 2016, Samuel Neves . + + You may use this under the terms of the CC0, the OpenSSL Licence, or + the Apache Public License 2.0, at your option. The terms of these + licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +int blake2xb_init( blake2xb_state *S, const size_t outlen ) { + return blake2xb_init_key(S, outlen, NULL, 0); +} + +int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen) +{ + if ( outlen == 0 || outlen > 0xFFFFFFFFUL ) { + return -1; + } + + if (NULL != key && keylen > BLAKE2B_KEYBYTES) { + return -1; + } + + if (NULL == key && keylen > 0) { + return -1; + } + + /* Initialize parameter block */ + S->P->digest_length = BLAKE2B_OUTBYTES; + S->P->key_length = keylen; + S->P->fanout = 1; + S->P->depth = 1; + store32( &S->P->leaf_length, 0 ); + store32( &S->P->node_offset, 0 ); + store32( &S->P->xof_length, outlen ); + S->P->node_depth = 0; + S->P->inner_length = 0; + memset( S->P->reserved, 0, sizeof( S->P->reserved ) ); + memset( S->P->salt, 0, sizeof( S->P->salt ) ); + memset( S->P->personal, 0, sizeof( S->P->personal ) ); + + if( blake2b_init_param( S->S, S->P ) < 0 ) { + return -1; + } + + if (keylen > 0) { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(S->S, block, BLAKE2B_BLOCKBYTES); + secure_zero_memory(block, BLAKE2B_BLOCKBYTES); + } + return 0; +} + +int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ) { + return blake2b_update( S->S, in, inlen ); +} + +int blake2xb_final( blake2xb_state *S, void *out, size_t outlen) { + + blake2b_state C[1]; + blake2b_param P[1]; + uint32_t xof_length = load32(&S->P->xof_length); + uint8_t root[BLAKE2B_BLOCKBYTES]; + size_t i; + + if (NULL == out) { + return -1; + } + + /* outlen must match the output size defined in xof_length, */ + /* unless it was -1, in which case anything goes except 0. */ + if(xof_length == 0xFFFFFFFFUL) { + if(outlen == 0) { + return -1; + } + } else { + if(outlen != xof_length) { + return -1; + } + } + + /* Finalize the root hash */ + if (blake2b_final(S->S, root, BLAKE2B_OUTBYTES) < 0) { + return -1; + } + + /* Set common block structure values */ + /* Copy values from parent instance, and only change the ones below */ + memcpy(P, S->P, sizeof(blake2b_param)); + P->key_length = 0; + P->fanout = 0; + P->depth = 0; + store32(&P->leaf_length, BLAKE2B_OUTBYTES); + P->inner_length = BLAKE2B_OUTBYTES; + P->node_depth = 0; + + for (i = 0; outlen > 0; ++i) { + const size_t block_size = (outlen < BLAKE2B_OUTBYTES) ? outlen : BLAKE2B_OUTBYTES; + /* Initialize state */ + P->digest_length = block_size; + store32(&P->node_offset, i); + blake2b_init_param(C, P); + /* Process key if needed */ + blake2b_update(C, root, BLAKE2B_OUTBYTES); + if (blake2b_final(C, (uint8_t *)out + i * BLAKE2B_OUTBYTES, block_size) < 0 ) { + return -1; + } + outlen -= block_size; + } + secure_zero_memory(root, sizeof(root)); + secure_zero_memory(P, sizeof(P)); + secure_zero_memory(C, sizeof(C)); + /* Put blake2xb in an invalid state? cf. blake2s_is_lastblock */ + return 0; + +} + +int blake2xb(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen) +{ + blake2xb_state S[1]; + + /* Verify parameters */ + if (NULL == in && inlen > 0) + return -1; + + if (NULL == out) + return -1; + + if (NULL == key && keylen > 0) + return -1; + + if (keylen > BLAKE2B_KEYBYTES) + return -1; + + if (outlen == 0) + return -1; + + /* Initialize the root block structure */ + if (blake2xb_init_key(S, outlen, key, keylen) < 0) { + return -1; + } + + /* Absorb the input message */ + blake2xb_update(S, in, inlen); + + /* Compute the root node of the tree and the final hash using the counter construction */ + return blake2xb_final(S, out, outlen); +} + +#if defined(BLAKE2XB_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step, outlen; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) { + key[i] = ( uint8_t )i; + } + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) { + buf[i] = ( uint8_t )i; + } + + /* Testing length of ouputs rather than inputs */ + /* (Test of input lengths mostly covered by blake2s tests) */ + + /* Test simple API */ + for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen ) + { + uint8_t hash[BLAKE2_KAT_LENGTH] = {0}; + if( blake2xb( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2B_KEYBYTES ) < 0 ) { + goto fail; + } + + if( 0 != memcmp( hash, blake2xb_keyed_kat[outlen-1], outlen ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) { + uint8_t hash[BLAKE2_KAT_LENGTH]; + blake2xb_state S; + uint8_t * p = buf; + size_t mlen = BLAKE2_KAT_LENGTH; + int err = 0; + + if( (err = blake2xb_init_key(&S, outlen, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2xb_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2xb_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2xb_final(&S, hash, outlen)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2xb_keyed_kat[outlen-1], outlen)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2xs-ref.c b/src/third_party/blake2/blake2xs-ref.c new file mode 100644 index 00000000..4261e7ac --- /dev/null +++ b/src/third_party/blake2/blake2xs-ref.c @@ -0,0 +1,239 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2016, JP Aumasson . + Copyright 2016, Samuel Neves . + + You may use this under the terms of the CC0, the OpenSSL Licence, or + the Apache Public License 2.0, at your option. The terms of these + licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +int blake2xs_init( blake2xs_state *S, const size_t outlen ) { + return blake2xs_init_key(S, outlen, NULL, 0); +} + +int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ) +{ + if ( outlen == 0 || outlen > 0xFFFFUL ) { + return -1; + } + + if (NULL != key && keylen > BLAKE2S_KEYBYTES) { + return -1; + } + + if (NULL == key && keylen > 0) { + return -1; + } + + /* Initialize parameter block */ + S->P->digest_length = BLAKE2S_OUTBYTES; + S->P->key_length = keylen; + S->P->fanout = 1; + S->P->depth = 1; + store32( &S->P->leaf_length, 0 ); + store32( &S->P->node_offset, 0 ); + store16( &S->P->xof_length, outlen ); + S->P->node_depth = 0; + S->P->inner_length = 0; + memset( S->P->salt, 0, sizeof( S->P->salt ) ); + memset( S->P->personal, 0, sizeof( S->P->personal ) ); + + if( blake2s_init_param( S->S, S->P ) < 0 ) { + return -1; + } + + if (keylen > 0) { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset(block, 0, BLAKE2S_BLOCKBYTES); + memcpy(block, key, keylen); + blake2s_update(S->S, block, BLAKE2S_BLOCKBYTES); + secure_zero_memory(block, BLAKE2S_BLOCKBYTES); + } + return 0; +} + +int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ) { + return blake2s_update( S->S, in, inlen ); +} + +int blake2xs_final(blake2xs_state *S, void *out, size_t outlen) { + + blake2s_state C[1]; + blake2s_param P[1]; + uint16_t xof_length = load16(&S->P->xof_length); + uint8_t root[BLAKE2S_BLOCKBYTES]; + size_t i; + + if (NULL == out) { + return -1; + } + + /* outlen must match the output size defined in xof_length, */ + /* unless it was -1, in which case anything goes except 0. */ + if(xof_length == 0xFFFFUL) { + if(outlen == 0) { + return -1; + } + } else { + if(outlen != xof_length) { + return -1; + } + } + + /* Finalize the root hash */ + if (blake2s_final(S->S, root, BLAKE2S_OUTBYTES) < 0) { + return -1; + } + + /* Set common block structure values */ + /* Copy values from parent instance, and only change the ones below */ + memcpy(P, S->P, sizeof(blake2s_param)); + P->key_length = 0; + P->fanout = 0; + P->depth = 0; + store32(&P->leaf_length, BLAKE2S_OUTBYTES); + P->inner_length = BLAKE2S_OUTBYTES; + P->node_depth = 0; + + for (i = 0; outlen > 0; ++i) { + const size_t block_size = (outlen < BLAKE2S_OUTBYTES) ? outlen : BLAKE2S_OUTBYTES; + /* Initialize state */ + P->digest_length = block_size; + store32(&P->node_offset, i); + blake2s_init_param(C, P); + /* Process key if needed */ + blake2s_update(C, root, BLAKE2S_OUTBYTES); + if (blake2s_final(C, (uint8_t *)out + i * BLAKE2S_OUTBYTES, block_size) < 0) { + return -1; + } + outlen -= block_size; + } + secure_zero_memory(root, sizeof(root)); + secure_zero_memory(P, sizeof(P)); + secure_zero_memory(C, sizeof(C)); + /* Put blake2xs in an invalid state? cf. blake2s_is_lastblock */ + return 0; +} + +int blake2xs(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen) +{ + blake2xs_state S[1]; + + /* Verify parameters */ + if (NULL == in && inlen > 0) + return -1; + + if (NULL == out) + return -1; + + if (NULL == key && keylen > 0) + return -1; + + if (keylen > BLAKE2S_KEYBYTES) + return -1; + + if (outlen == 0) + return -1; + + /* Initialize the root block structure */ + if (blake2xs_init_key(S, outlen, key, keylen) < 0) { + return -1; + } + + /* Absorb the input message */ + blake2xs_update(S, in, inlen); + + /* Compute the root node of the tree and the final hash using the counter construction */ + return blake2xs_final(S, out, outlen); +} + +#if defined(BLAKE2XS_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step, outlen; + + for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) { + key[i] = ( uint8_t )i; + } + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) { + buf[i] = ( uint8_t )i; + } + + /* Testing length of outputs rather than inputs */ + /* (Test of input lengths mostly covered by blake2s tests) */ + + /* Test simple API */ + for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen ) + { + uint8_t hash[BLAKE2_KAT_LENGTH] = {0}; + if( blake2xs( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2S_KEYBYTES ) < 0 ) { + goto fail; + } + + if( 0 != memcmp( hash, blake2xs_keyed_kat[outlen-1], outlen ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) { + uint8_t hash[BLAKE2_KAT_LENGTH]; + blake2xs_state S; + uint8_t * p = buf; + size_t mlen = BLAKE2_KAT_LENGTH; + int err = 0; + + if( (err = blake2xs_init_key(&S, outlen, key, BLAKE2S_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2xs_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2xs_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2xs_final(&S, hash, outlen)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2xs_keyed_kat[outlen-1], outlen)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/blake2xs.c b/src/third_party/blake2/blake2xs.c new file mode 100644 index 00000000..4b208e27 --- /dev/null +++ b/src/third_party/blake2/blake2xs.c @@ -0,0 +1,239 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2016, JP Aumasson . + Copyright 2016, Samuel Neves . + + You may use this under the terms of the CC0, the OpenSSL Licence, or + the Apache Public License 2.0, at your option. The terms of these + licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +int blake2xs_init( blake2xs_state *S, const size_t outlen ) { + return blake2xs_init_key(S, outlen, NULL, 0); +} + +int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ) +{ + if ( outlen == 0 || outlen > 0xFFFFUL ) { + return -1; + } + + if (NULL != key && keylen > BLAKE2S_KEYBYTES) { + return -1; + } + + if (NULL == key && keylen > 0) { + return -1; + } + + /* Initialize parameter block */ + S->P->digest_length = BLAKE2S_OUTBYTES; + S->P->key_length = keylen; + S->P->fanout = 1; + S->P->depth = 1; + store32( &S->P->leaf_length, 0 ); + store32( &S->P->node_offset, 0 ); + store16( &S->P->xof_length, outlen ); + S->P->node_depth = 0; + S->P->inner_length = 0; + memset( S->P->salt, 0, sizeof( S->P->salt ) ); + memset( S->P->personal, 0, sizeof( S->P->personal ) ); + + if( blake2s_init_param( S->S, S->P ) < 0 ) { + return -1; + } + + if (keylen > 0) { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset(block, 0, BLAKE2S_BLOCKBYTES); + memcpy(block, key, keylen); + blake2s_update(S->S, block, BLAKE2S_BLOCKBYTES); + secure_zero_memory(block, BLAKE2S_BLOCKBYTES); + } + return 0; +} + +int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ) { + return blake2s_update( S->S, in, inlen ); +} + +int blake2xs_final(blake2xs_state *S, void *out, size_t outlen) { + + blake2s_state C[1]; + blake2s_param P[1]; + uint16_t xof_length = load16(&S->P->xof_length); + uint8_t root[BLAKE2S_BLOCKBYTES]; + size_t i; + + if (NULL == out) { + return -1; + } + + /* outlen must match the output size defined in xof_length, */ + /* unless it was -1, in which case anything goes except 0. */ + if(xof_length == 0xFFFFUL) { + if(outlen == 0) { + return -1; + } + } else { + if(outlen != xof_length) { + return -1; + } + } + + /* Finalize the root hash */ + if (blake2s_final(S->S, root, BLAKE2S_OUTBYTES) < 0) { + return -1; + } + + /* Set common block structure values */ + /* Copy values from parent instance, and only change the ones below */ + memcpy(P, S->P, sizeof(blake2s_param)); + P->key_length = 0; + P->fanout = 0; + P->depth = 0; + store32(&P->leaf_length, BLAKE2S_OUTBYTES); + P->inner_length = BLAKE2S_OUTBYTES; + P->node_depth = 0; + + for (i = 0; outlen > 0; ++i) { + const size_t block_size = (outlen < BLAKE2S_OUTBYTES) ? outlen : BLAKE2S_OUTBYTES; + /* Initialize state */ + P->digest_length = block_size; + store32(&P->node_offset, i); + blake2s_init_param(C, P); + /* Process key if needed */ + blake2s_update(C, root, BLAKE2S_OUTBYTES); + if (blake2s_final(C, (uint8_t *)out + i * BLAKE2S_OUTBYTES, block_size) < 0) { + return -1; + } + outlen -= block_size; + } + secure_zero_memory(root, sizeof(root)); + secure_zero_memory(P, sizeof(P)); + secure_zero_memory(C, sizeof(C)); + /* Put blake2xs in an invalid state? cf. blake2s_is_lastblock */ + return 0; +} + +int blake2xs(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen) +{ + blake2xs_state S[1]; + + /* Verify parameters */ + if (NULL == in && inlen > 0) + return -1; + + if (NULL == out) + return -1; + + if (NULL == key && keylen > 0) + return -1; + + if (keylen > BLAKE2S_KEYBYTES) + return -1; + + if (outlen == 0) + return -1; + + /* Initialize the root block structure */ + if (blake2xs_init_key(S, outlen, key, keylen) < 0) { + return -1; + } + + /* Absorb the input message */ + blake2xs_update(S, in, inlen); + + /* Compute the root node of the tree and the final hash using the counter construction */ + return blake2xs_final(S, out, outlen); +} + +#if defined(BLAKE2XS_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step, outlen; + + for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) { + key[i] = ( uint8_t )i; + } + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) { + buf[i] = ( uint8_t )i; + } + + /* Testing length of ouputs rather than inputs */ + /* (Test of input lengths mostly covered by blake2s tests) */ + + /* Test simple API */ + for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen ) + { + uint8_t hash[BLAKE2_KAT_LENGTH] = {0}; + if( blake2xs( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2S_KEYBYTES ) < 0 ) { + goto fail; + } + + if( 0 != memcmp( hash, blake2xs_keyed_kat[outlen-1], outlen ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) { + uint8_t hash[BLAKE2_KAT_LENGTH]; + blake2xs_state S; + uint8_t * p = buf; + size_t mlen = BLAKE2_KAT_LENGTH; + int err = 0; + + if( (err = blake2xs_init_key(&S, outlen, key, BLAKE2S_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2xs_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2xs_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2xs_final(&S, hash, outlen)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2xs_keyed_kat[outlen-1], outlen)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/third_party/blake2/genkat-c.c b/src/third_party/blake2/genkat-c.c new file mode 100644 index 00000000..58a48fda --- /dev/null +++ b/src/third_party/blake2/genkat-c.c @@ -0,0 +1,139 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include +#include + +#include "blake2.h" + +#define STR_(x) #x +#define STR(x) STR_(x) + +#define LENGTH 256 + +#define MAKE_KAT(name, size_prefix) \ + do { \ + printf("static const uint8_t " #name "_kat[BLAKE2_KAT_LENGTH][" #size_prefix \ + "_OUTBYTES] = \n{\n"); \ + \ + for (i = 0; i < LENGTH; ++i) { \ + name(hash, size_prefix##_OUTBYTES, in, i, NULL, 0); \ + printf("\t{\n\t\t"); \ + \ + for (j = 0; j < size_prefix##_OUTBYTES; ++j) \ + printf("0x%02X%s", hash[j], \ + (j + 1) == size_prefix##_OUTBYTES ? "\n" : j && !((j + 1) % 8) ? ",\n\t\t" : ", "); \ + \ + printf("\t},\n"); \ + } \ + \ + printf("};\n\n\n\n\n"); \ + } while (0) + +#define MAKE_KEYED_KAT(name, size_prefix) \ + do { \ + printf("static const uint8_t " #name "_keyed_kat[BLAKE2_KAT_LENGTH][" #size_prefix \ + "_OUTBYTES] = \n{\n"); \ + \ + for (i = 0; i < LENGTH; ++i) { \ + name(hash, size_prefix##_OUTBYTES, in, i, key, size_prefix##_KEYBYTES); \ + printf("\t{\n\t\t"); \ + \ + for (j = 0; j < size_prefix##_OUTBYTES; ++j) \ + printf("0x%02X%s", hash[j], \ + (j + 1) == size_prefix##_OUTBYTES ? "\n" : j && !((j + 1) % 8) ? ",\n\t\t" : ", "); \ + \ + printf("\t},\n"); \ + } \ + \ + printf("};\n\n\n\n\n"); \ + } while (0) + +#define MAKE_XOF_KAT(name) \ + do { \ + printf("static const uint8_t " #name "_kat[BLAKE2_KAT_LENGTH][BLAKE2_KAT_LENGTH] = \n{\n"); \ + \ + for (i = 1; i <= LENGTH; ++i) { \ + name(hash, i, in, LENGTH, NULL, 0); \ + printf("\t{\n\t\t"); \ + \ + for (j = 0; j < i; ++j) \ + printf("0x%02X%s", hash[j], \ + (j + 1) == LENGTH ? "\n" : j && !((j + 1) % 8) ? ",\n\t\t" : ", "); \ + \ + for (j = i; j < LENGTH; ++j) \ + printf("0x00%s", (j + 1) == LENGTH ? "\n" : j && !((j + 1) % 8) ? ",\n\t\t" : ", "); \ + \ + printf("\t},\n"); \ + } \ + \ + printf("};\n\n\n\n\n"); \ + } while (0) + +#define MAKE_XOF_KEYED_KAT(name, size_prefix) \ + do { \ + printf("static const uint8_t " #name \ + "_keyed_kat[BLAKE2_KAT_LENGTH][BLAKE2_KAT_LENGTH] = \n{\n"); \ + \ + for (i = 1; i <= LENGTH; ++i) { \ + name(hash, i, in, LENGTH, key, size_prefix##_KEYBYTES); \ + printf("\t{\n\t\t"); \ + \ + for (j = 0; j < i; ++j) \ + printf("0x%02X%s", hash[j], \ + (j + 1) == LENGTH ? "\n" : j && !((j + 1) % 8) ? ",\n\t\t" : ", "); \ + \ + for (j = i; j < LENGTH; ++j) \ + printf("0x00%s", (j + 1) == LENGTH ? "\n" : j && !((j + 1) % 8) ? ",\n\t\t" : ", "); \ + \ + printf("\t},\n"); \ + } \ + \ + printf("};\n\n\n\n\n"); \ + } while (0) + +int main() { + uint8_t key[64] = {0}; + uint8_t in[LENGTH] = {0}; + uint8_t hash[LENGTH] = {0}; + size_t i, j; + + for (i = 0; i < sizeof(in); ++i) + in[i] = i; + + for (i = 0; i < sizeof(key); ++i) + key[i] = i; + + puts("#ifndef BLAKE2_KAT_H\n" + "#define BLAKE2_KAT_H\n\n\n" + "#include \n\n" + "#define BLAKE2_KAT_LENGTH " STR(LENGTH) "\n\n\n"); + MAKE_KAT(blake2s, BLAKE2S); + MAKE_KEYED_KAT(blake2s, BLAKE2S); + MAKE_KAT(blake2b, BLAKE2B); + MAKE_KEYED_KAT(blake2b, BLAKE2B); + MAKE_KAT(blake2sp, BLAKE2S); + MAKE_KEYED_KAT(blake2sp, BLAKE2S); + MAKE_KAT(blake2bp, BLAKE2B); + MAKE_KEYED_KAT(blake2bp, BLAKE2B); + MAKE_XOF_KAT(blake2xs); + MAKE_XOF_KEYED_KAT(blake2xs, BLAKE2S); + MAKE_XOF_KAT(blake2xb); + MAKE_XOF_KEYED_KAT(blake2xb, BLAKE2B); + puts("#endif"); + return 0; +} diff --git a/src/third_party/blake2/genkat-json.c b/src/third_party/blake2/genkat-json.c new file mode 100644 index 00000000..0275fb51 --- /dev/null +++ b/src/third_party/blake2/genkat-json.c @@ -0,0 +1,154 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include +#include + +#include "blake2.h" + +#define STR_(x) #x +#define STR(x) STR_(x) + +#define LENGTH 256 + +#define MAKE_KAT(name, size_prefix, first) \ + do { \ + for (i = 0; i < LENGTH; ++i) { \ + printf("%s\n{\n", i == 0 && first ? "" : ","); \ + \ + printf(" \"hash\": \"" #name "\",\n"); \ + printf(" \"in\": \""); \ + for (j = 0; j < i; ++j) \ + printf("%02x", in[j]); \ + \ + printf("\",\n"); \ + printf(" \"key\": \"\",\n"); \ + printf(" \"out\": \""); \ + \ + name(hash, size_prefix##_OUTBYTES, in, i, NULL, 0); \ + \ + for (j = 0; j < size_prefix##_OUTBYTES; ++j) \ + printf("%02x", hash[j]); \ + printf("\"\n"); \ + printf("}"); \ + } \ + } while (0) + +#define MAKE_KEYED_KAT(name, size_prefix, first) \ + do { \ + for (i = 0; i < LENGTH; ++i) { \ + printf("%s\n{\n", i == 0 && first ? "" : ","); \ + \ + printf(" \"hash\": \"" #name "\",\n"); \ + printf(" \"in\": \""); \ + for (j = 0; j < i; ++j) \ + printf("%02x", in[j]); \ + \ + printf("\",\n"); \ + printf(" \"key\": \""); \ + for (j = 0; j < size_prefix##_KEYBYTES; ++j) \ + printf("%02x", key[j]); \ + printf("\",\n"); \ + printf(" \"out\": \""); \ + \ + name(hash, size_prefix##_OUTBYTES, in, i, key, size_prefix##_KEYBYTES); \ + \ + for (j = 0; j < size_prefix##_OUTBYTES; ++j) \ + printf("%02x", hash[j]); \ + printf("\"\n"); \ + printf("}"); \ + } \ + } while (0) + +#define MAKE_XOF_KAT(name, first) \ + do { \ + for (i = 1; i <= LENGTH; ++i) { \ + printf("%s\n{\n", i == 1 && first ? "" : ","); \ + \ + printf(" \"hash\": \"" #name "\",\n"); \ + printf(" \"in\": \""); \ + for (j = 0; j < LENGTH; ++j) \ + printf("%02x", in[j]); \ + \ + printf("\",\n"); \ + printf(" \"key\": \"\",\n"); \ + printf(" \"out\": \""); \ + \ + name(hash, i, in, LENGTH, NULL, 0); \ + \ + for (j = 0; j < i; ++j) \ + printf("%02x", hash[j]); \ + printf("\"\n"); \ + printf("}"); \ + } \ + } while (0) + +#define MAKE_XOF_KEYED_KAT(name, size_prefix, first) \ + do { \ + for (i = 1; i <= LENGTH; ++i) { \ + printf("%s\n{\n", i == 1 && first ? "" : ","); \ + \ + printf(" \"hash\": \"" #name "\",\n"); \ + printf(" \"in\": \""); \ + for (j = 0; j < LENGTH; ++j) \ + printf("%02x", in[j]); \ + \ + printf("\",\n"); \ + printf(" \"key\": \""); \ + for (j = 0; j < size_prefix##_KEYBYTES; ++j) \ + printf("%02x", key[j]); \ + printf("\",\n"); \ + printf(" \"out\": \""); \ + \ + name(hash, i, in, LENGTH, key, size_prefix##_KEYBYTES); \ + \ + for (j = 0; j < i; ++j) \ + printf("%02x", hash[j]); \ + printf("\"\n"); \ + printf("}"); \ + } \ + } while (0) + +int main() { + uint8_t key[64] = {0}; + uint8_t in[LENGTH] = {0}; + uint8_t hash[LENGTH] = {0}; + size_t i, j; + + for (i = 0; i < sizeof(in); ++i) + in[i] = i; + + for (i = 0; i < sizeof(key); ++i) + key[i] = i; + + printf("["); + MAKE_KAT(blake2s, BLAKE2S, 1); + MAKE_KEYED_KAT(blake2s, BLAKE2S, 0); + MAKE_KAT(blake2b, BLAKE2B, 0); + MAKE_KEYED_KAT(blake2b, BLAKE2B, 0); + MAKE_KAT(blake2sp, BLAKE2S, 0); + MAKE_KEYED_KAT(blake2sp, BLAKE2S, 0); + MAKE_KAT(blake2bp, BLAKE2B, 0); + MAKE_KEYED_KAT(blake2bp, BLAKE2B, 0); + MAKE_XOF_KAT(blake2xs, 0); + MAKE_XOF_KEYED_KAT(blake2xs, BLAKE2S, 0); + MAKE_XOF_KAT(blake2xb, 0); + MAKE_XOF_KEYED_KAT(blake2xb, BLAKE2B, 0); + printf("\n]\n"); + fflush(stdout); + return 0; +} diff --git a/src/third_party/blake2/makefile b/src/third_party/blake2/makefile new file mode 100644 index 00000000..a59476ba --- /dev/null +++ b/src/third_party/blake2/makefile @@ -0,0 +1,40 @@ +CC=gcc +CFLAGS=-O3 -I../testvectors -Wall -Wextra -std=c89 -pedantic -Wno-long-long +BLAKEBINS=blake2s blake2b blake2sp blake2bp blake2xs blake2xb + +all: $(BLAKEBINS) check + +blake2s: blake2s.c + $(CC) blake2s.c -o $@ $(CFLAGS) -DBLAKE2S_SELFTEST + +blake2b: blake2b.c + $(CC) blake2b.c -o $@ $(CFLAGS) -DBLAKE2B_SELFTEST + +blake2sp: blake2sp.c blake2s.c + $(CC) blake2sp.c blake2s.c -o $@ $(CFLAGS) -DBLAKE2SP_SELFTEST + +blake2bp: blake2bp.c blake2b.c + $(CC) blake2bp.c blake2b.c -o $@ $(CFLAGS) -DBLAKE2BP_SELFTEST + +blake2xs: blake2xs.c blake2s.c + $(CC) blake2xs.c blake2s.c -o $@ $(CFLAGS) -DBLAKE2XS_SELFTEST + +blake2xb: blake2xb.c blake2b.c + $(CC) blake2xb.c blake2b.c -o $@ $(CFLAGS) -DBLAKE2XB_SELFTEST + +check: blake2s blake2b blake2sp blake2bp blake2xs blake2xb + ./blake2s + ./blake2b + ./blake2sp + ./blake2bp + ./blake2xs + ./blake2xb + +kat: + $(CC) $(CFLAGS) -o genkat-c genkat-c.c blake2b.c blake2s.c blake2sp.c blake2bp.c blake2xs.c blake2xb.c + $(CC) $(CFLAGS) -g -o genkat-json genkat-json.c blake2b.c blake2s.c blake2sp.c blake2bp.c blake2xs.c blake2xb.c + ./genkat-c > blake2-kat.h + ./genkat-json > blake2-kat.json + +clean: + rm -rf *.o genkat-c genkat-json blake2-kat.h blake2-kat.json $(BLAKEBINS) diff --git a/src/third_party/stb/stb_sprintf.h b/src/third_party/stb/stb_sprintf.h new file mode 100644 index 00000000..6a65f957 --- /dev/null +++ b/src/third_party/stb/stb_sprintf.h @@ -0,0 +1,1943 @@ +// ---------------------------------------------------------------------------- +// +// NOTE(rjf): This has been modified to support extra format specifiers +// for the debugger project - this is *not* an unmodified copy of the original +// stb_sprintf v1.10 code. +// +// ---------------------------------------------------------------------------- + +// stb_sprintf - v1.10 - public domain snprintf() implementation +// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 +// http://github.com/nothings/stb +// +// allowed types: sc uidBboXx p AaGgEef n +// lengths : hh h ll j z t I64 I32 I +// +// Contributors: +// Fabian "ryg" Giesen (reformatting) +// github:aganm (attribute format) +// +// Contributors (bugfixes): +// github:d26435 +// github:trex78 +// github:account-login +// Jari Komppa (SI suffixes) +// Rohit Nirmal +// Marcin Wojdyr +// Leonard Ritter +// Stefano Zanotti +// Adam Allison +// Arvid Gerstmann +// Markus Kolb +// +// LICENSE: +// +// See end of file for license information. + +#ifndef STB_SPRINTF_H_INCLUDE +#define STB_SPRINTF_H_INCLUDE + +/* +Single file sprintf replacement. + +Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. +Hereby placed in public domain. + +This is a full sprintf replacement that supports everything that +the C runtime sprintfs support, including float/double, 64-bit integers, +hex floats, field parameters (%*.*d stuff), length reads backs, etc. + +Why would you need this if sprintf already exists? Well, first off, +it's *much* faster (see below). It's also much smaller than the CRT +versions code-space-wise. We've also added some simple improvements +that are super handy (commas in thousands, callbacks at buffer full, +for example). Finally, the format strings for MSVC and GCC differ +for 64-bit integers (among other small things), so this lets you use +the same format strings in cross platform code. + +It uses the standard single file trick of being both the header file +and the source itself. If you just include it normally, you just get +the header file function definitions. To get the code, you include +it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. + +It only uses va_args macros from the C runtime to do it's work. It +does cast doubles to S64s and shifts and divides U64s, which does +drag in CRT code on most platforms. + +It compiles to roughly 8K with float support, and 4K without. +As a comparison, when using MSVC static libs, calling sprintf drags +in 16K. + +API: +==== +int stbsp_sprintf( char * buf, char const * fmt, ... ) +int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) + Convert an arg list into a buffer. stbsp_snprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) +int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) + Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) + typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); + Convert into a buffer, calling back every STB_SPRINTF_MIN chars. + Your callback can then copy the chars out, print them or whatever. + This function is actually the workhorse for everything else. + The buffer you pass in must hold at least STB_SPRINTF_MIN characters. + // you return the next buffer to use or 0 to stop converting + +void stbsp_set_separators( char comma, char period ) + Set the comma and period characters to use. + +FLOATS/DOUBLES: +=============== +This code uses a internal float->ascii conversion method that uses +doubles with error correction (double-doubles, for ~105 bits of +precision). This conversion is round-trip perfect - that is, an atof +of the values output here will give you the bit-exact double back. + +One difference is that our insignificant digits will be different than +with MSVC or GCC (but they don't match each other either). We also +don't attempt to find the minimum length matching float (pre-MSVC15 +doesn't either). + +If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT +and you'll save 4K of code space. + +64-BIT INTS: +============ +This library also supports 64-bit integers and you can use MSVC style or +GCC style indicators (%I64d or %lld). It supports the C99 specifiers +for size_t and ptr_diff_t (%jd %zd) as well. + +EXTRAS: +======= +Like some GCCs, for integers and floats, you can use a ' (single quote) +specifier and commas will be inserted on the thousands: "%'d" on 12345 +would print 12,345. + +For integers and floats, you can use a "$" specifier and the number +will be converted to float and then divided to get kilo, mega, giga or +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three +$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the +suffix, add "_" specifier: "%_$d" -> "2.53M". + +In addition to octal and hexadecimal conversions, you can print +integers in binary: "%b" for 256 would print 100. + +PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): +=================================================================== +"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) +"%24d" across all 32-bit ints (4.5x/4.2x faster) +"%x" across all 32-bit ints (4.5x/3.8x faster) +"%08x" across all 32-bit ints (4.3x/3.8x faster) +"%f" across e-10 to e+10 floats (7.3x/6.0x faster) +"%e" across e-10 to e+10 floats (8.1x/6.0x faster) +"%g" across e-10 to e+10 floats (10.0x/7.1x faster) +"%f" for values near e-300 (7.9x/6.5x faster) +"%f" for values near e+300 (10.0x/9.1x faster) +"%e" for values near e-300 (10.1x/7.0x faster) +"%e" for values near e+300 (9.2x/6.0x faster) +"%.320f" for values near e-300 (12.6x/11.2x faster) +"%a" for random values (8.6x/4.3x faster) +"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) +"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) +"%s%s%s" for 64 char strings (7.1x/7.3x faster) +"...512 char string..." ( 35.0x/32.5x faster!) +*/ + +#if defined(__clang__) +# if defined(__has_feature) && defined(__has_attribute) +# if __has_feature(address_sanitizer) +# if __has_attribute(__no_sanitize__) +# define STBSP__ASAN __attribute__((__no_sanitize__("address"))) +# elif __has_attribute(__no_sanitize_address__) +# define STBSP__ASAN __attribute__((__no_sanitize_address__)) +# elif __has_attribute(__no_address_safety_analysis__) +# define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) +# endif +# endif +# endif +#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +# if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ +# define STBSP__ASAN __attribute__((__no_sanitize_address__)) +# endif +#elif defined(_MSC_VER) +# if defined(__SANITIZE_ADDRESS__) +# define STBSP__ASAN __declspec(no_sanitize_address) +# endif +#endif + +#ifndef STBSP__ASAN +#define STBSP__ASAN +#endif + +#ifdef STB_SPRINTF_STATIC +#define STBSP__PUBLICDEC static STBSP__ASAN +#define STBSP__PUBLICDEF static STBSP__ASAN +#else +#ifdef __cplusplus +#define STBSP__PUBLICDEC extern "C" STBSP__ASAN +#define STBSP__PUBLICDEF extern "C" STBSP__ASAN +#else +#define STBSP__PUBLICDEC extern STBSP__ASAN +#define STBSP__PUBLICDEF STBSP__ASAN +#endif +#endif + +#if defined(__has_attribute) +#if __has_attribute(format) +#define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) +#endif +#endif + +#ifndef STBSP__ATTRIBUTE_FORMAT +#define STBSP__ATTRIBUTE_FORMAT(fmt,va) +#endif + +#ifdef _MSC_VER +#define STBSP__NOTUSED(v) (void)(v) +#else +#define STBSP__NOTUSED(v) (void)sizeof(v) +#endif + +#include // for va_arg(), va_list() +#include // size_t, ptrdiff_t + +#ifndef STB_SPRINTF_MIN +#define STB_SPRINTF_MIN 512 // how many characters per callback +#endif +typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); + +#ifndef STB_SPRINTF_DECORATE +#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names +#endif + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); + +#endif // STB_SPRINTF_H_INCLUDE + +#ifdef STB_SPRINTF_IMPLEMENTATION + +#define stbsp__uint32 unsigned int +#define stbsp__int32 signed int + +#ifdef _MSC_VER +#define stbsp__uint64 unsigned __int64 +#define stbsp__int64 signed __int64 +#else +#define stbsp__uint64 unsigned long long +#define stbsp__int64 signed long long +#endif +#define stbsp__uint16 unsigned short + +#ifndef stbsp__uintptr +#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) +#define stbsp__uintptr stbsp__uint64 +#else +#define stbsp__uintptr stbsp__uint32 +#endif +#endif + +#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define STB_SPRINTF_MSVC_MODE +#endif +#endif + +#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses +#define STBSP__UNALIGNED(code) +#else +#define STBSP__UNALIGNED(code) code +#endif + +#ifndef STB_SPRINTF_NOFLOAT +// internal float utility functions +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); +#define STBSP__SPECIAL 0x7000 +#endif + +static char stbsp__period = '.'; +static char stbsp__comma = ','; +static struct +{ + short temp; // force next field to be 2-byte aligned + char pair[201]; +} stbsp__digitpair = +{ + 0, + "00010203040506070809101112131415161718192021222324" + "25262728293031323334353637383940414243444546474849" + "50515253545556575859606162636465666768697071727374" + "75767778798081828384858687888990919293949596979899" +}; + +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) +{ + stbsp__period = pperiod; + stbsp__comma = pcomma; +} + +#define STBSP__LEFTJUST 1 +#define STBSP__LEADINGPLUS 2 +#define STBSP__LEADINGSPACE 4 +#define STBSP__LEADING_0X 8 +#define STBSP__LEADINGZERO 16 +#define STBSP__INTMAX 32 +#define STBSP__TRIPLET_COMMA 64 +#define STBSP__NEGATIVE 128 +#define STBSP__METRIC_SUFFIX 256 +#define STBSP__HALFWIDTH 512 +#define STBSP__METRIC_NOSPACE 1024 +#define STBSP__METRIC_1024 2048 +#define STBSP__METRIC_JEDEC 4096 + +static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +{ + sign[0] = 0; + if (fl & STBSP__NEGATIVE) { + sign[0] = 1; + sign[1] = '-'; + } else if (fl & STBSP__LEADINGSPACE) { + sign[0] = 1; + sign[1] = ' '; + } else if (fl & STBSP__LEADINGPLUS) { + sign[0] = 1; + sign[1] = '+'; + } +} + +static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) +{ + char const * sn = s; + + // get up to 4-byte alignment + for (;;) { + if (((stbsp__uintptr)sn & 3) == 0) + break; + + if (!limit || *sn == 0) + return (stbsp__uint32)(sn - s); + + ++sn; + --limit; + } + + // scan over 4 bytes at a time to find terminating 0 + // this will intentionally scan up to 3 bytes past the end of buffers, + // but becase it works 4B aligned, it will never cross page boundaries + // (hence the STBSP__ASAN markup; the over-read here is intentional + // and harmless) + while (limit >= 4) { + stbsp__uint32 v = *(stbsp__uint32 *)sn; + // bit hack to find if there's a 0 byte in there + if ((v - 0x01010101) & (~v) & 0x80808080UL) + break; + + sn += 4; + limit -= 4; + } + + // handle the last few characters to find actual size + while (limit && *sn) { + ++sn; + --limit; + } + + return (stbsp__uint32)(sn - s); +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) +{ + static char hex[] = "0123456789abcdefxp"; + static char hexu[] = "0123456789ABCDEFXP"; + char *bf; + char const *f; + int tlen = 0; + + bf = buf; + f = fmt; + for (;;) { + stbsp__int32 fw, pr, tz; + stbsp__uint32 fl; + + // macros for the callback buffer stuff +#define stbsp__chk_cb_bufL(bytes) \ +{ \ +int len = (int)(bf - buf); \ +if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ +tlen += len; \ +if (0 == (bf = buf = callback(buf, user, len))) \ +goto done; \ +} \ +} +#define stbsp__chk_cb_buf(bytes) \ +{ \ +if (callback) { \ +stbsp__chk_cb_bufL(bytes); \ +} \ +} +#define stbsp__flush_cb() \ +{ \ +stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ +} // flush if there is even one byte in the buffer +#define stbsp__cb_buf_clamp(cl, v) \ +cl = v; \ +if (callback) { \ +int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ +if (cl > lg) \ +cl = lg; \ +} + + // fast copy everything up to the next % (or end of string) + for (;;) { + while (((stbsp__uintptr)f) & 3) { + schk1: + if (f[0] == '%') + goto scandd; + schk2: + if (f[0] == 0) + goto endfmt; + stbsp__chk_cb_buf(1); + *bf++ = f[0]; + ++f; + } + for (;;) { + // Check if the next 4 bytes contain %(0x25) or end of string. + // Using the 'hasless' trick: + // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + stbsp__uint32 v, c; + v = *(stbsp__uint32 *)f; + c = (~v) & 0x80808080; + if (((v ^ 0x25252525) - 0x01010101) & c) + goto schk1; + if ((v - 0x01010101) & c) + goto schk2; + if (callback) + if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) + goto schk1; +#ifdef STB_SPRINTF_NOUNALIGNED + if(((stbsp__uintptr)bf) & 3) { + bf[0] = f[0]; + bf[1] = f[1]; + bf[2] = f[2]; + bf[3] = f[3]; + } else +#endif + { + *(stbsp__uint32 *)bf = v; + } + bf += 4; + f += 4; + } + } + scandd: + + ++f; + + // ok, we have a percent, read the modifiers first + fw = 0; + pr = -1; + fl = 0; + tz = 0; + + // flags + for (;;) { + switch (f[0]) { + // if we have left justify + case '-': + fl |= STBSP__LEFTJUST; + ++f; + continue; + // if we have leading plus + case '+': + fl |= STBSP__LEADINGPLUS; + ++f; + continue; + // if we have leading space + case ' ': + fl |= STBSP__LEADINGSPACE; + ++f; + continue; + // if we have leading 0x + case '#': + fl |= STBSP__LEADING_0X; + ++f; + continue; + // if we have thousand commas + case '\'': + fl |= STBSP__TRIPLET_COMMA; + ++f; + continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { + fl |= STBSP__METRIC_JEDEC; + } else { + fl |= STBSP__METRIC_1024; + } + } else { + fl |= STBSP__METRIC_SUFFIX; + } + ++f; + continue; + // if we don't want space between metric suffix and number + case '_': + fl |= STBSP__METRIC_NOSPACE; + ++f; + continue; + // if we have leading zero + case '0': + fl |= STBSP__LEADINGZERO; + ++f; + goto flags_done; + default: goto flags_done; + } + } + flags_done: + + // get the field width + if (f[0] == '*') { + fw = va_arg(va, stbsp__uint32); + ++f; + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { + fw = fw * 10 + f[0] - '0'; + f++; + } + } + // get the precision + if (f[0] == '.') { + ++f; + if (f[0] == '*') { + pr = va_arg(va, stbsp__uint32); + ++f; + } else { + pr = 0; + while ((f[0] >= '0') && (f[0] <= '9')) { + pr = pr * 10 + f[0] - '0'; + f++; + } + } + } + + // handle integer size overrides + switch (f[0]) { + // are we halfwidth? + case 'h': + fl |= STBSP__HALFWIDTH; + ++f; + if (f[0] == 'h') + ++f; // QUARTERWIDTH + break; + // are we 64-bit (unix style) + case 'l': + fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); + ++f; + if (f[0] == 'l') { + fl |= STBSP__INTMAX; + ++f; + } + break; + // are we 64-bit on intmax? (c99) + case 'j': + fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit on size_t or ptrdiff_t? (c99) + case 'z': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + case 't': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit (msft style) + case 'I': + if ((f[1] == '6') && (f[2] == '4')) { + fl |= STBSP__INTMAX; + f += 3; + } else if ((f[1] == '3') && (f[2] == '2')) { + f += 3; + } else { + fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); + ++f; + } + break; + default: break; + } + + // handle each replacement + switch (f[0]) { +#define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + char num[STBSP__NUMSZ]; + char lead[8]; + char tail[8]; + char *s; + char const *h; + stbsp__uint32 l, n, cs; + stbsp__uint64 n64; +#ifndef STB_SPRINTF_NOFLOAT + double fv; +#endif + stbsp__int32 dp; + char const *sn; + + case 's': + // get the string + s = va_arg(va, char *); + if (s == 0) + s = (char *)"null"; + // get the length, limited to desired precision + // always limit to ~0u chars since our counts are 32b + l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + // copy the string in + goto scopy; + + //- + //- + //- + // NOTE(rjf): DEBUGGER PROJECT ADDITION vvv + // + // The following additions are for using the debugger project's base layer + // types in format strings. + // + case 'S': + { + String8 string = va_arg(va, String8); + s = (char *)string.str; + l = (U32)string.size; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + }goto scopy; + // + // NOTE(rjf): DEBUGGER PROJECT ADDITION ^^^ + //- + //- + //- + + case 'c': // char + // get the character + s = num + STBSP__NUMSZ - 1; + *s = (char)va_arg(va, int); + l = 1; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + + case 'n': // weird write-bytes specifier + { + int *d = va_arg(va, int *); + *d = tlen + (int)(bf - buf); + } break; + +#ifdef STB_SPRINTF_NOFLOAT + case 'A': // float + case 'a': // hex float + case 'G': // float + case 'g': // float + case 'E': // float + case 'e': // float + case 'f': // float + va_arg(va, double); // eat it + s = (char *)"No float"; + l = 8; + lead[0] = 0; + tail[0] = 0; + pr = 0; + cs = 0; + STBSP__NOTUSED(dp); + goto scopy; +#else + case 'A': // hex float + case 'a': // hex float + h = (f[0] == 'A') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) + fl |= STBSP__NEGATIVE; + + s = num + 64; + + stbsp__lead_sign(fl, lead); + + if (dp == -1023) + dp = (n64) ? -1022 : 0; + else + n64 |= (((stbsp__uint64)1) << 52); + n64 <<= (64 - 56); + if (pr < 15) + n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); + // add leading chars + +#ifdef STB_SPRINTF_MSVC_MODE + *s++ = '0'; + *s++ = 'x'; +#else + lead[1 + lead[0]] = '0'; + lead[2 + lead[0]] = 'x'; + lead[0] += 2; +#endif + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + if (pr) + *s++ = stbsp__period; + sn = s; + + // print the bits + n = pr; + if (n > 13) + n = 13; + if (pr > (stbsp__int32)n) + tz = pr - n; + pr = 0; + while (n--) { + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + } + + // print the expo + tail[1] = h[17]; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; + n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + + dp = (int)(s - sn); + l = (int)(s - (num + 64)); + s = num + 64; + cs = 1 + (3 << 24); + goto scopy; + + case 'G': // float + case 'g': // float + h = (f[0] == 'G') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; + else if (pr == 0) + pr = 1; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) + fl |= STBSP__NEGATIVE; + + // clamp the precision and delete extra zeros after clamp + n = pr; + if (l > (stbsp__uint32)pr) + l = pr; + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + --pr; + --l; + } + + // should we use %e + if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if (pr > (stbsp__int32)l) + pr = l - 1; + else if (pr) + --pr; // when using %e, there is one digit before the decimal + goto doexpfromg; + } + // this is the insane action to get the pr to match %g semantics for %f + if (dp > 0) { + pr = (dp < (stbsp__int32)l) ? l - dp : 0; + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); + } + goto dofloatfromg; + + case 'E': // float + case 'e': // float + h = (f[0] == 'E') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) + fl |= STBSP__NEGATIVE; + doexpfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + // handle leading chars + *s++ = sn[0]; + + if (pr) + *s++ = stbsp__period; + + // handle after decimal + if ((l - 1) > (stbsp__uint32)pr) + l = pr + 1; + for (n = 1; n < l; n++) + *s++ = sn[n]; + // trailing zeros + tz = pr - (l - 1); + pr = 0; + // dump expo + tail[1] = h[0xe]; + dp -= 1; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; +#ifdef STB_SPRINTF_MSVC_MODE + n = 5; +#else + n = (dp >= 100) ? 5 : 4; +#endif + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + cs = 1 + (3 << 24); // how many tens + goto flt_lead; + + case 'f': // float + fv = va_arg(va, double); + doafloat: + // do kilos + if (fl & STBSP__METRIC_SUFFIX) { + double divisor; + divisor = 1000.0f; + if (fl & STBSP__METRIC_1024) + divisor = 1024.0; + while (fl < 0x4000000) { + if ((fv < divisor) && (fv > -divisor)) + break; + fv /= divisor; + fl += 0x1000000; + } + } + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) + fl |= STBSP__NEGATIVE; + dofloatfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + + // handle the three decimal varieties + if (dp <= 0) { + stbsp__int32 i; + // handle 0.000*000xxxx + *s++ = '0'; + if (pr) + *s++ = stbsp__period; + n = -dp; + if ((stbsp__int32)n > pr) + n = pr; + i = n; + while (i) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + i -= 4; + } + while (i) { + *s++ = '0'; + --i; + } + if ((stbsp__int32)(l + n) > pr) + l = pr - n; + i = l; + while (i) { + *s++ = *sn++; + --i; + } + tz = pr - (n + l); + cs = 1 + (3 << 24); // how many tens did we write (for commas below) + } else { + cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; + if ((stbsp__uint32)dp >= l) { + // handle xxxx000*000.0 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= l) + break; + } + } + if (n < (stbsp__uint32)dp) { + n = dp - n; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --n; + } + while (n >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + n -= 4; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = '0'; + --n; + } + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) { + *s++ = stbsp__period; + tz = pr; + } + } else { + // handle xxxxx.xxxx000*000 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= (stbsp__uint32)dp) + break; + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) + *s++ = stbsp__period; + if ((l - dp) > (stbsp__uint32)pr) + l = pr + dp; + while (n < l) { + *s++ = sn[n]; + ++n; + } + tz = pr - (l - dp); + } + } + pr = 0; + + // handle k,m,g,t + if (fl & STBSP__METRIC_SUFFIX) { + char idx; + idx = 1; + if (fl & STBSP__METRIC_NOSPACE) + idx = 0; + tail[0] = idx; + tail[1] = ' '; + { + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl & STBSP__METRIC_1024) + tail[idx + 1] = "_KMGT"[fl >> 24]; + else + tail[idx + 1] = "_kMGT"[fl >> 24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + tail[idx + 1] = 'i'; + idx++; + } + tail[0] = idx; + } + } + }; + + flt_lead: + // get the length that we copied + l = (stbsp__uint32)(s - (num + 64)); + s = num + 64; + goto scopy; +#endif + + case 'B': // upper binary + case 'b': // lower binary + h = (f[0] == 'B') ? hexu : hex; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[0xb]; + } + l = (8 << 4) | (1 << 8); + goto radixnum; + + case 'o': // octal + h = hexu; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 1; + lead[1] = '0'; + } + l = (3 << 4) | (3 << 8); + goto radixnum; + + case 'p': // pointer + fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; + pr = sizeof(void *) * 2; + fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros + // fall through - to X + + case 'X': // upper hex + case 'x': // lower hex + h = (f[0] == 'X') ? hexu : hex; + l = (4 << 4) | (4 << 8); + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[16]; + } + radixnum: + // get the number + if (fl & STBSP__INTMAX) + n64 = va_arg(va, stbsp__uint64); + else + n64 = va_arg(va, stbsp__uint32); + + s = num + STBSP__NUMSZ; + dp = 0; + // clear tail, and clear leading if value is zero + tail[0] = 0; + if (n64 == 0) { + lead[0] = 0; + if (pr == 0) { + l = 0; + cs = 0; + goto scopy; + } + } + // convert to string + for (;;) { + *--s = h[n64 & ((1 << (l >> 8)) - 1)]; + n64 >>= (l >> 8); + if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) + break; + if (fl & STBSP__TRIPLET_COMMA) { + ++l; + if ((l & 15) == ((l >> 4) & 15)) { + l &= ~15; + *--s = stbsp__comma; + } + } + }; + // get the tens and the comma pos + cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + // copy it + goto scopy; + + case 'u': // unsigned + case 'i': + case 'd': // integer + // get the integer and abs it + if (fl & STBSP__INTMAX) { + stbsp__int64 i64 = va_arg(va, stbsp__int64); + n64 = (stbsp__uint64)i64; + if ((f[0] != 'u') && (i64 < 0)) { + n64 = (stbsp__uint64)-i64; + fl |= STBSP__NEGATIVE; + } + } else { + stbsp__int32 i = va_arg(va, stbsp__int32); + n64 = (stbsp__uint32)i; + if ((f[0] != 'u') && (i < 0)) { + n64 = (stbsp__uint32)-i; + fl |= STBSP__NEGATIVE; + } + } + +#ifndef STB_SPRINTF_NOFLOAT + if (fl & STBSP__METRIC_SUFFIX) { + if (n64 < 1024) + pr = 0; + else if (pr == -1) + pr = 1; + fv = (double)(stbsp__int64)n64; + goto doafloat; + } +#endif + + // convert to string + s = num + STBSP__NUMSZ; + l = 0; + + for (;;) { + // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) + char *o = s - 8; + if (n64 >= 100000000) { + n = (stbsp__uint32)(n64 % 100000000); + n64 /= 100000000; + } else { + n = (stbsp__uint32)n64; + n64 = 0; + } + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + do { + s -= 2; + *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + } while (n); + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = (char)(n % 10) + '0'; + n /= 10; + } + } + if (n64 == 0) { + if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) + ++s; + break; + } + while (s != o) + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = '0'; + } + } + + tail[0] = 0; + stbsp__lead_sign(fl, lead); + + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + if (l == 0) { + *--s = '0'; + l = 1; + } + cs = l + (3 << 24); + if (pr < 0) + pr = 0; + + scopy: + // get fw=leading/trailing space, pr=leading zeros + if (pr < (stbsp__int32)l) + pr = l; + n = pr + lead[0] + tail[0] + tz; + if (fw < (stbsp__int32)n) + fw = n; + fw -= n; + pr -= l; + + // handle right justify and leading zeros + if ((fl & STBSP__LEFTJUST) == 0) { + if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr + { + pr = (fw > pr) ? fw : pr; + fw = 0; + } else { + fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas + } + } + + // copy the spaces and/or zeros + if (fw + pr) { + stbsp__int32 i; + stbsp__uint32 c; + + // copy leading spaces (or when doing %8.4d stuff) + if ((fl & STBSP__LEFTJUST) == 0) + while (fw > 0) { + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = ' '; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leader + sn = lead + 1; + while (lead[0]) { + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leading zeros + c = cs >> 24; + cs &= 0xffffff; + cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; + while (pr > 0) { + stbsp__cb_buf_clamp(i, pr); + pr -= i; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + } + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + cs = 0; + *bf++ = stbsp__comma; + } else + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + } + + // copy leader if there is still one + sn = lead + 1; + while (lead[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy the string + n = l; + while (n) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, n); + n -= i; + STBSP__UNALIGNED(while (i >= 4) { + *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; + bf += 4; + s += 4; + i -= 4; + }) + while (i) { + *bf++ = *s++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy trailing zeros + while (tz) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tz); + tz -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy tail if there is one + sn = tail + 1; + while (tail[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tail[0]); + tail[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // handle the left justify + if (fl & STBSP__LEFTJUST) + if (fw > 0) { + while (fw) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i--) + *bf++ = ' '; + stbsp__chk_cb_buf(1); + } + } + break; + + default: // unknown, just copy code + s = num + STBSP__NUMSZ - 1; + *s = f[0]; + l = 1; + fw = fl = 0; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + } + ++f; + } + endfmt: + + if (!callback) + *bf = 0; + else + stbsp__flush_cb(); + + done: + return tlen + (int)(bf - buf); +} + +// cleanup +#undef STBSP__LEFTJUST +#undef STBSP__LEADINGPLUS +#undef STBSP__LEADINGSPACE +#undef STBSP__LEADING_0X +#undef STBSP__LEADINGZERO +#undef STBSP__INTMAX +#undef STBSP__TRIPLET_COMMA +#undef STBSP__NEGATIVE +#undef STBSP__METRIC_SUFFIX +#undef STBSP__NUMSZ +#undef stbsp__chk_cb_bufL +#undef stbsp__chk_cb_buf +#undef stbsp__flush_cb +#undef stbsp__cb_buf_clamp + +// ============================================================================ +// wrapper functions + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); + va_end(va); + return result; +} + +typedef struct stbsp__context { + char *buf; + int count; + int length; + char tmp[STB_SPRINTF_MIN]; +} stbsp__context; + +static char *stbsp__clamp_callback(const char *buf, void *user, int len) +{ + stbsp__context *c = (stbsp__context *)user; + c->length += len; + + if (len > c->count) + len = c->count; + + if (len) { + if (buf != c->buf) { + const char *s, *se; + char *d; + d = c->buf; + s = buf; + se = buf + len; + do { + *d++ = *s++; + } while (s < se); + } + c->buf += len; + c->count -= len; + } + + if (c->count <= 0) + return c->tmp; + return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can +} + +static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) +{ + stbsp__context * c = (stbsp__context*)user; + (void) sizeof(buf); + + c->length += len; + return c->tmp; // go direct into buffer if you can +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +{ + stbsp__context c; + + if ( (count == 0) && !buf ) + { + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); + } + else + { + int l; + + c.buf = buf; + c.count = count; + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); + + // zero-terminate + l = (int)( c.buf - buf ); + if ( l >= count ) // should never be greater, only equal (or less) than count + l = count - 1; + buf[l] = 0; + } + + return c.length; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); + va_end(va); + + return result; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) +{ + return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); +} + +// ======================================================================= +// low level float utility functions + +#ifndef STB_SPRINTF_NOFLOAT + +// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) +#define STBSP__COPYFP(dest, src) \ +{ \ +int cn; \ +for (cn = 0; cn < 8; cn++) \ +((char *)&dest)[cn] = ((char *)&src)[cn]; \ +} + +// get float info +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) +{ + double d; + stbsp__int64 b = 0; + + // load value and round at the frac_digits + d = value; + + STBSP__COPYFP(b, d); + + *bits = b & ((((stbsp__uint64)1) << 52) - 1); + *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); + + return (stbsp__int32)((stbsp__uint64) b >> 63); +} + +static double const stbsp__bot[23] = { + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; +static double const stbsp__negbot[22] = { + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; +static double const stbsp__negboterr[22] = { + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; +static double const stbsp__top[13] = { + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; +static double const stbsp__negtop[13] = { + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; +static double const stbsp__toperr[13] = { + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; +static double const stbsp__negtoperr[13] = { + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; + +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; +#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) +#else +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; +#define stbsp__tento19th (1000000000000000000ULL) +#endif + +#define stbsp__ddmulthi(oh, ol, xh, yh) \ +{ \ +double ahi = 0, alo, bhi = 0, blo; \ +stbsp__int64 bt; \ +oh = xh * yh; \ +STBSP__COPYFP(bt, xh); \ +bt &= ((~(stbsp__uint64)0) << 27); \ +STBSP__COPYFP(ahi, bt); \ +alo = xh - ahi; \ +STBSP__COPYFP(bt, yh); \ +bt &= ((~(stbsp__uint64)0) << 27); \ +STBSP__COPYFP(bhi, bt); \ +blo = yh - bhi; \ +ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ +} + +#define stbsp__ddtoS64(ob, xh, xl) \ +{ \ +double ahi = 0, alo, vh, t; \ +ob = (stbsp__int64)xh; \ +vh = (double)ob; \ +ahi = (xh - vh); \ +t = (ahi - xh); \ +alo = (xh - (ahi - t)) - (vh + t); \ +ob += (stbsp__int64)(ahi + alo + xl); \ +} + +#define stbsp__ddrenorm(oh, ol) \ +{ \ +double s; \ +s = oh + ol; \ +ol = ol - (s - oh); \ +oh = s; \ +} + +#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); + +#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); + +static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 +{ + double ph, pl; + if ((power >= 0) && (power <= 22)) { + stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); + } else { + stbsp__int32 e, et, eb; + double p2h, p2l; + + e = power; + if (power < 0) + e = -e; + et = (e * 0x2c9) >> 14; /* %23 */ + if (et > 13) + et = 13; + eb = e - (et * 23); + + ph = d; + pl = 0.0; + if (power < 0) { + if (eb) { + --eb; + stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); + stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); + ph = p2h; + pl = p2l; + } + } else { + if (eb) { + e = eb; + if (eb > 22) + eb = 22; + e -= eb; + stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); + if (e) { + stbsp__ddrenorm(ph, pl); + stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); + stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); + ph = p2h; + pl = p2l; + } + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); + ph = p2h; + pl = p2l; + } + } + } + stbsp__ddrenorm(ph, pl); + *ohi = ph; + *olo = pl; +} + +// given a float value, returns the significant bits in bits, and the position of the +// decimal point in decimal_pos. +/-INF and NAN are specified by special values +// returned in the decimal_pos parameter. +// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) +{ + double d; + stbsp__int64 bits = 0; + stbsp__int32 expo, e, ng, tens; + + d = value; + STBSP__COPYFP(bits, d); + expo = (stbsp__int32)((bits >> 52) & 2047); + ng = (stbsp__int32)((stbsp__uint64) bits >> 63); + if (ng) + d = -d; + + if (expo == 2047) // is nan or inf? + { + *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; + *decimal_pos = STBSP__SPECIAL; + *len = 3; + return ng; + } + + if (expo == 0) // is zero or denormal + { + if (((stbsp__uint64) bits << 1) == 0) // do zero + { + *decimal_pos = 1; + *start = out; + out[0] = '0'; + *len = 1; + return ng; + } + // find the right expo for denormals + { + stbsp__int64 v = ((stbsp__uint64)1) << 51; + while ((bits & v) == 0) { + --expo; + v >>= 1; + } + } + } + + // find the decimal exponent as well as the decimal bits of the value + { + double ph, pl; + + // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 + tens = expo - 1023; + tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); + + // move the significant bits into position and stick them into an int + stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); + + // get full as much precision from double-double as possible + stbsp__ddtoS64(bits, ph, pl); + + // check if we undershot + if (((stbsp__uint64)bits) >= stbsp__tento19th) + ++tens; + } + + // now do the rounding in integer land + frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); + if ((frac_digits < 24)) { + stbsp__uint32 dg = 1; + if ((stbsp__uint64)bits >= stbsp__powten[9]) + dg = 10; + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + ++dg; + if (dg == 20) + goto noround; + } + if (frac_digits < dg) { + stbsp__uint64 r; + // add 0.5 at the right position and round + e = dg - frac_digits; + if ((stbsp__uint32)e >= 24) + goto noround; + r = stbsp__powten[e]; + bits = bits + (r / 2); + if ((stbsp__uint64)bits >= stbsp__powten[dg]) + ++tens; + bits /= r; + } + noround:; + } + + // kill long trailing runs of zeros + if (bits) { + stbsp__uint32 n; + for (;;) { + if (bits <= 0xffffffff) + break; + if (bits % 1000) + goto donez; + bits /= 1000; + } + n = (stbsp__uint32)bits; + while ((n % 1000) == 0) + n /= 1000; + bits = n; + donez:; + } + + // convert to string + out += 64; + e = 0; + for (;;) { + stbsp__uint32 n; + char *o = out - 8; + // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) + if (bits >= 100000000) { + n = (stbsp__uint32)(bits % 100000000); + bits /= 100000000; + } else { + n = (stbsp__uint32)bits; + bits = 0; + } + while (n) { + out -= 2; + *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + e += 2; + } + if (bits == 0) { + if ((e) && (out[0] == '0')) { + ++out; + --e; + } + break; + } + while (out != o) { + *--out = '0'; + ++e; + } + } + + *decimal_pos = tens; + *start = out; + *len = e; + return ng; +} + +#undef stbsp__ddmulthi +#undef stbsp__ddrenorm +#undef stbsp__ddmultlo +#undef stbsp__ddmultlos +#undef STBSP__SPECIAL +#undef STBSP__COPYFP + +#endif // STB_SPRINTF_NOFLOAT + +// clean up +#undef stbsp__uint16 +#undef stbsp__uint32 +#undef stbsp__int32 +#undef stbsp__uint64 +#undef stbsp__int64 +#undef STBSP__UNALIGNED + +#endif // STB_SPRINTF_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/src/third_party/udis86/CHANGES b/src/third_party/udis86/CHANGES new file mode 100644 index 00000000..34c4c050 --- /dev/null +++ b/src/third_party/udis86/CHANGES @@ -0,0 +1,47 @@ +v1.7.2 + + * Clean up input handling, removing unnecessary caching + of input, which should speed up things. + * Add the missing ud_insn_mnemonic api function. + * Rename ud_opr_isgpr to ud_opr_is_gpr. + * Fix decoding of relative jumps. + * Fix build with automake-1.14 + * Minor fix to AT&T syntax (missing "$" prefix for immedaites) + * Add a new api checker (tests/libcheck.c). + * Add a standalone script for diff-testing (tests/difftest.sh) + * Refinements to the documentation. + + Acknowledgements: + + Brendan Long (https://github.com/brendanlong) + radare (https://github.com/radare) + Sergey Basalaev (https://github.com/SBasalaev) + ebfe (https://github.com/ebfe) + +v1.7.1 + + * Full support for SSSE3, SSE4.1, SSE4.2, SMX, AES. + * New Sphinx-doc/RST based documentation. + * New api for client size symbol resolver. + * Visual Studio 2010 Build Support. + * Added an operand tester. + * Python 3.0 compatibility changes. + * Minor fixes to AT&T syntax. + * Fix install directory for data files. + * Many bug fixes, and optable updates. + * Add Texinfo document (make install-info). + + Acknowledgements: + + L Peter Deutsch (https://github.com/ghghost) + Bjoern Doebel (https://github.com/bjoernd) + Justin Stenning (http://github.com/spazzarama) + Jamie Iles (https://github.com/jamieiles) + Stephen Fewer (https://github.com/stephenfewer) + Piotr Gaczkowski (https://github.com/DoomHammer) + Evan Pheonix + mbarbu (https://github.com/mbarbu) + + + +Please see the commit logs for change information for older releases diff --git a/src/third_party/udis86/LICENSE b/src/third_party/udis86/LICENSE new file mode 100644 index 00000000..580f3598 --- /dev/null +++ b/src/third_party/udis86/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2002-2012, Vivek Thampi +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/third_party/udis86/README b/src/third_party/udis86/README new file mode 100644 index 00000000..03eaee5f --- /dev/null +++ b/src/third_party/udis86/README @@ -0,0 +1,91 @@ +Udis86 +====== + +Udis86 is a disassembler for the x86 and x86-64 class of instruction set +architectures. It consists of a C library called libudis86 which +provides a clean and simple interface to decode a stream of raw binary +data, and to inspect the disassembled instructions in a structured +manner. + + +LICENSE +------- + +Udis86 is distributed under the terms of the 2-clause "Simplified BSD +License". A copy of the license is included with the source in LICENSE. + + +libudis86 +--------- + + o Supports all x86 and x86-64 (AMD64) General purpose and + System instructions. + o Supported ISA extensions: + - MMX, FPU (x87), AMD 3DNow + - SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AES, + - AMD-V, INTEL-VMX, SMX + o Instructions are defined in an XML document, with opcode + tables generated for performance. + o Supports output in both INTEL (NASM) as well as AT&T (GNU as) style + assembly language syntax. + o Supports a variety of input methods: Files, Memory Buffers, and + Function Callback hooks. + o Re-entrant, no dynamic memory allocation. + o Fully documented API + + + -- EXAMPLE ----------------------------------------------------------- + + ud_t u; + + ud_init(&u); + ud_set_input_file(&u, stdin); + ud_set_mode(&u, 64); + ud_set_syntax(&u, UD_SYN_INTEL); + + while (ud_disassemble(&u)) { + printf("\t%s\n", ud_insn_asm(&ud_obj)); + } + + ---------------------------------------------------------------------- + + +udcli +----- + +udcli is a small command-line tool for your quick disassembly needs. + + -- EXAMPLE ----------------------------------------------------------- + + $ echo "65 67 89 87 76 65 54 56 78 89 09 00 90" | udcli -32 -x + 0000000080000800 656789877665 mov [gs:bx+0x6576], eax + 0000000080000806 54 push esp + 0000000080000807 56 push esi + 0000000080000808 7889 js 0x80000793 + 000000008000080a 0900 or [eax], eax + 000000008000080c 90 nop + + ---------------------------------------------------------------------- + + +Documentation +------------- + +The libudis86 api is fully documented. The package distribution contains +a Texinfo file which can be installed by invoking "make install-info". +You can also find an online html version of the documentation available +at http://udis86.sourceforge.net/. + + +Autotools Build +--------------- + +You need autotools if building from sources cloned form version control +system, or if you need to regenerate the build system. The wrapper +script 'autogen.sh' is provided that'll generate the build system. + + +AUTHOR +------ + +Udis86 is written and maintained by Vivek Thampi (vivek.mt@gmail.com). diff --git a/src/third_party/udis86/README.rad b/src/third_party/udis86/README.rad new file mode 100644 index 00000000..34e17129 --- /dev/null +++ b/src/third_party/udis86/README.rad @@ -0,0 +1,24 @@ +udis86 Version 1.7.2 +Disassembler library written in C, by vivek.mt@gmail.com +2-clause BSD license (see LICENSE) + +Documentation: http://udis86.sourceforge.net/ + +Checked out from https://github.com/vmt/udis86 +commit b24baf1e32bdd9ea12cc9f6dc4882b6ba04de0d7 +Date: Thu Nov 14 12:28:33 2013 -0800 + +Various unnecessary parts, like unittests, bootstrapping scripts and a +command-line utility have been stripped out. This is just the bare +library. + +In a normal build, libudis86/itab.h libudis86/itab.c are actually +generated from XML tables and a python script, but I've simply checked +in the generated results to keep things smaller and avoid that +bootstrapping step. + +I did something similar with config.h, which would normally be +generated through automake/configure. This is probably less OK, but +will do for now. + +-Won (wonc@radgametools.com) \ No newline at end of file diff --git a/src/third_party/udis86/config.h b/src/third_party/udis86/config.h new file mode 100644 index 00000000..f2284173 --- /dev/null +++ b/src/third_party/udis86/config.h @@ -0,0 +1,72 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "udis86" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "vivek.mt@gmail.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "udis86" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "udis86 1.7.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "udis86" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.7.2" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.7.2" diff --git a/src/third_party/udis86/libudis86/decode.c b/src/third_party/udis86/libudis86/decode.c new file mode 100644 index 00000000..39714732 --- /dev/null +++ b/src/third_party/udis86/libudis86/decode.c @@ -0,0 +1,1264 @@ +/* udis86 - libudis86/decode.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "udint.h" +#include "types.h" +#include "extern.h" +#include "decode.h" + +#ifndef __UD_STANDALONE__ +# include +#endif /* __UD_STANDALONE__ */ + +/* The max number of prefixes to an instruction */ +#define MAX_PREFIXES 15 + +/* rex prefix bits */ +#define REX_W(r) ( ( 0xF & ( r ) ) >> 3 ) +#define REX_R(r) ( ( 0x7 & ( r ) ) >> 2 ) +#define REX_X(r) ( ( 0x3 & ( r ) ) >> 1 ) +#define REX_B(r) ( ( 0x1 & ( r ) ) >> 0 ) +#define REX_PFX_MASK(n) ( ( P_REXW(n) << 3 ) | \ +( P_REXR(n) << 2 ) | \ +( P_REXX(n) << 1 ) | \ +( P_REXB(n) << 0 ) ) + +/* scable-index-base bits */ +#define SIB_S(b) ( ( b ) >> 6 ) +#define SIB_I(b) ( ( ( b ) >> 3 ) & 7 ) +#define SIB_B(b) ( ( b ) & 7 ) + +/* modrm bits */ +#define MODRM_REG(b) ( ( ( b ) >> 3 ) & 7 ) +#define MODRM_NNN(b) ( ( ( b ) >> 3 ) & 7 ) +#define MODRM_MOD(b) ( ( ( b ) >> 6 ) & 3 ) +#define MODRM_RM(b) ( ( b ) & 7 ) + +static int decode_ext(struct ud *u, uint16_t ptr); +static int decode_opcode(struct ud *u); + +enum reg_class { /* register classes */ + REGCLASS_GPR, + REGCLASS_MMX, + REGCLASS_CR, + REGCLASS_DB, + REGCLASS_SEG, + REGCLASS_XMM +}; + +/* +* inp_start +* Should be called before each de-code operation. +*/ +static void +inp_start(struct ud *u) +{ + u->inp_ctr = 0; +} + +static uint8_t +inp_peek(struct ud *u) +{ + if (u->inp_end == 0) { + if (u->inp_buf != NULL) { + if (u->inp_buf_index < u->inp_buf_size) { + return u->inp_buf[u->inp_buf_index]; + } + } else if (u->inp_peek != UD_EOI) { + return u->inp_peek; + } else { + int c; + if ((c = u->inp_hook(u)) != UD_EOI) { + u->inp_peek = c; + return u->inp_peek; + } + } + } + u->inp_end = 1; + UDERR(u, "byte expected, eoi received\n"); + return 0; +} + +static uint8_t +inp_next(struct ud *u) +{ + if (u->inp_end == 0) { + if (u->inp_buf != NULL) { + if (u->inp_buf_index < u->inp_buf_size) { + u->inp_ctr++; + return (u->inp_curr = u->inp_buf[u->inp_buf_index++]); + } + } else { + int c = u->inp_peek; + if (c != UD_EOI || (c = u->inp_hook(u)) != UD_EOI) { + u->inp_peek = UD_EOI; + u->inp_curr = c; + u->inp_sess[u->inp_ctr++] = u->inp_curr; + return u->inp_curr; + } + } + } + u->inp_end = 1; + UDERR(u, "byte expected, eoi received\n"); + return 0; +} + +static uint8_t +inp_curr(struct ud *u) +{ + return u->inp_curr; +} + + +/* + * inp_uint8 + * int_uint16 + * int_uint32 + * int_uint64 + * Load little-endian values from input + */ +static uint8_t +inp_uint8(struct ud* u) +{ + return inp_next(u); +} + +static uint16_t +inp_uint16(struct ud* u) +{ + uint16_t r, ret; + + ret = inp_next(u); + r = inp_next(u); + return ret | (r << 8); +} + +static uint32_t +inp_uint32(struct ud* u) +{ + uint32_t r, ret; + + ret = inp_next(u); + r = inp_next(u); + ret = ret | (r << 8); + r = inp_next(u); + ret = ret | (r << 16); + r = inp_next(u); + return ret | (r << 24); +} + +static uint64_t +inp_uint64(struct ud* u) +{ + uint64_t r, ret; + + ret = inp_next(u); + r = inp_next(u); + ret = ret | (r << 8); + r = inp_next(u); + ret = ret | (r << 16); + r = inp_next(u); + ret = ret | (r << 24); + r = inp_next(u); + ret = ret | (r << 32); + r = inp_next(u); + ret = ret | (r << 40); + r = inp_next(u); + ret = ret | (r << 48); + r = inp_next(u); + return ret | (r << 56); +} + + +static UD_INLINE int +eff_opr_mode(int dis_mode, int rex_w, int pfx_opr) +{ + if (dis_mode == 64) { + return rex_w ? 64 : (pfx_opr ? 16 : 32); + } else if (dis_mode == 32) { + return pfx_opr ? 16 : 32; + } else { + UD_ASSERT(dis_mode == 16); + return pfx_opr ? 32 : 16; + } +} + + +static UD_INLINE int +eff_adr_mode(int dis_mode, int pfx_adr) +{ + if (dis_mode == 64) { + return pfx_adr ? 32 : 64; + } else if (dis_mode == 32) { + return pfx_adr ? 16 : 32; + } else { + UD_ASSERT(dis_mode == 16); + return pfx_adr ? 32 : 16; + } +} + + +/* + * decode_prefixes + * + * Extracts instruction prefixes. + */ +static int +decode_prefixes(struct ud *u) +{ + int done = 0; + uint8_t curr = 0, last = 0; + UD_RETURN_ON_ERROR(u); + + do { + last = curr; + curr = inp_next(u); + UD_RETURN_ON_ERROR(u); + if (u->inp_ctr == MAX_INSN_LENGTH) { + UD_RETURN_WITH_ERROR(u, "max instruction length"); + } + + switch (curr) + { + case 0x2E: + u->pfx_seg = UD_R_CS; + break; + case 0x36: + u->pfx_seg = UD_R_SS; + break; + case 0x3E: + u->pfx_seg = UD_R_DS; + break; + case 0x26: + u->pfx_seg = UD_R_ES; + break; + case 0x64: + u->pfx_seg = UD_R_FS; + break; + case 0x65: + u->pfx_seg = UD_R_GS; + break; + case 0x67: /* adress-size override prefix */ + u->pfx_adr = 0x67; + break; + case 0xF0: + u->pfx_lock = 0xF0; + break; + case 0x66: + u->pfx_opr = 0x66; + break; + case 0xF2: + u->pfx_str = 0xf2; + break; + case 0xF3: + u->pfx_str = 0xf3; + break; + default: + /* consume if rex */ + done = (u->dis_mode == 64 && (curr & 0xF0) == 0x40) ? 0 : 1; + break; + } + } while (!done); + /* rex prefixes in 64bit mode, must be the last prefix */ + if (u->dis_mode == 64 && (last & 0xF0) == 0x40) { + u->pfx_rex = last; + } + return 0; +} + + +/* + * vex_l, vex_w + * Return the vex.L and vex.W bits + */ +static UD_INLINE uint8_t +vex_l(const struct ud *u) +{ + UD_ASSERT(u->vex_op != 0); + return ((u->vex_op == 0xc4 ? u->vex_b2 : u->vex_b1) >> 2) & 1; +} + +static UD_INLINE uint8_t +vex_w(const struct ud *u) +{ + UD_ASSERT(u->vex_op != 0); + return u->vex_op == 0xc4 ? ((u->vex_b2 >> 7) & 1) : 0; +} + + +static UD_INLINE uint8_t +modrm(struct ud * u) +{ + if ( !u->have_modrm ) { + u->modrm = inp_next( u ); + u->have_modrm = 1; + } + return u->modrm; +} + + +static unsigned int +resolve_operand_size(const struct ud* u, ud_operand_size_t osize) +{ + switch (osize) { + case SZ_V: + return u->opr_mode; + case SZ_Z: + return u->opr_mode == 16 ? 16 : 32; + case SZ_Y: + return u->opr_mode == 16 ? 32 : u->opr_mode; + case SZ_RDQ: + return u->dis_mode == 64 ? 64 : 32; + case SZ_X: + UD_ASSERT(u->vex_op != 0); + return (P_VEXL(u->itab_entry->prefix) && vex_l(u)) ? SZ_QQ : SZ_DQ; + default: + return osize; + } +} + + +static int resolve_mnemonic( struct ud* u ) +{ + /* resolve 3dnow weirdness. */ + if ( u->mnemonic == UD_I3dnow ) { + u->mnemonic = ud_itab[ u->le->table[ inp_curr( u ) ] ].mnemonic; + } + /* SWAPGS is only valid in 64bits mode */ + if ( u->mnemonic == UD_Iswapgs && u->dis_mode != 64 ) { + UDERR(u, "swapgs invalid in 64bits mode\n"); + return -1; + } + + if (u->mnemonic == UD_Ixchg) { + if ((u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_AX && + u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_AX) || + (u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_EAX && + u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_EAX)) { + u->operand[0].type = UD_NONE; + u->operand[1].type = UD_NONE; + u->mnemonic = UD_Inop; + } + } + + if (u->mnemonic == UD_Inop && u->pfx_repe) { + u->pfx_repe = 0; + u->mnemonic = UD_Ipause; + } + return 0; +} + + +/* ----------------------------------------------------------------------------- + * decode_a()- Decodes operands of the type seg:offset + * ----------------------------------------------------------------------------- + */ +static void +decode_a(struct ud* u, struct ud_operand *op) +{ + if (u->opr_mode == 16) { + /* seg16:off16 */ + op->type = UD_OP_PTR; + op->size = 32; + op->lval.ptr.off = inp_uint16(u); + op->lval.ptr.seg = inp_uint16(u); + } else { + /* seg16:off32 */ + op->type = UD_OP_PTR; + op->size = 48; + op->lval.ptr.off = inp_uint32(u); + op->lval.ptr.seg = inp_uint16(u); + } +} + +/* ----------------------------------------------------------------------------- + * decode_gpr() - Returns decoded General Purpose Register + * ----------------------------------------------------------------------------- + */ +static enum ud_type +decode_gpr(/*register*/ struct ud* u, unsigned int s, unsigned char rm) +{ + switch (s) { + case 64: + return (enum ud_type)(UD_R_RAX + rm); + case 32: + return (enum ud_type)(UD_R_EAX + rm); + case 16: + return (enum ud_type)(UD_R_AX + rm); + case 8: + if (u->dis_mode == 64 && u->pfx_rex) { + if (rm >= 4) + return (enum ud_type)(UD_R_SPL + (rm-4)); + return (enum ud_type)(UD_R_AL + rm); + } else return (enum ud_type)(UD_R_AL + rm); + case 0: + /* invalid size in case of a decode error */ + UD_ASSERT(u->error); + return UD_NONE; + default: + UD_ASSERT(!"invalid operand size"); + return UD_NONE; + } +} + +static void +decode_reg(struct ud *u, + struct ud_operand *opr, + int type, + int num, + int size) +{ + int reg; + size = resolve_operand_size(u, size); + switch (type) { + case REGCLASS_GPR : reg = decode_gpr(u, size, num); break; + case REGCLASS_MMX : reg = UD_R_MM0 + (num & 7); break; + case REGCLASS_XMM : + reg = num + (size == SZ_QQ ? UD_R_YMM0 : UD_R_XMM0); + break; + case REGCLASS_CR : reg = UD_R_CR0 + num; break; + case REGCLASS_DB : reg = UD_R_DR0 + num; break; + case REGCLASS_SEG : { + /* + * Only 6 segment registers, anything else is an error. + */ + if ((num & 7) > 5) { + UDERR(u, "invalid segment register value\n"); + return; + } else { + reg = UD_R_ES + (num & 7); + } + break; + } + default: + UD_ASSERT(!"invalid register type"); + return; + } + opr->type = UD_OP_REG; + opr->base = (enum ud_type)(reg); + opr->size = size; +} + + +/* + * decode_imm + * + * Decode Immediate values. + */ +static void +decode_imm(struct ud* u, unsigned int size, struct ud_operand *op) +{ + op->size = resolve_operand_size(u, size); + op->type = UD_OP_IMM; + + switch (op->size) { + case 8: op->lval.sbyte = inp_uint8(u); break; + case 16: op->lval.uword = inp_uint16(u); break; + case 32: op->lval.udword = inp_uint32(u); break; + case 64: op->lval.uqword = inp_uint64(u); break; + default: return; + } +} + + +/* + * decode_mem_disp + * + * Decode mem address displacement. + */ +static void +decode_mem_disp(struct ud* u, unsigned int size, struct ud_operand *op) +{ + switch (size) { + case 8: + op->offset = 8; + op->lval.ubyte = inp_uint8(u); + break; + case 16: + op->offset = 16; + op->lval.uword = inp_uint16(u); + break; + case 32: + op->offset = 32; + op->lval.udword = inp_uint32(u); + break; + case 64: + op->offset = 64; + op->lval.uqword = inp_uint64(u); + break; + default: + return; + } +} + + +/* + * decode_modrm_reg + * + * Decodes reg field of mod/rm byte + * + */ +static UD_INLINE void +decode_modrm_reg(struct ud *u, + struct ud_operand *operand, + unsigned int type, + unsigned int size) +{ + uint8_t reg = (REX_R(u->_rex) << 3) | MODRM_REG(modrm(u)); + decode_reg(u, operand, type, reg, size); +} + + +/* + * decode_modrm_rm + * + * Decodes rm field of mod/rm byte + * + */ +static void +decode_modrm_rm(struct ud *u, + struct ud_operand *op, + unsigned char type, /* register type */ + unsigned int size) /* operand size */ + +{ + size_t offset = 0; + unsigned char mod, rm; + + /* get mod, r/m and reg fields */ + mod = MODRM_MOD(modrm(u)); + rm = (REX_B(u->_rex) << 3) | MODRM_RM(modrm(u)); + + /* + * If mod is 11b, then the modrm.rm specifies a register. + * + */ + if (mod == 3) { + decode_reg(u, op, type, rm, size); + return; + } + + /* + * !11b => Memory Address + */ + op->type = UD_OP_MEM; + op->size = resolve_operand_size(u, size); + + if (u->adr_mode == 64) { + op->base = (enum ud_type)(UD_R_RAX + rm); + if (mod == 1) { + offset = 8; + } else if (mod == 2) { + offset = 32; + } else if (mod == 0 && (rm & 7) == 5) { + op->base = UD_R_RIP; + offset = 32; + } else { + offset = 0; + } + /* + * Scale-Index-Base (SIB) + */ + if ((rm & 7) == 4) { + inp_next(u); + + op->base = (enum ud_type)(UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->_rex) << 3))); + op->index = (enum ud_type)(UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->_rex) << 3))); + /* special conditions for base reference */ + if (op->index == UD_R_RSP) { + op->index = UD_NONE; + op->scale = UD_NONE; + } else { + op->scale = (1 << SIB_S(inp_curr(u))) & ~1; + } + + if (op->base == UD_R_RBP || op->base == UD_R_R13) { + if (mod == 0) { + op->base = UD_NONE; + } + if (mod == 1) { + offset = 8; + } else { + offset = 32; + } + } + } else { + op->scale = UD_NONE; + op->index = UD_NONE; + } + } else if (u->adr_mode == 32) { + op->base = (enum ud_type)(UD_R_EAX + rm); + if (mod == 1) { + offset = 8; + } else if (mod == 2) { + offset = 32; + } else if (mod == 0 && rm == 5) { + op->base = UD_NONE; + offset = 32; + } else { + offset = 0; + } + + /* Scale-Index-Base (SIB) */ + if ((rm & 7) == 4) { + inp_next(u); + + op->scale = (1 << SIB_S(inp_curr(u))) & ~1; + op->index = (enum ud_type)(UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3))); + op->base = (enum ud_type)(UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3))); + + if (op->index == UD_R_ESP) { + op->index = UD_NONE; + op->scale = UD_NONE; + } + + /* special condition for base reference */ + if (op->base == UD_R_EBP) { + if (mod == 0) { + op->base = UD_NONE; + } + if (mod == 1) { + offset = 8; + } else { + offset = 32; + } + } + } else { + op->scale = UD_NONE; + op->index = UD_NONE; + } + } else { + const unsigned int bases[] = { UD_R_BX, UD_R_BX, UD_R_BP, UD_R_BP, + UD_R_SI, UD_R_DI, UD_R_BP, UD_R_BX }; + const unsigned int indices[] = { UD_R_SI, UD_R_DI, UD_R_SI, UD_R_DI, + UD_NONE, UD_NONE, UD_NONE, UD_NONE }; + op->base = (enum ud_type)(bases[rm & 7]); + op->index = (enum ud_type)(indices[rm & 7]); + op->scale = UD_NONE; + if (mod == 0 && rm == 6) { + offset = 16; + op->base = UD_NONE; + } else if (mod == 1) { + offset = 8; + } else if (mod == 2) { + offset = 16; + } + } + + if (offset) { + decode_mem_disp(u, offset, op); + } else { + op->offset = 0; + } +} + + +/* + * decode_moffset + * Decode offset-only memory operand + */ +static void +decode_moffset(struct ud *u, unsigned int size, struct ud_operand *opr) +{ + opr->type = UD_OP_MEM; + opr->base = UD_NONE; + opr->index = UD_NONE; + opr->scale = UD_NONE; + opr->size = resolve_operand_size(u, size); + decode_mem_disp(u, u->adr_mode, opr); +} + + +static void +decode_vex_vvvv(struct ud *u, struct ud_operand *opr, unsigned size) +{ + uint8_t vvvv; + UD_ASSERT(u->vex_op != 0); + vvvv = ((u->vex_op == 0xc4 ? u->vex_b2 : u->vex_b1) >> 3) & 0xf; + decode_reg(u, opr, REGCLASS_XMM, (0xf & ~vvvv), size); +} + + +/* + * decode_vex_immreg + * Decode source operand encoded in immediate byte [7:4] + */ +static int +decode_vex_immreg(struct ud *u, struct ud_operand *opr, unsigned size) +{ + uint8_t imm = inp_next(u); + uint8_t mask = u->dis_mode == 64 ? 0xf : 0x7; + UD_RETURN_ON_ERROR(u); + UD_ASSERT(u->vex_op != 0); + decode_reg(u, opr, REGCLASS_XMM, mask & (imm >> 4), size); + return 0; +} + + +/* + * decode_operand + * + * Decodes a single operand. + * Returns the type of the operand (UD_NONE if none) + */ +static int +decode_operand(struct ud *u, + struct ud_operand *operand, + enum ud_operand_code type, + unsigned int size) +{ + operand->type = UD_NONE; + operand->_oprcode = type; + + switch (type) { + case OP_A : + decode_a(u, operand); + break; + case OP_MR: + decode_modrm_rm(u, operand, REGCLASS_GPR, + MODRM_MOD(modrm(u)) == 3 ? + Mx_reg_size(size) : Mx_mem_size(size)); + break; + case OP_F: + u->br_far = 1; + /* intended fall through */ + case OP_M: + if (MODRM_MOD(modrm(u)) == 3) { + UDERR(u, "expected modrm.mod != 3\n"); + } + /* intended fall through */ + case OP_E: + decode_modrm_rm(u, operand, REGCLASS_GPR, size); + break; + case OP_G: + decode_modrm_reg(u, operand, REGCLASS_GPR, size); + break; + case OP_sI: + case OP_I: + decode_imm(u, size, operand); + break; + case OP_I1: + operand->type = UD_OP_CONST; + operand->lval.udword = 1; + break; + case OP_N: + if (MODRM_MOD(modrm(u)) != 3) { + UDERR(u, "expected modrm.mod == 3\n"); + } + /* intended fall through */ + case OP_Q: + decode_modrm_rm(u, operand, REGCLASS_MMX, size); + break; + case OP_P: + decode_modrm_reg(u, operand, REGCLASS_MMX, size); + break; + case OP_U: + if (MODRM_MOD(modrm(u)) != 3) { + UDERR(u, "expected modrm.mod == 3\n"); + } + /* intended fall through */ + case OP_W: + decode_modrm_rm(u, operand, REGCLASS_XMM, size); + break; + case OP_V: + decode_modrm_reg(u, operand, REGCLASS_XMM, size); + break; + case OP_H: + decode_vex_vvvv(u, operand, size); + break; + case OP_MU: + decode_modrm_rm(u, operand, REGCLASS_XMM, + MODRM_MOD(modrm(u)) == 3 ? + Mx_reg_size(size) : Mx_mem_size(size)); + break; + case OP_S: + decode_modrm_reg(u, operand, REGCLASS_SEG, size); + break; + case OP_O: + decode_moffset(u, size, operand); + break; + case OP_R0: + case OP_R1: + case OP_R2: + case OP_R3: + case OP_R4: + case OP_R5: + case OP_R6: + case OP_R7: + decode_reg(u, operand, REGCLASS_GPR, + (REX_B(u->_rex) << 3) | (type - OP_R0), size); + break; + case OP_AL: + case OP_AX: + case OP_eAX: + case OP_rAX: + decode_reg(u, operand, REGCLASS_GPR, 0, size); + break; + case OP_CL: + case OP_CX: + case OP_eCX: + decode_reg(u, operand, REGCLASS_GPR, 1, size); + break; + case OP_DL: + case OP_DX: + case OP_eDX: + decode_reg(u, operand, REGCLASS_GPR, 2, size); + break; + case OP_ES: + case OP_CS: + case OP_DS: + case OP_SS: + case OP_FS: + case OP_GS: + /* in 64bits mode, only fs and gs are allowed */ + if (u->dis_mode == 64) { + if (type != OP_FS && type != OP_GS) { + UDERR(u, "invalid segment register in 64bits\n"); + } + } + operand->type = UD_OP_REG; + operand->base = (enum ud_type)((type - OP_ES) + UD_R_ES); + operand->size = 16; + break; + case OP_J : + decode_imm(u, size, operand); + operand->type = UD_OP_JIMM; + break ; + case OP_R : + if (MODRM_MOD(modrm(u)) != 3) { + UDERR(u, "expected modrm.mod == 3\n"); + } + decode_modrm_rm(u, operand, REGCLASS_GPR, size); + break; + case OP_C: + decode_modrm_reg(u, operand, REGCLASS_CR, size); + break; + case OP_D: + decode_modrm_reg(u, operand, REGCLASS_DB, size); + break; + case OP_I3 : + operand->type = UD_OP_CONST; + operand->lval.sbyte = 3; + break; + case OP_ST0: + case OP_ST1: + case OP_ST2: + case OP_ST3: + case OP_ST4: + case OP_ST5: + case OP_ST6: + case OP_ST7: + operand->type = UD_OP_REG; + operand->base = (enum ud_type)((type - OP_ST0) + UD_R_ST0); + operand->size = 80; + break; + case OP_L: + decode_vex_immreg(u, operand, size); + break; + default : + operand->type = UD_NONE; + break; + } + return operand->type; +} + + +/* + * decode_operands + * + * Disassemble upto 3 operands of the current instruction being + * disassembled. By the end of the function, the operand fields + * of the ud structure will have been filled. + */ +static int +decode_operands(struct ud* u) +{ + decode_operand(u, &u->operand[0], + u->itab_entry->operand1.type, + u->itab_entry->operand1.size); + if (u->operand[0].type != UD_NONE) { + decode_operand(u, &u->operand[1], + u->itab_entry->operand2.type, + u->itab_entry->operand2.size); + } + if (u->operand[1].type != UD_NONE) { + decode_operand(u, &u->operand[2], + u->itab_entry->operand3.type, + u->itab_entry->operand3.size); + } + if (u->operand[2].type != UD_NONE) { + decode_operand(u, &u->operand[3], + u->itab_entry->operand4.type, + u->itab_entry->operand4.size); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * clear_insn() - clear instruction structure + * ----------------------------------------------------------------------------- + */ +static void +clear_insn(register struct ud* u) +{ + u->error = 0; + u->pfx_seg = 0; + u->pfx_opr = 0; + u->pfx_adr = 0; + u->pfx_lock = 0; + u->pfx_repne = 0; + u->pfx_rep = 0; + u->pfx_repe = 0; + u->pfx_rex = 0; + u->pfx_str = 0; + u->mnemonic = UD_Inone; + u->itab_entry = NULL; + u->have_modrm = 0; + u->br_far = 0; + u->vex_op = 0; + u->_rex = 0; + u->operand[0].type = UD_NONE; + u->operand[1].type = UD_NONE; + u->operand[2].type = UD_NONE; + u->operand[3].type = UD_NONE; +} + + +static UD_INLINE int +resolve_pfx_str(struct ud* u) +{ + if (u->pfx_str == 0xf3) { + if (P_STR(u->itab_entry->prefix)) { + u->pfx_rep = 0xf3; + } else { + u->pfx_repe = 0xf3; + } + } else if (u->pfx_str == 0xf2) { + u->pfx_repne = 0xf3; + } + return 0; +} + + +static int +resolve_mode( struct ud* u ) +{ + /* if in error state, bail out */ + if ( u->error ) return -1; + + /* propagate prefix effects */ + if ( u->dis_mode == 64 ) { /* set 64bit-mode flags */ + + /* Check validity of instruction m64 */ + if ( P_INV64( u->itab_entry->prefix ) ) { + UDERR(u, "instruction invalid in 64bits\n"); + return -1; + } + + /* compute effective rex based on, + * - vex prefix (if any) + * - rex prefix (if any, and not vex) + * - allowed prefixes specified by the opcode map + */ + if (u->vex_op == 0xc4) { + /* vex has rex.rxb in 1's complement */ + u->_rex = ((~(u->vex_b1 >> 5) & 0x7) /* rex.0rxb */ | + ((u->vex_b2 >> 4) & 0x8) /* rex.w000 */); + } else if (u->vex_op == 0xc5) { + /* vex has rex.r in 1's complement */ + u->_rex = (~(u->vex_b1 >> 5)) & 4; + } else { + UD_ASSERT(u->vex_op == 0); + u->_rex = u->pfx_rex; + } + u->_rex &= REX_PFX_MASK(u->itab_entry->prefix); + + /* whether this instruction has a default operand size of + * 64bit, also hardcoded into the opcode map. + */ + int default64 = P_DEF64( u->itab_entry->prefix ); + /* calculate effective operand size */ + if (REX_W(u->_rex)) { + u->opr_mode = 64; + } else if ( u->pfx_opr ) { + u->opr_mode = 16; + } else { + /* unless the default opr size of instruction is 64, + * the effective operand size in the absence of rex.w + * prefix is 32. + */ + u->opr_mode = default64 ? 64 : 32; + } + + /* calculate effective address size */ + u->adr_mode = (u->pfx_adr) ? 32 : 64; + } else if ( u->dis_mode == 32 ) { /* set 32bit-mode flags */ + u->opr_mode = ( u->pfx_opr ) ? 16 : 32; + u->adr_mode = ( u->pfx_adr ) ? 16 : 32; + } else if ( u->dis_mode == 16 ) { /* set 16bit-mode flags */ + u->opr_mode = ( u->pfx_opr ) ? 32 : 16; + u->adr_mode = ( u->pfx_adr ) ? 32 : 16; + } + + return 0; +} + + +static UD_INLINE int +decode_insn(struct ud *u, uint16_t ptr) +{ + UD_ASSERT((ptr & 0x8000) == 0); + u->itab_entry = &ud_itab[ ptr ]; + u->mnemonic = u->itab_entry->mnemonic; + return (resolve_pfx_str(u) == 0 && + resolve_mode(u) == 0 && + decode_operands(u) == 0 && + resolve_mnemonic(u) == 0) ? 0 : -1; +} + + +/* + * decode_3dnow() + * + * Decoding 3dnow is a little tricky because of its strange opcode + * structure. The final opcode disambiguation depends on the last + * byte that comes after the operands have been decoded. Fortunately, + * all 3dnow instructions have the same set of operand types. So we + * go ahead and decode the instruction by picking an arbitrarily chosen + * valid entry in the table, decode the operands, and read the final + * byte to resolve the menmonic. + */ +static UD_INLINE int +decode_3dnow(struct ud* u) +{ + uint16_t ptr; + UD_ASSERT(u->le->type == UD_TAB__OPC_3DNOW); + UD_ASSERT(u->le->table[0xc] != 0); + decode_insn(u, u->le->table[0xc]); + inp_next(u); + if (u->error) { + return -1; + } + ptr = u->le->table[inp_curr(u)]; + UD_ASSERT((ptr & 0x8000) == 0); + u->mnemonic = ud_itab[ptr].mnemonic; + return 0; +} + + +static int +decode_ssepfx(struct ud *u) +{ + uint8_t idx; + uint8_t pfx; + + /* + * String prefixes (f2, f3) take precedence over operand + * size prefix (66). + */ + pfx = u->pfx_str; + if (pfx == 0) { + pfx = u->pfx_opr; + } + idx = ((pfx & 0xf) + 1) / 2; + if (u->le->table[idx] == 0) { + idx = 0; + } + if (idx && u->le->table[idx] != 0) { + /* + * "Consume" the prefix as a part of the opcode, so it is no + * longer exported as an instruction prefix. + */ + u->pfx_str = 0; + if (pfx == 0x66) { + /* + * consume "66" only if it was used for decoding, leaving + * it to be used as an operands size override for some + * simd instructions. + */ + u->pfx_opr = 0; + } + } + return decode_ext(u, u->le->table[idx]); +} + + +static int +decode_vex(struct ud *u) +{ + uint8_t index; + if (u->dis_mode != 64 && MODRM_MOD(inp_peek(u)) != 0x3) { + index = 0; + } else { + u->vex_op = inp_curr(u); + u->vex_b1 = inp_next(u); + if (u->vex_op == 0xc4) { + uint8_t pp, m; + /* 3-byte vex */ + u->vex_b2 = inp_next(u); + UD_RETURN_ON_ERROR(u); + m = u->vex_b1 & 0x1f; + if (m == 0 || m > 3) { + UD_RETURN_WITH_ERROR(u, "reserved vex.m-mmmm value"); + } + pp = u->vex_b2 & 0x3; + index = (pp << 2) | m; + } else { + /* 2-byte vex */ + UD_ASSERT(u->vex_op == 0xc5); + index = 0x1 | ((u->vex_b1 & 0x3) << 2); + } + } + return decode_ext(u, u->le->table[index]); +} + + +/* + * decode_ext() + * + * Decode opcode extensions (if any) + */ +static int +decode_ext(struct ud *u, uint16_t ptr) +{ + uint8_t idx = 0; + if ((ptr & 0x8000) == 0) { + return decode_insn(u, ptr); + } + u->le = &ud_lookup_table_list[(~0x8000 & ptr)]; + if (u->le->type == UD_TAB__OPC_3DNOW) { + return decode_3dnow(u); + } + + switch (u->le->type) { + case UD_TAB__OPC_MOD: + /* !11 = 0, 11 = 1 */ + idx = (MODRM_MOD(modrm(u)) + 1) / 4; + break; + /* disassembly mode/operand size/address size based tables. + * 16 = 0,, 32 = 1, 64 = 2 + */ + case UD_TAB__OPC_MODE: + idx = u->dis_mode != 64 ? 0 : 1; + break; + case UD_TAB__OPC_OSIZE: + idx = eff_opr_mode(u->dis_mode, REX_W(u->pfx_rex), u->pfx_opr) / 32; + break; + case UD_TAB__OPC_ASIZE: + idx = eff_adr_mode(u->dis_mode, u->pfx_adr) / 32; + break; + case UD_TAB__OPC_X87: + idx = modrm(u) - 0xC0; + break; + case UD_TAB__OPC_VENDOR: + if (u->vendor == UD_VENDOR_ANY) { + /* choose a valid entry */ + idx = (u->le->table[idx] != 0) ? 0 : 1; + } else if (u->vendor == UD_VENDOR_AMD) { + idx = 0; + } else { + idx = 1; + } + break; + case UD_TAB__OPC_RM: + idx = MODRM_RM(modrm(u)); + break; + case UD_TAB__OPC_REG: + idx = MODRM_REG(modrm(u)); + break; + case UD_TAB__OPC_SSE: + return decode_ssepfx(u); + case UD_TAB__OPC_VEX: + return decode_vex(u); + case UD_TAB__OPC_VEX_W: + idx = vex_w(u); + break; + case UD_TAB__OPC_VEX_L: + idx = vex_l(u); + break; + case UD_TAB__OPC_TABLE: + inp_next(u); + return decode_opcode(u); + default: + UD_ASSERT(!"not reached"); + break; + } + + return decode_ext(u, u->le->table[idx]); +} + + +static int +decode_opcode(struct ud *u) +{ + uint16_t ptr; + UD_ASSERT(u->le->type == UD_TAB__OPC_TABLE); + UD_RETURN_ON_ERROR(u); + ptr = u->le->table[inp_curr(u)]; + return decode_ext(u, ptr); +} + + +/* ============================================================================= + * ud_decode() - Instruction decoder. Returns the number of bytes decoded. + * ============================================================================= + */ +unsigned int +ud_decode(struct ud *u) +{ + inp_start(u); + clear_insn(u); + u->le = &ud_lookup_table_list[0]; + u->error = decode_prefixes(u) == -1 || + decode_opcode(u) == -1 || + u->error; + /* Handle decode error. */ + if (u->error) { + /* clear out the decode data. */ + clear_insn(u); + /* mark the sequence of bytes as invalid. */ + u->itab_entry = &ud_itab[0]; /* entry 0 is invalid */ + u->mnemonic = u->itab_entry->mnemonic; + } + + /* maybe this stray segment override byte + * should be spewed out? + */ + if ( !P_SEG( u->itab_entry->prefix ) && + u->operand[0].type != UD_OP_MEM && + u->operand[1].type != UD_OP_MEM ) + u->pfx_seg = 0; + + u->insn_offset = u->pc; /* set offset of instruction */ + u->asm_buf_fill = 0; /* set translation buffer index to 0 */ + u->pc += u->inp_ctr; /* move program counter by bytes decoded */ + + /* return number of bytes disassembled. */ + return u->inp_ctr; +} + +/* +vim: set ts=2 sw=2 expandtab +*/ diff --git a/src/third_party/udis86/libudis86/decode.h b/src/third_party/udis86/libudis86/decode.h new file mode 100644 index 00000000..3949c4e2 --- /dev/null +++ b/src/third_party/udis86/libudis86/decode.h @@ -0,0 +1,197 @@ +/* udis86 - libudis86/decode.h + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef UD_DECODE_H +#define UD_DECODE_H + +#include "types.h" +#include "udint.h" +#include "itab.h" + +#define MAX_INSN_LENGTH 15 + +/* itab prefix bits */ +#define P_none ( 0 ) + +#define P_inv64 ( 1 << 0 ) +#define P_INV64(n) ( ( n >> 0 ) & 1 ) +#define P_def64 ( 1 << 1 ) +#define P_DEF64(n) ( ( n >> 1 ) & 1 ) + +#define P_oso ( 1 << 2 ) +#define P_OSO(n) ( ( n >> 2 ) & 1 ) +#define P_aso ( 1 << 3 ) +#define P_ASO(n) ( ( n >> 3 ) & 1 ) + +#define P_rexb ( 1 << 4 ) +#define P_REXB(n) ( ( n >> 4 ) & 1 ) +#define P_rexw ( 1 << 5 ) +#define P_REXW(n) ( ( n >> 5 ) & 1 ) +#define P_rexr ( 1 << 6 ) +#define P_REXR(n) ( ( n >> 6 ) & 1 ) +#define P_rexx ( 1 << 7 ) +#define P_REXX(n) ( ( n >> 7 ) & 1 ) + +#define P_seg ( 1 << 8 ) +#define P_SEG(n) ( ( n >> 8 ) & 1 ) + +#define P_vexl ( 1 << 9 ) +#define P_VEXL(n) ( ( n >> 9 ) & 1 ) +#define P_vexw ( 1 << 10 ) +#define P_VEXW(n) ( ( n >> 10 ) & 1 ) + +#define P_str ( 1 << 11 ) +#define P_STR(n) ( ( n >> 11 ) & 1 ) +#define P_strz ( 1 << 12 ) +#define P_STR_ZF(n) ( ( n >> 12 ) & 1 ) + +/* operand type constants -- order is important! */ + +enum ud_operand_code { + OP_NONE, + + OP_A, OP_E, OP_M, OP_G, + OP_I, OP_F, + + OP_R0, OP_R1, OP_R2, OP_R3, + OP_R4, OP_R5, OP_R6, OP_R7, + + OP_AL, OP_CL, OP_DL, + OP_AX, OP_CX, OP_DX, + OP_eAX, OP_eCX, OP_eDX, + OP_rAX, OP_rCX, OP_rDX, + + OP_ES, OP_CS, OP_SS, OP_DS, + OP_FS, OP_GS, + + OP_ST0, OP_ST1, OP_ST2, OP_ST3, + OP_ST4, OP_ST5, OP_ST6, OP_ST7, + + OP_J, OP_S, OP_O, + OP_I1, OP_I3, OP_sI, + + OP_V, OP_W, OP_Q, OP_P, + OP_U, OP_N, OP_MU, OP_H, + OP_L, + + OP_R, OP_C, OP_D, + + OP_MR +} UD_ATTR_PACKED; + + +/* + * Operand size constants + * + * Symbolic constants for various operand sizes. Some of these constants + * are given a value equal to the width of the data (SZ_B == 8), such + * that they maybe used interchangeably in the internals. Modifying them + * will most certainly break things! + */ +typedef uint16_t ud_operand_size_t; + +#define SZ_NA 0 +#define SZ_Z 1 +#define SZ_V 2 +#define SZ_Y 3 +#define SZ_X 4 +#define SZ_RDQ 7 +#define SZ_B 8 +#define SZ_W 16 +#define SZ_D 32 +#define SZ_Q 64 +#define SZ_T 80 +#define SZ_O 12 +#define SZ_DQ 128 /* double quad */ +#define SZ_QQ 256 /* quad quad */ + +/* + * Complex size types; that encode sizes for operands of type MR (memory or + * register); for internal use only. Id space above 256. + */ +#define SZ_BD ((SZ_B << 8) | SZ_D) +#define SZ_BV ((SZ_B << 8) | SZ_V) +#define SZ_WD ((SZ_W << 8) | SZ_D) +#define SZ_WV ((SZ_W << 8) | SZ_V) +#define SZ_WY ((SZ_W << 8) | SZ_Y) +#define SZ_DY ((SZ_D << 8) | SZ_Y) +#define SZ_WO ((SZ_W << 8) | SZ_O) +#define SZ_DO ((SZ_D << 8) | SZ_O) +#define SZ_QO ((SZ_Q << 8) | SZ_O) + + +/* resolve complex size type. + */ +static UD_INLINE ud_operand_size_t +Mx_mem_size(ud_operand_size_t size) +{ + return (size >> 8) & 0xff; +} + +static UD_INLINE ud_operand_size_t +Mx_reg_size(ud_operand_size_t size) +{ + return size & 0xff; +} + +/* A single operand of an entry in the instruction table. + * (internal use only) + */ +struct ud_itab_entry_operand +{ + enum ud_operand_code type; + ud_operand_size_t size; +}; + + +/* A single entry in an instruction table. + *(internal use only) + */ +struct ud_itab_entry +{ + enum ud_mnemonic_code mnemonic; + struct ud_itab_entry_operand operand1; + struct ud_itab_entry_operand operand2; + struct ud_itab_entry_operand operand3; + struct ud_itab_entry_operand operand4; + uint32_t prefix; +}; + +struct ud_lookup_table_list_entry { + const uint16_t *table; + enum ud_table_type type; + const char *meta; +}; + +extern struct ud_itab_entry ud_itab[]; +extern struct ud_lookup_table_list_entry ud_lookup_table_list[]; + +#endif /* UD_DECODE_H */ + +/* vim:cindent + * vim:expandtab + * vim:ts=4 + * vim:sw=4 + */ diff --git a/src/third_party/udis86/libudis86/extern.h b/src/third_party/udis86/libudis86/extern.h new file mode 100644 index 00000000..ba1c0b34 --- /dev/null +++ b/src/third_party/udis86/libudis86/extern.h @@ -0,0 +1,113 @@ +/* udis86 - libudis86/extern.h + * + * Copyright (c) 2002-2009, 2013 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef UD_EXTERN_H +#define UD_EXTERN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +#if defined(_MSC_VER) && defined(_USRDLL) +# ifdef LIBUDIS86_EXPORTS +# define LIBUDIS86_DLLEXTERN __declspec(dllexport) +# else +# define LIBUDIS86_DLLEXTERN __declspec(dllimport) +# endif +#else +# define LIBUDIS86_DLLEXTERN +#endif + + /* ============================= PUBLIC API ================================= */ + + extern LIBUDIS86_DLLEXTERN void ud_init(struct ud*); + + extern LIBUDIS86_DLLEXTERN void ud_set_mode(struct ud*, uint8_t); + + extern LIBUDIS86_DLLEXTERN void ud_set_pc(struct ud*, uint64_t); + + extern LIBUDIS86_DLLEXTERN void ud_set_input_hook(struct ud*, int (*)(struct ud*)); + + extern LIBUDIS86_DLLEXTERN void ud_set_input_buffer(struct ud*, const uint8_t*, size_t); + +#ifndef __UD_STANDALONE__ + extern LIBUDIS86_DLLEXTERN void ud_set_input_file(struct ud*, FILE*); +#endif /* __UD_STANDALONE__ */ + + extern LIBUDIS86_DLLEXTERN void ud_set_vendor(struct ud*, unsigned); + + extern LIBUDIS86_DLLEXTERN void ud_set_syntax(struct ud*, void (*)(struct ud*)); + + extern LIBUDIS86_DLLEXTERN void ud_input_skip(struct ud*, size_t); + + extern LIBUDIS86_DLLEXTERN int ud_input_end(const struct ud*); + + extern LIBUDIS86_DLLEXTERN unsigned int ud_decode(struct ud*); + + extern LIBUDIS86_DLLEXTERN unsigned int ud_disassemble(struct ud*); + + extern LIBUDIS86_DLLEXTERN void ud_translate_intel(struct ud*); + + extern LIBUDIS86_DLLEXTERN void ud_translate_att(struct ud*); + + extern LIBUDIS86_DLLEXTERN const char* ud_insn_asm(const struct ud* u); + + extern LIBUDIS86_DLLEXTERN const uint8_t* ud_insn_ptr(const struct ud* u); + + extern LIBUDIS86_DLLEXTERN uint64_t ud_insn_off(const struct ud*); + + extern LIBUDIS86_DLLEXTERN const char* ud_insn_hex(struct ud*); + + extern LIBUDIS86_DLLEXTERN unsigned int ud_insn_len(const struct ud* u); + + extern LIBUDIS86_DLLEXTERN const struct ud_operand* ud_insn_opr(const struct ud *u, unsigned int n); + + extern LIBUDIS86_DLLEXTERN int ud_opr_is_sreg(const struct ud_operand *opr); + + extern LIBUDIS86_DLLEXTERN int ud_opr_is_gpr(const struct ud_operand *opr); + + extern LIBUDIS86_DLLEXTERN enum ud_mnemonic_code ud_insn_mnemonic(const struct ud *u); + + extern LIBUDIS86_DLLEXTERN const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); + + extern LIBUDIS86_DLLEXTERN void ud_set_user_opaque_data(struct ud*, void*); + + extern LIBUDIS86_DLLEXTERN void* ud_get_user_opaque_data(const struct ud*); + + extern LIBUDIS86_DLLEXTERN void ud_set_asm_buffer(struct ud *u, char *buf, size_t size); + + extern LIBUDIS86_DLLEXTERN void ud_set_sym_resolver(struct ud *u, + const char* (*resolver)(struct ud*, + uint64_t addr, + int64_t *offset)); + + /* ========================================================================== */ + +#ifdef __cplusplus +} +#endif +#endif /* UD_EXTERN_H */ diff --git a/src/third_party/udis86/libudis86/itab.c b/src/third_party/udis86/libudis86/itab.c new file mode 100644 index 00000000..7ea0569e --- /dev/null +++ b/src/third_party/udis86/libudis86/itab.c @@ -0,0 +1,5937 @@ +/* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */ +#include "decode.h" + +#define GROUP(n) (0x8000 | (n)) +#define INVALID 0 + + +const uint16_t ud_itab__0[] = { + /* 0 */ 15, 16, 17, 18, + /* 4 */ 19, 20, GROUP(1), GROUP(2), + /* 8 */ 960, 961, 962, 963, + /* c */ 964, 965, GROUP(3), GROUP(4), + /* 10 */ 5, 6, 7, 8, + /* 14 */ 9, 10, GROUP(284), GROUP(285), + /* 18 */ 1332, 1333, 1334, 1335, + /* 1c */ 1336, 1337, GROUP(286), GROUP(287), + /* 20 */ 49, 50, 51, 52, + /* 24 */ 53, 54, INVALID, GROUP(288), + /* 28 */ 1403, 1404, 1405, 1406, + /* 2c */ 1407, 1408, INVALID, GROUP(289), + /* 30 */ 1483, 1484, 1485, 1486, + /* 34 */ 1487, 1488, INVALID, GROUP(290), + /* 38 */ 100, 101, 102, 103, + /* 3c */ 104, 105, INVALID, GROUP(291), + /* 40 */ 695, 696, 697, 698, + /* 44 */ 699, 700, 701, 702, + /* 48 */ 175, 176, 177, 178, + /* 4c */ 179, 180, 181, 182, + /* 50 */ 1242, 1243, 1244, 1245, + /* 54 */ 1246, 1247, 1248, 1249, + /* 58 */ 1097, 1098, 1099, 1100, + /* 5c */ 1101, 1102, 1103, 1104, + /* 60 */ GROUP(292), GROUP(295), GROUP(298), GROUP(299), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ 1250, 693, 1252, 694, + /* 6c */ 705, GROUP(300), 978, GROUP(301), + /* 70 */ 722, 724, 726, 728, + /* 74 */ 730, 732, 734, 736, + /* 78 */ 738, 740, 742, 744, + /* 7c */ 746, 748, 750, 752, + /* 80 */ GROUP(302), GROUP(303), GROUP(304), GROUP(313), + /* 84 */ 1429, 1430, 1471, 1472, + /* 88 */ 824, 825, 826, 827, + /* 8c */ 828, 766, 829, GROUP(314), + /* 90 */ 1473, 1474, 1475, 1476, + /* 94 */ 1477, 1478, 1479, 1480, + /* 98 */ GROUP(315), GROUP(316), GROUP(317), 1466, + /* 9c */ GROUP(318), GROUP(322), 1306, 762, + /* a0 */ 830, 831, 832, 833, + /* a4 */ 918, GROUP(326), 114, GROUP(327), + /* a8 */ 1431, 1432, 1398, GROUP(328), + /* ac */ 786, GROUP(329), 1342, GROUP(330), + /* b0 */ 834, 835, 836, 837, + /* b4 */ 838, 839, 840, 841, + /* b8 */ 842, 843, 844, 845, + /* bc */ 846, 847, 848, 849, + /* c0 */ GROUP(331), GROUP(332), 1297, 1298, + /* c4 */ GROUP(333), GROUP(403), GROUP(405), GROUP(406), + /* c8 */ 200, 772, 1299, 1300, + /* cc */ 709, 710, GROUP(407), GROUP(408), + /* d0 */ GROUP(409), GROUP(410), GROUP(411), GROUP(412), + /* d4 */ GROUP(413), GROUP(414), GROUP(415), 1482, + /* d8 */ GROUP(416), GROUP(419), GROUP(422), GROUP(425), + /* dc */ GROUP(428), GROUP(431), GROUP(434), GROUP(437), + /* e0 */ 790, 791, 792, GROUP(440), + /* e4 */ 686, 687, 974, 975, + /* e8 */ 72, 759, GROUP(441), 761, + /* ec */ 688, 689, 976, 977, + /* f0 */ 785, 708, 1295, 1296, + /* f4 */ 683, 83, GROUP(442), GROUP(443), + /* f8 */ 77, 1391, 81, 1394, + /* fc */ 78, 1392, GROUP(444), GROUP(445), +}; + +static const uint16_t ud_itab__1[] = { + /* 0 */ 1236, INVALID, +}; + +static const uint16_t ud_itab__2[] = { + /* 0 */ 1092, INVALID, +}; + +static const uint16_t ud_itab__3[] = { + /* 0 */ 1237, INVALID, +}; + +static const uint16_t ud_itab__4[] = { + /* 0 */ GROUP(5), GROUP(6), 763, 793, + /* 4 */ INVALID, 1422, 82, 1427, + /* 8 */ 712, 1467, INVALID, 1440, + /* c */ INVALID, GROUP(27), 430, GROUP(28), + /* 10 */ GROUP(29), GROUP(30), GROUP(31), GROUP(34), + /* 14 */ GROUP(35), GROUP(36), GROUP(37), GROUP(40), + /* 18 */ GROUP(41), 951, 952, 953, + /* 1c */ 954, 955, 956, 957, + /* 20 */ 850, 851, 852, 853, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ GROUP(42), GROUP(43), GROUP(44), GROUP(45), + /* 2c */ GROUP(46), GROUP(47), GROUP(48), GROUP(49), + /* 30 */ 1468, 1293, 1291, 1292, + /* 34 */ GROUP(50), GROUP(52), INVALID, 1510, + /* 38 */ GROUP(54), INVALID, GROUP(116), INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 84, 85, 86, 87, + /* 44 */ 88, 89, 90, 91, + /* 48 */ 92, 93, 94, 95, + /* 4c */ 96, 97, 98, 99, + /* 50 */ GROUP(143), GROUP(144), GROUP(145), GROUP(146), + /* 54 */ GROUP(147), GROUP(148), GROUP(149), GROUP(150), + /* 58 */ GROUP(151), GROUP(152), GROUP(153), GROUP(154), + /* 5c */ GROUP(155), GROUP(156), GROUP(157), GROUP(158), + /* 60 */ GROUP(159), GROUP(160), GROUP(161), GROUP(162), + /* 64 */ GROUP(163), GROUP(164), GROUP(165), GROUP(166), + /* 68 */ GROUP(167), GROUP(168), GROUP(169), GROUP(170), + /* 6c */ GROUP(171), GROUP(172), GROUP(173), GROUP(176), + /* 70 */ GROUP(177), GROUP(178), GROUP(182), GROUP(186), + /* 74 */ GROUP(191), GROUP(192), GROUP(193), 199, + /* 78 */ GROUP(194), GROUP(195), INVALID, INVALID, + /* 7c */ GROUP(196), GROUP(197), GROUP(198), GROUP(201), + /* 80 */ 723, 725, 727, 729, + /* 84 */ 731, 733, 735, 737, + /* 88 */ 739, 741, 743, 745, + /* 8c */ 747, 749, 751, 753, + /* 90 */ 1346, 1347, 1348, 1349, + /* 94 */ 1350, 1351, 1352, 1353, + /* 98 */ 1354, 1355, 1356, 1357, + /* 9c */ 1358, 1359, 1360, 1361, + /* a0 */ 1241, 1096, 131, 1665, + /* a4 */ 1371, 1372, GROUP(202), GROUP(207), + /* a8 */ 1240, 1095, 1301, 1670, + /* ac */ 1373, 1374, GROUP(215), 690, + /* b0 */ 122, 123, 771, 1668, + /* b4 */ 768, 769, 936, 937, + /* b8 */ GROUP(221), INVALID, GROUP(222), 1666, + /* bc */ 1654, 1655, 926, 927, + /* c0 */ 1469, 1470, GROUP(223), 900, + /* c4 */ GROUP(224), GROUP(225), GROUP(226), GROUP(227), + /* c8 */ 1656, 1657, 1658, 1659, + /* cc */ 1660, 1661, 1662, 1663, + /* d0 */ GROUP(236), GROUP(237), GROUP(238), GROUP(239), + /* d4 */ GROUP(240), GROUP(241), GROUP(242), GROUP(243), + /* d8 */ GROUP(244), GROUP(245), GROUP(246), GROUP(247), + /* dc */ GROUP(248), GROUP(249), GROUP(250), GROUP(251), + /* e0 */ GROUP(252), GROUP(253), GROUP(254), GROUP(255), + /* e4 */ GROUP(256), GROUP(257), GROUP(258), GROUP(259), + /* e8 */ GROUP(260), GROUP(261), GROUP(262), GROUP(263), + /* ec */ GROUP(264), GROUP(265), GROUP(266), GROUP(267), + /* f0 */ GROUP(268), GROUP(269), GROUP(270), GROUP(271), + /* f4 */ GROUP(272), GROUP(273), GROUP(274), GROUP(275), + /* f8 */ GROUP(277), GROUP(278), GROUP(279), GROUP(280), + /* fc */ GROUP(281), GROUP(282), GROUP(283), INVALID, +}; + +static const uint16_t ud_itab__5[] = { + /* 0 */ 1380, 1402, 782, 794, + /* 4 */ 1449, 1450, INVALID, INVALID, +}; + +static const uint16_t ud_itab__6[] = { + /* 0 */ GROUP(7), GROUP(8), +}; + +static const uint16_t ud_itab__7[] = { + /* 0 */ 1370, 1379, 781, 770, + /* 4 */ 1381, INVALID, 783, 715, +}; + +static const uint16_t ud_itab__8[] = { + /* 0 */ GROUP(9), GROUP(14), GROUP(15), GROUP(16), + /* 4 */ 1382, INVALID, 784, GROUP(25), +}; + +static const uint16_t ud_itab__9[] = { + /* 0 */ INVALID, GROUP(10), GROUP(11), GROUP(12), + /* 4 */ GROUP(13), INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__10[] = { + /* 0 */ INVALID, 1451, INVALID, +}; + +static const uint16_t ud_itab__11[] = { + /* 0 */ INVALID, 1457, INVALID, +}; + +static const uint16_t ud_itab__12[] = { + /* 0 */ INVALID, 1458, INVALID, +}; + +static const uint16_t ud_itab__13[] = { + /* 0 */ INVALID, 1459, INVALID, +}; + +static const uint16_t ud_itab__14[] = { + /* 0 */ 820, 948, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__15[] = { + /* 0 */ 1481, 1504, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__16[] = { + /* 0 */ GROUP(17), GROUP(18), GROUP(19), GROUP(20), + /* 4 */ GROUP(21), GROUP(22), GROUP(23), GROUP(24), +}; + +static const uint16_t ud_itab__17[] = { + /* 0 */ 1462, INVALID, INVALID, +}; + +static const uint16_t ud_itab__18[] = { + /* 0 */ 1463, INVALID, INVALID, +}; + +static const uint16_t ud_itab__19[] = { + /* 0 */ 1464, INVALID, INVALID, +}; + +static const uint16_t ud_itab__20[] = { + /* 0 */ 1465, INVALID, INVALID, +}; + +static const uint16_t ud_itab__21[] = { + /* 0 */ 1393, INVALID, INVALID, +}; + +static const uint16_t ud_itab__22[] = { + /* 0 */ 80, INVALID, INVALID, +}; + +static const uint16_t ud_itab__23[] = { + /* 0 */ 1395, INVALID, INVALID, +}; + +static const uint16_t ud_itab__24[] = { + /* 0 */ 716, INVALID, INVALID, +}; + +static const uint16_t ud_itab__25[] = { + /* 0 */ 1421, GROUP(26), INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__26[] = { + /* 0 */ 1294, INVALID, INVALID, +}; + +static const uint16_t ud_itab__27[] = { + /* 0 */ 1115, 1116, 1117, 1118, + /* 4 */ 1119, 1120, 1121, 1122, +}; + +static const uint16_t ud_itab__28[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ 1212, 1213, INVALID, INVALID, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ 1214, 1215, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, 1216, INVALID, + /* 8c */ INVALID, INVALID, 1217, INVALID, + /* 90 */ 1218, INVALID, INVALID, INVALID, + /* 94 */ 1219, INVALID, 1220, 1221, + /* 98 */ INVALID, INVALID, 1222, INVALID, + /* 9c */ INVALID, INVALID, 1223, INVALID, + /* a0 */ 1224, INVALID, INVALID, INVALID, + /* a4 */ 1225, INVALID, 1226, 1227, + /* a8 */ INVALID, INVALID, 1228, INVALID, + /* ac */ INVALID, INVALID, 1229, INVALID, + /* b0 */ 1230, INVALID, INVALID, INVALID, + /* b4 */ 1231, INVALID, 1232, 1233, + /* b8 */ INVALID, INVALID, INVALID, 1234, + /* bc */ INVALID, INVALID, INVALID, 1235, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__29[] = { + /* 0 */ 932, 921, 924, 928, +}; + +static const uint16_t ud_itab__30[] = { + /* 0 */ 934, 922, 925, 930, +}; + +static const uint16_t ud_itab__31[] = { + /* 0 */ GROUP(32), GROUP(33), +}; + +static const uint16_t ud_itab__32[] = { + /* 0 */ 888, 1558, 1566, 884, +}; + +static const uint16_t ud_itab__33[] = { + /* 0 */ 892, 1556, 1564, INVALID, +}; + +static const uint16_t ud_itab__34[] = { + /* 0 */ 890, INVALID, INVALID, 886, +}; + +static const uint16_t ud_itab__35[] = { + /* 0 */ 1445, INVALID, INVALID, 1447, +}; + +static const uint16_t ud_itab__36[] = { + /* 0 */ 1443, INVALID, INVALID, 1441, +}; + +static const uint16_t ud_itab__37[] = { + /* 0 */ GROUP(38), GROUP(39), +}; + +static const uint16_t ud_itab__38[] = { + /* 0 */ 878, INVALID, 1562, 874, +}; + +static const uint16_t ud_itab__39[] = { + /* 0 */ 882, INVALID, 1560, INVALID, +}; + +static const uint16_t ud_itab__40[] = { + /* 0 */ 880, INVALID, INVALID, 876, +}; + +static const uint16_t ud_itab__41[] = { + /* 0 */ 1123, 1124, 1125, 1126, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__42[] = { + /* 0 */ 858, INVALID, INVALID, 854, +}; + +static const uint16_t ud_itab__43[] = { + /* 0 */ 860, INVALID, INVALID, 856, +}; + +static const uint16_t ud_itab__44[] = { + /* 0 */ 141, 152, 154, 142, +}; + +static const uint16_t ud_itab__45[] = { + /* 0 */ 903, INVALID, INVALID, 901, +}; + +static const uint16_t ud_itab__46[] = { + /* 0 */ 165, 166, 168, 162, +}; + +static const uint16_t ud_itab__47[] = { + /* 0 */ 147, 148, 158, 138, +}; + +static const uint16_t ud_itab__48[] = { + /* 0 */ 1438, INVALID, INVALID, 1436, +}; + +static const uint16_t ud_itab__49[] = { + /* 0 */ 129, INVALID, INVALID, 127, +}; + +static const uint16_t ud_itab__50[] = { + /* 0 */ 1423, GROUP(51), +}; + +static const uint16_t ud_itab__51[] = { + /* 0 */ INVALID, 1424, INVALID, +}; + +static const uint16_t ud_itab__52[] = { + /* 0 */ 1425, GROUP(53), +}; + +static const uint16_t ud_itab__53[] = { + /* 0 */ INVALID, 1426, INVALID, +}; + +static const uint16_t ud_itab__54[] = { + /* 0 */ GROUP(67), GROUP(68), GROUP(63), GROUP(64), + /* 4 */ GROUP(65), GROUP(66), GROUP(86), GROUP(90), + /* 8 */ GROUP(69), GROUP(70), GROUP(71), GROUP(72), + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(73), INVALID, INVALID, INVALID, + /* 14 */ GROUP(75), GROUP(76), INVALID, GROUP(77), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ GROUP(78), GROUP(79), GROUP(80), INVALID, + /* 20 */ GROUP(81), GROUP(82), GROUP(83), GROUP(84), + /* 24 */ GROUP(85), GROUP(108), INVALID, INVALID, + /* 28 */ GROUP(87), GROUP(88), GROUP(89), GROUP(74), + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ GROUP(91), GROUP(92), GROUP(93), GROUP(94), + /* 34 */ GROUP(95), GROUP(96), INVALID, GROUP(97), + /* 38 */ GROUP(98), GROUP(99), GROUP(100), GROUP(101), + /* 3c */ GROUP(102), GROUP(103), GROUP(104), GROUP(105), + /* 40 */ GROUP(106), GROUP(107), INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ GROUP(55), GROUP(59), INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, GROUP(109), + /* dc */ GROUP(110), GROUP(111), GROUP(112), GROUP(113), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ GROUP(114), GROUP(115), INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__55[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(56), +}; + +static const uint16_t ud_itab__56[] = { + /* 0 */ GROUP(57), GROUP(58), +}; + +static const uint16_t ud_itab__57[] = { + /* 0 */ INVALID, 713, INVALID, +}; + +static const uint16_t ud_itab__58[] = { + /* 0 */ INVALID, 714, INVALID, +}; + +static const uint16_t ud_itab__59[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(60), +}; + +static const uint16_t ud_itab__60[] = { + /* 0 */ GROUP(61), GROUP(62), +}; + +static const uint16_t ud_itab__61[] = { + /* 0 */ INVALID, 717, INVALID, +}; + +static const uint16_t ud_itab__62[] = { + /* 0 */ INVALID, 718, INVALID, +}; + +static const uint16_t ud_itab__63[] = { + /* 0 */ 1583, INVALID, INVALID, 1584, +}; + +static const uint16_t ud_itab__64[] = { + /* 0 */ 1586, INVALID, INVALID, 1587, +}; + +static const uint16_t ud_itab__65[] = { + /* 0 */ 1589, INVALID, INVALID, 1590, +}; + +static const uint16_t ud_itab__66[] = { + /* 0 */ 1592, INVALID, INVALID, 1593, +}; + +static const uint16_t ud_itab__67[] = { + /* 0 */ 1577, INVALID, INVALID, 1578, +}; + +static const uint16_t ud_itab__68[] = { + /* 0 */ 1580, INVALID, INVALID, 1581, +}; + +static const uint16_t ud_itab__69[] = { + /* 0 */ 1601, INVALID, INVALID, 1602, +}; + +static const uint16_t ud_itab__70[] = { + /* 0 */ 1607, INVALID, INVALID, 1608, +}; + +static const uint16_t ud_itab__71[] = { + /* 0 */ 1604, INVALID, INVALID, 1605, +}; + +static const uint16_t ud_itab__72[] = { + /* 0 */ 1610, INVALID, INVALID, 1611, +}; + +static const uint16_t ud_itab__73[] = { + /* 0 */ INVALID, INVALID, INVALID, 1616, +}; + +static const uint16_t ud_itab__74[] = { + /* 0 */ INVALID, INVALID, INVALID, 1678, +}; + +static const uint16_t ud_itab__75[] = { + /* 0 */ INVALID, INVALID, INVALID, 1652, +}; + +static const uint16_t ud_itab__76[] = { + /* 0 */ INVALID, INVALID, INVALID, 1651, +}; + +static const uint16_t ud_itab__77[] = { + /* 0 */ INVALID, INVALID, INVALID, 1706, +}; + +static const uint16_t ud_itab__78[] = { + /* 0 */ 1568, INVALID, INVALID, 1569, +}; + +static const uint16_t ud_itab__79[] = { + /* 0 */ 1571, INVALID, INVALID, 1572, +}; + +static const uint16_t ud_itab__80[] = { + /* 0 */ 1574, INVALID, INVALID, 1575, +}; + +static const uint16_t ud_itab__81[] = { + /* 0 */ INVALID, INVALID, INVALID, 1680, +}; + +static const uint16_t ud_itab__82[] = { + /* 0 */ INVALID, INVALID, INVALID, 1682, +}; + +static const uint16_t ud_itab__83[] = { + /* 0 */ INVALID, INVALID, INVALID, 1684, +}; + +static const uint16_t ud_itab__84[] = { + /* 0 */ INVALID, INVALID, INVALID, 1686, +}; + +static const uint16_t ud_itab__85[] = { + /* 0 */ INVALID, INVALID, INVALID, 1688, +}; + +static const uint16_t ud_itab__86[] = { + /* 0 */ 1595, INVALID, INVALID, 1596, +}; + +static const uint16_t ud_itab__87[] = { + /* 0 */ INVALID, INVALID, INVALID, 1617, +}; + +static const uint16_t ud_itab__88[] = { + /* 0 */ INVALID, INVALID, INVALID, 1703, +}; + +static const uint16_t ud_itab__89[] = { + /* 0 */ INVALID, INVALID, INVALID, 1676, +}; + +static const uint16_t ud_itab__90[] = { + /* 0 */ 1598, INVALID, INVALID, 1599, +}; + +static const uint16_t ud_itab__91[] = { + /* 0 */ INVALID, INVALID, INVALID, 1691, +}; + +static const uint16_t ud_itab__92[] = { + /* 0 */ INVALID, INVALID, INVALID, 1693, +}; + +static const uint16_t ud_itab__93[] = { + /* 0 */ INVALID, INVALID, INVALID, 1695, +}; + +static const uint16_t ud_itab__94[] = { + /* 0 */ INVALID, INVALID, INVALID, 1697, +}; + +static const uint16_t ud_itab__95[] = { + /* 0 */ INVALID, INVALID, INVALID, 1699, +}; + +static const uint16_t ud_itab__96[] = { + /* 0 */ INVALID, INVALID, INVALID, 1701, +}; + +static const uint16_t ud_itab__97[] = { + /* 0 */ INVALID, INVALID, INVALID, 1712, +}; + +static const uint16_t ud_itab__98[] = { + /* 0 */ INVALID, INVALID, INVALID, 1619, +}; + +static const uint16_t ud_itab__99[] = { + /* 0 */ INVALID, INVALID, INVALID, 1621, +}; + +static const uint16_t ud_itab__100[] = { + /* 0 */ INVALID, INVALID, INVALID, 1623, +}; + +static const uint16_t ud_itab__101[] = { + /* 0 */ INVALID, INVALID, INVALID, 1625, +}; + +static const uint16_t ud_itab__102[] = { + /* 0 */ INVALID, INVALID, INVALID, 1627, +}; + +static const uint16_t ud_itab__103[] = { + /* 0 */ INVALID, INVALID, INVALID, 1629, +}; + +static const uint16_t ud_itab__104[] = { + /* 0 */ INVALID, INVALID, INVALID, 1633, +}; + +static const uint16_t ud_itab__105[] = { + /* 0 */ INVALID, INVALID, INVALID, 1631, +}; + +static const uint16_t ud_itab__106[] = { + /* 0 */ INVALID, INVALID, INVALID, 1635, +}; + +static const uint16_t ud_itab__107[] = { + /* 0 */ INVALID, INVALID, INVALID, 1637, +}; + +static const uint16_t ud_itab__108[] = { + /* 0 */ INVALID, INVALID, INVALID, 1690, +}; + +static const uint16_t ud_itab__109[] = { + /* 0 */ INVALID, INVALID, INVALID, 45, +}; + +static const uint16_t ud_itab__110[] = { + /* 0 */ INVALID, INVALID, INVALID, 41, +}; + +static const uint16_t ud_itab__111[] = { + /* 0 */ INVALID, INVALID, INVALID, 43, +}; + +static const uint16_t ud_itab__112[] = { + /* 0 */ INVALID, INVALID, INVALID, 37, +}; + +static const uint16_t ud_itab__113[] = { + /* 0 */ INVALID, INVALID, INVALID, 39, +}; + +static const uint16_t ud_itab__114[] = { + /* 0 */ 1718, 1720, INVALID, INVALID, +}; + +static const uint16_t ud_itab__115[] = { + /* 0 */ 1719, 1721, INVALID, INVALID, +}; + +static const uint16_t ud_itab__116[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ GROUP(117), GROUP(118), GROUP(119), GROUP(120), + /* c */ GROUP(121), GROUP(122), GROUP(123), GROUP(124), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(125), GROUP(126), GROUP(127), GROUP(129), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(130), GROUP(131), GROUP(132), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ GROUP(134), GROUP(135), GROUP(136), INVALID, + /* 44 */ GROUP(137), INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ GROUP(139), GROUP(140), GROUP(141), GROUP(142), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, GROUP(138), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__117[] = { + /* 0 */ INVALID, INVALID, INVALID, 1639, +}; + +static const uint16_t ud_itab__118[] = { + /* 0 */ INVALID, INVALID, INVALID, 1641, +}; + +static const uint16_t ud_itab__119[] = { + /* 0 */ INVALID, INVALID, INVALID, 1643, +}; + +static const uint16_t ud_itab__120[] = { + /* 0 */ INVALID, INVALID, INVALID, 1645, +}; + +static const uint16_t ud_itab__121[] = { + /* 0 */ INVALID, INVALID, INVALID, 1649, +}; + +static const uint16_t ud_itab__122[] = { + /* 0 */ INVALID, INVALID, INVALID, 1647, +}; + +static const uint16_t ud_itab__123[] = { + /* 0 */ INVALID, INVALID, INVALID, 1672, +}; + +static const uint16_t ud_itab__124[] = { + /* 0 */ 1613, INVALID, INVALID, 1614, +}; + +static const uint16_t ud_itab__125[] = { + /* 0 */ INVALID, INVALID, INVALID, 1041, +}; + +static const uint16_t ud_itab__126[] = { + /* 0 */ INVALID, INVALID, INVALID, 1052, +}; + +static const uint16_t ud_itab__127[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(128), +}; + +static const uint16_t ud_itab__128[] = { + /* 0 */ 1043, 1045, 1047, +}; + +static const uint16_t ud_itab__129[] = { + /* 0 */ INVALID, INVALID, INVALID, 201, +}; + +static const uint16_t ud_itab__130[] = { + /* 0 */ INVALID, INVALID, INVALID, 1054, +}; + +static const uint16_t ud_itab__131[] = { + /* 0 */ INVALID, INVALID, INVALID, 1552, +}; + +static const uint16_t ud_itab__132[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(133), +}; + +static const uint16_t ud_itab__133[] = { + /* 0 */ 1058, 1059, 1060, +}; + +static const uint16_t ud_itab__134[] = { + /* 0 */ INVALID, INVALID, INVALID, 197, +}; + +static const uint16_t ud_itab__135[] = { + /* 0 */ INVALID, INVALID, INVALID, 195, +}; + +static const uint16_t ud_itab__136[] = { + /* 0 */ INVALID, INVALID, INVALID, 1674, +}; + +static const uint16_t ud_itab__137[] = { + /* 0 */ INVALID, INVALID, INVALID, 1508, +}; + +static const uint16_t ud_itab__138[] = { + /* 0 */ INVALID, INVALID, INVALID, 47, +}; + +static const uint16_t ud_itab__139[] = { + /* 0 */ INVALID, INVALID, INVALID, 1710, +}; + +static const uint16_t ud_itab__140[] = { + /* 0 */ INVALID, INVALID, INVALID, 1708, +}; + +static const uint16_t ud_itab__141[] = { + /* 0 */ INVALID, INVALID, INVALID, 1716, +}; + +static const uint16_t ud_itab__142[] = { + /* 0 */ INVALID, INVALID, INVALID, 1714, +}; + +static const uint16_t ud_itab__143[] = { + /* 0 */ 896, INVALID, INVALID, 894, +}; + +static const uint16_t ud_itab__144[] = { + /* 0 */ 1383, 1387, 1389, 1385, +}; + +static const uint16_t ud_itab__145[] = { + /* 0 */ 1302, INVALID, 1304, INVALID, +}; + +static const uint16_t ud_itab__146[] = { + /* 0 */ 1287, INVALID, 1289, INVALID, +}; + +static const uint16_t ud_itab__147[] = { + /* 0 */ 61, INVALID, INVALID, 59, +}; + +static const uint16_t ud_itab__148[] = { + /* 0 */ 65, INVALID, INVALID, 63, +}; + +static const uint16_t ud_itab__149[] = { + /* 0 */ 972, INVALID, INVALID, 970, +}; + +static const uint16_t ud_itab__150[] = { + /* 0 */ 1495, INVALID, INVALID, 1493, +}; + +static const uint16_t ud_itab__151[] = { + /* 0 */ 27, 29, 31, 25, +}; + +static const uint16_t ud_itab__152[] = { + /* 0 */ 942, 944, 946, 940, +}; + +static const uint16_t ud_itab__153[] = { + /* 0 */ 145, 150, 156, 139, +}; + +static const uint16_t ud_itab__154[] = { + /* 0 */ 134, INVALID, 163, 143, +}; + +static const uint16_t ud_itab__155[] = { + /* 0 */ 1415, 1417, 1419, 1413, +}; + +static const uint16_t ud_itab__156[] = { + /* 0 */ 814, 816, 818, 812, +}; + +static const uint16_t ud_itab__157[] = { + /* 0 */ 189, 191, 193, 187, +}; + +static const uint16_t ud_itab__158[] = { + /* 0 */ 798, 800, 802, 796, +}; + +static const uint16_t ud_itab__159[] = { + /* 0 */ 1205, INVALID, INVALID, 1203, +}; + +static const uint16_t ud_itab__160[] = { + /* 0 */ 1208, INVALID, INVALID, 1206, +}; + +static const uint16_t ud_itab__161[] = { + /* 0 */ 1211, INVALID, INVALID, 1209, +}; + +static const uint16_t ud_itab__162[] = { + /* 0 */ 983, INVALID, INVALID, 981, +}; + +static const uint16_t ud_itab__163[] = { + /* 0 */ 1034, INVALID, INVALID, 1032, +}; + +static const uint16_t ud_itab__164[] = { + /* 0 */ 1037, INVALID, INVALID, 1035, +}; + +static const uint16_t ud_itab__165[] = { + /* 0 */ 1040, INVALID, INVALID, 1038, +}; + +static const uint16_t ud_itab__166[] = { + /* 0 */ 989, INVALID, INVALID, 987, +}; + +static const uint16_t ud_itab__167[] = { + /* 0 */ 1196, INVALID, INVALID, 1194, +}; + +static const uint16_t ud_itab__168[] = { + /* 0 */ 1199, INVALID, INVALID, 1197, +}; + +static const uint16_t ud_itab__169[] = { + /* 0 */ 1202, INVALID, INVALID, 1200, +}; + +static const uint16_t ud_itab__170[] = { + /* 0 */ 986, INVALID, INVALID, 984, +}; + +static const uint16_t ud_itab__171[] = { + /* 0 */ INVALID, INVALID, INVALID, 1542, +}; + +static const uint16_t ud_itab__172[] = { + /* 0 */ INVALID, INVALID, INVALID, 1540, +}; + +static const uint16_t ud_itab__173[] = { + /* 0 */ GROUP(174), INVALID, INVALID, GROUP(175), +}; + +static const uint16_t ud_itab__174[] = { + /* 0 */ 862, 863, 906, +}; + +static const uint16_t ud_itab__175[] = { + /* 0 */ 864, 866, 907, +}; + +static const uint16_t ud_itab__176[] = { + /* 0 */ 916, INVALID, 1518, 1513, +}; + +static const uint16_t ud_itab__177[] = { + /* 0 */ 1130, 1532, 1530, 1534, +}; + +static const uint16_t ud_itab__178[] = { + /* 0 */ INVALID, INVALID, GROUP(179), INVALID, + /* 4 */ GROUP(180), INVALID, GROUP(181), INVALID, +}; + +static const uint16_t ud_itab__179[] = { + /* 0 */ 1155, INVALID, INVALID, 1159, +}; + +static const uint16_t ud_itab__180[] = { + /* 0 */ 1148, INVALID, INVALID, 1146, +}; + +static const uint16_t ud_itab__181[] = { + /* 0 */ 1134, INVALID, INVALID, 1133, +}; + +static const uint16_t ud_itab__182[] = { + /* 0 */ INVALID, INVALID, GROUP(183), INVALID, + /* 4 */ GROUP(184), INVALID, GROUP(185), INVALID, +}; + +static const uint16_t ud_itab__183[] = { + /* 0 */ 1161, INVALID, INVALID, 1165, +}; + +static const uint16_t ud_itab__184[] = { + /* 0 */ 1149, INVALID, INVALID, 1153, +}; + +static const uint16_t ud_itab__185[] = { + /* 0 */ 1138, INVALID, INVALID, 1137, +}; + +static const uint16_t ud_itab__186[] = { + /* 0 */ INVALID, INVALID, GROUP(187), GROUP(188), + /* 4 */ INVALID, INVALID, GROUP(189), GROUP(190), +}; + +static const uint16_t ud_itab__187[] = { + /* 0 */ 1167, INVALID, INVALID, 1171, +}; + +static const uint16_t ud_itab__188[] = { + /* 0 */ INVALID, INVALID, INVALID, 1538, +}; + +static const uint16_t ud_itab__189[] = { + /* 0 */ 1142, INVALID, INVALID, 1141, +}; + +static const uint16_t ud_itab__190[] = { + /* 0 */ INVALID, INVALID, INVALID, 1536, +}; + +static const uint16_t ud_itab__191[] = { + /* 0 */ 1023, INVALID, INVALID, 1024, +}; + +static const uint16_t ud_itab__192[] = { + /* 0 */ 1026, INVALID, INVALID, 1027, +}; + +static const uint16_t ud_itab__193[] = { + /* 0 */ 1029, INVALID, INVALID, 1030, +}; + +static const uint16_t ud_itab__194[] = { + /* 0 */ INVALID, 1460, INVALID, +}; + +static const uint16_t ud_itab__195[] = { + /* 0 */ INVALID, 1461, INVALID, +}; + +static const uint16_t ud_itab__196[] = { + /* 0 */ INVALID, 1546, INVALID, 1544, +}; + +static const uint16_t ud_itab__197[] = { + /* 0 */ INVALID, 1550, INVALID, 1548, +}; + +static const uint16_t ud_itab__198[] = { + /* 0 */ GROUP(199), INVALID, 912, GROUP(200), +}; + +static const uint16_t ud_itab__199[] = { + /* 0 */ 868, 869, 909, +}; + +static const uint16_t ud_itab__200[] = { + /* 0 */ 870, 872, 910, +}; + +static const uint16_t ud_itab__201[] = { + /* 0 */ 917, INVALID, 1520, 1511, +}; + +static const uint16_t ud_itab__202[] = { + /* 0 */ INVALID, GROUP(203), +}; + +static const uint16_t ud_itab__203[] = { + /* 0 */ GROUP(204), GROUP(205), GROUP(206), INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__204[] = { + /* 0 */ 821, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__205[] = { + /* 0 */ 1505, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__206[] = { + /* 0 */ 1506, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__207[] = { + /* 0 */ INVALID, GROUP(208), +}; + +static const uint16_t ud_itab__208[] = { + /* 0 */ GROUP(209), GROUP(210), GROUP(211), GROUP(212), + /* 4 */ GROUP(213), GROUP(214), INVALID, INVALID, +}; + +static const uint16_t ud_itab__209[] = { + /* 0 */ 1507, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__210[] = { + /* 0 */ 1497, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__211[] = { + /* 0 */ 1498, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__212[] = { + /* 0 */ 1499, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__213[] = { + /* 0 */ 1500, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__214[] = { + /* 0 */ 1501, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__215[] = { + /* 0 */ GROUP(216), GROUP(217), +}; + +static const uint16_t ud_itab__216[] = { + /* 0 */ 679, 678, 764, 1396, + /* 4 */ 1503, 1502, INVALID, 79, +}; + +static const uint16_t ud_itab__217[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, GROUP(218), GROUP(219), GROUP(220), +}; + +static const uint16_t ud_itab__218[] = { + /* 0 */ 773, 774, 775, 776, + /* 4 */ 777, 778, 779, 780, +}; + +static const uint16_t ud_itab__219[] = { + /* 0 */ 804, 805, 806, 807, + /* 4 */ 808, 809, 810, 811, +}; + +static const uint16_t ud_itab__220[] = { + /* 0 */ 1362, 1363, 1364, 1365, + /* 4 */ 1366, 1367, 1368, 1369, +}; + +static const uint16_t ud_itab__221[] = { + /* 0 */ INVALID, INVALID, 1705, INVALID, +}; + +static const uint16_t ud_itab__222[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ 1664, 1671, 1669, 1667, +}; + +static const uint16_t ud_itab__223[] = { + /* 0 */ 112, 117, 120, 110, +}; + +static const uint16_t ud_itab__224[] = { + /* 0 */ 1055, INVALID, INVALID, 1056, +}; + +static const uint16_t ud_itab__225[] = { + /* 0 */ 1051, INVALID, INVALID, 1049, +}; + +static const uint16_t ud_itab__226[] = { + /* 0 */ 1377, INVALID, INVALID, 1375, +}; + +static const uint16_t ud_itab__227[] = { + /* 0 */ GROUP(228), GROUP(235), +}; + +static const uint16_t ud_itab__228[] = { + /* 0 */ INVALID, GROUP(229), INVALID, INVALID, + /* 4 */ INVALID, INVALID, GROUP(230), GROUP(234), +}; + +static const uint16_t ud_itab__229[] = { + /* 0 */ 124, 125, 126, +}; + +static const uint16_t ud_itab__230[] = { + /* 0 */ GROUP(231), INVALID, GROUP(232), GROUP(233), +}; + +static const uint16_t ud_itab__231[] = { + /* 0 */ INVALID, 1455, INVALID, +}; + +static const uint16_t ud_itab__232[] = { + /* 0 */ INVALID, 1454, INVALID, +}; + +static const uint16_t ud_itab__233[] = { + /* 0 */ INVALID, 1453, INVALID, +}; + +static const uint16_t ud_itab__234[] = { + /* 0 */ INVALID, 1456, INVALID, +}; + +static const uint16_t ud_itab__235[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, 1452, INVALID, +}; + +static const uint16_t ud_itab__236[] = { + /* 0 */ INVALID, 35, INVALID, 33, +}; + +static const uint16_t ud_itab__237[] = { + /* 0 */ 1156, INVALID, INVALID, 1157, +}; + +static const uint16_t ud_itab__238[] = { + /* 0 */ 1162, INVALID, INVALID, 1163, +}; + +static const uint16_t ud_itab__239[] = { + /* 0 */ 1168, INVALID, INVALID, 1169, +}; + +static const uint16_t ud_itab__240[] = { + /* 0 */ 1522, INVALID, INVALID, 1523, +}; + +static const uint16_t ud_itab__241[] = { + /* 0 */ 1089, INVALID, INVALID, 1090, +}; + +static const uint16_t ud_itab__242[] = { + /* 0 */ INVALID, 1517, 1521, 914, +}; + +static const uint16_t ud_itab__243[] = { + /* 0 */ 1082, INVALID, INVALID, 1080, +}; + +static const uint16_t ud_itab__244[] = { + /* 0 */ 1188, INVALID, INVALID, 1189, +}; + +static const uint16_t ud_itab__245[] = { + /* 0 */ 1191, INVALID, INVALID, 1192, +}; + +static const uint16_t ud_itab__246[] = { + /* 0 */ 1079, INVALID, INVALID, 1077, +}; + +static const uint16_t ud_itab__247[] = { + /* 0 */ 1013, INVALID, INVALID, 1011, +}; + +static const uint16_t ud_itab__248[] = { + /* 0 */ 1005, INVALID, INVALID, 1006, +}; + +static const uint16_t ud_itab__249[] = { + /* 0 */ 1008, INVALID, INVALID, 1009, +}; + +static const uint16_t ud_itab__250[] = { + /* 0 */ 1071, INVALID, INVALID, 1072, +}; + +static const uint16_t ud_itab__251[] = { + /* 0 */ 1016, INVALID, INVALID, 1014, +}; + +static const uint16_t ud_itab__252[] = { + /* 0 */ 1019, INVALID, INVALID, 1017, +}; + +static const uint16_t ud_itab__253[] = { + /* 0 */ 1143, INVALID, INVALID, 1144, +}; + +static const uint16_t ud_itab__254[] = { + /* 0 */ 1152, INVALID, INVALID, 1150, +}; + +static const uint16_t ud_itab__255[] = { + /* 0 */ 1022, INVALID, INVALID, 1020, +}; + +static const uint16_t ud_itab__256[] = { + /* 0 */ 1083, INVALID, INVALID, 1084, +}; + +static const uint16_t ud_itab__257[] = { + /* 0 */ 1088, INVALID, INVALID, 1086, +}; + +static const uint16_t ud_itab__258[] = { + /* 0 */ INVALID, 136, 132, 160, +}; + +static const uint16_t ud_itab__259[] = { + /* 0 */ 905, INVALID, INVALID, 898, +}; + +static const uint16_t ud_itab__260[] = { + /* 0 */ 1182, INVALID, INVALID, 1183, +}; + +static const uint16_t ud_itab__261[] = { + /* 0 */ 1185, INVALID, INVALID, 1186, +}; + +static const uint16_t ud_itab__262[] = { + /* 0 */ 1076, INVALID, INVALID, 1074, +}; + +static const uint16_t ud_itab__263[] = { + /* 0 */ 1114, INVALID, INVALID, 1112, +}; + +static const uint16_t ud_itab__264[] = { + /* 0 */ 999, INVALID, INVALID, 1000, +}; + +static const uint16_t ud_itab__265[] = { + /* 0 */ 1002, INVALID, INVALID, 1003, +}; + +static const uint16_t ud_itab__266[] = { + /* 0 */ 1070, INVALID, INVALID, 1068, +}; + +static const uint16_t ud_itab__267[] = { + /* 0 */ 1262, INVALID, INVALID, 1260, +}; + +static const uint16_t ud_itab__268[] = { + /* 0 */ INVALID, 1554, INVALID, INVALID, +}; + +static const uint16_t ud_itab__269[] = { + /* 0 */ 1132, INVALID, INVALID, 1131, +}; + +static const uint16_t ud_itab__270[] = { + /* 0 */ 1136, INVALID, INVALID, 1135, +}; + +static const uint16_t ud_itab__271[] = { + /* 0 */ 1140, INVALID, INVALID, 1139, +}; + +static const uint16_t ud_itab__272[] = { + /* 0 */ 1528, INVALID, INVALID, 1529, +}; + +static const uint16_t ud_itab__273[] = { + /* 0 */ 1065, INVALID, INVALID, 1066, +}; + +static const uint16_t ud_itab__274[] = { + /* 0 */ 1129, INVALID, INVALID, 1127, +}; + +static const uint16_t ud_itab__275[] = { + /* 0 */ INVALID, GROUP(276), +}; + +static const uint16_t ud_itab__276[] = { + /* 0 */ 795, INVALID, INVALID, 1515, +}; + +static const uint16_t ud_itab__277[] = { + /* 0 */ 1175, INVALID, INVALID, 1173, +}; + +static const uint16_t ud_itab__278[] = { + /* 0 */ 1178, INVALID, INVALID, 1176, +}; + +static const uint16_t ud_itab__279[] = { + /* 0 */ 1179, INVALID, INVALID, 1180, +}; + +static const uint16_t ud_itab__280[] = { + /* 0 */ 1527, INVALID, INVALID, 1525, +}; + +static const uint16_t ud_itab__281[] = { + /* 0 */ 992, INVALID, INVALID, 990, +}; + +static const uint16_t ud_itab__282[] = { + /* 0 */ 993, INVALID, INVALID, 994, +}; + +static const uint16_t ud_itab__283[] = { + /* 0 */ 996, INVALID, INVALID, 997, +}; + +static const uint16_t ud_itab__284[] = { + /* 0 */ 1238, INVALID, +}; + +static const uint16_t ud_itab__285[] = { + /* 0 */ 1093, INVALID, +}; + +static const uint16_t ud_itab__286[] = { + /* 0 */ 1239, INVALID, +}; + +static const uint16_t ud_itab__287[] = { + /* 0 */ 1094, INVALID, +}; + +static const uint16_t ud_itab__288[] = { + /* 0 */ 173, INVALID, +}; + +static const uint16_t ud_itab__289[] = { + /* 0 */ 174, INVALID, +}; + +static const uint16_t ud_itab__290[] = { + /* 0 */ 1, INVALID, +}; + +static const uint16_t ud_itab__291[] = { + /* 0 */ 4, INVALID, +}; + +static const uint16_t ud_itab__292[] = { + /* 0 */ GROUP(293), GROUP(294), INVALID, +}; + +static const uint16_t ud_itab__293[] = { + /* 0 */ 1253, INVALID, +}; + +static const uint16_t ud_itab__294[] = { + /* 0 */ 1254, INVALID, +}; + +static const uint16_t ud_itab__295[] = { + /* 0 */ GROUP(296), GROUP(297), INVALID, +}; + +static const uint16_t ud_itab__296[] = { + /* 0 */ 1106, INVALID, +}; + +static const uint16_t ud_itab__297[] = { + /* 0 */ 1107, INVALID, +}; + +static const uint16_t ud_itab__298[] = { + /* 0 */ 1653, INVALID, +}; + +static const uint16_t ud_itab__299[] = { + /* 0 */ 67, 68, +}; + +static const uint16_t ud_itab__300[] = { + /* 0 */ 706, 707, INVALID, +}; + +static const uint16_t ud_itab__301[] = { + /* 0 */ 979, 980, INVALID, +}; + +static const uint16_t ud_itab__302[] = { + /* 0 */ 21, 966, 11, 1338, + /* 4 */ 55, 1409, 1489, 106, +}; + +static const uint16_t ud_itab__303[] = { + /* 0 */ 23, 967, 13, 1339, + /* 4 */ 57, 1410, 1490, 108, +}; + +static const uint16_t ud_itab__304[] = { + /* 0 */ GROUP(305), GROUP(306), GROUP(307), GROUP(308), + /* 4 */ GROUP(309), GROUP(310), GROUP(311), GROUP(312), +}; + +static const uint16_t ud_itab__305[] = { + /* 0 */ 22, INVALID, +}; + +static const uint16_t ud_itab__306[] = { + /* 0 */ 968, INVALID, +}; + +static const uint16_t ud_itab__307[] = { + /* 0 */ 12, INVALID, +}; + +static const uint16_t ud_itab__308[] = { + /* 0 */ 1340, INVALID, +}; + +static const uint16_t ud_itab__309[] = { + /* 0 */ 56, INVALID, +}; + +static const uint16_t ud_itab__310[] = { + /* 0 */ 1411, INVALID, +}; + +static const uint16_t ud_itab__311[] = { + /* 0 */ 1491, INVALID, +}; + +static const uint16_t ud_itab__312[] = { + /* 0 */ 107, INVALID, +}; + +static const uint16_t ud_itab__313[] = { + /* 0 */ 24, 969, 14, 1341, + /* 4 */ 58, 1412, 1492, 109, +}; + +static const uint16_t ud_itab__314[] = { + /* 0 */ 1105, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__315[] = { + /* 0 */ 74, 75, 76, +}; + +static const uint16_t ud_itab__316[] = { + /* 0 */ 170, 171, 172, +}; + +static const uint16_t ud_itab__317[] = { + /* 0 */ 73, INVALID, +}; + +static const uint16_t ud_itab__318[] = { + /* 0 */ GROUP(319), GROUP(320), GROUP(321), +}; + +static const uint16_t ud_itab__319[] = { + /* 0 */ 1255, 1256, +}; + +static const uint16_t ud_itab__320[] = { + /* 0 */ 1257, 1258, +}; + +static const uint16_t ud_itab__321[] = { + /* 0 */ INVALID, 1259, +}; + +static const uint16_t ud_itab__322[] = { + /* 0 */ GROUP(323), GROUP(324), GROUP(325), +}; + +static const uint16_t ud_itab__323[] = { + /* 0 */ 1108, INVALID, +}; + +static const uint16_t ud_itab__324[] = { + /* 0 */ 1109, 1110, +}; + +static const uint16_t ud_itab__325[] = { + /* 0 */ INVALID, 1111, +}; + +static const uint16_t ud_itab__326[] = { + /* 0 */ 919, 920, 923, +}; + +static const uint16_t ud_itab__327[] = { + /* 0 */ 115, 116, 119, +}; + +static const uint16_t ud_itab__328[] = { + /* 0 */ 1399, 1400, 1401, +}; + +static const uint16_t ud_itab__329[] = { + /* 0 */ 787, 788, 789, +}; + +static const uint16_t ud_itab__330[] = { + /* 0 */ 1343, 1344, 1345, +}; + +static const uint16_t ud_itab__331[] = { + /* 0 */ 1275, 1282, 1263, 1271, + /* 4 */ 1323, 1330, 1314, 1309, +}; + +static const uint16_t ud_itab__332[] = { + /* 0 */ 1280, 1283, 1264, 1270, + /* 4 */ 1319, 1326, 1315, 1311, +}; + +static const uint16_t ud_itab__333[] = { + /* 0 */ GROUP(334), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__334[] = { + /* 0 */ 767, INVALID, +}; + +static const uint16_t ud_itab__335[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 933, 935, GROUP(336), 891, + /* 14 */ 1446, 1444, GROUP(337), 881, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 859, 861, INVALID, 904, + /* 2c */ INVALID, INVALID, 1439, 130, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 897, 1384, 1303, 1288, + /* 54 */ 62, 66, 973, 1496, + /* 58 */ 28, 943, 146, 135, + /* 5c */ 1416, 815, 190, 799, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, GROUP(340), + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, GROUP(338), INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 113, INVALID, + /* c4 */ INVALID, INVALID, 1378, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__336[] = { + /* 0 */ 889, 893, +}; + +static const uint16_t ud_itab__337[] = { + /* 0 */ 879, 883, +}; + +static const uint16_t ud_itab__338[] = { + /* 0 */ GROUP(339), INVALID, +}; + +static const uint16_t ud_itab__339[] = { + /* 0 */ INVALID, INVALID, INVALID, 1397, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__340[] = { + /* 0 */ 1737, 1738, +}; + +static const uint16_t ud_itab__341[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 929, 931, GROUP(342), 887, + /* 14 */ 1448, 1442, GROUP(343), 877, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 855, 857, INVALID, 902, + /* 2c */ INVALID, INVALID, 1437, 128, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 895, 1386, INVALID, INVALID, + /* 54 */ 60, 64, 971, 1494, + /* 58 */ 26, 941, 140, 144, + /* 5c */ 1414, 813, 188, 797, + /* 60 */ 1204, 1207, 1210, 982, + /* 64 */ 1033, 1036, 1039, 988, + /* 68 */ 1195, 1198, 1201, 985, + /* 6c */ 1543, 1541, GROUP(344), 1514, + /* 70 */ 1535, GROUP(345), GROUP(347), GROUP(349), + /* 74 */ 1025, 1028, 1031, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1545, 1549, GROUP(351), 1512, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 111, INVALID, + /* c4 */ 1057, 1050, 1376, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 34, 1158, 1164, 1170, + /* d4 */ 1524, 1091, 915, GROUP(352), + /* d8 */ 1190, 1193, 1078, 1012, + /* dc */ 1007, 1010, 1073, 1015, + /* e0 */ 1018, 1145, 1151, 1021, + /* e4 */ 1085, 1087, 161, 899, + /* e8 */ 1184, 1187, 1075, 1113, + /* ec */ 1001, 1004, 1069, 1261, + /* f0 */ INVALID, GROUP(353), GROUP(354), GROUP(355), + /* f4 */ INVALID, 1067, 1128, GROUP(356), + /* f8 */ 1174, 1177, 1181, 1526, + /* fc */ 991, 995, 998, INVALID, +}; + +static const uint16_t ud_itab__342[] = { + /* 0 */ 885, INVALID, +}; + +static const uint16_t ud_itab__343[] = { + /* 0 */ 875, INVALID, +}; + +static const uint16_t ud_itab__344[] = { + /* 0 */ 865, 867, 908, +}; + +static const uint16_t ud_itab__345[] = { + /* 0 */ INVALID, INVALID, 1160, INVALID, + /* 4 */ 1147, INVALID, GROUP(346), INVALID, +}; + +static const uint16_t ud_itab__346[] = { + /* 0 */ 1751, INVALID, +}; + +static const uint16_t ud_itab__347[] = { + /* 0 */ INVALID, INVALID, 1166, INVALID, + /* 4 */ 1154, INVALID, GROUP(348), INVALID, +}; + +static const uint16_t ud_itab__348[] = { + /* 0 */ 1753, INVALID, +}; + +static const uint16_t ud_itab__349[] = { + /* 0 */ INVALID, INVALID, 1172, 1539, + /* 4 */ INVALID, INVALID, GROUP(350), 1537, +}; + +static const uint16_t ud_itab__350[] = { + /* 0 */ 1755, INVALID, +}; + +static const uint16_t ud_itab__351[] = { + /* 0 */ 871, 873, 911, +}; + +static const uint16_t ud_itab__352[] = { + /* 0 */ 1081, INVALID, +}; + +static const uint16_t ud_itab__353[] = { + /* 0 */ 1750, INVALID, +}; + +static const uint16_t ud_itab__354[] = { + /* 0 */ 1752, INVALID, +}; + +static const uint16_t ud_itab__355[] = { + /* 0 */ 1754, INVALID, +}; + +static const uint16_t ud_itab__356[] = { + /* 0 */ INVALID, 1516, +}; + +static const uint16_t ud_itab__357[] = { + /* 0 */ 1579, 1582, 1585, 1588, + /* 4 */ 1591, 1594, 1597, 1600, + /* 8 */ 1603, 1609, 1606, 1612, + /* c */ GROUP(358), GROUP(359), GROUP(360), GROUP(361), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, 1707, + /* 18 */ GROUP(362), GROUP(363), INVALID, INVALID, + /* 1c */ 1570, 1573, 1576, INVALID, + /* 20 */ 1681, 1683, 1685, 1687, + /* 24 */ 1689, INVALID, INVALID, INVALID, + /* 28 */ 1618, 1704, 1677, 1679, + /* 2c */ GROUP(365), GROUP(366), GROUP(367), GROUP(368), + /* 30 */ 1692, 1694, 1696, 1698, + /* 34 */ 1700, 1702, INVALID, 1713, + /* 38 */ 1620, 1622, 1624, 1626, + /* 3c */ 1628, 1630, 1634, 1632, + /* 40 */ 1636, 1638, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, 46, + /* dc */ 42, 44, 38, 40, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__358[] = { + /* 0 */ 1732, INVALID, +}; + +static const uint16_t ud_itab__359[] = { + /* 0 */ 1730, INVALID, +}; + +static const uint16_t ud_itab__360[] = { + /* 0 */ 1735, INVALID, +}; + +static const uint16_t ud_itab__361[] = { + /* 0 */ 1736, INVALID, +}; + +static const uint16_t ud_itab__362[] = { + /* 0 */ 1722, INVALID, +}; + +static const uint16_t ud_itab__363[] = { + /* 0 */ GROUP(364), INVALID, +}; + +static const uint16_t ud_itab__364[] = { + /* 0 */ INVALID, 1723, +}; + +static const uint16_t ud_itab__365[] = { + /* 0 */ 1726, INVALID, +}; + +static const uint16_t ud_itab__366[] = { + /* 0 */ 1728, INVALID, +}; + +static const uint16_t ud_itab__367[] = { + /* 0 */ 1727, INVALID, +}; + +static const uint16_t ud_itab__368[] = { + /* 0 */ 1729, INVALID, +}; + +static const uint16_t ud_itab__369[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ GROUP(370), GROUP(371), GROUP(372), INVALID, + /* 8 */ 1640, 1642, 1644, 1646, + /* c */ 1650, 1648, 1673, 1615, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(374), 1053, GROUP(375), 202, + /* 18 */ GROUP(379), GROUP(381), INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(383), 1553, GROUP(385), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 198, 196, 1675, INVALID, + /* 44 */ 1509, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, GROUP(391), GROUP(392), + /* 4c */ GROUP(393), INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ 1711, 1709, 1717, 1715, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, 48, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__370[] = { + /* 0 */ 1733, INVALID, +}; + +static const uint16_t ud_itab__371[] = { + /* 0 */ 1731, INVALID, +}; + +static const uint16_t ud_itab__372[] = { + /* 0 */ GROUP(373), INVALID, +}; + +static const uint16_t ud_itab__373[] = { + /* 0 */ INVALID, 1734, +}; + +static const uint16_t ud_itab__374[] = { + /* 0 */ 1042, INVALID, +}; + +static const uint16_t ud_itab__375[] = { + /* 0 */ GROUP(376), GROUP(377), GROUP(378), +}; + +static const uint16_t ud_itab__376[] = { + /* 0 */ 1044, INVALID, +}; + +static const uint16_t ud_itab__377[] = { + /* 0 */ 1046, INVALID, +}; + +static const uint16_t ud_itab__378[] = { + /* 0 */ INVALID, 1048, +}; + +static const uint16_t ud_itab__379[] = { + /* 0 */ GROUP(380), INVALID, +}; + +static const uint16_t ud_itab__380[] = { + /* 0 */ INVALID, 1725, +}; + +static const uint16_t ud_itab__381[] = { + /* 0 */ GROUP(382), INVALID, +}; + +static const uint16_t ud_itab__382[] = { + /* 0 */ INVALID, 1724, +}; + +static const uint16_t ud_itab__383[] = { + /* 0 */ GROUP(384), INVALID, +}; + +static const uint16_t ud_itab__384[] = { + /* 0 */ 1061, INVALID, +}; + +static const uint16_t ud_itab__385[] = { + /* 0 */ GROUP(386), GROUP(388), +}; + +static const uint16_t ud_itab__386[] = { + /* 0 */ GROUP(387), INVALID, +}; + +static const uint16_t ud_itab__387[] = { + /* 0 */ 1062, INVALID, +}; + +static const uint16_t ud_itab__388[] = { + /* 0 */ GROUP(389), GROUP(390), +}; + +static const uint16_t ud_itab__389[] = { + /* 0 */ 1063, INVALID, +}; + +static const uint16_t ud_itab__390[] = { + /* 0 */ 1064, INVALID, +}; + +static const uint16_t ud_itab__391[] = { + /* 0 */ 1740, INVALID, +}; + +static const uint16_t ud_itab__392[] = { + /* 0 */ 1739, INVALID, +}; + +static const uint16_t ud_itab__393[] = { + /* 0 */ 1749, INVALID, +}; + +static const uint16_t ud_itab__394[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(395), GROUP(396), GROUP(397), INVALID, + /* 14 */ INVALID, INVALID, GROUP(398), INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 155, INVALID, + /* 2c */ 169, 159, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1390, 1305, 1290, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 32, 947, 157, 164, + /* 5c */ 1420, 819, 194, 803, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, 1519, + /* 70 */ 1531, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, 913, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 121, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 133, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__395[] = { + /* 0 */ 1746, 1745, +}; + +static const uint16_t ud_itab__396[] = { + /* 0 */ 1748, 1747, +}; + +static const uint16_t ud_itab__397[] = { + /* 0 */ 1567, 1565, +}; + +static const uint16_t ud_itab__398[] = { + /* 0 */ 1563, 1561, +}; + +static const uint16_t ud_itab__399[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(402), GROUP(400), GROUP(401), INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 153, INVALID, + /* 2c */ 167, 149, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1388, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 30, 945, 151, INVALID, + /* 5c */ 1418, 817, 192, 801, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ 1533, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1547, 1551, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 118, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 36, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 137, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ 1555, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__400[] = { + /* 0 */ 1744, 1743, +}; + +static const uint16_t ud_itab__401[] = { + /* 0 */ 1559, 1557, +}; + +static const uint16_t ud_itab__402[] = { + /* 0 */ 1742, 1741, +}; + +static const uint16_t ud_itab__403[] = { + /* 0 */ GROUP(404), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__404[] = { + /* 0 */ 765, INVALID, +}; + +static const uint16_t ud_itab__405[] = { + /* 0 */ 822, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__406[] = { + /* 0 */ 823, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__407[] = { + /* 0 */ 711, INVALID, +}; + +static const uint16_t ud_itab__408[] = { + /* 0 */ 719, 720, 721, +}; + +static const uint16_t ud_itab__409[] = { + /* 0 */ 1276, 1281, 1265, 1269, + /* 4 */ 1322, 1329, 1316, 1310, +}; + +static const uint16_t ud_itab__410[] = { + /* 0 */ 1277, 1284, 1268, 1272, + /* 4 */ 1321, 1328, 1325, 1308, +}; + +static const uint16_t ud_itab__411[] = { + /* 0 */ 1278, 1285, 1266, 1273, + /* 4 */ 1320, 1327, 1317, 1312, +}; + +static const uint16_t ud_itab__412[] = { + /* 0 */ 1279, 1286, 1267, 1274, + /* 4 */ 1324, 1331, 1318, 1313, +}; + +static const uint16_t ud_itab__413[] = { + /* 0 */ 3, INVALID, +}; + +static const uint16_t ud_itab__414[] = { + /* 0 */ 2, INVALID, +}; + +static const uint16_t ud_itab__415[] = { + /* 0 */ 1307, INVALID, +}; + +static const uint16_t ud_itab__416[] = { + /* 0 */ GROUP(417), GROUP(418), +}; + +static const uint16_t ud_itab__417[] = { + /* 0 */ 206, 503, 307, 357, + /* 4 */ 583, 626, 387, 413, +}; + +static const uint16_t ud_itab__418[] = { + /* 0 */ 215, 216, 217, 218, + /* 4 */ 219, 220, 221, 222, + /* 8 */ 504, 505, 506, 507, + /* c */ 508, 509, 510, 511, + /* 10 */ 309, 310, 311, 312, + /* 14 */ 313, 314, 315, 316, + /* 18 */ 359, 360, 361, 362, + /* 1c */ 363, 364, 365, 366, + /* 20 */ 585, 586, 587, 588, + /* 24 */ 589, 590, 591, 592, + /* 28 */ 610, 611, 612, 613, + /* 2c */ 614, 615, 616, 617, + /* 30 */ 388, 389, 390, 391, + /* 34 */ 392, 393, 394, 395, + /* 38 */ 414, 415, 416, 417, + /* 3c */ 418, 419, 420, 421, +}; + +static const uint16_t ud_itab__419[] = { + /* 0 */ GROUP(420), GROUP(421), +}; + +static const uint16_t ud_itab__420[] = { + /* 0 */ 476, INVALID, 569, 536, + /* 4 */ 493, 492, 580, 579, +}; + +static const uint16_t ud_itab__421[] = { + /* 0 */ 477, 478, 479, 480, + /* 4 */ 481, 482, 483, 484, + /* 8 */ 654, 655, 656, 657, + /* c */ 658, 659, 660, 661, + /* 10 */ 522, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ 545, 546, 547, 548, + /* 1c */ 549, 550, 551, 552, + /* 20 */ 233, 204, INVALID, INVALID, + /* 24 */ 635, 653, INVALID, INVALID, + /* 28 */ 485, 486, 487, 488, + /* 2c */ 489, 490, 491, INVALID, + /* 30 */ 203, 681, 526, 523, + /* 34 */ 680, 525, 377, 454, + /* 38 */ 524, 682, 533, 532, + /* 3c */ 527, 530, 531, 376, +}; + +static const uint16_t ud_itab__422[] = { + /* 0 */ GROUP(423), GROUP(424), +}; + +static const uint16_t ud_itab__423[] = { + /* 0 */ 456, 520, 448, 450, + /* 4 */ 462, 464, 460, 458, +}; + +static const uint16_t ud_itab__424[] = { + /* 0 */ 235, 236, 237, 238, + /* 4 */ 239, 240, 241, 242, + /* 8 */ 243, 244, 245, 246, + /* c */ 247, 248, 249, 250, + /* 10 */ 251, 252, 253, 254, + /* 14 */ 255, 256, 257, 258, + /* 18 */ 259, 260, 261, 262, + /* 1c */ 263, 264, 265, 266, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, 652, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__425[] = { + /* 0 */ GROUP(426), GROUP(427), +}; + +static const uint16_t ud_itab__426[] = { + /* 0 */ 453, 471, 467, 470, + /* 4 */ INVALID, 474, INVALID, 534, +}; + +static const uint16_t ud_itab__427[] = { + /* 0 */ 267, 268, 269, 270, + /* 4 */ 271, 272, 273, 274, + /* 8 */ 275, 276, 277, 278, + /* c */ 279, 280, 281, 282, + /* 10 */ 283, 284, 285, 286, + /* 14 */ 287, 288, 289, 290, + /* 18 */ 291, 292, 293, 294, + /* 1c */ 295, 296, 297, 298, + /* 20 */ INVALID, INVALID, 234, 455, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 299, 300, 301, 302, + /* 2c */ 303, 304, 305, 306, + /* 30 */ 333, 334, 335, 336, + /* 34 */ 337, 338, 339, 340, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__428[] = { + /* 0 */ GROUP(429), GROUP(430), +}; + +static const uint16_t ud_itab__429[] = { + /* 0 */ 205, 494, 308, 358, + /* 4 */ 584, 609, 378, 404, +}; + +static const uint16_t ud_itab__430[] = { + /* 0 */ 207, 208, 209, 210, + /* 4 */ 211, 212, 213, 214, + /* 8 */ 495, 496, 497, 498, + /* c */ 499, 500, 501, 502, + /* 10 */ 317, 318, 319, 320, + /* 14 */ 321, 322, 323, 324, + /* 18 */ 325, 326, 327, 328, + /* 1c */ 329, 330, 331, 332, + /* 20 */ 618, 619, 620, 621, + /* 24 */ 622, 623, 624, 625, + /* 28 */ 593, 594, 595, 596, + /* 2c */ 597, 598, 599, 600, + /* 30 */ 405, 406, 407, 408, + /* 34 */ 409, 410, 411, 412, + /* 38 */ 379, 380, 381, 382, + /* 3c */ 383, 384, 385, 386, +}; + +static const uint16_t ud_itab__431[] = { + /* 0 */ GROUP(432), GROUP(433), +}; + +static const uint16_t ud_itab__432[] = { + /* 0 */ 475, 472, 570, 535, + /* 4 */ 528, INVALID, 529, 581, +}; + +static const uint16_t ud_itab__433[] = { + /* 0 */ 431, 432, 433, 434, + /* 4 */ 435, 436, 437, 438, + /* 8 */ 662, 663, 664, 665, + /* c */ 666, 667, 668, 669, + /* 10 */ 571, 572, 573, 574, + /* 14 */ 575, 576, 577, 578, + /* 18 */ 537, 538, 539, 540, + /* 1c */ 541, 542, 543, 544, + /* 20 */ 636, 637, 638, 639, + /* 24 */ 640, 641, 642, 643, + /* 28 */ 644, 645, 646, 647, + /* 2c */ 648, 649, 650, 651, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__434[] = { + /* 0 */ GROUP(435), GROUP(436), +}; + +static const uint16_t ud_itab__435[] = { + /* 0 */ 457, 521, 447, 449, + /* 4 */ 463, 465, 461, 459, +}; + +static const uint16_t ud_itab__436[] = { + /* 0 */ 223, 224, 225, 226, + /* 4 */ 227, 228, 229, 230, + /* 8 */ 512, 513, 514, 515, + /* c */ 516, 517, 518, 519, + /* 10 */ 367, 368, 369, 370, + /* 14 */ 371, 372, 373, 374, + /* 18 */ INVALID, 375, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ 627, 628, 629, 630, + /* 24 */ 631, 632, 633, 634, + /* 28 */ 601, 602, 603, 604, + /* 2c */ 605, 606, 607, 608, + /* 30 */ 422, 423, 424, 425, + /* 34 */ 426, 427, 428, 429, + /* 38 */ 396, 397, 398, 399, + /* 3c */ 400, 401, 402, 403, +}; + +static const uint16_t ud_itab__437[] = { + /* 0 */ GROUP(438), GROUP(439), +}; + +static const uint16_t ud_itab__438[] = { + /* 0 */ 451, 473, 466, 468, + /* 4 */ 231, 452, 232, 469, +}; + +static const uint16_t ud_itab__439[] = { + /* 0 */ 439, 440, 441, 442, + /* 4 */ 443, 444, 445, 446, + /* 8 */ 670, 671, 672, 673, + /* c */ 674, 675, 676, 677, + /* 10 */ 553, 554, 555, 556, + /* 14 */ 557, 558, 559, 560, + /* 18 */ 561, 562, 563, 564, + /* 1c */ 565, 566, 567, 568, + /* 20 */ 582, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 341, 342, 343, 344, + /* 2c */ 345, 346, 347, 348, + /* 30 */ 349, 350, 351, 352, + /* 34 */ 353, 354, 355, 356, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__440[] = { + /* 0 */ 754, 755, 756, +}; + +static const uint16_t ud_itab__441[] = { + /* 0 */ 760, INVALID, +}; + +static const uint16_t ud_itab__442[] = { + /* 0 */ 1428, 1433, 958, 949, + /* 4 */ 938, 691, 186, 685, +}; + +static const uint16_t ud_itab__443[] = { + /* 0 */ 1434, 1435, 959, 950, + /* 4 */ 939, 692, 185, 684, +}; + +static const uint16_t ud_itab__444[] = { + /* 0 */ 704, 183, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__445[] = { + /* 0 */ 703, 184, GROUP(446), 71, + /* 4 */ 757, 758, 1251, INVALID, +}; + +static const uint16_t ud_itab__446[] = { + /* 0 */ 69, 70, +}; + + +struct ud_lookup_table_list_entry ud_lookup_table_list[] = { + /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "opctbl" }, + /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" }, + /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" }, + /* 003 */ { ud_itab__3, UD_TAB__OPC_MODE, "/m" }, + /* 004 */ { ud_itab__4, UD_TAB__OPC_TABLE, "opctbl" }, + /* 005 */ { ud_itab__5, UD_TAB__OPC_REG, "/reg" }, + /* 006 */ { ud_itab__6, UD_TAB__OPC_MOD, "/mod" }, + /* 007 */ { ud_itab__7, UD_TAB__OPC_REG, "/reg" }, + /* 008 */ { ud_itab__8, UD_TAB__OPC_REG, "/reg" }, + /* 009 */ { ud_itab__9, UD_TAB__OPC_RM, "/rm" }, + /* 010 */ { ud_itab__10, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 011 */ { ud_itab__11, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 012 */ { ud_itab__12, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 013 */ { ud_itab__13, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 014 */ { ud_itab__14, UD_TAB__OPC_RM, "/rm" }, + /* 015 */ { ud_itab__15, UD_TAB__OPC_RM, "/rm" }, + /* 016 */ { ud_itab__16, UD_TAB__OPC_RM, "/rm" }, + /* 017 */ { ud_itab__17, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 018 */ { ud_itab__18, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 019 */ { ud_itab__19, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 020 */ { ud_itab__20, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 021 */ { ud_itab__21, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 022 */ { ud_itab__22, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 023 */ { ud_itab__23, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 024 */ { ud_itab__24, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 025 */ { ud_itab__25, UD_TAB__OPC_RM, "/rm" }, + /* 026 */ { ud_itab__26, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 027 */ { ud_itab__27, UD_TAB__OPC_REG, "/reg" }, + /* 028 */ { ud_itab__28, UD_TAB__OPC_3DNOW, "/3dnow" }, + /* 029 */ { ud_itab__29, UD_TAB__OPC_SSE, "/sse" }, + /* 030 */ { ud_itab__30, UD_TAB__OPC_SSE, "/sse" }, + /* 031 */ { ud_itab__31, UD_TAB__OPC_MOD, "/mod" }, + /* 032 */ { ud_itab__32, UD_TAB__OPC_SSE, "/sse" }, + /* 033 */ { ud_itab__33, UD_TAB__OPC_SSE, "/sse" }, + /* 034 */ { ud_itab__34, UD_TAB__OPC_SSE, "/sse" }, + /* 035 */ { ud_itab__35, UD_TAB__OPC_SSE, "/sse" }, + /* 036 */ { ud_itab__36, UD_TAB__OPC_SSE, "/sse" }, + /* 037 */ { ud_itab__37, UD_TAB__OPC_MOD, "/mod" }, + /* 038 */ { ud_itab__38, UD_TAB__OPC_SSE, "/sse" }, + /* 039 */ { ud_itab__39, UD_TAB__OPC_SSE, "/sse" }, + /* 040 */ { ud_itab__40, UD_TAB__OPC_SSE, "/sse" }, + /* 041 */ { ud_itab__41, UD_TAB__OPC_REG, "/reg" }, + /* 042 */ { ud_itab__42, UD_TAB__OPC_SSE, "/sse" }, + /* 043 */ { ud_itab__43, UD_TAB__OPC_SSE, "/sse" }, + /* 044 */ { ud_itab__44, UD_TAB__OPC_SSE, "/sse" }, + /* 045 */ { ud_itab__45, UD_TAB__OPC_SSE, "/sse" }, + /* 046 */ { ud_itab__46, UD_TAB__OPC_SSE, "/sse" }, + /* 047 */ { ud_itab__47, UD_TAB__OPC_SSE, "/sse" }, + /* 048 */ { ud_itab__48, UD_TAB__OPC_SSE, "/sse" }, + /* 049 */ { ud_itab__49, UD_TAB__OPC_SSE, "/sse" }, + /* 050 */ { ud_itab__50, UD_TAB__OPC_MODE, "/m" }, + /* 051 */ { ud_itab__51, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 052 */ { ud_itab__52, UD_TAB__OPC_MODE, "/m" }, + /* 053 */ { ud_itab__53, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 054 */ { ud_itab__54, UD_TAB__OPC_TABLE, "opctbl" }, + /* 055 */ { ud_itab__55, UD_TAB__OPC_SSE, "/sse" }, + /* 056 */ { ud_itab__56, UD_TAB__OPC_MODE, "/m" }, + /* 057 */ { ud_itab__57, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 058 */ { ud_itab__58, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 059 */ { ud_itab__59, UD_TAB__OPC_SSE, "/sse" }, + /* 060 */ { ud_itab__60, UD_TAB__OPC_MODE, "/m" }, + /* 061 */ { ud_itab__61, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 062 */ { ud_itab__62, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 063 */ { ud_itab__63, UD_TAB__OPC_SSE, "/sse" }, + /* 064 */ { ud_itab__64, UD_TAB__OPC_SSE, "/sse" }, + /* 065 */ { ud_itab__65, UD_TAB__OPC_SSE, "/sse" }, + /* 066 */ { ud_itab__66, UD_TAB__OPC_SSE, "/sse" }, + /* 067 */ { ud_itab__67, UD_TAB__OPC_SSE, "/sse" }, + /* 068 */ { ud_itab__68, UD_TAB__OPC_SSE, "/sse" }, + /* 069 */ { ud_itab__69, UD_TAB__OPC_SSE, "/sse" }, + /* 070 */ { ud_itab__70, UD_TAB__OPC_SSE, "/sse" }, + /* 071 */ { ud_itab__71, UD_TAB__OPC_SSE, "/sse" }, + /* 072 */ { ud_itab__72, UD_TAB__OPC_SSE, "/sse" }, + /* 073 */ { ud_itab__73, UD_TAB__OPC_SSE, "/sse" }, + /* 074 */ { ud_itab__74, UD_TAB__OPC_SSE, "/sse" }, + /* 075 */ { ud_itab__75, UD_TAB__OPC_SSE, "/sse" }, + /* 076 */ { ud_itab__76, UD_TAB__OPC_SSE, "/sse" }, + /* 077 */ { ud_itab__77, UD_TAB__OPC_SSE, "/sse" }, + /* 078 */ { ud_itab__78, UD_TAB__OPC_SSE, "/sse" }, + /* 079 */ { ud_itab__79, UD_TAB__OPC_SSE, "/sse" }, + /* 080 */ { ud_itab__80, UD_TAB__OPC_SSE, "/sse" }, + /* 081 */ { ud_itab__81, UD_TAB__OPC_SSE, "/sse" }, + /* 082 */ { ud_itab__82, UD_TAB__OPC_SSE, "/sse" }, + /* 083 */ { ud_itab__83, UD_TAB__OPC_SSE, "/sse" }, + /* 084 */ { ud_itab__84, UD_TAB__OPC_SSE, "/sse" }, + /* 085 */ { ud_itab__85, UD_TAB__OPC_SSE, "/sse" }, + /* 086 */ { ud_itab__86, UD_TAB__OPC_SSE, "/sse" }, + /* 087 */ { ud_itab__87, UD_TAB__OPC_SSE, "/sse" }, + /* 088 */ { ud_itab__88, UD_TAB__OPC_SSE, "/sse" }, + /* 089 */ { ud_itab__89, UD_TAB__OPC_SSE, "/sse" }, + /* 090 */ { ud_itab__90, UD_TAB__OPC_SSE, "/sse" }, + /* 091 */ { ud_itab__91, UD_TAB__OPC_SSE, "/sse" }, + /* 092 */ { ud_itab__92, UD_TAB__OPC_SSE, "/sse" }, + /* 093 */ { ud_itab__93, UD_TAB__OPC_SSE, "/sse" }, + /* 094 */ { ud_itab__94, UD_TAB__OPC_SSE, "/sse" }, + /* 095 */ { ud_itab__95, UD_TAB__OPC_SSE, "/sse" }, + /* 096 */ { ud_itab__96, UD_TAB__OPC_SSE, "/sse" }, + /* 097 */ { ud_itab__97, UD_TAB__OPC_SSE, "/sse" }, + /* 098 */ { ud_itab__98, UD_TAB__OPC_SSE, "/sse" }, + /* 099 */ { ud_itab__99, UD_TAB__OPC_SSE, "/sse" }, + /* 100 */ { ud_itab__100, UD_TAB__OPC_SSE, "/sse" }, + /* 101 */ { ud_itab__101, UD_TAB__OPC_SSE, "/sse" }, + /* 102 */ { ud_itab__102, UD_TAB__OPC_SSE, "/sse" }, + /* 103 */ { ud_itab__103, UD_TAB__OPC_SSE, "/sse" }, + /* 104 */ { ud_itab__104, UD_TAB__OPC_SSE, "/sse" }, + /* 105 */ { ud_itab__105, UD_TAB__OPC_SSE, "/sse" }, + /* 106 */ { ud_itab__106, UD_TAB__OPC_SSE, "/sse" }, + /* 107 */ { ud_itab__107, UD_TAB__OPC_SSE, "/sse" }, + /* 108 */ { ud_itab__108, UD_TAB__OPC_SSE, "/sse" }, + /* 109 */ { ud_itab__109, UD_TAB__OPC_SSE, "/sse" }, + /* 110 */ { ud_itab__110, UD_TAB__OPC_SSE, "/sse" }, + /* 111 */ { ud_itab__111, UD_TAB__OPC_SSE, "/sse" }, + /* 112 */ { ud_itab__112, UD_TAB__OPC_SSE, "/sse" }, + /* 113 */ { ud_itab__113, UD_TAB__OPC_SSE, "/sse" }, + /* 114 */ { ud_itab__114, UD_TAB__OPC_SSE, "/sse" }, + /* 115 */ { ud_itab__115, UD_TAB__OPC_SSE, "/sse" }, + /* 116 */ { ud_itab__116, UD_TAB__OPC_TABLE, "opctbl" }, + /* 117 */ { ud_itab__117, UD_TAB__OPC_SSE, "/sse" }, + /* 118 */ { ud_itab__118, UD_TAB__OPC_SSE, "/sse" }, + /* 119 */ { ud_itab__119, UD_TAB__OPC_SSE, "/sse" }, + /* 120 */ { ud_itab__120, UD_TAB__OPC_SSE, "/sse" }, + /* 121 */ { ud_itab__121, UD_TAB__OPC_SSE, "/sse" }, + /* 122 */ { ud_itab__122, UD_TAB__OPC_SSE, "/sse" }, + /* 123 */ { ud_itab__123, UD_TAB__OPC_SSE, "/sse" }, + /* 124 */ { ud_itab__124, UD_TAB__OPC_SSE, "/sse" }, + /* 125 */ { ud_itab__125, UD_TAB__OPC_SSE, "/sse" }, + /* 126 */ { ud_itab__126, UD_TAB__OPC_SSE, "/sse" }, + /* 127 */ { ud_itab__127, UD_TAB__OPC_SSE, "/sse" }, + /* 128 */ { ud_itab__128, UD_TAB__OPC_OSIZE, "/o" }, + /* 129 */ { ud_itab__129, UD_TAB__OPC_SSE, "/sse" }, + /* 130 */ { ud_itab__130, UD_TAB__OPC_SSE, "/sse" }, + /* 131 */ { ud_itab__131, UD_TAB__OPC_SSE, "/sse" }, + /* 132 */ { ud_itab__132, UD_TAB__OPC_SSE, "/sse" }, + /* 133 */ { ud_itab__133, UD_TAB__OPC_OSIZE, "/o" }, + /* 134 */ { ud_itab__134, UD_TAB__OPC_SSE, "/sse" }, + /* 135 */ { ud_itab__135, UD_TAB__OPC_SSE, "/sse" }, + /* 136 */ { ud_itab__136, UD_TAB__OPC_SSE, "/sse" }, + /* 137 */ { ud_itab__137, UD_TAB__OPC_SSE, "/sse" }, + /* 138 */ { ud_itab__138, UD_TAB__OPC_SSE, "/sse" }, + /* 139 */ { ud_itab__139, UD_TAB__OPC_SSE, "/sse" }, + /* 140 */ { ud_itab__140, UD_TAB__OPC_SSE, "/sse" }, + /* 141 */ { ud_itab__141, UD_TAB__OPC_SSE, "/sse" }, + /* 142 */ { ud_itab__142, UD_TAB__OPC_SSE, "/sse" }, + /* 143 */ { ud_itab__143, UD_TAB__OPC_SSE, "/sse" }, + /* 144 */ { ud_itab__144, UD_TAB__OPC_SSE, "/sse" }, + /* 145 */ { ud_itab__145, UD_TAB__OPC_SSE, "/sse" }, + /* 146 */ { ud_itab__146, UD_TAB__OPC_SSE, "/sse" }, + /* 147 */ { ud_itab__147, UD_TAB__OPC_SSE, "/sse" }, + /* 148 */ { ud_itab__148, UD_TAB__OPC_SSE, "/sse" }, + /* 149 */ { ud_itab__149, UD_TAB__OPC_SSE, "/sse" }, + /* 150 */ { ud_itab__150, UD_TAB__OPC_SSE, "/sse" }, + /* 151 */ { ud_itab__151, UD_TAB__OPC_SSE, "/sse" }, + /* 152 */ { ud_itab__152, UD_TAB__OPC_SSE, "/sse" }, + /* 153 */ { ud_itab__153, UD_TAB__OPC_SSE, "/sse" }, + /* 154 */ { ud_itab__154, UD_TAB__OPC_SSE, "/sse" }, + /* 155 */ { ud_itab__155, UD_TAB__OPC_SSE, "/sse" }, + /* 156 */ { ud_itab__156, UD_TAB__OPC_SSE, "/sse" }, + /* 157 */ { ud_itab__157, UD_TAB__OPC_SSE, "/sse" }, + /* 158 */ { ud_itab__158, UD_TAB__OPC_SSE, "/sse" }, + /* 159 */ { ud_itab__159, UD_TAB__OPC_SSE, "/sse" }, + /* 160 */ { ud_itab__160, UD_TAB__OPC_SSE, "/sse" }, + /* 161 */ { ud_itab__161, UD_TAB__OPC_SSE, "/sse" }, + /* 162 */ { ud_itab__162, UD_TAB__OPC_SSE, "/sse" }, + /* 163 */ { ud_itab__163, UD_TAB__OPC_SSE, "/sse" }, + /* 164 */ { ud_itab__164, UD_TAB__OPC_SSE, "/sse" }, + /* 165 */ { ud_itab__165, UD_TAB__OPC_SSE, "/sse" }, + /* 166 */ { ud_itab__166, UD_TAB__OPC_SSE, "/sse" }, + /* 167 */ { ud_itab__167, UD_TAB__OPC_SSE, "/sse" }, + /* 168 */ { ud_itab__168, UD_TAB__OPC_SSE, "/sse" }, + /* 169 */ { ud_itab__169, UD_TAB__OPC_SSE, "/sse" }, + /* 170 */ { ud_itab__170, UD_TAB__OPC_SSE, "/sse" }, + /* 171 */ { ud_itab__171, UD_TAB__OPC_SSE, "/sse" }, + /* 172 */ { ud_itab__172, UD_TAB__OPC_SSE, "/sse" }, + /* 173 */ { ud_itab__173, UD_TAB__OPC_SSE, "/sse" }, + /* 174 */ { ud_itab__174, UD_TAB__OPC_OSIZE, "/o" }, + /* 175 */ { ud_itab__175, UD_TAB__OPC_OSIZE, "/o" }, + /* 176 */ { ud_itab__176, UD_TAB__OPC_SSE, "/sse" }, + /* 177 */ { ud_itab__177, UD_TAB__OPC_SSE, "/sse" }, + /* 178 */ { ud_itab__178, UD_TAB__OPC_REG, "/reg" }, + /* 179 */ { ud_itab__179, UD_TAB__OPC_SSE, "/sse" }, + /* 180 */ { ud_itab__180, UD_TAB__OPC_SSE, "/sse" }, + /* 181 */ { ud_itab__181, UD_TAB__OPC_SSE, "/sse" }, + /* 182 */ { ud_itab__182, UD_TAB__OPC_REG, "/reg" }, + /* 183 */ { ud_itab__183, UD_TAB__OPC_SSE, "/sse" }, + /* 184 */ { ud_itab__184, UD_TAB__OPC_SSE, "/sse" }, + /* 185 */ { ud_itab__185, UD_TAB__OPC_SSE, "/sse" }, + /* 186 */ { ud_itab__186, UD_TAB__OPC_REG, "/reg" }, + /* 187 */ { ud_itab__187, UD_TAB__OPC_SSE, "/sse" }, + /* 188 */ { ud_itab__188, UD_TAB__OPC_SSE, "/sse" }, + /* 189 */ { ud_itab__189, UD_TAB__OPC_SSE, "/sse" }, + /* 190 */ { ud_itab__190, UD_TAB__OPC_SSE, "/sse" }, + /* 191 */ { ud_itab__191, UD_TAB__OPC_SSE, "/sse" }, + /* 192 */ { ud_itab__192, UD_TAB__OPC_SSE, "/sse" }, + /* 193 */ { ud_itab__193, UD_TAB__OPC_SSE, "/sse" }, + /* 194 */ { ud_itab__194, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 195 */ { ud_itab__195, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 196 */ { ud_itab__196, UD_TAB__OPC_SSE, "/sse" }, + /* 197 */ { ud_itab__197, UD_TAB__OPC_SSE, "/sse" }, + /* 198 */ { ud_itab__198, UD_TAB__OPC_SSE, "/sse" }, + /* 199 */ { ud_itab__199, UD_TAB__OPC_OSIZE, "/o" }, + /* 200 */ { ud_itab__200, UD_TAB__OPC_OSIZE, "/o" }, + /* 201 */ { ud_itab__201, UD_TAB__OPC_SSE, "/sse" }, + /* 202 */ { ud_itab__202, UD_TAB__OPC_MOD, "/mod" }, + /* 203 */ { ud_itab__203, UD_TAB__OPC_REG, "/reg" }, + /* 204 */ { ud_itab__204, UD_TAB__OPC_RM, "/rm" }, + /* 205 */ { ud_itab__205, UD_TAB__OPC_RM, "/rm" }, + /* 206 */ { ud_itab__206, UD_TAB__OPC_RM, "/rm" }, + /* 207 */ { ud_itab__207, UD_TAB__OPC_MOD, "/mod" }, + /* 208 */ { ud_itab__208, UD_TAB__OPC_REG, "/reg" }, + /* 209 */ { ud_itab__209, UD_TAB__OPC_RM, "/rm" }, + /* 210 */ { ud_itab__210, UD_TAB__OPC_RM, "/rm" }, + /* 211 */ { ud_itab__211, UD_TAB__OPC_RM, "/rm" }, + /* 212 */ { ud_itab__212, UD_TAB__OPC_RM, "/rm" }, + /* 213 */ { ud_itab__213, UD_TAB__OPC_RM, "/rm" }, + /* 214 */ { ud_itab__214, UD_TAB__OPC_RM, "/rm" }, + /* 215 */ { ud_itab__215, UD_TAB__OPC_MOD, "/mod" }, + /* 216 */ { ud_itab__216, UD_TAB__OPC_REG, "/reg" }, + /* 217 */ { ud_itab__217, UD_TAB__OPC_REG, "/reg" }, + /* 218 */ { ud_itab__218, UD_TAB__OPC_RM, "/rm" }, + /* 219 */ { ud_itab__219, UD_TAB__OPC_RM, "/rm" }, + /* 220 */ { ud_itab__220, UD_TAB__OPC_RM, "/rm" }, + /* 221 */ { ud_itab__221, UD_TAB__OPC_SSE, "/sse" }, + /* 222 */ { ud_itab__222, UD_TAB__OPC_REG, "/reg" }, + /* 223 */ { ud_itab__223, UD_TAB__OPC_SSE, "/sse" }, + /* 224 */ { ud_itab__224, UD_TAB__OPC_SSE, "/sse" }, + /* 225 */ { ud_itab__225, UD_TAB__OPC_SSE, "/sse" }, + /* 226 */ { ud_itab__226, UD_TAB__OPC_SSE, "/sse" }, + /* 227 */ { ud_itab__227, UD_TAB__OPC_MOD, "/mod" }, + /* 228 */ { ud_itab__228, UD_TAB__OPC_REG, "/reg" }, + /* 229 */ { ud_itab__229, UD_TAB__OPC_OSIZE, "/o" }, + /* 230 */ { ud_itab__230, UD_TAB__OPC_SSE, "/sse" }, + /* 231 */ { ud_itab__231, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 232 */ { ud_itab__232, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 233 */ { ud_itab__233, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 234 */ { ud_itab__234, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 235 */ { ud_itab__235, UD_TAB__OPC_REG, "/reg" }, + /* 236 */ { ud_itab__236, UD_TAB__OPC_SSE, "/sse" }, + /* 237 */ { ud_itab__237, UD_TAB__OPC_SSE, "/sse" }, + /* 238 */ { ud_itab__238, UD_TAB__OPC_SSE, "/sse" }, + /* 239 */ { ud_itab__239, UD_TAB__OPC_SSE, "/sse" }, + /* 240 */ { ud_itab__240, UD_TAB__OPC_SSE, "/sse" }, + /* 241 */ { ud_itab__241, UD_TAB__OPC_SSE, "/sse" }, + /* 242 */ { ud_itab__242, UD_TAB__OPC_SSE, "/sse" }, + /* 243 */ { ud_itab__243, UD_TAB__OPC_SSE, "/sse" }, + /* 244 */ { ud_itab__244, UD_TAB__OPC_SSE, "/sse" }, + /* 245 */ { ud_itab__245, UD_TAB__OPC_SSE, "/sse" }, + /* 246 */ { ud_itab__246, UD_TAB__OPC_SSE, "/sse" }, + /* 247 */ { ud_itab__247, UD_TAB__OPC_SSE, "/sse" }, + /* 248 */ { ud_itab__248, UD_TAB__OPC_SSE, "/sse" }, + /* 249 */ { ud_itab__249, UD_TAB__OPC_SSE, "/sse" }, + /* 250 */ { ud_itab__250, UD_TAB__OPC_SSE, "/sse" }, + /* 251 */ { ud_itab__251, UD_TAB__OPC_SSE, "/sse" }, + /* 252 */ { ud_itab__252, UD_TAB__OPC_SSE, "/sse" }, + /* 253 */ { ud_itab__253, UD_TAB__OPC_SSE, "/sse" }, + /* 254 */ { ud_itab__254, UD_TAB__OPC_SSE, "/sse" }, + /* 255 */ { ud_itab__255, UD_TAB__OPC_SSE, "/sse" }, + /* 256 */ { ud_itab__256, UD_TAB__OPC_SSE, "/sse" }, + /* 257 */ { ud_itab__257, UD_TAB__OPC_SSE, "/sse" }, + /* 258 */ { ud_itab__258, UD_TAB__OPC_SSE, "/sse" }, + /* 259 */ { ud_itab__259, UD_TAB__OPC_SSE, "/sse" }, + /* 260 */ { ud_itab__260, UD_TAB__OPC_SSE, "/sse" }, + /* 261 */ { ud_itab__261, UD_TAB__OPC_SSE, "/sse" }, + /* 262 */ { ud_itab__262, UD_TAB__OPC_SSE, "/sse" }, + /* 263 */ { ud_itab__263, UD_TAB__OPC_SSE, "/sse" }, + /* 264 */ { ud_itab__264, UD_TAB__OPC_SSE, "/sse" }, + /* 265 */ { ud_itab__265, UD_TAB__OPC_SSE, "/sse" }, + /* 266 */ { ud_itab__266, UD_TAB__OPC_SSE, "/sse" }, + /* 267 */ { ud_itab__267, UD_TAB__OPC_SSE, "/sse" }, + /* 268 */ { ud_itab__268, UD_TAB__OPC_SSE, "/sse" }, + /* 269 */ { ud_itab__269, UD_TAB__OPC_SSE, "/sse" }, + /* 270 */ { ud_itab__270, UD_TAB__OPC_SSE, "/sse" }, + /* 271 */ { ud_itab__271, UD_TAB__OPC_SSE, "/sse" }, + /* 272 */ { ud_itab__272, UD_TAB__OPC_SSE, "/sse" }, + /* 273 */ { ud_itab__273, UD_TAB__OPC_SSE, "/sse" }, + /* 274 */ { ud_itab__274, UD_TAB__OPC_SSE, "/sse" }, + /* 275 */ { ud_itab__275, UD_TAB__OPC_MOD, "/mod" }, + /* 276 */ { ud_itab__276, UD_TAB__OPC_SSE, "/sse" }, + /* 277 */ { ud_itab__277, UD_TAB__OPC_SSE, "/sse" }, + /* 278 */ { ud_itab__278, UD_TAB__OPC_SSE, "/sse" }, + /* 279 */ { ud_itab__279, UD_TAB__OPC_SSE, "/sse" }, + /* 280 */ { ud_itab__280, UD_TAB__OPC_SSE, "/sse" }, + /* 281 */ { ud_itab__281, UD_TAB__OPC_SSE, "/sse" }, + /* 282 */ { ud_itab__282, UD_TAB__OPC_SSE, "/sse" }, + /* 283 */ { ud_itab__283, UD_TAB__OPC_SSE, "/sse" }, + /* 284 */ { ud_itab__284, UD_TAB__OPC_MODE, "/m" }, + /* 285 */ { ud_itab__285, UD_TAB__OPC_MODE, "/m" }, + /* 286 */ { ud_itab__286, UD_TAB__OPC_MODE, "/m" }, + /* 287 */ { ud_itab__287, UD_TAB__OPC_MODE, "/m" }, + /* 288 */ { ud_itab__288, UD_TAB__OPC_MODE, "/m" }, + /* 289 */ { ud_itab__289, UD_TAB__OPC_MODE, "/m" }, + /* 290 */ { ud_itab__290, UD_TAB__OPC_MODE, "/m" }, + /* 291 */ { ud_itab__291, UD_TAB__OPC_MODE, "/m" }, + /* 292 */ { ud_itab__292, UD_TAB__OPC_OSIZE, "/o" }, + /* 293 */ { ud_itab__293, UD_TAB__OPC_MODE, "/m" }, + /* 294 */ { ud_itab__294, UD_TAB__OPC_MODE, "/m" }, + /* 295 */ { ud_itab__295, UD_TAB__OPC_OSIZE, "/o" }, + /* 296 */ { ud_itab__296, UD_TAB__OPC_MODE, "/m" }, + /* 297 */ { ud_itab__297, UD_TAB__OPC_MODE, "/m" }, + /* 298 */ { ud_itab__298, UD_TAB__OPC_MODE, "/m" }, + /* 299 */ { ud_itab__299, UD_TAB__OPC_MODE, "/m" }, + /* 300 */ { ud_itab__300, UD_TAB__OPC_OSIZE, "/o" }, + /* 301 */ { ud_itab__301, UD_TAB__OPC_OSIZE, "/o" }, + /* 302 */ { ud_itab__302, UD_TAB__OPC_REG, "/reg" }, + /* 303 */ { ud_itab__303, UD_TAB__OPC_REG, "/reg" }, + /* 304 */ { ud_itab__304, UD_TAB__OPC_REG, "/reg" }, + /* 305 */ { ud_itab__305, UD_TAB__OPC_MODE, "/m" }, + /* 306 */ { ud_itab__306, UD_TAB__OPC_MODE, "/m" }, + /* 307 */ { ud_itab__307, UD_TAB__OPC_MODE, "/m" }, + /* 308 */ { ud_itab__308, UD_TAB__OPC_MODE, "/m" }, + /* 309 */ { ud_itab__309, UD_TAB__OPC_MODE, "/m" }, + /* 310 */ { ud_itab__310, UD_TAB__OPC_MODE, "/m" }, + /* 311 */ { ud_itab__311, UD_TAB__OPC_MODE, "/m" }, + /* 312 */ { ud_itab__312, UD_TAB__OPC_MODE, "/m" }, + /* 313 */ { ud_itab__313, UD_TAB__OPC_REG, "/reg" }, + /* 314 */ { ud_itab__314, UD_TAB__OPC_REG, "/reg" }, + /* 315 */ { ud_itab__315, UD_TAB__OPC_OSIZE, "/o" }, + /* 316 */ { ud_itab__316, UD_TAB__OPC_OSIZE, "/o" }, + /* 317 */ { ud_itab__317, UD_TAB__OPC_MODE, "/m" }, + /* 318 */ { ud_itab__318, UD_TAB__OPC_OSIZE, "/o" }, + /* 319 */ { ud_itab__319, UD_TAB__OPC_MODE, "/m" }, + /* 320 */ { ud_itab__320, UD_TAB__OPC_MODE, "/m" }, + /* 321 */ { ud_itab__321, UD_TAB__OPC_MODE, "/m" }, + /* 322 */ { ud_itab__322, UD_TAB__OPC_OSIZE, "/o" }, + /* 323 */ { ud_itab__323, UD_TAB__OPC_MODE, "/m" }, + /* 324 */ { ud_itab__324, UD_TAB__OPC_MODE, "/m" }, + /* 325 */ { ud_itab__325, UD_TAB__OPC_MODE, "/m" }, + /* 326 */ { ud_itab__326, UD_TAB__OPC_OSIZE, "/o" }, + /* 327 */ { ud_itab__327, UD_TAB__OPC_OSIZE, "/o" }, + /* 328 */ { ud_itab__328, UD_TAB__OPC_OSIZE, "/o" }, + /* 329 */ { ud_itab__329, UD_TAB__OPC_OSIZE, "/o" }, + /* 330 */ { ud_itab__330, UD_TAB__OPC_OSIZE, "/o" }, + /* 331 */ { ud_itab__331, UD_TAB__OPC_REG, "/reg" }, + /* 332 */ { ud_itab__332, UD_TAB__OPC_REG, "/reg" }, + /* 333 */ { ud_itab__333, UD_TAB__OPC_VEX, "/vex" }, + /* 334 */ { ud_itab__334, UD_TAB__OPC_MODE, "/m" }, + /* 335 */ { ud_itab__335, UD_TAB__OPC_TABLE, "opctbl" }, + /* 336 */ { ud_itab__336, UD_TAB__OPC_MOD, "/mod" }, + /* 337 */ { ud_itab__337, UD_TAB__OPC_MOD, "/mod" }, + /* 338 */ { ud_itab__338, UD_TAB__OPC_MOD, "/mod" }, + /* 339 */ { ud_itab__339, UD_TAB__OPC_REG, "/reg" }, + /* 340 */ { ud_itab__340, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 341 */ { ud_itab__341, UD_TAB__OPC_TABLE, "opctbl" }, + /* 342 */ { ud_itab__342, UD_TAB__OPC_MOD, "/mod" }, + /* 343 */ { ud_itab__343, UD_TAB__OPC_MOD, "/mod" }, + /* 344 */ { ud_itab__344, UD_TAB__OPC_OSIZE, "/o" }, + /* 345 */ { ud_itab__345, UD_TAB__OPC_REG, "/reg" }, + /* 346 */ { ud_itab__346, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 347 */ { ud_itab__347, UD_TAB__OPC_REG, "/reg" }, + /* 348 */ { ud_itab__348, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 349 */ { ud_itab__349, UD_TAB__OPC_REG, "/reg" }, + /* 350 */ { ud_itab__350, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 351 */ { ud_itab__351, UD_TAB__OPC_OSIZE, "/o" }, + /* 352 */ { ud_itab__352, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 353 */ { ud_itab__353, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 354 */ { ud_itab__354, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 355 */ { ud_itab__355, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 356 */ { ud_itab__356, UD_TAB__OPC_MOD, "/mod" }, + /* 357 */ { ud_itab__357, UD_TAB__OPC_TABLE, "opctbl" }, + /* 358 */ { ud_itab__358, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 359 */ { ud_itab__359, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 360 */ { ud_itab__360, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 361 */ { ud_itab__361, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 362 */ { ud_itab__362, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 363 */ { ud_itab__363, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 364 */ { ud_itab__364, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 365 */ { ud_itab__365, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 366 */ { ud_itab__366, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 367 */ { ud_itab__367, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 368 */ { ud_itab__368, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 369 */ { ud_itab__369, UD_TAB__OPC_TABLE, "opctbl" }, + /* 370 */ { ud_itab__370, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 371 */ { ud_itab__371, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 372 */ { ud_itab__372, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 373 */ { ud_itab__373, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 374 */ { ud_itab__374, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 375 */ { ud_itab__375, UD_TAB__OPC_OSIZE, "/o" }, + /* 376 */ { ud_itab__376, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 377 */ { ud_itab__377, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 378 */ { ud_itab__378, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 379 */ { ud_itab__379, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 380 */ { ud_itab__380, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 381 */ { ud_itab__381, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 382 */ { ud_itab__382, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 383 */ { ud_itab__383, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 384 */ { ud_itab__384, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 385 */ { ud_itab__385, UD_TAB__OPC_MODE, "/m" }, + /* 386 */ { ud_itab__386, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 387 */ { ud_itab__387, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 388 */ { ud_itab__388, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 389 */ { ud_itab__389, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 390 */ { ud_itab__390, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 391 */ { ud_itab__391, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 392 */ { ud_itab__392, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 393 */ { ud_itab__393, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 394 */ { ud_itab__394, UD_TAB__OPC_TABLE, "opctbl" }, + /* 395 */ { ud_itab__395, UD_TAB__OPC_MOD, "/mod" }, + /* 396 */ { ud_itab__396, UD_TAB__OPC_MOD, "/mod" }, + /* 397 */ { ud_itab__397, UD_TAB__OPC_MOD, "/mod" }, + /* 398 */ { ud_itab__398, UD_TAB__OPC_MOD, "/mod" }, + /* 399 */ { ud_itab__399, UD_TAB__OPC_TABLE, "opctbl" }, + /* 400 */ { ud_itab__400, UD_TAB__OPC_MOD, "/mod" }, + /* 401 */ { ud_itab__401, UD_TAB__OPC_MOD, "/mod" }, + /* 402 */ { ud_itab__402, UD_TAB__OPC_MOD, "/mod" }, + /* 403 */ { ud_itab__403, UD_TAB__OPC_VEX, "/vex" }, + /* 404 */ { ud_itab__404, UD_TAB__OPC_MODE, "/m" }, + /* 405 */ { ud_itab__405, UD_TAB__OPC_REG, "/reg" }, + /* 406 */ { ud_itab__406, UD_TAB__OPC_REG, "/reg" }, + /* 407 */ { ud_itab__407, UD_TAB__OPC_MODE, "/m" }, + /* 408 */ { ud_itab__408, UD_TAB__OPC_OSIZE, "/o" }, + /* 409 */ { ud_itab__409, UD_TAB__OPC_REG, "/reg" }, + /* 410 */ { ud_itab__410, UD_TAB__OPC_REG, "/reg" }, + /* 411 */ { ud_itab__411, UD_TAB__OPC_REG, "/reg" }, + /* 412 */ { ud_itab__412, UD_TAB__OPC_REG, "/reg" }, + /* 413 */ { ud_itab__413, UD_TAB__OPC_MODE, "/m" }, + /* 414 */ { ud_itab__414, UD_TAB__OPC_MODE, "/m" }, + /* 415 */ { ud_itab__415, UD_TAB__OPC_MODE, "/m" }, + /* 416 */ { ud_itab__416, UD_TAB__OPC_MOD, "/mod" }, + /* 417 */ { ud_itab__417, UD_TAB__OPC_REG, "/reg" }, + /* 418 */ { ud_itab__418, UD_TAB__OPC_X87, "/x87" }, + /* 419 */ { ud_itab__419, UD_TAB__OPC_MOD, "/mod" }, + /* 420 */ { ud_itab__420, UD_TAB__OPC_REG, "/reg" }, + /* 421 */ { ud_itab__421, UD_TAB__OPC_X87, "/x87" }, + /* 422 */ { ud_itab__422, UD_TAB__OPC_MOD, "/mod" }, + /* 423 */ { ud_itab__423, UD_TAB__OPC_REG, "/reg" }, + /* 424 */ { ud_itab__424, UD_TAB__OPC_X87, "/x87" }, + /* 425 */ { ud_itab__425, UD_TAB__OPC_MOD, "/mod" }, + /* 426 */ { ud_itab__426, UD_TAB__OPC_REG, "/reg" }, + /* 427 */ { ud_itab__427, UD_TAB__OPC_X87, "/x87" }, + /* 428 */ { ud_itab__428, UD_TAB__OPC_MOD, "/mod" }, + /* 429 */ { ud_itab__429, UD_TAB__OPC_REG, "/reg" }, + /* 430 */ { ud_itab__430, UD_TAB__OPC_X87, "/x87" }, + /* 431 */ { ud_itab__431, UD_TAB__OPC_MOD, "/mod" }, + /* 432 */ { ud_itab__432, UD_TAB__OPC_REG, "/reg" }, + /* 433 */ { ud_itab__433, UD_TAB__OPC_X87, "/x87" }, + /* 434 */ { ud_itab__434, UD_TAB__OPC_MOD, "/mod" }, + /* 435 */ { ud_itab__435, UD_TAB__OPC_REG, "/reg" }, + /* 436 */ { ud_itab__436, UD_TAB__OPC_X87, "/x87" }, + /* 437 */ { ud_itab__437, UD_TAB__OPC_MOD, "/mod" }, + /* 438 */ { ud_itab__438, UD_TAB__OPC_REG, "/reg" }, + /* 439 */ { ud_itab__439, UD_TAB__OPC_X87, "/x87" }, + /* 440 */ { ud_itab__440, UD_TAB__OPC_ASIZE, "/a" }, + /* 441 */ { ud_itab__441, UD_TAB__OPC_MODE, "/m" }, + /* 442 */ { ud_itab__442, UD_TAB__OPC_REG, "/reg" }, + /* 443 */ { ud_itab__443, UD_TAB__OPC_REG, "/reg" }, + /* 444 */ { ud_itab__444, UD_TAB__OPC_REG, "/reg" }, + /* 445 */ { ud_itab__445, UD_TAB__OPC_REG, "/reg" }, + /* 446 */ { ud_itab__446, UD_TAB__OPC_MODE, "/m" }, +}; + +/* itab entry operand definitions (for readability) */ +#define O_AL { OP_AL, SZ_B } +#define O_AX { OP_AX, SZ_W } +#define O_Av { OP_A, SZ_V } +#define O_C { OP_C, SZ_NA } +#define O_CL { OP_CL, SZ_B } +#define O_CS { OP_CS, SZ_NA } +#define O_CX { OP_CX, SZ_W } +#define O_D { OP_D, SZ_NA } +#define O_DL { OP_DL, SZ_B } +#define O_DS { OP_DS, SZ_NA } +#define O_DX { OP_DX, SZ_W } +#define O_E { OP_E, SZ_NA } +#define O_ES { OP_ES, SZ_NA } +#define O_Eb { OP_E, SZ_B } +#define O_Ed { OP_E, SZ_D } +#define O_Eq { OP_E, SZ_Q } +#define O_Ev { OP_E, SZ_V } +#define O_Ew { OP_E, SZ_W } +#define O_Ey { OP_E, SZ_Y } +#define O_Ez { OP_E, SZ_Z } +#define O_FS { OP_FS, SZ_NA } +#define O_Fv { OP_F, SZ_V } +#define O_G { OP_G, SZ_NA } +#define O_GS { OP_GS, SZ_NA } +#define O_Gb { OP_G, SZ_B } +#define O_Gd { OP_G, SZ_D } +#define O_Gq { OP_G, SZ_Q } +#define O_Gv { OP_G, SZ_V } +#define O_Gw { OP_G, SZ_W } +#define O_Gy { OP_G, SZ_Y } +#define O_Gz { OP_G, SZ_Z } +#define O_H { OP_H, SZ_X } +#define O_Hqq { OP_H, SZ_QQ } +#define O_Hx { OP_H, SZ_X } +#define O_I1 { OP_I1, SZ_NA } +#define O_I3 { OP_I3, SZ_NA } +#define O_Ib { OP_I, SZ_B } +#define O_Iv { OP_I, SZ_V } +#define O_Iw { OP_I, SZ_W } +#define O_Iz { OP_I, SZ_Z } +#define O_Jb { OP_J, SZ_B } +#define O_Jv { OP_J, SZ_V } +#define O_Jz { OP_J, SZ_Z } +#define O_L { OP_L, SZ_O } +#define O_Lx { OP_L, SZ_X } +#define O_M { OP_M, SZ_NA } +#define O_Mb { OP_M, SZ_B } +#define O_MbRd { OP_MR, SZ_BD } +#define O_MbRv { OP_MR, SZ_BV } +#define O_Md { OP_M, SZ_D } +#define O_MdRy { OP_MR, SZ_DY } +#define O_MdU { OP_MU, SZ_DO } +#define O_Mdq { OP_M, SZ_DQ } +#define O_Mo { OP_M, SZ_O } +#define O_Mq { OP_M, SZ_Q } +#define O_MqU { OP_MU, SZ_QO } +#define O_Ms { OP_M, SZ_W } +#define O_Mt { OP_M, SZ_T } +#define O_Mv { OP_M, SZ_V } +#define O_Mw { OP_M, SZ_W } +#define O_MwRd { OP_MR, SZ_WD } +#define O_MwRv { OP_MR, SZ_WV } +#define O_MwRy { OP_MR, SZ_WY } +#define O_MwU { OP_MU, SZ_WO } +#define O_N { OP_N, SZ_Q } +#define O_NONE { OP_NONE, SZ_NA } +#define O_Ob { OP_O, SZ_B } +#define O_Ov { OP_O, SZ_V } +#define O_Ow { OP_O, SZ_W } +#define O_P { OP_P, SZ_Q } +#define O_Q { OP_Q, SZ_Q } +#define O_R { OP_R, SZ_RDQ } +#define O_R0b { OP_R0, SZ_B } +#define O_R0v { OP_R0, SZ_V } +#define O_R0w { OP_R0, SZ_W } +#define O_R0y { OP_R0, SZ_Y } +#define O_R0z { OP_R0, SZ_Z } +#define O_R1b { OP_R1, SZ_B } +#define O_R1v { OP_R1, SZ_V } +#define O_R1w { OP_R1, SZ_W } +#define O_R1y { OP_R1, SZ_Y } +#define O_R1z { OP_R1, SZ_Z } +#define O_R2b { OP_R2, SZ_B } +#define O_R2v { OP_R2, SZ_V } +#define O_R2w { OP_R2, SZ_W } +#define O_R2y { OP_R2, SZ_Y } +#define O_R2z { OP_R2, SZ_Z } +#define O_R3b { OP_R3, SZ_B } +#define O_R3v { OP_R3, SZ_V } +#define O_R3w { OP_R3, SZ_W } +#define O_R3y { OP_R3, SZ_Y } +#define O_R3z { OP_R3, SZ_Z } +#define O_R4b { OP_R4, SZ_B } +#define O_R4v { OP_R4, SZ_V } +#define O_R4w { OP_R4, SZ_W } +#define O_R4y { OP_R4, SZ_Y } +#define O_R4z { OP_R4, SZ_Z } +#define O_R5b { OP_R5, SZ_B } +#define O_R5v { OP_R5, SZ_V } +#define O_R5w { OP_R5, SZ_W } +#define O_R5y { OP_R5, SZ_Y } +#define O_R5z { OP_R5, SZ_Z } +#define O_R6b { OP_R6, SZ_B } +#define O_R6v { OP_R6, SZ_V } +#define O_R6w { OP_R6, SZ_W } +#define O_R6y { OP_R6, SZ_Y } +#define O_R6z { OP_R6, SZ_Z } +#define O_R7b { OP_R7, SZ_B } +#define O_R7v { OP_R7, SZ_V } +#define O_R7w { OP_R7, SZ_W } +#define O_R7y { OP_R7, SZ_Y } +#define O_R7z { OP_R7, SZ_Z } +#define O_S { OP_S, SZ_W } +#define O_SS { OP_SS, SZ_NA } +#define O_ST0 { OP_ST0, SZ_NA } +#define O_ST1 { OP_ST1, SZ_NA } +#define O_ST2 { OP_ST2, SZ_NA } +#define O_ST3 { OP_ST3, SZ_NA } +#define O_ST4 { OP_ST4, SZ_NA } +#define O_ST5 { OP_ST5, SZ_NA } +#define O_ST6 { OP_ST6, SZ_NA } +#define O_ST7 { OP_ST7, SZ_NA } +#define O_U { OP_U, SZ_O } +#define O_Ux { OP_U, SZ_X } +#define O_V { OP_V, SZ_DQ } +#define O_Vdq { OP_V, SZ_DQ } +#define O_Vqq { OP_V, SZ_QQ } +#define O_Vsd { OP_V, SZ_Q } +#define O_Vx { OP_V, SZ_X } +#define O_W { OP_W, SZ_DQ } +#define O_Wdq { OP_W, SZ_DQ } +#define O_Wqq { OP_W, SZ_QQ } +#define O_Wsd { OP_W, SZ_Q } +#define O_Wx { OP_W, SZ_X } +#define O_eAX { OP_eAX, SZ_Z } +#define O_eCX { OP_eCX, SZ_Z } +#define O_eDX { OP_eDX, SZ_Z } +#define O_rAX { OP_rAX, SZ_V } +#define O_rCX { OP_rCX, SZ_V } +#define O_rDX { OP_rDX, SZ_V } +#define O_sIb { OP_sI, SZ_B } +#define O_sIv { OP_sI, SZ_V } +#define O_sIz { OP_sI, SZ_Z } + +struct ud_itab_entry ud_itab[] = { + /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0001 */ { UD_Iaaa, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0002 */ { UD_Iaad, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0003 */ { UD_Iaam, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0004 */ { UD_Iaas, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0005 */ { UD_Iadc, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0006 */ { UD_Iadc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0007 */ { UD_Iadc, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0008 */ { UD_Iadc, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0009 */ { UD_Iadc, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0010 */ { UD_Iadc, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0011 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0012 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0013 */ { UD_Iadc, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0014 */ { UD_Iadc, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0015 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0016 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0017 */ { UD_Iadd, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0018 */ { UD_Iadd, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0019 */ { UD_Iadd, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0020 */ { UD_Iadd, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0021 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0022 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0023 */ { UD_Iadd, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0024 */ { UD_Iadd, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0025 */ { UD_Iaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0026 */ { UD_Ivaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0027 */ { UD_Iaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0028 */ { UD_Ivaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0029 */ { UD_Iaddsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0030 */ { UD_Ivaddsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0031 */ { UD_Iaddss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0032 */ { UD_Ivaddss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0033 */ { UD_Iaddsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0034 */ { UD_Ivaddsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0035 */ { UD_Iaddsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0036 */ { UD_Ivaddsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0037 */ { UD_Iaesdec, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0038 */ { UD_Ivaesdec, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0039 */ { UD_Iaesdeclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0040 */ { UD_Ivaesdeclast, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0041 */ { UD_Iaesenc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0042 */ { UD_Ivaesenc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0043 */ { UD_Iaesenclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0044 */ { UD_Ivaesenclast, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0045 */ { UD_Iaesimc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0046 */ { UD_Ivaesimc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0047 */ { UD_Iaeskeygenassist, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0048 */ { UD_Ivaeskeygenassist, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0049 */ { UD_Iand, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0050 */ { UD_Iand, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0051 */ { UD_Iand, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0052 */ { UD_Iand, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0053 */ { UD_Iand, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0054 */ { UD_Iand, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0055 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0056 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0057 */ { UD_Iand, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0058 */ { UD_Iand, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0059 */ { UD_Iandpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0060 */ { UD_Ivandpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0061 */ { UD_Iandps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0062 */ { UD_Ivandps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0063 */ { UD_Iandnpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0064 */ { UD_Ivandnpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0065 */ { UD_Iandnps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0066 */ { UD_Ivandnps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0067 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, O_NONE, P_aso }, + /* 0068 */ { UD_Imovsxd, O_Gq, O_Ed, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 0069 */ { UD_Icall, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0070 */ { UD_Icall, O_Eq, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0071 */ { UD_Icall, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0072 */ { UD_Icall, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0073 */ { UD_Icall, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0074 */ { UD_Icbw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0075 */ { UD_Icwde, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0076 */ { UD_Icdqe, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0077 */ { UD_Iclc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0078 */ { UD_Icld, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0079 */ { UD_Iclflush, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0080 */ { UD_Iclgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0081 */ { UD_Icli, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0082 */ { UD_Iclts, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0083 */ { UD_Icmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0084 */ { UD_Icmovo, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0085 */ { UD_Icmovno, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0086 */ { UD_Icmovb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0087 */ { UD_Icmovae, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0088 */ { UD_Icmovz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0089 */ { UD_Icmovnz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0090 */ { UD_Icmovbe, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0091 */ { UD_Icmova, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0092 */ { UD_Icmovs, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0093 */ { UD_Icmovns, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0094 */ { UD_Icmovp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0095 */ { UD_Icmovnp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0096 */ { UD_Icmovl, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0097 */ { UD_Icmovge, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0098 */ { UD_Icmovle, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0099 */ { UD_Icmovg, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0100 */ { UD_Icmp, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0101 */ { UD_Icmp, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0102 */ { UD_Icmp, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0103 */ { UD_Icmp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0104 */ { UD_Icmp, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0105 */ { UD_Icmp, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0106 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0107 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0108 */ { UD_Icmp, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0109 */ { UD_Icmp, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0110 */ { UD_Icmppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0111 */ { UD_Ivcmppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0112 */ { UD_Icmpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0113 */ { UD_Ivcmpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0114 */ { UD_Icmpsb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_seg }, + /* 0115 */ { UD_Icmpsw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0116 */ { UD_Icmpsd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0117 */ { UD_Icmpsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0118 */ { UD_Ivcmpsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0119 */ { UD_Icmpsq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0120 */ { UD_Icmpss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0121 */ { UD_Ivcmpss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0122 */ { UD_Icmpxchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0123 */ { UD_Icmpxchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0124 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0125 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0126 */ { UD_Icmpxchg16b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0127 */ { UD_Icomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0128 */ { UD_Ivcomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0129 */ { UD_Icomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0130 */ { UD_Ivcomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0131 */ { UD_Icpuid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0132 */ { UD_Icvtdq2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0133 */ { UD_Ivcvtdq2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0134 */ { UD_Icvtdq2ps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0135 */ { UD_Ivcvtdq2ps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0136 */ { UD_Icvtpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0137 */ { UD_Ivcvtpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0138 */ { UD_Icvtpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0139 */ { UD_Icvtpd2ps, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0140 */ { UD_Ivcvtpd2ps, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0141 */ { UD_Icvtpi2ps, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0142 */ { UD_Icvtpi2pd, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0143 */ { UD_Icvtps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0144 */ { UD_Ivcvtps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0145 */ { UD_Icvtps2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0146 */ { UD_Ivcvtps2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0147 */ { UD_Icvtps2pi, O_P, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0148 */ { UD_Icvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0149 */ { UD_Ivcvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0150 */ { UD_Icvtsd2ss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0151 */ { UD_Ivcvtsd2ss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0152 */ { UD_Icvtsi2sd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0153 */ { UD_Ivcvtsi2sd, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0154 */ { UD_Icvtsi2ss, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0155 */ { UD_Ivcvtsi2ss, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0156 */ { UD_Icvtss2sd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0157 */ { UD_Ivcvtss2sd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0158 */ { UD_Icvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0159 */ { UD_Ivcvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0160 */ { UD_Icvttpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0161 */ { UD_Ivcvttpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0162 */ { UD_Icvttpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0163 */ { UD_Icvttps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0164 */ { UD_Ivcvttps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0165 */ { UD_Icvttps2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0166 */ { UD_Icvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0167 */ { UD_Ivcvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0168 */ { UD_Icvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0169 */ { UD_Ivcvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0170 */ { UD_Icwd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0171 */ { UD_Icdq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0172 */ { UD_Icqo, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0173 */ { UD_Idaa, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0174 */ { UD_Idas, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0175 */ { UD_Idec, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0176 */ { UD_Idec, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0177 */ { UD_Idec, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0178 */ { UD_Idec, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0179 */ { UD_Idec, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0180 */ { UD_Idec, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0181 */ { UD_Idec, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0182 */ { UD_Idec, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0183 */ { UD_Idec, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0184 */ { UD_Idec, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0185 */ { UD_Idiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0186 */ { UD_Idiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0187 */ { UD_Idivpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0188 */ { UD_Ivdivpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0189 */ { UD_Idivps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0190 */ { UD_Ivdivps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0191 */ { UD_Idivsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0192 */ { UD_Ivdivsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0193 */ { UD_Idivss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0194 */ { UD_Ivdivss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0195 */ { UD_Idppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0196 */ { UD_Ivdppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0197 */ { UD_Idpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0198 */ { UD_Ivdpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0199 */ { UD_Iemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0200 */ { UD_Ienter, O_Iw, O_Ib, O_NONE, O_NONE, P_def64 }, + /* 0201 */ { UD_Iextractps, O_MdRy, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0202 */ { UD_Ivextractps, O_MdRy, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0203 */ { UD_If2xm1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0204 */ { UD_Ifabs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0205 */ { UD_Ifadd, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0206 */ { UD_Ifadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0207 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0208 */ { UD_Ifadd, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0209 */ { UD_Ifadd, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0210 */ { UD_Ifadd, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0211 */ { UD_Ifadd, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0212 */ { UD_Ifadd, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0213 */ { UD_Ifadd, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0214 */ { UD_Ifadd, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0215 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0216 */ { UD_Ifadd, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0217 */ { UD_Ifadd, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0218 */ { UD_Ifadd, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0219 */ { UD_Ifadd, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0220 */ { UD_Ifadd, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0221 */ { UD_Ifadd, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0222 */ { UD_Ifadd, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0223 */ { UD_Ifaddp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0224 */ { UD_Ifaddp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0225 */ { UD_Ifaddp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0226 */ { UD_Ifaddp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0227 */ { UD_Ifaddp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0228 */ { UD_Ifaddp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0229 */ { UD_Ifaddp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0230 */ { UD_Ifaddp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0231 */ { UD_Ifbld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0232 */ { UD_Ifbstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0233 */ { UD_Ifchs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0234 */ { UD_Ifclex, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0235 */ { UD_Ifcmovb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0236 */ { UD_Ifcmovb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0237 */ { UD_Ifcmovb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0238 */ { UD_Ifcmovb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0239 */ { UD_Ifcmovb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0240 */ { UD_Ifcmovb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0241 */ { UD_Ifcmovb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0242 */ { UD_Ifcmovb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0243 */ { UD_Ifcmove, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0244 */ { UD_Ifcmove, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0245 */ { UD_Ifcmove, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0246 */ { UD_Ifcmove, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0247 */ { UD_Ifcmove, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0248 */ { UD_Ifcmove, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0249 */ { UD_Ifcmove, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0250 */ { UD_Ifcmove, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0251 */ { UD_Ifcmovbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0252 */ { UD_Ifcmovbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0253 */ { UD_Ifcmovbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0254 */ { UD_Ifcmovbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0255 */ { UD_Ifcmovbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0256 */ { UD_Ifcmovbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0257 */ { UD_Ifcmovbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0258 */ { UD_Ifcmovbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0259 */ { UD_Ifcmovu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0260 */ { UD_Ifcmovu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0261 */ { UD_Ifcmovu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0262 */ { UD_Ifcmovu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0263 */ { UD_Ifcmovu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0264 */ { UD_Ifcmovu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0265 */ { UD_Ifcmovu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0266 */ { UD_Ifcmovu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0267 */ { UD_Ifcmovnb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0268 */ { UD_Ifcmovnb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0269 */ { UD_Ifcmovnb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0270 */ { UD_Ifcmovnb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0271 */ { UD_Ifcmovnb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0272 */ { UD_Ifcmovnb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0273 */ { UD_Ifcmovnb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0274 */ { UD_Ifcmovnb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0275 */ { UD_Ifcmovne, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0276 */ { UD_Ifcmovne, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0277 */ { UD_Ifcmovne, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0278 */ { UD_Ifcmovne, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0279 */ { UD_Ifcmovne, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0280 */ { UD_Ifcmovne, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0281 */ { UD_Ifcmovne, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0282 */ { UD_Ifcmovne, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0283 */ { UD_Ifcmovnbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0284 */ { UD_Ifcmovnbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0285 */ { UD_Ifcmovnbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0286 */ { UD_Ifcmovnbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0287 */ { UD_Ifcmovnbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0288 */ { UD_Ifcmovnbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0289 */ { UD_Ifcmovnbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0290 */ { UD_Ifcmovnbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0291 */ { UD_Ifcmovnu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0292 */ { UD_Ifcmovnu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0293 */ { UD_Ifcmovnu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0294 */ { UD_Ifcmovnu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0295 */ { UD_Ifcmovnu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0296 */ { UD_Ifcmovnu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0297 */ { UD_Ifcmovnu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0298 */ { UD_Ifcmovnu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0299 */ { UD_Ifucomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0300 */ { UD_Ifucomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0301 */ { UD_Ifucomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0302 */ { UD_Ifucomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0303 */ { UD_Ifucomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0304 */ { UD_Ifucomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0305 */ { UD_Ifucomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0306 */ { UD_Ifucomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0307 */ { UD_Ifcom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0308 */ { UD_Ifcom, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0309 */ { UD_Ifcom, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0310 */ { UD_Ifcom, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0311 */ { UD_Ifcom, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0312 */ { UD_Ifcom, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0313 */ { UD_Ifcom, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0314 */ { UD_Ifcom, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0315 */ { UD_Ifcom, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0316 */ { UD_Ifcom, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0317 */ { UD_Ifcom2, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0318 */ { UD_Ifcom2, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0319 */ { UD_Ifcom2, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0320 */ { UD_Ifcom2, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0321 */ { UD_Ifcom2, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0322 */ { UD_Ifcom2, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0323 */ { UD_Ifcom2, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0324 */ { UD_Ifcom2, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0325 */ { UD_Ifcomp3, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0326 */ { UD_Ifcomp3, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0327 */ { UD_Ifcomp3, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0328 */ { UD_Ifcomp3, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0329 */ { UD_Ifcomp3, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0330 */ { UD_Ifcomp3, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0331 */ { UD_Ifcomp3, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0332 */ { UD_Ifcomp3, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0333 */ { UD_Ifcomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0334 */ { UD_Ifcomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0335 */ { UD_Ifcomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0336 */ { UD_Ifcomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0337 */ { UD_Ifcomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0338 */ { UD_Ifcomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0339 */ { UD_Ifcomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0340 */ { UD_Ifcomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0341 */ { UD_Ifucomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0342 */ { UD_Ifucomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0343 */ { UD_Ifucomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0344 */ { UD_Ifucomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0345 */ { UD_Ifucomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0346 */ { UD_Ifucomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0347 */ { UD_Ifucomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0348 */ { UD_Ifucomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0349 */ { UD_Ifcomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0350 */ { UD_Ifcomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0351 */ { UD_Ifcomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0352 */ { UD_Ifcomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0353 */ { UD_Ifcomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0354 */ { UD_Ifcomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0355 */ { UD_Ifcomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0356 */ { UD_Ifcomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0357 */ { UD_Ifcomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0358 */ { UD_Ifcomp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0359 */ { UD_Ifcomp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0360 */ { UD_Ifcomp, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0361 */ { UD_Ifcomp, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0362 */ { UD_Ifcomp, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0363 */ { UD_Ifcomp, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0364 */ { UD_Ifcomp, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0365 */ { UD_Ifcomp, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0366 */ { UD_Ifcomp, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0367 */ { UD_Ifcomp5, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0368 */ { UD_Ifcomp5, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0369 */ { UD_Ifcomp5, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0370 */ { UD_Ifcomp5, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0371 */ { UD_Ifcomp5, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0372 */ { UD_Ifcomp5, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0373 */ { UD_Ifcomp5, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0374 */ { UD_Ifcomp5, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0375 */ { UD_Ifcompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0376 */ { UD_Ifcos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0377 */ { UD_Ifdecstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0378 */ { UD_Ifdiv, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0379 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0380 */ { UD_Ifdiv, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0381 */ { UD_Ifdiv, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0382 */ { UD_Ifdiv, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0383 */ { UD_Ifdiv, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0384 */ { UD_Ifdiv, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0385 */ { UD_Ifdiv, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0386 */ { UD_Ifdiv, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0387 */ { UD_Ifdiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0388 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0389 */ { UD_Ifdiv, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0390 */ { UD_Ifdiv, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0391 */ { UD_Ifdiv, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0392 */ { UD_Ifdiv, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0393 */ { UD_Ifdiv, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0394 */ { UD_Ifdiv, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0395 */ { UD_Ifdiv, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0396 */ { UD_Ifdivp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0397 */ { UD_Ifdivp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0398 */ { UD_Ifdivp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0399 */ { UD_Ifdivp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0400 */ { UD_Ifdivp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0401 */ { UD_Ifdivp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0402 */ { UD_Ifdivp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0403 */ { UD_Ifdivp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0404 */ { UD_Ifdivr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0405 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0406 */ { UD_Ifdivr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0407 */ { UD_Ifdivr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0408 */ { UD_Ifdivr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0409 */ { UD_Ifdivr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0410 */ { UD_Ifdivr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0411 */ { UD_Ifdivr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0412 */ { UD_Ifdivr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0413 */ { UD_Ifdivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0414 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0415 */ { UD_Ifdivr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0416 */ { UD_Ifdivr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0417 */ { UD_Ifdivr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0418 */ { UD_Ifdivr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0419 */ { UD_Ifdivr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0420 */ { UD_Ifdivr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0421 */ { UD_Ifdivr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0422 */ { UD_Ifdivrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0423 */ { UD_Ifdivrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0424 */ { UD_Ifdivrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0425 */ { UD_Ifdivrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0426 */ { UD_Ifdivrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0427 */ { UD_Ifdivrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0428 */ { UD_Ifdivrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0429 */ { UD_Ifdivrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0430 */ { UD_Ifemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0431 */ { UD_Iffree, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0432 */ { UD_Iffree, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0433 */ { UD_Iffree, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0434 */ { UD_Iffree, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0435 */ { UD_Iffree, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0436 */ { UD_Iffree, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0437 */ { UD_Iffree, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0438 */ { UD_Iffree, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0439 */ { UD_Iffreep, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0440 */ { UD_Iffreep, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0441 */ { UD_Iffreep, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0442 */ { UD_Iffreep, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0443 */ { UD_Iffreep, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0444 */ { UD_Iffreep, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0445 */ { UD_Iffreep, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0446 */ { UD_Iffreep, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0447 */ { UD_Ificom, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0448 */ { UD_Ificom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0449 */ { UD_Ificomp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0450 */ { UD_Ificomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0451 */ { UD_Ifild, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0452 */ { UD_Ifild, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0453 */ { UD_Ifild, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0454 */ { UD_Ifincstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0455 */ { UD_Ifninit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0456 */ { UD_Ifiadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0457 */ { UD_Ifiadd, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0458 */ { UD_Ifidivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0459 */ { UD_Ifidivr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0460 */ { UD_Ifidiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0461 */ { UD_Ifidiv, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0462 */ { UD_Ifisub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0463 */ { UD_Ifisub, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0464 */ { UD_Ifisubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0465 */ { UD_Ifisubr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0466 */ { UD_Ifist, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0467 */ { UD_Ifist, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0468 */ { UD_Ifistp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0469 */ { UD_Ifistp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0470 */ { UD_Ifistp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0471 */ { UD_Ifisttp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0472 */ { UD_Ifisttp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0473 */ { UD_Ifisttp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0474 */ { UD_Ifld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0475 */ { UD_Ifld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0476 */ { UD_Ifld, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0477 */ { UD_Ifld, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0478 */ { UD_Ifld, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0479 */ { UD_Ifld, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0480 */ { UD_Ifld, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0481 */ { UD_Ifld, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0482 */ { UD_Ifld, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0483 */ { UD_Ifld, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0484 */ { UD_Ifld, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0485 */ { UD_Ifld1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0486 */ { UD_Ifldl2t, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0487 */ { UD_Ifldl2e, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0488 */ { UD_Ifldpi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0489 */ { UD_Ifldlg2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0490 */ { UD_Ifldln2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0491 */ { UD_Ifldz, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0492 */ { UD_Ifldcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0493 */ { UD_Ifldenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0494 */ { UD_Ifmul, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0495 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0496 */ { UD_Ifmul, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0497 */ { UD_Ifmul, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0498 */ { UD_Ifmul, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0499 */ { UD_Ifmul, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0500 */ { UD_Ifmul, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0501 */ { UD_Ifmul, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0502 */ { UD_Ifmul, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0503 */ { UD_Ifmul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0504 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0505 */ { UD_Ifmul, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0506 */ { UD_Ifmul, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0507 */ { UD_Ifmul, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0508 */ { UD_Ifmul, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0509 */ { UD_Ifmul, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0510 */ { UD_Ifmul, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0511 */ { UD_Ifmul, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0512 */ { UD_Ifmulp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0513 */ { UD_Ifmulp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0514 */ { UD_Ifmulp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0515 */ { UD_Ifmulp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0516 */ { UD_Ifmulp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0517 */ { UD_Ifmulp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0518 */ { UD_Ifmulp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0519 */ { UD_Ifmulp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0520 */ { UD_Ifimul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0521 */ { UD_Ifimul, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0522 */ { UD_Ifnop, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0523 */ { UD_Ifpatan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0524 */ { UD_Ifprem, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0525 */ { UD_Ifprem1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0526 */ { UD_Ifptan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0527 */ { UD_Ifrndint, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0528 */ { UD_Ifrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0529 */ { UD_Ifnsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0530 */ { UD_Ifscale, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0531 */ { UD_Ifsin, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0532 */ { UD_Ifsincos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0533 */ { UD_Ifsqrt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0534 */ { UD_Ifstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0535 */ { UD_Ifstp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0536 */ { UD_Ifstp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0537 */ { UD_Ifstp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0538 */ { UD_Ifstp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0539 */ { UD_Ifstp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0540 */ { UD_Ifstp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0541 */ { UD_Ifstp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0542 */ { UD_Ifstp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0543 */ { UD_Ifstp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0544 */ { UD_Ifstp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0545 */ { UD_Ifstp1, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0546 */ { UD_Ifstp1, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0547 */ { UD_Ifstp1, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0548 */ { UD_Ifstp1, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0549 */ { UD_Ifstp1, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0550 */ { UD_Ifstp1, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0551 */ { UD_Ifstp1, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0552 */ { UD_Ifstp1, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0553 */ { UD_Ifstp8, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0554 */ { UD_Ifstp8, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0555 */ { UD_Ifstp8, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0556 */ { UD_Ifstp8, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0557 */ { UD_Ifstp8, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0558 */ { UD_Ifstp8, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0559 */ { UD_Ifstp8, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0560 */ { UD_Ifstp8, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0561 */ { UD_Ifstp9, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0562 */ { UD_Ifstp9, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0563 */ { UD_Ifstp9, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0564 */ { UD_Ifstp9, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0565 */ { UD_Ifstp9, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0566 */ { UD_Ifstp9, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0567 */ { UD_Ifstp9, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0568 */ { UD_Ifstp9, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0569 */ { UD_Ifst, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0570 */ { UD_Ifst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0571 */ { UD_Ifst, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0572 */ { UD_Ifst, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0573 */ { UD_Ifst, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0574 */ { UD_Ifst, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0575 */ { UD_Ifst, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0576 */ { UD_Ifst, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0577 */ { UD_Ifst, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0578 */ { UD_Ifst, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0579 */ { UD_Ifnstcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0580 */ { UD_Ifnstenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0581 */ { UD_Ifnstsw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0582 */ { UD_Ifnstsw, O_AX, O_NONE, O_NONE, O_NONE, P_none }, + /* 0583 */ { UD_Ifsub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0584 */ { UD_Ifsub, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0585 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0586 */ { UD_Ifsub, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0587 */ { UD_Ifsub, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0588 */ { UD_Ifsub, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0589 */ { UD_Ifsub, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0590 */ { UD_Ifsub, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0591 */ { UD_Ifsub, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0592 */ { UD_Ifsub, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0593 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0594 */ { UD_Ifsub, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0595 */ { UD_Ifsub, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0596 */ { UD_Ifsub, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0597 */ { UD_Ifsub, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0598 */ { UD_Ifsub, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0599 */ { UD_Ifsub, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0600 */ { UD_Ifsub, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0601 */ { UD_Ifsubp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0602 */ { UD_Ifsubp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0603 */ { UD_Ifsubp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0604 */ { UD_Ifsubp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0605 */ { UD_Ifsubp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0606 */ { UD_Ifsubp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0607 */ { UD_Ifsubp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0608 */ { UD_Ifsubp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0609 */ { UD_Ifsubr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0610 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0611 */ { UD_Ifsubr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0612 */ { UD_Ifsubr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0613 */ { UD_Ifsubr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0614 */ { UD_Ifsubr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0615 */ { UD_Ifsubr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0616 */ { UD_Ifsubr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0617 */ { UD_Ifsubr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0618 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0619 */ { UD_Ifsubr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0620 */ { UD_Ifsubr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0621 */ { UD_Ifsubr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0622 */ { UD_Ifsubr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0623 */ { UD_Ifsubr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0624 */ { UD_Ifsubr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0625 */ { UD_Ifsubr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0626 */ { UD_Ifsubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0627 */ { UD_Ifsubrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0628 */ { UD_Ifsubrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0629 */ { UD_Ifsubrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0630 */ { UD_Ifsubrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0631 */ { UD_Ifsubrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0632 */ { UD_Ifsubrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0633 */ { UD_Ifsubrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0634 */ { UD_Ifsubrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0635 */ { UD_Iftst, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0636 */ { UD_Ifucom, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0637 */ { UD_Ifucom, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0638 */ { UD_Ifucom, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0639 */ { UD_Ifucom, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0640 */ { UD_Ifucom, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0641 */ { UD_Ifucom, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0642 */ { UD_Ifucom, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0643 */ { UD_Ifucom, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0644 */ { UD_Ifucomp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0645 */ { UD_Ifucomp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0646 */ { UD_Ifucomp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0647 */ { UD_Ifucomp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0648 */ { UD_Ifucomp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0649 */ { UD_Ifucomp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0650 */ { UD_Ifucomp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0651 */ { UD_Ifucomp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0652 */ { UD_Ifucompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0653 */ { UD_Ifxam, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0654 */ { UD_Ifxch, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0655 */ { UD_Ifxch, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0656 */ { UD_Ifxch, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0657 */ { UD_Ifxch, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0658 */ { UD_Ifxch, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0659 */ { UD_Ifxch, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0660 */ { UD_Ifxch, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0661 */ { UD_Ifxch, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0662 */ { UD_Ifxch4, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0663 */ { UD_Ifxch4, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0664 */ { UD_Ifxch4, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0665 */ { UD_Ifxch4, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0666 */ { UD_Ifxch4, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0667 */ { UD_Ifxch4, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0668 */ { UD_Ifxch4, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0669 */ { UD_Ifxch4, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0670 */ { UD_Ifxch7, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0671 */ { UD_Ifxch7, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0672 */ { UD_Ifxch7, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0673 */ { UD_Ifxch7, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0674 */ { UD_Ifxch7, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0675 */ { UD_Ifxch7, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0676 */ { UD_Ifxch7, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0677 */ { UD_Ifxch7, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0678 */ { UD_Ifxrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0679 */ { UD_Ifxsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0680 */ { UD_Ifxtract, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0681 */ { UD_Ifyl2x, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0682 */ { UD_Ifyl2xp1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0683 */ { UD_Ihlt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0684 */ { UD_Iidiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0685 */ { UD_Iidiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0686 */ { UD_Iin, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0687 */ { UD_Iin, O_eAX, O_Ib, O_NONE, O_NONE, P_oso }, + /* 0688 */ { UD_Iin, O_AL, O_DX, O_NONE, O_NONE, P_none }, + /* 0689 */ { UD_Iin, O_eAX, O_DX, O_NONE, O_NONE, P_oso }, + /* 0690 */ { UD_Iimul, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0691 */ { UD_Iimul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0692 */ { UD_Iimul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0693 */ { UD_Iimul, O_Gv, O_Ev, O_Iz, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0694 */ { UD_Iimul, O_Gv, O_Ev, O_sIb, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0695 */ { UD_Iinc, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0696 */ { UD_Iinc, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0697 */ { UD_Iinc, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0698 */ { UD_Iinc, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0699 */ { UD_Iinc, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0700 */ { UD_Iinc, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0701 */ { UD_Iinc, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0702 */ { UD_Iinc, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0703 */ { UD_Iinc, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0704 */ { UD_Iinc, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0705 */ { UD_Iinsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0706 */ { UD_Iinsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0707 */ { UD_Iinsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0708 */ { UD_Iint1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0709 */ { UD_Iint3, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0710 */ { UD_Iint, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0711 */ { UD_Iinto, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0712 */ { UD_Iinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0713 */ { UD_Iinvept, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0714 */ { UD_Iinvept, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0715 */ { UD_Iinvlpg, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0716 */ { UD_Iinvlpga, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0717 */ { UD_Iinvvpid, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0718 */ { UD_Iinvvpid, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0719 */ { UD_Iiretw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0720 */ { UD_Iiretd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0721 */ { UD_Iiretq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0722 */ { UD_Ijo, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0723 */ { UD_Ijo, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0724 */ { UD_Ijno, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0725 */ { UD_Ijno, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0726 */ { UD_Ijb, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0727 */ { UD_Ijb, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0728 */ { UD_Ijae, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0729 */ { UD_Ijae, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0730 */ { UD_Ijz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0731 */ { UD_Ijz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0732 */ { UD_Ijnz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0733 */ { UD_Ijnz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0734 */ { UD_Ijbe, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0735 */ { UD_Ijbe, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0736 */ { UD_Ija, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0737 */ { UD_Ija, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0738 */ { UD_Ijs, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0739 */ { UD_Ijs, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0740 */ { UD_Ijns, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0741 */ { UD_Ijns, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0742 */ { UD_Ijp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0743 */ { UD_Ijp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0744 */ { UD_Ijnp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0745 */ { UD_Ijnp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0746 */ { UD_Ijl, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0747 */ { UD_Ijl, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0748 */ { UD_Ijge, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0749 */ { UD_Ijge, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0750 */ { UD_Ijle, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0751 */ { UD_Ijle, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0752 */ { UD_Ijg, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0753 */ { UD_Ijg, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0754 */ { UD_Ijcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0755 */ { UD_Ijecxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0756 */ { UD_Ijrcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0757 */ { UD_Ijmp, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0758 */ { UD_Ijmp, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0759 */ { UD_Ijmp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0760 */ { UD_Ijmp, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0761 */ { UD_Ijmp, O_Jb, O_NONE, O_NONE, O_NONE, P_def64 }, + /* 0762 */ { UD_Ilahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0763 */ { UD_Ilar, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0764 */ { UD_Ildmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0765 */ { UD_Ilds, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0766 */ { UD_Ilea, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0767 */ { UD_Iles, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0768 */ { UD_Ilfs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0769 */ { UD_Ilgs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0770 */ { UD_Ilidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0771 */ { UD_Ilss, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0772 */ { UD_Ileave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0773 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0774 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0775 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0776 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0777 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0778 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0779 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0780 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0781 */ { UD_Ilgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0782 */ { UD_Illdt, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0783 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0784 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0785 */ { UD_Ilock, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0786 */ { UD_Ilodsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0787 */ { UD_Ilodsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0788 */ { UD_Ilodsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0789 */ { UD_Ilodsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0790 */ { UD_Iloopne, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0791 */ { UD_Iloope, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0792 */ { UD_Iloop, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0793 */ { UD_Ilsl, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0794 */ { UD_Iltr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0795 */ { UD_Imaskmovq, O_P, O_N, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0796 */ { UD_Imaxpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0797 */ { UD_Ivmaxpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0798 */ { UD_Imaxps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0799 */ { UD_Ivmaxps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0800 */ { UD_Imaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0801 */ { UD_Ivmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0802 */ { UD_Imaxss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0803 */ { UD_Ivmaxss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0804 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0805 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0806 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0807 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0808 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0809 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0810 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0811 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0812 */ { UD_Iminpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0813 */ { UD_Ivminpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0814 */ { UD_Iminps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0815 */ { UD_Ivminps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0816 */ { UD_Iminsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0817 */ { UD_Ivminsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0818 */ { UD_Iminss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0819 */ { UD_Ivminss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0820 */ { UD_Imonitor, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0821 */ { UD_Imontmul, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0822 */ { UD_Imov, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0823 */ { UD_Imov, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0824 */ { UD_Imov, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0825 */ { UD_Imov, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0826 */ { UD_Imov, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0827 */ { UD_Imov, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0828 */ { UD_Imov, O_MwRv, O_S, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0829 */ { UD_Imov, O_S, O_MwRv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0830 */ { UD_Imov, O_AL, O_Ob, O_NONE, O_NONE, P_none }, + /* 0831 */ { UD_Imov, O_rAX, O_Ov, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0832 */ { UD_Imov, O_Ob, O_AL, O_NONE, O_NONE, P_none }, + /* 0833 */ { UD_Imov, O_Ov, O_rAX, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0834 */ { UD_Imov, O_R0b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0835 */ { UD_Imov, O_R1b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0836 */ { UD_Imov, O_R2b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0837 */ { UD_Imov, O_R3b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0838 */ { UD_Imov, O_R4b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0839 */ { UD_Imov, O_R5b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0840 */ { UD_Imov, O_R6b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0841 */ { UD_Imov, O_R7b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0842 */ { UD_Imov, O_R0v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0843 */ { UD_Imov, O_R1v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0844 */ { UD_Imov, O_R2v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0845 */ { UD_Imov, O_R3v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0846 */ { UD_Imov, O_R4v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0847 */ { UD_Imov, O_R5v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0848 */ { UD_Imov, O_R6v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0849 */ { UD_Imov, O_R7v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0850 */ { UD_Imov, O_R, O_C, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0851 */ { UD_Imov, O_R, O_D, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0852 */ { UD_Imov, O_C, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0853 */ { UD_Imov, O_D, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0854 */ { UD_Imovapd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0855 */ { UD_Ivmovapd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0856 */ { UD_Imovapd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0857 */ { UD_Ivmovapd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0858 */ { UD_Imovaps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0859 */ { UD_Ivmovaps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0860 */ { UD_Imovaps, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0861 */ { UD_Ivmovaps, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0862 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0863 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0864 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0865 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0866 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0867 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0868 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0869 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0870 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0871 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0872 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0873 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0874 */ { UD_Imovhpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0875 */ { UD_Ivmovhpd, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0876 */ { UD_Imovhpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0877 */ { UD_Ivmovhpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0878 */ { UD_Imovhps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0879 */ { UD_Ivmovhps, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0880 */ { UD_Imovhps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0881 */ { UD_Ivmovhps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0882 */ { UD_Imovlhps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0883 */ { UD_Ivmovlhps, O_Vx, O_Hx, O_Ux, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0884 */ { UD_Imovlpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0885 */ { UD_Ivmovlpd, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0886 */ { UD_Imovlpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0887 */ { UD_Ivmovlpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0888 */ { UD_Imovlps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0889 */ { UD_Ivmovlps, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0890 */ { UD_Imovlps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0891 */ { UD_Ivmovlps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0892 */ { UD_Imovhlps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0893 */ { UD_Ivmovhlps, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0894 */ { UD_Imovmskpd, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0895 */ { UD_Ivmovmskpd, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb|P_vexl }, + /* 0896 */ { UD_Imovmskps, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0897 */ { UD_Ivmovmskps, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0898 */ { UD_Imovntdq, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0899 */ { UD_Ivmovntdq, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0900 */ { UD_Imovnti, O_M, O_Gy, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0901 */ { UD_Imovntpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0902 */ { UD_Ivmovntpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0903 */ { UD_Imovntps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0904 */ { UD_Ivmovntps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0905 */ { UD_Imovntq, O_M, O_P, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0906 */ { UD_Imovq, O_P, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0907 */ { UD_Imovq, O_V, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0908 */ { UD_Ivmovq, O_Vx, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0909 */ { UD_Imovq, O_Eq, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0910 */ { UD_Imovq, O_Eq, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0911 */ { UD_Ivmovq, O_Eq, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0912 */ { UD_Imovq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0913 */ { UD_Ivmovq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0914 */ { UD_Imovq, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0915 */ { UD_Ivmovq, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0916 */ { UD_Imovq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0917 */ { UD_Imovq, O_Q, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0918 */ { UD_Imovsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0919 */ { UD_Imovsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0920 */ { UD_Imovsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0921 */ { UD_Imovsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0922 */ { UD_Imovsd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0923 */ { UD_Imovsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0924 */ { UD_Imovss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0925 */ { UD_Imovss, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0926 */ { UD_Imovsx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0927 */ { UD_Imovsx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0928 */ { UD_Imovupd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0929 */ { UD_Ivmovupd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0930 */ { UD_Imovupd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0931 */ { UD_Ivmovupd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0932 */ { UD_Imovups, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0933 */ { UD_Ivmovups, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0934 */ { UD_Imovups, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0935 */ { UD_Ivmovups, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0936 */ { UD_Imovzx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0937 */ { UD_Imovzx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0938 */ { UD_Imul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0939 */ { UD_Imul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0940 */ { UD_Imulpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0941 */ { UD_Ivmulpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0942 */ { UD_Imulps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0943 */ { UD_Ivmulps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0944 */ { UD_Imulsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0945 */ { UD_Ivmulsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0946 */ { UD_Imulss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0947 */ { UD_Ivmulss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0948 */ { UD_Imwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0949 */ { UD_Ineg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0950 */ { UD_Ineg, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0951 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0952 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0953 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0954 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0955 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0956 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0957 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0958 */ { UD_Inot, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0959 */ { UD_Inot, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0960 */ { UD_Ior, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0961 */ { UD_Ior, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0962 */ { UD_Ior, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0963 */ { UD_Ior, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0964 */ { UD_Ior, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0965 */ { UD_Ior, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0966 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0967 */ { UD_Ior, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0968 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0969 */ { UD_Ior, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0970 */ { UD_Iorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0971 */ { UD_Ivorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0972 */ { UD_Iorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0973 */ { UD_Ivorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0974 */ { UD_Iout, O_Ib, O_AL, O_NONE, O_NONE, P_none }, + /* 0975 */ { UD_Iout, O_Ib, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0976 */ { UD_Iout, O_DX, O_AL, O_NONE, O_NONE, P_none }, + /* 0977 */ { UD_Iout, O_DX, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0978 */ { UD_Ioutsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0979 */ { UD_Ioutsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0980 */ { UD_Ioutsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0981 */ { UD_Ipacksswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0982 */ { UD_Ivpacksswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0983 */ { UD_Ipacksswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0984 */ { UD_Ipackssdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0985 */ { UD_Ivpackssdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0986 */ { UD_Ipackssdw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0987 */ { UD_Ipackuswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0988 */ { UD_Ivpackuswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0989 */ { UD_Ipackuswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0990 */ { UD_Ipaddb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0991 */ { UD_Ivpaddb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0992 */ { UD_Ipaddb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0993 */ { UD_Ipaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0994 */ { UD_Ipaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0995 */ { UD_Ivpaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0996 */ { UD_Ipaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0997 */ { UD_Ipaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0998 */ { UD_Ivpaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0999 */ { UD_Ipaddsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1000 */ { UD_Ipaddsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1001 */ { UD_Ivpaddsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1002 */ { UD_Ipaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1003 */ { UD_Ipaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1004 */ { UD_Ivpaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1005 */ { UD_Ipaddusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1006 */ { UD_Ipaddusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1007 */ { UD_Ivpaddusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1008 */ { UD_Ipaddusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1009 */ { UD_Ipaddusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1010 */ { UD_Ivpaddusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1011 */ { UD_Ipand, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1012 */ { UD_Ivpand, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1013 */ { UD_Ipand, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1014 */ { UD_Ipandn, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1015 */ { UD_Ivpandn, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1016 */ { UD_Ipandn, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1017 */ { UD_Ipavgb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1018 */ { UD_Ivpavgb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1019 */ { UD_Ipavgb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1020 */ { UD_Ipavgw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1021 */ { UD_Ivpavgw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1022 */ { UD_Ipavgw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1023 */ { UD_Ipcmpeqb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1024 */ { UD_Ipcmpeqb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1025 */ { UD_Ivpcmpeqb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1026 */ { UD_Ipcmpeqw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1027 */ { UD_Ipcmpeqw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1028 */ { UD_Ivpcmpeqw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1029 */ { UD_Ipcmpeqd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1030 */ { UD_Ipcmpeqd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1031 */ { UD_Ivpcmpeqd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1032 */ { UD_Ipcmpgtb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1033 */ { UD_Ivpcmpgtb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1034 */ { UD_Ipcmpgtb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1035 */ { UD_Ipcmpgtw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1036 */ { UD_Ivpcmpgtw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1037 */ { UD_Ipcmpgtw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1038 */ { UD_Ipcmpgtd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1039 */ { UD_Ivpcmpgtd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1040 */ { UD_Ipcmpgtd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1041 */ { UD_Ipextrb, O_MbRv, O_V, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1042 */ { UD_Ivpextrb, O_MbRv, O_Vx, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1043 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1044 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1045 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1046 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1047 */ { UD_Ipextrq, O_Eq, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1048 */ { UD_Ivpextrq, O_Eq, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1049 */ { UD_Ipextrw, O_Gd, O_U, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1050 */ { UD_Ivpextrw, O_Gd, O_Ux, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1051 */ { UD_Ipextrw, O_Gd, O_N, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1052 */ { UD_Ipextrw, O_MwRd, O_V, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1053 */ { UD_Ivpextrw, O_MwRd, O_Vx, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1054 */ { UD_Ipinsrb, O_V, O_MbRd, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1055 */ { UD_Ipinsrw, O_P, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1056 */ { UD_Ipinsrw, O_V, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1057 */ { UD_Ivpinsrw, O_Vx, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1058 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1059 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1060 */ { UD_Ipinsrq, O_V, O_Eq, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1061 */ { UD_Ivpinsrb, O_V, O_H, O_MbRd, O_Ib, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1062 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1063 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1064 */ { UD_Ivpinsrq, O_V, O_H, O_Eq, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1065 */ { UD_Ipmaddwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1066 */ { UD_Ipmaddwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1067 */ { UD_Ivpmaddwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1068 */ { UD_Ipmaxsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1069 */ { UD_Ivpmaxsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1070 */ { UD_Ipmaxsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1071 */ { UD_Ipmaxub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1072 */ { UD_Ipmaxub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1073 */ { UD_Ivpmaxub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1074 */ { UD_Ipminsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1075 */ { UD_Ivpminsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1076 */ { UD_Ipminsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1077 */ { UD_Ipminub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1078 */ { UD_Ivpminub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1079 */ { UD_Ipminub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1080 */ { UD_Ipmovmskb, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1081 */ { UD_Ivpmovmskb, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1082 */ { UD_Ipmovmskb, O_Gd, O_N, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1083 */ { UD_Ipmulhuw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1084 */ { UD_Ipmulhuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1085 */ { UD_Ivpmulhuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1086 */ { UD_Ipmulhw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1087 */ { UD_Ivpmulhw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1088 */ { UD_Ipmulhw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1089 */ { UD_Ipmullw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1090 */ { UD_Ipmullw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1091 */ { UD_Ivpmullw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1092 */ { UD_Ipop, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1093 */ { UD_Ipop, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1094 */ { UD_Ipop, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1095 */ { UD_Ipop, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1096 */ { UD_Ipop, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1097 */ { UD_Ipop, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1098 */ { UD_Ipop, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1099 */ { UD_Ipop, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1100 */ { UD_Ipop, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1101 */ { UD_Ipop, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1102 */ { UD_Ipop, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1103 */ { UD_Ipop, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1104 */ { UD_Ipop, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1105 */ { UD_Ipop, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1106 */ { UD_Ipopa, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1107 */ { UD_Ipopad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1108 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1109 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1110 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1111 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1112 */ { UD_Ipor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1113 */ { UD_Ivpor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1114 */ { UD_Ipor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1115 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1116 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1117 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1118 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1119 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1120 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1121 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1122 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1123 */ { UD_Iprefetchnta, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1124 */ { UD_Iprefetcht0, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1125 */ { UD_Iprefetcht1, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1126 */ { UD_Iprefetcht2, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1127 */ { UD_Ipsadbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1128 */ { UD_Ivpsadbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1129 */ { UD_Ipsadbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1130 */ { UD_Ipshufw, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1131 */ { UD_Ipsllw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1132 */ { UD_Ipsllw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1133 */ { UD_Ipsllw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1134 */ { UD_Ipsllw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1135 */ { UD_Ipslld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1136 */ { UD_Ipslld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1137 */ { UD_Ipslld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1138 */ { UD_Ipslld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1139 */ { UD_Ipsllq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1140 */ { UD_Ipsllq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1141 */ { UD_Ipsllq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1142 */ { UD_Ipsllq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1143 */ { UD_Ipsraw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1144 */ { UD_Ipsraw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1145 */ { UD_Ivpsraw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1146 */ { UD_Ipsraw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1147 */ { UD_Ivpsraw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1148 */ { UD_Ipsraw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1149 */ { UD_Ipsrad, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1150 */ { UD_Ipsrad, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1151 */ { UD_Ivpsrad, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1152 */ { UD_Ipsrad, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1153 */ { UD_Ipsrad, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1154 */ { UD_Ivpsrad, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1155 */ { UD_Ipsrlw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1156 */ { UD_Ipsrlw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1157 */ { UD_Ipsrlw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1158 */ { UD_Ivpsrlw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1159 */ { UD_Ipsrlw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1160 */ { UD_Ivpsrlw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1161 */ { UD_Ipsrld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1162 */ { UD_Ipsrld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1163 */ { UD_Ipsrld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1164 */ { UD_Ivpsrld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1165 */ { UD_Ipsrld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1166 */ { UD_Ivpsrld, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1167 */ { UD_Ipsrlq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1168 */ { UD_Ipsrlq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1169 */ { UD_Ipsrlq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1170 */ { UD_Ivpsrlq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1171 */ { UD_Ipsrlq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1172 */ { UD_Ivpsrlq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1173 */ { UD_Ipsubb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1174 */ { UD_Ivpsubb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1175 */ { UD_Ipsubb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1176 */ { UD_Ipsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1177 */ { UD_Ivpsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1178 */ { UD_Ipsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1179 */ { UD_Ipsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1180 */ { UD_Ipsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1181 */ { UD_Ivpsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1182 */ { UD_Ipsubsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1183 */ { UD_Ipsubsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1184 */ { UD_Ivpsubsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1185 */ { UD_Ipsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1186 */ { UD_Ipsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1187 */ { UD_Ivpsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1188 */ { UD_Ipsubusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1189 */ { UD_Ipsubusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1190 */ { UD_Ivpsubusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1191 */ { UD_Ipsubusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1192 */ { UD_Ipsubusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1193 */ { UD_Ivpsubusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1194 */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1195 */ { UD_Ivpunpckhbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1196 */ { UD_Ipunpckhbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1197 */ { UD_Ipunpckhwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1198 */ { UD_Ivpunpckhwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1199 */ { UD_Ipunpckhwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1200 */ { UD_Ipunpckhdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1201 */ { UD_Ivpunpckhdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1202 */ { UD_Ipunpckhdq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1203 */ { UD_Ipunpcklbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1204 */ { UD_Ivpunpcklbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1205 */ { UD_Ipunpcklbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1206 */ { UD_Ipunpcklwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1207 */ { UD_Ivpunpcklwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1208 */ { UD_Ipunpcklwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1209 */ { UD_Ipunpckldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1210 */ { UD_Ivpunpckldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1211 */ { UD_Ipunpckldq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1212 */ { UD_Ipi2fw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1213 */ { UD_Ipi2fd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1214 */ { UD_Ipf2iw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1215 */ { UD_Ipf2id, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1216 */ { UD_Ipfnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1217 */ { UD_Ipfpnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1218 */ { UD_Ipfcmpge, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1219 */ { UD_Ipfmin, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1220 */ { UD_Ipfrcp, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1221 */ { UD_Ipfrsqrt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1222 */ { UD_Ipfsub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1223 */ { UD_Ipfadd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1224 */ { UD_Ipfcmpgt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1225 */ { UD_Ipfmax, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1226 */ { UD_Ipfrcpit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1227 */ { UD_Ipfrsqit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1228 */ { UD_Ipfsubr, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1229 */ { UD_Ipfacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1230 */ { UD_Ipfcmpeq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1231 */ { UD_Ipfmul, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1232 */ { UD_Ipfrcpit2, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1233 */ { UD_Ipmulhrw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1234 */ { UD_Ipswapd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1235 */ { UD_Ipavgusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1236 */ { UD_Ipush, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1237 */ { UD_Ipush, O_CS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1238 */ { UD_Ipush, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1239 */ { UD_Ipush, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1240 */ { UD_Ipush, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1241 */ { UD_Ipush, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1242 */ { UD_Ipush, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1243 */ { UD_Ipush, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1244 */ { UD_Ipush, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1245 */ { UD_Ipush, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1246 */ { UD_Ipush, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1247 */ { UD_Ipush, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1248 */ { UD_Ipush, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1249 */ { UD_Ipush, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1250 */ { UD_Ipush, O_sIz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1251 */ { UD_Ipush, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1252 */ { UD_Ipush, O_sIb, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1253 */ { UD_Ipusha, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1254 */ { UD_Ipushad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1255 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1256 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1257 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1258 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1259 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1260 */ { UD_Ipxor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1261 */ { UD_Ivpxor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1262 */ { UD_Ipxor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1263 */ { UD_Ircl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1264 */ { UD_Ircl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1265 */ { UD_Ircl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1266 */ { UD_Ircl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1267 */ { UD_Ircl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1268 */ { UD_Ircl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1269 */ { UD_Ircr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1270 */ { UD_Ircr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1271 */ { UD_Ircr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1272 */ { UD_Ircr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1273 */ { UD_Ircr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1274 */ { UD_Ircr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1275 */ { UD_Irol, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1276 */ { UD_Irol, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1277 */ { UD_Irol, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1278 */ { UD_Irol, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1279 */ { UD_Irol, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1280 */ { UD_Irol, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1281 */ { UD_Iror, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1282 */ { UD_Iror, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1283 */ { UD_Iror, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1284 */ { UD_Iror, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1285 */ { UD_Iror, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1286 */ { UD_Iror, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1287 */ { UD_Ircpps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1288 */ { UD_Ivrcpps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1289 */ { UD_Ircpss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1290 */ { UD_Ivrcpss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1291 */ { UD_Irdmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1292 */ { UD_Irdpmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1293 */ { UD_Irdtsc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1294 */ { UD_Irdtscp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1295 */ { UD_Irepne, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1296 */ { UD_Irep, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1297 */ { UD_Iret, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1298 */ { UD_Iret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1299 */ { UD_Iretf, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1300 */ { UD_Iretf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1301 */ { UD_Irsm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1302 */ { UD_Irsqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1303 */ { UD_Ivrsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1304 */ { UD_Irsqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1305 */ { UD_Ivrsqrtss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1306 */ { UD_Isahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1307 */ { UD_Isalc, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1308 */ { UD_Isar, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1309 */ { UD_Isar, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1310 */ { UD_Isar, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1311 */ { UD_Isar, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1312 */ { UD_Isar, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1313 */ { UD_Isar, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1314 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1315 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1316 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1317 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1318 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1319 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1320 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1321 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1322 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1323 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1324 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1325 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1326 */ { UD_Ishr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1327 */ { UD_Ishr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1328 */ { UD_Ishr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1329 */ { UD_Ishr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1330 */ { UD_Ishr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1331 */ { UD_Ishr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1332 */ { UD_Isbb, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1333 */ { UD_Isbb, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1334 */ { UD_Isbb, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1335 */ { UD_Isbb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1336 */ { UD_Isbb, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1337 */ { UD_Isbb, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1338 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1339 */ { UD_Isbb, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1340 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1341 */ { UD_Isbb, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1342 */ { UD_Iscasb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz }, + /* 1343 */ { UD_Iscasw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1344 */ { UD_Iscasd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1345 */ { UD_Iscasq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1346 */ { UD_Iseto, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1347 */ { UD_Isetno, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1348 */ { UD_Isetb, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1349 */ { UD_Isetae, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1350 */ { UD_Isetz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1351 */ { UD_Isetnz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1352 */ { UD_Isetbe, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1353 */ { UD_Iseta, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1354 */ { UD_Isets, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1355 */ { UD_Isetns, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1356 */ { UD_Isetp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1357 */ { UD_Isetnp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1358 */ { UD_Isetl, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1359 */ { UD_Isetge, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1360 */ { UD_Isetle, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1361 */ { UD_Isetg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1362 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1363 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1364 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1365 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1366 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1367 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1368 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1369 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1370 */ { UD_Isgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1371 */ { UD_Ishld, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1372 */ { UD_Ishld, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1373 */ { UD_Ishrd, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1374 */ { UD_Ishrd, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1375 */ { UD_Ishufpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1376 */ { UD_Ivshufpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1377 */ { UD_Ishufps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1378 */ { UD_Ivshufps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1379 */ { UD_Isidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1380 */ { UD_Isldt, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1381 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1382 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1383 */ { UD_Isqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1384 */ { UD_Ivsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1385 */ { UD_Isqrtpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1386 */ { UD_Ivsqrtpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1387 */ { UD_Isqrtsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1388 */ { UD_Ivsqrtsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1389 */ { UD_Isqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1390 */ { UD_Ivsqrtss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1391 */ { UD_Istc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1392 */ { UD_Istd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1393 */ { UD_Istgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1394 */ { UD_Isti, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1395 */ { UD_Iskinit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1396 */ { UD_Istmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1397 */ { UD_Ivstmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1398 */ { UD_Istosb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 1399 */ { UD_Istosw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1400 */ { UD_Istosd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1401 */ { UD_Istosq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1402 */ { UD_Istr, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1403 */ { UD_Isub, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1404 */ { UD_Isub, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1405 */ { UD_Isub, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1406 */ { UD_Isub, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1407 */ { UD_Isub, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1408 */ { UD_Isub, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1409 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1410 */ { UD_Isub, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1411 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1412 */ { UD_Isub, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1413 */ { UD_Isubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1414 */ { UD_Ivsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1415 */ { UD_Isubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1416 */ { UD_Ivsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1417 */ { UD_Isubsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1418 */ { UD_Ivsubsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1419 */ { UD_Isubss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1420 */ { UD_Ivsubss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1421 */ { UD_Iswapgs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1422 */ { UD_Isyscall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1423 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1424 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1425 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1426 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1427 */ { UD_Isysret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1428 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1429 */ { UD_Itest, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1430 */ { UD_Itest, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1431 */ { UD_Itest, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1432 */ { UD_Itest, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1433 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1434 */ { UD_Itest, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1435 */ { UD_Itest, O_Ev, O_Iz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1436 */ { UD_Iucomisd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1437 */ { UD_Ivucomisd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1438 */ { UD_Iucomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1439 */ { UD_Ivucomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1440 */ { UD_Iud2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1441 */ { UD_Iunpckhpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1442 */ { UD_Ivunpckhpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1443 */ { UD_Iunpckhps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1444 */ { UD_Ivunpckhps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1445 */ { UD_Iunpcklps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1446 */ { UD_Ivunpcklps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1447 */ { UD_Iunpcklpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1448 */ { UD_Ivunpcklpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1449 */ { UD_Iverr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1450 */ { UD_Iverw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1451 */ { UD_Ivmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1452 */ { UD_Irdrand, O_R, O_NONE, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1453 */ { UD_Ivmclear, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1454 */ { UD_Ivmxon, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1455 */ { UD_Ivmptrld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1456 */ { UD_Ivmptrst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1457 */ { UD_Ivmlaunch, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1458 */ { UD_Ivmresume, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1459 */ { UD_Ivmxoff, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1460 */ { UD_Ivmread, O_Ey, O_Gy, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1461 */ { UD_Ivmwrite, O_Gy, O_Ey, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1462 */ { UD_Ivmrun, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1463 */ { UD_Ivmmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1464 */ { UD_Ivmload, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1465 */ { UD_Ivmsave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1466 */ { UD_Iwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1467 */ { UD_Iwbinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1468 */ { UD_Iwrmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1469 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 1470 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1471 */ { UD_Ixchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1472 */ { UD_Ixchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1473 */ { UD_Ixchg, O_R0v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1474 */ { UD_Ixchg, O_R1v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1475 */ { UD_Ixchg, O_R2v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1476 */ { UD_Ixchg, O_R3v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1477 */ { UD_Ixchg, O_R4v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1478 */ { UD_Ixchg, O_R5v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1479 */ { UD_Ixchg, O_R6v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1480 */ { UD_Ixchg, O_R7v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1481 */ { UD_Ixgetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1482 */ { UD_Ixlatb, O_NONE, O_NONE, O_NONE, O_NONE, P_rexw|P_seg }, + /* 1483 */ { UD_Ixor, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1484 */ { UD_Ixor, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1485 */ { UD_Ixor, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1486 */ { UD_Ixor, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1487 */ { UD_Ixor, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1488 */ { UD_Ixor, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1489 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1490 */ { UD_Ixor, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1491 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1492 */ { UD_Ixor, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1493 */ { UD_Ixorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1494 */ { UD_Ivxorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1495 */ { UD_Ixorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1496 */ { UD_Ivxorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1497 */ { UD_Ixcryptecb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1498 */ { UD_Ixcryptcbc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1499 */ { UD_Ixcryptctr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1500 */ { UD_Ixcryptcfb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1501 */ { UD_Ixcryptofb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1502 */ { UD_Ixrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1503 */ { UD_Ixsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1504 */ { UD_Ixsetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1505 */ { UD_Ixsha1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1506 */ { UD_Ixsha256, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1507 */ { UD_Ixstore, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1508 */ { UD_Ipclmulqdq, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1509 */ { UD_Ivpclmulqdq, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1510 */ { UD_Igetsec, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1511 */ { UD_Imovdqa, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1512 */ { UD_Ivmovdqa, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1513 */ { UD_Imovdqa, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1514 */ { UD_Ivmovdqa, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1515 */ { UD_Imaskmovdqu, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1516 */ { UD_Ivmaskmovdqu, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1517 */ { UD_Imovdq2q, O_P, O_U, O_NONE, O_NONE, P_aso|P_rexb }, + /* 1518 */ { UD_Imovdqu, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1519 */ { UD_Ivmovdqu, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1520 */ { UD_Imovdqu, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1521 */ { UD_Imovq2dq, O_V, O_N, O_NONE, O_NONE, P_aso|P_rexr }, + /* 1522 */ { UD_Ipaddq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1523 */ { UD_Ipaddq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1524 */ { UD_Ivpaddq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1525 */ { UD_Ipsubq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1526 */ { UD_Ivpsubq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1527 */ { UD_Ipsubq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1528 */ { UD_Ipmuludq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1529 */ { UD_Ipmuludq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1530 */ { UD_Ipshufhw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1531 */ { UD_Ivpshufhw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1532 */ { UD_Ipshuflw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1533 */ { UD_Ivpshuflw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1534 */ { UD_Ipshufd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1535 */ { UD_Ivpshufd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1536 */ { UD_Ipslldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1537 */ { UD_Ivpslldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1538 */ { UD_Ipsrldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1539 */ { UD_Ivpsrldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1540 */ { UD_Ipunpckhqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1541 */ { UD_Ivpunpckhqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1542 */ { UD_Ipunpcklqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1543 */ { UD_Ivpunpcklqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1544 */ { UD_Ihaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1545 */ { UD_Ivhaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1546 */ { UD_Ihaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1547 */ { UD_Ivhaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1548 */ { UD_Ihsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1549 */ { UD_Ivhsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1550 */ { UD_Ihsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1551 */ { UD_Ivhsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1552 */ { UD_Iinsertps, O_V, O_Md, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1553 */ { UD_Ivinsertps, O_Vx, O_Hx, O_Md, O_Ib, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1554 */ { UD_Ilddqu, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1555 */ { UD_Ivlddqu, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1556 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1557 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1558 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1559 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1560 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1561 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1562 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1563 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1564 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1565 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1566 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1567 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1568 */ { UD_Ipabsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1569 */ { UD_Ipabsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1570 */ { UD_Ivpabsb, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1571 */ { UD_Ipabsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1572 */ { UD_Ipabsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1573 */ { UD_Ivpabsw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1574 */ { UD_Ipabsd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1575 */ { UD_Ipabsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1576 */ { UD_Ivpabsd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1577 */ { UD_Ipshufb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1578 */ { UD_Ipshufb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1579 */ { UD_Ivpshufb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1580 */ { UD_Iphaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1581 */ { UD_Iphaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1582 */ { UD_Ivphaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1583 */ { UD_Iphaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1584 */ { UD_Iphaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1585 */ { UD_Ivphaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1586 */ { UD_Iphaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1587 */ { UD_Iphaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1588 */ { UD_Ivphaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1589 */ { UD_Ipmaddubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1590 */ { UD_Ipmaddubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1591 */ { UD_Ivpmaddubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1592 */ { UD_Iphsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1593 */ { UD_Iphsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1594 */ { UD_Ivphsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1595 */ { UD_Iphsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1596 */ { UD_Iphsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1597 */ { UD_Ivphsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1598 */ { UD_Iphsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1599 */ { UD_Iphsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1600 */ { UD_Ivphsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1601 */ { UD_Ipsignb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1602 */ { UD_Ipsignb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1603 */ { UD_Ivpsignb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1604 */ { UD_Ipsignd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1605 */ { UD_Ipsignd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1606 */ { UD_Ivpsignd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1607 */ { UD_Ipsignw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1608 */ { UD_Ipsignw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1609 */ { UD_Ivpsignw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1610 */ { UD_Ipmulhrsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1611 */ { UD_Ipmulhrsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1612 */ { UD_Ivpmulhrsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1613 */ { UD_Ipalignr, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1614 */ { UD_Ipalignr, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1615 */ { UD_Ivpalignr, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1616 */ { UD_Ipblendvb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1617 */ { UD_Ipmuldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1618 */ { UD_Ivpmuldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1619 */ { UD_Ipminsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1620 */ { UD_Ivpminsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1621 */ { UD_Ipminsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1622 */ { UD_Ivpminsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1623 */ { UD_Ipminuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1624 */ { UD_Ivpminuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1625 */ { UD_Ipminud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1626 */ { UD_Ivpminud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1627 */ { UD_Ipmaxsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1628 */ { UD_Ivpmaxsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1629 */ { UD_Ipmaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1630 */ { UD_Ivpmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1631 */ { UD_Ipmaxud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1632 */ { UD_Ivpmaxud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1633 */ { UD_Ipmaxuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1634 */ { UD_Ivpmaxuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1635 */ { UD_Ipmulld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1636 */ { UD_Ivpmulld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1637 */ { UD_Iphminposuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1638 */ { UD_Ivphminposuw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1639 */ { UD_Iroundps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1640 */ { UD_Ivroundps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1641 */ { UD_Iroundpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1642 */ { UD_Ivroundpd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1643 */ { UD_Iroundss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1644 */ { UD_Ivroundss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1645 */ { UD_Iroundsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1646 */ { UD_Ivroundsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1647 */ { UD_Iblendpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1648 */ { UD_Ivblendpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1649 */ { UD_Iblendps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1650 */ { UD_Ivblendps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1651 */ { UD_Iblendvpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1652 */ { UD_Iblendvps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1653 */ { UD_Ibound, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 1654 */ { UD_Ibsf, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1655 */ { UD_Ibsr, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1656 */ { UD_Ibswap, O_R0y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1657 */ { UD_Ibswap, O_R1y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1658 */ { UD_Ibswap, O_R2y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1659 */ { UD_Ibswap, O_R3y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1660 */ { UD_Ibswap, O_R4y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1661 */ { UD_Ibswap, O_R5y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1662 */ { UD_Ibswap, O_R6y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1663 */ { UD_Ibswap, O_R7y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1664 */ { UD_Ibt, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1665 */ { UD_Ibt, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1666 */ { UD_Ibtc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1667 */ { UD_Ibtc, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1668 */ { UD_Ibtr, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1669 */ { UD_Ibtr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1670 */ { UD_Ibts, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1671 */ { UD_Ibts, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1672 */ { UD_Ipblendw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1673 */ { UD_Ivpblendw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1674 */ { UD_Impsadbw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1675 */ { UD_Ivmpsadbw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1676 */ { UD_Imovntdqa, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1677 */ { UD_Ivmovntdqa, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1678 */ { UD_Ipackusdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1679 */ { UD_Ivpackusdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1680 */ { UD_Ipmovsxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1681 */ { UD_Ivpmovsxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1682 */ { UD_Ipmovsxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1683 */ { UD_Ivpmovsxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1684 */ { UD_Ipmovsxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1685 */ { UD_Ivpmovsxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1686 */ { UD_Ipmovsxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1687 */ { UD_Ivpmovsxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1688 */ { UD_Ipmovsxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1689 */ { UD_Ivpmovsxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1690 */ { UD_Ipmovsxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1691 */ { UD_Ipmovzxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1692 */ { UD_Ivpmovzxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1693 */ { UD_Ipmovzxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1694 */ { UD_Ivpmovzxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1695 */ { UD_Ipmovzxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1696 */ { UD_Ivpmovzxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1697 */ { UD_Ipmovzxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1698 */ { UD_Ivpmovzxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1699 */ { UD_Ipmovzxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1700 */ { UD_Ivpmovzxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1701 */ { UD_Ipmovzxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1702 */ { UD_Ivpmovzxdq, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1703 */ { UD_Ipcmpeqq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1704 */ { UD_Ivpcmpeqq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1705 */ { UD_Ipopcnt, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1706 */ { UD_Iptest, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1707 */ { UD_Ivptest, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1708 */ { UD_Ipcmpestri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1709 */ { UD_Ivpcmpestri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1710 */ { UD_Ipcmpestrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1711 */ { UD_Ivpcmpestrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1712 */ { UD_Ipcmpgtq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1713 */ { UD_Ivpcmpgtq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1714 */ { UD_Ipcmpistri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1715 */ { UD_Ivpcmpistri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1716 */ { UD_Ipcmpistrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1717 */ { UD_Ivpcmpistrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1718 */ { UD_Imovbe, O_Gv, O_Mv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1719 */ { UD_Imovbe, O_Mv, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1720 */ { UD_Icrc32, O_Gy, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1721 */ { UD_Icrc32, O_Gy, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1722 */ { UD_Ivbroadcastss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1723 */ { UD_Ivbroadcastsd, O_Vqq, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1724 */ { UD_Ivextractf128, O_Wdq, O_Vqq, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1725 */ { UD_Ivinsertf128, O_Vqq, O_Hqq, O_Wdq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1726 */ { UD_Ivmaskmovps, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1727 */ { UD_Ivmaskmovps, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1728 */ { UD_Ivmaskmovpd, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1729 */ { UD_Ivmaskmovpd, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1730 */ { UD_Ivpermilpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1731 */ { UD_Ivpermilpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1732 */ { UD_Ivpermilps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1733 */ { UD_Ivpermilps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1734 */ { UD_Ivperm2f128, O_Vqq, O_Hqq, O_Wqq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1735 */ { UD_Ivtestps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1736 */ { UD_Ivtestpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1737 */ { UD_Ivzeroupper, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1738 */ { UD_Ivzeroall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1739 */ { UD_Ivblendvpd, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1740 */ { UD_Ivblendvps, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1741 */ { UD_Ivmovsd, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1742 */ { UD_Ivmovsd, O_V, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1743 */ { UD_Ivmovsd, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1744 */ { UD_Ivmovsd, O_Mq, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1745 */ { UD_Ivmovss, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1746 */ { UD_Ivmovss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1747 */ { UD_Ivmovss, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1748 */ { UD_Ivmovss, O_Md, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1749 */ { UD_Ivpblendvb, O_V, O_H, O_W, O_L, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1750 */ { UD_Ivpsllw, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1751 */ { UD_Ivpsllw, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1752 */ { UD_Ivpslld, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1753 */ { UD_Ivpslld, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1754 */ { UD_Ivpsllq, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1755 */ { UD_Ivpsllq, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + + +const char* ud_mnemonics_str[] = { + "aaa", + "aad", + "aam", + "aas", + "adc", + "add", + "addpd", + "addps", + "addsd", + "addss", + "addsubpd", + "addsubps", + "aesdec", + "aesdeclast", + "aesenc", + "aesenclast", + "aesimc", + "aeskeygenassist", + "and", + "andnpd", + "andnps", + "andpd", + "andps", + "arpl", + "blendpd", + "blendps", + "blendvpd", + "blendvps", + "bound", + "bsf", + "bsr", + "bswap", + "bt", + "btc", + "btr", + "bts", + "call", + "cbw", + "cdq", + "cdqe", + "clc", + "cld", + "clflush", + "clgi", + "cli", + "clts", + "cmc", + "cmova", + "cmovae", + "cmovb", + "cmovbe", + "cmovg", + "cmovge", + "cmovl", + "cmovle", + "cmovno", + "cmovnp", + "cmovns", + "cmovnz", + "cmovo", + "cmovp", + "cmovs", + "cmovz", + "cmp", + "cmppd", + "cmpps", + "cmpsb", + "cmpsd", + "cmpsq", + "cmpss", + "cmpsw", + "cmpxchg", + "cmpxchg16b", + "cmpxchg8b", + "comisd", + "comiss", + "cpuid", + "cqo", + "crc32", + "cvtdq2pd", + "cvtdq2ps", + "cvtpd2dq", + "cvtpd2pi", + "cvtpd2ps", + "cvtpi2pd", + "cvtpi2ps", + "cvtps2dq", + "cvtps2pd", + "cvtps2pi", + "cvtsd2si", + "cvtsd2ss", + "cvtsi2sd", + "cvtsi2ss", + "cvtss2sd", + "cvtss2si", + "cvttpd2dq", + "cvttpd2pi", + "cvttps2dq", + "cvttps2pi", + "cvttsd2si", + "cvttss2si", + "cwd", + "cwde", + "daa", + "das", + "dec", + "div", + "divpd", + "divps", + "divsd", + "divss", + "dppd", + "dpps", + "emms", + "enter", + "extractps", + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fclex", + "fcmovb", + "fcmovbe", + "fcmove", + "fcmovnb", + "fcmovnbe", + "fcmovne", + "fcmovnu", + "fcmovu", + "fcom", + "fcom2", + "fcomi", + "fcomip", + "fcomp", + "fcomp3", + "fcomp5", + "fcompp", + "fcos", + "fdecstp", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "femms", + "ffree", + "ffreep", + "fiadd", + "ficom", + "ficomp", + "fidiv", + "fidivr", + "fild", + "fimul", + "fincstp", + "fist", + "fistp", + "fisttp", + "fisub", + "fisubr", + "fld", + "fld1", + "fldcw", + "fldenv", + "fldl2e", + "fldl2t", + "fldlg2", + "fldln2", + "fldpi", + "fldz", + "fmul", + "fmulp", + "fninit", + "fnop", + "fnsave", + "fnstcw", + "fnstenv", + "fnstsw", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "fscale", + "fsin", + "fsincos", + "fsqrt", + "fst", + "fstp", + "fstp1", + "fstp8", + "fstp9", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomi", + "fucomip", + "fucomp", + "fucompp", + "fxam", + "fxch", + "fxch4", + "fxch7", + "fxrstor", + "fxsave", + "fxtract", + "fyl2x", + "fyl2xp1", + "getsec", + "haddpd", + "haddps", + "hlt", + "hsubpd", + "hsubps", + "idiv", + "imul", + "in", + "inc", + "insb", + "insd", + "insertps", + "insw", + "int", + "int1", + "int3", + "into", + "invd", + "invept", + "invlpg", + "invlpga", + "invvpid", + "iretd", + "iretq", + "iretw", + "ja", + "jae", + "jb", + "jbe", + "jcxz", + "jecxz", + "jg", + "jge", + "jl", + "jle", + "jmp", + "jno", + "jnp", + "jns", + "jnz", + "jo", + "jp", + "jrcxz", + "js", + "jz", + "lahf", + "lar", + "lddqu", + "ldmxcsr", + "lds", + "lea", + "leave", + "les", + "lfence", + "lfs", + "lgdt", + "lgs", + "lidt", + "lldt", + "lmsw", + "lock", + "lodsb", + "lodsd", + "lodsq", + "lodsw", + "loop", + "loope", + "loopne", + "lsl", + "lss", + "ltr", + "maskmovdqu", + "maskmovq", + "maxpd", + "maxps", + "maxsd", + "maxss", + "mfence", + "minpd", + "minps", + "minsd", + "minss", + "monitor", + "montmul", + "mov", + "movapd", + "movaps", + "movbe", + "movd", + "movddup", + "movdq2q", + "movdqa", + "movdqu", + "movhlps", + "movhpd", + "movhps", + "movlhps", + "movlpd", + "movlps", + "movmskpd", + "movmskps", + "movntdq", + "movntdqa", + "movnti", + "movntpd", + "movntps", + "movntq", + "movq", + "movq2dq", + "movsb", + "movsd", + "movshdup", + "movsldup", + "movsq", + "movss", + "movsw", + "movsx", + "movsxd", + "movupd", + "movups", + "movzx", + "mpsadbw", + "mul", + "mulpd", + "mulps", + "mulsd", + "mulss", + "mwait", + "neg", + "nop", + "not", + "or", + "orpd", + "orps", + "out", + "outsb", + "outsd", + "outsw", + "pabsb", + "pabsd", + "pabsw", + "packssdw", + "packsswb", + "packusdw", + "packuswb", + "paddb", + "paddd", + "paddq", + "paddsb", + "paddsw", + "paddusb", + "paddusw", + "paddw", + "palignr", + "pand", + "pandn", + "pavgb", + "pavgusb", + "pavgw", + "pblendvb", + "pblendw", + "pclmulqdq", + "pcmpeqb", + "pcmpeqd", + "pcmpeqq", + "pcmpeqw", + "pcmpestri", + "pcmpestrm", + "pcmpgtb", + "pcmpgtd", + "pcmpgtq", + "pcmpgtw", + "pcmpistri", + "pcmpistrm", + "pextrb", + "pextrd", + "pextrq", + "pextrw", + "pf2id", + "pf2iw", + "pfacc", + "pfadd", + "pfcmpeq", + "pfcmpge", + "pfcmpgt", + "pfmax", + "pfmin", + "pfmul", + "pfnacc", + "pfpnacc", + "pfrcp", + "pfrcpit1", + "pfrcpit2", + "pfrsqit1", + "pfrsqrt", + "pfsub", + "pfsubr", + "phaddd", + "phaddsw", + "phaddw", + "phminposuw", + "phsubd", + "phsubsw", + "phsubw", + "pi2fd", + "pi2fw", + "pinsrb", + "pinsrd", + "pinsrq", + "pinsrw", + "pmaddubsw", + "pmaddwd", + "pmaxsb", + "pmaxsd", + "pmaxsw", + "pmaxub", + "pmaxud", + "pmaxuw", + "pminsb", + "pminsd", + "pminsw", + "pminub", + "pminud", + "pminuw", + "pmovmskb", + "pmovsxbd", + "pmovsxbq", + "pmovsxbw", + "pmovsxdq", + "pmovsxwd", + "pmovsxwq", + "pmovzxbd", + "pmovzxbq", + "pmovzxbw", + "pmovzxdq", + "pmovzxwd", + "pmovzxwq", + "pmuldq", + "pmulhrsw", + "pmulhrw", + "pmulhuw", + "pmulhw", + "pmulld", + "pmullw", + "pmuludq", + "pop", + "popa", + "popad", + "popcnt", + "popfd", + "popfq", + "popfw", + "por", + "prefetch", + "prefetchnta", + "prefetcht0", + "prefetcht1", + "prefetcht2", + "psadbw", + "pshufb", + "pshufd", + "pshufhw", + "pshuflw", + "pshufw", + "psignb", + "psignd", + "psignw", + "pslld", + "pslldq", + "psllq", + "psllw", + "psrad", + "psraw", + "psrld", + "psrldq", + "psrlq", + "psrlw", + "psubb", + "psubd", + "psubq", + "psubsb", + "psubsw", + "psubusb", + "psubusw", + "psubw", + "pswapd", + "ptest", + "punpckhbw", + "punpckhdq", + "punpckhqdq", + "punpckhwd", + "punpcklbw", + "punpckldq", + "punpcklqdq", + "punpcklwd", + "push", + "pusha", + "pushad", + "pushfd", + "pushfq", + "pushfw", + "pxor", + "rcl", + "rcpps", + "rcpss", + "rcr", + "rdmsr", + "rdpmc", + "rdrand", + "rdtsc", + "rdtscp", + "rep", + "repne", + "ret", + "retf", + "rol", + "ror", + "roundpd", + "roundps", + "roundsd", + "roundss", + "rsm", + "rsqrtps", + "rsqrtss", + "sahf", + "salc", + "sar", + "sbb", + "scasb", + "scasd", + "scasq", + "scasw", + "seta", + "setae", + "setb", + "setbe", + "setg", + "setge", + "setl", + "setle", + "setno", + "setnp", + "setns", + "setnz", + "seto", + "setp", + "sets", + "setz", + "sfence", + "sgdt", + "shl", + "shld", + "shr", + "shrd", + "shufpd", + "shufps", + "sidt", + "skinit", + "sldt", + "smsw", + "sqrtpd", + "sqrtps", + "sqrtsd", + "sqrtss", + "stc", + "std", + "stgi", + "sti", + "stmxcsr", + "stosb", + "stosd", + "stosq", + "stosw", + "str", + "sub", + "subpd", + "subps", + "subsd", + "subss", + "swapgs", + "syscall", + "sysenter", + "sysexit", + "sysret", + "test", + "ucomisd", + "ucomiss", + "ud2", + "unpckhpd", + "unpckhps", + "unpcklpd", + "unpcklps", + "vaddpd", + "vaddps", + "vaddsd", + "vaddss", + "vaddsubpd", + "vaddsubps", + "vaesdec", + "vaesdeclast", + "vaesenc", + "vaesenclast", + "vaesimc", + "vaeskeygenassist", + "vandnpd", + "vandnps", + "vandpd", + "vandps", + "vblendpd", + "vblendps", + "vblendvpd", + "vblendvps", + "vbroadcastsd", + "vbroadcastss", + "vcmppd", + "vcmpps", + "vcmpsd", + "vcmpss", + "vcomisd", + "vcomiss", + "vcvtdq2pd", + "vcvtdq2ps", + "vcvtpd2dq", + "vcvtpd2ps", + "vcvtps2dq", + "vcvtps2pd", + "vcvtsd2si", + "vcvtsd2ss", + "vcvtsi2sd", + "vcvtsi2ss", + "vcvtss2sd", + "vcvtss2si", + "vcvttpd2dq", + "vcvttps2dq", + "vcvttsd2si", + "vcvttss2si", + "vdivpd", + "vdivps", + "vdivsd", + "vdivss", + "vdppd", + "vdpps", + "verr", + "verw", + "vextractf128", + "vextractps", + "vhaddpd", + "vhaddps", + "vhsubpd", + "vhsubps", + "vinsertf128", + "vinsertps", + "vlddqu", + "vmaskmovdqu", + "vmaskmovpd", + "vmaskmovps", + "vmaxpd", + "vmaxps", + "vmaxsd", + "vmaxss", + "vmcall", + "vmclear", + "vminpd", + "vminps", + "vminsd", + "vminss", + "vmlaunch", + "vmload", + "vmmcall", + "vmovapd", + "vmovaps", + "vmovd", + "vmovddup", + "vmovdqa", + "vmovdqu", + "vmovhlps", + "vmovhpd", + "vmovhps", + "vmovlhps", + "vmovlpd", + "vmovlps", + "vmovmskpd", + "vmovmskps", + "vmovntdq", + "vmovntdqa", + "vmovntpd", + "vmovntps", + "vmovq", + "vmovsd", + "vmovshdup", + "vmovsldup", + "vmovss", + "vmovupd", + "vmovups", + "vmpsadbw", + "vmptrld", + "vmptrst", + "vmread", + "vmresume", + "vmrun", + "vmsave", + "vmulpd", + "vmulps", + "vmulsd", + "vmulss", + "vmwrite", + "vmxoff", + "vmxon", + "vorpd", + "vorps", + "vpabsb", + "vpabsd", + "vpabsw", + "vpackssdw", + "vpacksswb", + "vpackusdw", + "vpackuswb", + "vpaddb", + "vpaddd", + "vpaddq", + "vpaddsb", + "vpaddsw", + "vpaddusb", + "vpaddusw", + "vpaddw", + "vpalignr", + "vpand", + "vpandn", + "vpavgb", + "vpavgw", + "vpblendvb", + "vpblendw", + "vpclmulqdq", + "vpcmpeqb", + "vpcmpeqd", + "vpcmpeqq", + "vpcmpeqw", + "vpcmpestri", + "vpcmpestrm", + "vpcmpgtb", + "vpcmpgtd", + "vpcmpgtq", + "vpcmpgtw", + "vpcmpistri", + "vpcmpistrm", + "vperm2f128", + "vpermilpd", + "vpermilps", + "vpextrb", + "vpextrd", + "vpextrq", + "vpextrw", + "vphaddd", + "vphaddsw", + "vphaddw", + "vphminposuw", + "vphsubd", + "vphsubsw", + "vphsubw", + "vpinsrb", + "vpinsrd", + "vpinsrq", + "vpinsrw", + "vpmaddubsw", + "vpmaddwd", + "vpmaxsb", + "vpmaxsd", + "vpmaxsw", + "vpmaxub", + "vpmaxud", + "vpmaxuw", + "vpminsb", + "vpminsd", + "vpminsw", + "vpminub", + "vpminud", + "vpminuw", + "vpmovmskb", + "vpmovsxbd", + "vpmovsxbq", + "vpmovsxbw", + "vpmovsxwd", + "vpmovsxwq", + "vpmovzxbd", + "vpmovzxbq", + "vpmovzxbw", + "vpmovzxdq", + "vpmovzxwd", + "vpmovzxwq", + "vpmuldq", + "vpmulhrsw", + "vpmulhuw", + "vpmulhw", + "vpmulld", + "vpmullw", + "vpor", + "vpsadbw", + "vpshufb", + "vpshufd", + "vpshufhw", + "vpshuflw", + "vpsignb", + "vpsignd", + "vpsignw", + "vpslld", + "vpslldq", + "vpsllq", + "vpsllw", + "vpsrad", + "vpsraw", + "vpsrld", + "vpsrldq", + "vpsrlq", + "vpsrlw", + "vpsubb", + "vpsubd", + "vpsubq", + "vpsubsb", + "vpsubsw", + "vpsubusb", + "vpsubusw", + "vpsubw", + "vptest", + "vpunpckhbw", + "vpunpckhdq", + "vpunpckhqdq", + "vpunpckhwd", + "vpunpcklbw", + "vpunpckldq", + "vpunpcklqdq", + "vpunpcklwd", + "vpxor", + "vrcpps", + "vrcpss", + "vroundpd", + "vroundps", + "vroundsd", + "vroundss", + "vrsqrtps", + "vrsqrtss", + "vshufpd", + "vshufps", + "vsqrtpd", + "vsqrtps", + "vsqrtsd", + "vsqrtss", + "vstmxcsr", + "vsubpd", + "vsubps", + "vsubsd", + "vsubss", + "vtestpd", + "vtestps", + "vucomisd", + "vucomiss", + "vunpckhpd", + "vunpckhps", + "vunpcklpd", + "vunpcklps", + "vxorpd", + "vxorps", + "vzeroall", + "vzeroupper", + "wait", + "wbinvd", + "wrmsr", + "xadd", + "xchg", + "xcryptcbc", + "xcryptcfb", + "xcryptctr", + "xcryptecb", + "xcryptofb", + "xgetbv", + "xlatb", + "xor", + "xorpd", + "xorps", + "xrstor", + "xsave", + "xsetbv", + "xsha1", + "xsha256", + "xstore", + "invalid", + "3dnow", + "none", + "db", + "pause" +}; diff --git a/src/third_party/udis86/libudis86/itab.h b/src/third_party/udis86/libudis86/itab.h new file mode 100644 index 00000000..329fa07e --- /dev/null +++ b/src/third_party/udis86/libudis86/itab.h @@ -0,0 +1,935 @@ +#ifndef UD_ITAB_H +#define UD_ITAB_H + +/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */ + +/* ud_table_type -- lookup table types (see decode.c) */ +enum ud_table_type { + UD_TAB__OPC_VEX, + UD_TAB__OPC_TABLE, + UD_TAB__OPC_X87, + UD_TAB__OPC_MOD, + UD_TAB__OPC_RM, + UD_TAB__OPC_OSIZE, + UD_TAB__OPC_MODE, + UD_TAB__OPC_VEX_L, + UD_TAB__OPC_3DNOW, + UD_TAB__OPC_REG, + UD_TAB__OPC_ASIZE, + UD_TAB__OPC_VEX_W, + UD_TAB__OPC_SSE, + UD_TAB__OPC_VENDOR +}; + +/* ud_mnemonic -- mnemonic constants */ +enum ud_mnemonic_code { + UD_Iaaa, + UD_Iaad, + UD_Iaam, + UD_Iaas, + UD_Iadc, + UD_Iadd, + UD_Iaddpd, + UD_Iaddps, + UD_Iaddsd, + UD_Iaddss, + UD_Iaddsubpd, + UD_Iaddsubps, + UD_Iaesdec, + UD_Iaesdeclast, + UD_Iaesenc, + UD_Iaesenclast, + UD_Iaesimc, + UD_Iaeskeygenassist, + UD_Iand, + UD_Iandnpd, + UD_Iandnps, + UD_Iandpd, + UD_Iandps, + UD_Iarpl, + UD_Iblendpd, + UD_Iblendps, + UD_Iblendvpd, + UD_Iblendvps, + UD_Ibound, + UD_Ibsf, + UD_Ibsr, + UD_Ibswap, + UD_Ibt, + UD_Ibtc, + UD_Ibtr, + UD_Ibts, + UD_Icall, + UD_Icbw, + UD_Icdq, + UD_Icdqe, + UD_Iclc, + UD_Icld, + UD_Iclflush, + UD_Iclgi, + UD_Icli, + UD_Iclts, + UD_Icmc, + UD_Icmova, + UD_Icmovae, + UD_Icmovb, + UD_Icmovbe, + UD_Icmovg, + UD_Icmovge, + UD_Icmovl, + UD_Icmovle, + UD_Icmovno, + UD_Icmovnp, + UD_Icmovns, + UD_Icmovnz, + UD_Icmovo, + UD_Icmovp, + UD_Icmovs, + UD_Icmovz, + UD_Icmp, + UD_Icmppd, + UD_Icmpps, + UD_Icmpsb, + UD_Icmpsd, + UD_Icmpsq, + UD_Icmpss, + UD_Icmpsw, + UD_Icmpxchg, + UD_Icmpxchg16b, + UD_Icmpxchg8b, + UD_Icomisd, + UD_Icomiss, + UD_Icpuid, + UD_Icqo, + UD_Icrc32, + UD_Icvtdq2pd, + UD_Icvtdq2ps, + UD_Icvtpd2dq, + UD_Icvtpd2pi, + UD_Icvtpd2ps, + UD_Icvtpi2pd, + UD_Icvtpi2ps, + UD_Icvtps2dq, + UD_Icvtps2pd, + UD_Icvtps2pi, + UD_Icvtsd2si, + UD_Icvtsd2ss, + UD_Icvtsi2sd, + UD_Icvtsi2ss, + UD_Icvtss2sd, + UD_Icvtss2si, + UD_Icvttpd2dq, + UD_Icvttpd2pi, + UD_Icvttps2dq, + UD_Icvttps2pi, + UD_Icvttsd2si, + UD_Icvttss2si, + UD_Icwd, + UD_Icwde, + UD_Idaa, + UD_Idas, + UD_Idec, + UD_Idiv, + UD_Idivpd, + UD_Idivps, + UD_Idivsd, + UD_Idivss, + UD_Idppd, + UD_Idpps, + UD_Iemms, + UD_Ienter, + UD_Iextractps, + UD_If2xm1, + UD_Ifabs, + UD_Ifadd, + UD_Ifaddp, + UD_Ifbld, + UD_Ifbstp, + UD_Ifchs, + UD_Ifclex, + UD_Ifcmovb, + UD_Ifcmovbe, + UD_Ifcmove, + UD_Ifcmovnb, + UD_Ifcmovnbe, + UD_Ifcmovne, + UD_Ifcmovnu, + UD_Ifcmovu, + UD_Ifcom, + UD_Ifcom2, + UD_Ifcomi, + UD_Ifcomip, + UD_Ifcomp, + UD_Ifcomp3, + UD_Ifcomp5, + UD_Ifcompp, + UD_Ifcos, + UD_Ifdecstp, + UD_Ifdiv, + UD_Ifdivp, + UD_Ifdivr, + UD_Ifdivrp, + UD_Ifemms, + UD_Iffree, + UD_Iffreep, + UD_Ifiadd, + UD_Ificom, + UD_Ificomp, + UD_Ifidiv, + UD_Ifidivr, + UD_Ifild, + UD_Ifimul, + UD_Ifincstp, + UD_Ifist, + UD_Ifistp, + UD_Ifisttp, + UD_Ifisub, + UD_Ifisubr, + UD_Ifld, + UD_Ifld1, + UD_Ifldcw, + UD_Ifldenv, + UD_Ifldl2e, + UD_Ifldl2t, + UD_Ifldlg2, + UD_Ifldln2, + UD_Ifldpi, + UD_Ifldz, + UD_Ifmul, + UD_Ifmulp, + UD_Ifninit, + UD_Ifnop, + UD_Ifnsave, + UD_Ifnstcw, + UD_Ifnstenv, + UD_Ifnstsw, + UD_Ifpatan, + UD_Ifprem, + UD_Ifprem1, + UD_Ifptan, + UD_Ifrndint, + UD_Ifrstor, + UD_Ifscale, + UD_Ifsin, + UD_Ifsincos, + UD_Ifsqrt, + UD_Ifst, + UD_Ifstp, + UD_Ifstp1, + UD_Ifstp8, + UD_Ifstp9, + UD_Ifsub, + UD_Ifsubp, + UD_Ifsubr, + UD_Ifsubrp, + UD_Iftst, + UD_Ifucom, + UD_Ifucomi, + UD_Ifucomip, + UD_Ifucomp, + UD_Ifucompp, + UD_Ifxam, + UD_Ifxch, + UD_Ifxch4, + UD_Ifxch7, + UD_Ifxrstor, + UD_Ifxsave, + UD_Ifxtract, + UD_Ifyl2x, + UD_Ifyl2xp1, + UD_Igetsec, + UD_Ihaddpd, + UD_Ihaddps, + UD_Ihlt, + UD_Ihsubpd, + UD_Ihsubps, + UD_Iidiv, + UD_Iimul, + UD_Iin, + UD_Iinc, + UD_Iinsb, + UD_Iinsd, + UD_Iinsertps, + UD_Iinsw, + UD_Iint, + UD_Iint1, + UD_Iint3, + UD_Iinto, + UD_Iinvd, + UD_Iinvept, + UD_Iinvlpg, + UD_Iinvlpga, + UD_Iinvvpid, + UD_Iiretd, + UD_Iiretq, + UD_Iiretw, + UD_Ija, + UD_Ijae, + UD_Ijb, + UD_Ijbe, + UD_Ijcxz, + UD_Ijecxz, + UD_Ijg, + UD_Ijge, + UD_Ijl, + UD_Ijle, + UD_Ijmp, + UD_Ijno, + UD_Ijnp, + UD_Ijns, + UD_Ijnz, + UD_Ijo, + UD_Ijp, + UD_Ijrcxz, + UD_Ijs, + UD_Ijz, + UD_Ilahf, + UD_Ilar, + UD_Ilddqu, + UD_Ildmxcsr, + UD_Ilds, + UD_Ilea, + UD_Ileave, + UD_Iles, + UD_Ilfence, + UD_Ilfs, + UD_Ilgdt, + UD_Ilgs, + UD_Ilidt, + UD_Illdt, + UD_Ilmsw, + UD_Ilock, + UD_Ilodsb, + UD_Ilodsd, + UD_Ilodsq, + UD_Ilodsw, + UD_Iloop, + UD_Iloope, + UD_Iloopne, + UD_Ilsl, + UD_Ilss, + UD_Iltr, + UD_Imaskmovdqu, + UD_Imaskmovq, + UD_Imaxpd, + UD_Imaxps, + UD_Imaxsd, + UD_Imaxss, + UD_Imfence, + UD_Iminpd, + UD_Iminps, + UD_Iminsd, + UD_Iminss, + UD_Imonitor, + UD_Imontmul, + UD_Imov, + UD_Imovapd, + UD_Imovaps, + UD_Imovbe, + UD_Imovd, + UD_Imovddup, + UD_Imovdq2q, + UD_Imovdqa, + UD_Imovdqu, + UD_Imovhlps, + UD_Imovhpd, + UD_Imovhps, + UD_Imovlhps, + UD_Imovlpd, + UD_Imovlps, + UD_Imovmskpd, + UD_Imovmskps, + UD_Imovntdq, + UD_Imovntdqa, + UD_Imovnti, + UD_Imovntpd, + UD_Imovntps, + UD_Imovntq, + UD_Imovq, + UD_Imovq2dq, + UD_Imovsb, + UD_Imovsd, + UD_Imovshdup, + UD_Imovsldup, + UD_Imovsq, + UD_Imovss, + UD_Imovsw, + UD_Imovsx, + UD_Imovsxd, + UD_Imovupd, + UD_Imovups, + UD_Imovzx, + UD_Impsadbw, + UD_Imul, + UD_Imulpd, + UD_Imulps, + UD_Imulsd, + UD_Imulss, + UD_Imwait, + UD_Ineg, + UD_Inop, + UD_Inot, + UD_Ior, + UD_Iorpd, + UD_Iorps, + UD_Iout, + UD_Ioutsb, + UD_Ioutsd, + UD_Ioutsw, + UD_Ipabsb, + UD_Ipabsd, + UD_Ipabsw, + UD_Ipackssdw, + UD_Ipacksswb, + UD_Ipackusdw, + UD_Ipackuswb, + UD_Ipaddb, + UD_Ipaddd, + UD_Ipaddq, + UD_Ipaddsb, + UD_Ipaddsw, + UD_Ipaddusb, + UD_Ipaddusw, + UD_Ipaddw, + UD_Ipalignr, + UD_Ipand, + UD_Ipandn, + UD_Ipavgb, + UD_Ipavgusb, + UD_Ipavgw, + UD_Ipblendvb, + UD_Ipblendw, + UD_Ipclmulqdq, + UD_Ipcmpeqb, + UD_Ipcmpeqd, + UD_Ipcmpeqq, + UD_Ipcmpeqw, + UD_Ipcmpestri, + UD_Ipcmpestrm, + UD_Ipcmpgtb, + UD_Ipcmpgtd, + UD_Ipcmpgtq, + UD_Ipcmpgtw, + UD_Ipcmpistri, + UD_Ipcmpistrm, + UD_Ipextrb, + UD_Ipextrd, + UD_Ipextrq, + UD_Ipextrw, + UD_Ipf2id, + UD_Ipf2iw, + UD_Ipfacc, + UD_Ipfadd, + UD_Ipfcmpeq, + UD_Ipfcmpge, + UD_Ipfcmpgt, + UD_Ipfmax, + UD_Ipfmin, + UD_Ipfmul, + UD_Ipfnacc, + UD_Ipfpnacc, + UD_Ipfrcp, + UD_Ipfrcpit1, + UD_Ipfrcpit2, + UD_Ipfrsqit1, + UD_Ipfrsqrt, + UD_Ipfsub, + UD_Ipfsubr, + UD_Iphaddd, + UD_Iphaddsw, + UD_Iphaddw, + UD_Iphminposuw, + UD_Iphsubd, + UD_Iphsubsw, + UD_Iphsubw, + UD_Ipi2fd, + UD_Ipi2fw, + UD_Ipinsrb, + UD_Ipinsrd, + UD_Ipinsrq, + UD_Ipinsrw, + UD_Ipmaddubsw, + UD_Ipmaddwd, + UD_Ipmaxsb, + UD_Ipmaxsd, + UD_Ipmaxsw, + UD_Ipmaxub, + UD_Ipmaxud, + UD_Ipmaxuw, + UD_Ipminsb, + UD_Ipminsd, + UD_Ipminsw, + UD_Ipminub, + UD_Ipminud, + UD_Ipminuw, + UD_Ipmovmskb, + UD_Ipmovsxbd, + UD_Ipmovsxbq, + UD_Ipmovsxbw, + UD_Ipmovsxdq, + UD_Ipmovsxwd, + UD_Ipmovsxwq, + UD_Ipmovzxbd, + UD_Ipmovzxbq, + UD_Ipmovzxbw, + UD_Ipmovzxdq, + UD_Ipmovzxwd, + UD_Ipmovzxwq, + UD_Ipmuldq, + UD_Ipmulhrsw, + UD_Ipmulhrw, + UD_Ipmulhuw, + UD_Ipmulhw, + UD_Ipmulld, + UD_Ipmullw, + UD_Ipmuludq, + UD_Ipop, + UD_Ipopa, + UD_Ipopad, + UD_Ipopcnt, + UD_Ipopfd, + UD_Ipopfq, + UD_Ipopfw, + UD_Ipor, + UD_Iprefetch, + UD_Iprefetchnta, + UD_Iprefetcht0, + UD_Iprefetcht1, + UD_Iprefetcht2, + UD_Ipsadbw, + UD_Ipshufb, + UD_Ipshufd, + UD_Ipshufhw, + UD_Ipshuflw, + UD_Ipshufw, + UD_Ipsignb, + UD_Ipsignd, + UD_Ipsignw, + UD_Ipslld, + UD_Ipslldq, + UD_Ipsllq, + UD_Ipsllw, + UD_Ipsrad, + UD_Ipsraw, + UD_Ipsrld, + UD_Ipsrldq, + UD_Ipsrlq, + UD_Ipsrlw, + UD_Ipsubb, + UD_Ipsubd, + UD_Ipsubq, + UD_Ipsubsb, + UD_Ipsubsw, + UD_Ipsubusb, + UD_Ipsubusw, + UD_Ipsubw, + UD_Ipswapd, + UD_Iptest, + UD_Ipunpckhbw, + UD_Ipunpckhdq, + UD_Ipunpckhqdq, + UD_Ipunpckhwd, + UD_Ipunpcklbw, + UD_Ipunpckldq, + UD_Ipunpcklqdq, + UD_Ipunpcklwd, + UD_Ipush, + UD_Ipusha, + UD_Ipushad, + UD_Ipushfd, + UD_Ipushfq, + UD_Ipushfw, + UD_Ipxor, + UD_Ircl, + UD_Ircpps, + UD_Ircpss, + UD_Ircr, + UD_Irdmsr, + UD_Irdpmc, + UD_Irdrand, + UD_Irdtsc, + UD_Irdtscp, + UD_Irep, + UD_Irepne, + UD_Iret, + UD_Iretf, + UD_Irol, + UD_Iror, + UD_Iroundpd, + UD_Iroundps, + UD_Iroundsd, + UD_Iroundss, + UD_Irsm, + UD_Irsqrtps, + UD_Irsqrtss, + UD_Isahf, + UD_Isalc, + UD_Isar, + UD_Isbb, + UD_Iscasb, + UD_Iscasd, + UD_Iscasq, + UD_Iscasw, + UD_Iseta, + UD_Isetae, + UD_Isetb, + UD_Isetbe, + UD_Isetg, + UD_Isetge, + UD_Isetl, + UD_Isetle, + UD_Isetno, + UD_Isetnp, + UD_Isetns, + UD_Isetnz, + UD_Iseto, + UD_Isetp, + UD_Isets, + UD_Isetz, + UD_Isfence, + UD_Isgdt, + UD_Ishl, + UD_Ishld, + UD_Ishr, + UD_Ishrd, + UD_Ishufpd, + UD_Ishufps, + UD_Isidt, + UD_Iskinit, + UD_Isldt, + UD_Ismsw, + UD_Isqrtpd, + UD_Isqrtps, + UD_Isqrtsd, + UD_Isqrtss, + UD_Istc, + UD_Istd, + UD_Istgi, + UD_Isti, + UD_Istmxcsr, + UD_Istosb, + UD_Istosd, + UD_Istosq, + UD_Istosw, + UD_Istr, + UD_Isub, + UD_Isubpd, + UD_Isubps, + UD_Isubsd, + UD_Isubss, + UD_Iswapgs, + UD_Isyscall, + UD_Isysenter, + UD_Isysexit, + UD_Isysret, + UD_Itest, + UD_Iucomisd, + UD_Iucomiss, + UD_Iud2, + UD_Iunpckhpd, + UD_Iunpckhps, + UD_Iunpcklpd, + UD_Iunpcklps, + UD_Ivaddpd, + UD_Ivaddps, + UD_Ivaddsd, + UD_Ivaddss, + UD_Ivaddsubpd, + UD_Ivaddsubps, + UD_Ivaesdec, + UD_Ivaesdeclast, + UD_Ivaesenc, + UD_Ivaesenclast, + UD_Ivaesimc, + UD_Ivaeskeygenassist, + UD_Ivandnpd, + UD_Ivandnps, + UD_Ivandpd, + UD_Ivandps, + UD_Ivblendpd, + UD_Ivblendps, + UD_Ivblendvpd, + UD_Ivblendvps, + UD_Ivbroadcastsd, + UD_Ivbroadcastss, + UD_Ivcmppd, + UD_Ivcmpps, + UD_Ivcmpsd, + UD_Ivcmpss, + UD_Ivcomisd, + UD_Ivcomiss, + UD_Ivcvtdq2pd, + UD_Ivcvtdq2ps, + UD_Ivcvtpd2dq, + UD_Ivcvtpd2ps, + UD_Ivcvtps2dq, + UD_Ivcvtps2pd, + UD_Ivcvtsd2si, + UD_Ivcvtsd2ss, + UD_Ivcvtsi2sd, + UD_Ivcvtsi2ss, + UD_Ivcvtss2sd, + UD_Ivcvtss2si, + UD_Ivcvttpd2dq, + UD_Ivcvttps2dq, + UD_Ivcvttsd2si, + UD_Ivcvttss2si, + UD_Ivdivpd, + UD_Ivdivps, + UD_Ivdivsd, + UD_Ivdivss, + UD_Ivdppd, + UD_Ivdpps, + UD_Iverr, + UD_Iverw, + UD_Ivextractf128, + UD_Ivextractps, + UD_Ivhaddpd, + UD_Ivhaddps, + UD_Ivhsubpd, + UD_Ivhsubps, + UD_Ivinsertf128, + UD_Ivinsertps, + UD_Ivlddqu, + UD_Ivmaskmovdqu, + UD_Ivmaskmovpd, + UD_Ivmaskmovps, + UD_Ivmaxpd, + UD_Ivmaxps, + UD_Ivmaxsd, + UD_Ivmaxss, + UD_Ivmcall, + UD_Ivmclear, + UD_Ivminpd, + UD_Ivminps, + UD_Ivminsd, + UD_Ivminss, + UD_Ivmlaunch, + UD_Ivmload, + UD_Ivmmcall, + UD_Ivmovapd, + UD_Ivmovaps, + UD_Ivmovd, + UD_Ivmovddup, + UD_Ivmovdqa, + UD_Ivmovdqu, + UD_Ivmovhlps, + UD_Ivmovhpd, + UD_Ivmovhps, + UD_Ivmovlhps, + UD_Ivmovlpd, + UD_Ivmovlps, + UD_Ivmovmskpd, + UD_Ivmovmskps, + UD_Ivmovntdq, + UD_Ivmovntdqa, + UD_Ivmovntpd, + UD_Ivmovntps, + UD_Ivmovq, + UD_Ivmovsd, + UD_Ivmovshdup, + UD_Ivmovsldup, + UD_Ivmovss, + UD_Ivmovupd, + UD_Ivmovups, + UD_Ivmpsadbw, + UD_Ivmptrld, + UD_Ivmptrst, + UD_Ivmread, + UD_Ivmresume, + UD_Ivmrun, + UD_Ivmsave, + UD_Ivmulpd, + UD_Ivmulps, + UD_Ivmulsd, + UD_Ivmulss, + UD_Ivmwrite, + UD_Ivmxoff, + UD_Ivmxon, + UD_Ivorpd, + UD_Ivorps, + UD_Ivpabsb, + UD_Ivpabsd, + UD_Ivpabsw, + UD_Ivpackssdw, + UD_Ivpacksswb, + UD_Ivpackusdw, + UD_Ivpackuswb, + UD_Ivpaddb, + UD_Ivpaddd, + UD_Ivpaddq, + UD_Ivpaddsb, + UD_Ivpaddsw, + UD_Ivpaddusb, + UD_Ivpaddusw, + UD_Ivpaddw, + UD_Ivpalignr, + UD_Ivpand, + UD_Ivpandn, + UD_Ivpavgb, + UD_Ivpavgw, + UD_Ivpblendvb, + UD_Ivpblendw, + UD_Ivpclmulqdq, + UD_Ivpcmpeqb, + UD_Ivpcmpeqd, + UD_Ivpcmpeqq, + UD_Ivpcmpeqw, + UD_Ivpcmpestri, + UD_Ivpcmpestrm, + UD_Ivpcmpgtb, + UD_Ivpcmpgtd, + UD_Ivpcmpgtq, + UD_Ivpcmpgtw, + UD_Ivpcmpistri, + UD_Ivpcmpistrm, + UD_Ivperm2f128, + UD_Ivpermilpd, + UD_Ivpermilps, + UD_Ivpextrb, + UD_Ivpextrd, + UD_Ivpextrq, + UD_Ivpextrw, + UD_Ivphaddd, + UD_Ivphaddsw, + UD_Ivphaddw, + UD_Ivphminposuw, + UD_Ivphsubd, + UD_Ivphsubsw, + UD_Ivphsubw, + UD_Ivpinsrb, + UD_Ivpinsrd, + UD_Ivpinsrq, + UD_Ivpinsrw, + UD_Ivpmaddubsw, + UD_Ivpmaddwd, + UD_Ivpmaxsb, + UD_Ivpmaxsd, + UD_Ivpmaxsw, + UD_Ivpmaxub, + UD_Ivpmaxud, + UD_Ivpmaxuw, + UD_Ivpminsb, + UD_Ivpminsd, + UD_Ivpminsw, + UD_Ivpminub, + UD_Ivpminud, + UD_Ivpminuw, + UD_Ivpmovmskb, + UD_Ivpmovsxbd, + UD_Ivpmovsxbq, + UD_Ivpmovsxbw, + UD_Ivpmovsxwd, + UD_Ivpmovsxwq, + UD_Ivpmovzxbd, + UD_Ivpmovzxbq, + UD_Ivpmovzxbw, + UD_Ivpmovzxdq, + UD_Ivpmovzxwd, + UD_Ivpmovzxwq, + UD_Ivpmuldq, + UD_Ivpmulhrsw, + UD_Ivpmulhuw, + UD_Ivpmulhw, + UD_Ivpmulld, + UD_Ivpmullw, + UD_Ivpor, + UD_Ivpsadbw, + UD_Ivpshufb, + UD_Ivpshufd, + UD_Ivpshufhw, + UD_Ivpshuflw, + UD_Ivpsignb, + UD_Ivpsignd, + UD_Ivpsignw, + UD_Ivpslld, + UD_Ivpslldq, + UD_Ivpsllq, + UD_Ivpsllw, + UD_Ivpsrad, + UD_Ivpsraw, + UD_Ivpsrld, + UD_Ivpsrldq, + UD_Ivpsrlq, + UD_Ivpsrlw, + UD_Ivpsubb, + UD_Ivpsubd, + UD_Ivpsubq, + UD_Ivpsubsb, + UD_Ivpsubsw, + UD_Ivpsubusb, + UD_Ivpsubusw, + UD_Ivpsubw, + UD_Ivptest, + UD_Ivpunpckhbw, + UD_Ivpunpckhdq, + UD_Ivpunpckhqdq, + UD_Ivpunpckhwd, + UD_Ivpunpcklbw, + UD_Ivpunpckldq, + UD_Ivpunpcklqdq, + UD_Ivpunpcklwd, + UD_Ivpxor, + UD_Ivrcpps, + UD_Ivrcpss, + UD_Ivroundpd, + UD_Ivroundps, + UD_Ivroundsd, + UD_Ivroundss, + UD_Ivrsqrtps, + UD_Ivrsqrtss, + UD_Ivshufpd, + UD_Ivshufps, + UD_Ivsqrtpd, + UD_Ivsqrtps, + UD_Ivsqrtsd, + UD_Ivsqrtss, + UD_Ivstmxcsr, + UD_Ivsubpd, + UD_Ivsubps, + UD_Ivsubsd, + UD_Ivsubss, + UD_Ivtestpd, + UD_Ivtestps, + UD_Ivucomisd, + UD_Ivucomiss, + UD_Ivunpckhpd, + UD_Ivunpckhps, + UD_Ivunpcklpd, + UD_Ivunpcklps, + UD_Ivxorpd, + UD_Ivxorps, + UD_Ivzeroall, + UD_Ivzeroupper, + UD_Iwait, + UD_Iwbinvd, + UD_Iwrmsr, + UD_Ixadd, + UD_Ixchg, + UD_Ixcryptcbc, + UD_Ixcryptcfb, + UD_Ixcryptctr, + UD_Ixcryptecb, + UD_Ixcryptofb, + UD_Ixgetbv, + UD_Ixlatb, + UD_Ixor, + UD_Ixorpd, + UD_Ixorps, + UD_Ixrstor, + UD_Ixsave, + UD_Ixsetbv, + UD_Ixsha1, + UD_Ixsha256, + UD_Ixstore, + UD_Iinvalid, + UD_I3dnow, + UD_Inone, + UD_Idb, + UD_Ipause, + UD_MAX_MNEMONIC_CODE +} UD_ATTR_PACKED; + +extern const char * ud_mnemonics_str[]; + +#endif /* UD_ITAB_H */ diff --git a/src/third_party/udis86/libudis86/syn-att.c b/src/third_party/udis86/libudis86/syn-att.c new file mode 100644 index 00000000..7be01423 --- /dev/null +++ b/src/third_party/udis86/libudis86/syn-att.c @@ -0,0 +1,228 @@ +/* udis86 - libudis86/syn-att.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "types.h" +#include "extern.h" +#include "decode.h" +#include "itab.h" +#include "syn.h" +#include "udint.h" + +/* ----------------------------------------------------------------------------- + * opr_cast_att() - Prints an operand cast. + * ----------------------------------------------------------------------------- + */ +static void +opr_cast_att(struct ud* u, struct ud_operand* op) +{ + switch(op->size) { + case 16 : case 32 : + ud_asmprintf(u, "*"); break; + default: break; + } +} + +/* ----------------------------------------------------------------------------- + * gen_operand_att() - Generates assembly output for each operand. + * ----------------------------------------------------------------------------- + */ +static void +gen_operand_att(struct ud* u, struct ud_operand* op) +{ + switch(op->type) { + case UD_OP_CONST: + ud_asmprintf(u, "$0x%x", op->lval.udword); + break; + + case UD_OP_REG: + ud_asmprintf(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]); + break; + + case UD_OP_MEM: + if (u->br_far) { + opr_cast_att(u, op); + } + if (u->pfx_seg) { + ud_asmprintf(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + } + if (op->offset != 0) { + ud_syn_print_mem_disp(u, op, 0); + } + if (op->base) { + ud_asmprintf(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]); + } + if (op->index) { + if (op->base) { + ud_asmprintf(u, ","); + } else { + ud_asmprintf(u, "("); + } + ud_asmprintf(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]); + } + if (op->scale) { + ud_asmprintf(u, ",%d", op->scale); + } + if (op->base || op->index) { + ud_asmprintf(u, ")"); + } + break; + + case UD_OP_IMM: + ud_asmprintf(u, "$"); + ud_syn_print_imm(u, op); + break; + + case UD_OP_JIMM: + ud_syn_print_addr(u, ud_syn_rel_target(u, op)); + break; + + case UD_OP_PTR: + switch (op->size) { + case 32: + ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg, + op->lval.ptr.off & 0xFFFF); + break; + case 48: + ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg, + op->lval.ptr.off); + break; + } + break; + + default: return; + } +} + +/* ============================================================================= + * translates to AT&T syntax + * ============================================================================= + */ +extern void +ud_translate_att(struct ud *u) +{ + int size = 0; + int star = 0; + + /* check if P_OSO prefix is used */ + if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { + switch (u->dis_mode) { + case 16: + ud_asmprintf(u, "o32 "); + break; + case 32: + case 64: + ud_asmprintf(u, "o16 "); + break; + } + } + + /* check if P_ASO prefix was used */ + if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { + switch (u->dis_mode) { + case 16: + ud_asmprintf(u, "a32 "); + break; + case 32: + ud_asmprintf(u, "a16 "); + break; + case 64: + ud_asmprintf(u, "a32 "); + break; + } + } + + if (u->pfx_lock) + ud_asmprintf(u, "lock "); + if (u->pfx_rep) { + ud_asmprintf(u, "rep "); + } else if (u->pfx_rep) { + ud_asmprintf(u, "repe "); + } else if (u->pfx_repne) { + ud_asmprintf(u, "repne "); + } + + /* special instructions */ + switch (u->mnemonic) { + case UD_Iretf: + ud_asmprintf(u, "lret "); + break; + case UD_Idb: + ud_asmprintf(u, ".byte 0x%x", u->operand[0].lval.ubyte); + return; + case UD_Ijmp: + case UD_Icall: + if (u->br_far) ud_asmprintf(u, "l"); + if (u->operand[0].type == UD_OP_REG) { + star = 1; + } + ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + break; + case UD_Ibound: + case UD_Ienter: + if (u->operand[0].type != UD_NONE) + gen_operand_att(u, &u->operand[0]); + if (u->operand[1].type != UD_NONE) { + ud_asmprintf(u, ","); + gen_operand_att(u, &u->operand[1]); + } + return; + default: + ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + } + + if (size == 8) { + ud_asmprintf(u, "b"); + } else if (size == 16) { + ud_asmprintf(u, "w"); + } else if (size == 64) { + ud_asmprintf(u, "q"); + } + + if (star) { + ud_asmprintf(u, " *"); + } else { + ud_asmprintf(u, " "); + } + + if (u->operand[3].type != UD_NONE) { + gen_operand_att(u, &u->operand[3]); + ud_asmprintf(u, ", "); + } + if (u->operand[2].type != UD_NONE) { + gen_operand_att(u, &u->operand[2]); + ud_asmprintf(u, ", "); + } + if (u->operand[1].type != UD_NONE) { + gen_operand_att(u, &u->operand[1]); + ud_asmprintf(u, ", "); + } + if (u->operand[0].type != UD_NONE) { + gen_operand_att(u, &u->operand[0]); + } +} + +/* +vim: set ts=2 sw=2 expandtab +*/ diff --git a/src/third_party/udis86/libudis86/syn-intel.c b/src/third_party/udis86/libudis86/syn-intel.c new file mode 100644 index 00000000..471293c6 --- /dev/null +++ b/src/third_party/udis86/libudis86/syn-intel.c @@ -0,0 +1,225 @@ +/* udis86 - libudis86/syn-intel.c + * + * Copyright (c) 2002-2013 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "types.h" +#include "extern.h" +#include "decode.h" +#include "itab.h" +#include "syn.h" +#include "udint.h" + +/* ----------------------------------------------------------------------------- + * opr_cast_intel() - Prints an operand cast. + * ----------------------------------------------------------------------------- + */ +static void +opr_cast_intel(struct ud* u, struct ud_operand* op) +{ + if (u->br_far) { + ud_asmprintf(u, "far "); + } + switch(op->size) { + case 8: ud_asmprintf(u, "byte " ); break; + case 16: ud_asmprintf(u, "word " ); break; + case 32: ud_asmprintf(u, "dword "); break; + case 64: ud_asmprintf(u, "qword "); break; + case 80: ud_asmprintf(u, "tword "); break; + case 128: ud_asmprintf(u, "oword "); break; + case 256: ud_asmprintf(u, "yword "); break; + default: break; + } +} + +/* ----------------------------------------------------------------------------- + * gen_operand_intel() - Generates assembly output for each operand. + * ----------------------------------------------------------------------------- + */ +static void gen_operand_intel(struct ud* u, struct ud_operand* op, int syn_cast) +{ + switch(op->type) { + case UD_OP_REG: + ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]); + break; + + case UD_OP_MEM: + { + opr_cast_intel(u, op); + ud_asmprintf(u, "ptr "); + } + ud_asmprintf(u, "["); + if (u->pfx_seg) { + ud_asmprintf(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + } + if (op->base) { + ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]); + } + if (op->index) { + ud_asmprintf(u, "%s%s", op->base != UD_NONE? "+" : "", + ud_reg_tab[op->index - UD_R_AL]); + if (op->scale) { + ud_asmprintf(u, "*%d", op->scale); + } + } + if (op->offset != 0) { + ud_syn_print_mem_disp(u, op, (op->base != UD_NONE || + op->index != UD_NONE) ? 1 : 0); + } + ud_asmprintf(u, "]"); + break; + + case UD_OP_IMM: + ud_syn_print_imm(u, op); + break; + + + case UD_OP_JIMM: + ud_syn_print_addr(u, ud_syn_rel_target(u, op)); + break; + + case UD_OP_PTR: + switch (op->size) { + case 32: + ud_asmprintf(u, "word 0x%x:0x%x", op->lval.ptr.seg, + op->lval.ptr.off & 0xFFFF); + break; + case 48: + ud_asmprintf(u, "dword 0x%x:0x%x", op->lval.ptr.seg, + op->lval.ptr.off); + break; + } + break; + + case UD_OP_CONST: + opr_cast_intel(u, op); + ud_asmprintf(u, "%d", op->lval.udword); + break; + + default: return; + } +} + +/* ============================================================================= + * translates to intel syntax + * ============================================================================= + */ +extern void +ud_translate_intel(struct ud* u) +{ + /* check if P_OSO prefix is used */ + if (!P_OSO(u->itab_entry->prefix) && u->pfx_opr) { + switch (u->dis_mode) { + case 16: ud_asmprintf(u, "o32 "); break; + case 32: + case 64: ud_asmprintf(u, "o16 "); break; + } + } + + /* check if P_ASO prefix was used */ + if (!P_ASO(u->itab_entry->prefix) && u->pfx_adr) { + switch (u->dis_mode) { + case 16: ud_asmprintf(u, "a32 "); break; + case 32: ud_asmprintf(u, "a16 "); break; + case 64: ud_asmprintf(u, "a32 "); break; + } + } + + if (u->pfx_seg && + u->operand[0].type != UD_OP_MEM && + u->operand[1].type != UD_OP_MEM ) { + ud_asmprintf(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]); + } + + if (u->pfx_lock) { + ud_asmprintf(u, "lock "); + } + if (u->pfx_rep) { + ud_asmprintf(u, "rep "); + } else if (u->pfx_repe) { + ud_asmprintf(u, "repe "); + } else if (u->pfx_repne) { + ud_asmprintf(u, "repne "); + } + + /* print the instruction mnemonic */ + ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + + if (u->operand[0].type != UD_NONE) { + int cast = 0; + ud_asmprintf(u, " "); + if (u->operand[0].type == UD_OP_MEM) { + if (u->operand[1].type == UD_OP_IMM || + u->operand[1].type == UD_OP_CONST || + u->operand[1].type == UD_NONE || + (u->operand[0].size != u->operand[1].size)) { + cast = 1; + } else if (u->operand[1].type == UD_OP_REG && + u->operand[1].base == UD_R_CL) { + switch (u->mnemonic) { + case UD_Ircl: + case UD_Irol: + case UD_Iror: + case UD_Ircr: + case UD_Ishl: + case UD_Ishr: + case UD_Isar: + cast = 1; + break; + default: break; + } + } + } + gen_operand_intel(u, &u->operand[0], cast); + } + + if (u->operand[1].type != UD_NONE) { + int cast = 0; + ud_asmprintf(u, ", "); + if (u->operand[1].type == UD_OP_MEM && + u->operand[0].size != u->operand[1].size && + !ud_opr_is_sreg(&u->operand[0])) { + cast = 1; + } + gen_operand_intel(u, &u->operand[1], cast); + } + + if (u->operand[2].type != UD_NONE) { + int cast = 0; + ud_asmprintf(u, ", "); + if (u->operand[2].type == UD_OP_MEM && + u->operand[2].size != u->operand[1].size) { + cast = 1; + } + gen_operand_intel(u, &u->operand[2], cast); + } + + if (u->operand[3].type != UD_NONE) { + ud_asmprintf(u, ", "); + gen_operand_intel(u, &u->operand[3], 0); + } +} + +/* +vim: set ts=2 sw=2 expandtab +*/ diff --git a/src/third_party/udis86/libudis86/syn.c b/src/third_party/udis86/libudis86/syn.c new file mode 100644 index 00000000..09e97653 --- /dev/null +++ b/src/third_party/udis86/libudis86/syn.c @@ -0,0 +1,212 @@ +/* udis86 - libudis86/syn.c + * + * Copyright (c) 2002-2013 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "types.h" +#include "decode.h" +#include "syn.h" +#include "udint.h" + +/* + * Register Table - Order Matters (types.h)! + * + */ +const char* ud_reg_tab[] = +{ + "al", "cl", "dl", "bl", + "ah", "ch", "dh", "bh", + "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", + "r12b", "r13b", "r14b", "r15b", + + "ax", "cx", "dx", "bx", + "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", + "r12w", "r13w", "r14w", "r15w", + + "eax", "ecx", "edx", "ebx", + "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", + "r12d", "r13d", "r14d", "r15d", + + "rax", "rcx", "rdx", "rbx", + "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", + + "es", "cs", "ss", "ds", + "fs", "gs", + + "cr0", "cr1", "cr2", "cr3", + "cr4", "cr5", "cr6", "cr7", + "cr8", "cr9", "cr10", "cr11", + "cr12", "cr13", "cr14", "cr15", + + "dr0", "dr1", "dr2", "dr3", + "dr4", "dr5", "dr6", "dr7", + "dr8", "dr9", "dr10", "dr11", + "dr12", "dr13", "dr14", "dr15", + + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15", + + "ymm0", "ymm1", "ymm2", "ymm3", + "ymm4", "ymm5", "ymm6", "ymm7", + "ymm8", "ymm9", "ymm10", "ymm11", + "ymm12", "ymm13", "ymm14", "ymm15", + + "rip" +}; + + +uint64_t +ud_syn_rel_target(struct ud *u, struct ud_operand *opr) +{ + const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->opr_mode); + switch (opr->size) { + case 8 : return (u->pc + opr->lval.sbyte) & trunc_mask; + case 16: return (u->pc + opr->lval.sword) & trunc_mask; + case 32: return (u->pc + opr->lval.sdword) & trunc_mask; + default: UD_ASSERT(!"invalid relative offset size."); + return 0ull; + } +} + + +/* + * asmprintf + * Printf style function for printing translated assembly + * output. Returns the number of characters written and + * moves the buffer pointer forward. On an overflow, + * returns a negative number and truncates the output. + */ +int +ud_asmprintf(struct ud *u, const char *fmt, ...) +{ + int ret; + int avail; + va_list ap; + va_start(ap, fmt); + avail = u->asm_buf_size - u->asm_buf_fill - 1 /* nullchar */; + ret = vsnprintf((char*) u->asm_buf + u->asm_buf_fill, avail, fmt, ap); + if (ret < 0 || ret > avail) { + u->asm_buf_fill = u->asm_buf_size - 1; + } else { + u->asm_buf_fill += ret; + } + va_end(ap); + return ret; +} + + +void +ud_syn_print_addr(struct ud *u, uint64_t addr) +{ + const char *name = 0; + if (u->sym_resolver) { + int64_t offset = 0; + name = u->sym_resolver(u, addr, &offset); + if (name) { + if (offset) { + ud_asmprintf(u, "%s%+" FMT64 "d", name, offset); + } else { + ud_asmprintf(u, "%s", name); + } + return; + } + } + ud_asmprintf(u, "0x%" FMT64 "x", addr); +} + + +void +ud_syn_print_imm(struct ud* u, const struct ud_operand *op) +{ + uint64_t v; + if (op->_oprcode == OP_sI && op->size != u->opr_mode) { + if (op->size == 8) { + v = (int64_t)op->lval.sbyte; + } else { + UD_ASSERT(op->size == 32); + v = (int64_t)op->lval.sdword; + } + if (u->opr_mode < 64) { + v = v & ((1ull << u->opr_mode) - 1ull); + } + } else { + switch (op->size) { + case 8 : v = op->lval.ubyte; break; + case 16: v = op->lval.uword; break; + case 32: v = op->lval.udword; break; + case 64: v = op->lval.uqword; break; + default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */ + } + } + ud_asmprintf(u, "0x%" FMT64 "x", v); +} + + +void +ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *op, int sign) +{ + UD_ASSERT(op->offset != 0); + if (op->base == UD_NONE && op->index == UD_NONE) { + uint64_t v; + UD_ASSERT(op->scale == UD_NONE && op->offset != 8); + /* unsigned mem-offset */ + switch (op->offset) { + case 16: v = op->lval.uword; break; + case 32: v = op->lval.udword; break; + case 64: v = op->lval.uqword; break; + default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */ + } + ud_asmprintf(u, "0x%" FMT64 "x", v); + } else { + int64_t v; + UD_ASSERT(op->offset != 64); + switch (op->offset) { + case 8 : v = op->lval.sbyte; break; + case 16: v = op->lval.sword; break; + case 32: v = op->lval.sdword; break; + default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */ + } + if (v < 0) { + ud_asmprintf(u, "-0x%" FMT64 "x", -v); + } else if (v > 0) { + ud_asmprintf(u, "%s0x%" FMT64 "x", sign? "+" : "", v); + } + } +} + +/* +vim: set ts=2 sw=2 expandtab +*/ diff --git a/src/third_party/udis86/libudis86/syn.h b/src/third_party/udis86/libudis86/syn.h new file mode 100644 index 00000000..bef13330 --- /dev/null +++ b/src/third_party/udis86/libudis86/syn.h @@ -0,0 +1,53 @@ +/* udis86 - libudis86/syn.h + * + * Copyright (c) 2002-2009 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef UD_SYN_H +#define UD_SYN_H + +#include "types.h" +#ifndef __UD_STANDALONE__ +# include +#endif /* __UD_STANDALONE__ */ + +extern const char* ud_reg_tab[]; + +uint64_t ud_syn_rel_target(struct ud*, struct ud_operand*); + +#ifdef __GNUC__ +int ud_asmprintf(struct ud *u, const char *fmt, ...) + __attribute__ ((format (gnu_printf, 2, 3))); +#else +int ud_asmprintf(struct ud *u, const char *fmt, ...); +#endif + +void ud_syn_print_addr(struct ud *u, uint64_t addr); +void ud_syn_print_imm(struct ud* u, const struct ud_operand *op); +void ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *, int sign); + +#endif /* UD_SYN_H */ + +/* +vim: set ts=2 sw=2 expandtab +*/ diff --git a/src/third_party/udis86/libudis86/types.h b/src/third_party/udis86/libudis86/types.h new file mode 100644 index 00000000..d79dae93 --- /dev/null +++ b/src/third_party/udis86/libudis86/types.h @@ -0,0 +1,259 @@ +/* udis86 - libudis86/types.h + * + * Copyright (c) 2002-2013 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef UD_TYPES_H +#define UD_TYPES_H + +#ifdef __KERNEL__ + /* + * -D__KERNEL__ is automatically passed on the command line when + * building something as part of the Linux kernel. Assume standalone + * mode. + */ +# include +# include +# ifndef __UD_STANDALONE__ +# define __UD_STANDALONE__ 1 +# endif +#endif /* __KERNEL__ */ + +#if !defined(__UD_STANDALONE__) +# include +# include +#endif + +/* gcc specific extensions */ +#ifdef __GNUC__ +# define UD_ATTR_PACKED __attribute__((packed)) +#else +# define UD_ATTR_PACKED +#endif /* UD_ATTR_PACKED */ + + +/* ----------------------------------------------------------------------------- + * All possible "types" of objects in udis86. Order is Important! + * ----------------------------------------------------------------------------- + */ +enum ud_type +{ + UD_NONE, + + /* 8 bit GPRs */ + UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL, + UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH, + UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL, + UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B, + UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B, + + /* 16 bit GPRs */ + UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX, + UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI, + UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W, + UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W, + + /* 32 bit GPRs */ + UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX, + UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI, + UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D, + UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D, + + /* 64 bit GPRs */ + UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX, + UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI, + UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11, + UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15, + + /* segment registers */ + UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS, + UD_R_FS, UD_R_GS, + + /* control registers*/ + UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3, + UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7, + UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11, + UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15, + + /* debug registers */ + UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3, + UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7, + UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11, + UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15, + + /* mmx registers */ + UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3, + UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7, + + /* x87 registers */ + UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3, + UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7, + + /* extended multimedia registers */ + UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3, + UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7, + UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11, + UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15, + + /* 256B multimedia registers */ + UD_R_YMM0, UD_R_YMM1, UD_R_YMM2, UD_R_YMM3, + UD_R_YMM4, UD_R_YMM5, UD_R_YMM6, UD_R_YMM7, + UD_R_YMM8, UD_R_YMM9, UD_R_YMM10, UD_R_YMM11, + UD_R_YMM12, UD_R_YMM13, UD_R_YMM14, UD_R_YMM15, + + UD_R_RIP, + + /* Operand Types */ + UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM, + UD_OP_JIMM, UD_OP_CONST +}; + +#include "itab.h" + +union ud_lval { + int8_t sbyte; + uint8_t ubyte; + int16_t sword; + uint16_t uword; + int32_t sdword; + uint32_t udword; + int64_t sqword; + uint64_t uqword; + struct { + uint16_t seg; + uint32_t off; + } ptr; +}; + +/* ----------------------------------------------------------------------------- + * struct ud_operand - Disassembled instruction Operand. + * ----------------------------------------------------------------------------- + */ +struct ud_operand { + enum ud_type type; + uint16_t size; + enum ud_type base; + enum ud_type index; + uint8_t scale; + uint8_t offset; + union ud_lval lval; + /* + * internal use only + */ + uint64_t _legacy; /* this will be removed in 1.8 */ + uint8_t _oprcode; +}; + +/* ----------------------------------------------------------------------------- + * struct ud - The udis86 object. + * ----------------------------------------------------------------------------- + */ +struct ud +{ + /* + * input buffering + */ + int (*inp_hook) (struct ud*); +#ifndef __UD_STANDALONE__ + FILE* inp_file; +#endif + const uint8_t* inp_buf; + size_t inp_buf_size; + size_t inp_buf_index; + uint8_t inp_curr; + size_t inp_ctr; + uint8_t inp_sess[64]; + int inp_end; + int inp_peek; + + void (*translator)(struct ud*); + uint64_t insn_offset; + char insn_hexcode[64]; + + /* + * Assembly output buffer + */ + char *asm_buf; + size_t asm_buf_size; + size_t asm_buf_fill; + char asm_buf_int[128]; + + /* + * Symbol resolver for use in the translation phase. + */ + const char* (*sym_resolver)(struct ud*, uint64_t addr, int64_t *offset); + + uint8_t dis_mode; + uint64_t pc; + uint8_t vendor; + enum ud_mnemonic_code mnemonic; + struct ud_operand operand[4]; + uint8_t error; + uint8_t _rex; + uint8_t pfx_rex; + uint8_t pfx_seg; + uint8_t pfx_opr; + uint8_t pfx_adr; + uint8_t pfx_lock; + uint8_t pfx_str; + uint8_t pfx_rep; + uint8_t pfx_repe; + uint8_t pfx_repne; + uint8_t opr_mode; + uint8_t adr_mode; + uint8_t br_far; + uint8_t br_near; + uint8_t have_modrm; + uint8_t modrm; + uint8_t vex_op; + uint8_t vex_b1; + uint8_t vex_b2; + uint8_t primary_opcode; + void * user_opaque_data; + struct ud_itab_entry * itab_entry; + struct ud_lookup_table_list_entry *le; +}; + +/* ----------------------------------------------------------------------------- + * Type-definitions + * ----------------------------------------------------------------------------- + */ +typedef enum ud_type ud_type_t; +typedef enum ud_mnemonic_code ud_mnemonic_code_t; + +typedef struct ud ud_t; +typedef struct ud_operand ud_operand_t; + +#define UD_SYN_INTEL ud_translate_intel +#define UD_SYN_ATT ud_translate_att +#define UD_EOI (-1) +#define UD_INP_CACHE_SZ 32 +#define UD_VENDOR_AMD 0 +#define UD_VENDOR_INTEL 1 +#define UD_VENDOR_ANY 2 + +#endif + +/* +vim: set ts=2 sw=2 expandtab +*/ diff --git a/src/third_party/udis86/libudis86/udint.h b/src/third_party/udis86/libudis86/udint.h new file mode 100644 index 00000000..2e3e612b --- /dev/null +++ b/src/third_party/udis86/libudis86/udint.h @@ -0,0 +1,97 @@ +/* udis86 - libudis86/udint.h -- definitions for internal use only + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _UDINT_H_ +#define _UDINT_H_ + +#if defined(HAVE_CONFIG_H) // || true // < Simplification for our (RAD Debugger) build process +# include +#endif /* HAVE_CONFIG_H */ + +#if defined(UD_DEBUG) && HAVE_ASSERT_H +# include +# define UD_ASSERT(_x) assert(_x) +#else +# define UD_ASSERT(_x) +#endif /* !HAVE_ASSERT_H */ + +#if defined(UD_DEBUG) +#define UDERR(u, msg) \ +do { \ +(u)->error = 1; \ +fprintf(stderr, "decode-error: %s:%d: %s", \ +__FILE__, __LINE__, (msg)); \ +} while (0) +#else +#define UDERR(u, m) \ +do { \ +(u)->error = 1; \ +} while (0) +#endif /* !LOGERR */ + +#define UD_RETURN_ON_ERROR(u) \ +do { \ +if ((u)->error != 0) { \ +return (u)->error; \ +} \ +} while (0) + +#define UD_RETURN_WITH_ERROR(u, m) \ +do { \ +UDERR(u, m); \ +return (u)->error; \ +} while (0) + +#ifndef __UD_STANDALONE__ +# define UD_NON_STANDALONE(x) x +#else +# define UD_NON_STANDALONE(x) +#endif + +/* printf formatting int64 specifier */ +#ifdef FMT64 +# undef FMT64 +#endif +#if defined(_MSC_VER) || defined(__BORLANDC__) +# define FMT64 "I64" +#else +# if defined(__APPLE__) || defined(_WIN32) // RJM added this +# define FMT64 "ll" +# elif defined(__amd64__) || defined(__x86_64__) +# define FMT64 "l" +# else +# define FMT64 "ll" +# endif /* !x64 */ +#endif + +/* define an inline macro */ +#if defined(_MSC_VER) || defined(__BORLANDC__) +# define UD_INLINE __inline /* MS Visual Studio requires __inline + instead of inline for C code */ +#else +# define UD_INLINE inline +#endif + +#endif /* _UDINT_H_ */ diff --git a/src/third_party/udis86/libudis86/udis86.c b/src/third_party/udis86/libudis86/udis86.c new file mode 100644 index 00000000..8a4956eb --- /dev/null +++ b/src/third_party/udis86/libudis86/udis86.c @@ -0,0 +1,458 @@ +/* udis86 - libudis86/udis86.c + * + * Copyright (c) 2002-2013 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "udint.h" +#include "extern.h" +#include "decode.h" + +#if !defined(__UD_STANDALONE__) +# if HAVE_STRING_H +# include +# endif +#endif /* !__UD_STANDALONE__ */ + +static void ud_inp_init(struct ud *u); + +/* ============================================================================= + * ud_init + * Initializes ud_t object. + * ============================================================================= + */ +extern void +ud_init(struct ud* u) +{ + memset((void*)u, 0, sizeof(struct ud)); + ud_set_mode(u, 16); + u->mnemonic = UD_Iinvalid; + ud_set_pc(u, 0); +#ifndef __UD_STANDALONE__ + ud_set_input_file(u, stdin); +#endif /* __UD_STANDALONE__ */ + + ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int)); +} + + +/* ============================================================================= + * ud_disassemble + * Disassembles one instruction and returns the number of + * bytes disassembled. A zero means end of disassembly. + * ============================================================================= + */ +extern unsigned int +ud_disassemble(struct ud* u) +{ + int len; + if (u->inp_end) { + return 0; + } + if ((len = ud_decode(u)) > 0) { + if (u->translator != 0) { + u->asm_buf[0] = '\0'; + u->translator(u); + } + } + return len; +} + + +/* ============================================================================= + * ud_set_mode() - Set Disassemly Mode. + * ============================================================================= + */ +extern void +ud_set_mode(struct ud* u, uint8_t m) +{ + switch(m) { + case 16: + case 32: + case 64: u->dis_mode = m ; return; + default: u->dis_mode = 16; return; + } +} + +/* ============================================================================= + * ud_set_vendor() - Set vendor. + * ============================================================================= + */ +extern void +ud_set_vendor(struct ud* u, unsigned v) +{ + switch(v) { + case UD_VENDOR_INTEL: + u->vendor = v; + break; + case UD_VENDOR_ANY: + u->vendor = v; + break; + default: + u->vendor = UD_VENDOR_AMD; + } +} + +/* ============================================================================= + * ud_set_pc() - Sets code origin. + * ============================================================================= + */ +extern void +ud_set_pc(struct ud* u, uint64_t o) +{ + u->pc = o; +} + +/* ============================================================================= + * ud_set_syntax() - Sets the output syntax. + * ============================================================================= + */ +extern void +ud_set_syntax(struct ud* u, void (*t)(struct ud*)) +{ + u->translator = t; +} + +/* ============================================================================= + * ud_insn() - returns the disassembled instruction + * ============================================================================= + */ +const char* +ud_insn_asm(const struct ud* u) +{ + return u->asm_buf; +} + +/* ============================================================================= + * ud_insn_offset() - Returns the offset. + * ============================================================================= + */ +uint64_t +ud_insn_off(const struct ud* u) +{ + return u->insn_offset; +} + + +/* ============================================================================= + * ud_insn_hex() - Returns hex form of disassembled instruction. + * ============================================================================= + */ +const char* +ud_insn_hex(struct ud* u) +{ + u->insn_hexcode[0] = 0; + if (!u->error) { + unsigned int i; + const unsigned char *src_ptr = ud_insn_ptr(u); + char* src_hex; + src_hex = (char*) u->insn_hexcode; + /* for each byte used to decode instruction */ + for (i = 0; i < ud_insn_len(u) && i < sizeof(u->insn_hexcode) / 2; + ++i, ++src_ptr) { + sprintf(src_hex, "%02x", *src_ptr & 0xFF); + src_hex += 2; + } + } + return u->insn_hexcode; +} + + +/* ============================================================================= + * ud_insn_ptr + * Returns a pointer to buffer containing the bytes that were + * disassembled. + * ============================================================================= + */ +extern const uint8_t* +ud_insn_ptr(const struct ud* u) +{ + return (u->inp_buf == 0) ? + u->inp_sess : u->inp_buf + (u->inp_buf_index - u->inp_ctr); +} + + +/* ============================================================================= + * ud_insn_len + * Returns the count of bytes disassembled. + * ============================================================================= + */ +extern unsigned int +ud_insn_len(const struct ud* u) +{ + return u->inp_ctr; +} + + +/* ============================================================================= + * ud_insn_get_opr + * Return the operand struct representing the nth operand of + * the currently disassembled instruction. Returns 0 if + * there's no such operand. + * ============================================================================= + */ +const struct ud_operand* +ud_insn_opr(const struct ud *u, unsigned int n) +{ + if (n > 3 || u->operand[n].type == UD_NONE) { + return 0; + } else { + return &u->operand[n]; + } +} + + +/* ============================================================================= + * ud_opr_is_sreg + * Returns non-zero if the given operand is of a segment register type. + * ============================================================================= + */ +int +ud_opr_is_sreg(const struct ud_operand *opr) +{ + return opr->type == UD_OP_REG && + opr->base >= UD_R_ES && + opr->base <= UD_R_GS; +} + + +/* ============================================================================= + * ud_opr_is_sreg + * Returns non-zero if the given operand is of a general purpose + * register type. + * ============================================================================= + */ +int +ud_opr_is_gpr(const struct ud_operand *opr) +{ + return opr->type == UD_OP_REG && + opr->base >= UD_R_AL && + opr->base <= UD_R_R15; +} + + +/* ============================================================================= + * ud_set_user_opaque_data + * ud_get_user_opaque_data + * Get/set user opaqute data pointer + * ============================================================================= + */ +void +ud_set_user_opaque_data(struct ud * u, void* opaque) +{ + u->user_opaque_data = opaque; +} + +void* +ud_get_user_opaque_data(const struct ud *u) +{ + return u->user_opaque_data; +} + + +/* ============================================================================= + * ud_set_asm_buffer + * Allow the user to set an assembler output buffer. If `buf` is 0, + * we switch back to the internal buffer. + * ============================================================================= + */ +void +ud_set_asm_buffer(struct ud *u, char *buf, size_t size) +{ + if (buf == 0) { + ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int)); + } else { + u->asm_buf = buf; + u->asm_buf_size = size; + } +} + + +/* ============================================================================= + * ud_set_sym_resolver + * Set symbol resolver for relative targets used in the translation + * phase. + * + * The resolver is a function that takes a uint64_t address and returns a + * symbolic name for the that address. The function also takes a second + * argument pointing to an integer that the client can optionally set to a + * non-zero value for offsetted targets. (symbol+offset) The function may + * also return 0, in which case the translator only prints the target + * address. + * + * The function pointer maybe 0 which resets symbol resolution. + * ============================================================================= + */ +void +ud_set_sym_resolver(struct ud *u, const char* (*resolver)(struct ud*, + uint64_t addr, + int64_t *offset)) +{ + u->sym_resolver = resolver; +} + + +/* ============================================================================= + * ud_insn_mnemonic + * Return the current instruction mnemonic. + * ============================================================================= + */ +enum ud_mnemonic_code +ud_insn_mnemonic(const struct ud *u) +{ + return u->mnemonic; +} + + +/* ============================================================================= + * ud_lookup_mnemonic + * Looks up mnemonic code in the mnemonic string table. + * Returns 0 if the mnemonic code is invalid. + * ============================================================================= + */ +const char* +ud_lookup_mnemonic(enum ud_mnemonic_code c) +{ + if (c < UD_MAX_MNEMONIC_CODE) { + return ud_mnemonics_str[c]; + } else { + return 0; + } +} + + +/* + * ud_inp_init + * Initializes the input system. + */ +static void +ud_inp_init(struct ud *u) +{ + u->inp_hook = 0; + u->inp_buf = 0; + u->inp_buf_size = 0; + u->inp_buf_index = 0; + u->inp_curr = 0; + u->inp_ctr = 0; + u->inp_end = 0; + u->inp_peek = UD_EOI; + UD_NON_STANDALONE(u->inp_file = 0); +} + + +/* ============================================================================= + * ud_inp_set_hook + * Sets input hook. + * ============================================================================= + */ +void +ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*)) +{ + ud_inp_init(u); + u->inp_hook = hook; +} + +/* ============================================================================= + * ud_inp_set_buffer + * Set buffer as input. + * ============================================================================= + */ +void +ud_set_input_buffer(register struct ud* u, const uint8_t* buf, size_t len) +{ + ud_inp_init(u); + u->inp_buf = buf; + u->inp_buf_size = len; + u->inp_buf_index = 0; +} + + +#ifndef __UD_STANDALONE__ +/* ============================================================================= + * ud_input_set_file + * Set FILE as input. + * ============================================================================= + */ +static int +inp_file_hook(struct ud* u) +{ + return fgetc(u->inp_file); +} + +void +ud_set_input_file(register struct ud* u, FILE* f) +{ + ud_inp_init(u); + u->inp_hook = inp_file_hook; + u->inp_file = f; +} +#endif /* __UD_STANDALONE__ */ + + +/* ============================================================================= + * ud_input_skip + * Skip n input bytes. + * ============================================================================ + */ +void +ud_input_skip(struct ud* u, size_t n) +{ + if (u->inp_end) { + return; + } + if (u->inp_buf == 0) { + while (n--) { + int c = u->inp_hook(u); + if (c == UD_EOI) { + goto eoi; + } + } + return; + } else { + if (n > u->inp_buf_size || + u->inp_buf_index > u->inp_buf_size - n) { + u->inp_buf_index = u->inp_buf_size; + goto eoi; + } + u->inp_buf_index += n; + return; + } + eoi: + u->inp_end = 1; + UDERR(u, "cannot skip, eoi received\b"); + return; +} + + +/* ============================================================================= + * ud_input_end + * Returns non-zero on end-of-input. + * ============================================================================= + */ +int +ud_input_end(const struct ud *u) +{ + return u->inp_end; +} + +/* vim:set ts=2 sw=2 expandtab */ diff --git a/src/third_party/udis86/udis86.h b/src/third_party/udis86/udis86.h new file mode 100644 index 00000000..bdd3857b --- /dev/null +++ b/src/third_party/udis86/udis86.h @@ -0,0 +1,33 @@ +/* udis86 - udis86.h + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef UDIS86_H +#define UDIS86_H + +#include "libudis86/types.h" +#include "libudis86/extern.h" +#include "libudis86/itab.h" + +#endif diff --git a/src/third_party/udis86/udis86_v56ff6c8.LICENSE b/src/third_party/udis86/udis86_v56ff6c8.LICENSE new file mode 100644 index 00000000..b173897d --- /dev/null +++ b/src/third_party/udis86/udis86_v56ff6c8.LICENSE @@ -0,0 +1,27 @@ +================================================================================ +Software Name: udis86 +Version: 56ff6c8 +URL:https://github.com/vmt/udis86/blob/master/LICENSE +=========================================================================================== +Copyright (c) 2002-2012, Vivek Thampi +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/src/third_party/udis86/udis86_v56ff6c8.tps b/src/third_party/udis86/udis86_v56ff6c8.tps new file mode 100644 index 00000000..c7f0d0dc --- /dev/null +++ b/src/third_party/udis86/udis86_v56ff6c8.tps @@ -0,0 +1,19 @@ + + + udis86 + + + + Rad Games Github + Disassembles x86 object code. + https://github.com/jpcy/xatlas/blob/master/LICENSE + + Licencees + P4 + Git + + /Engine/Source/ThirdParty/Licenses + + \ No newline at end of file diff --git a/src/txti/txti.c b/src/txti/txti.c new file mode 100644 index 00000000..81eb7381 --- /dev/null +++ b/src/txti/txti.c @@ -0,0 +1,1247 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +txti_init(void) +{ + Arena *arena = arena_alloc(); + txti_state = push_array(arena, TXTI_State, 1); + txti_state->arena = arena; + txti_state->entity_map.slots_count = 1024; + txti_state->entity_map.slots = push_array(txti_state->arena, TXTI_EntitySlot, txti_state->entity_map.slots_count); + txti_state->entity_map_stripes.count = 64; + txti_state->entity_map_stripes.v = push_array(txti_state->arena, TXTI_Stripe, txti_state->entity_map_stripes.count); + for(U64 idx = 0; idx < txti_state->entity_map_stripes.count; idx += 1) + { + txti_state->entity_map_stripes.v[idx].arena = arena_alloc(); + txti_state->entity_map_stripes.v[idx].cv = os_condition_variable_alloc(); + txti_state->entity_map_stripes.v[idx].rw_mutex = os_rw_mutex_alloc(); + } + txti_state->mut_thread_count = Min(4, os_logical_core_count()); + txti_state->mut_threads = push_array(txti_state->arena, TXTI_MutThread, txti_state->mut_thread_count); + for(U64 idx = 0; idx < txti_state->mut_thread_count; idx += 1) + { + TXTI_MutThread *thread = &txti_state->mut_threads[idx]; + thread->msg_arena = arena_alloc(); + thread->msg_mutex = os_mutex_alloc(); + thread->msg_cv = os_condition_variable_alloc(); + thread->thread = os_launch_thread(txti_mut_thread_entry_point, (void *)idx, 0); + } + txti_state->detector_thread = os_launch_thread(txti_detector_thread_entry_point, 0, 0); +} + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +txti_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal TXTI_LangKind +txti_lang_kind_from_extension(String8 extension) +{ + TXTI_LangKind kind = TXTI_LangKind_Null; + if(str8_match(extension, str8_lit("c"), 0) || + str8_match(extension, str8_lit("h"), 0)) + { + kind = TXTI_LangKind_C; + } + else if(str8_match(extension, str8_lit("cpp"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cxx"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cc"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("c++"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("C"), 0) || + str8_match(extension, str8_lit("hpp"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("hxx"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("hh"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("h++"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("H"), 0)) + { + kind = TXTI_LangKind_CPlusPlus; + } + return kind; +} + +//////////////////////////////// +//~ rjf: Token Type Functions + +internal void +txti_token_chunk_list_push(Arena *arena, TXTI_TokenChunkList *list, U64 cap, TXTI_Token *token) +{ + TXTI_TokenChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, TXTI_TokenChunkNode, 1); + SLLQueuePush(list->first, list->last, node); + node->cap = cap; + node->v = push_array_no_zero(arena, TXTI_Token, node->cap); + list->chunk_count += 1; + } + MemoryCopyStruct(&node->v[node->count], token); + node->count += 1; + list->token_count += 1; +} + +internal void +txti_token_list_push(Arena *arena, TXTI_TokenList *list, TXTI_Token *token) +{ + TXTI_TokenNode *node = push_array(arena, TXTI_TokenNode, 1); + MemoryCopyStruct(&node->v, token); + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal TXTI_TokenArray +txti_token_array_from_chunk_list(Arena *arena, TXTI_TokenChunkList *list) +{ + TXTI_TokenArray array = {0}; + array.count = list->token_count; + array.v = push_array_no_zero(arena, TXTI_Token, array.count); + U64 idx = 0; + for(TXTI_TokenChunkNode *n = list->first; n != 0; n = n->next) + { + MemoryCopy(array.v+idx, n->v, n->count*sizeof(TXTI_Token)); + idx += n->count; + } + return array; +} + +internal TXTI_TokenArray +txti_token_array_from_list(Arena *arena, TXTI_TokenList *list) +{ + TXTI_TokenArray array = {0}; + array.count = list->count; + array.v = push_array_no_zero(arena, TXTI_Token, array.count); + U64 idx = 0; + for(TXTI_TokenNode *n = list->first; n != 0; n = n->next) + { + MemoryCopyStruct(array.v+idx, &n->v); + idx += 1; + } + return array; +} + +//////////////////////////////// +//~ rjf: Lexing Functions + +internal TXTI_TokenArray +txti_token_array_from_string__cpp(Arena *arena, U64 *bytes_processed_counter, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: generate token list + TXTI_TokenChunkList tokens = {0}; + { + B32 comment_is_single_line = 0; + B32 string_is_char = 0; + TXTI_TokenKind active_token_kind = TXTI_TokenKind_Null; + U64 active_token_start_idx = 0; + B32 escaped = 0; + B32 next_escaped = 0; + U64 byte_process_start_idx = 0; + for(U64 idx = 0; idx <= string.size;) + { + U8 byte = (idx+0 < string.size) ? (string.str[idx+0]) : 0; + U8 next_byte = (idx+1 < string.size) ? (string.str[idx+1]) : 0; + + // rjf: update counter + if(bytes_processed_counter != 0 && ((idx-byte_process_start_idx) >= 1000 || idx == string.size)) + { + ins_atomic_u64_add_eval(bytes_processed_counter, (idx-byte_process_start_idx)); + byte_process_start_idx = idx; + } + + // rjf: escaping + if(escaped && (byte != '\r' && byte != '\n')) + { + next_escaped = 0; + } + else if(!escaped && byte == '\\') + { + next_escaped = 1; + } + + // rjf: take starter, determine active token kind + if(active_token_kind == TXTI_TokenKind_Null) + { + // rjf: use next bytes to start a new token + if(0){} + else if(char_is_space(byte)) { active_token_kind = TXTI_TokenKind_Whitespace; } + else if(byte == '_' || + byte == '$' || + char_is_alpha(byte)) { active_token_kind = TXTI_TokenKind_Identifier; } + else if(char_is_digit(byte, 10) || + (byte == '.' && + char_is_digit(next_byte, 10))) { active_token_kind = TXTI_TokenKind_Numeric; } + else if(byte == '"') { active_token_kind = TXTI_TokenKind_String; string_is_char = 0; } + else if(byte == '\'') { active_token_kind = TXTI_TokenKind_String; string_is_char = 1; } + else if(byte == '/' && next_byte == '/') { active_token_kind = TXTI_TokenKind_Comment; comment_is_single_line = 1; } + else if(byte == '/' && next_byte == '*') { active_token_kind = TXTI_TokenKind_Comment; comment_is_single_line = 0; } + else if(byte == '~' || byte == '!' || + byte == '%' || byte == '^' || + byte == '&' || byte == '*' || + byte == '(' || byte == ')' || + byte == '-' || byte == '=' || + byte == '+' || byte == '[' || + byte == ']' || byte == '{' || + byte == '}' || byte == ':' || + byte == ';' || byte == ',' || + byte == '.' || byte == '<' || + byte == '>' || byte == '/' || + byte == '?' || byte == '|') { active_token_kind = TXTI_TokenKind_Symbol; } + else if(byte == '#') { active_token_kind = TXTI_TokenKind_Meta; } + + // rjf: start new token + if(active_token_kind != TXTI_TokenKind_Null) + { + active_token_start_idx = idx; + } + + // rjf: invalid token kind -> emit error + else + { + TXTI_Token token = {TXTI_TokenKind_Error, r1u64(idx, idx+1)}; + txti_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + } + } + + // rjf: look for ender + U64 ender_pad = 0; + B32 ender_found = 0; + if(active_token_kind != TXTI_TokenKind_Null && idx>active_token_start_idx) + { + if(idx == string.size) + { + ender_pad = 0; + ender_found = 1; + } + else switch(active_token_kind) + { + default:break; + case TXTI_TokenKind_Whitespace: + { + ender_found = !char_is_space(byte); + }break; + case TXTI_TokenKind_Identifier: + { + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + }break; + case TXTI_TokenKind_Numeric: + { + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '.'); + }break; + case TXTI_TokenKind_String: + { + ender_found = (!escaped && ((!string_is_char && byte == '"') || (string_is_char && byte == '\''))); + ender_pad += 1; + }break; + case TXTI_TokenKind_Symbol: + { + ender_found = (byte != '~' && byte != '!' && + byte != '%' && byte != '^' && + byte != '&' && byte != '*' && + byte != '(' && byte != ')' && + byte != '-' && byte != '=' && + byte != '+' && byte != '[' && + byte != ']' && byte != '{' && + byte != '}' && byte != ':' && + byte != ';' && byte != ',' && + byte != '.' && byte != '<' && + byte != '>' && byte != '/' && + byte != '?' && byte != '|'); + }break; + case TXTI_TokenKind_Comment: + { + if(comment_is_single_line) + { + ender_found = (!escaped && (byte == '\r' || byte == '\n')); + } + else + { + ender_found = (active_token_start_idx+1 < idx && byte == '*' && next_byte == '/'); + ender_pad += 2; + } + }break; + case TXTI_TokenKind_Meta: + { + ender_found = (!escaped && (byte == '\r' || byte == '\n')); + }break; + } + } + + // rjf: next byte is ender => emit token + if(ender_found) + { + TXTI_Token token = {active_token_kind, r1u64(active_token_start_idx, idx+ender_pad)}; + active_token_kind = TXTI_TokenKind_Null; + + // rjf: identifier -> keyword in special cases + if(token.kind == TXTI_TokenKind_Identifier) + { + read_only local_persist String8 cpp_keywords[] = + { + str8_lit_comp("alignas"), + str8_lit_comp("alignof"), + str8_lit_comp("and"), + str8_lit_comp("and_eq"), + str8_lit_comp("asm"), + str8_lit_comp("atomic_cancel"), + str8_lit_comp("atomic_commit"), + str8_lit_comp("atomic_noexcept"), + str8_lit_comp("auto"), + str8_lit_comp("bitand"), + str8_lit_comp("bitor"), + str8_lit_comp("bool"), + str8_lit_comp("break"), + str8_lit_comp("case"), + str8_lit_comp("catch"), + str8_lit_comp("char"), + str8_lit_comp("char8_t"), + str8_lit_comp("char16_t"), + str8_lit_comp("char32_t"), + str8_lit_comp("class"), + str8_lit_comp("compl"), + str8_lit_comp("concept"), + str8_lit_comp("const"), + str8_lit_comp("consteval"), + str8_lit_comp("constexpr"), + str8_lit_comp("constinit"), + str8_lit_comp("const_cast"), + str8_lit_comp("continue"), + str8_lit_comp("co_await"), + str8_lit_comp("co_return"), + str8_lit_comp("co_yield"), + str8_lit_comp("decltype"), + str8_lit_comp("default"), + str8_lit_comp("delete"), + str8_lit_comp("do"), + str8_lit_comp("double"), + str8_lit_comp("dynamic_cast"), + str8_lit_comp("else"), + str8_lit_comp("enum"), + str8_lit_comp("explicit"), + str8_lit_comp("export"), + str8_lit_comp("extern"), + str8_lit_comp("false"), + str8_lit_comp("float"), + str8_lit_comp("for"), + str8_lit_comp("friend"), + str8_lit_comp("goto"), + str8_lit_comp("if"), + str8_lit_comp("inline"), + str8_lit_comp("int"), + str8_lit_comp("long"), + str8_lit_comp("mutable"), + str8_lit_comp("namespace"), + str8_lit_comp("new"), + str8_lit_comp("noexcept"), + str8_lit_comp("not"), + str8_lit_comp("not_eq"), + str8_lit_comp("nullptr"), + str8_lit_comp("operator"), + str8_lit_comp("or"), + str8_lit_comp("or_eq"), + str8_lit_comp("private"), + str8_lit_comp("protected"), + str8_lit_comp("public"), + str8_lit_comp("reflexpr"), + str8_lit_comp("register"), + str8_lit_comp("reinterpret_cast"), + str8_lit_comp("requires"), + str8_lit_comp("return"), + str8_lit_comp("short"), + str8_lit_comp("signed"), + str8_lit_comp("sizeof"), + str8_lit_comp("static"), + str8_lit_comp("static_assert"), + str8_lit_comp("static_cast"), + str8_lit_comp("struct"), + str8_lit_comp("switch"), + str8_lit_comp("synchronized"), + str8_lit_comp("template"), + str8_lit_comp("this"), + str8_lit_comp("thread_local"), + str8_lit_comp("throw"), + str8_lit_comp("true"), + str8_lit_comp("try"), + str8_lit_comp("typedef"), + str8_lit_comp("typeid"), + str8_lit_comp("typename"), + str8_lit_comp("union"), + str8_lit_comp("unsigned"), + str8_lit_comp("using"), + str8_lit_comp("virtual"), + str8_lit_comp("void"), + str8_lit_comp("volatile"), + str8_lit_comp("wchar_t"), + str8_lit_comp("while"), + str8_lit_comp("xor"), + str8_lit_comp("xor_eq"), + }; + String8 token_string = str8_substr(string, r1u64(active_token_start_idx, idx+ender_pad)); + for(U64 keyword_idx = 0; keyword_idx < ArrayCount(cpp_keywords); keyword_idx += 1) + { + if(str8_match(cpp_keywords[keyword_idx], token_string, 0)) + { + token.kind = TXTI_TokenKind_Keyword; + break; + } + } + } + + // rjf: push + txti_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + + // rjf: increment by ender padding + idx += ender_pad; + } + + // rjf: advance by 1 byte if we haven't found an ender + if(!ender_found) + { + idx += 1; + } + escaped = next_escaped; + } + } + + //- rjf: token list -> token array + TXTI_TokenArray result = txti_token_array_from_chunk_list(arena, &tokens); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Message Type Functions + +internal void +txti_msg_list_push(Arena *arena, TXTI_MsgList *msgs, TXTI_Msg *msg) +{ + TXTI_MsgNode *node = push_array(arena, TXTI_MsgNode, 1); + MemoryCopyStruct(&node->v, msg); + SLLQueuePush(msgs->first, msgs->last, node); + msgs->count += 1; +} + +internal void +txti_msg_list_concat_in_place(TXTI_MsgList *dst, TXTI_MsgList *src) +{ + if(dst->last == 0) + { + MemoryCopyStruct(dst, src); + } + else if(src->first) + { + dst->last->next = src->first; + dst->last = src->last; + dst->count += src->count; + } + MemoryZeroStruct(src); +} + +internal TXTI_MsgList +txti_msg_list_deep_copy(Arena *arena, TXTI_MsgList *src) +{ + TXTI_MsgList dst = {0}; + for(TXTI_MsgNode *src_n = src->first; src_n != 0; src_n = src_n->next) + { + TXTI_MsgNode *dst_n = push_array(arena, TXTI_MsgNode, 1); + SLLQueuePush(dst.first, dst.last, dst_n); + dst.count += 1; + MemoryCopyStruct(&dst_n->v, &src_n->v); + dst_n->v.string = push_str8_copy(arena, src_n->v.string); + } + return dst; +} + +//////////////////////////////// +//~ rjf: Entities API + +//- rjf: opening entities & correllation w/ path + +internal TXTI_Handle +txti_handle_from_path(String8 path) +{ + TXTI_Handle handle = {0}; + { + // rjf: path -> hash * slot *stripe + U64 hash = txti_hash_from_string(path); + U64 slot_idx = hash%txti_state->entity_map.slots_count; + U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; + TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; + TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; + + // rjf: determine if entity exists (shared lock) + TXTI_Entity *found_entity = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TXTI_Entity *entity = slot->first; entity != 0; entity = entity->next) + { + if(str8_match(entity->path, path, 0)) + { + found_entity = entity; + break; + } + } + if(found_entity != 0) + { + handle.u64[0] = hash; + handle.u64[1] = found_entity->id; + } + } + + // rjf: if entity does not exist -> exclusive lock & check again -- if still + // does not exist, then build it + if(found_entity == 0) OS_MutexScopeW(stripe->rw_mutex) + { + for(TXTI_Entity *entity = slot->first; entity != 0; entity = entity->next) + { + if(str8_match(entity->path, path, 0)) + { + found_entity = entity; + break; + } + } + if(found_entity == 0) + { + TXTI_Entity *entity = push_array(stripe->arena, TXTI_Entity, 1); + entity->path = push_str8_copy(stripe->arena, path); + entity->id = ins_atomic_u64_inc_eval(&txti_state->entity_id_gen); + for(U64 idx = 0; idx < TXTI_ENTITY_BUFFER_COUNT; idx += 1) + { + TXTI_Buffer *buffer = &entity->buffers[idx]; + buffer->data_arena = arena_alloc__sized(GB(32), KB(64)); + buffer->analysis_arena = arena_alloc__sized(GB(32), KB(64)); + buffer->data_arena->align = 1; + } + SLLQueuePush(slot->first, slot->last, entity); + found_entity = entity; + } + handle.u64[0] = hash; + handle.u64[1] = found_entity->id; + } + } + return handle; +} + +//- rjf: buffer introspection + +internal TXTI_BufferInfo +txti_buffer_info_from_handle(Arena *arena, TXTI_Handle handle) +{ + TXTI_BufferInfo result = {0}; + U64 hash = handle.u64[0]; + U64 id = handle.u64[1]; + U64 slot_idx = hash%txti_state->entity_map.slots_count; + U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; + TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; + TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + TXTI_Entity *entity = 0; + for(TXTI_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + TXTI_Buffer *buffer = &entity->buffers[entity->buffer_apply_gen%TXTI_ENTITY_BUFFER_COUNT]; + result.path = push_str8_copy(arena, entity->path); + result.timestamp = entity->timestamp; + result.line_end_kind = entity->line_end_kind; + result.total_line_count = buffer->lines_count; + result.max_line_size = buffer->lines_max_size; + result.mut_gen = entity->mut_gen; + result.buffer_apply_gen = entity->buffer_apply_gen; + result.bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed); + result.bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); + } + } + result.total_line_count = Max(1, result.total_line_count); + return result; +} + +internal TXTI_Slice +txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line_range) +{ + ProfBeginFunction(); + TXTI_Slice result = {0}; + Temp scratch = scratch_begin(&arena, 1); + U64 hash = handle.u64[0]; + U64 id = handle.u64[1]; + U64 slot_idx = hash%txti_state->entity_map.slots_count; + U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; + TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; + TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + TXTI_Entity *entity = 0; + for(TXTI_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + TXTI_Buffer *buffer = &entity->buffers[entity->buffer_apply_gen%TXTI_ENTITY_BUFFER_COUNT]; + Rng1S64 line_range_clamped = r1s64(Clamp(1, line_range.min, (S64)buffer->lines_count), Clamp(1, line_range.max, (S64)buffer->lines_count)); + + // rjf: allocate output arrays + result.line_count = (U64)dim_1s64(line_range_clamped)+1; + result.line_text = push_array(arena, String8, result.line_count); + result.line_ranges = push_array(arena, Rng1U64, result.line_count); + result.line_tokens = push_array(arena, TXTI_TokenArray, result.line_count); + + // rjf: fill line ranges & text + U64 line_slice_idx = 0; + U64 line_buffer_idx = line_range_clamped.min-1; + ProfScope("fill line ranges & text") + for(S64 line_num = line_range_clamped.min; + line_num <= line_range_clamped.max && line_buffer_idx < buffer->lines_count; + line_num += 1, + line_slice_idx += 1, + line_buffer_idx += 1) + { + Rng1U64 range = buffer->lines_ranges[line_buffer_idx]; + String8 line_text_internal = str8_substr(buffer->data, range); + result.line_ranges[line_slice_idx] = range; + result.line_text[line_slice_idx] = push_str8_copy(arena, line_text_internal); + } + + // rjf: binary search to find first token + TXTI_Token *tokens_first = 0; + ProfScope("binary search to find first token") + { + Rng1U64 slice_range = r1u64(result.line_ranges[0].min, result.line_ranges[result.line_count-1].max); + U64 min_idx = 0; + U64 opl_idx = buffer->tokens.count; + for(;;) + { + U64 mid_idx = (opl_idx+min_idx)/2; + if(mid_idx >= opl_idx) + { + break; + } + TXTI_Token *mid_token = &buffer->tokens.v[mid_idx]; + if(mid_token->range.min > slice_range.max) + { + opl_idx = mid_idx; + } + else if(mid_token->range.max < slice_range.min) + { + min_idx = mid_idx; + } + else if(tokens_first == 0 || mid_token->range.min < tokens_first->range.min) + { + tokens_first = mid_token; + opl_idx = mid_idx; + } + if(mid_idx == min_idx && mid_idx+1 == opl_idx) + { + break; + } + } + } + + // rjf: grab per-line tokens + TXTI_TokenList *line_tokens_lists = push_array(scratch.arena, TXTI_TokenList, result.line_count); + if(tokens_first != 0) ProfScope("grab per-line tokens") + { + TXTI_Token *tokens_opl = buffer->tokens.v+buffer->tokens.count; + U64 line_slice_idx = 0; + for(TXTI_Token *token = tokens_first; token < tokens_opl && line_slice_idx < result.line_count;) + { + if(token->range.min < result.line_ranges[line_slice_idx].max) + { + if(token->range.max > result.line_ranges[line_slice_idx].min) + { + txti_token_list_push(scratch.arena, &line_tokens_lists[line_slice_idx], token); + } + B32 need_token_advance = 0; + B32 need_line_advance = 0; + if(token->range.max >= result.line_ranges[line_slice_idx].max) + { + need_line_advance = 1; + } + if(token->range.max <= result.line_ranges[line_slice_idx].max) + { + need_token_advance += 1; + } + if(need_line_advance) { line_slice_idx += 1; } + if(need_token_advance) { token += 1; } + } + else + { + line_slice_idx += 1; + } + } + } + + // rjf: bake per-line tokens to arrays + for(U64 line_slice_idx = 0; line_slice_idx < result.line_count; line_slice_idx += 1) + { + result.line_tokens[line_slice_idx] = txti_token_array_from_list(arena, &line_tokens_lists[line_slice_idx]); + } + } + } + scratch_end(scratch); + ProfEnd(); + return result; +} + +internal String8 +txti_string_from_handle_txt_rng(Arena *arena, TXTI_Handle handle, TxtRng range) +{ + String8 result = {0}; + Temp scratch = scratch_begin(&arena, 1); + { + Rng1S64 line_range = r1s64(ClampBot(1, range.min.line), ClampBot(1, range.max.line)); + TXTI_BufferInfo info = txti_buffer_info_from_handle(scratch.arena, handle); + TXTI_Slice slice = txti_slice_from_handle_line_range(scratch.arena, handle, line_range); + String8List line_strings = {0}; + for(U64 line_idx = 0; line_idx < slice.line_count; line_idx += 1) + { + String8 line_text = slice.line_text[line_idx]; + if(line_idx == slice.line_count-1) + { + line_text = str8_prefix(line_text, range.max.column-1); + } + if(line_idx == 0) + { + line_text = str8_skip(line_text, range.min.column-1); + } + str8_list_push(scratch.arena, &line_strings, line_text); + } + StringJoin join = {0}; + switch(info.line_end_kind) + { + default: + case TXTI_LineEndKind_LF:{join.sep = str8_lit("\n");}break; + case TXTI_LineEndKind_CRLF:{join.sep = str8_lit("\r\n");}break; + } + result = str8_list_join(arena, &line_strings, &join); + } + scratch_end(scratch); + return result; +} + +internal String8 +txti_string_from_handle_line_num(Arena *arena, TXTI_Handle handle, S64 line_num) +{ + String8 result = {0}; + TXTI_Slice slice = txti_slice_from_handle_line_range(arena, handle, r1s64(line_num, line_num)); + if(slice.line_count != 0) + { + result = slice.line_text[0]; + } + return result; +} + +internal Rng1U64 +txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXTI_TokenArray *line_tokens) +{ + Rng1U64 result = {0}; + Temp scratch = scratch_begin(0, 0); + { + // rjf: unpack line info + TXTI_Token *line_tokens_first = line_tokens->v; + TXTI_Token *line_tokens_opl = line_tokens->v+line_tokens->count; + + // rjf: find token containing `off` + TXTI_Token *pt_token = 0; + for(TXTI_Token *token = line_tokens_first; + token < line_tokens_opl; + token += 1) + { + if(contains_1u64(token->range, off)) + { + Rng1U64 token_range_clamped = intersect_1u64(line_range, token->range); + String8 token_string = str8_substr(line_text, r1u64(token_range_clamped.max - line_range.min, token_range_clamped.max - line_range.min)); + B32 token_ender = 0; + switch(token->kind) + { + default:{}break; + case TXTI_TokenKind_Symbol: + { + token_ender = (str8_match(token_string, str8_lit("]"), 0)); + }break; + case TXTI_TokenKind_Identifier: + case TXTI_TokenKind_Keyword: + case TXTI_TokenKind_String: + case TXTI_TokenKind_Meta: + { + token_ender = 1; + }break; + } + if(token_ender) + { + pt_token = token; + } + break; + } + } + + // rjf: found token containing `off`? -> mark that as our initial range + if(pt_token != 0) + { + result = pt_token->range; + } + + // rjf: walk back from pt_token - try to find plausible start of expression + if(pt_token != 0) + { + B32 walkback_done = 0; + S32 nest = 0; + for(TXTI_Token *wb_token = pt_token; + wb_token >= line_tokens_first && walkback_done == 0; + wb_token -= 1) + { + Rng1U64 wb_token_range_clamped = intersect_1u64(line_range, wb_token->range); + String8 wb_token_string = str8_substr(line_text, r1u64(wb_token_range_clamped.min - line_range.min, wb_token_range_clamped.max - line_range.min)); + B32 include_wb_token = 0; + switch(wb_token->kind) + { + default:{}break; + case TXTI_TokenKind_Symbol: + { + B32 is_dot = str8_match(wb_token_string, str8_lit("."), 0); + B32 is_arrow = str8_match(wb_token_string, str8_lit("->"), 0); + B32 is_open_bracket = str8_match(wb_token_string, str8_lit("["), 0); + B32 is_close_bracket = str8_match(wb_token_string, str8_lit("]"), 0); + nest -= !!(is_open_bracket); + nest += !!(is_close_bracket); + if(is_dot || + is_arrow || + is_open_bracket|| + is_close_bracket) + { + include_wb_token = 1; + } + }break; + case TXTI_TokenKind_Identifier: + { + include_wb_token = 1; + }break; + } + if(include_wb_token) + { + result = union_1u64(result, wb_token->range); + } + else if(nest == 0) + { + walkback_done = 1; + } + } + } + } + scratch_end(scratch); + return result; +} + +internal TxtRng +txti_expr_range_from_handle_pt(TXTI_Handle handle, TxtPt pt) +{ + TxtRng result = {0}; + Temp scratch = scratch_begin(0, 0); + TXTI_Slice slice = txti_slice_from_handle_line_range(scratch.arena, handle, r1s64(pt.line, pt.line)); + if(slice.line_count != 0) + { + // rjf: unpack line info + String8 line_text = slice.line_text[0]; + Rng1U64 line_range = slice.line_ranges[0]; + TXTI_TokenArray line_tokens = slice.line_tokens[0]; + TXTI_Token *line_tokens_first = line_tokens.v; + TXTI_Token *line_tokens_opl = line_tokens.v+line_tokens.count; + U64 pt_off = line_range.min + (pt.column-1); + + // rjf: grab offset range of expression + Rng1U64 expr_off_rng = txti_expr_range_from_line_off_range_string_tokens(pt_off, line_range, line_text, &line_tokens); + + // rjf: convert offset range into text range + result = txt_rng(txt_pt(pt.line, 1+(expr_off_rng.min-line_range.min)), txt_pt(pt.line, 1+(expr_off_rng.max-line_range.min))); + } + scratch_end(scratch); + return result; +} + +//- rjf: buffer mutations + +internal void +txti_reload(TXTI_Handle handle, String8 path) +{ + U64 hash = handle.u64[0]; + U64 id = handle.u64[1]; + U64 mut_thread_idx = id%txti_state->mut_thread_count; + TXTI_MutThread *mut_thread = &txti_state->mut_threads[mut_thread_idx]; + OS_MutexScope(mut_thread->msg_mutex) + { + TXTI_MsgNode *node = push_array(mut_thread->msg_arena, TXTI_MsgNode, 1); + TXTI_Msg *msg = &node->v; + msg->kind = TXTI_MsgKind_Reload; + msg->handle = handle; + msg->string = push_str8_copy(mut_thread->msg_arena, path); + SLLQueuePush(mut_thread->msg_list.first, mut_thread->msg_list.last, node); + mut_thread->msg_list.count += 1; + } + os_condition_variable_broadcast(mut_thread->msg_cv); +} + +internal void +txti_append(TXTI_Handle handle, String8 string) +{ + U64 hash = handle.u64[0]; + U64 id = handle.u64[1]; + U64 mut_thread_idx = id%txti_state->mut_thread_count; + TXTI_MutThread *mut_thread = &txti_state->mut_threads[mut_thread_idx]; + OS_MutexScope(mut_thread->msg_mutex) + { + TXTI_MsgNode *node = push_array(mut_thread->msg_arena, TXTI_MsgNode, 1); + TXTI_Msg *msg = &node->v; + msg->kind = TXTI_MsgKind_Append; + msg->handle = handle; + msg->string = push_str8_copy(mut_thread->msg_arena, string); + SLLQueuePush(mut_thread->msg_list.first, mut_thread->msg_list.last, node); + mut_thread->msg_list.count += 1; + } + os_condition_variable_broadcast(mut_thread->msg_cv); +} + +//////////////////////////////// +//~ rjf: Mutator Threads + +internal void +txti_mut_thread_entry_point(void *p) +{ + TCTX tctx_; + tctx_init_and_equip(&tctx_); + + U64 mut_thread_idx = (U64)p; + ProfThreadName("[txti] mut #%I64u", mut_thread_idx); + TXTI_MutThread *mut_thread = &txti_state->mut_threads[mut_thread_idx]; + for(;;) + { + //- rjf: begin + Temp scratch = scratch_begin(0, 0); + + //- rjf: pull messages + TXTI_MsgList msgs = {0}; + OS_MutexScope(mut_thread->msg_mutex) for(;;) + { + if(mut_thread->msg_list.count != 0) + { + msgs = txti_msg_list_deep_copy(scratch.arena, &mut_thread->msg_list); + MemoryZeroStruct(&mut_thread->msg_list); + arena_clear(mut_thread->msg_arena); + break; + } + os_condition_variable_wait(mut_thread->msg_cv, mut_thread->msg_mutex, max_U64); + } + + //- rjf: process msgs + for(TXTI_MsgNode *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next) ProfScope("process msg") + { + //- rjf: unpack message + TXTI_Msg *msg = &msg_n->v; + U64 hash = msg->handle.u64[0]; + U64 id = msg->handle.u64[1]; + U64 slot_idx = hash%txti_state->entity_map.slots_count; + U64 stripe_idx = slot_idx%txti_state->entity_map_stripes.count; + TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; + TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; + + //- rjf: load file if we need it + String8 file_contents = {0}; + TXTI_LangKind lang_kind = TXTI_LangKind_Null; + U64 timestamp = 0; + if(msg->kind == TXTI_MsgKind_Reload) + { + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, msg->string); + FileProperties props = os_properties_from_file(file); + timestamp = props.modified; + file_contents = os_string_from_file_range(scratch.arena, file, r1u64(0, props.size)); + lang_kind = txti_lang_kind_from_extension(str8_skip_last_dot(msg->string)); + os_file_close(file); + } + + //- rjf: nonzero lang kind -> unpack lang info + TXTI_LangLexFunctionType *lex_function = 0; + switch(lang_kind) + { + default:{}break; + case TXTI_LangKind_C: + case TXTI_LangKind_CPlusPlus: + { + lex_function = txti_token_array_from_string__cpp; + }break; + } + + //- rjf: detect line end kind + TXTI_LineEndKind line_end_kind = TXTI_LineEndKind_Null; + { + U64 lf_count = 0; + U64 cr_count = 0; + for(U64 idx = 0; idx < file_contents.size && idx < 1024; idx += 1) + { + if(file_contents.str[idx] == '\r') + { + cr_count += 1; + } + if(file_contents.str[idx] == '\n') + { + lf_count += 1; + } + } + if(cr_count >= lf_count/2 && lf_count >= 1) + { + line_end_kind = TXTI_LineEndKind_CRLF; + } + else if(lf_count >= 1) + { + line_end_kind = TXTI_LineEndKind_LF; + } + } + + //- rjf: obtain initial buffer_apply_gen, reset byte processing counters + U64 initial_buffer_apply_gen = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + TXTI_Entity *entity = 0; + for(TXTI_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + initial_buffer_apply_gen = entity->buffer_apply_gen; + if(msg->kind == TXTI_MsgKind_Reload) + { + ins_atomic_u64_eval_assign(&entity->bytes_processed, 0); + ins_atomic_u64_eval_assign(&entity->bytes_to_process, file_contents.size + !!lex_function*file_contents.size); + } + } + } + + //- rjf: apply edits + for(U64 buffer_apply_idx = 0; + buffer_apply_idx < TXTI_ENTITY_BUFFER_COUNT; + buffer_apply_idx += 1) + { + // rjf: last buffer we're going to edit? -> bump buffer_apply_gen, + // so that before we touch this last buffer, all readers of this + // entity will get the already-modified buffers. + if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) + { + OS_MutexScopeW(stripe->rw_mutex) + { + TXTI_Entity *entity = 0; + for(TXTI_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + entity->buffer_apply_gen += 1; + if(line_end_kind != TXTI_LineEndKind_Null) + { + entity->line_end_kind = line_end_kind; + } + if(lang_kind != TXTI_LangKind_Null) + { + entity->lang_kind = lang_kind; + } + if(timestamp != 0) + { + entity->timestamp = timestamp; + } + } + } + } + + // rjf: apply edit to this buffer. + // + // NOTE(rjf): all edits can apply *with a shared mutex lock*, + // because only the mutator thread for this buffer can touch the + // non-currently-viewable buffers. we only need to have an + // exclusive lock to bump the buffer_apply_gen (to change the + // actively viewable buffer). + // + OS_MutexScopeR(stripe->rw_mutex) + { + TXTI_Entity *entity = 0; + for(TXTI_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + TXTI_Buffer *buffer = &entity->buffers[(initial_buffer_apply_gen+1+buffer_apply_idx)%TXTI_ENTITY_BUFFER_COUNT]; + + // rjf: clear old analysis data + arena_clear(buffer->analysis_arena); + buffer->lines_count = 0; + buffer->lines_ranges = 0; + buffer->lines_max_size = 0; + MemoryZeroStruct(&buffer->tokens); + + // rjf: perform edit to buffer data + switch(msg->kind) + { + default:{}break; + + // rjf: replace range + case TXTI_MsgKind_Append: ProfScope("append") + { + U8 *append_data_buffer = push_array_no_zero(buffer->data_arena, U8, msg->string.size); + MemoryCopy(append_data_buffer, msg->string.str, msg->string.size); + buffer->data.size += msg->string.size; + if(buffer->data.str == 0) + { + buffer->data.str = append_data_buffer; + } + }break; + + // rjf: reload from disk + case TXTI_MsgKind_Reload: ProfScope("reload") + { + arena_clear(buffer->data_arena); + buffer->data = push_str8_copy(buffer->data_arena, file_contents); + }break; + } + + // rjf: parse & store line range info + { + // rjf: count # of lines + U64 line_count = 1; + U64 byte_process_start_idx = 0; + for(U64 idx = 0; idx < buffer->data.size; idx += 1) + { + if(buffer_apply_idx == 0 && idx-byte_process_start_idx >= 1000) + { + ins_atomic_u64_add_eval(&entity->bytes_processed, (idx-byte_process_start_idx)); + byte_process_start_idx = idx; + } + if(buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') + { + line_count += 1; + if(buffer->data.str[idx] == '\r') + { + idx += 1; + } + } + } + + // rjf: allocate & store line ranges + buffer->lines_count = line_count; + buffer->lines_ranges = push_array_no_zero(buffer->analysis_arena, Rng1U64, buffer->lines_count); + U64 line_idx = 0; + U64 line_start_idx = 0; + for(U64 idx = 0; idx <= buffer->data.size; idx += 1) + { + if(idx == buffer->data.size || buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') + { + Rng1U64 line_range = r1u64(line_start_idx, idx); + U64 line_size = dim_1u64(line_range); + buffer->lines_ranges[line_idx] = line_range; + buffer->lines_max_size = Max(buffer->lines_max_size, line_size); + line_idx += 1; + line_start_idx = idx+1; + if(idx < buffer->data.size && buffer->data.str[idx] == '\r') + { + line_start_idx += 1; + idx += 1; + } + } + } + } + + // rjf: lex file contents + if(lex_function != 0) + { + buffer->tokens = lex_function(buffer->analysis_arena, buffer_apply_idx == 0 ? &entity->bytes_processed : 0, buffer->data); + } + + // rjf: mark final process counter + if(buffer_apply_idx == 0) + { + ins_atomic_u64_eval_assign(&entity->bytes_processed, entity->bytes_to_process); + } + + // rjf: mark task completion + if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) + { + ins_atomic_u64_eval_assign(&entity->working_count, 0); + } + } + } + } + } + + //- rjf: end + scratch_end(scratch); + } +} + +//////////////////////////////// +//~ rjf: Detector Thread + +internal void +txti_detector_thread_entry_point(void *p) +{ + TCTX tctx_; + tctx_init_and_equip(&tctx_); + ProfThreadName("[txti] detector"); + for(;;) + { + U64 slots_per_stripe = txti_state->entity_map.slots_count/txti_state->entity_map_stripes.count; + for(U64 stripe_idx = 0; stripe_idx < txti_state->entity_map_stripes.count; stripe_idx += 1) + { + TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) + { + U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx; + TXTI_EntitySlot *slot = &txti_state->entity_map.slots[slot_idx]; + for(TXTI_Entity *entity = slot->first; entity != 0; entity = entity->next) + { + FileProperties props = os_properties_from_file_path(entity->path); + U64 entity_timestamp = entity->timestamp; + if(props.modified != entity_timestamp && ins_atomic_u64_eval(&entity->working_count) == 0) + { + TXTI_Handle handle = {txti_hash_from_string(entity->path), entity->id}; + txti_reload(handle, entity->path); + ins_atomic_u64_inc_eval(&entity->working_count); + } + } + } + } + os_sleep_milliseconds(100); + } +} diff --git a/src/txti/txti.h b/src/txti/txti.h new file mode 100644 index 00000000..4fb87d4a --- /dev/null +++ b/src/txti/txti.h @@ -0,0 +1,392 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef TXTI_H +#define TXTI_H + +//////////////////////////////// +//~ NOTE(rjf): Text Info Layer Overview (8/30/2023) +// +// This layer's purpose is to provide access to a mutable cache of parsed +// information about textual data, backed by filesystem contents. This +// cache associates unique handles (`TXTI_Handle`) with "entities", where +// entities contain information about textual contents of each line, how many +// lines of text the entity contains, and the tokenization of each line. +// +// While it is generally correct for a debugger to only provide read-only UIs +// for text viewing (so that the user does not mistakenly modify a buffer and +// continue debugging with it, even if the line or symbol info is no longer +// reflective of the source code), there are cases where read/write buffers are +// useful, and so this layer needs to support that, and the disabling of writes +// can remain as a high-level UI decision (rather than a lack of capability of +// the debugger). Mutable buffers may be used for editing config files (or +// otherwise any files that are not relevant to actively-used debug info), +// or debug logs. +// +// This layer is also responsible for hot-reloading changed files from disk, +// *and* for reporting conflicts, if a buffer was mutated within the process, +// but was also modified on disk. +// +// In order to avoid hanging UI while larger files are being edited or lexed, +// all buffer loading, mutation, & parsing happen on "mutator threads". These +// threads consume messages (`TXTI_Msg`), which command them to reload a file +// from disk, or to replace textual ranges in a buffer. After completing those +// operations, the buffer is lexed/parsed. +// +// Entities have *two* buffer data structures -- this allows a mutator thread +// to apply edits to one while the other can be read by user threads. For each +// editing operation, the mutator threads apply identical operations in a +// *rotation-based* order. If the currently-viewable buffer is slot 0, the edit +// will first be applied to slot 1, and before edits are reflected in slot 0, +// the mutator thread will bump a "buffer mutation counter", such that before +// any edits are made to slot 0, the viewable buffer is changed to being within +// slot *1*. +// +// Importantly, entities map to a *unique* mutator thread -- it is not possible +// for multiple mutator threads to be attempting to write to the same entity at +// the same time, as this could not produce meaningful or coherent results. +// This way, all edits to each entity are applied serially. + +//////////////////////////////// +//~ rjf: Handle Type + +typedef struct TXTI_Handle TXTI_Handle; +struct TXTI_Handle +{ + U64 u64[2]; +}; + +//////////////////////////////// +//~ rjf: Parsed Text Info Types + +typedef enum TXTI_LineEndKind +{ + TXTI_LineEndKind_Null, + TXTI_LineEndKind_LF, + TXTI_LineEndKind_CRLF, + TXTI_LineEndKind_COUNT +} +TXTI_LineEndKind; + +typedef enum TXTI_TokenKind +{ + TXTI_TokenKind_Null, + TXTI_TokenKind_Error, + TXTI_TokenKind_Whitespace, + TXTI_TokenKind_Keyword, + TXTI_TokenKind_Identifier, + TXTI_TokenKind_Numeric, + TXTI_TokenKind_String, + TXTI_TokenKind_Symbol, + TXTI_TokenKind_Comment, + TXTI_TokenKind_Meta, // preprocessor, etc. + TXTI_TokenKind_COUNT +} +TXTI_TokenKind; + +typedef struct TXTI_Token TXTI_Token; +struct TXTI_Token +{ + TXTI_TokenKind kind; + Rng1U64 range; +}; + +typedef struct TXTI_TokenChunkNode TXTI_TokenChunkNode; +struct TXTI_TokenChunkNode +{ + TXTI_TokenChunkNode *next; + U64 count; + U64 cap; + TXTI_Token *v; +}; + +typedef struct TXTI_TokenChunkList TXTI_TokenChunkList; +struct TXTI_TokenChunkList +{ + TXTI_TokenChunkNode *first; + TXTI_TokenChunkNode *last; + U64 chunk_count; + U64 token_count; +}; + +typedef struct TXTI_TokenNode TXTI_TokenNode; +struct TXTI_TokenNode +{ + TXTI_TokenNode *next; + TXTI_Token v; +}; + +typedef struct TXTI_TokenList TXTI_TokenList; +struct TXTI_TokenList +{ + TXTI_TokenNode *first; + TXTI_TokenNode *last; + U64 count; +}; + +typedef struct TXTI_TokenArray TXTI_TokenArray; +struct TXTI_TokenArray +{ + U64 count; + TXTI_Token *v; +}; + +typedef struct TXTI_TokenArrayArray TXTI_TokenArrayArray; +struct TXTI_TokenArrayArray +{ + U64 count; + TXTI_TokenArray *v; +}; + +//////////////////////////////// +//~ rjf: Language Kinds + +typedef enum TXTI_LangKind +{ + TXTI_LangKind_Null, + TXTI_LangKind_C, + TXTI_LangKind_CPlusPlus, + TXTI_LangKind_COUNT +} +TXTI_LangKind; + +typedef TXTI_TokenArray TXTI_LangLexFunctionType(Arena *arena, U64 *bytes_processed_counter, String8 string); + +//////////////////////////////// +//~ rjf: Buffer Entity Types + +#define TXTI_ENTITY_BUFFER_COUNT 2 + +typedef struct TXTI_Buffer TXTI_Buffer; +struct TXTI_Buffer +{ + // rjf: arenas + Arena *data_arena; + Arena *analysis_arena; + + // rjf: raw textual data + String8 data; + + // rjf: line range info + U64 lines_count; + Rng1U64 *lines_ranges; + U64 lines_max_size; + + // rjf: tokens + TXTI_TokenArray tokens; +}; + +typedef struct TXTI_Entity TXTI_Entity; +struct TXTI_Entity +{ + // rjf: top-level info + TXTI_Entity *next; + String8 path; + U64 id; + U64 timestamp; + U64 mut_gen; + + // rjf: metadata + TXTI_LineEndKind line_end_kind; + TXTI_LangKind lang_kind; + U64 bytes_processed; + U64 bytes_to_process; + U64 working_count; + + // rjf: double-buffered mutable text buffers + U64 buffer_apply_gen; + TXTI_Buffer buffers[TXTI_ENTITY_BUFFER_COUNT]; +}; + +typedef struct TXTI_EntitySlot TXTI_EntitySlot; +struct TXTI_EntitySlot +{ + TXTI_Entity *first; + TXTI_Entity *last; +}; + +typedef struct TXTI_EntityMap TXTI_EntityMap; +struct TXTI_EntityMap +{ + U64 slots_count; + TXTI_EntitySlot *slots; +}; + +//////////////////////////////// +//~ rjf: Striped Access Types + +typedef struct TXTI_Stripe TXTI_Stripe; +struct TXTI_Stripe +{ + Arena *arena; + OS_Handle cv; + OS_Handle rw_mutex; +}; + +typedef struct TXTI_StripeTable TXTI_StripeTable; +struct TXTI_StripeTable +{ + U64 count; + TXTI_Stripe *v; +}; + +//////////////////////////////// +//~ rjf: Entity Introspection Result Types + +typedef struct TXTI_BufferInfo TXTI_BufferInfo; +struct TXTI_BufferInfo +{ + String8 path; + U64 timestamp; + TXTI_LineEndKind line_end_kind; + TXTI_LangKind lang_kind; + U64 total_line_count; + U64 last_line_size; + U64 max_line_size; + U64 mut_gen; + U64 buffer_apply_gen; + U64 bytes_processed; + U64 bytes_to_process; +}; + +typedef struct TXTI_Slice TXTI_Slice; +struct TXTI_Slice +{ + U64 line_count; + String8 *line_text; + Rng1U64 *line_ranges; + TXTI_TokenArray *line_tokens; +}; + +//////////////////////////////// +//~ rjf: User -> Mutator Thread Messages + +typedef enum TXTI_MsgKind +{ + TXTI_MsgKind_Null, + TXTI_MsgKind_Append, + TXTI_MsgKind_Reload, + TXTI_MsgKind_COUNT +} +TXTI_MsgKind; + +typedef struct TXTI_Msg TXTI_Msg; +struct TXTI_Msg +{ + TXTI_MsgKind kind; + TXTI_Handle handle; + String8 string; +}; + +typedef struct TXTI_MsgNode TXTI_MsgNode; +struct TXTI_MsgNode +{ + TXTI_MsgNode *next; + TXTI_Msg v; +}; + +typedef struct TXTI_MsgList TXTI_MsgList; +struct TXTI_MsgList +{ + TXTI_MsgNode *first; + TXTI_MsgNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Central State + +typedef struct TXTI_MutThread TXTI_MutThread; +struct TXTI_MutThread +{ + OS_Handle thread; + Arena *msg_arena; + TXTI_MsgList msg_list; + OS_Handle msg_mutex; + OS_Handle msg_cv; +}; + +typedef struct TXTI_State TXTI_State; +struct TXTI_State +{ + // rjf: arena + Arena *arena; + + // rjf: entities state + TXTI_EntityMap entity_map; + TXTI_StripeTable entity_map_stripes; + U64 entity_id_gen; + + // rjf: mutator threads + U64 mut_thread_count; + TXTI_MutThread *mut_threads; + + // rjf: detector thread + OS_Handle detector_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +global TXTI_State *txti_state = 0; + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void txti_init(void); + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 txti_hash_from_string(String8 string); +internal TXTI_LangKind txti_lang_kind_from_extension(String8 extension); + +//////////////////////////////// +//~ rjf: Token Type Functions + +internal void txti_token_chunk_list_push(Arena *arena, TXTI_TokenChunkList *list, U64 cap, TXTI_Token *token); +internal void txti_token_list_push(Arena *arena, TXTI_TokenList *list, TXTI_Token *token); +internal TXTI_TokenArray txti_token_array_from_chunk_list(Arena *arena, TXTI_TokenChunkList *list); +internal TXTI_TokenArray txti_token_array_from_list(Arena *arena, TXTI_TokenList *list); + +//////////////////////////////// +//~ rjf: Lexing Functions + +internal TXTI_TokenArray txti_token_array_from_string__cpp(Arena *arena, U64 *bytes_processed_counter, String8 string); + +//////////////////////////////// +//~ rjf: Message Type Functions + +internal void txti_msg_list_push(Arena *arena, TXTI_MsgList *msgs, TXTI_Msg *msg); +internal void txti_msg_list_concat_in_place(TXTI_MsgList *dst, TXTI_MsgList *src); +internal TXTI_MsgList txti_msg_list_deep_copy(Arena *arena, TXTI_MsgList *src); + +//////////////////////////////// +//~ rjf: Entities API + +//- rjf: opening entities & correllation w/ path +internal TXTI_Handle txti_handle_from_path(String8 path); + +//- rjf: buffer introspection +internal TXTI_BufferInfo txti_buffer_info_from_handle(Arena *arena, TXTI_Handle handle); +internal TXTI_Slice txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line_range); +internal String8 txti_string_from_handle_txt_rng(Arena *arena, TXTI_Handle handle, TxtRng range); +internal String8 txti_string_from_handle_line_num(Arena *arena, TXTI_Handle handle, S64 line_num); +internal Rng1U64 txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXTI_TokenArray *line_tokens); +internal TxtRng txti_expr_range_from_handle_pt(TXTI_Handle handle, TxtPt pt); + +//- rjf: buffer mutations +internal void txti_reload(TXTI_Handle handle, String8 path); +internal void txti_append(TXTI_Handle handle, String8 string); + +//////////////////////////////// +//~ rjf: Mutator Threads + +internal void txti_mut_thread_entry_point(void *p); + +//////////////////////////////// +//~ rjf: Detector Thread + +internal void txti_detector_thread_entry_point(void *p); + +#endif //TXTI_H diff --git a/src/type_graph/generated/type_graph.meta.c b/src/type_graph/generated/type_graph.meta.c new file mode 100644 index 00000000..b9d27fe6 --- /dev/null +++ b/src/type_graph/generated/type_graph.meta.c @@ -0,0 +1,5 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + diff --git a/src/type_graph/generated/type_graph.meta.h b/src/type_graph/generated/type_graph.meta.h new file mode 100644 index 00000000..d869ee04 --- /dev/null +++ b/src/type_graph/generated/type_graph.meta.h @@ -0,0 +1,195 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef TYPE_GRAPH_META_H +#define TYPE_GRAPH_META_H + +typedef enum TG_Kind +{ +TG_Kind_Null, +TG_Kind_Void, +TG_Kind_Handle, +TG_Kind_Char8, +TG_Kind_Char16, +TG_Kind_Char32, +TG_Kind_UChar8, +TG_Kind_UChar16, +TG_Kind_UChar32, +TG_Kind_U8, +TG_Kind_U16, +TG_Kind_U32, +TG_Kind_U64, +TG_Kind_U128, +TG_Kind_U256, +TG_Kind_U512, +TG_Kind_S8, +TG_Kind_S16, +TG_Kind_S32, +TG_Kind_S64, +TG_Kind_S128, +TG_Kind_S256, +TG_Kind_S512, +TG_Kind_Bool, +TG_Kind_F16, +TG_Kind_F32, +TG_Kind_F32PP, +TG_Kind_F48, +TG_Kind_F64, +TG_Kind_F80, +TG_Kind_F128, +TG_Kind_ComplexF32, +TG_Kind_ComplexF64, +TG_Kind_ComplexF80, +TG_Kind_ComplexF128, +TG_Kind_Modifier, +TG_Kind_Ptr, +TG_Kind_LRef, +TG_Kind_RRef, +TG_Kind_Array, +TG_Kind_Function, +TG_Kind_Method, +TG_Kind_MemberPtr, +TG_Kind_Struct, +TG_Kind_Class, +TG_Kind_Union, +TG_Kind_Enum, +TG_Kind_Alias, +TG_Kind_IncompleteStruct, +TG_Kind_IncompleteUnion, +TG_Kind_IncompleteClass, +TG_Kind_IncompleteEnum, +TG_Kind_Bitfield, +TG_Kind_Variadic, +TG_Kind_COUNT, +TG_Kind_FirstBasic = TG_Kind_Void, +TG_Kind_LastBasic = TG_Kind_ComplexF128, +TG_Kind_FirstInteger = TG_Kind_Char8, +TG_Kind_LastInteger = TG_Kind_S512, +TG_Kind_FirstSigned1 = TG_Kind_Char8, +TG_Kind_LastSigned1 = TG_Kind_Char32, +TG_Kind_FirstSigned2 = TG_Kind_S8, +TG_Kind_LastSigned2 = TG_Kind_S512, +TG_Kind_FirstIncomplete = TG_Kind_IncompleteStruct, +TG_Kind_LastIncomplete = TG_Kind_IncompleteEnum, +} TG_Kind; + +U8 tg_kind_basic_byte_size_table[] = +{ +0, +0, +0xFF, +1, +2, +4, +1, +2, +4, +1, +2, +4, +8, +16, +32, +64, +1, +2, +4, +8, +16, +32, +64, +1, +2, +4, +4, +6, +8, +10, +16, +8, +16, +20, +32, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +}; + +String8 tg_kind_basic_string_table[] = +{ +str8_lit_comp(""), +str8_lit_comp("void"), +str8_lit_comp("HANDLE"), +str8_lit_comp("char8"), +str8_lit_comp("char16"), +str8_lit_comp("char32"), +str8_lit_comp("uchar8"), +str8_lit_comp("uchar16"), +str8_lit_comp("uchar32"), +str8_lit_comp("U8"), +str8_lit_comp("U16"), +str8_lit_comp("U32"), +str8_lit_comp("U64"), +str8_lit_comp("U128"), +str8_lit_comp("U256"), +str8_lit_comp("U512"), +str8_lit_comp("S8"), +str8_lit_comp("S16"), +str8_lit_comp("S32"), +str8_lit_comp("S64"), +str8_lit_comp("S128"), +str8_lit_comp("S256"), +str8_lit_comp("S512"), +str8_lit_comp("bool"), +str8_lit_comp("F16"), +str8_lit_comp("F32"), +str8_lit_comp("F32PP"), +str8_lit_comp("F48"), +str8_lit_comp("F64"), +str8_lit_comp("F80"), +str8_lit_comp("F128"), +str8_lit_comp("ComplexF32"), +str8_lit_comp("ComplexF64"), +str8_lit_comp("ComplexF80"), +str8_lit_comp("ComplexF128"), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +}; + + +#endif // TYPE_GRAPH_META_H diff --git a/src/type_graph/type_graph.c b/src/type_graph/type_graph.c new file mode 100644 index 00000000..0142cffd --- /dev/null +++ b/src/type_graph/type_graph.c @@ -0,0 +1,1174 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +tg_hash_from_string(U64 seed, String8 string) +{ + U64 result = seed; + for(U64 idx = 0; idx < string.size; idx += 1) + { + result = ((result<<5)+result) + string.str[idx]; + } + return result; +} + +//////////////////////////////// +//~ rjf: RADDBG <-> TG Enum Conversions + +internal TG_Kind +tg_kind_from_raddbg_type_kind(RADDBG_TypeKind kind) +{ + TG_Kind result = TG_Kind_Null; + switch(kind) + { + default:{}break; + case RADDBG_TypeKind_Void: {result = TG_Kind_Void;}break; + case RADDBG_TypeKind_Handle: {result = TG_Kind_Handle;}break; + case RADDBG_TypeKind_Char8: {result = TG_Kind_Char8;}break; + case RADDBG_TypeKind_Char16: {result = TG_Kind_Char16;}break; + case RADDBG_TypeKind_Char32: {result = TG_Kind_Char32;}break; + case RADDBG_TypeKind_UChar8: {result = TG_Kind_UChar8;}break; + case RADDBG_TypeKind_UChar16: {result = TG_Kind_UChar16;}break; + case RADDBG_TypeKind_UChar32: {result = TG_Kind_UChar32;}break; + case RADDBG_TypeKind_U8: {result = TG_Kind_U8;}break; + case RADDBG_TypeKind_U16: {result = TG_Kind_U16;}break; + case RADDBG_TypeKind_U32: {result = TG_Kind_U32;}break; + case RADDBG_TypeKind_U64: {result = TG_Kind_U64;}break; + case RADDBG_TypeKind_U128: {result = TG_Kind_U128;}break; + case RADDBG_TypeKind_U256: {result = TG_Kind_U256;}break; + case RADDBG_TypeKind_U512: {result = TG_Kind_U512;}break; + case RADDBG_TypeKind_S8: {result = TG_Kind_S8;}break; + case RADDBG_TypeKind_S16: {result = TG_Kind_S16;}break; + case RADDBG_TypeKind_S32: {result = TG_Kind_S32;}break; + case RADDBG_TypeKind_S64: {result = TG_Kind_S64;}break; + case RADDBG_TypeKind_S128: {result = TG_Kind_S128;}break; + case RADDBG_TypeKind_S256: {result = TG_Kind_S256;}break; + case RADDBG_TypeKind_S512: {result = TG_Kind_S512;}break; + case RADDBG_TypeKind_Bool: {result = TG_Kind_Bool;}break; + case RADDBG_TypeKind_F16: {result = TG_Kind_F16;}break; + case RADDBG_TypeKind_F32: {result = TG_Kind_F32;}break; + case RADDBG_TypeKind_F32PP: {result = TG_Kind_F32PP;}break; + case RADDBG_TypeKind_F48: {result = TG_Kind_F48;}break; + case RADDBG_TypeKind_F64: {result = TG_Kind_F64;}break; + case RADDBG_TypeKind_F80: {result = TG_Kind_F80;}break; + case RADDBG_TypeKind_F128: {result = TG_Kind_F128;}break; + case RADDBG_TypeKind_ComplexF32: {result = TG_Kind_ComplexF32;}break; + case RADDBG_TypeKind_ComplexF64: {result = TG_Kind_ComplexF64;}break; + case RADDBG_TypeKind_ComplexF80: {result = TG_Kind_ComplexF80;}break; + case RADDBG_TypeKind_ComplexF128: {result = TG_Kind_ComplexF128;}break; + case RADDBG_TypeKind_Modifier: {result = TG_Kind_Modifier;}break; + case RADDBG_TypeKind_Ptr: {result = TG_Kind_Ptr;}break; + case RADDBG_TypeKind_LRef: {result = TG_Kind_LRef;}break; + case RADDBG_TypeKind_RRef: {result = TG_Kind_RRef;}break; + case RADDBG_TypeKind_Array: {result = TG_Kind_Array;}break; + case RADDBG_TypeKind_Function: {result = TG_Kind_Function;}break; + case RADDBG_TypeKind_Method: {result = TG_Kind_Method;}break; + case RADDBG_TypeKind_MemberPtr: {result = TG_Kind_MemberPtr;}break; + case RADDBG_TypeKind_Struct: {result = TG_Kind_Struct;}break; + case RADDBG_TypeKind_Class: {result = TG_Kind_Class;}break; + case RADDBG_TypeKind_Union: {result = TG_Kind_Union;}break; + case RADDBG_TypeKind_Enum: {result = TG_Kind_Enum;}break; + case RADDBG_TypeKind_Alias: {result = TG_Kind_Alias;}break; + case RADDBG_TypeKind_IncompleteStruct: {result = TG_Kind_IncompleteStruct;}break; + case RADDBG_TypeKind_IncompleteUnion: {result = TG_Kind_IncompleteUnion;}break; + case RADDBG_TypeKind_IncompleteClass: {result = TG_Kind_IncompleteClass;}break; + case RADDBG_TypeKind_IncompleteEnum: {result = TG_Kind_IncompleteEnum;}break; + case RADDBG_TypeKind_Bitfield: {result = TG_Kind_Bitfield;}break; + case RADDBG_TypeKind_Variadic: {result = TG_Kind_Variadic;}break; + } + return result; +} + +internal TG_MemberKind +tg_member_kind_from_raddbg_member_kind(RADDBG_MemberKind kind) +{ + TG_MemberKind result = TG_MemberKind_Null; + switch(kind) + { + default:{}break; + case RADDBG_MemberKind_DataField: {result = TG_MemberKind_DataField;}break; + case RADDBG_MemberKind_StaticData: {result = TG_MemberKind_StaticData;}break; + case RADDBG_MemberKind_Method: {result = TG_MemberKind_Method;}break; + case RADDBG_MemberKind_StaticMethod: {result = TG_MemberKind_StaticMethod;}break; + case RADDBG_MemberKind_VirtualMethod: {result = TG_MemberKind_VirtualMethod;}break; + case RADDBG_MemberKind_VTablePtr: {result = TG_MemberKind_VTablePtr;}break; + case RADDBG_MemberKind_Base: {result = TG_MemberKind_Base;}break; + case RADDBG_MemberKind_VirtualBase: {result = TG_MemberKind_VirtualBase;}break; + case RADDBG_MemberKind_NestedType: {result = TG_MemberKind_NestedType;}break; + } + return result; +} + +//////////////////////////////// +//~ rjf: Key Type Functions + +internal TG_Key +tg_key_zero(void) +{ + TG_Key key = zero_struct; + return key; +} + +internal TG_Key +tg_key_basic(TG_Kind kind) +{ + TG_Key key = {TG_KeyKind_Basic}; + key.u32[0] = (U32)kind; + return key; +} + +internal TG_Key +tg_key_ext(TG_Kind kind, U64 id) +{ + TG_Key key = {TG_KeyKind_Ext}; + key.u32[0] = (U32)kind; + if(TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) + { + key.kind = TG_KeyKind_Basic; + } + else + { + key.u64[0] = id; + } + return key; +} + +internal TG_Key +tg_key_reg(Architecture arch, REGS_RegCode code) +{ + TG_Key key = {TG_KeyKind_Reg}; + key.u32[0] = (U32)arch; + key.u64[0] = (U64)code; + return key; +} + +internal TG_Key +tg_key_reg_alias(Architecture arch, REGS_AliasCode code) +{ + TG_Key key = {TG_KeyKind_RegAlias}; + key.u32[0] = (U32)arch; + key.u64[0] = (U64)code; + return key; +} + +internal B32 +tg_key_match(TG_Key a, TG_Key b) +{ + B32 result = MemoryMatchStruct(&a, &b); + return result; +} + +//////////////////////////////// +//~ rjf: Graph Construction API + +internal TG_Graph * +tg_graph_begin(U64 address_size, U64 slot_count) +{ + if(tg_build_arena == 0) + { + tg_build_arena = arena_alloc(); + } + else + { + arena_clear(tg_build_arena); + } + TG_Graph *graph = push_array(tg_build_arena, TG_Graph, 1); + graph->address_size = address_size; + graph->content_hash_slots_count = slot_count; + graph->content_hash_slots = push_array(tg_build_arena, TG_Slot, graph->content_hash_slots_count); + graph->key_hash_slots_count = slot_count; + graph->key_hash_slots = push_array(tg_build_arena, TG_Slot, graph->key_hash_slots_count); + return graph; +} + +internal TG_Key +tg_cons_type_make(TG_Graph *graph, TG_Kind kind, TG_Key direct_type_key, U64 u64) +{ + U32 buffer[] = + { + (U32)kind, + (U32)direct_type_key.kind, + (U32)direct_type_key.u32[0], + (U32)((direct_type_key.u64[0] & 0x00000000ffffffffull)>> 0), + (U32)((direct_type_key.u64[0] & 0xffffffff00000000ull)>>32), + (U32)((u64 & 0x00000000ffffffffull)>> 0), + (U32)((u64 & 0xffffffff00000000ull)>> 32), + }; + U64 content_hash = tg_hash_from_string(5381, str8((U8 *)buffer, sizeof(buffer))); + U64 content_slot_idx = content_hash%graph->content_hash_slots_count; + TG_Slot *content_slot = &graph->content_hash_slots[content_slot_idx]; + TG_Node *node = 0; + for(TG_Node *n = content_slot->first; n != 0; n = n->content_hash_next) + { + if(n->cons_type.kind == kind && tg_key_match(n->cons_type.direct_type_key, direct_type_key)) + { + node = n; + break; + } + } + TG_Key result = zero_struct; + if(node == 0) + { + TG_Key key = {TG_KeyKind_Cons}; + key.u32[0] = (U32)kind; + key.u64[0] = graph->cons_id_gen; + U64 key_hash = tg_hash_from_string(5381, str8_struct(&key)); + U64 key_slot_idx = key_hash%graph->key_hash_slots_count; + TG_Slot *key_slot = &graph->key_hash_slots[key_slot_idx]; + graph->cons_id_gen += 1; + TG_Node *node = push_array(tg_build_arena, TG_Node, 1); + SLLQueuePush_N(content_slot->first, content_slot->last, node, content_hash_next); + SLLQueuePush_N(key_slot->first, key_slot->last, node, key_hash_next); + node->key = key; + node->cons_type.kind = kind; + node->cons_type.direct_type_key = direct_type_key; + node->cons_type.u64 = u64; + result = key; + } + else + { + result = node->key; + } + return result; +} + +//////////////////////////////// +//~ rjf: Graph Introspection API + +internal TG_Type * +tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_Type *type = &tg_type_nil; + U64 reg_byte_count = 0; + { + switch(key.kind) + { + default:{}break; + + //- rjf: basic type keys + case TG_KeyKind_Basic: + { + TG_Kind kind = (TG_Kind)key.u32[0]; + if(TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) + { + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->name = tg_kind_basic_string_table[kind]; + type->byte_size = tg_kind_basic_byte_size_table[kind]; + } + }break; + + //- rjf: constructed type keys + case TG_KeyKind_Cons: + { + U64 key_hash = tg_hash_from_string(5381, str8_struct(&key)); + U64 key_slot_idx = key_hash%graph->key_hash_slots_count; + TG_Slot *key_slot = &graph->key_hash_slots[key_slot_idx]; + for(TG_Node *node = key_slot->first; node != 0; node = node->key_hash_next) + { + if(tg_key_match(node->key, key)) + { + TG_ConsType *cons_type = &node->cons_type; + type = push_array(arena, TG_Type, 1); + type->kind = cons_type->kind; + type->direct_type_key = cons_type->direct_type_key; + type->count = cons_type->u64; + switch(type->kind) + { + default: + { + type->byte_size = graph->address_size; + }break; + case TG_Kind_Array: + { + U64 ptee_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, cons_type->direct_type_key); + type->byte_size = ptee_size * type->count; + }break; + } + } + } + }break; + + //- rjf: external (raddbg) type keys + case TG_KeyKind_Ext: + { + U64 type_node_idx = key.u64[0]; + if(0 <= type_node_idx && type_node_idx < rdbg->type_node_count) + { + RADDBG_TypeNode *rdbg_type = &rdbg->type_nodes[type_node_idx]; + TG_Kind kind = tg_kind_from_raddbg_type_kind(rdbg_type->kind); + + //- rjf: record types => unpack name * members & produce + if(RADDBG_TypeKind_FirstRecord <= rdbg_type->kind && rdbg_type->kind <= RADDBG_TypeKind_LastRecord) + { + // rjf: unpack name + String8 name = {0}; + name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + + // rjf: unpack members + TG_Member *members = 0; + U32 members_count = 0; + { + U32 udt_idx = rdbg_type->user_defined.udt_idx; + if(0 <= udt_idx && udt_idx < rdbg->udt_count) + { + RADDBG_UDT *udt = &rdbg->udts[udt_idx]; + members_count = udt->member_count; + members = push_array(arena, TG_Member, members_count); + if(0 <= udt->member_first && udt->member_first+udt->member_count < rdbg->member_count) + { + for(U32 member_idx = udt->member_first; + member_idx < udt->member_first+udt->member_count; + member_idx += 1) + { + RADDBG_Member *src = &rdbg->members[member_idx]; + TG_Kind member_type_kind = TG_Kind_Null; + if(src->type_idx < rdbg->type_node_count) + { + RADDBG_TypeNode *member_type = &rdbg->type_nodes[src->type_idx]; + member_type_kind = tg_kind_from_raddbg_type_kind(member_type->kind); + } + TG_Member *dst = &members[member_idx-udt->member_first]; + dst->kind = tg_member_kind_from_raddbg_member_kind(src->kind); + dst->type_key = tg_key_ext(member_type_kind, (U64)src->type_idx); + dst->name.str = raddbg_string_from_idx(rdbg, src->name_string_idx, &dst->name.size); + dst->off = (U64)src->off; + } + } + } + } + + // rjf: produce + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + type->byte_size = (U64)rdbg_type->byte_size; + type->count = members_count; + type->members = members; + } + + //- rjf: enum types => unpack name * values & produce + else if(rdbg_type->kind == RADDBG_TypeKind_Enum) + { + // rjf: unpack name + String8 name = {0}; + name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + + // rjf: unpack direct type + TG_Key direct_type_key = zero_struct; + if(rdbg_type->user_defined.direct_type_idx < type_node_idx) + { + RADDBG_TypeNode *direct_type_node = &rdbg->type_nodes[rdbg_type->user_defined.direct_type_idx]; + TG_Kind direct_type_kind = tg_kind_from_raddbg_type_kind(direct_type_node->kind); + direct_type_key = tg_key_ext(direct_type_kind, (U64)rdbg_type->user_defined.direct_type_idx); + } + + // rjf: unpack members + TG_EnumVal *enum_vals = 0; + U32 enum_vals_count = 0; + { + U32 udt_idx = rdbg_type->user_defined.udt_idx; + if(0 <= udt_idx && udt_idx < rdbg->udt_count) + { + RADDBG_UDT *udt = &rdbg->udts[udt_idx]; + enum_vals_count = udt->member_count; + enum_vals = push_array(arena, TG_EnumVal, enum_vals_count); + if(0 <= udt->member_first && udt->member_first+udt->member_count < rdbg->enum_member_count) + { + for(U32 member_idx = udt->member_first; + member_idx < udt->member_first+udt->member_count; + member_idx += 1) + { + RADDBG_EnumMember *src = &rdbg->enum_members[member_idx]; + TG_EnumVal *dst = &enum_vals[member_idx-udt->member_first]; + dst->name.str = raddbg_string_from_idx(rdbg, src->name_string_idx, &dst->name.size); + dst->val = src->val; + } + } + } + } + + // rjf: produce + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + type->byte_size = (U64)rdbg_type->byte_size; + type->count = enum_vals_count; + type->enum_vals = enum_vals; + type->direct_type_key = direct_type_key; + } + + //- rjf: constructed types + if(RADDBG_TypeKind_FirstConstructed <= rdbg_type->kind && rdbg_type->kind <= RADDBG_TypeKind_LastConstructed) + { + // rjf: unpack direct type + B32 direct_type_is_good = 0; + TG_Key direct_type_key = zero_struct; + U64 direct_type_byte_size = 0; + if(rdbg_type->constructed.direct_type_idx < type_node_idx) + { + RADDBG_TypeNode *direct_type_node = &rdbg->type_nodes[rdbg_type->constructed.direct_type_idx]; + TG_Kind direct_type_kind = tg_kind_from_raddbg_type_kind(direct_type_node->kind); + direct_type_key = tg_key_ext(direct_type_kind, (U64)rdbg_type->constructed.direct_type_idx); + direct_type_is_good = 1; + direct_type_byte_size = (U64)direct_type_node->byte_size; + } + + // rjf: construct based on kind + switch(rdbg_type->kind) + { + case RADDBG_TypeKind_Modifier: + { + TG_Flags flags = 0; + if(rdbg_type->flags & RADDBG_TypeModifierFlag_Const) + { + flags |= TG_Flag_Const; + } + if(rdbg_type->flags & RADDBG_TypeModifierFlag_Volatile) + { + flags |= TG_Flag_Volatile; + } + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->direct_type_key = direct_type_key; + type->byte_size = direct_type_byte_size; + type->flags = flags; + }break; + case RADDBG_TypeKind_Ptr: + case RADDBG_TypeKind_LRef: + case RADDBG_TypeKind_RRef: + { + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->direct_type_key = direct_type_key; + type->byte_size = graph->address_size; + }break; + + case RADDBG_TypeKind_Array: + { + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->direct_type_key = direct_type_key; + type->count = rdbg_type->constructed.count; + type->byte_size = direct_type_byte_size * type->count; + }break; + case RADDBG_TypeKind_Function: + { + U32 count = rdbg_type->constructed.count; + U32 idx_run_first = rdbg_type->constructed.param_idx_run_first; + U32 check_count = 0; + U32 *idx_run = raddbg_idx_run_from_first_count(rdbg, idx_run_first, count, &check_count); + if(check_count == count) + { + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->byte_size = graph->address_size; + type->direct_type_key = direct_type_key; + type->count = count; + type->param_type_keys = push_array_no_zero(arena, TG_Key, type->count); + for(U32 idx = 0; idx < type->count; idx += 1) + { + U32 param_type_idx = idx_run[idx]; + if(param_type_idx < type_node_idx) + { + RADDBG_TypeNode *param_type_node = &rdbg->type_nodes[param_type_idx]; + TG_Kind param_kind = tg_kind_from_raddbg_type_kind(param_type_node->kind); + type->param_type_keys[idx] = tg_key_ext(param_kind, (U64)param_type_idx); + } + else + { + break; + } + } + } + }break; + case RADDBG_TypeKind_Method: + { + // NOTE(rjf): for methods, the `direct` type points at the owner type. + // the return type, instead of being encoded via the `direct` type, is + // encoded via the first parameter. + U32 count = rdbg_type->constructed.count; + U32 idx_run_first = rdbg_type->constructed.param_idx_run_first; + U32 check_count = 0; + U32 *idx_run = raddbg_idx_run_from_first_count(rdbg, idx_run_first, count, &check_count); + if(check_count == count) + { + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->byte_size = graph->address_size; + type->owner_type_key = direct_type_key; + type->count = count; + type->param_type_keys = push_array_no_zero(arena, TG_Key, type->count); + for(U32 idx = 0; idx < type->count; idx += 1) + { + U32 param_type_idx = idx_run[idx]; + if(param_type_idx < type_node_idx) + { + RADDBG_TypeNode *param_type_node = &rdbg->type_nodes[param_type_idx]; + TG_Kind param_kind = tg_kind_from_raddbg_type_kind(param_type_node->kind); + type->param_type_keys[idx] = tg_key_ext(param_kind, (U64)param_type_idx); + } + else + { + break; + } + } + if(type->count > 0) + { + type->direct_type_key = type->param_type_keys[0]; + type->count -= 1; + type->param_type_keys += 1; + } + } + }break; + case RADDBG_TypeKind_MemberPtr: + { + // rjf: unpack owner type + TG_Key owner_type_key = zero_struct; + if(rdbg_type->constructed.owner_type_idx < type_node_idx) + { + RADDBG_TypeNode *owner_type_node = &rdbg->type_nodes[rdbg_type->constructed.owner_type_idx]; + TG_Kind owner_type_kind = tg_kind_from_raddbg_type_kind(owner_type_node->kind); + owner_type_key = tg_key_ext(owner_type_kind, (U64)rdbg_type->constructed.owner_type_idx); + } + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->byte_size = graph->address_size; + type->owner_type_key = owner_type_key; + type->direct_type_key = direct_type_key; + }break; + } + } + + //- rjf: alias types + else if(rdbg_type->kind == RADDBG_TypeKind_Alias) + { + // rjf: unpack name + String8 name = {0}; + name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + + // rjf: unpack direct type + TG_Key direct_type_key = zero_struct; + U64 direct_type_byte_size = 0; + if(rdbg_type->user_defined.direct_type_idx < type_node_idx) + { + RADDBG_TypeNode *direct_type_node = &rdbg->type_nodes[rdbg_type->user_defined.direct_type_idx]; + TG_Kind direct_type_kind = tg_kind_from_raddbg_type_kind(direct_type_node->kind); + direct_type_key = tg_key_ext(direct_type_kind, (U64)rdbg_type->user_defined.direct_type_idx); + direct_type_byte_size = direct_type_node->byte_size; + } + + // rjf: produce + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + type->byte_size = direct_type_byte_size; + type->direct_type_key = direct_type_key; + } + + //- rjf: incomplete types + else if(RADDBG_TypeKind_FirstIncomplete <= rdbg_type->kind && rdbg_type->kind <= RADDBG_TypeKind_LastIncomplete) + { + // rjf: unpack name + String8 name = {0}; + name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + + // rjf: produce + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->name = push_str8_copy(arena, name); + } + + } + }break; + + //- rjf: reg type keys + case TG_KeyKind_Reg: + { + Architecture arch = (Architecture)key.u32[0]; + REGS_RegCode code = (REGS_RegCode)key.u64[0]; + REGS_Rng rng = regs_reg_code_rng_table_from_architecture(arch)[code]; + reg_byte_count = (U64)rng.byte_size; + }goto build_reg_type; + case TG_KeyKind_RegAlias: + { + Architecture arch = (Architecture)key.u32[0]; + REGS_AliasCode code = (REGS_AliasCode)key.u64[0]; + REGS_Slice slice = regs_alias_code_slice_table_from_architecture(arch)[code]; + reg_byte_count = (U64)slice.byte_size; + }goto build_reg_type; + build_reg_type: + { + Temp scratch = scratch_begin(&arena, 1); + type = push_array(arena, TG_Type, 1); + type->kind = TG_Kind_Union; + type->name = push_str8f(arena, "reg_%I64u_bit", reg_byte_count*8); + type->byte_size = (U64)reg_byte_count; + + // rjf: build register type members + TG_MemberList members = {0}; + { + // rjf: build exact-sized members + { + if(type->byte_size == 16) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u128"); + mem->type_key = tg_key_basic(TG_Kind_U128); + } + if(type->byte_size == 8) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u64"); + mem->type_key = tg_key_basic(TG_Kind_U64); + } + if(type->byte_size == 4) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u32"); + mem->type_key = tg_key_basic(TG_Kind_U32); + } + if(type->byte_size == 2) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u16"); + mem->type_key = tg_key_basic(TG_Kind_U16); + } + if(type->byte_size == 1) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u8"); + mem->type_key = tg_key_basic(TG_Kind_U8); + } + } + + // rjf: build arrays for subdivisions + { + if(type->byte_size > 16 && type->byte_size%16 == 0) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u128s"); + mem->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_U128), reg_byte_count/16); + } + if(type->byte_size > 8 && type->byte_size%8 == 0) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u64s"); + mem->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_U64), reg_byte_count/8); + } + if(type->byte_size > 4 && type->byte_size%4 == 0) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u32s"); + mem->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_U32), reg_byte_count/4); + } + if(type->byte_size > 2 && type->byte_size%2 == 0) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u16s"); + mem->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_U16), reg_byte_count/2); + } + if(type->byte_size > 1) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("u8s"); + mem->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_U8), reg_byte_count); + } + if(type->byte_size > 4 && type->byte_size%4 == 0) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("f32s"); + mem->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_F32), reg_byte_count/4); + } + if(type->byte_size > 8 && type->byte_size%8 == 0) + { + TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1); + SLLQueuePush(members.first, members.last, n); + members.count += 1; + TG_Member *mem = &n->v; + mem->kind = TG_MemberKind_DataField; + mem->name = str8_lit("f64s"); + mem->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_F64), reg_byte_count/8); + } + } + } + + // rjf: commit members + type->count = members.count; + type->members = push_array_no_zero(arena, TG_Member, 1); + U64 idx = 0; + for(TG_MemberNode *n = members.first; n != 0; n = n->next, idx += 1) + { + MemoryCopyStruct(&type->members[idx], &n->v); + } + + scratch_end(scratch); + }break; + } + } + return type; +} + +internal TG_Key +tg_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_Key result = zero_struct; + switch(key.kind) + { + default:{}break; + case TG_KeyKind_Ext: + case TG_KeyKind_Cons: + { + Temp scratch = scratch_begin(0, 0); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + result = type->direct_type_key; + scratch_end(scratch); + }break; + } + return result; +} + +internal TG_Key +tg_owner_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_Key result = zero_struct; + switch(key.kind) + { + default:{}break; + case TG_KeyKind_Ext: + case TG_KeyKind_Cons: + { + Temp scratch = scratch_begin(0, 0); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + result = type->owner_type_key; + scratch_end(scratch); + }break; + } + return result; +} + +internal TG_Key +tg_ptee_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_Key result = key; + B32 passed_ptr = 0; + for(;;) + { + TG_Kind kind = tg_kind_from_key(result); + result = tg_direct_from_graph_raddbg_key(graph, rdbg, result); + if(kind == TG_Kind_Ptr || kind == TG_Kind_LRef || kind == TG_Kind_RRef) + { + passed_ptr = 1; + } + TG_Kind next_kind = tg_kind_from_key(result); + if(passed_ptr && + next_kind != TG_Kind_IncompleteStruct && + next_kind != TG_Kind_IncompleteUnion && + next_kind != TG_Kind_IncompleteEnum && + next_kind != TG_Kind_IncompleteClass && + next_kind != TG_Kind_Alias && + next_kind != TG_Kind_Modifier) + { + break; + } + if(kind == TG_Kind_Null) + { + break; + } + } + return result; +} + +internal TG_Key +tg_unwrapped_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_Key result = key; + for(B32 good = 1; good;) + { + TG_Kind kind = tg_kind_from_key(result); + if((TG_Kind_FirstIncomplete <= kind && kind <= TG_Kind_LastIncomplete) || + kind == TG_Kind_Modifier || + kind == TG_Kind_Alias) + { + result = tg_direct_from_graph_raddbg_key(graph, rdbg, result); + } + else + { + good = 0; + } + } + return result; +} + +internal U64 +tg_byte_size_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + U64 result = 0; + switch(key.kind) + { + default:{}break; + case TG_KeyKind_Basic: + { + TG_Kind kind = (TG_Kind)key.u32[0]; + result = tg_kind_basic_byte_size_table[kind]; + }break; + case TG_KeyKind_Ext: + case TG_KeyKind_Cons: + { + Temp scratch = scratch_begin(0, 0); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + result = type->byte_size; + scratch_end(scratch); + }break; + } + return result; +} + +internal TG_Kind +tg_kind_from_key(TG_Key key) +{ + TG_Kind kind = TG_Kind_Null; + switch(key.kind) + { + default:{}break; + case TG_KeyKind_Basic: {kind = (TG_Kind)key.u32[0];}break; + case TG_KeyKind_Ext: {kind = (TG_Kind)key.u32[0];}break; + case TG_KeyKind_Cons: {kind = (TG_Kind)key.u32[0];}break; + case TG_KeyKind_Reg: {kind = TG_Kind_Union;}break; + case TG_KeyKind_RegAlias:{kind = TG_Kind_Union;}break; + } + return kind; +} + +internal TG_MemberArray +tg_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_MemberArray result = {0}; + Temp scratch = scratch_begin(&arena, 1); + { + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + if(type->members != 0) + { + result.count = type->count; + result.v = push_array_no_zero(arena, TG_Member, result.count); + MemoryCopy(result.v, type->members, sizeof(TG_Member)*result.count); + for(U64 idx = 0; idx < result.count; idx += 1) + { + result.v[idx].name = push_str8_copy(arena, result.v[idx].name); + } + } + } + scratch_end(scratch); + return result; +} + +internal TG_MemberArray +tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + TG_MemberArray result = {0}; + Temp scratch = scratch_begin(&arena, 1); + { + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + if(type->members != 0) + { + U64 data_member_count = 0; + for(U64 member_idx = 0; member_idx < type->count; member_idx += 1) + { + if(type->members[member_idx].kind == TG_MemberKind_DataField) + { + data_member_count += 1; + } + } + result.count = data_member_count; + result.v = push_array_no_zero(arena, TG_Member, result.count); + U64 idx = 0; + for(U64 member_idx = 0; member_idx < type->count; member_idx += 1) + { + if(type->members[member_idx].kind == TG_MemberKind_DataField) + { + MemoryCopyStruct(&result.v[idx], &type->members[member_idx]); + result.v[idx].name = push_str8_copy(arena, result.v[idx].name); + idx += 1; + } + } + } + } + scratch_end(scratch); + return result; +} + +internal void +tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec, B32 skip_return) +{ + String8 keyword = {0}; + TG_Kind kind = tg_kind_from_key(key); + switch(kind) + { + default: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + str8_list_push(arena, out, push_str8_copy(arena, type->name)); + str8_list_push(arena, out, str8_lit(" ")); + scratch_end(scratch); + }break; + + case TG_Kind_Bitfield: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, prec, skip_return); + }break; + + case TG_Kind_Modifier: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Key direct = type->direct_type_key; + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + if(type->flags & TG_Flag_Const) + { + str8_list_push(arena, out, str8_lit("const ")); + } + if(type->flags & TG_Flag_Volatile) + { + str8_list_push(arena, out, str8_lit("volatile ")); + } + scratch_end(scratch); + }break; + + case TG_Kind_Variadic: + { + str8_list_push(arena, out, str8_lit("...")); + }break; + + case TG_Kind_Struct: + case TG_Kind_Union: + case TG_Kind_Enum: + case TG_Kind_Class: + case TG_Kind_Alias: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + str8_list_push(arena, out, push_str8_copy(arena, type->name)); + str8_list_push(arena, out, str8_lit(" ")); + scratch_end(scratch); + }break; + + case TG_Kind_IncompleteStruct: keyword = str8_lit("struct"); goto fwd_udt; + case TG_Kind_IncompleteUnion: keyword = str8_lit("union"); goto fwd_udt; + case TG_Kind_IncompleteEnum: keyword = str8_lit("enum"); goto fwd_udt; + case TG_Kind_IncompleteClass: keyword = str8_lit("class"); goto fwd_udt; + fwd_udt:; + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + str8_list_push(arena, out, keyword); + str8_list_push(arena, out, str8_lit(" ")); + str8_list_push(arena, out, push_str8_copy(arena, type->name)); + str8_list_push(arena, out, str8_lit(" ")); + scratch_end(scratch); + }break; + + case TG_Kind_Array: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 2, skip_return); + if(prec == 1) + { + str8_list_push(arena, out, str8_lit("(")); + } + }break; + + case TG_Kind_Function: + { + if(!skip_return) + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 2, 0); + } + if(prec == 1) + { + str8_list_push(arena, out, str8_lit("(")); + } + }break; + + case TG_Kind_Ptr: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + str8_list_push(arena, out, str8_lit("*")); + }break; + + case TG_Kind_LRef: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + str8_list_push(arena, out, str8_lit("&")); + }break; + + case TG_Kind_RRef: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + str8_list_push(arena, out, str8_lit("&&")); + }break; + + case TG_Kind_MemberPtr: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Key direct = type->direct_type_key; + tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + TG_Type *container = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, type->owner_type_key); + if(container->kind != TG_Kind_Null) + { + str8_list_push(arena, out, push_str8_copy(arena, container->name)); + } + else + { + str8_list_push(arena, out, str8_lit("")); + } + str8_list_push(arena, out, str8_lit("::*")); + scratch_end(scratch); + }break; + } +} + +internal void +tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec) +{ + TG_Kind kind = tg_kind_from_key(key); + switch(kind) + { + default:{}break; + + case TG_Kind_Bitfield: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_rhs_string_from_key(arena, graph, rdbg, direct, out, prec); + }break; + + case TG_Kind_Modifier: + case TG_Kind_Ptr: + case TG_Kind_LRef: + case TG_Kind_RRef: + case TG_Kind_MemberPtr: + { + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_rhs_string_from_key(arena, graph, rdbg, direct, out, 1); + }break; + + case TG_Kind_Array: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + if(prec == 1) + { + str8_list_push(arena, out, str8_lit(")")); + } + String8 count_str = str8_from_u64(arena, type->count, 10, 0, 0); + str8_list_push(arena, out, str8_lit("[")); + str8_list_push(arena, out, count_str); + str8_list_push(arena, out, str8_lit("]")); + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_rhs_string_from_key(arena, graph, rdbg, direct, out, 2); + scratch_end(scratch); + }break; + + case TG_Kind_Function: + { + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + if(prec == 1) + { + str8_list_push(arena, out, str8_lit(")")); + } + + // parameters + if(type->count == 0) + { + str8_list_push(arena, out, str8_lit("(void)")); + } + else + { + str8_list_push(arena, out, str8_lit("(")); + U64 param_count = type->count; + TG_Key *param_type_keys = type->param_type_keys; + for(U64 param_idx = 0; param_idx < param_count; param_idx += 1) + { + TG_Key param_type_key = param_type_keys[param_idx]; + String8 param_str = tg_string_from_key(arena, graph, rdbg, param_type_key); + String8 param_str_trimmed = str8_skip_chop_whitespace(param_str); + str8_list_push(arena, out, param_str_trimmed); + if(param_idx+1 < param_count) + { + str8_list_push(arena, out, str8_lit(", ")); + } + } + str8_list_push(arena, out, str8_lit(")")); + } + TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); + tg_rhs_string_from_key(arena, graph, rdbg, direct, out, 2); + scratch_end(scratch); + }break; + } +} + +internal String8 +tg_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + tg_lhs_string_from_key(scratch.arena, graph, rdbg, key, &list, 0, 0); + tg_rhs_string_from_key(scratch.arena, graph, rdbg, key, &list, 0); + String8 result = str8_list_join(arena, &list, 0); + scratch_end(scratch); + return result; +} diff --git a/src/type_graph/type_graph.h b/src/type_graph/type_graph.h new file mode 100644 index 00000000..9003f13e --- /dev/null +++ b/src/type_graph/type_graph.h @@ -0,0 +1,221 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef TYPE_GRAPH_NEW_H +#define TYPE_GRAPH_NEW_H + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/type_graph.meta.h" + +//////////////////////////////// +//~ rjf: Key Types + +typedef enum TG_KeyKind +{ + TG_KeyKind_Null, + TG_KeyKind_Basic, + TG_KeyKind_Ext, + TG_KeyKind_Cons, + TG_KeyKind_Reg, + TG_KeyKind_RegAlias, +} +TG_KeyKind; + +typedef struct TG_Key TG_Key; +struct TG_Key +{ + TG_KeyKind kind; + U32 u32[1]; // basic -> type_kind; cons -> type_kind; ext -> type_kind; reg -> arch + U64 u64[1]; // ext -> unique id; cons -> idx; reg -> code +}; + +//////////////////////////////// +//~ rjf: Graph Types + +typedef struct TG_ConsType TG_ConsType; +struct TG_ConsType +{ + TG_Kind kind; + TG_Key direct_type_key; + U64 u64; +}; + +typedef struct TG_Node TG_Node; +struct TG_Node +{ + TG_Node *key_hash_next; + TG_Node *content_hash_next; + TG_Key key; + TG_ConsType cons_type; +}; + +typedef struct TG_Slot TG_Slot; +struct TG_Slot +{ + TG_Node *first; + TG_Node *last; +}; + +typedef struct TG_Graph TG_Graph; +struct TG_Graph +{ + U64 address_size; + U64 cons_id_gen; + U64 content_hash_slots_count; + TG_Slot *content_hash_slots; + U64 key_hash_slots_count; + TG_Slot *key_hash_slots; +}; + +//////////////////////////////// +//~ rjf: Extracted Info Types + +typedef enum TG_MemberKind +{ + TG_MemberKind_Null, + TG_MemberKind_DataField, + TG_MemberKind_StaticData, + TG_MemberKind_Method, + TG_MemberKind_StaticMethod, + TG_MemberKind_VirtualMethod, + TG_MemberKind_VTablePtr, + TG_MemberKind_Base, + TG_MemberKind_VirtualBase, + TG_MemberKind_NestedType, + TG_MemberKind_COUNT +} +TG_MemberKind; + +typedef U32 TG_Flags; +enum +{ + TG_Flag_Const = (1<<0), + TG_Flag_Volatile = (1<<1), +}; + +typedef struct TG_Member TG_Member; +struct TG_Member +{ + TG_MemberKind kind; + TG_Key type_key; + String8 name; + U64 off; +}; + +typedef struct TG_MemberNode TG_MemberNode; +struct TG_MemberNode +{ + TG_MemberNode *next; + TG_Member v; +}; + +typedef struct TG_MemberList TG_MemberList; +struct TG_MemberList +{ + TG_MemberNode *first; + TG_MemberNode *last; + U64 count; +}; + +typedef struct TG_MemberArray TG_MemberArray; +struct TG_MemberArray +{ + TG_Member *v; + U64 count; +}; + +typedef struct TG_EnumVal TG_EnumVal; +struct TG_EnumVal +{ + String8 name; + U64 val; +}; + +typedef struct TG_EnumValArray TG_EnumValArray; +struct TG_EnumValArray +{ + TG_EnumVal *v; + U64 count; +}; + +typedef struct TG_Type TG_Type; +struct TG_Type +{ + TG_Kind kind; + TG_Flags flags; + String8 name; + U64 byte_size; + U64 count; + U32 off; + TG_Key direct_type_key; + TG_Key owner_type_key; + TG_Key *param_type_keys; + TG_Member *members; + TG_EnumVal *enum_vals; +}; + +//////////////////////////////// +//~ rjf: Globals + +global read_only TG_Type tg_type_nil = +{ + /* kind */ TG_Kind_Null, + /* flags */ 0, + /* name */ {(U8*)"",5}, +}; + +global read_only TG_Type tg_type_variadic = +{ + /* kind */ TG_Kind_Variadic, + /* flags */ 0, + /* name */ {(U8*)"...",3}, +}; + +thread_static Arena *tg_build_arena = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 tg_hash_from_string(U64 seed, String8 string); + +//////////////////////////////// +//~ rjf: RADDBG <-> TG Enum Conversions + +internal TG_Kind tg_kind_from_raddbg_type_kind(RADDBG_TypeKind kind); +internal TG_MemberKind tg_member_kind_from_raddbg_member_kind(RADDBG_MemberKind kind); + +//////////////////////////////// +//~ rjf: Key Type Functions + +internal TG_Key tg_key_zero(void); +internal TG_Key tg_key_basic(TG_Kind kind); +internal TG_Key tg_key_ext(TG_Kind kind, U64 id); +internal TG_Key tg_key_reg(Architecture arch, REGS_RegCode code); +internal TG_Key tg_key_reg_alias(Architecture arch, REGS_AliasCode code); +internal B32 tg_key_match(TG_Key a, TG_Key b); + +//////////////////////////////// +//~ rjf: Graph Construction API + +internal TG_Graph *tg_graph_begin(U64 address_size, U64 slot_count); +internal TG_Key tg_cons_type_make(TG_Graph *graph, TG_Kind kind, TG_Key direct_type_key, U64 u64); + +//////////////////////////////// +//~ rjf: Graph Introspection API + +internal TG_Type *tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Key tg_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Key tg_owner_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Key tg_ptee_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Key tg_unwrapped_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal U64 tg_byte_size_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Kind tg_kind_from_key(TG_Key key); +internal TG_MemberArray tg_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_MemberArray tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal void tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec, B32 skip_return); +internal void tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec); +internal String8 tg_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); + +#endif // TYPE_GRAPH_NEW_H diff --git a/src/type_graph/type_graph.mc b/src/type_graph/type_graph.mc new file mode 100644 index 00000000..2a22968d --- /dev/null +++ b/src/type_graph/type_graph.mc @@ -0,0 +1,97 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Tables + +@table(name basic_string basic_byte_size) +// NOTE(rjf): basic_byte_size == 0xFF? => address sized +TG_KindTable: +{ + {Null "" 0 } + {Void "void" 0 } + {Handle "HANDLE" 0xFF } + {Char8 "char8" 1 } + {Char16 "char16" 2 } + {Char32 "char32" 4 } + {UChar8 "uchar8" 1 } + {UChar16 "uchar16" 2 } + {UChar32 "uchar32" 4 } + {U8 "U8" 1 } + {U16 "U16" 2 } + {U32 "U32" 4 } + {U64 "U64" 8 } + {U128 "U128" 16 } + {U256 "U256" 32 } + {U512 "U512" 64 } + {S8 "S8" 1 } + {S16 "S16" 2 } + {S32 "S32" 4 } + {S64 "S64" 8 } + {S128 "S128" 16 } + {S256 "S256" 32 } + {S512 "S512" 64 } + {Bool "bool" 1 } + {F16 "F16" 2 } + {F32 "F32" 4 } + {F32PP "F32PP" 4 } + {F48 "F48" 6 } + {F64 "F64" 8 } + {F80 "F80" 10 } + {F128 "F128" 16 } + {ComplexF32 "ComplexF32" 8 } + {ComplexF64 "ComplexF64" 16 } + {ComplexF80 "ComplexF80" 20 } + {ComplexF128 "ComplexF128" 32 } + {Modifier "" 0 } + {Ptr "" 0 } + {LRef "" 0 } + {RRef "" 0 } + {Array "" 0 } + {Function "" 0 } + {Method "" 0 } + {MemberPtr "" 0 } + {Struct "" 0 } + {Class "" 0 } + {Union "" 0 } + {Enum "" 0 } + {Alias "" 0 } + {IncompleteStruct "" 0 } + {IncompleteUnion "" 0 } + {IncompleteClass "" 0 } + {IncompleteEnum "" 0 } + {Bitfield "" 0 } + {Variadic "" 0 } +} + +//////////////////////////////// +//~ rjf: Generators + +@table_gen_enum +TG_Kind: +{ + @expand(TG_KindTable a) `TG_Kind_$(a.name),`; + `TG_Kind_COUNT,`; + `TG_Kind_FirstBasic = TG_Kind_Void,`; + `TG_Kind_LastBasic = TG_Kind_ComplexF128,`; + `TG_Kind_FirstInteger = TG_Kind_Char8,`; + `TG_Kind_LastInteger = TG_Kind_S512,`; + `TG_Kind_FirstSigned1 = TG_Kind_Char8,`; + `TG_Kind_LastSigned1 = TG_Kind_Char32,`; + `TG_Kind_FirstSigned2 = TG_Kind_S8,`; + `TG_Kind_LastSigned2 = TG_Kind_S512,`; + `TG_Kind_FirstIncomplete = TG_Kind_IncompleteStruct,`; + `TG_Kind_LastIncomplete = TG_Kind_IncompleteEnum,`; +} + +@table_gen_data(type:U8, fallback:0) +tg_kind_basic_byte_size_table: +{ + @expand(TG_KindTable a) `$(a.basic_byte_size),`; +} + +@table_gen_data(type:String8, fallback:`{0}`) +tg_kind_basic_string_table: +{ + @expand(TG_KindTable a) `str8_lit_comp("$(a.basic_string)"),`; +} diff --git a/src/ui/generated/ui.meta.c b/src/ui/generated/ui.meta.c new file mode 100644 index 00000000..1f13055a --- /dev/null +++ b/src/ui/generated/ui.meta.c @@ -0,0 +1,135 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +internal UI_Box * ui_push_parent(UI_Box * v) {return UI_StackPush(parent, v);} +internal Axis2 ui_push_child_layout_axis(Axis2 v) {return UI_StackPush(child_layout_axis, v);} +internal F32 ui_push_fixed_x(F32 v) {return UI_StackPush(fixed_x, v);} +internal F32 ui_push_fixed_y(F32 v) {return UI_StackPush(fixed_y, v);} +internal F32 ui_push_fixed_width(F32 v) {return UI_StackPush(fixed_width, v);} +internal F32 ui_push_fixed_height(F32 v) {return UI_StackPush(fixed_height, v);} +internal UI_Size ui_push_pref_width(UI_Size v) {return UI_StackPush(pref_width, v);} +internal UI_Size ui_push_pref_height(UI_Size v) {return UI_StackPush(pref_height, v);} +internal UI_BoxFlags ui_push_flags(UI_BoxFlags v) {return UI_StackPush(flags, v);} +internal U32 ui_push_fastpath_codepoint(U32 v) {return UI_StackPush(fastpath_codepoint, v);} +internal Vec4F32 ui_push_background_color(Vec4F32 v) {return UI_StackPush(background_color, v);} +internal Vec4F32 ui_push_text_color(Vec4F32 v) {return UI_StackPush(text_color, v);} +internal Vec4F32 ui_push_border_color(Vec4F32 v) {return UI_StackPush(border_color, v);} +internal Vec4F32 ui_push_overlay_color(Vec4F32 v) {return UI_StackPush(overlay_color, v);} +internal Vec4F32 ui_push_text_select_color(Vec4F32 v) {return UI_StackPush(text_select_color, v);} +internal Vec4F32 ui_push_text_cursor_color(Vec4F32 v) {return UI_StackPush(text_cursor_color, v);} +internal OS_Cursor ui_push_hover_cursor(OS_Cursor v) {return UI_StackPush(hover_cursor, v);} +internal F_Tag ui_push_font(F_Tag v) {return UI_StackPush(font, v);} +internal F32 ui_push_font_size(F32 v) {return UI_StackPush(font_size, v);} +internal F32 ui_push_corner_radius_00(F32 v) {return UI_StackPush(corner_radius_00, v);} +internal F32 ui_push_corner_radius_01(F32 v) {return UI_StackPush(corner_radius_01, v);} +internal F32 ui_push_corner_radius_10(F32 v) {return UI_StackPush(corner_radius_10, v);} +internal F32 ui_push_corner_radius_11(F32 v) {return UI_StackPush(corner_radius_11, v);} +internal F32 ui_push_blur_size(F32 v) {return UI_StackPush(blur_size, v);} +internal F32 ui_push_text_padding(F32 v) {return UI_StackPush(text_padding, v);} +internal UI_TextAlign ui_push_text_alignment(UI_TextAlign v) {return UI_StackPush(text_alignment, v);} +internal UI_Box * ui_pop_parent(void) {UI_Box * popped; return UI_StackPop(parent, popped);} +internal Axis2 ui_pop_child_layout_axis(void) {Axis2 popped; return UI_StackPop(child_layout_axis, popped);} +internal F32 ui_pop_fixed_x(void) {F32 popped; return UI_StackPop(fixed_x, popped);} +internal F32 ui_pop_fixed_y(void) {F32 popped; return UI_StackPop(fixed_y, popped);} +internal F32 ui_pop_fixed_width(void) {F32 popped; return UI_StackPop(fixed_width, popped);} +internal F32 ui_pop_fixed_height(void) {F32 popped; return UI_StackPop(fixed_height, popped);} +internal UI_Size ui_pop_pref_width(void) {UI_Size popped; return UI_StackPop(pref_width, popped);} +internal UI_Size ui_pop_pref_height(void) {UI_Size popped; return UI_StackPop(pref_height, popped);} +internal UI_BoxFlags ui_pop_flags(void) {UI_BoxFlags popped; return UI_StackPop(flags, popped);} +internal U32 ui_pop_fastpath_codepoint(void) {U32 popped; return UI_StackPop(fastpath_codepoint, popped);} +internal Vec4F32 ui_pop_background_color(void) {Vec4F32 popped; return UI_StackPop(background_color, popped);} +internal Vec4F32 ui_pop_text_color(void) {Vec4F32 popped; return UI_StackPop(text_color, popped);} +internal Vec4F32 ui_pop_border_color(void) {Vec4F32 popped; return UI_StackPop(border_color, popped);} +internal Vec4F32 ui_pop_overlay_color(void) {Vec4F32 popped; return UI_StackPop(overlay_color, popped);} +internal Vec4F32 ui_pop_text_select_color(void) {Vec4F32 popped; return UI_StackPop(text_select_color, popped);} +internal Vec4F32 ui_pop_text_cursor_color(void) {Vec4F32 popped; return UI_StackPop(text_cursor_color, popped);} +internal OS_Cursor ui_pop_hover_cursor(void) {OS_Cursor popped; return UI_StackPop(hover_cursor, popped);} +internal F_Tag ui_pop_font(void) {F_Tag popped; return UI_StackPop(font, popped);} +internal F32 ui_pop_font_size(void) {F32 popped; return UI_StackPop(font_size, popped);} +internal F32 ui_pop_corner_radius_00(void) {F32 popped; return UI_StackPop(corner_radius_00, popped);} +internal F32 ui_pop_corner_radius_01(void) {F32 popped; return UI_StackPop(corner_radius_01, popped);} +internal F32 ui_pop_corner_radius_10(void) {F32 popped; return UI_StackPop(corner_radius_10, popped);} +internal F32 ui_pop_corner_radius_11(void) {F32 popped; return UI_StackPop(corner_radius_11, popped);} +internal F32 ui_pop_blur_size(void) {F32 popped; return UI_StackPop(blur_size, popped);} +internal F32 ui_pop_text_padding(void) {F32 popped; return UI_StackPop(text_padding, popped);} +internal UI_TextAlign ui_pop_text_alignment(void) {UI_TextAlign popped; return UI_StackPop(text_alignment, popped);} +internal UI_Box * ui_top_parent(void) {return UI_StackTop(parent);} +internal Axis2 ui_top_child_layout_axis(void) {return UI_StackTop(child_layout_axis);} +internal F32 ui_top_fixed_x(void) {return UI_StackTop(fixed_x);} +internal F32 ui_top_fixed_y(void) {return UI_StackTop(fixed_y);} +internal F32 ui_top_fixed_width(void) {return UI_StackTop(fixed_width);} +internal F32 ui_top_fixed_height(void) {return UI_StackTop(fixed_height);} +internal UI_Size ui_top_pref_width(void) {return UI_StackTop(pref_width);} +internal UI_Size ui_top_pref_height(void) {return UI_StackTop(pref_height);} +internal UI_BoxFlags ui_top_flags(void) {return UI_StackTop(flags);} +internal U32 ui_top_fastpath_codepoint(void) {return UI_StackTop(fastpath_codepoint);} +internal Vec4F32 ui_top_background_color(void) {return UI_StackTop(background_color);} +internal Vec4F32 ui_top_text_color(void) {return UI_StackTop(text_color);} +internal Vec4F32 ui_top_border_color(void) {return UI_StackTop(border_color);} +internal Vec4F32 ui_top_overlay_color(void) {return UI_StackTop(overlay_color);} +internal Vec4F32 ui_top_text_select_color(void) {return UI_StackTop(text_select_color);} +internal Vec4F32 ui_top_text_cursor_color(void) {return UI_StackTop(text_cursor_color);} +internal OS_Cursor ui_top_hover_cursor(void) {return UI_StackTop(hover_cursor);} +internal F_Tag ui_top_font(void) {return UI_StackTop(font);} +internal F32 ui_top_font_size(void) {return UI_StackTop(font_size);} +internal F32 ui_top_corner_radius_00(void) {return UI_StackTop(corner_radius_00);} +internal F32 ui_top_corner_radius_01(void) {return UI_StackTop(corner_radius_01);} +internal F32 ui_top_corner_radius_10(void) {return UI_StackTop(corner_radius_10);} +internal F32 ui_top_corner_radius_11(void) {return UI_StackTop(corner_radius_11);} +internal F32 ui_top_blur_size(void) {return UI_StackTop(blur_size);} +internal F32 ui_top_text_padding(void) {return UI_StackTop(text_padding);} +internal UI_TextAlign ui_top_text_alignment(void) {return UI_StackTop(text_alignment);} +internal UI_Box * ui_bottom_parent(void) {return UI_StackBottom(parent);} +internal Axis2 ui_bottom_child_layout_axis(void) {return UI_StackBottom(child_layout_axis);} +internal F32 ui_bottom_fixed_x(void) {return UI_StackBottom(fixed_x);} +internal F32 ui_bottom_fixed_y(void) {return UI_StackBottom(fixed_y);} +internal F32 ui_bottom_fixed_width(void) {return UI_StackBottom(fixed_width);} +internal F32 ui_bottom_fixed_height(void) {return UI_StackBottom(fixed_height);} +internal UI_Size ui_bottom_pref_width(void) {return UI_StackBottom(pref_width);} +internal UI_Size ui_bottom_pref_height(void) {return UI_StackBottom(pref_height);} +internal UI_BoxFlags ui_bottom_flags(void) {return UI_StackBottom(flags);} +internal U32 ui_bottom_fastpath_codepoint(void) {return UI_StackBottom(fastpath_codepoint);} +internal Vec4F32 ui_bottom_background_color(void) {return UI_StackBottom(background_color);} +internal Vec4F32 ui_bottom_text_color(void) {return UI_StackBottom(text_color);} +internal Vec4F32 ui_bottom_border_color(void) {return UI_StackBottom(border_color);} +internal Vec4F32 ui_bottom_overlay_color(void) {return UI_StackBottom(overlay_color);} +internal Vec4F32 ui_bottom_text_select_color(void) {return UI_StackBottom(text_select_color);} +internal Vec4F32 ui_bottom_text_cursor_color(void) {return UI_StackBottom(text_cursor_color);} +internal OS_Cursor ui_bottom_hover_cursor(void) {return UI_StackBottom(hover_cursor);} +internal F_Tag ui_bottom_font(void) {return UI_StackBottom(font);} +internal F32 ui_bottom_font_size(void) {return UI_StackBottom(font_size);} +internal F32 ui_bottom_corner_radius_00(void) {return UI_StackBottom(corner_radius_00);} +internal F32 ui_bottom_corner_radius_01(void) {return UI_StackBottom(corner_radius_01);} +internal F32 ui_bottom_corner_radius_10(void) {return UI_StackBottom(corner_radius_10);} +internal F32 ui_bottom_corner_radius_11(void) {return UI_StackBottom(corner_radius_11);} +internal F32 ui_bottom_blur_size(void) {return UI_StackBottom(blur_size);} +internal F32 ui_bottom_text_padding(void) {return UI_StackBottom(text_padding);} +internal UI_TextAlign ui_bottom_text_alignment(void) {return UI_StackBottom(text_alignment);} +internal UI_Box * ui_set_next_parent(UI_Box * v) {return UI_StackSetNext(parent, v);} +internal Axis2 ui_set_next_child_layout_axis(Axis2 v) {return UI_StackSetNext(child_layout_axis, v);} +internal F32 ui_set_next_fixed_x(F32 v) {return UI_StackSetNext(fixed_x, v);} +internal F32 ui_set_next_fixed_y(F32 v) {return UI_StackSetNext(fixed_y, v);} +internal F32 ui_set_next_fixed_width(F32 v) {return UI_StackSetNext(fixed_width, v);} +internal F32 ui_set_next_fixed_height(F32 v) {return UI_StackSetNext(fixed_height, v);} +internal UI_Size ui_set_next_pref_width(UI_Size v) {return UI_StackSetNext(pref_width, v);} +internal UI_Size ui_set_next_pref_height(UI_Size v) {return UI_StackSetNext(pref_height, v);} +internal UI_BoxFlags ui_set_next_flags(UI_BoxFlags v) {return UI_StackSetNext(flags, v);} +internal U32 ui_set_next_fastpath_codepoint(U32 v) {return UI_StackSetNext(fastpath_codepoint, v);} +internal Vec4F32 ui_set_next_background_color(Vec4F32 v) {return UI_StackSetNext(background_color, v);} +internal Vec4F32 ui_set_next_text_color(Vec4F32 v) {return UI_StackSetNext(text_color, v);} +internal Vec4F32 ui_set_next_border_color(Vec4F32 v) {return UI_StackSetNext(border_color, v);} +internal Vec4F32 ui_set_next_overlay_color(Vec4F32 v) {return UI_StackSetNext(overlay_color, v);} +internal Vec4F32 ui_set_next_text_select_color(Vec4F32 v) {return UI_StackSetNext(text_select_color, v);} +internal Vec4F32 ui_set_next_text_cursor_color(Vec4F32 v) {return UI_StackSetNext(text_cursor_color, v);} +internal OS_Cursor ui_set_next_hover_cursor(OS_Cursor v) {return UI_StackSetNext(hover_cursor, v);} +internal F_Tag ui_set_next_font(F_Tag v) {return UI_StackSetNext(font, v);} +internal F32 ui_set_next_font_size(F32 v) {return UI_StackSetNext(font_size, v);} +internal F32 ui_set_next_corner_radius_00(F32 v) {return UI_StackSetNext(corner_radius_00, v);} +internal F32 ui_set_next_corner_radius_01(F32 v) {return UI_StackSetNext(corner_radius_01, v);} +internal F32 ui_set_next_corner_radius_10(F32 v) {return UI_StackSetNext(corner_radius_10, v);} +internal F32 ui_set_next_corner_radius_11(F32 v) {return UI_StackSetNext(corner_radius_11, v);} +internal F32 ui_set_next_blur_size(F32 v) {return UI_StackSetNext(blur_size, v);} +internal F32 ui_set_next_text_padding(F32 v) {return UI_StackSetNext(text_padding, v);} +internal UI_TextAlign ui_set_next_text_alignment(UI_TextAlign v) {return UI_StackSetNext(text_alignment, v);} diff --git a/src/ui/generated/ui.meta.h b/src/ui/generated/ui.meta.h new file mode 100644 index 00000000..3625e587 --- /dev/null +++ b/src/ui/generated/ui.meta.h @@ -0,0 +1,252 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef UI_META_H +#define UI_META_H + +#define UI_StackDecls struct{\ +struct { UI_Box * active; UI_Box * v[64]; U64 count; B32 auto_pop; } parent;\ +struct { Axis2 active; Axis2 v[64]; U64 count; B32 auto_pop; } child_layout_axis;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } fixed_x;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } fixed_y;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } fixed_width;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } fixed_height;\ +struct { UI_Size active; UI_Size v[64]; U64 count; B32 auto_pop; } pref_width;\ +struct { UI_Size active; UI_Size v[64]; U64 count; B32 auto_pop; } pref_height;\ +struct { UI_BoxFlags active; UI_BoxFlags v[64]; U64 count; B32 auto_pop; } flags;\ +struct { U32 active; U32 v[64]; U64 count; B32 auto_pop; } fastpath_codepoint;\ +struct { Vec4F32 active; Vec4F32 v[64]; U64 count; B32 auto_pop; } background_color;\ +struct { Vec4F32 active; Vec4F32 v[64]; U64 count; B32 auto_pop; } text_color;\ +struct { Vec4F32 active; Vec4F32 v[64]; U64 count; B32 auto_pop; } border_color;\ +struct { Vec4F32 active; Vec4F32 v[64]; U64 count; B32 auto_pop; } overlay_color;\ +struct { Vec4F32 active; Vec4F32 v[64]; U64 count; B32 auto_pop; } text_select_color;\ +struct { Vec4F32 active; Vec4F32 v[64]; U64 count; B32 auto_pop; } text_cursor_color;\ +struct { OS_Cursor active; OS_Cursor v[64]; U64 count; B32 auto_pop; } hover_cursor;\ +struct { F_Tag active; F_Tag v[64]; U64 count; B32 auto_pop; } font;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } font_size;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } corner_radius_00;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } corner_radius_01;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } corner_radius_10;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } corner_radius_11;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } blur_size;\ +struct { F32 active; F32 v[64]; U64 count; B32 auto_pop; } text_padding;\ +struct { UI_TextAlign active; UI_TextAlign v[64]; U64 count; B32 auto_pop; } text_alignment;\ +} +#define UI_ZeroAllStacks(ui_state) do{\ +MemoryZeroStruct(&ui_state->parent);\ +MemoryZeroStruct(&ui_state->child_layout_axis);\ +MemoryZeroStruct(&ui_state->fixed_x);\ +MemoryZeroStruct(&ui_state->fixed_y);\ +MemoryZeroStruct(&ui_state->fixed_width);\ +MemoryZeroStruct(&ui_state->fixed_height);\ +MemoryZeroStruct(&ui_state->pref_width);\ +MemoryZeroStruct(&ui_state->pref_height);\ +MemoryZeroStruct(&ui_state->flags);\ +MemoryZeroStruct(&ui_state->fastpath_codepoint);\ +MemoryZeroStruct(&ui_state->background_color);\ +MemoryZeroStruct(&ui_state->text_color);\ +MemoryZeroStruct(&ui_state->border_color);\ +MemoryZeroStruct(&ui_state->overlay_color);\ +MemoryZeroStruct(&ui_state->text_select_color);\ +MemoryZeroStruct(&ui_state->text_cursor_color);\ +MemoryZeroStruct(&ui_state->hover_cursor);\ +MemoryZeroStruct(&ui_state->font);\ +MemoryZeroStruct(&ui_state->font_size);\ +MemoryZeroStruct(&ui_state->corner_radius_00);\ +MemoryZeroStruct(&ui_state->corner_radius_01);\ +MemoryZeroStruct(&ui_state->corner_radius_10);\ +MemoryZeroStruct(&ui_state->corner_radius_11);\ +MemoryZeroStruct(&ui_state->blur_size);\ +MemoryZeroStruct(&ui_state->text_padding);\ +MemoryZeroStruct(&ui_state->text_alignment);\ +} while(0) +#define UI_AutoPopAllStacks(ui_state) do{\ +if(ui_state->parent.auto_pop) {ui_state->parent.auto_pop = 0; ui_pop_parent();}\ +if(ui_state->child_layout_axis.auto_pop) {ui_state->child_layout_axis.auto_pop = 0; ui_pop_child_layout_axis();}\ +if(ui_state->fixed_x.auto_pop) {ui_state->fixed_x.auto_pop = 0; ui_pop_fixed_x();}\ +if(ui_state->fixed_y.auto_pop) {ui_state->fixed_y.auto_pop = 0; ui_pop_fixed_y();}\ +if(ui_state->fixed_width.auto_pop) {ui_state->fixed_width.auto_pop = 0; ui_pop_fixed_width();}\ +if(ui_state->fixed_height.auto_pop) {ui_state->fixed_height.auto_pop = 0; ui_pop_fixed_height();}\ +if(ui_state->pref_width.auto_pop) {ui_state->pref_width.auto_pop = 0; ui_pop_pref_width();}\ +if(ui_state->pref_height.auto_pop) {ui_state->pref_height.auto_pop = 0; ui_pop_pref_height();}\ +if(ui_state->flags.auto_pop) {ui_state->flags.auto_pop = 0; ui_pop_flags();}\ +if(ui_state->fastpath_codepoint.auto_pop) {ui_state->fastpath_codepoint.auto_pop = 0; ui_pop_fastpath_codepoint();}\ +if(ui_state->background_color.auto_pop) {ui_state->background_color.auto_pop = 0; ui_pop_background_color();}\ +if(ui_state->text_color.auto_pop) {ui_state->text_color.auto_pop = 0; ui_pop_text_color();}\ +if(ui_state->border_color.auto_pop) {ui_state->border_color.auto_pop = 0; ui_pop_border_color();}\ +if(ui_state->overlay_color.auto_pop) {ui_state->overlay_color.auto_pop = 0; ui_pop_overlay_color();}\ +if(ui_state->text_select_color.auto_pop) {ui_state->text_select_color.auto_pop = 0; ui_pop_text_select_color();}\ +if(ui_state->text_cursor_color.auto_pop) {ui_state->text_cursor_color.auto_pop = 0; ui_pop_text_cursor_color();}\ +if(ui_state->hover_cursor.auto_pop) {ui_state->hover_cursor.auto_pop = 0; ui_pop_hover_cursor();}\ +if(ui_state->font.auto_pop) {ui_state->font.auto_pop = 0; ui_pop_font();}\ +if(ui_state->font_size.auto_pop) {ui_state->font_size.auto_pop = 0; ui_pop_font_size();}\ +if(ui_state->corner_radius_00.auto_pop) {ui_state->corner_radius_00.auto_pop = 0; ui_pop_corner_radius_00();}\ +if(ui_state->corner_radius_01.auto_pop) {ui_state->corner_radius_01.auto_pop = 0; ui_pop_corner_radius_01();}\ +if(ui_state->corner_radius_10.auto_pop) {ui_state->corner_radius_10.auto_pop = 0; ui_pop_corner_radius_10();}\ +if(ui_state->corner_radius_11.auto_pop) {ui_state->corner_radius_11.auto_pop = 0; ui_pop_corner_radius_11();}\ +if(ui_state->blur_size.auto_pop) {ui_state->blur_size.auto_pop = 0; ui_pop_blur_size();}\ +if(ui_state->text_padding.auto_pop) {ui_state->text_padding.auto_pop = 0; ui_pop_text_padding();}\ +if(ui_state->text_alignment.auto_pop) {ui_state->text_alignment.auto_pop = 0; ui_pop_text_alignment();}\ +} while(0) +internal UI_Box * ui_push_parent(UI_Box * v); +internal Axis2 ui_push_child_layout_axis(Axis2 v); +internal F32 ui_push_fixed_x(F32 v); +internal F32 ui_push_fixed_y(F32 v); +internal F32 ui_push_fixed_width(F32 v); +internal F32 ui_push_fixed_height(F32 v); +internal UI_Size ui_push_pref_width(UI_Size v); +internal UI_Size ui_push_pref_height(UI_Size v); +internal UI_BoxFlags ui_push_flags(UI_BoxFlags v); +internal U32 ui_push_fastpath_codepoint(U32 v); +internal Vec4F32 ui_push_background_color(Vec4F32 v); +internal Vec4F32 ui_push_text_color(Vec4F32 v); +internal Vec4F32 ui_push_border_color(Vec4F32 v); +internal Vec4F32 ui_push_overlay_color(Vec4F32 v); +internal Vec4F32 ui_push_text_select_color(Vec4F32 v); +internal Vec4F32 ui_push_text_cursor_color(Vec4F32 v); +internal OS_Cursor ui_push_hover_cursor(OS_Cursor v); +internal F_Tag ui_push_font(F_Tag v); +internal F32 ui_push_font_size(F32 v); +internal F32 ui_push_corner_radius_00(F32 v); +internal F32 ui_push_corner_radius_01(F32 v); +internal F32 ui_push_corner_radius_10(F32 v); +internal F32 ui_push_corner_radius_11(F32 v); +internal F32 ui_push_blur_size(F32 v); +internal F32 ui_push_text_padding(F32 v); +internal UI_TextAlign ui_push_text_alignment(UI_TextAlign v); +internal UI_Box * ui_pop_parent(void); +internal Axis2 ui_pop_child_layout_axis(void); +internal F32 ui_pop_fixed_x(void); +internal F32 ui_pop_fixed_y(void); +internal F32 ui_pop_fixed_width(void); +internal F32 ui_pop_fixed_height(void); +internal UI_Size ui_pop_pref_width(void); +internal UI_Size ui_pop_pref_height(void); +internal UI_BoxFlags ui_pop_flags(void); +internal U32 ui_pop_fastpath_codepoint(void); +internal Vec4F32 ui_pop_background_color(void); +internal Vec4F32 ui_pop_text_color(void); +internal Vec4F32 ui_pop_border_color(void); +internal Vec4F32 ui_pop_overlay_color(void); +internal Vec4F32 ui_pop_text_select_color(void); +internal Vec4F32 ui_pop_text_cursor_color(void); +internal OS_Cursor ui_pop_hover_cursor(void); +internal F_Tag ui_pop_font(void); +internal F32 ui_pop_font_size(void); +internal F32 ui_pop_corner_radius_00(void); +internal F32 ui_pop_corner_radius_01(void); +internal F32 ui_pop_corner_radius_10(void); +internal F32 ui_pop_corner_radius_11(void); +internal F32 ui_pop_blur_size(void); +internal F32 ui_pop_text_padding(void); +internal UI_TextAlign ui_pop_text_alignment(void); +internal UI_Box * ui_top_parent(void); +internal Axis2 ui_top_child_layout_axis(void); +internal F32 ui_top_fixed_x(void); +internal F32 ui_top_fixed_y(void); +internal F32 ui_top_fixed_width(void); +internal F32 ui_top_fixed_height(void); +internal UI_Size ui_top_pref_width(void); +internal UI_Size ui_top_pref_height(void); +internal UI_BoxFlags ui_top_flags(void); +internal U32 ui_top_fastpath_codepoint(void); +internal Vec4F32 ui_top_background_color(void); +internal Vec4F32 ui_top_text_color(void); +internal Vec4F32 ui_top_border_color(void); +internal Vec4F32 ui_top_overlay_color(void); +internal Vec4F32 ui_top_text_select_color(void); +internal Vec4F32 ui_top_text_cursor_color(void); +internal OS_Cursor ui_top_hover_cursor(void); +internal F_Tag ui_top_font(void); +internal F32 ui_top_font_size(void); +internal F32 ui_top_corner_radius_00(void); +internal F32 ui_top_corner_radius_01(void); +internal F32 ui_top_corner_radius_10(void); +internal F32 ui_top_corner_radius_11(void); +internal F32 ui_top_blur_size(void); +internal F32 ui_top_text_padding(void); +internal UI_TextAlign ui_top_text_alignment(void); +internal UI_Box * ui_bottom_parent(void); +internal Axis2 ui_bottom_child_layout_axis(void); +internal F32 ui_bottom_fixed_x(void); +internal F32 ui_bottom_fixed_y(void); +internal F32 ui_bottom_fixed_width(void); +internal F32 ui_bottom_fixed_height(void); +internal UI_Size ui_bottom_pref_width(void); +internal UI_Size ui_bottom_pref_height(void); +internal UI_BoxFlags ui_bottom_flags(void); +internal U32 ui_bottom_fastpath_codepoint(void); +internal Vec4F32 ui_bottom_background_color(void); +internal Vec4F32 ui_bottom_text_color(void); +internal Vec4F32 ui_bottom_border_color(void); +internal Vec4F32 ui_bottom_overlay_color(void); +internal Vec4F32 ui_bottom_text_select_color(void); +internal Vec4F32 ui_bottom_text_cursor_color(void); +internal OS_Cursor ui_bottom_hover_cursor(void); +internal F_Tag ui_bottom_font(void); +internal F32 ui_bottom_font_size(void); +internal F32 ui_bottom_corner_radius_00(void); +internal F32 ui_bottom_corner_radius_01(void); +internal F32 ui_bottom_corner_radius_10(void); +internal F32 ui_bottom_corner_radius_11(void); +internal F32 ui_bottom_blur_size(void); +internal F32 ui_bottom_text_padding(void); +internal UI_TextAlign ui_bottom_text_alignment(void); +internal UI_Box * ui_set_next_parent(UI_Box * v); +internal Axis2 ui_set_next_child_layout_axis(Axis2 v); +internal F32 ui_set_next_fixed_x(F32 v); +internal F32 ui_set_next_fixed_y(F32 v); +internal F32 ui_set_next_fixed_width(F32 v); +internal F32 ui_set_next_fixed_height(F32 v); +internal UI_Size ui_set_next_pref_width(UI_Size v); +internal UI_Size ui_set_next_pref_height(UI_Size v); +internal UI_BoxFlags ui_set_next_flags(UI_BoxFlags v); +internal U32 ui_set_next_fastpath_codepoint(U32 v); +internal Vec4F32 ui_set_next_background_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_color(Vec4F32 v); +internal Vec4F32 ui_set_next_border_color(Vec4F32 v); +internal Vec4F32 ui_set_next_overlay_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_select_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_cursor_color(Vec4F32 v); +internal OS_Cursor ui_set_next_hover_cursor(OS_Cursor v); +internal F_Tag ui_set_next_font(F_Tag v); +internal F32 ui_set_next_font_size(F32 v); +internal F32 ui_set_next_corner_radius_00(F32 v); +internal F32 ui_set_next_corner_radius_01(F32 v); +internal F32 ui_set_next_corner_radius_10(F32 v); +internal F32 ui_set_next_corner_radius_11(F32 v); +internal F32 ui_set_next_blur_size(F32 v); +internal F32 ui_set_next_text_padding(F32 v); +internal UI_TextAlign ui_set_next_text_alignment(UI_TextAlign v); +#if 0 +#define UI_Parent(v) DeferLoop(ui_push_parent(v), ui_pop_parent()) +#define UI_ChildLayoutAxis(v) DeferLoop(ui_push_child_layout_axis(v), ui_pop_child_layout_axis()) +#define UI_FixedX(v) DeferLoop(ui_push_fixed_x(v), ui_pop_fixed_x()) +#define UI_FixedY(v) DeferLoop(ui_push_fixed_y(v), ui_pop_fixed_y()) +#define UI_FixedWidth(v) DeferLoop(ui_push_fixed_width(v), ui_pop_fixed_width()) +#define UI_FixedHeight(v) DeferLoop(ui_push_fixed_height(v), ui_pop_fixed_height()) +#define UI_PrefWidth(v) DeferLoop(ui_push_pref_width(v), ui_pop_pref_width()) +#define UI_PrefHeight(v) DeferLoop(ui_push_pref_height(v), ui_pop_pref_height()) +#define UI_Flags(v) DeferLoop(ui_push_flags(v), ui_pop_flags()) +#define UI_FastpathCodepoint(v) DeferLoop(ui_push_fastpath_codepoint(v), ui_pop_fastpath_codepoint()) +#define UI_BackgroundColor(v) DeferLoop(ui_push_background_color(v), ui_pop_background_color()) +#define UI_TextColor(v) DeferLoop(ui_push_text_color(v), ui_pop_text_color()) +#define UI_BorderColor(v) DeferLoop(ui_push_border_color(v), ui_pop_border_color()) +#define UI_OverlayColor(v) DeferLoop(ui_push_overlay_color(v), ui_pop_overlay_color()) +#define UI_TextSelectColor(v) DeferLoop(ui_push_text_select_color(v), ui_pop_text_select_color()) +#define UI_TextCursorColor(v) DeferLoop(ui_push_text_cursor_color(v), ui_pop_text_cursor_color()) +#define UI_HoverCursor(v) DeferLoop(ui_push_hover_cursor(v), ui_pop_hover_cursor()) +#define UI_Font(v) DeferLoop(ui_push_font(v), ui_pop_font()) +#define UI_FontSize(v) DeferLoop(ui_push_font_size(v), ui_pop_font_size()) +#define UI_CornerRadius00(v) DeferLoop(ui_push_corner_radius_00(v), ui_pop_corner_radius_00()) +#define UI_CornerRadius01(v) DeferLoop(ui_push_corner_radius_01(v), ui_pop_corner_radius_01()) +#define UI_CornerRadius10(v) DeferLoop(ui_push_corner_radius_10(v), ui_pop_corner_radius_10()) +#define UI_CornerRadius11(v) DeferLoop(ui_push_corner_radius_11(v), ui_pop_corner_radius_11()) +#define UI_BlurSize(v) DeferLoop(ui_push_blur_size(v), ui_pop_blur_size()) +#define UI_TextPadding(v) DeferLoop(ui_push_text_padding(v), ui_pop_text_padding()) +#define UI_TextAlignment(v) DeferLoop(ui_push_text_alignment(v), ui_pop_text_alignment()) +#endif + +#endif // UI_META_H diff --git a/src/ui/ui.mc b/src/ui/ui.mc new file mode 100644 index 00000000..bfc946b4 --- /dev/null +++ b/src/ui/ui.mc @@ -0,0 +1,114 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +@table(name, name_lower, type) +UI_StackTable: +{ + //- rjf: parents + { Parent parent `UI_Box *` } + + //- rjf: layout params + { ChildLayoutAxis child_layout_axis Axis2 } + + //- rjf: size/position + { FixedX fixed_x F32 } + { FixedY fixed_y F32 } + { FixedWidth fixed_width F32 } + { FixedHeight fixed_height F32 } + { PrefWidth pref_width UI_Size } + { PrefHeight pref_height UI_Size } + + //- rjf: flags + { Flags flags UI_BoxFlags } + + //- rjf: interaction + { FastpathCodepoint fastpath_codepoint U32 } + + //- rjf: colors + { BackgroundColor background_color Vec4F32 } + { TextColor text_color Vec4F32 } + { BorderColor border_color Vec4F32 } + { OverlayColor overlay_color Vec4F32 } + { TextSelectColor text_select_color Vec4F32 } + { TextCursorColor text_cursor_color Vec4F32 } + + //- rjf: hover cursor + { HoverCursor hover_cursor OS_Cursor } + + //- rjf: font + { Font font F_Tag } + { FontSize font_size F32 } + + //- rjf: corner radii + { CornerRadius00 corner_radius_00 F32 } + { CornerRadius01 corner_radius_01 F32 } + { CornerRadius10 corner_radius_10 F32 } + { CornerRadius11 corner_radius_11 F32 } + + //- rjf: blur size + { BlurSize blur_size F32 } + + //- rjf: text parameters + { TextPadding text_padding F32 } + { TextAlignment text_alignment UI_TextAlign } +} + +@table_gen +{ + `#define UI_StackDecls struct{\\`; + @expand(UI_StackTable a) + `struct { $(a.type) active; $(a.type) v[64]; U64 count; B32 auto_pop; } $(a.name_lower);\\`; + `}`; +} + +@table_gen +{ + `#define UI_ZeroAllStacks(ui_state) do{\\`; + @expand(UI_StackTable a) + `MemoryZeroStruct(&ui_state->$(a.name_lower));\\`; + `} while(0)`; +} + +@table_gen +{ + `#define UI_AutoPopAllStacks(ui_state) do{\\`; + @expand(UI_StackTable a) + `if(ui_state->$(a.name_lower).auto_pop) {ui_state->$(a.name_lower).auto_pop = 0; ui_pop_$(a.name_lower)();}\\`; + `} while(0)`; +} + +@table_gen +{ + @expand(UI_StackTable a) + `internal $(a.type) $(=>35) ui_push_$(a.name_lower)($(a.type) v);`; + @expand(UI_StackTable a) + `internal $(a.type) $(=>35) ui_pop_$(a.name_lower)(void);`; + @expand(UI_StackTable a) + `internal $(a.type) $(=>35) ui_top_$(a.name_lower)(void);`; + @expand(UI_StackTable a) + `internal $(a.type) $(=>35) ui_bottom_$(a.name_lower)(void);`; + @expand(UI_StackTable a) + `internal $(a.type) $(=>35) ui_set_next_$(a.name_lower)($(a.type) v);`; +} + +@table_gen +{ + `#if 0`; + @expand(UI_StackTable a) + `#define UI_$(a.name)(v) $(=>35) DeferLoop(ui_push_$(a.name_lower)(v), ui_pop_$(a.name_lower)())`; + `#endif`; +} + +@table_gen @c_file +{ + @expand(UI_StackTable a) + `internal $(a.type) ui_push_$(a.name_lower)($(a.type) v) {return UI_StackPush($(a.name_lower), v);}`; + @expand(UI_StackTable a) + `internal $(a.type) ui_pop_$(a.name_lower)(void) {$(a.type) popped; return UI_StackPop($(a.name_lower), popped);}`; + @expand(UI_StackTable a) + `internal $(a.type) ui_top_$(a.name_lower)(void) {return UI_StackTop($(a.name_lower));}`; + @expand(UI_StackTable a) + `internal $(a.type) ui_bottom_$(a.name_lower)(void) {return UI_StackBottom($(a.name_lower));}`; + @expand(UI_StackTable a) + `internal $(a.type) ui_set_next_$(a.name_lower)($(a.type) v) {return UI_StackSetNext($(a.name_lower), v);}`; +} diff --git a/src/ui/ui_basic_widgets.c b/src/ui/ui_basic_widgets.c new file mode 100644 index 00000000..b19fa333 --- /dev/null +++ b/src/ui/ui_basic_widgets.c @@ -0,0 +1,1418 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Widgets + +internal UI_Signal +ui_spacer(UI_Size size) +{ + UI_Box *parent = ui_top_parent(); + ui_set_next_pref_size(parent->child_layout_axis, size); + UI_Box *box = ui_build_box_from_string(0, str8_lit("")); + UI_Signal interact = ui_signal_from_box(box); + return interact; +} + +internal UI_Signal +ui_label(String8 string) +{ + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText, str8_lit("")); + ui_box_equip_display_string(box, string); + UI_Signal interact = ui_signal_from_box(box); + return interact; +} + +internal UI_Signal +ui_labelf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal result = ui_label(string); + scratch_end(scratch); + return result; +} + +internal void +ui_label_multiline(F32 max, String8 string) +{ + Temp scratch = scratch_begin(0, 0); + ui_set_next_child_layout_axis(Axis2_Y); + ui_set_next_pref_height(ui_children_sum(1)); + UI_Box *box = ui_build_box_from_key(0, ui_key_zero()); + String8List lines = f_wrapped_string_lines_from_font_size_string_max(scratch.arena, ui_top_font(), ui_top_font_size(), string, max); + for(String8Node *n = lines.first; n != 0; n = n->next) + { + ui_label(n->string); + } + scratch_end(scratch); +} + +internal void +ui_label_multilinef(F32 max, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + ui_label_multiline(max, string); + scratch_end(scratch); +} + +internal UI_Signal +ui_button(String8 string) +{ + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawText| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + string); + UI_Signal interact = ui_signal_from_box(box); + return interact; +} + +internal UI_Signal +ui_buttonf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal result = ui_button(string); + scratch_end(scratch); + return result; +} + +internal UI_Signal +ui_hover_label(String8 string) +{ + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, string); + UI_Signal interact = ui_signal_from_box(box); + if(interact.hovering) + { + box->flags |= UI_BoxFlag_DrawBorder; + } + return interact; +} + +internal UI_Signal +ui_hover_labelf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = ui_hover_label(string); + scratch_end(scratch); + return sig; +} + +typedef struct UI_LineEditDrawData UI_LineEditDrawData; +struct UI_LineEditDrawData +{ + String8 edited_string; + Vec4F32 cursor_color; + Vec4F32 select_color; + TxtPt cursor; + TxtPt mark; +}; + +internal UI_BOX_CUSTOM_DRAW(ui_line_edit_draw) +{ + UI_LineEditDrawData *draw_data = (UI_LineEditDrawData *)user_data; + F_Tag font = box->font; + F32 font_size = box->font_size; + Vec4F32 cursor_color = draw_data->cursor_color; + cursor_color.w *= box->parent->parent->focus_active_t; + Vec4F32 select_color = draw_data->select_color; + select_color.w *= (box->parent->parent->focus_active_t*0.2f + 0.8f); + Vec2F32 text_position = ui_box_text_position(box); + String8 edited_string = draw_data->edited_string; + TxtPt cursor = draw_data->cursor; + TxtPt mark = draw_data->mark; + F32 cursor_pixel_off = f_dim_from_tag_size_string(font, font_size, str8_prefix(edited_string, cursor.column-1)).x + font_size/8.f; + F32 mark_pixel_off = f_dim_from_tag_size_string(font, font_size, str8_prefix(edited_string, mark.column-1)).x + font_size/8.f; + Rng2F32 cursor_rect = + { + text_position.x-ClampBot(2.f, font_size/4.f) + cursor_pixel_off, + box->rect.y0+4.f, + text_position.x+ClampBot(2.f, font_size/4.f) + cursor_pixel_off, + box->rect.y1-4.f, + }; + Rng2F32 mark_rect = + { + text_position.x-2.f + mark_pixel_off, + box->rect.y0+2.f, + text_position.x+2.f + mark_pixel_off, + box->rect.y1-2.f, + }; + Rng2F32 select_rect = union_2f32(cursor_rect, mark_rect); + d_rect(select_rect, select_color, font_size/2.f, 0, 1.f); + d_rect(cursor_rect, cursor_color, 0.f, 0, 1.f); +} + +internal UI_Signal +ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, String8 string) +{ + //- rjf: build top-level box + UI_Key key = ui_key_from_string(ui_active_seed_key(), string); + B32 is_auto_focus_hot = ui_is_key_auto_focus_hot(key); + B32 is_auto_focus_active = ui_is_key_auto_focus_active(key); + if(is_auto_focus_hot) { ui_set_focus_hot(1); } + if(is_auto_focus_active) { ui_set_focus_active(1); } + B32 is_focus_hot = ui_is_focus_hot(); + B32 is_focus_active = ui_is_focus_active(); + ui_set_next_hover_cursor(is_focus_active ? OS_Cursor_IBar : OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_MouseClickable| + UI_BoxFlag_ClickToFocus| + ((is_auto_focus_hot || is_auto_focus_active)*UI_BoxFlag_KeyboardClickable)| + UI_BoxFlag_DrawHotEffects| + is_focus_active*(UI_BoxFlag_Clip|UI_BoxFlag_AllowOverflowX|UI_BoxFlag_ViewClamp), + key); + + //- rjf: take navigation actions for editing + B32 changes_made = 0; + if(is_focus_active) + { + Temp scratch = scratch_begin(0, 0); + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); + next = n->next; + + // rjf: do not consume anything that doesn't fit a single-line's operations + if(n->v.delta.y != 0) + { + continue; + } + + // rjf: map this action to an op + UI_NavTxtOp op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, edit_string, *cursor, *mark); + + // rjf: perform replace range + if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) + { + String8 new_string = ui_nav_push_string_replace_range(scratch.arena, edit_string, r1s64(op.range.min.column, op.range.max.column), op.replace); + new_string.size = Min(edit_buffer_size, new_string.size); + MemoryCopy(edit_buffer, new_string.str, new_string.size); + edit_string_size_out[0] = new_string.size; + } + + // rjf: perform copy + if(op.flags & UI_NavTxtOpFlag_Copy) + { + os_set_clipboard_text(op.copy); + } + + // rjf: commit op's changed cursor & mark to caller-provided state + *cursor = op.cursor; + *mark = op.mark; + + // rjf: consume event + { + ui_nav_eat_action_node(nav_actions, n); + changes_made = 1; + } + } + scratch_end(scratch); + } + + //- rjf: build contents + TxtPt mouse_pt = {0}; + F32 cursor_off = 0; + UI_Parent(box) + { + String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); + if(!is_focus_active) + { + String8 display_string = ui_display_part_from_key_string(string); + if(pre_edit_value.size != 0) + { + display_string = pre_edit_value; + } + ui_label(display_string); + } + else + { + F32 total_text_width = f_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), edit_string).x; + ui_set_next_pref_width(ui_px(total_text_width+ui_top_font_size()*5, 1.f)); + UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); + UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); + draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); + draw_data->cursor = *cursor; + draw_data->mark = *mark; + draw_data->cursor_color = ui_top_text_cursor_color(); + draw_data->select_color = ui_top_text_select_color(); + ui_box_equip_display_string(editstr_box, edit_string); + ui_box_equip_custom_draw(editstr_box, ui_line_edit_draw, draw_data); + mouse_pt = txt_pt(1, 1+ui_box_char_pos_from_xy(editstr_box, ui_mouse())); + cursor_off = f_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), str8_prefix(edit_string, cursor->column-1)).x; + } + } + + //- rjf: interact + UI_Signal sig = ui_signal_from_box(box); + if(!is_focus_active && (sig.double_clicked || sig.keyboard_clicked)) + { + String8 edit_string = pre_edit_value; + edit_string.size = Min(edit_buffer_size, pre_edit_value.size); + MemoryCopy(edit_buffer, edit_string.str, edit_string.size); + edit_string_size_out[0] = edit_string.size; + ui_set_auto_focus_active_key(key); + ui_kill_action(); + *cursor = txt_pt(1, edit_string.size+1); + *mark = txt_pt(1, 1); + } + if(is_focus_active && sig.keyboard_clicked) + { + ui_set_auto_focus_active_key(ui_key_zero()); + sig.commit = 1; + } + if(is_focus_active && sig.dragging) + { + if(sig.pressed) + { + *mark = mouse_pt; + } + *cursor = mouse_pt; + } + + //- rjf: focus cursor + { + Rng1F32 cursor_range_px = r1f32(cursor_off-ui_top_font_size()*2.f, cursor_off+ui_top_font_size()*2.f); + Rng1F32 visible_range_px = r1f32(box->view_off_target.x, box->view_off_target.x + dim_2f32(box->rect).x); + cursor_range_px.min = ClampBot(0, cursor_range_px.min); + cursor_range_px.max = ClampBot(0, cursor_range_px.max); + F32 min_delta = cursor_range_px.min-visible_range_px.min; + F32 max_delta = cursor_range_px.max-visible_range_px.max; + min_delta = Min(min_delta, 0); + max_delta = Max(max_delta, 0); + box->view_off_target.x += min_delta; + box->view_off_target.x += max_delta; + } + + return sig; +} + +internal UI_Signal +ui_line_editf(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal result = ui_line_edit(cursor, mark, edit_buffer, edit_buffer_size, edit_string_size_out, pre_edit_value, string); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Special Buttons + +internal UI_Signal +ui_close_button(String8 string) +{ + ui_set_next_background_color(v4f32(0.6f, 0.2f, 0.1f, 1.f)); + ui_set_next_text_color(v4f32(1, 1, 1, 1)); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_text_alignment(UI_TextAlign_Center); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawText| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + string); + UI_Signal interact = ui_signal_from_box(box); + return interact; +} + +internal UI_Signal +ui_close_buttonf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = ui_close_button(string); + scratch_end(scratch); + return sig; +} + +internal UI_Signal +ui_expander(B32 is_expanded, String8 string) +{ + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_text_alignment(UI_TextAlign_Center); + ui_set_next_font(ui_icon_font()); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, string); + ui_box_equip_display_string(box, is_expanded ? str8_lit("v") : str8_lit(">")); + UI_Signal sig = ui_signal_from_box(box); + return sig; +} + +internal UI_Signal +ui_expanderf(B32 is_expanded, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = ui_expander(is_expanded, string); + scratch_end(scratch); + return sig; +} + +internal UI_Signal +ui_sort_header(B32 sorting, B32 ascending, String8 string) +{ + ui_set_next_child_layout_axis(Axis2_X); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawActiveEffects, string); + ui_push_parent(box); + + // rjf: make icon + if(sorting) + { + ui_set_next_pref_width(ui_em(1.8f, 1.f)); + ui_set_next_text_alignment(UI_TextAlign_Center); + ui_set_next_font(ui_icon_font()); + UI_Box *icon = ui_build_box_from_string(UI_BoxFlag_DrawText, str8_lit("")); + ui_box_equip_display_string(icon, ascending ? str8_lit("^") : str8_lit("v")); + } + + // rjf: make text + { + ui_label(string); + } + + ui_pop_parent(); + UI_Signal interact = ui_signal_from_box(box); + return interact; +} + +internal UI_Signal +ui_sort_headerf(B32 sorting, B32 ascending, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = ui_sort_header(sorting, ascending, string); + scratch_end(scratch); + return sig; +} + +//////////////////////////////// +//~ rjf: Color Pickers + +//- rjf: tooltips + +internal void +ui_do_color_tooltip_hsv(Vec3F32 hsv) +{ + Vec3F32 rgb = rgb_from_hsv(hsv); + UI_Tooltip UI_Padding(ui_em(2.f, 1.f)) + { + UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) UI_Row UI_Padding(ui_pct(1, 0)) + { + UI_BackgroundColor(v4f32(rgb.x, rgb.y, rgb.z, 1)) UI_CornerRadius(4.f) + UI_PrefWidth(ui_em(6.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) + ui_build_box_from_string(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, str8_lit("")); + } + ui_spacer(ui_em(0.3f, 1.f)); + UI_PrefWidth(ui_em(22.f, 1.f)) UI_TextAlignment(UI_TextAlign_Center) + { + ui_labelf("Hex: #%02x%02x%02x", (U8)(rgb.x*255.f), (U8)(rgb.y*255.f), (U8)(rgb.z*255.f)); + } + ui_spacer(ui_em(0.3f, 1.f)); + UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_children_sum(1)) UI_Row + { + UI_WidthFill UI_Column UI_PrefHeight(ui_em(1.8f, 1.f)) + { + ui_labelf("Red: %.2f", rgb.x); + ui_labelf("Green: %.2f", rgb.y); + ui_labelf("Blue: %.2f", rgb.z); + } + UI_WidthFill UI_Column UI_PrefHeight(ui_em(1.8f, 1.f)) + { + ui_labelf("Hue: %.2f", hsv.x); + ui_labelf("Sat: %.2f", hsv.y); + ui_labelf("Val: %.2f", hsv.z); + } + } + } +} + +internal void +ui_do_color_tooltip_hsva(Vec4F32 hsva) +{ + Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z); + Vec3F32 rgb = rgb_from_hsv(hsv); + Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, hsva.w); + UI_Tooltip UI_Padding(ui_em(2.f, 1.f)) + { + UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) UI_Row UI_Padding(ui_pct(1, 0)) + { + UI_BackgroundColor(rgba) UI_CornerRadius(4.f) + UI_PrefWidth(ui_em(6.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) + ui_build_box_from_string(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, str8_lit("")); + } + ui_spacer(ui_em(0.3f, 1.f)); + UI_PrefWidth(ui_em(22.f, 1.f)) UI_TextAlignment(UI_TextAlign_Center) + { + ui_labelf("Hex: #%02x%02x%02x%02x", (U8)(rgba.x*255.f), (U8)(rgba.y*255.f), (U8)(rgba.z*255.f), (U8)(rgba.w*255.f)); + } + ui_spacer(ui_em(0.3f, 1.f)); + UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_children_sum(1)) UI_Row + { + UI_WidthFill UI_Column UI_PrefHeight(ui_em(1.8f, 1.f)) + { + ui_labelf("Red: %.2f", rgba.x); + ui_labelf("Green: %.2f", rgba.y); + ui_labelf("Blue: %.2f", rgba.z); + ui_labelf("Alpha: %.2f", rgba.w); + } + UI_WidthFill UI_Column UI_PrefHeight(ui_em(1.8f, 1.f)) + { + ui_labelf("Hue: %.2f", hsva.x); + ui_labelf("Sat: %.2f", hsva.y); + ui_labelf("Val: %.2f", hsva.z); + ui_labelf("Alpha: %.2f", hsva.w); + } + } + } +} + +//- rjf: saturation/value picker + +typedef struct UI_SatValDrawData UI_SatValDrawData; +struct UI_SatValDrawData +{ + F32 hue; + F32 sat; + F32 val; +}; + +internal UI_BOX_CUSTOM_DRAW(ui_sat_val_picker_draw) +{ + UI_SatValDrawData *data = (UI_SatValDrawData *)user_data; + + // rjf: hue => rgb + Vec3F32 hue_rgb = rgb_from_hsv(v3f32(data->hue, 1, 1)); + + // rjf: value + { + R_Rect2DInst *inst = d_rect(pad_2f32(box->rect, -1.f), v4f32(0, 0, 0, 1), 4.f, 0, 1.f); + inst->colors[Corner_00] = inst->colors[Corner_10] = v4f32(1, 1, 1, 1); + } + + // rjf: saturation + { + R_Rect2DInst *inst = d_rect(pad_2f32(box->rect, -1.f), v4f32(0, 0, 0, 0), 4.f, 0, 1.f); + inst->colors[Corner_00] = v4f32(1, 1, 1, 1); + inst->colors[Corner_01] = v4f32(0, 0, 0, 0); + inst->colors[Corner_10] = v4f32(hue_rgb.x, hue_rgb.y, hue_rgb.z, 1); + inst->colors[Corner_11] = v4f32(hue_rgb.x, hue_rgb.y, hue_rgb.z, 0); + } + + // rjf: indicator + { + Vec2F32 box_rect_dim = dim_2f32(box->rect); + Vec2F32 center = v2f32(box->rect.x0 + data->sat*box_rect_dim.x, box->rect.y0 + (1-data->val)*box_rect_dim.y); + F32 half_size = box->font_size * (0.5f + box->active_t*0.2f); + Rng2F32 rect = r2f32p(center.x - half_size, + center.y - half_size, + center.x + half_size, + center.y + half_size); + d_rect(rect, v4f32(1, 1, 1, 1), half_size/2, 2.f, 1.f); + } +} + +internal UI_Signal +ui_sat_val_picker(F32 hue, F32 *out_sat, F32 *out_val, String8 string) +{ + // rjf: build & interact + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable, string); + UI_SatValDrawData *user = push_array(ui_build_arena(), UI_SatValDrawData, 1); + ui_box_equip_custom_draw(box, ui_sat_val_picker_draw, user); + UI_Signal sig = ui_signal_from_box(box); + + // rjf: click+draw behavior + if(sig.dragging) + { + Vec2F32 dim = dim_2f32(box->rect); + *out_sat = (ui_mouse().x - box->rect.x0) / dim.x; + *out_val = 1 - (ui_mouse().y - box->rect.y0) / dim.y; + *out_sat = Clamp(0, *out_sat, 1); + *out_val = Clamp(0, *out_val, 1); + ui_do_color_tooltip_hsv(v3f32(hue, *out_sat, *out_val)); + } + + // rjf: fill draw data + { + user->hue = hue; + user->sat = *out_sat; + user->val = *out_val; + } + + return sig; +} + +internal UI_Signal +ui_sat_val_pickerf(F32 hue, F32 *out_sat, F32 *out_val, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = ui_sat_val_picker(hue, out_sat, out_val, string); + scratch_end(scratch); + return sig; +} + +//- rjf: hue picker + +typedef struct UI_HueDrawData UI_HueDrawData; +struct UI_HueDrawData +{ + F32 hue; + F32 sat; + F32 val; +}; + +internal UI_BOX_CUSTOM_DRAW(ui_hue_picker_draw) +{ + UI_HueDrawData *data = (UI_HueDrawData *)user_data; + Vec2F32 dim = dim_2f32(box->rect); + F32 segment_dim = floor_f32(dim.y/6.f); + Rng2F32 hue_cycle_rect = box->rect; + Vec2F32 hue_cycle_center = center_2f32(hue_cycle_rect); + hue_cycle_rect.x0 += (hue_cycle_center.x - hue_cycle_rect.x0) * 0.3f; + hue_cycle_rect.x1 += (hue_cycle_center.x - hue_cycle_rect.x1) * 0.3f; + Rng2F32 rect = r2f32p(hue_cycle_rect.x0, + hue_cycle_rect.y0, + hue_cycle_rect.x1, + hue_cycle_rect.y0 + segment_dim); + for(int seg = 0; seg < 6; seg += 1) + { + F32 hue0 = (F32)(seg)/6; + F32 hue1 = (F32)(seg+1)/6; + Vec3F32 rgb0 = rgb_from_hsv(v3f32(hue0, 1, 1)); + Vec3F32 rgb1 = rgb_from_hsv(v3f32(hue1, 1, 1)); + Vec4F32 rgba0 = v4f32(rgb0.x, rgb0.y, rgb0.z, 1); + Vec4F32 rgba1 = v4f32(rgb1.x, rgb1.y, rgb1.z, 1); + R_Rect2DInst *inst = d_rect(rect, v4f32(0, 0, 0, 0), 0, 0, 0.f); + inst->colors[Corner_00] = rgba0; + inst->colors[Corner_01] = rgba1; + inst->colors[Corner_10] = rgba0; + inst->colors[Corner_11] = rgba1; + rect.y0 += segment_dim; + rect.y1 += segment_dim; + } + + // rjf: indicator + { + Vec2F32 box_rect_dim = dim_2f32(box->rect); + Vec2F32 center = v2f32((box->rect.x0+box->rect.x1)/2, box->rect.y0 + data->hue*box_rect_dim.y); + F32 half_size = box->font_size * (0.5f + box->active_t*0.2f); + Rng2F32 rect = r2f32p(center.x - half_size, + center.y - 2.f, + center.x + half_size, + center.y + 2.f); + d_rect(rect, v4f32(1, 1, 1, 1), half_size/2, 2.f, 1.f); + } +} + +internal UI_Signal +ui_hue_picker(F32 *out_hue, F32 sat, F32 val, String8 string) +{ + // rjf: build & interact + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable, string); + UI_HueDrawData *user = push_array(ui_build_arena(), UI_HueDrawData, 1); + ui_box_equip_custom_draw(box, ui_hue_picker_draw, user); + UI_Signal sig = ui_signal_from_box(box); + + // rjf: click+draw behavior + if(sig.dragging) + { + Vec2F32 dim = dim_2f32(box->rect); + *out_hue = (ui_mouse().y - box->rect.y0) / dim.y; + *out_hue = Clamp(0, *out_hue, 1); + ui_do_color_tooltip_hsv(v3f32(*out_hue, sat, val)); + } + + // rjf: fill draw data + { + user->hue = *out_hue; + user->sat = sat; + user->val = val; + } + + return sig; +} + +internal UI_Signal +ui_hue_pickerf(F32 *out_hue, F32 sat, F32 val, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = ui_hue_picker(out_hue, sat, val, string); + scratch_end(scratch); + return sig; +} + +//- rjf: alpha picker + +typedef struct UI_AlphaDrawData UI_AlphaDrawData; +struct UI_AlphaDrawData +{ + F32 alpha; +}; + +internal UI_BOX_CUSTOM_DRAW(ui_alpha_picker_draw) +{ + UI_AlphaDrawData *data = (UI_AlphaDrawData *)user_data; + Vec2F32 dim = dim_2f32(box->rect); + + // rjf: build gradient + { + Rng2F32 rect = box->rect; + Vec2F32 center = center_2f32(rect); + rect.x0 += (center.x - rect.x0) * 0.3f; + rect.x1 += (center.x - rect.x1) * 0.3f; + R_Rect2DInst *inst = d_rect(rect, v4f32(0, 0, 0, 0), 0, 0, 0); + inst->colors[Corner_00] = inst->colors[Corner_10] = v4f32(1, 1, 1, 1); + } + + // rjf: indicator + { + Vec2F32 box_rect_dim = dim_2f32(box->rect); + Vec2F32 center = v2f32((box->rect.x0+box->rect.x1)/2, box->rect.y0 + (1-data->alpha)*box_rect_dim.y); + F32 half_size = box->font_size * (0.5f + box->active_t*0.2f); + Rng2F32 rect = r2f32p(center.x - half_size, + center.y - 2.f, + center.x + half_size, + center.y + 2.f); + d_rect(rect, v4f32(1, 1, 1, 1), half_size/2, 2.f, 1.f); + } +} + +internal UI_Signal +ui_alpha_picker(F32 *out_alpha, String8 string) +{ + // rjf: build & interact + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable, string); + UI_AlphaDrawData *user = push_array(ui_build_arena(), UI_AlphaDrawData, 1); + ui_box_equip_custom_draw(box, ui_alpha_picker_draw, user); + UI_Signal sig = ui_signal_from_box(box); + + // rjf: click+draw behavior + if(sig.dragging) + { + Vec2F32 dim = dim_2f32(box->rect); + F32 drag_pct = (ui_mouse().y - box->rect.y0) / dim.y; + drag_pct = Clamp(0, drag_pct, 1); + *out_alpha = 1-drag_pct; + } + + // rjf: fill draw data + { + user->alpha = *out_alpha; + } + + return sig; +} + +internal UI_Signal +ui_alpha_pickerf(F32 *out_alpha, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Signal sig = ui_alpha_picker(out_alpha, string); + scratch_end(scratch); + return sig; +} + +//////////////////////////////// +//~ rjf: Simple Layout Widgets + +internal UI_Signal ui_row_begin(void) { return ui_named_row_begin(str8_lit("")); } +internal void ui_row_end(void) { ui_named_row_end(); } +internal UI_Signal ui_column_begin(void) { return ui_named_column_begin(str8_lit("")); } +internal void ui_column_end(void) { ui_named_column_end(); } + +internal UI_Signal +ui_named_row_begin(String8 string) +{ + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *box = ui_build_box_from_string(0, string); + ui_push_parent(box); + UI_Signal result = ui_signal_from_box(box); + return result; +} + +internal void +ui_named_row_end(void) +{ + ui_pop_parent(); +} + +internal UI_Signal +ui_named_column_begin(String8 string) +{ + ui_set_next_child_layout_axis(Axis2_Y); + UI_Box *box = ui_build_box_from_string(0, string); + ui_push_parent(box); + UI_Signal result = ui_signal_from_box(box); + return result; +} + +internal void +ui_named_column_end(void) +{ + ui_pop_parent(); +} + +//////////////////////////////// +//~ rjf: Floating Panes + +internal UI_Box * +ui_pane_begin(Rng2F32 rect, String8 string) +{ + ui_push_rect(rect); + ui_set_next_child_layout_axis(Axis2_Y); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable|UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, string); + ui_pop_rect(); + ui_push_parent(box); + ui_push_pref_width(ui_pct(1, 0)); + return box; +} + +internal UI_Box * +ui_pane_beginf(Rng2F32 rect, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Box *box = ui_pane_begin(rect, string); + scratch_end(scratch); + return box; +} + +internal void +ui_pane_end(void) +{ + ui_pop_pref_width(); + ui_pop_parent(); +} + +//////////////////////////////// +//~ rjf: Tables + +thread_static U64 ui_ts_col_pct_count = 0; +thread_static F32 *ui_ts_col_pcts_stable = 0; + +internal void +ui_table_begin(U64 column_pct_count, F32 **column_pcts, String8 string) +{ + //- rjf: store off persistent, user-provided column info + ui_ts_col_pct_count = column_pct_count; + + //- rjf: build main table parent + ui_set_next_pref_height(ui_children_sum(1)); + ui_set_next_child_layout_axis(Axis2_Y); + UI_Box *table = ui_build_box_from_string(0, string); + ui_push_parent(table); + + //- rjf: build column boundaries + F32 x_off = (ui_ts_col_pct_count > 0 ? *column_pcts[0] : 0) * dim_2f32(table->rect).x; + for(U64 column_idx = 1; column_idx < ui_ts_col_pct_count; column_idx += 1) + { + // rjf: build base rectangle + Rng2F32 rect = {0}; + { + rect.x0 = x_off-3.f; + rect.y0 = 0; + rect.x1 = x_off+3.f; + rect.y1 = dim_2f32(table->rect).y; + x_off += *column_pcts[column_idx] * dim_2f32(table->rect).x; + } + + // rjf: make column boundary widget + UI_Rect(rect) + { + ui_set_next_hover_cursor(OS_Cursor_LeftRight); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###%S_boundary_%I64u", table->string, column_idx); + + F32 *left_pct_ptr = column_idx < ui_ts_col_pct_count ? column_pcts[column_idx-1] : 0; + F32 *right_pct_ptr = column_idx < ui_ts_col_pct_count ? column_pcts[column_idx] : 0; + + // rjf: boundary dragging + UI_Signal interact = ui_signal_from_box(box); + if(interact.dragging) + { + if(interact.pressed) + { + Vec2F32 v = v2f32(*left_pct_ptr, *right_pct_ptr); + ui_store_drag_struct(&v); + } + + // rjf: calculate how much space we're dividing amongst the columns that + // the user can resize + F32 adjustable_table_dim = 0; + if(table->child_layout_axis == Axis2_Y) + { + adjustable_table_dim = dim_2f32(table->rect).x; + } + else + { + U64 child_idx = 0; + for(UI_Box *v = table->first; !ui_box_is_nil(v); v = v->next, child_idx += 1) + { + U64 column_idx = (child_idx+1); + if(column_idx < ui_ts_col_pct_count) + { + adjustable_table_dim += dim_2f32(v->rect).x; + } + else + { + break; + } + } + } + + // rjf: calculate diff + F32 min_size = 30.f; + F32 left_pct__before = ui_get_drag_struct(Vec2F32)->x; + F32 left_pixels__before = left_pct__before * adjustable_table_dim; + F32 left_pixels__after = left_pixels__before + ui_drag_delta().x; + + // rjf: clamp left side + if(left_pixels__after < min_size) + { + left_pixels__after = min_size; + } + + // rjf: calculate right side + F32 left_pct__after = left_pixels__after / adjustable_table_dim; + F32 pct_delta = left_pct__after - left_pct__before; + F32 right_pct__before = ui_get_drag_struct(Vec2F32)->y; + F32 right_pct__after = right_pct__before - pct_delta; + F32 right_pixels__after = right_pct__after * adjustable_table_dim; + + // rjf: clamp right side & back-solve + if(right_pixels__after < min_size) + { + right_pixels__after = min_size; + right_pct__after = right_pixels__after/adjustable_table_dim; + pct_delta = -(right_pct__after-right_pct__before); + left_pct__after = left_pct__before+pct_delta; + } + + // rjf: commit new percentages + *left_pct_ptr = left_pct__after; + *right_pct_ptr = right_pct__after; + } + } + } + + //- rjf: form stable pcts + ui_ts_col_pcts_stable = push_array(ui_build_arena(), F32, ui_ts_col_pct_count); + for(U64 idx = 0; idx < column_pct_count; idx += 1) + { + ui_ts_col_pcts_stable[idx] = *column_pcts[idx]; + } +} + +internal void +ui_table_beginf(U64 column_pct_count, F32 **column_pcts, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + ui_table_begin(column_pct_count, column_pcts, string); + scratch_end(scratch); +} + +internal void +ui_table_end(void) +{ + ui_pop_parent(); +} + +internal UI_Box * +ui_named_table_vector_begin(String8 string) +{ + ui_set_next_pref_width(ui_pct(1, 0)); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *vector = ui_build_box_from_string(UI_BoxFlag_DrawSideBottom, string); + ui_push_parent(vector); + return vector; +} + +internal UI_Box * +ui_named_table_vector_beginf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Box *vector = ui_named_table_vector_begin(string); + scratch_end(scratch); + return vector; +} + +internal UI_Box * +ui_table_vector_begin(void) +{ + UI_Box *table = ui_top_parent(); + UI_Box *vector = ui_named_table_vector_beginf("###tbl_vec_%p_%I64u", table, table->child_count); + return vector; +} + +internal UI_Signal +ui_table_vector_end(void) +{ + UI_Box *box = ui_pop_parent(); + return ui_signal_from_box(box); +} + +internal UI_Box * +ui_table_cell_begin(void) +{ + UI_Box *vector = ui_top_parent(); + U64 column_idx = vector->child_count; + F32 width_pct = column_idx < ui_ts_col_pct_count ? ui_ts_col_pcts_stable[column_idx] : 1.f; + return ui_table_cell_sized_begin(ui_pct(width_pct, 0)); +} + +internal UI_Signal +ui_table_cell_end(void) +{ + UI_Box *cell = ui_pop_parent(); + return ui_signal_from_box(cell); +} + +internal UI_Box * +ui_table_cell_sized_begin(UI_Size size) +{ + UI_Box *vector = ui_top_parent(); + U64 column_idx = vector->child_count; + ui_set_next_pref_width(size); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *cell = ui_build_box_from_stringf((column_idx > 0 ? UI_BoxFlag_DrawSideLeft : 0), "###tbl_cell_%p_%I64u", vector, vector->child_count); + ui_push_parent(cell); + return cell; +} + +//////////////////////////////// +//~ rjf: Scroll Regions + +internal void +ui_scroll_list_row_block_chunk_list_push(Arena *arena, UI_ScrollListRowBlockChunkList *list, U64 cap, UI_ScrollListRowBlock *block) +{ + UI_ScrollListRowBlockChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = push_array(arena, UI_ScrollListRowBlockChunkNode, 1); + n->cap = cap; + n->v = push_array_no_zero(arena, UI_ScrollListRowBlock, n->cap); + SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + MemoryCopyStruct(&n->v[n->count], block); + n->count += 1; + list->total_count += 1; +} + +internal UI_ScrollListRowBlockArray +ui_scroll_list_row_block_array_from_chunk_list(Arena *arena, UI_ScrollListRowBlockChunkList *list) +{ + UI_ScrollListRowBlockArray array = {0}; + array.count = list->total_count; + array.v = push_array_no_zero(arena, UI_ScrollListRowBlock, array.count); + U64 idx = 0; + for(UI_ScrollListRowBlockChunkNode *n = list->first; n != 0; n = n->next) + { + MemoryCopy(array.v+idx, n->v, sizeof(n->v[0])*n->count); + idx += n->count; + } + return array; +} + +internal U64 +ui_scroll_list_row_from_item(UI_ScrollListRowBlockArray *blocks, U64 item) +{ + U64 result = 0; + { + U64 row_idx = 0; + U64 item_idx = 0; + for(U64 block_idx = 0; block_idx < blocks->count; block_idx += 1) + { + UI_ScrollListRowBlock *block = &blocks->v[block_idx]; + U64 next_row_idx = row_idx + block->row_count; + U64 next_item_idx= item_idx+ block->item_count; + if(item_idx <= item && item < next_item_idx) + { + U64 item_off_rows = (item-item_idx) * (block->row_count/block->item_count); + result = row_idx + item_off_rows; + break; + } + row_idx = next_row_idx; + item_idx = next_item_idx; + } + } + return result; +} + +internal U64 +ui_scroll_list_item_from_row(UI_ScrollListRowBlockArray *blocks, U64 row) +{ + U64 result = 0; + { + U64 row_idx = 0; + U64 item_idx = 0; + for(U64 block_idx = 0; block_idx < blocks->count; block_idx += 1) + { + UI_ScrollListRowBlock *block = &blocks->v[block_idx]; + U64 next_row_idx = row_idx + block->row_count; + U64 next_item_idx= item_idx+ block->item_count; + if(row_idx <= row && row < next_row_idx) + { + result = item_idx; + break; + } + row_idx = next_row_idx; + item_idx = next_item_idx; + } + } + return result; +} + +internal UI_ScrollPt +ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_range, S64 view_num_indices) +{ + //- rjf: unpack + S64 idx_range_dim = Max(dim_1s64(idx_range), 1); + + //- rjf: produce extra flags for cases in which scrolling is disabled + UI_BoxFlags disabled_flags = 0; + if(idx_range.min == idx_range.max) + { + disabled_flags |= UI_BoxFlag_Disabled; + } + + //- rjf: build main container + ui_set_next_pref_size(axis2_flip(axis), off_axis_size); + ui_set_next_child_layout_axis(axis); + UI_Box *container_box = ui_build_box_from_key(UI_BoxFlag_DrawBorder, ui_key_zero()); + + //- rjf: build scroll-min button + UI_Signal min_scroll_sig = {0}; + UI_Parent(container_box) + UI_PrefSize(axis, off_axis_size) + UI_Flags(UI_BoxFlag_DrawBorder|disabled_flags) + UI_TextAlignment(UI_TextAlign_Center) + UI_Font(ui_icon_font()) + { + String8 arrow_string = ui_icon_string_from_kind(axis == Axis2_X ? UI_IconKind_LeftArrow : UI_IconKind_UpArrow); + min_scroll_sig = ui_buttonf("%S##_min_scroll_%i", arrow_string, axis); + } + + //- rjf: main scroller area + UI_Signal space_before_sig = {0}; + UI_Signal space_after_sig = {0}; + UI_Signal scroller_sig = {0}; + UI_Box *scroll_area_box = &ui_g_nil_box; + UI_Box *scroller_box = &ui_g_nil_box; + UI_Parent(container_box) + { + ui_set_next_pref_size(axis, ui_pct(1, 0)); + ui_set_next_child_layout_axis(axis); + scroll_area_box = ui_build_box_from_stringf(0, "##_scroll_area_%i", axis); + UI_Parent(scroll_area_box) + { + // rjf: space before + if(idx_range.max != idx_range.min) + { + ui_set_next_pref_size(axis, ui_pct((F32)((F64)(pt.idx-idx_range.min)/(F64)idx_range_dim), 0)); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *space_before_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "##scroll_area_before"); + space_before_sig = ui_signal_from_box(space_before_box); + } + + // rjf: scroller + UI_Flags(disabled_flags) UI_PrefSize(axis, ui_pct(Clamp(0.01f, (F32)((F64)Max(view_num_indices, 1)/(F64)idx_range_dim), 1.f), 0.f)) + { + scroller_sig = ui_buttonf("##_scroller_%i", axis); + scroller_box = scroller_sig.box; + } + + // rjf: space after + if(idx_range.max != idx_range.min) + { + ui_set_next_pref_size(axis, ui_pct(1.f - (F32)((F64)(pt.idx-idx_range.min)/(F64)idx_range_dim), 0)); + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *space_after_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "##scroll_area_after"); + space_after_sig = ui_signal_from_box(space_after_box); + } + } + } + + //- rjf: build scroll-max button + UI_Signal max_scroll_sig = {0}; + UI_Parent(container_box) + UI_PrefSize(axis, off_axis_size) + UI_Flags(UI_BoxFlag_DrawBorder|disabled_flags) + UI_TextAlignment(UI_TextAlign_Center) + UI_Font(ui_icon_font()) + { + String8 arrow_string = ui_icon_string_from_kind(axis == Axis2_X ? UI_IconKind_RightArrow : UI_IconKind_DownArrow); + max_scroll_sig = ui_buttonf("%S##_max_scroll_%i", arrow_string, axis); + } + + //- rjf: pt * signals -> new pt + UI_ScrollPt new_pt = pt; + { + typedef struct UI_ScrollBarDragData UI_ScrollBarDragData; + struct UI_ScrollBarDragData + { + UI_ScrollPt start_pt; + F32 scroll_space_px; + }; + if(scroller_sig.dragging) + { + if(scroller_sig.pressed) + { + UI_ScrollBarDragData drag_data = {pt, (floor_f32(dim_2f32(scroll_area_box->rect).v[axis])-floor_f32(dim_2f32(scroller_box->rect).v[axis]))}; + ui_store_drag_struct(&drag_data); + } + UI_ScrollBarDragData *drag_data = ui_get_drag_struct(UI_ScrollBarDragData); + UI_ScrollPt original_pt = drag_data->start_pt; + F32 drag_delta = ui_drag_delta().v[axis]; + F32 drag_pct = drag_delta / drag_data->scroll_space_px; + S64 new_idx = original_pt.idx + drag_pct*idx_range_dim; + new_idx = Clamp(idx_range.min, new_idx, idx_range.max); + ui_scroll_pt_target_idx(&new_pt, new_idx); + new_pt.off = 0; + } + if(min_scroll_sig.dragging || space_before_sig.dragging) + { + S64 new_idx = new_pt.idx-1; + new_idx = Clamp(idx_range.min, new_idx, idx_range.max); + ui_scroll_pt_target_idx(&new_pt, new_idx); + } + if(max_scroll_sig.dragging || space_after_sig.dragging) + { + S64 new_idx = new_pt.idx+1; + new_idx = Clamp(idx_range.min, new_idx, idx_range.max); + ui_scroll_pt_target_idx(&new_pt, new_idx); + } + } + return new_pt; +} + +thread_static UI_ScrollPt *ui_scroll_list_scroll_pt_ptr = 0; +thread_static F32 ui_scroll_list_scroll_bar_dim_px = 0; +thread_static Vec2F32 ui_scroll_list_dim_px = {0}; +thread_static Rng1S64 ui_scroll_list_scroll_idx_rng = {0}; + +internal void +ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt, Vec2S64 *cursor_out, Rng1S64 *visible_row_range_out, UI_ScrollListSignal *signal_out) +{ + //- rjf: unpack arguments + Rng1S64 scroll_row_idx_range = r1s64(params->item_range.min, ClampBot(params->item_range.min, params->item_range.max-1)); + S64 num_possible_visible_rows = (S64)(params->dim_px.y/params->row_height_px); + + //- rjf: do keyboard navigation + B32 moved = 0; + if(params->flags & UI_ScrollListFlag_Nav && cursor_out != 0 && ui_is_focus_active()) + { + UI_NavActionList *nav_actions = ui_nav_actions(); + Vec2S64 cursor = *cursor_out; + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + next = n->next; + UI_NavAction *action = &n->v; + if((action->delta.x == 0 && action->delta.y == 0) || + action->flags & (UI_NavActionFlag_KeepMark|UI_NavActionFlag_Delete)) + { + continue; + } + ui_nav_eat_action_node(nav_actions, n); + moved = 1; + switch(action->delta_unit) + { + default:{moved = 0;}break; + case UI_NavDeltaUnit_Element: + { + for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis+1)) + { + cursor.v[axis] += action->delta.v[axis]; + if(cursor.v[axis] < params->cursor_range.min.v[axis]) + { + cursor.v[axis] = params->cursor_range.max.v[axis]; + } + if(cursor.v[axis] > params->cursor_range.max.v[axis]) + { + cursor.v[axis] = params->cursor_range.min.v[axis]; + } + cursor.v[axis] = clamp_1s64(r1s64(params->cursor_range.min.v[axis], params->cursor_range.max.v[axis]), cursor.v[axis]); + } + }break; + case UI_NavDeltaUnit_Chunk: + case UI_NavDeltaUnit_Whole: + { + cursor.x = (action->delta.x>0 ? params->cursor_range.max.x : action->delta.x<0 ? params->cursor_range.min.x + !!params->cursor_min_is_empty_selection[Axis2_X] : cursor.x); + cursor.y += ((action->delta.y>0 ? +(num_possible_visible_rows-3) : action->delta.y<0 ? -(num_possible_visible_rows-3) : 0)); + cursor.y = clamp_1s64(r1s64(params->cursor_range.min.y + !!params->cursor_min_is_empty_selection[Axis2_Y], params->cursor_range.max.y), cursor.y); + }break; + case UI_NavDeltaUnit_EndPoint: + { + for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis+1)) + { + cursor.v[axis] = (action->delta.v[axis]>0 ? params->cursor_range.max.v[axis] : action->delta.v[axis]<0 ? params->cursor_range.min.v[axis] + !!params->cursor_min_is_empty_selection[axis] : cursor.v[axis]); + } + }break; + } + } + if(moved) + { + *cursor_out = cursor; + } + } + + //- rjf: moved -> snap + if(params->flags & UI_ScrollListFlag_Snap && moved) + { + S64 cursor_item_idx = cursor_out->y-1; + if(params->item_range.min <= cursor_item_idx && cursor_item_idx <= params->item_range.max) + { + //- rjf: compute visible row range + Rng1S64 visible_row_range = r1s64(scroll_pt->idx + 0 - !!(scroll_pt->off < 0), + scroll_pt->idx + 0 + num_possible_visible_rows + 1); + + //- rjf: compute cursor row range from cursor item + Rng1S64 cursor_visibility_row_range = {0}; + if(params->row_blocks.count == 0) + { + cursor_visibility_row_range = r1s64(cursor_item_idx-1, cursor_item_idx+3); + } + else + { + cursor_visibility_row_range.min = (S64)ui_scroll_list_row_from_item(¶ms->row_blocks, (U64)cursor_item_idx); + cursor_visibility_row_range.max = cursor_visibility_row_range.min + 4; + } + + //- rjf: compute deltas & apply + S64 min_delta = Min(0, cursor_visibility_row_range.min-visible_row_range.min); + S64 max_delta = Max(0, cursor_visibility_row_range.max-visible_row_range.max); + S64 new_idx = scroll_pt->idx+min_delta+max_delta; + new_idx = clamp_1s64(scroll_row_idx_range, new_idx); + ui_scroll_pt_target_idx(scroll_pt, new_idx); + } + } + + //- rjf: output signal + if(signal_out != 0) + { + signal_out->cursor_moved = moved; + } + + //- rjf: determine ranges & limits + Rng1S64 visible_row_range = r1s64(scroll_pt->idx + (S64)(scroll_pt->off) + 0 - !!(scroll_pt->off < 0), + scroll_pt->idx + (S64)(scroll_pt->off) + 0 + num_possible_visible_rows + 1); + visible_row_range.min = clamp_1s64(scroll_row_idx_range, visible_row_range.min); + visible_row_range.max = clamp_1s64(scroll_row_idx_range, visible_row_range.max); + *visible_row_range_out = visible_row_range; + + //- rjf: store thread-locals + ui_scroll_list_scroll_bar_dim_px = ui_top_font_size()*1.5f; + ui_scroll_list_scroll_pt_ptr = scroll_pt; + ui_scroll_list_dim_px = params->dim_px; + ui_scroll_list_scroll_idx_rng = scroll_row_idx_range; + + //- rjf: build top-level container + UI_Box *container_box = &ui_g_nil_box; + UI_FixedWidth(params->dim_px.x) UI_FixedHeight(params->dim_px.y) UI_ChildLayoutAxis(Axis2_X) + { + container_box = ui_build_box_from_key(0, ui_key_zero()); + } + + //- rjf: build scrollable container + UI_Box *scrollable_container_box = &ui_g_nil_box; + UI_Parent(container_box) UI_ChildLayoutAxis(Axis2_Y) UI_FixedWidth(params->dim_px.x-ui_scroll_list_scroll_bar_dim_px) UI_FixedHeight(params->dim_px.y) + { + scrollable_container_box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_AllowOverflowY|UI_BoxFlag_Scroll, "###sp"); + scrollable_container_box->view_off.y = scrollable_container_box->view_off_target.y = params->row_height_px*mod_f32(scroll_pt->off, 1.f) + params->row_height_px*(scroll_pt->off < 0) - params->row_height_px*(scroll_pt->off == -1.f && scroll_pt->idx == 1); + } + + //- rjf: build vertical scroll bar + UI_Parent(container_box) + { + ui_set_next_fixed_width(ui_scroll_list_scroll_bar_dim_px); + ui_set_next_fixed_height(ui_scroll_list_dim_px.y); + *ui_scroll_list_scroll_pt_ptr = ui_scroll_bar(Axis2_Y, + ui_px(ui_scroll_list_scroll_bar_dim_px, 1.f), + *ui_scroll_list_scroll_pt_ptr, + scroll_row_idx_range, + num_possible_visible_rows); + } + + //- rjf: begin scrollable region + ui_push_parent(container_box); + ui_push_parent(scrollable_container_box); + ui_push_pref_height(ui_px(params->row_height_px, 1.f)); +} + +internal void +ui_scroll_list_end(void) +{ + ui_pop_pref_height(); + UI_Box *scrollable_container_box = ui_pop_parent(); + UI_Box *container_box = ui_pop_parent(); + + //- rjf: scroll + { + UI_Signal sig = ui_signal_from_box(scrollable_container_box); + if(sig.scroll.y != 0) + { + S64 new_idx = ui_scroll_list_scroll_pt_ptr->idx + sig.scroll.y; + new_idx = clamp_1s64(ui_scroll_list_scroll_idx_rng, new_idx); + ui_scroll_pt_target_idx(ui_scroll_list_scroll_pt_ptr, new_idx); + } + ui_scroll_pt_clamp_idx(ui_scroll_list_scroll_pt_ptr, ui_scroll_list_scroll_idx_rng); + } +} diff --git a/src/ui/ui_basic_widgets.h b/src/ui/ui_basic_widgets.h new file mode 100644 index 00000000..c6bd0f01 --- /dev/null +++ b/src/ui/ui_basic_widgets.h @@ -0,0 +1,179 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef UI_BASIC_WIDGETS_H +#define UI_BASIC_WIDGETS_H + +//////////////////////////////// +//~ rjf: Scroll List Types + +typedef U32 UI_ScrollListFlags; +enum +{ + UI_ScrollListFlag_Nav = (1<<0), + UI_ScrollListFlag_Snap = (1<<1), + UI_ScrollListFlag_All = 0xffffffff, +}; + +typedef struct UI_ScrollListRowBlock UI_ScrollListRowBlock; +struct UI_ScrollListRowBlock +{ + U64 row_count; + U64 item_count; +}; + +typedef struct UI_ScrollListRowBlockChunkNode UI_ScrollListRowBlockChunkNode; +struct UI_ScrollListRowBlockChunkNode +{ + UI_ScrollListRowBlockChunkNode *next; + UI_ScrollListRowBlock *v; + U64 count; + U64 cap; +}; + +typedef struct UI_ScrollListRowBlockChunkList UI_ScrollListRowBlockChunkList; +struct UI_ScrollListRowBlockChunkList +{ + UI_ScrollListRowBlockChunkNode *first; + UI_ScrollListRowBlockChunkNode *last; + U64 chunk_count; + U64 total_count; +}; + +typedef struct UI_ScrollListRowBlockArray UI_ScrollListRowBlockArray; +struct UI_ScrollListRowBlockArray +{ + UI_ScrollListRowBlock *v; + U64 count; +}; + +typedef struct UI_ScrollListParams UI_ScrollListParams; +struct UI_ScrollListParams +{ + UI_ScrollListFlags flags; + Vec2F32 dim_px; + F32 row_height_px; + UI_ScrollListRowBlockArray row_blocks; + Rng2S64 cursor_range; + Rng1S64 item_range; + B32 cursor_min_is_empty_selection[Axis2_COUNT]; +}; + +typedef struct UI_ScrollListSignal UI_ScrollListSignal; +struct UI_ScrollListSignal +{ + B32 cursor_moved; +}; + +//////////////////////////////// +//~ rjf: Basic Widgets + +internal UI_Signal ui_spacer(UI_Size size); +internal UI_Signal ui_label(String8 string); +internal UI_Signal ui_labelf(char *fmt, ...); +internal void ui_label_multiline(F32 max, String8 string); +internal void ui_label_multilinef(F32 max, char *fmt, ...); +internal UI_Signal ui_button(String8 string); +internal UI_Signal ui_buttonf(char *fmt, ...); +internal UI_Signal ui_hover_label(String8 string); +internal UI_Signal ui_hover_labelf(char *fmt, ...); +internal UI_Signal ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, String8 string); +internal UI_Signal ui_line_editf(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, char *fmt, ...); + +//////////////////////////////// +//~ rjf: Special Buttons + +internal UI_Signal ui_close_button(String8 string); +internal UI_Signal ui_close_buttonf(char *fmt, ...); +internal UI_Signal ui_expander(B32 is_expanded, String8 string); +internal UI_Signal ui_expanderf(B32 is_expanded, char *fmt, ...); +internal UI_Signal ui_sort_header(B32 sorting, B32 ascending, String8 string); +internal UI_Signal ui_sort_headerf(B32 sorting, B32 ascending, char *fmt, ...); + +//////////////////////////////// +//~ rjf: Color Pickers + +//- rjf: tooltips +internal void ui_do_color_tooltip_hsv(Vec3F32 hsv); +internal void ui_do_color_tooltip_hsva(Vec4F32 hsva); + +//- rjf: saturation/value picker +internal UI_Signal ui_sat_val_picker(F32 hue, F32 *out_sat, F32 *out_val, String8 string); +internal UI_Signal ui_sat_val_pickerf(F32 hue, F32 *out_sat, F32 *out_val, char *fmt, ...); + +//- rjf: hue picker +internal UI_Signal ui_hue_picker(F32 *out_hue, F32 sat, F32 val, String8 string); +internal UI_Signal ui_hue_pickerf(F32 *out_hue, F32 sat, F32 val, char *fmt, ...); + +//- rjf: alpha picker +internal UI_Signal ui_alpha_picker(F32 *out_alpha, String8 string); +internal UI_Signal ui_alpha_pickerf(F32 *out_alpha, char *fmt, ...); + +//////////////////////////////// +//~ rjf: Simple Layout Widgets + +internal UI_Signal ui_row_begin(void); +internal void ui_row_end(void); +internal UI_Signal ui_column_begin(void); +internal void ui_column_end(void); +internal UI_Signal ui_named_row_begin(String8 string); +internal void ui_named_row_end(void); +internal UI_Signal ui_named_column_begin(String8 string); +internal void ui_named_column_end(void); + +//////////////////////////////// +//~ rjf: Floating Panes + +internal UI_Box *ui_pane_begin(Rng2F32 rect, String8 string); +internal UI_Box *ui_pane_beginf(Rng2F32 rect, char *fmt, ...); +internal void ui_pane_end(void); + +//////////////////////////////// +//~ rjf: Tables + +internal void ui_table_begin(U64 column_pct_count, F32 **column_pcts, String8 string); +internal void ui_table_beginf(U64 column_pct_count, F32 **column_pcts, char *fmt, ...); +internal void ui_table_end(void); +internal UI_Box * ui_named_table_vector_begin(String8 string); +internal UI_Box * ui_named_table_vector_beginf(char *fmt, ...); +internal UI_Box * ui_table_vector_begin(void); +internal UI_Signal ui_table_vector_end(void); +internal UI_Box * ui_table_cell_begin(void); +internal UI_Signal ui_table_cell_end(void); +internal UI_Box * ui_table_cell_sized_begin(UI_Size size); + +//////////////////////////////// +//~ rjf: Scroll Regions + +internal void ui_scroll_list_row_block_chunk_list_push(Arena *arena, UI_ScrollListRowBlockChunkList *list, U64 cap, UI_ScrollListRowBlock *block); +internal UI_ScrollListRowBlockArray ui_scroll_list_row_block_array_from_chunk_list(Arena *arena, UI_ScrollListRowBlockChunkList *list); +internal U64 ui_scroll_list_row_from_item(UI_ScrollListRowBlockArray *blocks, U64 item); +internal U64 ui_scroll_list_item_from_row(UI_ScrollListRowBlockArray *blocks, U64 row); + +internal UI_ScrollPt ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_range, S64 view_num_indices); +internal void ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt_out, Vec2S64 *cursor_out, Rng1S64 *visible_row_range_out, UI_ScrollListSignal *signal_out); +internal void ui_scroll_list_end(void); + +//////////////////////////////// +//~ rjf: Macro Loop Wrappers + +#define UI_Row DeferLoop(ui_row_begin(), ui_row_end()) +#define UI_Column DeferLoop(ui_column_begin(), ui_column_end()) +#define UI_NamedRow(s) DeferLoop(ui_named_row_begin(s), ui_named_row_end()) +#define UI_NamedColumn(s) DeferLoop(ui_named_column_begin(s), ui_named_column_end()) +#define UI_Pane(r, s) DeferLoop(ui_pane_begin(r, s), ui_pane_end()) +#define UI_PaneF(r, ...) DeferLoop(ui_pane_beginf(r, __VA_ARGS__), ui_pane_end()) +#define UI_Padding(size) DeferLoop(ui_spacer(size), ui_spacer(size)) +#define UI_Center UI_Padding(ui_pct(1, 0)) + +#define UI_Table(col_pct_count, col_pcts, s) DeferLoop(ui_table_begin(col_pct_count, col_pcts, s), ui_table_end()) +#define UI_TableF(col_pct_count, col_pcts, ...) DeferLoop(ui_table_beginf(col_pct_count, col_pcts, __VA_ARGS__), ui_table_end()) +#define UI_NamedTableVector(s) DeferLoop(ui_named_table_vector_begin(s), ui_table_vector_end()) +#define UI_NamedTableVectorF(...) DeferLoop(ui_named_table_vector_beginf(__VA_ARGS__), ui_table_vector_end()) +#define UI_TableVector DeferLoop(ui_table_vector_begin(), ui_table_vector_end()) +#define UI_TableCell DeferLoop(ui_table_cell_begin(), ui_table_cell_end()) +#define UI_TableCellSized(size) DeferLoop(ui_table_cell_sized_begin(size), ui_table_cell_end()) + +#define UI_ScrollList(params, scroll_pt_out, cursor_out, visible_row_range_out, signal_out) DeferLoop(ui_scroll_list_begin((params), (scroll_pt_out), (cursor_out), (visible_row_range_out), (signal_out)), ui_scroll_list_end()) + +#endif // UI_BASIC_WIDGETS_H diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c new file mode 100644 index 00000000..0ea22ca0 --- /dev/null +++ b/src/ui/ui_core.c @@ -0,0 +1,2700 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#undef RADDBG_LAYER_COLOR +#define RADDBG_LAYER_COLOR 0.80f, 0.40f, 0.35f + +//////////////////////////////// +//~ rjf: Globals + +thread_static UI_State *ui_state = 0; + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal U64 +ui_hash_from_string(U64 seed, String8 string) +{ + U64 result = seed; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal String8 +ui_hash_part_from_key_string(String8 string) +{ + String8 result = string; + + // rjf: look for ### patterns, which can replace the entirety of the part of + // the string that is hashed. + U64 hash_replace_signifier_pos = str8_find_needle(string, 0, str8_lit("###"), 0); + if(hash_replace_signifier_pos < string.size) + { + result = str8_skip(string, hash_replace_signifier_pos); + } + + return result; +} + +internal String8 +ui_display_part_from_key_string(String8 string) +{ + U64 hash_pos = str8_find_needle(string, 0, str8_lit("##"), 0); + string.size = hash_pos; + return string; +} + +internal UI_Key +ui_key_zero(void) +{ + UI_Key result = {0}; + return result; +} + +internal UI_Key +ui_key_make(U64 v) +{ + UI_Key result = {v}; + return result; +} + +internal UI_Key +ui_key_from_string(UI_Key seed_key, String8 string) +{ + ProfBeginFunction(); + UI_Key result = {0}; + if(string.size != 0) + { + String8 hash_part = ui_hash_part_from_key_string(string); + result.u64[0] = ui_hash_from_string(seed_key.u64[0], hash_part); + } + ProfEnd(); + return result; +} + +internal UI_Key +ui_key_from_stringf(UI_Key seed_key, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Key key = ui_key_from_string(seed_key, string); + scratch_end(scratch); + return key; +} + +internal B32 +ui_key_match(UI_Key a, UI_Key b) +{ + return a.u64[0] == b.u64[0]; +} + +//////////////////////////////// +//~ rjf: Navigation Action List Building & Consumption Functions + +internal void +ui_nav_action_list_push(Arena *arena, UI_NavActionList *list, UI_NavAction action) +{ + UI_NavActionNode *node = push_array(arena, UI_NavActionNode, 1); + DLLPushBack(list->first, list->last, node); + MemoryCopyStruct(&node->v, &action); + list->count += 1; +} + +internal void +ui_nav_eat_action_node(UI_NavActionList *list, UI_NavActionNode *node) +{ + DLLRemove(list->first, list->last, node); + list->count -= 1; +} + +//////////////////////////////// +//~ rjf: High Level Navigation Action => Text Operations + +internal B32 +ui_nav_char_is_scan_boundary(U8 c) +{ + return char_is_space(c) || char_is_slash(c); +} + +internal S64 +ui_nav_scanned_column_from_column(String8 string, S64 start_column, Side side) +{ + S64 new_column = start_column; + S64 delta = (!!side)*2 - 1; + B32 found_boundary = 0; + for(S64 col = start_column+delta; 1 <= col && col <= string.size+1; col += delta) + { + U8 byte = (col <= string.size) ? string.str[col-1] : 0; + B32 is_boundary = (ui_nav_char_is_scan_boundary(byte) ^ !(side == Side_Max)); + if((found_boundary && !is_boundary) || + (col == 1 || col == string.size+1)) + { + new_column = col + (!side && col != 1); + break; + } + else if(!found_boundary && is_boundary) + { + found_boundary = 1; + } + } + return new_column; +} + +internal UI_NavTxtOp +ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8 line, TxtPt cursor, TxtPt mark) +{ + TxtPt next_cursor = cursor; + TxtPt next_mark = mark; + TxtRng range = {0}; + String8 replace = {0}; + String8 copy = {0}; + UI_NavTxtOpFlags flags = 0; + Vec2S32 delta = action.delta; + Vec2S32 original_delta = delta; + + //- rjf: resolve high-level delta into byte delta, based on unit + switch(action.delta_unit) + { + default:{}break; + case UI_NavDeltaUnit_Element: + { + // TODO(rjf): this should account for multi-byte characters in UTF-8... for now, just assume ASCII and + // no-op + }break; + case UI_NavDeltaUnit_Chunk: + { + delta.x = (S32)ui_nav_scanned_column_from_column(line, cursor.column, delta.x > 0 ? Side_Max : Side_Min) - cursor.column; + }break; + case UI_NavDeltaUnit_Whole: + case UI_NavDeltaUnit_EndPoint: + { + S64 first_nonwhitespace_column = 1; + for(U64 idx = 0; idx < line.size; idx += 1) + { + if(!char_is_space(line.str[idx])) + { + first_nonwhitespace_column = (S64)idx + 1; + break; + } + } + S64 home_dest_column = (cursor.column == first_nonwhitespace_column) ? 1 : first_nonwhitespace_column; + delta.x = (delta.x > 0) ? ((S64)line.size+1 - cursor.column) : (home_dest_column - cursor.column); + }break; + } + + //- rjf: zero delta + if(!txt_pt_match(cursor, mark) && action.flags & UI_NavActionFlag_ZeroDeltaOnSelect) + { + delta = v2s32(0, 0); + } + + //- rjf: form next cursor + if(txt_pt_match(cursor, mark) || !(action.flags & UI_NavActionFlag_ZeroDeltaOnSelect)) + { + next_cursor.column += delta.x; + } + + //- rjf: cap at line + if(action.flags & UI_NavActionFlag_CapAtLine) + { + next_cursor.column = Clamp(1, next_cursor.column, (S64)(line.size+1)); + } + + //- rjf: in some cases, we want to pick a selection side based on the delta + if(!txt_pt_match(cursor, mark) && action.flags & UI_NavActionFlag_PickSelectSide) + { + if(original_delta.x < 0 || original_delta.y < 0) + { + next_cursor = next_mark = txt_pt_min(cursor, mark); + } + else if(original_delta.x > 0 || original_delta.y > 0) + { + next_cursor = next_mark = txt_pt_max(cursor, mark); + } + } + + //- rjf: copying + if(action.flags & UI_NavActionFlag_Copy) + { + if(cursor.line == mark.line) + { + copy = str8_substr(line, r1u64(cursor.column-1, mark.column-1)); + flags |= UI_NavTxtOpFlag_Copy; + } + else + { + flags |= UI_NavTxtOpFlag_Invalid; + } + } + + //- rjf: pasting + if(action.flags & UI_NavActionFlag_Paste) + { + range = txt_rng(cursor, mark); + replace = os_get_clipboard_text(arena); + next_cursor = next_mark = txt_pt(cursor.line, cursor.column+replace.size); + } + + //- rjf: deletion + if(action.flags & UI_NavActionFlag_Delete) + { + TxtPt new_pos = txt_pt_min(next_cursor, next_mark); + range = txt_rng(next_cursor, next_mark); + replace = str8_lit(""); + next_cursor = next_mark = new_pos; + } + + //- rjf: stick mark to cursor, when we don't want to keep it in the same spot + if(!(action.flags & UI_NavActionFlag_KeepMark)) + { + next_mark = next_cursor; + } + + //- rjf: insertion + if(action.insertion.size != 0) + { + range = txt_rng(cursor, mark); + replace = push_str8_copy(arena, action.insertion); + next_cursor = next_mark = txt_pt(range.min.line, range.min.column + action.insertion.size); + } + + //- rjf: replace & commit -> replace entire range + if(action.flags & UI_NavActionFlag_ReplaceAndCommit) + { + range = txt_rng(txt_pt(cursor.line, 1), txt_pt(cursor.line, line.size+1)); + } + + //- rjf: determine if this event should be taken, based on bounds of cursor + { + if(next_cursor.column > line.size+1 || 1 > next_cursor.column || action.delta.y != 0) + { + flags |= UI_NavTxtOpFlag_Invalid; + } + next_cursor.column = Clamp(1, next_cursor.column, line.size+replace.size+1); + next_mark.column = Clamp(1, next_mark.column, line.size+replace.size+1); + } + + //- rjf: build+fill + UI_NavTxtOp op = {0}; + { + op.flags = flags; + op.replace = replace; + op.copy = copy; + op.range = range; + op.cursor = next_cursor; + op.mark = next_mark; + } + return op; +} + +//////////////////////////////// +//~ rjf: Single-Line String Modification + +internal String8 +ui_nav_push_string_replace_range(Arena *arena, String8 string, Rng1S64 col_range, String8 replace) +{ + //- rjf: convert to offset range + Rng1U64 range = + { + (U64)(col_range.min-1), + (U64)(col_range.max-1), + }; + + //- rjf: clamp range + if(range.min > string.size) + { + range.min = 0; + } + if(range.max > string.size) + { + range.max = string.size; + } + + //- rjf: calculate new size + U64 old_size = string.size; + U64 new_size = old_size - (range.max - range.min) + replace.size; + + //- rjf: push+fill new string storage + U8 *push_base = push_array(arena, U8, new_size); + { + MemoryCopy(push_base+0, string.str, range.min); + MemoryCopy(push_base+range.min+replace.size, string.str+range.max, string.size-range.max); + if(replace.str != 0) + { + MemoryCopy(push_base+range.min, replace.str, replace.size); + } + } + + return str8(push_base, new_size); +} + +//////////////////////////////// +//~ rjf: Sizes + +internal UI_Size +ui_size(UI_SizeKind kind, F32 value, F32 strictness) +{ + UI_Size size = {kind, value, strictness}; + return size; +} + +//////////////////////////////// +//~ rjf: Scroll Point Type Functions + +internal UI_ScrollPt +ui_scroll_pt(S64 idx, F32 off) +{ + UI_ScrollPt pt = {idx, off}; + return pt; +} + +internal void +ui_scroll_pt_target_idx(UI_ScrollPt *v, S64 idx) +{ + v->off = mod_f32(v->off, 1.f) + (F32)(v->idx+(S64)v->off - idx); + v->idx = idx; +} + +internal void +ui_scroll_pt_clamp_idx(UI_ScrollPt *v, Rng1S64 range) +{ + if(v->idx < range.min || range.max < v->idx) + { + S64 clamped = range.min; + ui_scroll_pt_target_idx(v, clamped); + } +} + +//////////////////////////////// +//~ rjf: Boxes + +internal B32 +ui_box_is_nil(UI_Box *box) +{ + return box == 0 || box == &ui_g_nil_box; +} + +internal UI_BoxRec +ui_box_rec_df(UI_Box *box, UI_Box *root, U64 sib_member_off, U64 child_member_off) +{ + UI_BoxRec result = {0}; + result.next = &ui_g_nil_box; + if(!ui_box_is_nil(*MemberFromOffset(UI_Box **, box, child_member_off))) + { + result.next = *MemberFromOffset(UI_Box **, box, child_member_off); + result.push_count = 1; + } + else for(UI_Box *p = box; !ui_box_is_nil(p) && p != root; p = p->parent) + { + if(!ui_box_is_nil(*MemberFromOffset(UI_Box **, p, sib_member_off))) + { + result.next = *MemberFromOffset(UI_Box **, p, sib_member_off); + break; + } + result.pop_count += 1; + } + return result; +} + +internal void +ui_box_list_push(Arena *arena, UI_BoxList *list, UI_Box *box) +{ + UI_BoxNode *n = push_array(arena, UI_BoxNode, 1); + n->box = box; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +//////////////////////////////// +//~ rjf: State Building / Selecting + +internal UI_State * +ui_state_alloc(void) +{ + Arena *arena = arena_alloc(); + UI_State *ui = push_array(arena, UI_State, 1); + ui->arena = arena; + ui->build_arenas[0] = arena_alloc(); + ui->build_arenas[1] = arena_alloc(); + ui->drag_state_arena = arena_alloc(); + ui->box_table_size = 4096; + ui->box_table = push_array(arena, UI_BoxHashSlot, ui->box_table_size); + return ui; +} + +internal void +ui_state_release(UI_State *state) +{ + arena_release(state->drag_state_arena); + for(int i = 0; i < ArrayCount(state->build_arenas); i += 1) + { + arena_release(state->build_arenas[i]); + } + arena_release(state->arena); +} + +internal UI_Box * +ui_root_from_state(UI_State *state) +{ + return state->root; +} + +internal B32 +ui_animating_from_state(UI_State *state) +{ + return state->is_animating; +} + +internal void +ui_select_state(UI_State *state) +{ + ui_state = state; +} + +internal UI_State * +ui_get_selected_state(void) +{ + return ui_state; +} + +//////////////////////////////// +//~ rjf: Implicit State Accessors/Mutators + +//- rjf: per-frame info + +internal Arena * +ui_build_arena(void) +{ + Arena *result = ui_state->build_arenas[ui_state->build_index%ArrayCount(ui_state->build_arenas)]; + return result; +} + +internal OS_Handle +ui_window(void) +{ + return ui_state->window; +} + +internal OS_EventList * +ui_events(void) +{ + return ui_state->events; +} + +internal UI_NavActionList * +ui_nav_actions(void) +{ + return ui_state->nav_actions; +} + +internal Vec2F32 +ui_mouse(void) +{ + return ui_state->mouse; +} + +internal F_Tag +ui_icon_font(void) +{ + return ui_state->icon_info.icon_font; +} + +internal String8 +ui_icon_string_from_kind(UI_IconKind icon_kind) +{ + return ui_state->icon_info.icon_kind_text_map[icon_kind]; +} + +internal F32 +ui_dt(void) +{ + return ui_state->animation_dt; +} + +//- rjf: drag data + +internal Vec2F32 +ui_drag_delta(void) +{ + return sub_2f32(ui_mouse(), ui_state->drag_start_mouse); +} + +internal void +ui_store_drag_data(String8 string) +{ + arena_clear(ui_state->drag_state_arena); + ui_state->drag_state_data = push_str8_copy(ui_state->drag_state_arena, string); +} + +internal String8 +ui_get_drag_data(U64 min_required_size) +{ + if(ui_state->drag_state_data.size < min_required_size) + { + Temp scratch = scratch_begin(0, 0); + String8 str = {push_array(scratch.arena, U8, min_required_size), min_required_size}; + ui_store_drag_data(str); + scratch_end(scratch); + } + return ui_state->drag_state_data; +} + +//- rjf: interaction keys + +internal UI_Key +ui_hot_key(void) +{ + return ui_state->hot_box_key; +} + +internal UI_Key +ui_active_key(Side side) +{ + return ui_state->active_box_key[side]; +} + +//- rjf: controls over interaction + +internal void +ui_kill_action(void) +{ + ui_state->active_box_key[Side_Min] = ui_state->active_box_key[Side_Max] = ui_key_zero(); +} + +//- rjf: box cache lookup + +internal UI_Box * +ui_box_from_key(UI_Key key) +{ + ProfBeginFunction(); + UI_Box *result = &ui_g_nil_box; + if(!ui_key_match(key, ui_key_zero())) + { + U64 slot = key.u64[0] % ui_state->box_table_size; + for(UI_Box *b = ui_state->box_table[slot].hash_first; !ui_box_is_nil(b); b = b->hash_next) + { + if(ui_key_match(b->key, key)) + { + result = b; + break; + } + } + } + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Top-Level Building API + +internal void +ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_actions, UI_IconInfo *icon_info, F32 real_dt, F32 animation_dt) +{ + //- rjf: reset per-build ui state + { + UI_ZeroAllStacks(ui_state); + ui_state->root = &ui_g_nil_box; + ui_state->ctx_menu_touched_this_frame = 0; + ui_state->is_animating = 0; + ui_state->clipboard_copy_key = ui_key_zero(); + ui_state->last_build_box_count = ui_state->build_box_count; + ui_state->build_box_count = 0; + } + + //- rjf: fill build phase parameters + { + ui_state->events = events; + ui_state->window = window; + ui_state->nav_actions = nav_actions; + ui_state->mouse = os_mouse_from_window(window); + ui_state->animation_dt = animation_dt; + MemoryZeroStruct(&ui_state->icon_info); + ui_state->icon_info.icon_font = icon_info->icon_font; + for(UI_IconKind icon_kind = UI_IconKind_Null; + icon_kind < UI_IconKind_COUNT; + icon_kind = (UI_IconKind)(icon_kind + 1)) + { + ui_state->icon_info.icon_kind_text_map[icon_kind] = push_str8_copy(ui_build_arena(), icon_info->icon_kind_text_map[icon_kind]); + } + } + + //- rjf: do default navigation + { + Temp scratch = scratch_begin(0, 0); + if(!ui_key_match(ui_state->default_nav_root_key, ui_key_zero())) + { + UI_Box *nav_root = ui_box_from_key(ui_state->default_nav_root_key); + if(!ui_box_is_nil(nav_root)) + { + //- rjf: no child has the active focus -> do navigation at this layer + if(ui_key_match(ui_key_zero(), nav_root->default_nav_focus_active_key)) + { + for(;;) + { + B32 moved = 0; + UI_Box *focus_box = ui_box_from_key(nav_root->default_nav_focus_next_hot_key); + UI_BoxList next_focus_box_candidates = {0}; + + // rjf: gather & consume events & nav actions + B32 nav_next = 0; + B32 nav_prev = 0; + Axis2 axis_lock = Axis2_Invalid; + if(os_key_press(events, window, 0, OS_Key_Tab)) + { + nav_next = 1; + } + if(os_key_press(events, window, OS_EventFlag_Shift, OS_Key_Tab)) + { + nav_prev = 1; + } + for(UI_NavActionNode *node = nav_actions->first, *next = 0; + node != 0; + node = next) + { + next = node->next; + B32 taken = 0; + if(node->v.delta.x == 0 && node->v.delta.y == 0) + { + continue; + } + if(((node->v.delta.x > 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavX) || node->v.delta.x == 0) && + ((node->v.delta.y > 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavY) || node->v.delta.y == 0)) + { + taken = 1; + nav_next = 1; + } + if(((node->v.delta.x < 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavX) || node->v.delta.x == 0) && + ((node->v.delta.y < 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavY) || node->v.delta.y == 0)) + { + taken = 1; + nav_prev = 1; + } + if(node->v.flags & UI_NavActionFlag_ExplicitDirectional) + { + axis_lock = node->v.delta.x != 0 ? Axis2_X : Axis2_Y; + } + if(taken) + { + ui_nav_eat_action_node(nav_actions, node); + } + } + + // rjf: [+] directional movement + if(nav_next) + { + UI_Box *search_start = ui_box_is_nil(focus_box) ? nav_root : focus_box; + U64 moved_in_axis[Axis2_COUNT] = {0}; + moved = 1; + for(UI_Box *box = search_start;;) + { + if(box != search_start && !(box->flags & UI_BoxFlag_FocusNavSkip) && (box->flags & UI_BoxFlag_Clickable || ui_box_is_nil(box)) && (axis_lock == Axis2_Invalid || moved_in_axis[axis_lock] > 0)) + { + ui_box_list_push(scratch.arena, &next_focus_box_candidates, box); + if(axis_lock == Axis2_Invalid || moved_in_axis[axis_lock] > 1) + { + break; + } + } + UI_Box *last_box = box; + if(!ui_box_is_nil(box->first)) + { + moved_in_axis[box->child_layout_axis] += 1; + box = box->first; + } + else for(UI_Box *p = box; !ui_box_is_nil(p) && p != nav_root; p = p->parent) + { + if(!ui_box_is_nil(p->next)) + { + moved_in_axis[p->parent->child_layout_axis] += 1; + box = p->next; + break; + } + } + if(last_box == box) + { + ui_box_list_push(scratch.arena, &next_focus_box_candidates, &ui_g_nil_box); + break; + } + } + } + + // rjf: [-] directional movement + if(nav_prev) + { + UI_Box *search_start = ui_box_is_nil(focus_box) ? nav_root : focus_box; + U64 moved_in_axis[Axis2_COUNT] = {0}; + moved = 1; + for(UI_Box *box = search_start;;) + { + if(box != search_start && !(box->flags & UI_BoxFlag_FocusNavSkip) && (box->flags & UI_BoxFlag_Clickable || ui_box_is_nil(box)) && (axis_lock == Axis2_Invalid || moved_in_axis[axis_lock] > 0)) + { + ui_box_list_push(scratch.arena, &next_focus_box_candidates, box); + if(axis_lock == Axis2_Invalid || moved_in_axis[axis_lock] > 1) + { + break; + } + } + UI_Box *last_box = box; + UI_Box *root_descendant = &ui_g_nil_box; + if(box == nav_root && box == search_start) + { + for(UI_Box *d = box->last; !ui_box_is_nil(d); d = d->last) + { + moved_in_axis[d->parent->child_layout_axis] += 1; + root_descendant = d; + } + } + UI_Box *prev_descendant = &ui_g_nil_box; + for(UI_Box *d = box->prev; !ui_box_is_nil(d); d = d->last) + { + moved_in_axis[d->parent->child_layout_axis] += 1; + prev_descendant = d; + } + if(!ui_box_is_nil(root_descendant)) + { + box = root_descendant; + } + else if(!ui_box_is_nil(prev_descendant)) + { + box = prev_descendant; + } + else if(box->parent != nav_root) + { + moved_in_axis[box->parent->child_layout_axis] += 1; + box = box->parent; + } + if(box == last_box) + { + ui_box_list_push(scratch.arena, &next_focus_box_candidates, &ui_g_nil_box); + break; + } + } + } + + // rjf: scan candidates and grab next focus box + UI_Box *next_focus_box = focus_box; + F32 best_distance_from_start = 1000000; + for(UI_BoxNode *n = next_focus_box_candidates.first; n != 0; n = n->next) + { + UI_Box *box = n->box; + F32 distance_from_start = 0; + if(axis_lock != Axis2_Invalid) + { + distance_from_start = abs_f32(center_2f32(box->rect).v[axis2_flip(axis_lock)] - center_2f32(focus_box->rect).v[axis2_flip(axis_lock)]); + } + if(distance_from_start < best_distance_from_start && box != focus_box) + { + next_focus_box = box; + best_distance_from_start = distance_from_start; + } + } + + // rjf: commit next focus box + nav_root->default_nav_focus_next_hot_key = next_focus_box->key; + + // rjf: no movement -> break + if(moved == 0) + { + break; + } + } + } + + //- rjf: some child has the active focus -> accept escape keys to pop from the active key stack + if(!ui_key_match(ui_key_zero(), nav_root->default_nav_focus_active_key)) + { + for(;os_key_press(events, window, 0, OS_Key_Esc);) + { + UI_Box *prev_focus_root = nav_root; + for(UI_Box *focus_root = ui_box_from_key(nav_root->default_nav_focus_active_key); + !ui_box_is_nil(focus_root);) + { + UI_Box *next_focus_root = ui_box_from_key(focus_root->default_nav_focus_active_key); + if(ui_box_is_nil(next_focus_root)) + { + prev_focus_root->default_nav_focus_next_active_key = ui_key_zero(); + break; + } + else + { + prev_focus_root = focus_root; + focus_root = next_focus_root; + } + } + } + } + + //- rjf: some child has the active focus -> detect events which will cause an external focus commit + // (e.g. clicking outside of a line edit) + if(!ui_key_match(ui_key_zero(), nav_root->default_nav_focus_active_key)) + { + UI_Box *active_box = ui_box_from_key(nav_root->default_nav_focus_active_key); + if(!ui_box_is_nil(active_box)) + { + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if(!os_handle_match(event->window, window)) + { + continue; + } + if(event->kind == OS_EventKind_Press && + event->key == OS_Key_LeftMouseButton && + !contains_2f32(active_box->rect, ui_mouse())) + { + ui_state->external_focus_commit = 1; + } + } + } + } + } + } + ui_state->default_nav_root_key = ui_key_zero(); + scratch_end(scratch); + } + + //- rjf: next-default-nav-focus keys -> current-default-nav-focus-keys + for(U64 slot_idx = 0; slot_idx < ui_state->box_table_size; slot_idx += 1) + { + for(UI_Box *box = ui_state->box_table[slot_idx].hash_first; + !ui_box_is_nil(box); + box = box->hash_next) + { + box->default_nav_focus_hot_key = box->default_nav_focus_next_hot_key; + box->default_nav_focus_active_key = box->default_nav_focus_next_active_key; + } + } + + //- rjf: build top-level root + { + Rng2F32 window_rect = os_client_rect_from_window(window); + Vec2F32 window_rect_size = dim_2f32(window_rect); + ui_set_next_fixed_width(window_rect_size.x); + ui_set_next_fixed_height(window_rect_size.y); + ui_set_next_child_layout_axis(Axis2_X); + UI_Box *root = ui_build_box_from_stringf(0, "###%I64x", window.u64[0]); + ui_push_parent(root); + ui_state->root = root; + } + + //- rjf: setup parent box for tooltip + Vec2F32 mouse = ui_state->mouse; + UI_FixedX(mouse.x+15.f) UI_FixedY(mouse.y) UI_PrefWidth(ui_children_sum(1.f)) UI_PrefHeight(ui_children_sum(1.f)) + { + ui_set_next_child_layout_axis(Axis2_Y); + ui_state->tooltip_root = ui_build_box_from_stringf(0, "###tooltip_%I64x", window.u64[0]); + } + + //- rjf: setup parent box for context menu + ui_state->ctx_menu_open = ui_state->next_ctx_menu_open; + ui_state->ctx_menu_anchor_key = ui_state->next_ctx_menu_anchor_key; + { + UI_Box *anchor_box = ui_box_from_key(ui_state->ctx_menu_anchor_key); + if(!ui_box_is_nil(anchor_box)) + { + ui_state->ctx_menu_anchor_box_last_pos = anchor_box->rect.p0; + } + Vec2F32 anchor = add_2f32(ui_state->ctx_menu_anchor_box_last_pos, ui_state->ctx_menu_anchor_off); + UI_FixedX(anchor.x) UI_FixedY(anchor.y) UI_PrefWidth(ui_children_sum(1.f)) UI_PrefHeight(ui_children_sum(1.f)) UI_Focus(ui_state->ctx_menu_open) + { + ui_set_next_child_layout_axis(Axis2_Y); + ui_state->ctx_menu_root = ui_build_box_from_stringf(UI_BoxFlag_DrawDropShadow|(ui_state->ctx_menu_open*UI_BoxFlag_DefaultFocusNavY), "###ctx_menu_%I64x", window.u64[0]); + } + } + + //- rjf: reset hot if we don't have an active widget + if(ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) && + ui_key_match(ui_state->active_box_key[Side_Max], ui_key_zero())) + { + ui_state->hot_box_key = ui_key_zero(); + } + + //- rjf: reset active if our active box is disabled + for(Side side = (Side)0; side < Side_COUNT; side = (Side)(side+1)) + { + if(!ui_key_match(ui_state->active_box_key[side], ui_key_zero())) + { + UI_Box *box = ui_box_from_key(ui_state->active_box_key[side]); + if(!ui_box_is_nil(box) && box->flags & UI_BoxFlag_Disabled) + { + ui_state->active_box_key[side] = ui_key_zero(); + } + } + } + + //- rjf: reset active keys if they have been pruned + for(Side side = Side_Min; side < Side_COUNT; side = (Side)(side + 1)) + { + UI_Box *box = ui_box_from_key(ui_state->active_box_key[side]); + if(ui_box_is_nil(box)) + { + ui_state->active_box_key[side] = ui_key_zero(); + } + } + + //- rjf: reset active keys if there is clicking activity on other windows + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if((event->kind == OS_EventKind_Press || event->kind == OS_EventKind_Release) && + !os_handle_match(event->window, window)) + { + for(Side side = Side_Min; side < Side_COUNT; side = (Side)(side + 1)) + { + ui_state->active_box_key[side] = ui_key_zero(); + } + break; + } + } + + //- rjf: tick click timers + for(Side side = (Side)0; side < Side_COUNT; side = (Side)(side + 1)) + { + ui_state->time_since_last_click[side] += real_dt; + } + + + //- rjf: push initial stack values + ui_push_pref_width(ui_px(150.f, 0.4f)); + ui_push_pref_height(ui_px(25.f, 1.f)); + ui_push_background_color(v4f32(0.1f, 0.1f, 0.1f, 0.8f)); + ui_push_text_color(v4f32(1, 1, 1, 0.8f)); + ui_push_border_color(v4f32(1, 1, 1, 0.1f)); + ui_push_corner_radius(0.f); +} + +internal void +ui_end_build(void) +{ + ProfBeginFunction(); + + //- rjf: escape -> close context menu + if(ui_state->ctx_menu_open != 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + { + ui_ctx_menu_close(); + } + + //- rjf: prune untouched or transient widgets in the cache + { + ProfBegin("ui prune unused widgets"); + for(U64 slot_idx = 0; slot_idx < ui_state->box_table_size; slot_idx += 1) + { + for(UI_Box *box = ui_state->box_table[slot_idx].hash_first, *next = 0; + !ui_box_is_nil(box); + box = next) + { + next = box->hash_next; + if(box->last_touched_build_index < ui_state->build_index || + ui_key_match(box->key, ui_key_zero())) + { + DLLRemove_NPZ(&ui_g_nil_box, ui_state->box_table[slot_idx].hash_first, ui_state->box_table[slot_idx].hash_last, box, hash_next, hash_prev); + SLLStackPush(ui_state->first_free_box, box); + } + } + } + ProfEnd(); + } + + //- rjf: layout box tree + { + ProfBegin("ui box tree layout"); + for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis + 1)) + { + ui_layout_root(ui_state->root, axis); + } + ProfEnd(); + } + + //- rjf: close ctx menu if untouched + if(!ui_state->ctx_menu_touched_this_frame) + { + ui_ctx_menu_close(); + } + + //- rjf: close ctx menu if unconsumed clicks + for(OS_Event *event = ui_events()->first; event != 0; event = event->next) + { + if(event->kind == OS_EventKind_Press && os_handle_match(event->window, ui_window()) && + (event->key == OS_Key_LeftMouseButton || event->key == OS_Key_RightMouseButton)) + { + ui_ctx_menu_close(); + } + } + + //- rjf: stick ctx menu to anchor + if(ui_state->ctx_menu_touched_this_frame) + { + UI_Box *anchor_box = ui_box_from_key(ui_state->ctx_menu_anchor_key); + if(!ui_box_is_nil(anchor_box)) + { + Rng2F32 root_rect = ui_state->ctx_menu_root->rect; + Vec2F32 pos = + { + anchor_box->rect.x0 + ui_state->ctx_menu_anchor_off.x, + anchor_box->rect.y0 + ui_state->ctx_menu_anchor_off.y, + }; + Vec2F32 shift = sub_2f32(pos, root_rect.p0); + Rng2F32 new_root_rect = shift_2f32(root_rect, shift); + ui_state->ctx_menu_root->fixed_position = new_root_rect.p0; + ui_state->ctx_menu_root->fixed_size = dim_2f32(new_root_rect); + ui_state->ctx_menu_root->rect = new_root_rect; + } + } + + //- rjf: ensure special floating roots are within screen bounds + UI_Box *floating_roots[] = {ui_state->tooltip_root, ui_state->ctx_menu_root}; + for(U64 idx = 0; idx < ArrayCount(floating_roots); idx += 1) + { + UI_Box *root = floating_roots[idx]; + if(!ui_box_is_nil(root)) + { + Rng2F32 window_rect = os_client_rect_from_window(ui_window()); + Rng2F32 root_rect = root->rect; + Vec2F32 shift = + { + -ClampBot(0, root_rect.x1 - window_rect.x1), + -ClampBot(0, root_rect.y1 - window_rect.y1), + }; + Rng2F32 new_root_rect = shift_2f32(root_rect, shift); + root->fixed_position = new_root_rect.p0; + root->fixed_size = dim_2f32(new_root_rect); + root->rect = new_root_rect; + for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis + 1)) + { + ui_calc_sizes_standalone__in_place_rec(root, axis); + ui_calc_sizes_upwards_dependent__in_place_rec(root, axis); + ui_calc_sizes_downwards_dependent__in_place_rec(root, axis); + ui_layout_enforce_constraints__in_place_rec(root, axis); + ui_layout_position__in_place_rec(root, axis); + } + } + } + + //- rjf: enforce child-rounding + { + for(U64 slot_idx = 0; slot_idx < ui_state->box_table_size; slot_idx += 1) + { + for(UI_Box *box = ui_state->box_table[slot_idx].hash_first; + !ui_box_is_nil(box); + box = box->hash_next) + { + if(box->flags & UI_BoxFlag_RoundChildrenByParent && + !ui_box_is_nil(box->first) && !ui_box_is_nil(box->last)) + { + box->first->corner_radii[Corner_00] = box->corner_radii[Corner_00]; + box->first->corner_radii[Corner_10] = box->corner_radii[Corner_10]; + box->last->corner_radii[Corner_01] = box->corner_radii[Corner_01]; + box->last->corner_radii[Corner_11] = box->corner_radii[Corner_11]; + } + } + } + } + + //- rjf: animate + { + ProfBegin("ui animate"); + F32 vast_rate = 1 - pow_f32(2, (-100.f* ui_state->animation_dt)); + F32 fast_rate = 1 - pow_f32(2, (-50.f * ui_state->animation_dt)); + F32 fish_rate = 1 - pow_f32(2, (-40.f * ui_state->animation_dt)); + F32 slow_rate = 1 - pow_f32(2, (-30.f * ui_state->animation_dt)); + F32 slug_rate = 1 - pow_f32(2, (-15.f * ui_state->animation_dt)); + F32 slaf_rate = 1 - pow_f32(2, (-8.f * ui_state->animation_dt)); + ui_state->ctx_menu_open_t += ((F32)!!ui_state->ctx_menu_open - ui_state->ctx_menu_open_t) * fish_rate; + ui_state->is_animating = (ui_state->is_animating || fabsf((F32)!!ui_state->ctx_menu_open - ui_state->ctx_menu_open_t) > 0.01f); + if(ui_state->ctx_menu_open_t >= 0.99f) + { + ui_state->ctx_menu_open_t = 1.f; + } + for(U64 slot_idx = 0; slot_idx < ui_state->box_table_size; slot_idx += 1) + { + for(UI_Box *box = ui_state->box_table[slot_idx].hash_first; + !ui_box_is_nil(box); + box = box->hash_next) + { + // rjf: grab states informing animation + B32 is_hot = ui_key_match(box->key, ui_state->hot_box_key); + B32 is_active = ui_key_match(box->key, ui_state->active_box_key[Side_Min]); + B32 is_disabled = !!(box->flags & UI_BoxFlag_Disabled) && (box->first_disabled_build_index+10 < ui_state->build_index || + box->first_touched_build_index == box->first_disabled_build_index); + B32 is_focus_hot = !!(box->flags & UI_BoxFlag_FocusHot) && !(box->flags & UI_BoxFlag_FocusHotDisabled); + B32 is_focus_active = !!(box->flags & UI_BoxFlag_FocusActive) && !(box->flags & UI_BoxFlag_FocusActiveDisabled); + + // rjf: determine rates + F32 hot_rate = fast_rate; + F32 active_rate = fast_rate; + F32 disabled_rate = slow_rate; + F32 focus_rate = (is_focus_hot || is_focus_active) ? fast_rate : fast_rate; + + // rjf: determine animating status + B32 box_is_animating = 0; + box_is_animating = (box_is_animating || abs_f32((F32)is_hot - box->hot_t) > 0.01f); + box_is_animating = (box_is_animating || abs_f32((F32)is_active - box->active_t) > 0.01f); + box_is_animating = (box_is_animating || abs_f32((F32)is_disabled - box->disabled_t) > 0.01f); + box_is_animating = (box_is_animating || abs_f32((F32)is_focus_hot - box->focus_hot_t) > 0.01f); + box_is_animating = (box_is_animating || abs_f32((F32)is_focus_active - box->focus_active_t) > 0.01f); + box_is_animating = (box_is_animating || abs_f32(box->view_off_target.x - box->view_off.x) > 0.5f); + box_is_animating = (box_is_animating || abs_f32(box->view_off_target.y - box->view_off.y) > 0.5f); + if(box->flags & UI_BoxFlag_AnimatePosX) + { + box_is_animating = (box_is_animating || fabsf(box->fixed_position_animated.x - box->fixed_position.x) > 0.5f); + } + if(box->flags & UI_BoxFlag_AnimatePosY) + { + box_is_animating = (box_is_animating || fabsf(box->fixed_position_animated.y - box->fixed_position.y) > 0.5f); + } + ui_state->is_animating = (ui_state->is_animating || box_is_animating); +#if 0 // NOTE(rjf): enable to debug animation-causing-frames (or not) + if(box_is_animating) + { + box->overlay_color = v4f32(1, 0, 0, 0.1f); + box->flags |= UI_BoxFlag_DrawOverlay; + } +#endif + + // rjf: animate interaction transition states + box->hot_t += hot_rate * ((F32)is_hot - box->hot_t); + box->active_t += active_rate * ((F32)is_active - box->active_t); + box->disabled_t += disabled_rate * ((F32)is_disabled - box->disabled_t); + box->focus_hot_t += focus_rate * ((F32)is_focus_hot - box->focus_hot_t); + box->focus_active_t += focus_rate * ((F32)is_focus_active - box->focus_active_t); + + // rjf: animate positions + { + box->fixed_position_animated.x += fast_rate * (box->fixed_position.x - box->fixed_position_animated.x); + box->fixed_position_animated.y += fast_rate * (box->fixed_position.y - box->fixed_position_animated.y); + if(fabsf(box->fixed_position.x - box->fixed_position_animated.x) < 1) + { + box->fixed_position_animated.x = box->fixed_position.x; + } + if(fabsf(box->fixed_position.y - box->fixed_position_animated.y) < 1) + { + box->fixed_position_animated.y = box->fixed_position.y; + } + } + + // rjf: clamp view + if(box->flags & UI_BoxFlag_ViewClamp) + { + Vec2F32 max_view_off_target = + { + ClampBot(0, box->view_bounds.x - box->fixed_size.x), + ClampBot(0, box->view_bounds.y - box->fixed_size.y), + }; + box->view_off_target.x = Clamp(0, box->view_off_target.x, max_view_off_target.x); + box->view_off_target.y = Clamp(0, box->view_off_target.y, max_view_off_target.y); + } + + // rjf: animate view offset + { + box->view_off.x += fast_rate * (box->view_off_target.x - box->view_off.x); + box->view_off.y += fast_rate * (box->view_off_target.y - box->view_off.y); + if(fabsf(box->view_off.x - box->view_off_target.x) < 2) + { + box->view_off.x = box->view_off_target.x; + } + if(fabsf(box->view_off.y - box->view_off_target.y) < 2) + { + box->view_off.y = box->view_off_target.y; + } + } + } + } + ProfEnd(); + } + + //- rjf: animate context menu + if(ui_state->ctx_menu_open && !ui_box_is_nil(ui_state->ctx_menu_root)) + { + UI_Box *root = ui_state->ctx_menu_root; + Rng2F32 rect = root->rect; + root->rect.y1 = root->rect.y0 + dim_2f32(rect).y * ui_state->ctx_menu_open_t; + } + + //- rjf: hover cursor + { + UI_Box *hot = ui_box_from_key(ui_state->hot_box_key); + UI_Box *active = ui_box_from_key(ui_state->active_box_key[Side_Min]); + UI_Box *box = ui_box_is_nil(active) ? hot : active; + OS_Cursor cursor = box->hover_cursor; + if(box->flags & UI_BoxFlag_Disabled && box->flags & UI_BoxFlag_Clickable) + { + cursor = OS_Cursor_Disabled; + } + if(os_window_is_focused(ui_state->window) || !ui_box_is_nil(active)) + { + os_set_cursor(cursor); + } + } + + //- rjf: clipboard commits + { + Temp scratch = scratch_begin(0, 0); + UI_Box *box = ui_box_from_key(ui_state->clipboard_copy_key); + String8List strs = {0}; + { + UI_BoxRec rec = {0}; + for(UI_Box *b = box; !ui_box_is_nil(b); rec = ui_box_rec_df_pre(b, box), b = rec.next) + { + if(b->flags & UI_BoxFlag_DrawText && b->flags & UI_BoxFlag_HasDisplayString && !f_tag_match(b->font, ui_icon_font())) + { + String8 display_string = ui_box_display_string(b); + str8_list_push(scratch.arena, &strs, display_string); + } + } + if(strs.node_count != 0) + { + StringJoin join = {0}; + join.sep = str8_lit(" "); + String8 string = str8_list_join(scratch.arena, &strs, &join); + os_set_clipboard_text(string); + } + } + scratch_end(scratch); + } + + ui_state->build_index += 1; + arena_clear(ui_build_arena()); + ProfEnd(); +} + +internal void +ui_calc_sizes_standalone__in_place_rec(UI_Box *root, Axis2 axis) +{ + ProfBeginFunction(); + + switch(root->pref_size[axis].kind) + { + default:{}break; + case UI_SizeKind_Pixels: + { + root->fixed_size.v[axis] = root->pref_size[axis].value; + }break; + + case UI_SizeKind_TextContent: + { + F32 padding = root->pref_size[axis].value; + F32 text_size = root->display_string_runs.dim.x; + root->fixed_size.v[axis] = padding + text_size; + }break; + } + + //- rjf: recurse + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + ui_calc_sizes_standalone__in_place_rec(child, axis); + } + + ProfEnd(); +} + +internal void +ui_calc_sizes_upwards_dependent__in_place_rec(UI_Box *root, Axis2 axis) +{ + ProfBeginFunction(); + + //- rjf: solve for all kinds that are upwards-dependent + switch(root->pref_size[axis].kind) + { + default: break; + + // rjf: if root has a parent percentage, figure out its size + case UI_SizeKind_ParentPct: + { + // rjf: find parent that has a fixed size + UI_Box *fixed_parent = &ui_g_nil_box; + for(UI_Box *p = root->parent; !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & (UI_BoxFlag_FixedWidth<pref_size[axis].kind == UI_SizeKind_Pixels || + p->pref_size[axis].kind == UI_SizeKind_TextContent || + p->pref_size[axis].kind == UI_SizeKind_ParentPct) + { + fixed_parent = p; + break; + } + } + + // rjf: figure out root's size on this axis + F32 size = fixed_parent->fixed_size.v[axis] * root->pref_size[axis].value; + + // rjf: mutate root to have this size + root->fixed_size.v[axis] = size; + }break; + } + + //- rjf: recurse + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + ui_calc_sizes_upwards_dependent__in_place_rec(child, axis); + } + + ProfEnd(); +} + +internal void +ui_calc_sizes_downwards_dependent__in_place_rec(UI_Box *root, Axis2 axis) +{ + ProfBeginFunction(); + + //- rjf: recurse first. we may depend on children that have + // the same property + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + ui_calc_sizes_downwards_dependent__in_place_rec(child, axis); + } + + //- rjf: solve for all kinds that are downwards-dependent + switch(root->pref_size[axis].kind) + { + default: break; + + // rjf: sum children + case UI_SizeKind_ChildrenSum: + { + F32 sum = 0; + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + if(!(child->flags & (UI_BoxFlag_FloatingX<child_layout_axis) + { + sum += child->fixed_size.v[axis]; + } + else + { + sum = Max(sum, child->fixed_size.v[axis]); + } + } + } + + // rjf: figure out root's size on this axis + root->fixed_size.v[axis] = sum; + }break; + } + + ProfEnd(); +} + +internal void +ui_layout_enforce_constraints__in_place_rec(UI_Box *root, Axis2 axis) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + + // NOTE(rjf): The "layout axis" is the direction in which children + // of some node are intended to be laid out. + + //- rjf: fixup children sizes (if we're solving along the *non-layout* axis) + if(axis != root->child_layout_axis && !(root->flags & (UI_BoxFlag_AllowOverflowX << axis))) + { + F32 allowed_size = root->fixed_size.v[axis]; + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis]; + F32 violation = child_size - allowed_size; + F32 max_fixup = child_size; + F32 fixup = Clamp(0, violation, max_fixup); + if(fixup > 0) + { + child->fixed_size.v[axis] -= fixup; + } + } + } + + } + + //- rjf: fixup children sizes (in the direction of the layout axis) + if(axis == root->child_layout_axis && !(root->flags & (UI_BoxFlag_AllowOverflowX << axis))) + { + // rjf: figure out total allowed size & total size + F32 total_allowed_size = root->fixed_size.v[axis]; + F32 total_size = 0; + F32 total_weighted_size = 0; + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis]; + total_weighted_size += child->fixed_size.v[axis] * (1-child->pref_size[axis].strictness); + } + } + + // rjf: if we have a violation, we need to subtract some amount from all children + F32 violation = total_size - total_allowed_size; + if(violation > 0) + { + // rjf: figure out how much we can take in totality + F32 child_fixup_sum = 0; + F32 *child_fixups = push_array(scratch.arena, F32, root->child_count); + { + U64 child_idx = 0; + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next, child_idx += 1) + { + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis] * (1-child->pref_size[axis].strictness); + fixup_size_this_child = ClampBot(0, fixup_size_this_child); + child_fixups[child_idx] = fixup_size_this_child; + child_fixup_sum += fixup_size_this_child; + } + } + } + + // rjf: fixup child sizes + { + U64 child_idx = 0; + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next, child_idx += 1) + { + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis] -= child_fixups[child_idx] * fixup_pct; + child->fixed_size.v[axis] = child->fixed_size.v[axis]; + } + } + } + } + + } + + //- rjf: fixup upwards-relative sizes + if(root->flags & (UI_BoxFlag_AllowOverflowX << axis)) + { + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + if(child->pref_size[axis].kind == UI_SizeKind_ParentPct) + { + child->fixed_size.v[axis] = root->fixed_size.v[axis] * child->pref_size[axis].value; + } + } + } + + //- rjf: recurse + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + ui_layout_enforce_constraints__in_place_rec(child, axis); + } + + scratch_end(scratch); + ProfEnd(); +} + +internal void +ui_layout_position__in_place_rec(UI_Box *root, Axis2 axis) +{ + ProfBeginFunction(); + F32 layout_position = 0; + + //- rjf: lay out children + F32 bounds = 0; + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + // rjf: grab original position + F32 original_position = Min(child->rect.p0.v[axis], child->rect.p1.v[axis]); + + // rjf: calculate fixed position & size + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_position.v[axis] = layout_position; + if(root->child_layout_axis == axis) + { + layout_position += child->fixed_size.v[axis]; + bounds += child->fixed_size.v[axis]; + } + else + { + bounds = Max(bounds, child->fixed_size.v[axis]); + } + } + + // rjf: determine final rect for child, given fixed_position & size + if(child->flags & (UI_BoxFlag_AnimatePosX<first_touched_build_index == child->last_touched_build_index) + { + child->fixed_position_animated = child->fixed_position; + } + child->rect.p0.v[axis] = root->rect.p0.v[axis] + child->fixed_position_animated.v[axis] - !(child->flags&(UI_BoxFlag_SkipViewOffX<view_off.v[axis]; + } + else + { + child->rect.p0.v[axis] = root->rect.p0.v[axis] + child->fixed_position.v[axis] - !(child->flags&(UI_BoxFlag_SkipViewOffX<view_off.v[axis]; + } + child->rect.p1.v[axis] = child->rect.p0.v[axis] + child->fixed_size.v[axis]; + child->rect.p0.x = floorf(child->rect.p0.x); + child->rect.p0.y = floorf(child->rect.p0.y); + child->rect.p1.x = floorf(child->rect.p1.x); + child->rect.p1.y = floorf(child->rect.p1.y); + + // rjf: grab new position + F32 new_position = Min(child->rect.p0.v[axis], child->rect.p1.v[axis]); + + // rjf: store position delta + child->position_delta.v[axis] = new_position - original_position; + } + + //- rjf: store view bounds + { + root->view_bounds.v[axis] = bounds; + } + + //- rjf: recurse + for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + { + ui_layout_position__in_place_rec(child, axis); + } + + ProfEnd(); +} + +internal void +ui_layout_root(UI_Box *root, Axis2 axis) +{ + ProfBegin("ui layout pass (%s)", axis == Axis2_X ? "x" : "y"); + ui_calc_sizes_standalone__in_place_rec(root, axis); + ui_calc_sizes_upwards_dependent__in_place_rec(root, axis); + ui_calc_sizes_downwards_dependent__in_place_rec(root, axis); + ui_layout_enforce_constraints__in_place_rec(root, axis); + ui_layout_position__in_place_rec(root, axis); + ProfEnd(); +} + +//////////////////////////////// +//~ rjf: Box Building API + +//- rjf: tooltips + +internal void +ui_tooltip_begin_base(void) +{ + ui_push_parent(ui_root_from_state(ui_state)); + ui_push_parent(ui_state->tooltip_root); +} + +internal void +ui_tooltip_end_base(void) +{ + ui_pop_parent(); + ui_pop_parent(); +} + +internal void +ui_tooltip_begin(void) +{ + ui_tooltip_begin_base(); + UI_Flags(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_RoundChildrenByParent) + UI_PrefWidth(ui_children_sum(1)) + UI_PrefHeight(ui_children_sum(1)) + UI_CornerRadius(ui_top_font_size()*0.25f) + ui_column_begin(); + ui_push_pref_width(ui_text_dim(10.f, 1.f)); + ui_push_pref_height(ui_em(2.f, 1.f)); + ui_push_text_alignment(UI_TextAlign_Center); +} + +internal void +ui_tooltip_end(void) +{ + ui_pop_text_alignment(); + ui_pop_pref_width(); + ui_pop_pref_height(); + ui_column_end(); + ui_tooltip_end_base(); +} + +//- rjf: context menus + +internal void +ui_ctx_menu_open(UI_Key key, UI_Key anchor_box_key, Vec2F32 anchor_off) +{ + anchor_off.x = (F32)(int)anchor_off.x; + anchor_off.y = (F32)(int)anchor_off.y; + ui_state->next_ctx_menu_open = 1; + ui_state->ctx_menu_open_t = 0; + ui_state->ctx_menu_key = key; + ui_state->next_ctx_menu_anchor_key = anchor_box_key; + ui_state->ctx_menu_anchor_off = anchor_off; + ui_state->ctx_menu_touched_this_frame = 1; + ui_state->ctx_menu_anchor_box_last_pos = v2f32(0, 0); + ui_state->ctx_menu_root->default_nav_focus_active_key = ui_key_zero(); + ui_state->ctx_menu_root->default_nav_focus_next_active_key = ui_key_zero(); +} + +internal void +ui_ctx_menu_close(void) +{ + ui_state->next_ctx_menu_open = 0; +} + +internal B32 +ui_begin_ctx_menu(UI_Key key) +{ + ui_push_parent(ui_root_from_state(ui_state)); + ui_push_parent(ui_state->ctx_menu_root); + B32 result = ui_key_match(key, ui_state->ctx_menu_key) && ui_state->ctx_menu_open; + if(result != 0) + { + ui_state->ctx_menu_touched_this_frame = 1; + ui_state->ctx_menu_root->flags |= UI_BoxFlag_RoundChildrenByParent; + ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawBackgroundBlur; + ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawBackground; + ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawBorder; + ui_state->ctx_menu_root->flags |= UI_BoxFlag_Clip; + ui_state->ctx_menu_root->flags |= UI_BoxFlag_Clickable; + ui_state->ctx_menu_root->corner_radii[Corner_00] = ui_state->ctx_menu_root->corner_radii[Corner_01] = ui_state->ctx_menu_root->corner_radii[Corner_10] = ui_state->ctx_menu_root->corner_radii[Corner_11] = ui_top_font_size()*0.25f; + ui_state->ctx_menu_root->background_color = ui_top_background_color(); + ui_state->ctx_menu_root->border_color = ui_top_border_color(); + ui_state->ctx_menu_root->blur_size = ui_top_blur_size(); + } + ui_push_pref_width(ui_bottom_pref_width()); + ui_push_pref_height(ui_bottom_pref_height()); + return result; +} + +internal void +ui_end_ctx_menu(void) +{ + ui_pop_pref_width(); + ui_pop_pref_height(); + ui_pop_parent(); + ui_pop_parent(); +} + +internal B32 +ui_ctx_menu_is_open(UI_Key key) +{ + return (ui_state->ctx_menu_open && ui_key_match(key, ui_state->ctx_menu_key)); +} + +internal B32 +ui_any_ctx_menu_is_open(void) +{ + return ui_state->ctx_menu_open; +} + +//- rjf: focus tree coloring + +internal void +ui_set_focus_active(B32 check) +{ + ui_state->focus_active_is_set = check; + ui_state->focus_active_is_possible = 1; +} + +internal void +ui_unset_focus_active(void) +{ + ui_state->focus_active_is_set = 0; + ui_state->focus_active_is_possible = 0; +} + +internal void +ui_set_focus_hot(B32 check) +{ + ui_state->focus_hot_is_set = check; + ui_state->focus_hot_is_possible = 1; +} + +internal void +ui_unset_focus_hot(void) +{ + ui_state->focus_hot_is_set = 0; + ui_state->focus_hot_is_possible = 0; +} + +internal B32 +ui_is_focus_active(void) +{ + B32 result = ui_state->focus_active_is_set; + if(result) + { + for(UI_Box *box = ui_top_parent(); !ui_box_is_nil(box); box = box->parent) + { + if(box->flags & UI_BoxFlag_FocusActive) + { + result = !(box->flags & UI_BoxFlag_FocusActiveDisabled); + if(result == 0) + { + break; + } + } + } + } + return result; +} + +internal B32 +ui_is_focus_hot(void) +{ + B32 result = ui_state->focus_hot_is_set; + if(result) + { + for(UI_Box *box = ui_top_parent(); !ui_box_is_nil(box); box = box->parent) + { + if(box->flags & UI_BoxFlag_FocusHot) + { + result = !(box->flags & UI_BoxFlag_FocusHotDisabled); + if(result == 0) + { + break; + } + } + } + } + return result; +} + +//- rjf: implicit auto-managed tree-based focus state + +internal B32 +ui_is_key_auto_focus_active(UI_Key key) +{ + B32 result = 0; + if(!ui_key_match(ui_key_zero(), key)) + { + for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & UI_BoxFlag_FocusActive && ui_key_match(key, p->default_nav_focus_active_key)) + { + result = 1; + break; + } + } + } + return result; +} + +internal B32 +ui_is_key_auto_focus_hot(UI_Key key) +{ + B32 result = 0; + if(!ui_key_match(ui_key_zero(), key)) + { + for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & UI_BoxFlag_FocusHot && + ((!(p->flags & UI_BoxFlag_FocusHotDisabled) && + ui_key_match(key, p->default_nav_focus_hot_key)) || + ui_key_match(key, p->default_nav_focus_active_key))) + { + result = 1; + break; + } + } + } + return result; +} + +internal void +ui_set_auto_focus_active_key(UI_Key key) +{ + for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & UI_BoxFlag_DefaultFocusNav) + { + p->default_nav_focus_next_active_key = key; + break; + } + } +} + +internal void +ui_set_auto_focus_hot_key(UI_Key key) +{ + for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & UI_BoxFlag_DefaultFocusNav) + { + p->default_nav_focus_next_hot_key = key; + break; + } + } +} + +//- rjf: box node construction + +internal UI_Box * +ui_build_box_from_key(UI_BoxFlags flags, UI_Key key) +{ + ProfBeginFunction(); + ui_state->build_box_count += 1; + + //- rjf: grab active parent + UI_Box *parent = ui_top_parent(); + + //- rjf: try to get box + UI_BoxFlags last_flags = 0; + UI_Box *box = ui_box_from_key(key); + B32 box_first_frame = ui_box_is_nil(box); + last_flags = box->flags; + + //- rjf: zero key on duplicate + if(!box_first_frame && box->last_touched_build_index == ui_state->build_index) + { + box = &ui_g_nil_box; + key = ui_key_zero(); + box_first_frame = 1; + } + + //- rjf: gather info from box + B32 box_is_transient = ui_key_match(key, ui_key_zero()); + + //- rjf: allocate box if it doesn't yet exist + if(box_first_frame) + { + box = !box_is_transient ? ui_state->first_free_box : 0; + ui_state->is_animating = ui_state->is_animating || !box_is_transient; + if(!ui_box_is_nil(box)) + { + SLLStackPop(ui_state->first_free_box); + } + else + { + box = push_array_no_zero(box_is_transient ? ui_build_arena() : ui_state->arena, UI_Box, 1); + } + MemoryZeroStruct(box); + } + + //- rjf: zero out per-frame state + { + box->first = box->last = box->next = box->prev = box->parent = &ui_g_nil_box; + box->child_count = 0; + box->flags = 0; + box->hover_cursor = OS_Cursor_Pointer; + MemoryZeroArray(box->pref_size); + MemoryZeroStruct(&box->draw_bucket); + } + + //- rjf: hook into persistent state table + if(box_first_frame && !box_is_transient) + { + U64 slot = key.u64[0] % ui_state->box_table_size; + DLLInsert_NPZ(&ui_g_nil_box, ui_state->box_table[slot].hash_first, ui_state->box_table[slot].hash_last, ui_state->box_table[slot].hash_last, box, hash_next, hash_prev); + } + + //- rjf: hook into per-frame tree structure + if(!ui_box_is_nil(parent)) + { + DLLPushBack_NPZ(&ui_g_nil_box, parent->first, parent->last, box, next, prev); + parent->child_count += 1; + box->parent = parent; + } + + //- rjf: fill box + { + box->key = key; + box->flags = flags|ui_state->flags.active; + box->fastpath_codepoint = ui_state->fastpath_codepoint.active; + + if(ui_is_focus_active() && (box->flags & UI_BoxFlag_DefaultFocusNav) && ui_key_match(ui_state->default_nav_root_key, ui_key_zero())) + { + ui_state->default_nav_root_key = box->key; + } + + if(box_first_frame) + { + box->first_touched_build_index = ui_state->build_index; + box->disabled_t = (F32)!!(box->flags & UI_BoxFlag_Disabled); + } + box->last_touched_build_index = ui_state->build_index; + + if(box->flags & UI_BoxFlag_Disabled && (!(last_flags & UI_BoxFlag_Disabled) || box_first_frame)) + { + box->first_disabled_build_index = ui_state->build_index; + } + + if(ui_state->fixed_x.count != 0) + { + box->flags |= UI_BoxFlag_FloatingX; + box->fixed_position.x = ui_state->fixed_x.active; + } + if(ui_state->fixed_y.count != 0) + { + box->flags |= UI_BoxFlag_FloatingY; + box->fixed_position.y = ui_state->fixed_y.active; + } + if(ui_state->fixed_width.count != 0) + { + box->flags |= UI_BoxFlag_FixedWidth; + box->fixed_size.x = ui_state->fixed_width.active; + } + else + { + box->pref_size[Axis2_X] = ui_state->pref_width.active; + } + if(ui_state->fixed_height.count != 0) + { + box->flags |= UI_BoxFlag_FixedHeight; + box->fixed_size.y = ui_state->fixed_height.active; + } + else + { + box->pref_size[Axis2_Y] = ui_state->pref_height.active; + } + + B32 is_auto_focus_active = ui_is_key_auto_focus_active(key); + B32 is_auto_focus_hot = ui_is_key_auto_focus_hot(key); + if(is_auto_focus_active) + { + ui_state->focus_active_is_possible = ui_state->focus_active_is_set = 1; + } + if(is_auto_focus_hot) + { + ui_state->focus_hot_is_possible = ui_state->focus_hot_is_set = 1; + } + box->flags |= UI_BoxFlag_FocusHot*!!(ui_state->focus_hot_is_possible); + box->flags |= UI_BoxFlag_FocusActive*!!(ui_state->focus_active_is_possible); + box->flags |= UI_BoxFlag_FocusHotDisabled*(!(ui_state->focus_hot_is_set) && ui_state->focus_hot_is_possible); + box->flags |= UI_BoxFlag_FocusActiveDisabled*(!(ui_state->focus_active_is_set) && ui_state->focus_active_is_possible); + if((box->flags & UI_BoxFlag_FocusHot && ~box->flags & UI_BoxFlag_FocusHotDisabled) || + (box->flags & UI_BoxFlag_FocusActive && ~box->flags & UI_BoxFlag_FocusActiveDisabled)) + { + for(UI_Box *p = box->parent; !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & (UI_BoxFlag_FocusHotDisabled|UI_BoxFlag_FocusActiveDisabled)) + { + box->flags |= (UI_BoxFlag_FocusHotDisabled|UI_BoxFlag_FocusActiveDisabled); + break; + } + } + } + ui_state->focus_hot_is_set = 0; + ui_state->focus_hot_is_possible = 0; + ui_state->focus_active_is_set = 0; + ui_state->focus_active_is_possible = 0; + + box->text_align = ui_state->text_alignment.active; + box->child_layout_axis = ui_state->child_layout_axis.active; + box->background_color = ui_state->background_color.active; + box->text_color = ui_state->text_color.active; + box->border_color = ui_state->border_color.active; + box->overlay_color = ui_state->overlay_color.active; + box->font = ui_state->font.active; + box->font_size = ui_state->font_size.active; + box->corner_radii[Corner_00] = ui_state->corner_radius_00.active; + box->corner_radii[Corner_01] = ui_state->corner_radius_01.active; + box->corner_radii[Corner_10] = ui_state->corner_radius_10.active; + box->corner_radii[Corner_11] = ui_state->corner_radius_11.active; + box->blur_size = ui_state->blur_size.active; + box->text_padding = ui_state->text_padding.active; + box->hover_cursor = ui_state->hover_cursor.active; + box->custom_draw = 0; + } + + //- rjf: auto-pop all stacks + { + UI_AutoPopAllStacks(ui_state); + } + + //- rjf: return + ProfEnd(); + return box; +} + +internal UI_Key +ui_active_seed_key(void) +{ + UI_Box *keyed_ancestor = &ui_g_nil_box; + { + for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) + { + if(!ui_key_match(ui_key_zero(), p->key)) + { + keyed_ancestor = p; + break; + } + } + } + return keyed_ancestor->key; +} + +internal UI_Box * +ui_build_box_from_string(UI_BoxFlags flags, String8 string) +{ + ProfBeginFunction(); + + //- rjf: grab active parent + UI_Box *parent = ui_top_parent(); + + //- rjf: figure out key + UI_Key key = ui_key_from_string(ui_active_seed_key(), string); + + //- rjf: build box from key, equip passed string + UI_Box *box = ui_build_box_from_key(flags, key); + if(flags & UI_BoxFlag_DrawText) + { + ui_box_equip_display_string(box, string); + } + + //- rjf: return + ProfEnd(); + return box; +} + +internal UI_Box * +ui_build_box_from_stringf(UI_BoxFlags flags, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + va_end(args); + UI_Box *box = ui_build_box_from_string(flags, string); + scratch_end(scratch); + return box; +} + +//- rjf: box node equipment + +internal void +ui_box_equip_display_string(UI_Box *box, String8 string) +{ + ProfBeginFunction(); + box->string = push_str8_copy(ui_build_arena(), string); + box->flags |= UI_BoxFlag_HasDisplayString; + if(box->flags & UI_BoxFlag_DrawText && (!(box->flags & UI_BoxFlag_DrawTextFastpathCodepoint) || box->fastpath_codepoint == 0)) + { + String8 display_string = ui_box_display_string(box); + D_FancyStringNode fancy_string_n = {0, {box->font, display_string, box->text_color, box->font_size, 0, 0}}; + D_FancyStringList fancy_strings = {&fancy_string_n, &fancy_string_n, 1}; + box->display_string_runs = d_fancy_run_list_from_fancy_string_list(ui_build_arena(), &fancy_strings); + } + if(box->flags & UI_BoxFlag_DrawText && box->flags & UI_BoxFlag_DrawTextFastpathCodepoint && box->fastpath_codepoint != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 display_string = ui_box_display_string(box); + String32 fpcp32 = str32(&box->fastpath_codepoint, 1); + String8 fpcp = str8_from_32(scratch.arena, fpcp32); + U64 fpcp_pos = str8_find_needle(display_string, 0, fpcp, StringMatchFlag_CaseInsensitive); + if(fpcp_pos < display_string.size) + { + D_FancyStringNode pst_fancy_string_n = {0, {box->font, str8_skip(display_string, fpcp_pos+fpcp.size), box->text_color, box->font_size, 0, 0}}; + D_FancyStringNode cdp_fancy_string_n = {&pst_fancy_string_n, {box->font, str8_substr(display_string, r1u64(fpcp_pos, fpcp_pos+fpcp.size)), box->text_color, box->font_size, 4.f, 0}}; + D_FancyStringNode pre_fancy_string_n = {&cdp_fancy_string_n, {box->font, str8_prefix(display_string, fpcp_pos), box->text_color, box->font_size, 0, 0}}; + D_FancyStringList fancy_strings = {&pre_fancy_string_n, &pst_fancy_string_n, 3}; + box->display_string_runs = d_fancy_run_list_from_fancy_string_list(ui_build_arena(), &fancy_strings); + } + else + { + D_FancyStringNode fancy_string_n = {0, {box->font, display_string, box->text_color, box->font_size, 0, 0}}; + D_FancyStringList fancy_strings = {&fancy_string_n, &fancy_string_n, 1}; + box->display_string_runs = d_fancy_run_list_from_fancy_string_list(ui_build_arena(), &fancy_strings); + } + scratch_end(scratch); + } + ProfEnd(); +} + +internal void +ui_box_equip_display_fancy_strings(UI_Box *box, D_FancyStringList *strings) +{ + box->flags |= UI_BoxFlag_HasDisplayString; + box->string = d_string_from_fancy_string_list(ui_build_arena(), strings); + box->display_string_runs = d_fancy_run_list_from_fancy_string_list(ui_build_arena(), strings); +} + +internal void +ui_box_equip_draw_bucket(UI_Box *box, D_Bucket *bucket) +{ + box->flags |= UI_BoxFlag_DrawBucket; + if(box->draw_bucket != 0) + { + D_BucketScope(box->draw_bucket) d_sub_bucket(bucket); + } + else + { + box->draw_bucket = bucket; + } +} + +internal void +ui_box_equip_custom_draw(UI_Box *box, UI_BoxCustomDrawFunctionType *custom_draw, void *user_data) +{ + box->custom_draw = custom_draw; + box->custom_draw_user_data = user_data; +} + +//- rjf: box accessors / queries + +internal String8 +ui_box_display_string(UI_Box *box) +{ + String8 result = box->string; + if(!(box->flags & UI_BoxFlag_DisableIDString)) + { + result = ui_display_part_from_key_string(result); + } + return result; +} + +internal Vec2F32 +ui_box_text_position(UI_Box *box) +{ + Vec2F32 result = {0}; + F_Tag font = box->font; + F32 font_size = box->font_size; + F_Metrics font_metrics = f_metrics_from_tag_size(font, font_size); + result.y = ceilf((box->rect.p0.y + box->rect.p1.y)/2.f + (font_metrics.capital_height/2)); + switch(box->text_align) + { + default: + case UI_TextAlign_Left: + { + result.x = box->rect.p0.x + 2.f + box->text_padding; + }break; + case UI_TextAlign_Center: + { + Vec2F32 advance = box->display_string_runs.dim; + result.x = (box->rect.p0.x + box->rect.p1.x)/2 - advance.x/2; + result.x = ClampBot(result.x, box->rect.x0); + }break; + case UI_TextAlign_Right: + { + Vec2F32 advance = box->display_string_runs.dim; + result.x = (box->rect.p1.x) - 1.f - advance.x; + result.x = ClampBot(result.x, box->rect.x0); + }break; + } + result.x = floorf(result.x); + return result; +} + +internal U64 +ui_box_char_pos_from_xy(UI_Box *box, Vec2F32 xy) +{ + F_Tag font = box->font; + F32 font_size = box->font_size; + String8 line = ui_box_display_string(box); + U64 result = f_char_pos_from_tag_size_string_p(font, font_size, line, xy.x - ui_box_text_position(box).x); + return result; +} + +//////////////////////////////// +//~ rjf: Box Interaction + +//- rjf: single-line string editing + +internal B32 +ui_do_single_line_string_edits(TxtPt *cursor, TxtPt *mark, U64 string_max, String8 *out_string) +{ + B32 change = 0; + Temp scratch = scratch_begin(0, 0); + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + next = n->next; + + // rjf: do not consume anything that doesn't fit a single-line's operations + if(n->v.delta.y != 0) + { + continue; + } + + // rjf: map this action to an op + B32 taken = 0; + UI_NavTxtOp op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, *out_string, *cursor, *mark); + + // rjf: perform replace range + if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) + { + taken = 1; + String8 new_string = ui_nav_push_string_replace_range(scratch.arena, *out_string, r1s64(op.range.min.column, op.range.max.column), op.replace); + new_string.size = Min(string_max, new_string.size); + MemoryCopy(out_string->str, new_string.str, new_string.size); + out_string->size = new_string.size; + } + + // rjf: perform copy + if(op.flags & UI_NavTxtOpFlag_Copy) + { + taken = 1; + os_set_clipboard_text(op.copy); + } + + // rjf: commit op's changed cursor & mark to caller-provided state + taken = taken || (!txt_pt_match(*cursor, op.cursor) || !txt_pt_match(*mark, op.mark)); + *cursor = op.cursor; + *mark = op.mark; + + // rjf: consume event + if(taken) + { + ui_nav_eat_action_node(nav_actions, n); + change = 1; + } + } + scratch_end(scratch); + return change; +} + +//- rjf: general box interaction path + +internal UI_Signal +ui_signal_from_box(UI_Box *box) +{ + ProfBeginFunction(); + UI_Signal result = {0}; + result.box = box; + result.event_flags = os_get_event_flags(); + Vec2F32 mouse = ui_state->mouse; + B32 mouse_is_over = contains_2f32(box->rect, mouse); + B32 disabled = !!(box->flags & UI_BoxFlag_Disabled); + B32 is_focused = !!(box->flags & UI_BoxFlag_FocusHot) && !(box->flags & UI_BoxFlag_FocusHotDisabled); + + //- rjf: gather events + OS_Event *left_press = 0; + OS_Event *left_release = 0; + OS_Event *right_press = 0; + OS_Event *right_release = 0; + for(OS_Event *evt = ui_state->events->first; evt != 0; evt = evt->next) + { + if(os_handle_match(ui_state->window, evt->window)) + { + if(left_press == 0 && evt->kind == OS_EventKind_Press && evt->key == OS_Key_LeftMouseButton) + { + left_press = evt; + } + if(left_release == 0 && evt->kind == OS_EventKind_Release && evt->key == OS_Key_LeftMouseButton) + { + left_release = evt; + } + if(right_press == 0 && evt->kind == OS_EventKind_Press && evt->key == OS_Key_RightMouseButton) + { + right_press = evt; + } + if(right_release == 0 && evt->kind == OS_EventKind_Release && evt->key == OS_Key_RightMouseButton) + { + right_release = evt; + } + } + } + + //- rjf: check for parent that is clipping + if(box->flags & (UI_BoxFlag_Clickable|UI_BoxFlag_ViewScroll) && mouse_is_over) + { + for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent) + { + if(parent->flags & UI_BoxFlag_Clip) + { + mouse_is_over = mouse_is_over && contains_2f32(parent->rect, mouse); + break; + } + } + } + + //- rjf: get default nav ancestor + UI_Box *default_nav_parent = &ui_g_nil_box; + for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & UI_BoxFlag_DefaultFocusNav) + { + default_nav_parent = p; + break; + } + } + + //- rjf: determine if we're under the context menu or not + B32 ctx_menu_is_ancestor = 0; + ProfScope("check context menu ancestor") + { + for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent) + { + if(parent == ui_state->ctx_menu_root) + { + ctx_menu_is_ancestor = 1; + break; + } + } + } + + //- rjf: clip against floaters + if(mouse_is_over) ProfScope("clip against floaters") + { + if(!ctx_menu_is_ancestor && ui_state->ctx_menu_open != 0 && contains_2f32(ui_state->ctx_menu_root->rect, mouse)) + { + mouse_is_over = 0; + } + } + + //- rjf: mouse clickability + if(box->flags & UI_BoxFlag_MouseClickable && !ui_key_match(ui_key_zero(), box->key)) ProfScope("clickability") + { + // rjf: hot management + if((ui_key_match(ui_key_zero(), ui_state->active_box_key[Side_Min]) && + ui_key_match(ui_key_zero(), ui_state->active_box_key[Side_Max])) && + ui_key_match(ui_key_zero(), ui_state->hot_box_key) && + mouse_is_over) + { + ui_state->hot_box_key = box->key; + } + else if(ui_key_match(ui_state->hot_box_key, box->key) && + !mouse_is_over && + !ui_key_match(ui_state->active_box_key[Side_Min], box->key) && + !ui_key_match(ui_state->active_box_key[Side_Max], box->key)) + { + ui_state->hot_box_key = ui_key_zero(); + } + + // rjf: active management (left click) + if(!disabled && + ui_key_match(ui_state->hot_box_key, box->key) && + ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) && + left_press != 0) + { + os_eat_event(ui_state->events, left_press); + result.pressed = 1; + ui_state->active_box_key[Side_Min] = box->key; + } + else if(!disabled && + ui_key_match(ui_state->active_box_key[Side_Min], box->key) && + left_release != 0) + { + os_eat_event(ui_state->events, left_release); + result.released = 1; + result.clicked = mouse_is_over; + ui_state->hot_box_key = mouse_is_over ? box->key : ui_key_zero(); + ui_state->active_box_key[Side_Min] = ui_key_zero(); + } + + // rjf: active management (right click) + if(!disabled && + ui_key_match(ui_state->hot_box_key, box->key) && + ui_key_match(ui_state->active_box_key[Side_Max], ui_key_zero()) && + right_press != 0) + { + os_eat_event(ui_state->events, right_press); + // NOTE(rjf): Add this in if it ever needs to exist: + // result.right_pressed = 1; + ui_state->active_box_key[Side_Max] = box->key; + } + else if(!disabled && + ui_key_match(ui_state->active_box_key[Side_Max], box->key) && + right_release != 0) + { + os_eat_event(ui_state->events, right_release); + // NOTE(rjf): Add this in if it ever needs to exist: + // result.right_released = 1; + result.right_clicked = mouse_is_over; + ui_state->active_box_key[Side_Max] = ui_key_zero(); + } + + // rjf: dragging + if(ui_key_match(ui_state->active_box_key[Side_Min], box->key)) + { + result.dragging = 1; + if(result.pressed) + { + ui_state->drag_start_mouse = mouse; + } + } + } + + //- rjf: plain scrolling + if(box->flags & UI_BoxFlag_Scroll) + { + OS_EventList *events = ui_events(); + for(OS_Event *event = events->first, *next = 0; event != 0; event = next) + { + next = event->next; + if(os_handle_match(event->window, ui_state->window) && event->flags != OS_EventFlag_Ctrl) + { + switch(event->kind) + { + default:break; + case OS_EventKind_Scroll: + if(mouse_is_over) + { + Vec2F32 delta = event->delta; + if(event->flags & OS_EventFlag_Shift) + { + Swap(F32, delta.x, delta.y); + } + os_eat_event(events, event); + result.scroll.x += (S16)(delta.x/30.f); + result.scroll.y += (S16)(delta.y/30.f); + }break; + } + } + } + } + + //- rjf: view scrolling + if(box->first_touched_build_index != box->last_touched_build_index && box->flags & UI_BoxFlag_ViewScroll) + { + OS_EventList *events = ui_events(); + for(OS_Event *event = events->first, *next = 0; event != 0; event = next) + { + next = event->next; + if(os_handle_match(event->window, ui_state->window) && event->flags != OS_EventFlag_Ctrl) + { + switch(event->kind) + { + default:break; + case OS_EventKind_Scroll: + if(mouse_is_over) + { + Vec2F32 delta = event->delta; + if(event->flags & OS_EventFlag_Shift) + { + Swap(F32, delta.x, delta.y); + } + os_eat_event(events, event); + box->view_off_target.x += delta.x; + box->view_off_target.y += delta.y; + }break; + } + } + } + Vec2F32 max_view_off_target = + { + ClampBot(0, box->view_bounds.x - box->fixed_size.x), + ClampBot(0, box->view_bounds.y - box->fixed_size.y), + }; + box->view_off_target.x = Clamp(0, box->view_off_target.x, max_view_off_target.x); + box->view_off_target.y = Clamp(0, box->view_off_target.y, max_view_off_target.y); + } + + //- rjf: focus + clicks + B32 keyboard_click = 0; + if(!disabled && is_focused && box->flags & UI_BoxFlag_KeyboardClickable) + { + if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + { + keyboard_click = 1; + result.clicked = 1; + result.pressed = 1; + result.keyboard_clicked = 1; + } + } + + //- rjf: focus + ctrl+clicks + if(!disabled && is_focused && box->flags & UI_BoxFlag_KeyboardClickable) + { + if(os_key_press(ui_events(), ui_window(), OS_EventFlag_Shift, OS_Key_Return)) + { + result.right_clicked = 1; + } + } + + //- rjf: focus & ctrl+c + if(is_focused && box->flags & UI_BoxFlag_KeyboardClickable) + { + for(UI_NavActionNode *n = ui_nav_actions()->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(n->v.flags & UI_NavActionFlag_Copy) + { + ui_state->clipboard_copy_key = box->key; + ui_nav_eat_action_node(ui_nav_actions(), n); + } + } + } + + //- rjf: focused ancestors and fastpath codepoint -> click + if(box->flags & UI_BoxFlag_Clickable && box->fastpath_codepoint != 0) + { + B32 is_focused = 0; + for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent) + { + if(parent->flags & UI_BoxFlag_FocusActive) + { + is_focused = 1; + if(parent->flags & UI_BoxFlag_FocusActiveDisabled || + !ui_key_match(parent->default_nav_focus_active_key, ui_key_zero())) + { + is_focused = 0; + break; + } + } + } + if(is_focused) + { + Temp scratch = scratch_begin(0, 0); + B32 clicked = 0; + for(UI_NavActionNode *n = ui_nav_actions()->first; n != 0; n = n->next) + { + UI_NavAction *action = &n->v; + if(action->insertion.size != 0) + { + String32 insertion32 = str32_from_8(scratch.arena, action->insertion); + if(insertion32.size == 1 && insertion32.str[0] == box->fastpath_codepoint) + { + clicked = 1; + ui_nav_eat_action_node(ui_nav_actions(), n); + break; + } + } + } + if(clicked) + { + keyboard_click = 1; + result.clicked = 1; + result.pressed = 1; + result.keyboard_clicked = 1; + } + scratch_end(scratch); + } + } + + //- rjf: double-clicks + if(!keyboard_click && result.pressed) + { + if(ui_key_match(ui_state->last_click_key[Side_Min], box->key) && + ui_state->time_since_last_click[Side_Min] < os_double_click_time()) + { + result.double_clicked = 1; + } + ui_state->time_since_last_click[Side_Min] = 0; + ui_state->last_click_key[Side_Min] = box->key; + } + + //- rjf: clicking on something outside the context menu kills the context menu + if(!ctx_menu_is_ancestor && result.pressed) + { + ui_ctx_menu_close(); + } + + //- rjf: set hovering status + result.hovering = mouse_is_over && (ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) || + ui_key_match(ui_state->active_box_key[Side_Min], box->key)); + result.mouse_over = mouse_is_over; + + //- rjf: clicking in default nav -> set navigation state to this box + if(box->flags & UI_BoxFlag_ClickToFocus && result.pressed && !ui_box_is_nil(default_nav_parent)) + { + default_nav_parent->default_nav_focus_next_hot_key = box->key; + if(!ui_key_match(default_nav_parent->default_nav_focus_active_key, box->key)) + { + default_nav_parent->default_nav_focus_next_active_key = ui_key_zero(); + } + } + + //- rjf: focus & external commit events -> commit + if(is_focused && ui_state->external_focus_commit) + { + ui_state->external_focus_commit = 0; + result.commit = 1; + } + + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Stacks + +#define UI_StackPush(name, new_top)\ +(\ +(ui_state->name.v[ui_state->name.count] = ui_state->name.active),\ +(ui_state->name.active = new_top),\ +(ui_state->name.count += 1),\ +(ui_state->name.v[ui_state->name.count-1])\ +) +#define UI_StackPop(name, popped)\ +(\ +(ui_state->name.count -= 1),\ +(popped = ui_state->name.active),\ +(ui_state->name.active = ui_state->name.v[ui_state->name.count]),\ +(popped)\ +) +#define UI_StackSetNext(name, new_top)\ +(\ +(ui_state->name.auto_pop) ?\ +(ui_state->name.active = new_top) :\ +(\ +(ui_state->name.v[ui_state->name.count] = ui_state->name.active),\ +(ui_state->name.active = new_top),\ +(ui_state->name.count += 1),\ +(ui_state->name.auto_pop = 1),\ +(ui_state->name.v[ui_state->name.count-1])\ +)\ +) +#define UI_StackTop(name) (ui_state->name.active) +#define UI_StackBottom(name) (ui_state->name.count > 1 ? ui_state->name.v[1] : ui_state->name.active) + +//- rjf: helpers + +internal Rng2F32 +ui_push_rect(Rng2F32 rect) +{ + Rng2F32 replaced = {0}; + Vec2F32 size = dim_2f32(rect); + replaced.x0 = ui_push_fixed_x(rect.x0); + replaced.y0 = ui_push_fixed_y(rect.y0); + replaced.x1 = replaced.x0 + ui_push_fixed_width(size.x); + replaced.y1 = replaced.y0 + ui_push_fixed_height(size.y); + return replaced; +} + +internal Rng2F32 +ui_pop_rect(void) +{ + Rng2F32 popped = {0}; + popped.x0 = ui_pop_fixed_x(); + popped.y0 = ui_pop_fixed_y(); + popped.x1 = popped.x0 + ui_pop_fixed_width(); + popped.y1 = popped.y0 + ui_pop_fixed_height(); + return popped; +} + +internal UI_Size +ui_push_pref_size(Axis2 axis, UI_Size v) +{ + UI_Size result = zero_struct; + switch(axis) + { + default: break; + case Axis2_X: {result = ui_push_pref_width(v);}break; + case Axis2_Y: {result = ui_push_pref_height(v);}break; + } + return result; +} + +internal UI_Size +ui_pop_pref_size(Axis2 axis) +{ + UI_Size result = zero_struct; + switch(axis) + { + default: break; + case Axis2_X: {result = ui_pop_pref_width();}break; + case Axis2_Y: {result = ui_pop_pref_height();}break; + } + return result; +} + +internal UI_Size +ui_set_next_pref_size(Axis2 axis, UI_Size v) +{ + return (axis == Axis2_X ? ui_set_next_pref_width : ui_set_next_pref_height)(v); +} + +internal void +ui_push_corner_radius(F32 v) +{ + ui_push_corner_radius_00(v); + ui_push_corner_radius_01(v); + ui_push_corner_radius_10(v); + ui_push_corner_radius_11(v); +} + +internal void +ui_pop_corner_radius(void) +{ + ui_pop_corner_radius_00(); + ui_pop_corner_radius_01(); + ui_pop_corner_radius_10(); + ui_pop_corner_radius_11(); +} + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/ui.meta.c" diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h new file mode 100644 index 00000000..4e642629 --- /dev/null +++ b/src/ui/ui_core.h @@ -0,0 +1,794 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef UI_H +#define UI_H + +//////////////////////////////// +//~ rjf: Icon Info + +typedef enum UI_IconKind +{ + UI_IconKind_Null, + UI_IconKind_RightArrow, + UI_IconKind_DownArrow, + UI_IconKind_LeftArrow, + UI_IconKind_UpArrow, + UI_IconKind_RightCaret, + UI_IconKind_DownCaret, + UI_IconKind_LeftCaret, + UI_IconKind_UpCaret, + UI_IconKind_CheckHollow, + UI_IconKind_CheckFilled, + UI_IconKind_COUNT +} +UI_IconKind; + +typedef struct UI_IconInfo UI_IconInfo; +struct UI_IconInfo +{ + F_Tag icon_font; + String8 icon_kind_text_map[UI_IconKind_COUNT]; +}; + +//////////////////////////////// +//~ rjf: Navigation Types + +typedef enum UI_NavDeltaUnit +{ + UI_NavDeltaUnit_Element, + UI_NavDeltaUnit_Chunk, + UI_NavDeltaUnit_Whole, + UI_NavDeltaUnit_EndPoint, + UI_NavDeltaUnit_COUNT, +} +UI_NavDeltaUnit; + +typedef U32 UI_NavActionFlags; +enum +{ + UI_NavActionFlag_KeepMark = (1<<0), + UI_NavActionFlag_Delete = (1<<1), + UI_NavActionFlag_Copy = (1<<2), + UI_NavActionFlag_Paste = (1<<3), + UI_NavActionFlag_ZeroDeltaOnSelect = (1<<4), + UI_NavActionFlag_PickSelectSide = (1<<5), + UI_NavActionFlag_CapAtLine = (1<<6), + UI_NavActionFlag_ExplicitDirectional = (1<<7), + UI_NavActionFlag_ReplaceAndCommit = (1<<8), +}; + +typedef struct UI_NavAction UI_NavAction; +struct UI_NavAction +{ + UI_NavActionFlags flags; + Vec2S32 delta; + UI_NavDeltaUnit delta_unit; + String8 insertion; +}; + +typedef struct UI_NavActionNode UI_NavActionNode; +struct UI_NavActionNode +{ + UI_NavActionNode *next; + UI_NavActionNode *prev; + UI_NavAction v; +}; + +typedef struct UI_NavActionList UI_NavActionList; +struct UI_NavActionList +{ + UI_NavActionNode *first; + UI_NavActionNode *last; + U64 count; +}; + +typedef U32 UI_NavTxtOpFlags; +enum +{ + UI_NavTxtOpFlag_Invalid = (1<<0), + UI_NavTxtOpFlag_Copy = (1<<1), +}; + +typedef struct UI_NavTxtOp UI_NavTxtOp; +struct UI_NavTxtOp +{ + UI_NavTxtOpFlags flags; + String8 replace; + String8 copy; + TxtRng range; + TxtPt cursor; + TxtPt mark; +}; + +//////////////////////////////// +//~ rjf: Keys + +typedef struct UI_Key UI_Key; +struct UI_Key +{ + U64 u64[1]; +}; + +//////////////////////////////// +//~ rjf: Sizes + +typedef enum UI_SizeKind +{ + UI_SizeKind_Null, + UI_SizeKind_Pixels, // size is computed via a preferred pixel value + UI_SizeKind_TextContent, // size is computed via the dimensions of box's rendered string + UI_SizeKind_ParentPct, // size is computed via a well-determined parent or grandparent size + UI_SizeKind_ChildrenSum, // size is computed via summing well-determined sizes of children +} +UI_SizeKind; + +typedef struct UI_Size UI_Size; +struct UI_Size +{ + UI_SizeKind kind; + F32 value; + F32 strictness; +}; + +//////////////////////////////// +//~ rjf: Scroll Positions + +typedef struct UI_ScrollPt UI_ScrollPt; +struct UI_ScrollPt +{ + S64 idx; + F32 off; +}; + +typedef union UI_ScrollPt2 UI_ScrollPt2; +union UI_ScrollPt2 +{ + UI_ScrollPt v[2]; + struct + { + UI_ScrollPt x; + UI_ScrollPt y; + }; +}; + +//////////////////////////////// +//~ rjf: Box Types + +typedef enum UI_TextAlign +{ + UI_TextAlign_Left, + UI_TextAlign_Center, + UI_TextAlign_Right, + UI_TextAlign_COUNT +} +UI_TextAlign; + +struct UI_Box; +#define UI_BOX_CUSTOM_DRAW(name) void name(struct UI_Box *box, void *user_data) +typedef UI_BOX_CUSTOM_DRAW(UI_BoxCustomDrawFunctionType); + +typedef U64 UI_BoxFlags; +//{ +//- rjf: interaction +# define UI_BoxFlag_MouseClickable (UI_BoxFlags)(1ull<<0) +# define UI_BoxFlag_KeyboardClickable (UI_BoxFlags)(1ull<<1) +# define UI_BoxFlag_ClickToFocus (UI_BoxFlags)(1ull<<2) +# define UI_BoxFlag_Scroll (UI_BoxFlags)(1ull<<3) +# define UI_BoxFlag_ViewScroll (UI_BoxFlags)(1ull<<4) +# define UI_BoxFlag_ViewClamp (UI_BoxFlags)(1ull<<5) +# define UI_BoxFlag_FocusHot (UI_BoxFlags)(1ull<<6) +# define UI_BoxFlag_FocusActive (UI_BoxFlags)(1ull<<7) +# define UI_BoxFlag_FocusHotDisabled (UI_BoxFlags)(1ull<<8) +# define UI_BoxFlag_FocusActiveDisabled (UI_BoxFlags)(1ull<<9) +# define UI_BoxFlag_DefaultFocusNavX (UI_BoxFlags)(1ull<<10) +# define UI_BoxFlag_DefaultFocusNavY (UI_BoxFlags)(1ull<<11) +# define UI_BoxFlag_DefaultFocusEdit (UI_BoxFlags)(1ull<<12) +# define UI_BoxFlag_FocusNavSkip (UI_BoxFlags)(1ull<<13) +# define UI_BoxFlag_Disabled (UI_BoxFlags)(1ull<<14) + +//- rjf: layout +# define UI_BoxFlag_FloatingX (UI_BoxFlags)(1ull<<15) +# define UI_BoxFlag_FloatingY (UI_BoxFlags)(1ull<<16) +# define UI_BoxFlag_FixedWidth (UI_BoxFlags)(1ull<<17) +# define UI_BoxFlag_FixedHeight (UI_BoxFlags)(1ull<<18) +# define UI_BoxFlag_AllowOverflowX (UI_BoxFlags)(1ull<<19) +# define UI_BoxFlag_AllowOverflowY (UI_BoxFlags)(1ull<<20) +# define UI_BoxFlag_SkipViewOffX (UI_BoxFlags)(1ull<<21) +# define UI_BoxFlag_SkipViewOffY (UI_BoxFlags)(1ull<<22) + +//- rjf: appearance / animation +# define UI_BoxFlag_DrawDropShadow (UI_BoxFlags)(1ull<<23) +# define UI_BoxFlag_DrawBackgroundBlur (UI_BoxFlags)(1ull<<24) +# define UI_BoxFlag_DrawBackground (UI_BoxFlags)(1ull<<25) +# define UI_BoxFlag_DrawBorder (UI_BoxFlags)(1ull<<26) +# define UI_BoxFlag_DrawSideTop (UI_BoxFlags)(1ull<<27) +# define UI_BoxFlag_DrawSideBottom (UI_BoxFlags)(1ull<<28) +# define UI_BoxFlag_DrawSideLeft (UI_BoxFlags)(1ull<<29) +# define UI_BoxFlag_DrawSideRight (UI_BoxFlags)(1ull<<30) +# define UI_BoxFlag_DrawText (UI_BoxFlags)(1ull<<31) +# define UI_BoxFlag_DrawTextFastpathCodepoint (UI_BoxFlags)(1ull<<32) +# define UI_BoxFlag_DrawHotEffects (UI_BoxFlags)(1ull<<33) +# define UI_BoxFlag_DrawActiveEffects (UI_BoxFlags)(1ull<<34) +# define UI_BoxFlag_DrawOverlay (UI_BoxFlags)(1ull<<35) +# define UI_BoxFlag_DrawBucket (UI_BoxFlags)(1ull<<36) +# define UI_BoxFlag_Clip (UI_BoxFlags)(1ull<<37) +# define UI_BoxFlag_AnimatePosX (UI_BoxFlags)(1ull<<38) +# define UI_BoxFlag_AnimatePosY (UI_BoxFlags)(1ull<<39) +# define UI_BoxFlag_DisableTextTrunc (UI_BoxFlags)(1ull<<40) +# define UI_BoxFlag_DisableIDString (UI_BoxFlags)(1ull<<41) +# define UI_BoxFlag_DisableFocusViz (UI_BoxFlags)(1ull<<42) +# define UI_BoxFlag_RequireFocusBackground (UI_BoxFlags)(1ull<<43) +# define UI_BoxFlag_HasDisplayString (UI_BoxFlags)(1ull<<44) +# define UI_BoxFlag_RoundChildrenByParent (UI_BoxFlags)(1ull<<45) + +//- rjf: bundles +# define UI_BoxFlag_Clickable (UI_BoxFlag_MouseClickable|UI_BoxFlag_KeyboardClickable) +# define UI_BoxFlag_DefaultFocusNav (UI_BoxFlag_DefaultFocusNavX|UI_BoxFlag_DefaultFocusNavY|UI_BoxFlag_DefaultFocusEdit) +# define UI_BoxFlag_Floating (UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY) +# define UI_BoxFlag_FixedSize (UI_BoxFlag_FixedWidth|UI_BoxFlag_FixedHeight) +# define UI_BoxFlag_AllowOverflow (UI_BoxFlag_AllowOverflowX|UI_BoxFlag_AllowOverflowY) +# define UI_BoxFlag_AnimatePos (UI_BoxFlag_AnimatePosX|UI_BoxFlag_AnimatePosY) +//} + +typedef struct UI_Box UI_Box; +struct UI_Box +{ + //- rjf: persistent links + UI_Box *hash_next; + UI_Box *hash_prev; + + //- rjf: per-build links/data + UI_Box *first; + UI_Box *last; + UI_Box *next; + UI_Box *prev; + UI_Box *parent; + U64 child_count; + + //- rjf: per-build equipment + UI_Key key; + UI_BoxFlags flags; + String8 string; + UI_TextAlign text_align; + Vec2F32 fixed_position; + Vec2F32 fixed_size; + UI_Size pref_size[Axis2_COUNT]; + Axis2 child_layout_axis; + OS_Cursor hover_cursor; + U32 fastpath_codepoint; + D_Bucket *draw_bucket; + UI_BoxCustomDrawFunctionType *custom_draw; + void *custom_draw_user_data; + Vec4F32 background_color; + Vec4F32 text_color; + Vec4F32 border_color; + Vec4F32 overlay_color; + F_Tag font; + F32 font_size; + F32 corner_radii[Corner_COUNT]; + F32 blur_size; + F32 text_padding; + + //- rjf: per-build artifacts + D_FancyRunList display_string_runs; + Rng2F32 rect; + Vec2F32 fixed_position_animated; + Vec2F32 position_delta; + U64 num_focus_children; + + //- rjf: persistent data + U64 first_touched_build_index; + U64 last_touched_build_index; + U64 first_disabled_build_index; + F32 hot_t; + F32 active_t; + F32 disabled_t; + F32 focus_hot_t; + F32 focus_active_t; + Vec2F32 view_off; + Vec2F32 view_off_target; + Vec2F32 view_bounds; + UI_Key default_nav_focus_hot_key; + UI_Key default_nav_focus_active_key; + UI_Key default_nav_focus_next_hot_key; + UI_Key default_nav_focus_next_active_key; +}; + +typedef struct UI_BoxRec UI_BoxRec; +struct UI_BoxRec +{ + UI_Box *next; + S32 push_count; + S32 pop_count; +}; + +typedef struct UI_BoxNode UI_BoxNode; +struct UI_BoxNode +{ + UI_BoxNode *next; + UI_Box *box; +}; + +typedef struct UI_BoxList UI_BoxList; +struct UI_BoxList +{ + UI_BoxNode *first; + UI_BoxNode *last; + U64 count; +}; + +typedef struct UI_Signal UI_Signal; +struct UI_Signal +{ + UI_Box *box; + OS_EventFlags event_flags; + Vec2S16 scroll; + B8 clicked :1; + B8 keyboard_clicked :1; + B8 double_clicked :1; + B8 right_clicked :1; + B8 pressed :1; + B8 released :1; + B8 dragging :1; + B8 hovering :1; + B8 mouse_over :1; + B8 commit :1; +}; + +typedef struct UI_Nav UI_Nav; +struct UI_Nav +{ + B32 moved; + Vec2S64 new_p; +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/ui.meta.h" + +//////////////////////////////// +//~ rjf: State Types + +typedef struct UI_BoxHashSlot UI_BoxHashSlot; +struct UI_BoxHashSlot +{ + UI_Box *hash_first; + UI_Box *hash_last; +}; + +typedef struct UI_State UI_State; +struct UI_State +{ + //- rjf: main arena + Arena *arena; + + //- rjf: build arenas + Arena *build_arenas[2]; + U64 build_index; + + //- rjf: box cache + UI_Box *first_free_box; + U64 box_table_size; + UI_BoxHashSlot *box_table; + + //- rjf: build phase output + UI_Box *root; + UI_Box *tooltip_root; + UI_Box *ctx_menu_root; + UI_Key default_nav_root_key; + U64 build_box_count; + U64 last_build_box_count; + B32 ctx_menu_touched_this_frame; + B32 is_animating; + + //- rjf: build parameters + UI_IconInfo icon_info; + OS_Handle window; + OS_EventList *events; + UI_NavActionList *nav_actions; + Vec2F32 mouse; + F32 animation_dt; + B32 external_focus_commit; + + //- rjf: user interaction state + UI_Key hot_box_key; + UI_Key active_box_key[Side_COUNT]; + UI_Key clipboard_copy_key; + F32 time_since_last_click[Side_COUNT]; + UI_Key last_click_key[Side_COUNT]; + Vec2F32 drag_start_mouse; + Arena *drag_state_arena; + String8 drag_state_data; + + //- rjf: context menu state + UI_Key ctx_menu_anchor_key; + UI_Key next_ctx_menu_anchor_key; + Vec2F32 ctx_menu_anchor_box_last_pos; + Vec2F32 ctx_menu_anchor_off; + B32 ctx_menu_open; + B32 next_ctx_menu_open; + F32 ctx_menu_open_t; + UI_Key ctx_menu_key; + + //- rjf: build phase focus masks + B32 focus_hot_is_set; + B32 focus_hot_is_possible; + B32 focus_active_is_set; + B32 focus_active_is_possible; + + //- rjf: build phase stacks + UI_StackDecls; +}; + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal U64 ui_hash_from_string(U64 seed, String8 string); +internal String8 ui_hash_part_from_key_string(String8 string); +internal String8 ui_display_part_from_key_string(String8 string); +internal UI_Key ui_key_zero(void); +internal UI_Key ui_key_make(U64 v); +internal UI_Key ui_key_from_string(UI_Key seed_key, String8 string); +internal UI_Key ui_key_from_stringf(UI_Key seed_key, char *fmt, ...); +internal B32 ui_key_match(UI_Key a, UI_Key b); + +//////////////////////////////// +//~ rjf: Navigation Action List Building & Consumption Functions + +internal void ui_nav_action_list_push(Arena *arena, UI_NavActionList *list, UI_NavAction action); +internal void ui_nav_eat_action_node(UI_NavActionList *list, UI_NavActionNode *node); + +//////////////////////////////// +//~ rjf: High Level Navigation Action => Text Operations + +internal B32 ui_nav_char_is_scan_boundary(U8 c); +internal S64 ui_nav_scanned_column_from_column(String8 string, S64 start_column, Side side); +internal UI_NavTxtOp ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8 line, TxtPt cursor, TxtPt mark); + +//////////////////////////////// +//~ rjf: Single-Line String Modification + +internal String8 ui_nav_push_string_replace_range(Arena *arena, String8 string, Rng1S64 col_range, String8 replace); + +//////////////////////////////// +//~ rjf: Size Type Functions + +internal UI_Size ui_size(UI_SizeKind kind, F32 value, F32 strictness); +#define ui_px(value, strictness) ui_size(UI_SizeKind_Pixels, value, strictness) +#define ui_em(value, strictness) ui_size(UI_SizeKind_Pixels, (value) * ui_top_font_size(), strictness) +#define ui_text_dim(padding, strictness) ui_size(UI_SizeKind_TextContent, padding, strictness) +#define ui_pct(value, strictness) ui_size(UI_SizeKind_ParentPct, value, strictness) +#define ui_children_sum(strictness) ui_size(UI_SizeKind_ChildrenSum, 0.f, strictness) + +//////////////////////////////// +//~ rjf: Scroll Point Type Functions + +internal UI_ScrollPt ui_scroll_pt(S64 idx, F32 off); +internal void ui_scroll_pt_target_idx(UI_ScrollPt *v, S64 idx); +internal void ui_scroll_pt_clamp_idx(UI_ScrollPt *v, Rng1S64 range); + +//////////////////////////////// +//~ rjf: Box Type Functions + +read_only global UI_Box ui_g_nil_box = +{ + &ui_g_nil_box, + &ui_g_nil_box, + &ui_g_nil_box, + &ui_g_nil_box, + &ui_g_nil_box, + &ui_g_nil_box, + &ui_g_nil_box, +}; +internal B32 ui_box_is_nil(UI_Box *box); +internal UI_BoxRec ui_box_rec_df(UI_Box *box, UI_Box *root, U64 sib_member_off, U64 child_member_off); +#define ui_box_rec_df_pre(box, root) ui_box_rec_df(box, root, OffsetOf(UI_Box, next), OffsetOf(UI_Box, first)) +#define ui_box_rec_df_post(box, root) ui_box_rec_df(box, root, OffsetOf(UI_Box, prev), OffsetOf(UI_Box, last)) +internal void ui_box_list_push(Arena *arena, UI_BoxList *list, UI_Box *box); + +//////////////////////////////// +//~ rjf: State Allocating / Selection + +internal UI_State *ui_state_alloc(void); +internal void ui_state_release(UI_State *state); +internal UI_Box * ui_root_from_state(UI_State *state); +internal B32 ui_animating_from_state(UI_State *state); +internal void ui_select_state(UI_State *state); +internal UI_State *ui_get_selected_state(void); + +//////////////////////////////// +//~ rjf: Implicit State Accessors/Mutators + +//- rjf: per-frame info +internal Arena * ui_build_arena(void); +internal OS_Handle ui_window(void); +internal OS_EventList * ui_events(void); +internal UI_NavActionList *ui_nav_actions(void); +internal Vec2F32 ui_mouse(void); +internal F_Tag ui_icon_font(void); +internal String8 ui_icon_string_from_kind(UI_IconKind icon_kind); +internal F32 ui_dt(void); + +//- rjf: drag data +internal Vec2F32 ui_drag_delta(void); +internal void ui_store_drag_data(String8 string); +internal String8 ui_get_drag_data(U64 min_required_size); +#define ui_store_drag_struct(ptr) ui_store_drag_data(str8_struct(ptr)) +#define ui_get_drag_struct(type) ((type *)ui_get_drag_data(sizeof(type)).str) + +//- rjf: interaction keys +internal UI_Key ui_hot_key(void); +internal UI_Key ui_active_key(Side side); + +//- rjf: controls over interaction +internal void ui_kill_action(void); + +//- rjf: box cache lookup +internal UI_Box * ui_box_from_key(UI_Key key); + +//////////////////////////////// +//~ rjf: Top-Level Building API + +internal void ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_actions, UI_IconInfo *icon_info, F32 real_dt, F32 animation_dt); +internal void ui_end_build(void); +internal void ui_calc_sizes_standalone__in_place_rec(UI_Box *root, Axis2 axis); +internal void ui_calc_sizes_upwards_dependent__in_place_rec(UI_Box *root, Axis2 axis); +internal void ui_calc_sizes_downwards_dependent__in_place_rec(UI_Box *root, Axis2 axis); +internal void ui_layout_enforce_constraints__in_place_rec(UI_Box *root, Axis2 axis); +internal void ui_layout_position__in_place_rec(UI_Box *root, Axis2 axis); +internal void ui_layout_root(UI_Box *root, Axis2 axis); + +//////////////////////////////// +//~ rjf: Box Tree Building API + +//- rjf: tooltips +internal void ui_tooltip_begin_base(void); +internal void ui_tooltip_end_base(void); +internal void ui_tooltip_begin(void); +internal void ui_tooltip_end(void); + +//- rjf: context menus +internal void ui_ctx_menu_open(UI_Key key, UI_Key anchor_box_key, Vec2F32 anchor_off); +internal void ui_ctx_menu_close(void); +internal B32 ui_begin_ctx_menu(UI_Key key); +internal void ui_end_ctx_menu(void); +internal B32 ui_ctx_menu_is_open(UI_Key key); +internal B32 ui_any_ctx_menu_is_open(void); + +//- rjf: focus tree coloring +internal void ui_set_focus_active(B32 check); +internal void ui_unset_focus_active(void); +internal void ui_set_focus_hot(B32 check); +internal void ui_unset_focus_hot(void); +internal B32 ui_is_focus_active(void); +internal B32 ui_is_focus_hot(void); + +//- rjf: implicit auto-managed tree-based focus state +internal B32 ui_is_key_auto_focus_active(UI_Key key); +internal B32 ui_is_key_auto_focus_hot(UI_Key key); +internal void ui_set_auto_focus_active_key(UI_Key key); +internal void ui_set_auto_focus_hot_key(UI_Key key); + +//- rjf: box node construction +internal UI_Box * ui_build_box_from_key(UI_BoxFlags flags, UI_Key key); +internal UI_Key ui_active_seed_key(void); +internal UI_Box * ui_build_box_from_string(UI_BoxFlags flags, String8 string); +internal UI_Box * ui_build_box_from_stringf(UI_BoxFlags flags, char *fmt, ...); + +//- rjf: box node equipment +internal inline void ui_box_equip_display_string(UI_Box *box, String8 string); +internal inline void ui_box_equip_display_fancy_strings(UI_Box *box, D_FancyStringList *strings); +internal inline void ui_box_equip_draw_bucket(UI_Box *box, D_Bucket *bucket); +internal inline void ui_box_equip_custom_draw(UI_Box *box, UI_BoxCustomDrawFunctionType *custom_draw, void *user_data); + +//- rjf: box accessors / queries +internal String8 ui_box_display_string(UI_Box *box); +internal Vec2F32 ui_box_text_position(UI_Box *box); +internal U64 ui_box_char_pos_from_xy(UI_Box *box, Vec2F32 xy); + +//////////////////////////////// +//~ rjf: User Interaction + +//- rjf: single-line string editing +internal B32 ui_do_single_line_string_edits(TxtPt *cursor, TxtPt *mark, U64 string_max, String8 *out_string); + +//- rjf: general box interaction path +internal UI_Signal ui_signal_from_box(UI_Box *box); + +//////////////////////////////// +//~ rjf: Stacks + +//- rjf: base +internal UI_Box * ui_push_parent(UI_Box * v); +internal Axis2 ui_push_child_layout_axis(Axis2 v); +internal F32 ui_push_fixed_x(F32 v); +internal F32 ui_push_fixed_y(F32 v); +internal F32 ui_push_fixed_width(F32 v); +internal F32 ui_push_fixed_height(F32 v); +internal UI_Size ui_push_pref_width(UI_Size v); +internal UI_Size ui_push_pref_height(UI_Size v); +internal UI_BoxFlags ui_push_flags(UI_BoxFlags v); +internal U32 ui_push_fastpath_codepoint(U32 v); +internal Vec4F32 ui_push_background_color(Vec4F32 v); +internal Vec4F32 ui_push_text_color(Vec4F32 v); +internal Vec4F32 ui_push_border_color(Vec4F32 v); +internal Vec4F32 ui_push_overlay_color(Vec4F32 v); +internal Vec4F32 ui_push_text_select_color(Vec4F32 v); +internal Vec4F32 ui_push_text_cursor_color(Vec4F32 v); +internal OS_Cursor ui_push_hover_cursor(OS_Cursor v); +internal F_Tag ui_push_font(F_Tag v); +internal F32 ui_push_font_size(F32 v); +internal F32 ui_push_corner_radius_00(F32 v); +internal F32 ui_push_corner_radius_01(F32 v); +internal F32 ui_push_corner_radius_10(F32 v); +internal F32 ui_push_corner_radius_11(F32 v); +internal F32 ui_push_blur_size(F32 v); +internal F32 ui_push_text_padding(F32 v); +internal UI_TextAlign ui_push_text_alignment(UI_TextAlign v); +internal UI_Box * ui_pop_parent(void); +internal Axis2 ui_pop_child_layout_axis(void); +internal F32 ui_pop_fixed_x(void); +internal F32 ui_pop_fixed_y(void); +internal F32 ui_pop_fixed_width(void); +internal F32 ui_pop_fixed_height(void); +internal UI_Size ui_pop_pref_width(void); +internal UI_Size ui_pop_pref_height(void); +internal UI_BoxFlags ui_pop_flags(void); +internal U32 ui_pop_fastpath_codepoint(void); +internal Vec4F32 ui_pop_background_color(void); +internal Vec4F32 ui_pop_text_color(void); +internal Vec4F32 ui_pop_border_color(void); +internal Vec4F32 ui_pop_overlay_color(void); +internal Vec4F32 ui_pop_text_select_color(void); +internal Vec4F32 ui_pop_text_cursor_color(void); +internal OS_Cursor ui_pop_hover_cursor(void); +internal F_Tag ui_pop_font(void); +internal F32 ui_pop_font_size(void); +internal F32 ui_pop_corner_radius_00(void); +internal F32 ui_pop_corner_radius_01(void); +internal F32 ui_pop_corner_radius_10(void); +internal F32 ui_pop_corner_radius_11(void); +internal F32 ui_pop_blur_size(void); +internal F32 ui_pop_text_padding(void); +internal UI_TextAlign ui_pop_text_alignment(void); +internal UI_Box * ui_top_parent(void); +internal Axis2 ui_top_child_layout_axis(void); +internal F32 ui_top_fixed_x(void); +internal F32 ui_top_fixed_y(void); +internal F32 ui_top_fixed_width(void); +internal F32 ui_top_fixed_height(void); +internal UI_Size ui_top_pref_width(void); +internal UI_Size ui_top_pref_height(void); +internal UI_BoxFlags ui_top_flags(void); +internal U32 ui_top_fastpath_codepoint(void); +internal Vec4F32 ui_top_background_color(void); +internal Vec4F32 ui_top_text_color(void); +internal Vec4F32 ui_top_border_color(void); +internal Vec4F32 ui_top_overlay_color(void); +internal Vec4F32 ui_top_text_select_color(void); +internal Vec4F32 ui_top_text_cursor_color(void); +internal OS_Cursor ui_top_hover_cursor(void); +internal F_Tag ui_top_font(void); +internal F32 ui_top_font_size(void); +internal F32 ui_top_corner_radius_00(void); +internal F32 ui_top_corner_radius_01(void); +internal F32 ui_top_corner_radius_10(void); +internal F32 ui_top_corner_radius_11(void); +internal F32 ui_top_blur_size(void); +internal F32 ui_top_text_padding(void); +internal UI_TextAlign ui_top_text_alignment(void); +internal UI_Box * ui_bottom_parent(void); +internal Axis2 ui_bottom_child_layout_axis(void); +internal F32 ui_bottom_fixed_x(void); +internal F32 ui_bottom_fixed_y(void); +internal F32 ui_bottom_fixed_width(void); +internal F32 ui_bottom_fixed_height(void); +internal UI_Size ui_bottom_pref_width(void); +internal UI_Size ui_bottom_pref_height(void); +internal UI_BoxFlags ui_bottom_flags(void); +internal U32 ui_bottom_fastpath_codepoint(void); +internal Vec4F32 ui_bottom_background_color(void); +internal Vec4F32 ui_bottom_text_color(void); +internal Vec4F32 ui_bottom_border_color(void); +internal Vec4F32 ui_bottom_overlay_color(void); +internal Vec4F32 ui_bottom_text_select_color(void); +internal Vec4F32 ui_bottom_text_cursor_color(void); +internal OS_Cursor ui_bottom_hover_cursor(void); +internal F_Tag ui_bottom_font(void); +internal F32 ui_bottom_font_size(void); +internal F32 ui_bottom_corner_radius_00(void); +internal F32 ui_bottom_corner_radius_01(void); +internal F32 ui_bottom_corner_radius_10(void); +internal F32 ui_bottom_corner_radius_11(void); +internal F32 ui_bottom_blur_size(void); +internal F32 ui_bottom_text_padding(void); +internal UI_TextAlign ui_bottom_text_alignment(void); +internal UI_Box * ui_set_next_parent(UI_Box * v); +internal Axis2 ui_set_next_child_layout_axis(Axis2 v); +internal F32 ui_set_next_fixed_x(F32 v); +internal F32 ui_set_next_fixed_y(F32 v); +internal F32 ui_set_next_fixed_width(F32 v); +internal F32 ui_set_next_fixed_height(F32 v); +internal UI_Size ui_set_next_pref_width(UI_Size v); +internal UI_Size ui_set_next_pref_height(UI_Size v); +internal UI_BoxFlags ui_set_next_flags(UI_BoxFlags v); +internal U32 ui_set_next_fastpath_codepoint(U32 v); +internal Vec4F32 ui_set_next_background_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_color(Vec4F32 v); +internal Vec4F32 ui_set_next_border_color(Vec4F32 v); +internal Vec4F32 ui_set_next_overlay_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_select_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_cursor_color(Vec4F32 v); +internal OS_Cursor ui_set_next_hover_cursor(OS_Cursor v); +internal F_Tag ui_set_next_font(F_Tag v); +internal F32 ui_set_next_font_size(F32 v); +internal F32 ui_set_next_corner_radius_00(F32 v); +internal F32 ui_set_next_corner_radius_01(F32 v); +internal F32 ui_set_next_corner_radius_10(F32 v); +internal F32 ui_set_next_corner_radius_11(F32 v); +internal F32 ui_set_next_blur_size(F32 v); +internal F32 ui_set_next_text_padding(F32 v); +internal UI_TextAlign ui_set_next_text_alignment(UI_TextAlign v); + +//- rjf: helpers +internal Rng2F32 ui_push_rect(Rng2F32 rect); +internal Rng2F32 ui_pop_rect(void); +internal UI_Size ui_push_pref_size(Axis2 axis, UI_Size v); +internal UI_Size ui_pop_pref_size(Axis2 axis); +internal UI_Size ui_set_next_pref_size(Axis2 axis, UI_Size v); +internal void ui_push_corner_radius(F32 v); +internal void ui_pop_corner_radius(void); + +//////////////////////////////// +//~ rjf: Macro Loop Wrappers + +//- rjf: stacks (base) +#define UI_Parent(v) DeferLoop(ui_push_parent(v), ui_pop_parent()) +#define UI_ChildLayoutAxis(v) DeferLoop(ui_push_child_layout_axis(v), ui_pop_child_layout_axis()) +#define UI_FixedX(v) DeferLoop(ui_push_fixed_x(v), ui_pop_fixed_x()) +#define UI_FixedY(v) DeferLoop(ui_push_fixed_y(v), ui_pop_fixed_y()) +#define UI_FixedWidth(v) DeferLoop(ui_push_fixed_width(v), ui_pop_fixed_width()) +#define UI_FixedHeight(v) DeferLoop(ui_push_fixed_height(v), ui_pop_fixed_height()) +#define UI_PrefWidth(v) DeferLoop(ui_push_pref_width(v), ui_pop_pref_width()) +#define UI_PrefHeight(v) DeferLoop(ui_push_pref_height(v), ui_pop_pref_height()) +#define UI_Flags(v) DeferLoop(ui_push_flags(v), ui_pop_flags()) +#define UI_FastpathCodepoint(v) DeferLoop(ui_push_fastpath_codepoint(v), ui_pop_fastpath_codepoint()) +#define UI_BackgroundColor(v) DeferLoop(ui_push_background_color(v), ui_pop_background_color()) +#define UI_TextColor(v) DeferLoop(ui_push_text_color(v), ui_pop_text_color()) +#define UI_BorderColor(v) DeferLoop(ui_push_border_color(v), ui_pop_border_color()) +#define UI_OverlayColor(v) DeferLoop(ui_push_overlay_color(v), ui_pop_overlay_color()) +#define UI_TextSelectColor(v) DeferLoop(ui_push_text_select_color(v), ui_pop_text_select_color()) +#define UI_TextCursorColor(v) DeferLoop(ui_push_text_cursor_color(v), ui_pop_text_cursor_color()) +#define UI_HoverCursor(v) DeferLoop(ui_push_hover_cursor(v), ui_pop_hover_cursor()) +#define UI_Font(v) DeferLoop(ui_push_font(v), ui_pop_font()) +#define UI_FontSize(v) DeferLoop(ui_push_font_size(v), ui_pop_font_size()) +#define UI_CornerRadius00(v) DeferLoop(ui_push_corner_radius_00(v), ui_pop_corner_radius_00()) +#define UI_CornerRadius01(v) DeferLoop(ui_push_corner_radius_01(v), ui_pop_corner_radius_01()) +#define UI_CornerRadius10(v) DeferLoop(ui_push_corner_radius_10(v), ui_pop_corner_radius_10()) +#define UI_CornerRadius11(v) DeferLoop(ui_push_corner_radius_11(v), ui_pop_corner_radius_11()) +#define UI_BlurSize(v) DeferLoop(ui_push_blur_size(v), ui_pop_blur_size()) +#define UI_TextPadding(v) DeferLoop(ui_push_text_padding(v), ui_pop_text_padding()) +#define UI_TextAlignment(v) DeferLoop(ui_push_text_alignment(v), ui_pop_text_alignment()) + +//- rjf: stacks (compositions) +#define UI_WidthFill UI_PrefWidth(ui_pct(1.f, 0.f)) +#define UI_HeightFill UI_PrefHeight(ui_pct(1.f, 0.f)) +#define UI_Rect(r) DeferLoop(ui_push_rect(r), ui_pop_rect()) +#define UI_PrefSize(axis, v) DeferLoop(ui_push_pref_size((axis), (v)), ui_pop_pref_size(axis)) +#define UI_CornerRadius(v) DeferLoop(ui_push_corner_radius(v), ui_pop_corner_radius()) + +//- rjf: tooltip +#define UI_TooltipBase DeferLoop(ui_tooltip_begin_base(), ui_tooltip_end_base()) +#define UI_Tooltip DeferLoop(ui_tooltip_begin(), ui_tooltip_end()) + +//- rjf: context menu +#define UI_CtxMenu(key) DeferLoopChecked(ui_begin_ctx_menu(key), ui_end_ctx_menu()) + +//- rjf: focus +#define UI_FocusHot(is_focused) DeferLoop(ui_set_focus_hot(is_focused), ui_unset_focus_hot()) +#define UI_FocusActive(is_focused) DeferLoop(ui_set_focus_active(is_focused), ui_unset_focus_hot()) +#define UI_Focus(is_focused) UI_FocusHot(is_focused) UI_FocusActive(is_focused) + +#endif // UI_H diff --git a/src/ui/ui_inc.c b/src/ui/ui_inc.c new file mode 100644 index 00000000..dcedafd5 --- /dev/null +++ b/src/ui/ui_inc.c @@ -0,0 +1,8 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#undef RADDBG_LAYER_COLOR +#define RADDBG_LAYER_COLOR 0.70f, 0.30f, 0.15f + +#include "ui_core.c" +#include "ui_basic_widgets.c" diff --git a/src/ui/ui_inc.h b/src/ui/ui_inc.h new file mode 100644 index 00000000..d071b15c --- /dev/null +++ b/src/ui/ui_inc.h @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef UI_INC_H +#define UI_INC_H + +#include "ui_core.h" +#include "ui_basic_widgets.h" + +#endif // UI_INC_H diff --git a/src/unwind/unwind.c b/src/unwind/unwind.c new file mode 100644 index 00000000..20a1c9bb --- /dev/null +++ b/src/unwind/unwind.c @@ -0,0 +1,840 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ allen: Unwind Functions + +//- mem view construction + +internal UNW_MemView +unw_memview_from_data(String8 data, U64 base_vaddr){ + UNW_MemView result = {0}; + result.data = data.str; + result.addr_first = base_vaddr; + result.addr_opl = base_vaddr + data.size; + return(result); +} + +//- mem view user face for unwind users + +internal B32 +unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out){ + B32 result = 0; + if (memview->addr_first <= addr && addr + size <= memview->addr_opl){ + MemoryCopy(out, (U8*)memview->data + addr - memview->addr_first, size); + result = 1; + } + return(result); +} + + +//////////////////////////////// +//~ allen: PE X64 Unwind Functions + +//- main interface + +internal UNW_Result +unw_pe_x64(String8 bindata, PE_BinInfo *bin, + U64 base_vaddr, UNW_MemView *memview, UNW_X64_Regs *regs){ + UNW_Result result = {0}; + U64 missed_read_addr = 0; + + //- grab ip_voff (several places can use this) + U64 ip_voff = regs->rip.u64 - base_vaddr; + + //- get pdata entry from current ip + PE_IntelPdata *initial_pdata = 0; + { + U64 initial_pdata_off = pe_intel_pdata_off_from_voff__binary_search(bindata, bin, ip_voff); + if (initial_pdata_off != 0){ + initial_pdata = (PE_IntelPdata*)(bindata.str + initial_pdata_off); + } + } + + //- no pdata; unwind by reading stack pointer + if (initial_pdata == 0){ + // read ip from stack pointer + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if (!unw_memview_read_struct(memview, sp, &new_ip)){ + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + } + + //- got pdata; perform unwinding with exception handling + else{ + // try epilog unwind + B32 did_epilog_unwind = 0; + if (unw_pe_x64__voff_is_in_epilog(bindata, bin, ip_voff, initial_pdata)){ + result = unw_pe_x64__epilog(bindata, bin, base_vaddr, memview, regs); + did_epilog_unwind = 1; + } + + // try xdata unwind + if (!did_epilog_unwind){ + B32 did_machframe = 0; + + // get frame reg + REGS_Reg64 *frame_reg = 0; + U64 frame_off = 0; + + { + U64 unwind_info_off = initial_pdata->voff_unwind_info; + UNW_PE_Info *unwind_info = (UNW_PE_Info*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); + + U32 frame_reg_id = UNW_PE_INFO_REG_FROM_FRAME(unwind_info->frame); + U64 frame_off_val = UNW_PE_INFO_OFF_FROM_FRAME(unwind_info->frame); + + if (frame_reg_id != 0){ + frame_reg = unw_pe_x64__gpr_reg(regs, frame_reg_id); + // TODO(allen): at this point if frame_reg is zero, the exe is corrupted. + } + frame_off = frame_off_val; + } + + PE_IntelPdata *last_pdata = 0; + PE_IntelPdata *pdata = initial_pdata; + for (;pdata != last_pdata;){ + //- get unwind info & codes + U64 unwind_info_off = pdata->voff_unwind_info; + UNW_PE_Info *unwind_info = (UNW_PE_Info*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); + UNW_PE_Code *unwind_codes = (UNW_PE_Code*)(unwind_info + 1); + + //- get frame base + U64 frame_base = regs->rsp.u64; + if (frame_reg != 0){ + U64 raw_frame_base = frame_reg->u64; + U64 adjusted_frame_base = raw_frame_base - frame_off*16; + if (adjusted_frame_base < raw_frame_base){ + frame_base = adjusted_frame_base; + } + else{ + frame_base = 0; + } + } + + //- rjf: bad unwind info -> abort + if(unwind_info == 0) + { + result.dead = 1; + goto error_out; + } + + //- op code interpreter + UNW_PE_Code *code_ptr = unwind_codes; + UNW_PE_Code *code_opl = unwind_codes + unwind_info->codes_num; + for (UNW_PE_Code *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr){ + // extract op code parts + U32 op_code = UNW_PE_CODE_FROM_FLAGS(code_ptr->flags); + U32 op_info = UNW_PE_INFO_FROM_FLAGS(code_ptr->flags); + + // determine number of op code slots + U32 slot_count = unw_pe_x64__slot_count_from_op_code(op_code); + if (op_code == UNW_PE_OpCode_ALLOC_LARGE && op_info == 1){ + slot_count += 1; + } + + // check op code slot count + if (slot_count == 0 || code_ptr + slot_count > code_opl){ + result.dead = 1; + goto end_xdata_unwind; + } + + // set next op code pointer + next_code_ptr = code_ptr + slot_count; + + // interpret this op code + U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; + if (code_voff <= ip_voff){ + switch (op_code){ + case UNW_PE_OpCode_PUSH_NONVOL: + { + // read value from stack pointer + U64 sp = regs->rsp.u64; + U64 value = 0; + if (!unw_memview_read_struct(memview, sp, &value)){ + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + regs->rsp.u64 = new_sp; + }break; + + case UNW_PE_OpCode_ALLOC_LARGE: + { + // read alloc size + U64 size = 0; + if (op_info == 0){ + size = code_ptr[1].u16*8; + } + else if (op_info == 1){ + size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + } + else{ + result.dead = 1; + goto end_xdata_unwind; + } + + // advance stack pointer + U64 sp = regs->rsp.u64; + U64 new_sp = sp + size; + + // advance stack pointer + regs->rsp.u64 = new_sp; + }break; + + case UNW_PE_OpCode_ALLOC_SMALL: + { + // advance stack pointer + regs->rsp.u64 += op_info*8 + 8; + }break; + + case UNW_PE_OpCode_SET_FPREG: + { + // put stack pointer back to the frame base + regs->rsp.u64 = frame_base; + }break; + + case UNW_PE_OpCode_SAVE_NONVOL: + { + // read value from frame base + U64 off = code_ptr[1].u16*8; + U64 addr = frame_base + off; + U64 value = 0; + if (!unw_memview_read_struct(memview, addr, &value)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + }break; + + case UNW_PE_OpCode_SAVE_NONVOL_FAR: + { + // read value from frame base + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + U64 value = 0; + if (!unw_memview_read_struct(memview, addr, &value)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + }break; + + case UNW_PE_OpCode_EPILOG: + { + result.dead = 1; + }break; + + case UNW_PE_OpCode_SPARE_CODE: + { + Assert(!"Hit me!"); + // TODO(allen): ??? + }break; + + case UNW_PE_OpCode_SAVE_XMM128: + { + // read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16*16; + U64 addr = frame_base + off; + if (!unw_memview_read(memview, addr, 16, buf)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case UNW_PE_OpCode_SAVE_XMM128_FAR: + { + // read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + if (!unw_memview_read(memview, addr, 16, buf)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case UNW_PE_OpCode_PUSH_MACHFRAME: + { + // NOTE(rjf): this was found by stepping through kernel code after an exception was + // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main + + if (op_info > 1){ + result.dead = 1; + goto end_xdata_unwind; + } + + // read values + U64 sp_og = regs->rsp.u64; + U64 sp_adj = sp_og; + if (op_info == 1){ + sp_adj += 8; + } + + U64 ip_value = 0; + if (!unw_memview_read_struct(memview, sp_adj, &ip_value)){ + missed_read_addr = sp_adj; + goto error_out; + } + + U64 sp_after_ip = sp_adj + 8; + U16 ss_value = 0; + if (!unw_memview_read_struct(memview, sp_after_ip, &ss_value)){ + missed_read_addr = sp_after_ip; + goto error_out; + } + + U64 sp_after_ss = sp_after_ip + 8; + U64 rflags_value = 0; + if (!unw_memview_read_struct(memview, sp_after_ss, &rflags_value)){ + missed_read_addr = sp_after_ss; + goto error_out; + } + + U64 sp_after_rflags = sp_after_ss + 8; + U64 sp_value = 0; + if (!unw_memview_read_struct(memview, sp_after_rflags, &sp_value)){ + missed_read_addr = sp_after_rflags; + goto error_out; + } + + // commit registers + regs->rip.u64 = ip_value; + regs->ss.u16 = ss_value; + regs->rflags.u64 = rflags_value; + regs->rsp.u64 = sp_value; + + // mark machine frame + did_machframe = 1; + }break; + } + } + } + + //- iterate pdata chain + U32 flags = UNW_PE_INFO_FLAGS_FROM_HDR(unwind_info->header); + if (!(flags & UNW_PE_InfoFlag_CHAINED)){ + break; + } + + U64 code_count_rounded = AlignPow2(unwind_info->codes_num, 2); + U64 code_size = code_count_rounded*sizeof(UNW_PE_OpCode); + U64 chained_pdata_off = unwind_info_off + sizeof(UNW_PE_Info) + code_size; + + last_pdata = pdata; + pdata = (PE_IntelPdata*)pe_ptr_from_voff(bindata, bin, chained_pdata_off); + } + + if (!did_machframe){ + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if (!unw_memview_read_struct(memview, sp, &new_ip)){ + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + } + + end_xdata_unwind:; + } + } + + error_out:; + + if (missed_read_addr != 0){ + result.dead = 1; + result.missed_read = 1; + result.missed_read_addr = missed_read_addr; + } + + if (!result.dead){ + result.stack_pointer = regs->rsp.u64; + } + + return(result); +} + +//- pe x64 helpers + +internal UNW_Result +unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, + U64 base_vaddr, UNW_MemView*memview, UNW_X64_Regs *regs){ + UNW_Result result = {0}; + U64 missed_read_addr = 0; + + //- setup parsing context + U64 ip_voff = regs->rip.u64 - base_vaddr; + U64 sec_number = pe_section_num_from_voff(bindata, bin, ip_voff); + COFF_SectionHeader *sec = coff_section_header_from_num(bindata, bin->section_array_off, sec_number); + void* inst_base = pe_ptr_from_section_num(bindata, bin, sec_number); + U64 inst_size = sec->vsize; + + //- setup parsing variables + B32 keep_parsing = 1; + U64 off = ip_voff - sec->voff; + + + //- parsing loop + for (;keep_parsing;){ + keep_parsing = 0; + + U8 inst_byte = 0; + if (off + sizeof(inst_byte) <= inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); + } + off += 1; + + U8 rex = 0; + if ((inst_byte & 0xF0) == 0x40){ + rex = inst_byte & 0xF; // rex prefix + if (off + sizeof(inst_base) <= inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); + } + off += 1; + } + + switch (inst_byte){ + // pop + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + { + U64 sp = regs->rsp.u64; + U64 value = 0; + if (!unw_memview_read_struct(memview, sp, &value)){ + missed_read_addr = sp; + goto error_out; + } + + // modify register + UNW_PE_X64_GprReg gpr_reg = (inst_byte - 0x58) + (rex & 1)*8; + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); + + // not a final instruction + keep_parsing = 1; + + // commit registers + reg->u64 = value; + regs->rsp.u64 = sp + 8; + }break; + + // add $nnnn,%rsp + case 0x81: + { + // skip one byte (we already know what it is in this scenario) + off += 1; + + // read the 4-byte immediate + S32 imm = 0; + if (off + sizeof(imm) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&imm, ptr, sizeof(imm)); + } + off += 4; + + // not a final instruction + keep_parsing = 1; + + // update stack pointer + regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); + }break; + + // add $n,%rsp + case 0x83: + { + // skip one byte (we already know what it is in this scenario) + off += 1; + + // read the 1-byte immediate + S8 imm = 0; + if (off + sizeof(imm) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&imm, ptr, sizeof(imm)); + } + off += 1; + + // update stack pointer + regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); + keep_parsing = 1; + }break; + + // lea imm8/imm32,$rsp + case 0x8D: + { + // read source register + U8 modrm = 0; + if (off + sizeof(modrm) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&modrm, ptr, sizeof(modrm)); + } + UNW_PE_X64_GprReg gpr_reg = (modrm & 7) + (rex & 1)*8; + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); + U64 reg_value = reg->u64; + + // advance to the immediate + off += 1; + + S32 imm = 0; + // read 1-byte immediate + if ((modrm >> 6) == 1){ + S8 imm8 = 0; + if (off + sizeof(imm8) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&imm8, ptr, sizeof(imm8)); + } + imm = imm8; + off += 1; + } + + // read 4-byte immediate + else{ + if (off + sizeof(imm) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&imm, ptr, sizeof(imm)); + } + off += 4; + } + + regs->rsp.u64 = (U64)(reg_value + imm); + keep_parsing = 1; + }break; + + // ret $nn + case 0xC2: + { + // read new ip + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if (!unw_memview_read_struct(memview, sp, &new_ip)){ + missed_read_addr = sp; + goto error_out; + } + + // read 2-byte immediate & advance stack pointer + U16 imm = 0; + if (off + sizeof(imm) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&imm, ptr, sizeof(imm)); + } + U64 new_sp = sp + 8 + imm; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + }break; + + // ret / rep; ret + case 0xF3: + { + Assert(!"Hit me!"); + } + case 0xC3: + { + // read new ip + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if (!unw_memview_read_struct(memview, sp, &new_ip)){ + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + }break; + + // jmp nnnn + case 0xE9: + { + Assert(!"Hit Me"); + // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done + // we don't have any cases to exercise this right now. no guess implementation! + }break; + + // jmp n + case 0xEB: + { + Assert(!"Hit Me"); + // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done + // we don't have any cases to exercise this right now. no guess implementation! + }break; + } + + } + + error_out:; + + if (missed_read_addr != 0){ + result.dead = 1; + result.missed_read = 1; + result.missed_read_addr = missed_read_addr; + } + + return(result); +} + +internal U32 +unw_pe_x64__slot_count_from_op_code(UNW_PE_OpCode opcode){ + U32 result = 0; + switch (opcode){ + case UNW_PE_OpCode_PUSH_NONVOL: result = 1; break; + case UNW_PE_OpCode_ALLOC_LARGE: result = 2; break; + case UNW_PE_OpCode_ALLOC_SMALL: result = 1; break; + case UNW_PE_OpCode_SET_FPREG: result = 1; break; + case UNW_PE_OpCode_SAVE_NONVOL: result = 2; break; + case UNW_PE_OpCode_SAVE_NONVOL_FAR: result = 3; break; + case UNW_PE_OpCode_EPILOG: result = 2; break; + case UNW_PE_OpCode_SPARE_CODE: result = 3; break; + case UNW_PE_OpCode_SAVE_XMM128: result = 2; break; + case UNW_PE_OpCode_SAVE_XMM128_FAR: result = 3; break; + case UNW_PE_OpCode_PUSH_MACHFRAME: result = 1; break; + } + return(result); +} + +internal B32 +unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, + U64 voff, PE_IntelPdata *final_pdata){ + // NOTE(allen): There are restrictions placed on how an epilog is allowed + // to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160) + // Here we interpret machine code directly according to the rules + // given there to determine if the code we're looking at looks like an epilog. + + // TODO(allen): Figure out how to verify this. + + //- setup parsing context + U64 sec_number = pe_section_num_from_voff(bindata, bin, voff); + COFF_SectionHeader *sec = coff_section_header_from_num(bindata, bin->section_array_off, sec_number); + void* inst_base = pe_ptr_from_section_num(bindata, bin, sec_number); + U64 inst_size = sec->vsize; + + //- setup parsing variables + B32 is_epilog = 0; + B32 keep_parsing = 1; + U64 off = voff - sec->voff; + + //- check first instruction + { + B32 inst_read_success = 0; + U8 inst[4]; + if (off + sizeof(inst) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&inst, ptr, sizeof(inst)); + inst_read_success = 1; + } + + if (!inst_read_success){ + keep_parsing = 0; + } + else{ + if ((inst[0] & 0xF8) == 0x48){ + switch (inst[1]){ + // add $nnnn,%rsp + case 0x81: + { + if (inst[0] == 0x48 && inst[2] == 0xC4){ + off += 7; + } + else{ + keep_parsing = 0; + } + }break; + + // add $n,%rsp + case 0x83: + { + if (inst[0] == 0x48 && inst[2] == 0xC4){ + off += 4; + } + else{ + keep_parsing = 0; + } + }break; + + // lea n(reg),%rsp + case 0x8D: + { + if ((inst[0] & 0x06) == 0 && + ((inst[2] >> 3) & 0x07) == 0x04 && + (inst[2] & 0x07) != 0x04){ + U8 imm_size = (inst[2] >> 6); + // 1-byte immediate + if (imm_size == 1){ + off += 4; + } + // 4-byte immediate + else if (imm_size == 2){ + off += 7; + } + else{ + keep_parsing = 0; + } + } + else{ + keep_parsing = 0; + } + }break; + } + } + } + } + + //- parsing loop + if (keep_parsing){ + for (;;){ + // read inst + U8 inst_byte = 0; + if (off + sizeof(inst_byte) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); + } + else{ + goto loop_break; + } + + // when (... I don't know ...) rely on the next byte + U64 check_off = off; + U8 check_inst_byte = inst_byte; + if ((inst_byte & 0xF0) == 0x40){ + check_off = off + 1; + if (off + sizeof(check_inst_byte) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&check_inst_byte, ptr, sizeof(check_inst_byte)); + } + else{ + goto loop_break; + } + } + + switch (check_inst_byte){ + // pop + case 0x58:case 0x59:case 0x5A:case 0x5B: + case 0x5C:case 0x5D:case 0x5E:case 0x5F: + { + off = check_off + 1; + }break; + + // ret + case 0xC2:case 0xC3: + { + is_epilog = 1; + goto loop_break; + }break; + + // jmp nnnn + case 0xE9: + { + U64 imm_off = check_off + 1; + S32 imm = 0; + if (off + sizeof(imm) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&imm, ptr, sizeof(imm)); + } + else{ + goto loop_break; + } + + U64 next_off = (U64)(imm_off + sizeof(imm) + imm); + if (!(final_pdata->voff_first <= next_off && next_off < final_pdata->voff_one_past_last)){ + goto loop_break; + } + + off = next_off; + // TODO(allen): why isn't this just the end of the epilog? + }break; + + // rep; ret (for amd64 prediction bug) + case 0xF3: + { + U8 next_inst_byte = 0; + if (off + sizeof(next_inst_byte) < inst_size){ + void *ptr = (U8*)inst_base + off; + MemoryCopy(&next_inst_byte, ptr, sizeof(next_inst_byte)); + } + is_epilog = (next_inst_byte == 0xC3); + goto loop_break; + }break; + + default: goto loop_break; + } + } + + loop_break:; + } + + //- fill result + B32 result = is_epilog; + return(result); +} + +internal REGS_Reg64* +unw_pe_x64__gpr_reg(UNW_X64_Regs *regs, UNW_PE_X64_GprReg unw_reg){ + static REGS_Reg64 dummy = {0}; + REGS_Reg64 *result = &dummy; + switch (unw_reg){ + case UNW_PE_X64_GprReg_RAX: result = ®s->rax; break; + case UNW_PE_X64_GprReg_RCX: result = ®s->rcx; break; + case UNW_PE_X64_GprReg_RDX: result = ®s->rdx; break; + case UNW_PE_X64_GprReg_RBX: result = ®s->rbx; break; + case UNW_PE_X64_GprReg_RSP: result = ®s->rsp; break; + case UNW_PE_X64_GprReg_RBP: result = ®s->rbp; break; + case UNW_PE_X64_GprReg_RSI: result = ®s->rsi; break; + case UNW_PE_X64_GprReg_RDI: result = ®s->rdi; break; + case UNW_PE_X64_GprReg_R8 : result = ®s->r8 ; break; + case UNW_PE_X64_GprReg_R9 : result = ®s->r9 ; break; + case UNW_PE_X64_GprReg_R10: result = ®s->r10; break; + case UNW_PE_X64_GprReg_R11: result = ®s->r11; break; + case UNW_PE_X64_GprReg_R12: result = ®s->r12; break; + case UNW_PE_X64_GprReg_R13: result = ®s->r13; break; + case UNW_PE_X64_GprReg_R14: result = ®s->r14; break; + case UNW_PE_X64_GprReg_R15: result = ®s->r15; break; + } + return(result); +} + diff --git a/src/unwind/unwind.h b/src/unwind/unwind.h new file mode 100644 index 00000000..3d34d9bf --- /dev/null +++ b/src/unwind/unwind.h @@ -0,0 +1,314 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef UNWIND_H +#define UNWIND_H + +//////////////////////////////// +//~ allen: Unwind Types + +// * applies to (any X,Y: unwind(X, Y)) + +typedef struct UNW_MemView{ + // Upgrade Path: + // 1. A list of ranges like this one + // 2. Binary-searchable list of ranges + // 3. In-line growth strategy for missing pages (hardwired to source of new data) + // 4. Abstracted source of new data + void *data; + U64 addr_first; + U64 addr_opl; +} UNW_MemView; + +typedef struct UNW_Result{ + B32 dead; + B32 missed_read; + U64 missed_read_addr; + U64 stack_pointer; +} UNW_Result; + + +//////////////////////////////// +//~ allen: X64 Unwind Types + +// * applies to (any X: unwind(X, X64)) + +typedef REGS_RegBlockX64 UNW_X64_Regs; + + + + +//////////////////////////////// +//~ allen: PE X64 Unwind Types + +//- pe format unwind types + +#define UNW_PE_OpCodeXList(X) \ +X(PUSH_NONVOL , 0) \ +X(ALLOC_LARGE , 1) \ +X(ALLOC_SMALL , 2) \ +X(SET_FPREG , 3) \ +X(SAVE_NONVOL , 4) \ +X(SAVE_NONVOL_FAR, 5) \ +X(EPILOG , 6) \ +X(SPARE_CODE , 7) \ +X(SAVE_XMM128 , 8) \ +X(SAVE_XMM128_FAR, 9) \ +X(PUSH_MACHFRAME , 10) + +#define UNW_PE_CODE_FROM_FLAGS(f) ((f)&0xF) +#define UNW_PE_INFO_FROM_FLAGS(f) (((f) >> 4)&0xF) + +typedef U32 UNW_PE_OpCode; +enum UNW_PE_OpCodeEnum{ +#define X(N,C) UNW_PE_OpCode_##N = C, + UNW_PE_OpCodeXList(X) +#undef X +}; + +typedef union UNW_PE_Code{ + struct{ + U8 off_in_prolog; + U8 flags; + }; + U16 u16; +} UNW_PE_Code; + +typedef U8 UNW_PE_InfoFlags; +enum UNW_PE_InfoFlagsEnum{ + UNW_PE_InfoFlag_EHANDLER = (1 << 0), + UNW_PE_InfoFlag_UHANDLER = (1 << 1), + UNW_PE_InfoFlag_FHANDLER = 3, + UNW_PE_InfoFlag_CHAINED = (1 << 2), +} UNW_PE_InfoFlagsEnum; + +#define UNW_PE_INFO_VERSION_FROM_HDR(x) ((x)&0x7) +#define UNW_PE_INFO_FLAGS_FROM_HDR(x) (((x) >> 3)&0x1F) +#define UNW_PE_INFO_REG_FROM_FRAME(x) ((x)&0xF) +#define UNW_PE_INFO_OFF_FROM_FRAME(x) (((x) >> 4)&0xF) + +typedef struct UNW_PE_Info{ + U8 header; + U8 prolog_size; + U8 codes_num; + U8 frame; +} UNW_PE_Info; + + +//////////////////////////////// +//~ allen: PE X64 Unwind Types + +// * applies to (unwind(PE, X64)) + +typedef U8 UNW_PE_X64_GprReg; +enum{ + UNW_PE_X64_GprReg_RAX = 0, + UNW_PE_X64_GprReg_RCX = 1, + UNW_PE_X64_GprReg_RDX = 2, + UNW_PE_X64_GprReg_RBX = 3, + UNW_PE_X64_GprReg_RSP = 4, + UNW_PE_X64_GprReg_RBP = 5, + UNW_PE_X64_GprReg_RSI = 6, + UNW_PE_X64_GprReg_RDI = 7, + UNW_PE_X64_GprReg_R8 = 8, + UNW_PE_X64_GprReg_R9 = 9, + UNW_PE_X64_GprReg_R10 = 10, + UNW_PE_X64_GprReg_R11 = 11, + UNW_PE_X64_GprReg_R12 = 12, + UNW_PE_X64_GprReg_R13 = 13, + UNW_PE_X64_GprReg_R14 = 14, + UNW_PE_X64_GprReg_R15 = 15, +}; + + + + +//////////////////////////////// +//~ allen: ELF/DW Unwind Types + +// * applies to (any X: unwind(ELF/DW, X)) + +// EH: Exception Frames +typedef U8 UNW_DW_EhPtrEnc; +enum{ + UNW_DW_EhPtrEnc_TYPE_MASK = 0x0F, + UNW_DW_EhPtrEnc_PTR = 0x00, // Pointer sized unsigned value + UNW_DW_EhPtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value + UNW_DW_EhPtrEnc_UDATA2 = 0x02, // Unsigned 16-bit value + UNW_DW_EhPtrEnc_UDATA4 = 0x03, // Unsigned 32-bit value + UNW_DW_EhPtrEnc_UDATA8 = 0x04, // Unsigned 64-bit value + UNW_DW_EhPtrEnc_SIGNED = 0x08, // Signed pointer + UNW_DW_EhPtrEnc_SLEB128 = 0x09, // Signed LE base-128 value + UNW_DW_EhPtrEnc_SDATA2 = 0x0A, // Signed 16-bit value + UNW_DW_EhPtrEnc_SDATA4 = 0x0B, // Signed 32-bit value + UNW_DW_EhPtrEnc_SDATA8 = 0x0C, // Signed 64-bit value +}; +enum{ + UNW_DW_EhPtrEnc_MODIF_MASK = 0x70, + UNW_DW_EhPtrEnc_PCREL = 0x10, // Value is relative to the current program counter. + UNW_DW_EhPtrEnc_TEXTREL = 0x20, // Value is relative to the .text section. + UNW_DW_EhPtrEnc_DATAREL = 0x30, // Value is relative to the .got or .eh_frame_hdr section. + UNW_DW_EhPtrEnc_FUNCREL = 0x40, // Value is relative to the function. + UNW_DW_EhPtrEnc_ALIGNED = 0x50, // Value is aligned to an address unit sized boundary. +}; +enum{ + UNW_DW_EhPtrEnc_INDIRECT = 0x80, // This flag indicates that value is stored in virtual memory. + UNW_DW_EhPtrEnc_OMIT = 0xFF, +}; + +typedef struct UNW_DW_EhPtrCtx{ + U64 raw_base_vaddr; // address where pointer is being read + U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64) + U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64) + U64 func_vaddr; // base address of function where IP is located +} UNW_DW_EhPtrCtx; + +// CIE: Common Information Entry +typedef struct UNW_DW_CIEUnpacked{ + U8 version; + UNW_DW_EhPtrEnc lsda_encoding; + UNW_DW_EhPtrEnc addr_encoding; + + B8 has_augmentation_size; + U64 augmentation_size; + String8 augmentation; + + U64 code_align_factor; + S64 data_align_factor; + U64 ret_addr_reg; + + U64 handler_ip; + + U64 cfi_range_min; + U64 cfi_range_max; +} UNW_DW_CIEUnpacked; + +typedef struct UNW_DW_CIEUnpackedNode{ + struct UNW_DW_CIEUnpackedNode *next; + UNW_DW_CIEUnpacked cie; + U64 offset; +} UNW_DW_CIEUnpackedNode; + +// FDE: Frame Description Entry +typedef struct UNW_DW_FDEUnpacked{ + U64 ip_voff_min; + U64 ip_voff_max; + U64 lsda_ip; + + U64 cfi_range_min; + U64 cfi_range_max; +} UNW_DW_FDEUnpacked; + +// CFI: Call Frame Information +typedef struct UNW_DW_CFIRecords{ + B32 valid; + UNW_DW_CIEUnpacked cie; + UNW_DW_FDEUnpacked fde; +} UNW_DW_CFIRecords; + +typedef enum UNW_DW_CFICFARule{ + UNW_DW_CFICFARule_REGOFF, + UNW_DW_CFICFARule_EXPR, +} UNW_DW_CFICFARule; + +typedef struct UNW_DW_CFICFACell{ + UNW_DW_CFICFARule rule; + union{ + struct{ + U64 reg_idx; + S64 offset; + }; + U64 expr_min; + U64 expr_max; + }; +} UNW_DW_CFICFACell; + +typedef enum UNW_DW_CFIRegisterRule{ + UNW_DW_CFIRegisterRule_SAME_VALUE, + UNW_DW_CFIRegisterRule_UNDEFINED, + UNW_DW_CFIRegisterRule_OFFSET, + UNW_DW_CFIRegisterRule_VAL_OFFSET, + UNW_DW_CFIRegisterRule_REGISTER, + UNW_DW_CFIRegisterRule_EXPRESSION, + UNW_DW_CFIRegisterRule_VAL_EXPRESSION, +} UNW_DW_CFIRegisterRule; + +typedef struct UNW_DW_CFICell{ + UNW_DW_CFIRegisterRule rule; + union{ + S64 n; + struct{ + U64 expr_min; + U64 expr_max; + }; + }; +} UNW_DW_CFICell; + +typedef struct UNW_DW_CFIRow{ + struct UNW_DW_CFIRow *next; + UNW_DW_CFICell *cells; + UNW_DW_CFICFACell cfa_cell; +} UNW_DW_CFIRow; + +typedef struct UNW_DW_CFIMachine{ + U64 cells_per_row; + UNW_DW_CIEUnpacked *cie; + UNW_DW_EhPtrCtx *ptr_ctx; + UNW_DW_CFIRow *initial_row; + U64 fde_ip; +} UNW_DW_CFIMachine; + +typedef U8 UNW_DW_CFADecode; +enum{ + UNW_DW_CFADecode_NOP = 0x0, + // 1,2,4,8 reserved for literal byte sizes + UNW_DW_CFADecode_ADDRESS = 0x9, + UNW_DW_CFADecode_ULEB128 = 0xA, + UNW_DW_CFADecode_SLEB128 = 0xB, +}; + +typedef U16 UNW_DW_CFAControlBits; +enum{ + UNW_DW_CFAControlBits_DEC1_MASK = 0x00F, + UNW_DW_CFAControlBits_DEC2_MASK = 0x0F0, + UNW_DW_CFAControlBits_IS_REG_0 = 0x100, + UNW_DW_CFAControlBits_IS_REG_1 = 0x200, + UNW_DW_CFAControlBits_IS_REG_2 = 0x400, + UNW_DW_CFAControlBits_NEW_ROW = 0x800, +}; + + + +//////////////////////////////// +//~ allen: Unwind Functions + +//- mem view construction +internal UNW_MemView unw_memview_from_data(String8 data, U64 base_vaddr); + +//- mem view user face for unwind users +internal B32 unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out); + +#define unw_memview_read_struct(v,addr,p) unw_memview_read((v), (addr), sizeof(*(p)), (p)) + + +//////////////////////////////// +//~ allen: PE X64 Unwind Functions + +//- main interface +internal UNW_Result unw_pe_x64(String8 bindata, PE_BinInfo *bin, + U64 base_vaddr, UNW_MemView *memview, + UNW_X64_Regs *regs_inout); + + +//- pe x64 helpers +internal UNW_Result unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, + U64 base_vaddr, UNW_MemView*memview, + UNW_X64_Regs *regs_inout); + +internal U32 unw_pe_x64__slot_count_from_op_code(UNW_PE_OpCode opcode); +internal B32 unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, + U64 voff, PE_IntelPdata *final_pdata); + +internal REGS_Reg64 *unw_pe_x64__gpr_reg(UNW_X64_Regs *regs, UNW_PE_X64_GprReg unw_reg); + +#endif //UNWIND_H