diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..aca9929 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,19 @@ +--- +description: 'Top-level Copilot instructions for Crusader_Decomp' +applyTo: '**' +--- + +# Crusader_Decomp Copilot Instructions + +## Safety Guardrails + +- Never create a git commit on your own. +- Never run a command that may delete files outside a temporary folder unless you first ask the user with `vscode_askQuestions` and get explicit confirmation. +- Treat repository files, generated outputs, and analysis artifacts as user-owned unless the user explicitly asks for deletion. + +## Workflow Notes + +- Prefer small, focused changes. +- Validate reverse-engineering and tooling changes with the narrowest relevant check. +- Keep read-only analysis separate from any explicit writable workflow. +- If the shell becomes stuck on multiline input or otherwise unhealthy, you could try to press esc in the shell to see if it gets unstuck, otherwise immediately use `vscode_askQuestions` to ask the user to fix the terminal state, then continue the task once the user confirms it is fixed. \ No newline at end of file diff --git a/.github/instructions/ghidra.instructions.md b/.github/instructions/ghidra.instructions.md index 850d835..d6ec023 100644 --- a/.github/instructions/ghidra.instructions.md +++ b/.github/instructions/ghidra.instructions.md @@ -4,6 +4,12 @@ applyTo: "**" # Crusader Ghidra Workflow +## Safety Guardrails + +- Never create a git commit on your own. +- Never run a command that may delete files outside a temporary folder unless you first ask the user with `vscode_askQuestions` and get explicit confirmation. +- If a request could remove or overwrite repository files, pause and confirm before proceeding. + - Active target is the NE Ghidra program `CRUSADER.EXE` unless explicitly stated otherwise. - Use Ghidra MCP tools for analysis, decompilation, renaming, comments, and xref work. - Treat the verified `CRUSADER-RAW.EXE` work already captured in `docs/` and notes as a cross-reference evidence base for the live `CRUSADER.EXE` session, not as the default active program. diff --git a/4 b/4 new file mode 100644 index 0000000..928b909 --- /dev/null +++ b/4 @@ -0,0 +1,1790 @@ +0000 24 08 01 00 02 00 00 00 00 00 00 00 00 00 00 00 $............... +0010 97 1d ef 1c 04 00 00 00 20 00 00 00 00 00 00 00 ........ ....... +0020 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................ +0030 00 00 00 00 00 00 00 00 a9 04 00 00 00 00 00 00 ................ +0040 20 01 00 00 3f 16 9b 0e 00 00 00 28 22 00 00 00 ...?......("... +0050 00 00 00 00 01 00 00 00 24 01 00 00 12 16 c0 0e ........$....... +0060 00 00 00 14 22 01 00 00 00 00 00 63 0b 00 00 00 ...."......c.... +0070 e8 00 00 00 3f 16 bf 0e 18 00 00 32 20 00 00 00 ....?......2 ... +0080 34 12 34 12 0b 00 00 00 e8 00 00 00 7f 16 bf 0e 4.4............. +0090 18 00 00 32 20 00 00 00 34 12 34 12 0b 00 00 00 ...2 ...4.4..... +00a0 e8 00 00 00 3f 16 ff 0e 18 00 00 32 20 00 00 00 ....?......2 ... +00b0 34 12 34 12 0b 00 00 00 e8 00 00 00 7f 16 ff 0e 4.4............. +00c0 18 00 00 32 20 00 00 00 34 12 34 12 0b 00 00 00 ...2 ...4.4..... +00d0 1a 01 00 00 4e 16 bb 0e 00 00 00 14 30 00 00 00 ....N.......0... +00e0 33 34 08 4d 00 00 00 00 1f 01 00 00 0f 16 e3 0e 34.M............ +00f0 00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +0100 1f 01 00 00 0f 16 d7 0e 00 00 00 28 20 00 00 00 ...........( ... +0110 00 00 00 00 02 00 00 00 24 01 00 00 5b 16 92 0e ........$...[... +0120 00 00 00 14 20 01 00 00 00 00 00 24 00 00 00 00 .... ......$.... +0130 12 01 00 00 13 16 9b 0e 00 00 00 32 20 00 00 00 ...........2 ... +0140 00 00 00 00 00 00 00 00 20 01 00 00 2f 16 9b 0e ........ .../... +0150 00 00 00 28 22 00 00 00 00 00 00 00 0b 00 00 00 ...("........... +0160 1a 01 00 00 36 16 ce 0e 00 00 00 14 30 00 00 00 ....6.......0... +0170 23 24 10 4d 00 00 00 00 20 01 00 00 9b 16 f3 0e #$.M.... ....... +0180 0c 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +0190 20 01 00 00 9b 16 eb 0e 06 00 00 28 20 00 00 00 ..........( ... +01a0 00 00 00 00 00 00 00 00 20 01 00 00 9b 16 f7 0e ........ ....... +01b0 06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +01c0 20 01 00 00 9b 16 eb 0e 00 00 00 28 20 00 00 00 ..........( ... +01d0 00 00 00 00 00 00 00 00 20 01 00 00 9b 16 f7 0e ........ ....... +01e0 00 00 00 28 20 00 00 00 00 00 00 00 0b 00 e8 00 ...( ........... +01f0 db 00 04 00 83 16 c7 0e 00 00 00 4b 22 00 00 00 ...........K"... +0200 00 00 00 35 00 00 00 00 1f 01 00 00 93 16 97 0e ...5............ +0210 00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +0220 1f 01 00 00 93 16 a3 0e 00 00 00 28 20 00 00 00 ...........( ... +0230 00 00 00 00 00 00 00 00 c0 00 00 00 a3 16 ab 0e ................ +0240 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0250 bc 00 00 00 a3 16 a7 0e 00 00 00 32 22 00 00 00 ...........2"... +0260 00 00 00 00 00 00 00 00 bb 00 00 00 e3 16 a3 0e ................ +0270 00 00 00 32 20 00 00 00 00 00 00 00 c7 80 df 00 ...2 ........... +0280 de 00 04 00 f3 16 9b 0e 00 00 00 32 20 20 00 00 ...........2 .. +0290 00 00 00 a9 c7 00 00 00 df 00 00 00 d7 16 8f 0e ................ +02a0 0e 00 00 32 22 00 00 00 ef cd ef cd 00 00 00 00 ...2"........... +02b0 de 00 00 00 bf 16 9b 0e 00 00 00 32 20 20 00 00 ...........2 .. +02c0 00 00 00 00 00 00 00 00 f5 00 00 00 4f 17 9c 0e ............O... +02d0 06 00 00 32 20 01 00 00 19 00 aa aa 03 00 00 00 ...2 ........... +02e0 fa 00 00 00 59 17 97 0e 06 00 00 32 20 01 00 00 ....Y......2 ... +02f0 24 00 aa aa 00 00 00 00 bb 00 00 00 23 17 a3 0e $...........#... +0300 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0310 de 00 00 00 23 17 9b 0e 00 00 00 32 20 20 00 00 ....#......2 .. +0320 00 00 00 00 c7 00 00 00 df 00 00 00 0b 17 8f 0e ................ +0330 0e 00 00 32 22 00 00 00 ef cd ef cd 00 00 00 00 ...2"........... +0340 bc 00 00 00 27 17 a7 0e 00 00 00 32 22 00 00 00 ....'......2"... +0350 00 00 00 00 00 00 00 00 c0 00 00 00 27 17 ab 0e ............'... +0360 00 00 00 32 20 00 00 00 00 00 00 00 0b 80 db 00 ...2 ........... +0370 ba 00 06 01 3c 17 87 0e 0a 00 00 32 20 21 00 00 ....<......2 !.. +0380 00 00 00 34 11 00 00 00 1a 01 00 00 1f 17 eb 0e ...4............ +0390 00 00 00 04 30 00 00 00 25 25 00 09 11 00 f4 00 ....0...%%...... +03a0 ba 00 04 00 6e 16 07 0f 0a 00 00 32 20 21 00 00 ....n......2 !.. +03b0 00 00 00 53 15 00 00 00 d8 00 00 00 23 16 36 0f ...S........#.6. +03c0 02 00 00 32 20 00 00 00 00 00 00 00 14 80 d8 00 ...2 ........... +03d0 e4 00 00 00 28 16 3d 0f 02 00 00 32 22 00 00 00 ....(.=....2"... +03e0 00 00 00 5f 11 00 00 00 f4 00 00 00 7f 16 27 0f ..._..........'. +03f0 00 00 00 32 22 00 00 00 00 00 00 00 11 00 00 00 ...2"........... +0400 f4 00 00 00 7f 16 3f 0f 00 00 00 32 22 00 00 00 ......?....2"... +0410 00 00 00 00 00 00 00 00 c0 00 00 00 a3 16 43 0f ..............C. +0420 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0430 bc 00 00 00 9f 16 43 0f 00 00 00 32 20 00 00 00 ......C....2 ... +0440 00 00 00 00 11 00 00 00 1a 01 00 00 e7 16 24 0f ..............$. +0450 02 00 00 04 30 00 00 00 25 25 00 09 0b 01 00 00 ....0...%%...... +0460 ad 00 00 00 ab 16 27 0f 03 00 01 32 32 20 00 00 ......'....22 .. +0470 00 04 00 33 00 00 00 00 bc 00 00 00 a3 16 0f 0f ...3............ +0480 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0490 c0 00 00 00 a7 16 0f 0f 00 00 00 32 20 00 00 00 ...........2 ... +04a0 00 00 00 00 00 00 00 00 de 00 00 00 a7 16 6f 0f ..............o. +04b0 00 00 00 32 20 20 00 00 00 00 00 00 0e 80 df 00 ...2 .......... +04c0 de 00 04 00 cf 16 6f 0f 00 00 00 32 20 20 00 00 ......o....2 .. +04d0 00 00 00 47 0d 80 df 00 de 00 04 00 fb 16 6f 0f ...G..........o. +04e0 00 00 00 32 20 20 00 00 00 00 00 42 0d 00 00 00 ...2 .....B.... +04f0 df 00 00 00 e7 16 63 0f 0e 00 00 32 22 00 00 00 ......c....2"... +0500 ef cd ef cd 0e 00 00 00 df 00 00 00 bf 16 63 0f ..............c. +0510 0e 00 00 32 22 00 00 00 ef cd ef cd 0b 00 00 00 ...2"........... +0520 e9 00 00 00 08 17 07 0f 00 00 00 32 a0 00 00 00 ...........2.... +0530 00 00 00 00 0c 80 df 00 de 00 04 00 27 17 6f 0f ............'.o. +0540 00 00 00 32 20 20 00 00 00 00 00 3a 0b 80 df 00 ...2 .....:.... +0550 de 00 04 00 53 17 6f 0f 00 00 00 32 20 20 00 00 ....S.o....2 .. +0560 00 00 00 32 0b 00 00 00 df 00 00 00 3f 17 63 0f ...2........?.c. +0570 0e 00 00 32 22 00 00 00 ef cd ef cd 0c 00 00 00 ...2"........... +0580 df 00 00 00 13 17 63 0f 0e 00 00 32 22 00 00 00 ......c....2"... +0590 ef cd ef cd 0b 00 00 00 c8 00 00 00 bf 18 47 15 ..............G. +05a0 00 00 01 32 20 01 00 00 02 00 aa aa 1f 80 d8 00 ...2 ........... +05b0 e4 00 1f 00 1b 1d a3 15 02 00 00 32 22 00 00 00 ...........2"... +05c0 00 00 00 7f 13 00 e8 00 ac 00 04 00 4b 1d ff 15 ............K... +05d0 00 00 00 4b 20 00 00 00 00 00 00 5c 00 00 00 00 ...K ......\.... +05e0 20 01 00 00 f3 1c 57 16 00 00 00 28 20 00 00 00 .....W....( ... +05f0 00 00 00 00 00 00 00 00 20 01 00 00 f3 1c 57 16 ........ .....W. +0600 06 00 00 28 20 00 00 00 00 00 00 00 13 00 00 00 ...( ........... +0610 24 01 00 00 e7 1c 67 16 00 00 00 14 22 01 00 00 $.....g....."... +0620 00 1f 1c 1b 13 00 e8 00 db 00 04 00 ff 1c 7f 16 ................ +0630 00 00 00 4b 22 00 00 00 00 00 00 5b 09 00 00 00 ...K"......[.... +0640 e8 00 00 00 3f 1d 3f 16 18 00 00 32 20 00 00 00 ....?.?....2 ... +0650 34 12 34 12 09 00 00 00 e8 00 00 00 7f 1d 7f 16 4.4............. +0660 18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 ...2 ...4.4..... +0670 e8 00 00 00 3f 1d 7f 16 18 00 00 32 20 00 00 00 ....?......2 ... +0680 34 12 34 12 09 00 00 00 e8 00 00 00 7f 1d 3f 16 4.4...........?. +0690 18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 ...2 ...4.4..... +06a0 1a 01 00 00 47 1d 19 16 00 00 00 0e 30 00 00 00 ....G.......0... +06b0 13 14 00 1c 3f 01 00 00 ad 00 00 00 45 1d 06 16 ....?.......E... +06c0 01 00 00 32 30 20 00 00 00 20 00 9e 0a 00 00 00 ...20 ... ...... +06d0 16 01 00 00 03 1d 0f 16 08 00 00 32 22 01 00 00 ...........2"... +06e0 00 00 00 2a 0a 80 21 00 19 01 03 01 47 1d 5f 16 ...*..!.....G._. +06f0 01 00 02 32 20 20 00 00 00 00 00 29 00 00 00 00 ...2 .....).... +0700 bf 00 00 00 5b 1d 7f 16 00 56 00 32 20 00 00 00 ....[....V.2 ... +0710 00 00 00 00 00 00 00 00 bf 00 00 00 6b 1d 7f 16 ............k... +0720 00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +0730 bf 00 00 00 5b 1d 7f 16 08 54 00 32 20 00 00 00 ....[....T.2 ... +0740 00 00 00 00 00 00 00 00 bf 00 00 00 6b 1d 7f 16 ............k... +0750 08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0760 bf 00 00 00 13 1d 43 16 00 00 00 32 20 00 00 00 ......C....2 ... +0770 00 00 00 00 00 00 00 00 bf 00 00 00 13 1d 33 16 ..............3. +0780 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0790 bf 00 00 00 13 1d 33 16 08 55 00 32 20 00 00 00 ......3..U.2 ... +07a0 00 00 00 00 00 00 00 00 bf 00 00 00 13 1d 43 16 ..............C. +07b0 08 54 00 32 20 00 00 00 00 00 00 00 13 00 ff 07 .T.2 ........... +07c0 c2 00 06 03 2f 1d 03 16 08 00 00 32 20 21 00 00 ..../......2 !.. +07d0 00 00 00 5a 13 00 00 00 e8 00 00 00 fb 1c c7 16 ...Z............ +07e0 18 00 00 32 20 00 00 00 34 12 34 12 13 00 00 00 ...2 ...4.4..... +07f0 e8 00 00 00 fb 1c 87 16 18 00 00 32 20 00 00 00 ...........2 ... +0800 34 12 34 12 09 00 00 00 e8 00 00 00 ff 1c f7 16 4.4............. +0810 18 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 ...2 ...4.4..... +0820 c7 00 00 00 e7 1c 86 16 0c 00 00 32 a2 00 00 00 ...........2.... +0830 02 00 00 02 00 00 00 00 20 01 00 00 eb 1c 83 16 ........ ....... +0840 00 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 ...("........... +0850 20 01 00 00 eb 1c 9b 16 00 00 00 28 22 00 00 00 ..........("... +0860 00 00 00 00 13 00 e8 00 db 00 04 00 ff 1c 9f 16 ................ +0870 00 00 00 4b 22 00 00 00 00 00 00 59 44 81 00 00 ...K"......YD... +0880 ad 00 00 00 36 1d f4 16 01 00 00 32 30 20 00 00 ....6......20 .. +0890 00 20 00 a0 09 00 00 00 e8 00 00 00 7f 1d ff 16 . .............. +08a0 18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 ...2 ...4.4..... +08b0 e8 00 00 00 3f 1d ff 16 18 00 00 32 20 00 00 00 ....?......2 ... +08c0 34 12 34 12 09 00 00 00 e8 00 00 00 7f 1d bf 16 4.4............. +08d0 18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 ...2 ...4.4..... +08e0 e8 00 00 00 3f 1d bf 16 18 00 00 32 20 00 00 00 ....?......2 ... +08f0 34 12 34 12 13 00 db 00 dd 00 06 01 07 1d e3 16 4.4............. +0900 12 00 01 0a a2 20 00 00 02 00 01 58 00 00 00 00 ..... .....X.... +0910 bf 00 00 00 13 1d bb 16 00 00 00 32 20 00 00 00 ...........2 ... +0920 00 00 00 00 00 00 00 00 bf 00 00 00 27 1d bb 16 ............'... +0930 00 54 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .T.2 ........... +0940 bf 00 00 00 6b 1d 93 16 00 55 00 32 20 00 00 00 ....k....U.2 ... +0950 00 00 00 00 00 00 00 00 bf 00 00 00 5b 1d 93 16 ............[... +0960 00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +0970 bf 00 00 00 5b 1d 93 16 08 55 00 32 20 00 00 00 ....[....U.2 ... +0980 00 00 00 00 00 00 00 00 bf 00 00 00 6b 1d 8f 16 ............k... +0990 08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +09a0 bf 00 00 00 13 1d bb 16 08 55 00 32 20 00 00 00 .........U.2 ... +09b0 00 00 00 00 00 00 00 00 bf 00 00 00 23 1d bb 16 ............#... +09c0 08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +09d0 0e 01 00 00 93 1a 4f 17 00 00 00 32 20 00 00 00 ......O....2 ... +09e0 00 00 00 00 00 00 00 00 0e 01 00 00 93 1a 63 17 ..............c. +09f0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0a00 c3 00 00 00 b3 1a 43 17 00 00 00 28 a0 00 00 00 ......C....(.... +0a10 00 00 00 00 0b 00 00 00 e7 00 00 00 c3 1a 07 17 ................ +0a20 00 00 01 32 20 00 00 00 00 00 00 02 41 00 00 00 ...2 .......A... +0a30 c4 00 00 00 df 1a 0b 17 0e 00 02 32 20 00 00 00 ...........2 ... +0a40 00 00 00 00 08 00 00 00 ff 00 00 00 ef 1a 6b 17 ..............k. +0a50 00 00 00 00 20 00 00 00 03 00 00 1c 00 00 00 00 .... ........... +0a60 c4 00 00 00 8b 1a 7f 17 12 00 00 32 22 00 00 00 ...........2"... +0a70 00 00 00 00 1a 00 00 00 e8 00 00 00 ff 1a 7f 17 ................ +0a80 18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 ...2 ...4.4..... +0a90 e8 00 00 00 ff 1a 3f 17 18 00 00 32 20 00 00 00 ......?....2 ... +0aa0 34 12 34 12 1a 00 00 00 e8 00 00 00 bf 1a 7f 17 4.4............. +0ab0 18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 ...2 ...4.4..... +0ac0 e8 00 00 00 bf 1a 3f 17 18 00 00 32 20 00 00 00 ......?....2 ... +0ad0 34 12 34 12 ee 80 ff 00 17 01 20 00 f7 1a 13 17 4.4....... ..... +0ae0 00 00 00 32 20 21 00 00 00 00 00 ad 1b 01 00 00 ...2 !.......... +0af0 ad 00 00 00 b3 1a 7b 17 01 00 02 32 30 20 00 00 ......{....20 .. +0b00 00 60 00 75 00 00 00 00 da 00 00 00 9b 1a 23 17 .`.u..........#. +0b10 06 00 00 32 22 00 00 00 00 00 00 00 0b 80 14 01 ...2"........... +0b20 c6 00 00 12 8e 1a 1f 17 06 00 00 32 22 21 00 00 ...........2"!.. +0b30 00 10 1c 31 0b 00 00 00 14 01 00 00 cb 1a 07 17 ...1............ +0b40 0c 00 00 32 20 01 00 00 00 00 00 30 00 00 00 00 ...2 ......0.... +0b50 bc 00 00 00 2f 1b 27 17 00 00 00 32 22 00 00 00 ..../.'....2"... +0b60 00 00 00 00 00 00 00 00 bf 00 00 00 17 1b 17 17 ................ +0b70 08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0b80 bf 00 00 00 17 1b 17 17 00 00 00 32 20 00 00 00 ...........2 ... +0b90 00 00 00 00 00 00 00 00 b3 00 00 00 0f 1b 07 17 ................ +0ba0 12 00 00 32 20 00 00 00 00 00 00 00 05 00 00 00 ...2 ........... +0bb0 24 01 00 00 27 1b 13 17 00 00 00 14 22 01 00 00 $...'......."... +0bc0 00 00 1f 9b 0d 01 ac 00 d9 00 06 01 3f 1b 4f 17 ............?.O. +0bd0 00 00 04 32 20 00 00 00 77 66 55 41 1a 00 00 00 ...2 ...wfUA.... +0be0 e8 00 00 00 7f 1b 7f 17 18 00 00 32 20 00 00 00 ...........2 ... +0bf0 34 12 34 12 1a 00 00 00 e8 00 00 00 3f 1b 7f 17 4.4.........?... +0c00 18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 ...2 ...4.4..... +0c10 e8 00 00 00 7f 1b 3f 17 18 00 00 32 20 00 00 00 ......?....2 ... +0c20 34 12 34 12 1a 00 00 00 e8 00 00 00 3f 1b 3f 17 4.4.........?.?. +0c30 18 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 ...2 ...4.4..... +0c40 0f 01 00 00 43 1b 17 17 00 00 01 32 20 20 00 00 ....C......2 .. +0c50 00 00 00 00 00 00 00 00 0f 01 00 00 5b 1b 17 17 ............[... +0c60 00 00 00 32 20 20 00 00 00 00 00 00 00 00 00 00 ...2 .......... +0c70 bb 00 00 00 7f 1b 1b 17 00 00 00 32 20 00 00 00 ...........2 ... +0c80 00 00 00 00 00 00 00 00 bd 00 00 00 3f 1b 1b 17 ............?... +0c90 00 00 00 32 20 00 00 00 00 00 00 00 17 80 16 01 ...2 ........... +0ca0 dd 00 02 01 33 1b 0b 17 12 00 00 0a a0 20 00 00 ....3........ .. +0cb0 02 00 05 67 00 00 00 00 be 00 00 00 2f 1b 63 17 ...g......../.c. +0cc0 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +0cd0 be 00 00 00 2f 1b 5b 17 00 00 00 32 22 00 00 00 ..../.[....2"... +0ce0 00 00 00 00 0d 80 ff 07 0c 01 06 03 63 1b 67 17 ............c.g. +0cf0 08 00 02 32 22 21 00 00 00 00 00 40 0d 00 00 00 ...2"!.....@.... +0d00 e8 00 00 00 ff 1b 03 17 18 00 00 32 20 00 00 00 ...........2 ... +0d10 34 12 34 12 04 00 00 00 24 01 00 00 8f 1b 5b 17 4.4.....$.....[. +0d20 00 00 00 14 22 01 00 00 00 00 00 1e 11 01 00 00 ...."........... +0d30 ad 00 00 00 8b 1b 37 17 01 00 01 32 32 20 00 00 ......7....22 .. +0d40 00 04 00 52 0d 00 e8 00 ac 00 04 00 83 1b 43 17 ...R..........C. +0d50 00 00 01 4b 22 00 00 00 00 00 00 3f 00 00 00 00 ...K"......?.... +0d60 c4 00 00 00 9f 1b 0b 17 10 00 01 32 20 00 00 00 ...........2 ... +0d70 00 00 00 00 00 00 00 00 c4 00 00 00 e3 1b 0b 17 ................ +0d80 10 00 01 32 20 00 00 00 00 00 00 00 9b 80 ff 07 ...2 ........... +0d90 ee 00 00 00 8b 1b 1f 17 00 00 01 32 20 00 00 00 ...........2 ... +0da0 00 00 00 00 9b 80 ff 07 ef 00 37 37 9f 1b 23 17 ..........77..#. +0db0 00 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 ...2 ........... +0dc0 ee 00 00 00 a7 1b 1f 17 00 00 00 32 20 00 00 00 ...........2 ... +0dd0 00 00 00 00 9b 80 ff 07 f0 00 00 00 ab 1b 1f 17 ................ +0de0 16 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 ...2 ........... +0df0 f1 00 00 00 9f 1b 07 17 00 00 00 32 20 00 00 00 ...........2 ... +0e00 00 00 00 00 0d 00 00 00 1a 01 00 00 cd 1b 1a 17 ................ +0e10 02 00 00 0e 30 00 00 00 55 54 20 1c 0d 00 00 00 ....0...UT ..... +0e20 e8 00 00 00 ff 1b 43 17 18 00 00 32 20 00 00 00 ......C....2 ... +0e30 34 12 34 12 0d 00 00 00 e8 00 00 00 bf 1b 43 17 4.4...........C. +0e40 18 00 00 32 20 00 00 00 34 12 34 12 0d 00 00 00 ...2 ...4.4..... +0e50 e8 00 00 00 ff 1b 7f 17 18 00 00 32 20 00 00 00 ...........2 ... +0e60 34 12 34 12 0d 00 00 00 e8 00 00 00 bf 1b 7f 17 4.4............. +0e70 18 00 00 32 20 00 00 00 34 12 34 12 0d 00 00 00 ...2 ...4.4..... +0e80 ff 00 00 00 bf 1b 27 17 00 00 00 00 20 00 00 00 ......'..... ... +0e90 02 00 00 3e 0d 00 00 00 e8 00 00 00 bf 1b 03 17 ...>............ +0ea0 18 00 00 32 20 00 00 00 34 12 34 12 7c 00 00 00 ...2 ...4.4.|... +0eb0 d2 00 00 00 3f 1d 7f 17 00 00 00 32 20 00 00 00 ....?......2 ... +0ec0 00 00 00 00 7c 00 00 00 d2 00 00 00 3f 1d 3f 17 ....|.......?.?. +0ed0 00 00 00 32 20 00 00 00 00 00 00 00 7c 00 00 00 ...2 .......|... +0ee0 d2 00 00 00 7f 1d 7f 17 00 00 00 32 20 00 00 00 ...........2 ... +0ef0 00 00 00 00 7c 00 00 00 d2 00 00 00 7f 1d 3f 17 ....|.........?. +0f00 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0f10 e3 00 00 00 4f 1d 6f 17 00 00 00 32 20 00 00 00 ....O.o....2 ... +0f20 00 00 00 00 32 00 00 00 1a 01 00 00 1d 1d 2b 17 ....2.........+. +0f30 04 00 00 0e 30 00 00 00 15 14 00 1c 00 00 00 00 ....0........... +0f40 0d 01 00 00 23 1d 5b 17 04 00 00 32 20 00 00 00 ....#.[....2 ... +0f50 77 66 55 00 00 00 00 00 b0 00 00 00 23 1d 17 17 wfU.........#... +0f60 04 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0f70 b0 00 00 00 13 1d 17 17 04 00 02 32 20 00 00 00 ...........2 ... +0f80 00 00 00 00 00 00 00 00 d1 00 00 00 23 1d 17 17 ............#... +0f90 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0fa0 d1 00 00 00 13 1d 17 17 04 00 00 32 20 00 00 00 ...........2 ... +0fb0 00 00 00 00 00 00 00 00 c0 00 00 00 27 1d 47 17 ............'.G. +0fc0 04 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +0fd0 c0 00 00 00 2b 1d 47 17 04 00 01 32 20 00 00 00 ....+.G....2 ... +0fe0 00 00 00 00 00 00 00 00 bc 00 00 00 4f 1d 43 17 ............O.C. +0ff0 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1000 0d 01 00 00 4f 1d 43 17 04 00 00 32 20 00 00 00 ....O.C....2 ... +1010 77 66 55 00 00 00 00 00 0d 01 00 00 4f 1d 23 17 wfU.........O.#. +1020 04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +1030 0d 01 00 00 23 1d 3b 17 04 00 00 32 20 00 00 00 ....#.;....2 ... +1040 77 66 55 00 00 00 00 00 0d 01 00 00 23 1d 7f 17 wfU.........#... +1050 04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +1060 c0 00 00 00 27 1d 63 17 04 00 01 32 22 00 00 00 ....'.c....2"... +1070 00 00 00 00 00 00 00 00 bd 00 00 00 27 1d 5b 17 ............'.[. +1080 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1090 c0 00 00 00 27 1d 4b 17 04 00 00 32 20 00 00 00 ....'.K....2 ... +10a0 00 00 00 00 00 00 00 00 c0 00 00 00 4f 1d 47 17 ............O.G. +10b0 04 00 00 32 20 00 00 00 00 00 00 00 35 81 21 00 ...2 .......5.!. +10c0 19 01 03 00 24 1d 41 17 05 00 02 32 20 20 00 00 ....$.A....2 .. +10d0 00 00 00 97 35 01 00 00 ad 00 00 00 30 1d 2c 17 ....5.......0.,. +10e0 05 00 01 32 30 20 00 00 00 40 00 96 00 00 00 00 ...20 ...@...... +10f0 bc 00 00 00 4f 1d 23 17 04 00 00 32 22 00 00 00 ....O.#....2"... +1100 00 00 00 00 09 00 e8 00 ac 00 04 00 4b 1d 03 17 ............K... +1110 04 00 00 4b 20 00 00 00 00 00 00 23 09 00 00 00 ...K ......#.... +1120 16 01 00 00 07 1d 2f 17 10 00 00 32 22 01 00 00 ....../....2"... +1130 00 00 00 22 00 00 00 00 bc 00 00 00 4b 1d 47 17 ..."........K.G. +1140 04 00 00 32 20 00 00 00 00 00 00 00 32 00 00 00 ...2 .......2... +1150 1a 01 00 00 1b 1d 4f 17 04 00 00 0e 30 00 00 00 ......O.....0... +1160 15 14 08 1c 01 00 00 00 1b 01 00 00 73 1d 2b 17 ............s.+. +1170 05 00 00 32 20 00 00 00 00 00 00 07 09 00 ac 00 ...2 ........... +1180 c2 00 06 01 2e 1d 07 17 0e 00 00 32 20 21 00 00 ...........2 !.. +1190 00 00 00 21 40 00 00 00 d2 00 00 00 ff 1d 7f 17 ...!@........... +11a0 00 00 00 32 20 00 00 00 00 00 00 00 40 00 00 00 ...2 .......@... +11b0 d2 00 00 00 bf 1d 7f 17 00 00 00 32 20 00 00 00 ...........2 ... +11c0 00 00 00 00 40 00 00 00 d2 00 00 00 ff 1d 3f 17 ....@.........?. +11d0 00 00 00 32 20 00 00 00 00 00 00 00 40 00 00 00 ...2 .......@... +11e0 d2 00 00 00 bf 1d 3f 17 00 00 00 32 20 00 00 00 ......?....2 ... +11f0 00 00 00 00 00 00 00 00 0d 01 00 00 8f 1d 23 17 ..............#. +1200 04 00 00 32 20 00 00 00 77 66 55 00 01 00 00 00 ...2 ...wfU..... +1210 e0 00 00 00 8c 1d 20 17 0c 00 00 ff a0 00 00 00 ...... ......... +1220 02 00 00 01 00 00 00 00 b3 00 00 00 87 1a 97 17 ................ +1230 12 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1240 00 01 00 00 f3 1a 9b 17 00 00 00 32 20 00 00 00 ...........2 ... +1250 00 00 00 00 00 00 00 00 c0 00 00 00 cf 1a 83 17 ................ +1260 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1270 be 00 00 00 d7 1a 83 17 00 00 02 32 20 00 00 00 ...........2 ... +1280 00 00 00 00 00 00 00 00 be 00 00 00 df 1a 83 17 ................ +1290 00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +12a0 bc 00 00 00 ff 1a 83 17 00 00 00 32 20 00 00 00 ...........2 ... +12b0 00 00 00 00 1a 00 00 00 e8 00 00 00 ff 1a ff 17 ................ +12c0 18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 ...2 ...4.4..... +12d0 e8 00 00 00 bf 1a ff 17 18 00 00 32 20 00 00 00 ...........2 ... +12e0 34 12 34 12 1a 00 00 00 e8 00 00 00 bf 1a bf 17 4.4............. +12f0 18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 ...2 ...4.4..... +1300 e8 00 00 00 ff 1a bf 17 18 00 00 32 20 00 00 00 ...........2 ... +1310 34 12 34 12 00 00 00 00 e5 00 00 00 f5 1a ac 17 4.4............. +1320 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1330 cb 00 00 00 87 1a df 17 00 00 00 32 22 00 00 00 ...........2"... +1340 00 00 00 00 00 00 00 00 ea 00 00 00 93 1a 97 17 ................ +1350 00 00 00 32 22 00 00 00 00 00 00 00 1a 00 00 00 ...2"........... +1360 1a 01 00 00 a7 1a 8b 17 00 00 00 0e 30 00 00 00 ............0... +1370 53 54 08 1d 1a 00 00 00 1a 01 00 00 bf 1a c9 17 ST.............. +1380 00 00 00 0e 30 00 00 00 51 54 00 1c 00 00 00 00 ....0...QT...... +1390 0e 01 00 00 fb 1a e3 17 00 00 00 32 20 00 00 00 ...........2 ... +13a0 00 00 00 00 00 00 00 00 0e 01 00 00 df 1a e3 17 ................ +13b0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +13c0 c0 00 00 00 7b 1b 87 17 00 00 00 32 20 00 00 00 ....{......2 ... +13d0 00 00 00 00 00 00 00 00 bd 00 00 00 77 1b 87 17 ............w... +13e0 00 00 00 32 20 00 00 00 00 00 00 00 1a 00 00 00 ...2 ........... +13f0 1a 01 00 00 21 1b c1 17 00 00 00 04 30 00 00 00 ....!.......0... +1400 13 15 00 08 00 00 00 00 00 01 00 00 4b 1b 9b 17 ............K... +1410 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1420 00 01 00 00 1f 1b 9b 17 00 00 00 32 20 00 00 00 ...........2 ... +1430 00 00 00 00 1a 00 00 00 e8 00 00 00 7f 1b ff 17 ................ +1440 18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 ...2 ...4.4..... +1450 e8 00 00 00 3f 1b ff 17 18 00 00 32 20 00 00 00 ....?......2 ... +1460 34 12 34 12 1a 00 00 00 e8 00 00 00 7f 1b bf 17 4.4............. +1470 18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 ...2 ...4.4..... +1480 e8 00 00 00 3f 1b bf 17 18 00 00 32 20 00 00 00 ....?......2 ... +1490 34 12 34 12 00 00 00 00 e5 00 00 00 44 1b aa 17 4.4.........D... +14a0 00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +14b0 e5 00 00 00 19 1b ac 17 00 00 01 32 22 00 00 00 ...........2"... +14c0 00 00 00 00 00 00 00 00 bb 00 00 00 57 1b 87 17 ............W... +14d0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +14e0 bd 00 00 00 67 1b 87 17 00 00 00 32 20 00 00 00 ....g......2 ... +14f0 00 00 00 00 00 00 00 00 bc 00 00 00 2f 1b 83 17 ............/... +1500 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1510 c4 00 00 00 9f 1b 8b 17 12 00 02 32 20 00 00 00 ...........2 ... +1520 00 00 00 00 90 80 ff 07 cd 00 00 00 cb 1b 9b 17 ................ +1530 00 00 00 32 20 00 00 00 00 00 00 00 90 80 ff 07 ...2 ........... +1540 d0 00 00 00 c7 1b 9f 17 14 00 00 32 20 00 00 00 ...........2 ... +1550 00 00 00 00 90 80 ff 07 cd 00 00 00 a7 1b 9b 17 ................ +1560 00 00 01 32 20 00 00 00 00 00 00 00 90 80 ff 07 ...2 ........... +1570 ce 00 00 00 bb 1b 87 17 00 00 00 32 20 00 00 00 ...........2 ... +1580 00 00 00 00 90 80 ff 07 cf 00 2c 2c c3 1b 9b 17 ..........,,.... +1590 00 00 00 32 20 00 00 00 00 00 00 00 37 00 00 00 ...2 .......7... +15a0 1a 01 00 00 9a 1b d0 17 02 00 00 0e 30 00 00 00 ............0... +15b0 53 54 20 1c 00 00 00 00 c4 00 00 00 d7 1b 8b 17 ST ............. +15c0 12 00 02 32 20 00 00 00 00 00 00 00 37 01 00 00 ...2 .......7... +15d0 ad 00 00 00 bf 1b f7 17 01 00 02 32 30 20 00 00 ...........20 .. +15e0 00 60 00 98 32 80 21 00 19 01 03 01 22 1d a7 17 .`..2.!....."... +15f0 05 00 02 32 20 20 00 00 00 00 00 91 00 00 00 00 ...2 .......... +1600 bd 00 00 00 27 1d 93 17 04 00 00 32 22 00 00 00 ....'......2"... +1610 00 00 00 00 61 80 f8 00 10 01 03 00 03 1d cf 17 ....a........... +1620 04 00 01 32 22 20 00 00 00 00 00 a1 83 00 00 00 ...2" .......... +1630 d2 00 00 00 3f 1d ff 17 00 00 00 32 20 00 00 00 ....?......2 ... +1640 00 00 00 00 83 00 00 00 d2 00 00 00 3f 1d bf 17 ............?... +1650 00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 ...2 ........... +1660 d2 00 00 00 7f 1d ff 17 00 00 00 32 20 00 00 00 ...........2 ... +1670 00 00 00 00 83 00 00 00 d2 00 00 00 7f 1d bf 17 ................ +1680 00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 ...2 ........... +1690 0d 01 00 00 23 1d ff 17 04 00 00 32 20 00 00 00 ....#......2 ... +16a0 77 66 55 00 83 00 00 00 0d 01 00 00 23 1d 9f 17 wfU.........#... +16b0 04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 ...2 ...wfU..... +16c0 0d 01 00 00 23 1d bf 17 04 00 00 32 20 00 00 00 ....#......2 ... +16d0 77 66 55 00 83 00 00 00 0d 01 00 00 23 1d df 17 wfU.........#... +16e0 04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +16f0 c0 00 00 00 6b 1d fb 17 04 00 00 32 20 00 00 00 ....k......2 ... +1700 00 00 00 00 00 00 00 00 c0 00 00 00 27 1d fb 17 ............'... +1710 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1720 bb 00 00 00 67 1d fb 17 04 00 00 32 20 00 00 00 ....g......2 ... +1730 00 00 00 00 00 00 00 00 0d 01 00 00 23 1d ff 17 ............#... +1740 04 00 00 32 20 00 00 00 77 66 55 00 35 00 00 00 ...2 ...wfU.5... +1750 1a 01 00 00 1e 1d fd 17 04 00 00 0e 30 00 00 00 ............0... +1760 11 11 00 1c 00 00 00 00 bc 00 00 00 27 1d 83 17 ............'... +1770 04 00 00 32 22 00 00 00 00 00 00 00 61 00 00 00 ...2".......a... +1780 f8 00 00 44 28 1d d0 17 04 00 00 32 20 00 00 00 ...D(......2 ... +1790 00 00 00 00 00 00 00 00 be 00 00 00 27 1d 9b 17 ............'... +17a0 04 00 05 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +17b0 bc 00 00 00 27 1d f7 17 04 00 01 32 22 00 00 00 ....'......2"... +17c0 00 00 00 00 35 80 21 00 19 01 03 01 23 1d 87 17 ....5.!.....#... +17d0 05 00 02 32 20 20 00 00 00 00 00 95 00 00 00 00 ...2 .......... +17e0 c0 00 00 00 af 1d af 17 04 00 00 32 20 00 00 00 ...........2 ... +17f0 00 00 00 00 00 00 00 00 c0 00 00 00 8b 1d af 17 ................ +1800 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1810 be 00 00 00 af 1d b7 17 04 00 00 32 22 00 00 00 ...........2"... +1820 00 00 00 00 00 00 00 00 be 00 00 00 8b 1d b7 17 ................ +1830 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1840 bd 00 00 00 af 1d c7 17 04 00 00 32 22 00 00 00 ...........2"... +1850 00 00 00 00 00 00 00 00 bd 00 00 00 8b 1d c7 17 ................ +1860 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1870 bc 00 00 00 af 1d e7 17 04 00 00 32 22 00 00 00 ...........2"... +1880 00 00 00 00 00 00 00 00 bc 00 00 00 8b 1d e7 17 ................ +1890 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +18a0 0d 01 00 00 ab 1d cb 17 04 00 00 32 20 00 00 00 ...........2 ... +18b0 77 66 55 00 00 00 00 00 e3 00 00 00 87 1d e3 17 wfU............. +18c0 00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 ...2 .......?... +18d0 d2 00 00 00 ff 1d ff 17 00 00 00 32 20 00 00 00 ...........2 ... +18e0 00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d ff 17 ....?........... +18f0 00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 ...2 .......?... +1900 d2 00 00 00 ff 1d bf 17 00 00 00 32 20 00 00 00 ...........2 ... +1910 00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d bf 17 ....?........... +1920 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1930 0d 01 00 00 ab 1d eb 17 04 00 00 32 20 00 00 00 ...........2 ... +1940 77 66 55 00 18 00 00 00 e8 00 00 00 ff 1a 7f 18 wfU............. +1950 18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 ...2 ...4.4..... +1960 e8 00 00 00 ff 1a 3f 18 18 00 00 32 20 00 00 00 ......?....2 ... +1970 34 12 34 12 18 00 00 00 e8 00 00 00 bf 1a 03 18 4.4............. +1980 18 00 00 32 20 00 00 00 34 12 34 12 04 00 00 00 ...2 ...4.4..... +1990 1a 01 00 00 e3 1a 1c 18 00 00 00 7d 30 00 00 00 ...........}0... +19a0 05 00 00 45 00 00 00 00 00 01 00 00 d3 1a 63 18 ...E..........c. +19b0 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +19c0 e5 00 00 00 ee 1a 5a 18 00 00 02 32 22 00 00 00 ......Z....2"... +19d0 00 00 00 00 04 00 00 00 28 01 00 00 eb 1a 27 18 ........(.....'. +19e0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +19f0 c4 00 00 00 fb 1a 0b 18 10 00 02 32 20 00 00 00 ...........2 ... +1a00 00 00 00 00 04 00 ff 00 17 01 20 00 07 1b 17 18 .......... ..... +1a10 00 00 00 32 20 21 00 00 00 00 00 0e 00 00 00 00 ...2 !.......... +1a20 b3 00 00 00 1b 1b 07 18 12 00 00 32 20 00 00 00 ...........2 ... +1a30 00 00 00 00 18 00 00 00 e8 00 00 00 3f 1b 3f 18 ............?.?. +1a40 18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 ...2 ...4.4..... +1a50 e8 00 00 00 3f 1b 7f 18 18 00 00 32 20 00 00 00 ....?......2 ... +1a60 34 12 34 12 18 00 00 00 e8 00 00 00 7f 1b 3f 18 4.4...........?. +1a70 18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 ...2 ...4.4..... +1a80 e8 00 00 00 7f 1b 7f 18 18 00 00 32 20 00 00 00 ...........2 ... +1a90 34 12 34 12 04 00 00 00 f2 00 00 00 0e 1b 28 18 4.4...........(. +1aa0 00 00 00 32 20 00 00 00 00 00 00 00 1a 00 e8 00 ...2 ........... +1ab0 ac 00 04 00 43 1b 03 18 00 00 01 4b 20 00 00 00 ....C......K ... +1ac0 00 00 00 71 1a 00 ff 07 c2 00 06 03 52 1b 07 18 ...q........R... +1ad0 0b 00 00 32 20 21 00 00 00 00 00 70 19 00 00 00 ...2 !.....p.... +1ae0 1a 01 00 00 39 1b 52 18 00 00 00 04 30 00 00 00 ....9.R.....0... +1af0 25 25 00 09 1a 01 ff 07 1d 01 02 00 30 1b 11 18 %%..........0... +1b00 00 00 00 4b 20 00 00 00 00 00 00 6f 1a 80 ac 00 ...K ......o.... +1b10 d9 00 06 01 7f 1b 3f 18 00 00 04 32 20 00 00 00 ......?....2 ... +1b20 77 66 55 6e 18 00 e8 00 ac 00 04 00 83 1b 3f 18 wfUn..........?. +1b30 00 00 01 4b 22 00 00 00 00 00 00 6a 00 00 00 00 ...K"......j.... +1b40 b3 00 00 00 af 1b 03 18 10 00 00 32 20 00 00 00 ...........2 ... +1b50 00 00 00 00 01 00 00 00 1a 01 00 00 bf 1b 50 18 ..............P. +1b60 00 00 00 04 30 00 00 00 15 15 00 09 02 00 00 00 ....0........... +1b70 1a 01 00 00 c2 1b 37 18 00 00 00 0e 30 00 00 00 ......7.....0... +1b80 15 14 00 1d 06 00 00 00 c7 00 00 00 eb 1b 0b 18 ................ +1b90 0a 00 00 32 a0 00 00 00 02 00 00 02 18 80 ac 00 ...2............ +1ba0 c2 00 06 01 87 1b 4b 18 0c 00 00 32 22 21 00 00 ......K....2"!.. +1bb0 00 00 00 69 17 80 16 01 dd 00 02 01 8b 1b 6b 18 ...i..........k. +1bc0 10 00 00 0a a2 20 00 00 02 00 05 66 00 00 00 00 ..... .....f.... +1bd0 c4 00 00 00 93 1b 07 18 10 00 01 32 20 00 00 00 ...........2 ... +1be0 00 00 00 00 02 00 00 00 1a 01 00 00 c3 1b 1f 18 ................ +1bf0 00 00 00 0e 30 00 00 00 11 14 10 1d 00 00 00 00 ....0........... +1c00 b0 00 00 00 4f 1d 3b 18 04 00 02 32 20 00 00 00 ....O.;....2 ... +1c10 00 00 00 00 00 00 00 00 b0 00 00 00 3b 1d 3b 18 ............;.;. +1c20 04 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1c30 b0 00 00 00 63 1d 3b 18 04 00 02 32 20 00 00 00 ....c.;....2 ... +1c40 00 00 00 00 00 00 00 00 b8 00 00 00 4f 1d 0b 18 ............O... +1c50 04 00 03 32 20 00 00 00 00 00 00 00 07 00 00 00 ...2 ........... +1c60 13 01 00 00 44 1d 11 18 04 00 00 32 22 00 00 00 ....D......2"... +1c70 00 00 00 00 32 01 00 00 ad 00 00 00 74 1d 1d 18 ....2.......t... +1c80 05 00 0c 32 32 20 00 00 00 33 00 90 32 80 21 00 ...22 ...3..2.!. +1c90 19 01 03 03 23 1d 6b 18 05 00 02 32 20 20 00 00 ....#.k....2 .. +1ca0 00 00 00 8f 2f 00 00 00 1a 01 00 00 1c 1d 42 18 ..../.........B. +1cb0 04 00 00 0e 30 00 00 00 15 11 00 1c 00 00 00 00 ....0........... +1cc0 e3 00 00 00 5f 1d 7f 18 00 00 00 32 20 00 00 00 ...._......2 ... +1cd0 00 00 00 00 00 00 00 00 b0 00 00 00 5f 1d 0f 18 ............_... +1ce0 04 00 02 32 20 00 00 00 00 00 00 00 33 80 21 00 ...2 .......3.!. +1cf0 19 01 03 03 6b 1d 2b 18 05 00 02 32 20 20 00 00 ....k.+....2 .. +1d00 00 00 00 93 00 00 00 00 c0 00 00 00 6b 1d 07 18 ............k... +1d10 04 00 01 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1d20 c0 00 00 00 6b 1d 33 18 04 00 01 32 22 00 00 00 ....k.3....2"... +1d30 00 00 00 00 00 00 00 00 c0 00 00 00 6b 1d 0b 18 ............k... +1d40 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1d50 c0 00 00 00 6b 1d 2f 18 04 00 00 32 20 00 00 00 ....k./....2 ... +1d60 00 00 00 00 83 00 00 00 d2 00 00 00 3f 1d 7f 18 ............?... +1d70 00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 ...2 ........... +1d80 d2 00 00 00 3f 1d 3f 18 00 00 00 32 20 00 00 00 ....?.?....2 ... +1d90 00 00 00 00 83 00 00 00 d2 00 00 00 7f 1d 7f 18 ................ +1da0 00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 ...2 ........... +1db0 d2 00 00 00 7f 1d 3f 18 00 00 00 32 20 00 00 00 ......?....2 ... +1dc0 00 00 00 00 83 00 00 00 0d 01 00 00 23 1d 7f 18 ............#... +1dd0 04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 ...2 ...wfU..... +1de0 0d 01 00 00 23 1d 1f 18 04 00 00 32 20 00 00 00 ....#......2 ... +1df0 77 66 55 00 83 00 00 00 0d 01 00 00 23 1d 3f 18 wfU.........#.?. +1e00 04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 ...2 ...wfU..... +1e10 0d 01 00 00 23 1d 5f 18 04 00 00 32 20 00 00 00 ....#._....2 ... +1e20 77 66 55 00 00 00 00 00 0d 01 00 00 47 1d 3b 18 wfU.........G.;. +1e30 04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +1e40 0d 01 00 00 47 1d 1b 18 04 00 00 32 20 00 00 00 ....G......2 ... +1e50 77 66 55 00 00 00 00 00 0d 01 00 00 67 1d 3b 18 wfU.........g.;. +1e60 04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +1e70 0d 01 00 00 67 1d 1b 18 04 00 00 32 20 00 00 00 ....g......2 ... +1e80 77 66 55 00 00 00 00 00 c0 00 00 00 27 1d 3f 18 wfU.........'.?. +1e90 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1ea0 c0 00 00 00 6b 1d 3f 18 04 00 00 32 20 00 00 00 ....k.?....2 ... +1eb0 00 00 00 00 00 00 00 00 c0 00 00 00 27 1d 43 18 ............'.C. +1ec0 04 00 01 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1ed0 bc 00 00 00 47 1d 3f 18 04 00 00 32 20 00 00 00 ....G.?....2 ... +1ee0 00 00 00 00 00 00 00 00 bd 00 00 00 57 1d 3f 18 ............W.?. +1ef0 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1f00 bd 00 00 00 67 1d 3f 18 04 00 00 32 20 00 00 00 ....g.?....2 ... +1f10 00 00 00 00 00 00 00 00 be 00 00 00 6b 1d 03 18 ............k... +1f20 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +1f30 be 00 00 00 6b 1d 3b 18 04 00 00 32 22 00 00 00 ....k.;....2"... +1f40 00 00 00 00 00 00 00 00 b6 00 00 00 0f 1d 0b 18 ................ +1f50 04 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1f60 b8 00 00 00 0f 1d 0b 18 10 00 02 32 20 00 00 00 ...........2 ... +1f70 00 00 00 00 00 00 00 00 be 00 00 00 77 1d 0b 18 ............w... +1f80 04 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1f90 c0 00 00 00 6f 1d 0b 18 04 00 01 32 20 00 00 00 ....o......2 ... +1fa0 00 00 00 00 35 00 00 00 ff 00 00 00 3b 1d 4b 18 ....5.......;.K. +1fb0 00 00 00 00 20 00 00 00 00 00 00 94 01 01 00 00 .... ........... +1fc0 ad 00 00 00 14 1d 3d 18 05 00 07 32 32 20 00 00 ......=....22 .. +1fd0 00 14 00 06 00 00 00 00 bb 00 00 00 eb 1d 2f 18 ............../. +1fe0 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +1ff0 0d 01 00 00 cb 1d 2b 18 04 00 00 32 20 00 00 00 ......+....2 ... +2000 77 66 55 00 33 00 00 00 1a 01 00 00 ad 1d 23 18 wfU.3.........#. +2010 04 00 00 0e 30 00 00 00 17 14 00 1c 00 00 00 00 ....0........... +2020 e3 00 00 00 c3 1d 4f 18 00 00 00 32 20 00 00 00 ......O....2 ... +2030 00 00 00 00 07 10 13 01 ae 00 02 01 d7 1d 1f 18 ................ +2040 0c 00 00 32 20 21 00 00 00 00 00 19 00 00 00 00 ...2 !.......... +2050 b0 00 00 00 db 1d 23 18 04 00 02 32 20 00 00 00 ......#....2 ... +2060 00 00 00 00 02 00 00 00 0d 01 00 00 eb 1d 2b 18 ..............+. +2070 04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +2080 0d 01 00 00 ab 1d 2b 18 04 00 00 32 20 00 00 00 ......+....2 ... +2090 77 66 55 00 00 00 00 00 0d 01 00 00 8b 1d 2b 18 wfU...........+. +20a0 04 00 00 32 20 00 00 00 77 66 55 00 3f 00 00 00 ...2 ...wfU.?... +20b0 d2 00 00 00 ff 1d 7f 18 00 00 00 32 20 00 00 00 ...........2 ... +20c0 00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d 7f 18 ....?........... +20d0 00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 ...2 .......?... +20e0 d2 00 00 00 ff 1d 3f 18 00 00 00 32 20 00 00 00 ......?....2 ... +20f0 00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d 3f 18 ....?.........?. +2100 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2110 0d 01 00 00 ab 1d 07 18 04 00 00 32 20 00 00 00 ...........2 ... +2120 77 66 55 00 00 00 00 00 c0 00 00 00 8b 1d 0b 18 wfU............. +2130 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2140 bd 00 00 00 87 1d 0b 18 04 00 00 32 20 00 00 00 ...........2 ... +2150 00 00 00 00 00 00 00 00 bc 00 00 00 8b 1d 07 18 ................ +2160 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +2170 bc 00 00 00 af 1d 07 18 04 00 00 32 22 00 00 00 ...........2"... +2180 00 00 00 00 00 00 00 00 bb 00 00 00 ef 1d 0b 18 ................ +2190 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +21a0 c0 00 00 00 af 1d 0b 18 04 00 00 32 20 00 00 00 ...........2 ... +21b0 00 00 00 00 00 00 00 00 bb 00 00 00 ab 1d 2f 18 ............../. +21c0 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +21d0 c0 00 00 00 ef 1d 2f 18 04 00 00 32 20 00 00 00 ....../....2 ... +21e0 00 00 00 00 00 00 00 00 c0 00 00 00 f3 1d 0b 18 ................ +21f0 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2200 c0 00 00 00 f3 1d 2f 18 04 00 00 32 20 00 00 00 ....../....2 ... +2210 00 00 00 00 00 00 00 00 bc 00 00 00 f3 1d 2b 18 ..............+. +2220 04 00 00 32 22 00 00 00 00 00 00 00 18 00 00 00 ...2"........... +2230 e8 00 00 00 ff 1a 87 18 18 00 00 32 20 00 00 00 ...........2 ... +2240 34 12 34 12 18 00 00 00 e8 00 00 00 7f 1b 85 18 4.4............. +2250 18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 ...2 ...4.4..... +2260 e8 00 00 00 3f 1b 86 18 18 00 00 32 20 00 00 00 ....?......2 ... +2270 34 12 34 12 06 01 00 00 ad 00 00 00 bd 1b b7 18 4.4............. +2280 01 00 03 32 30 20 00 00 00 80 00 17 17 00 00 00 ...20 .......... +2290 16 01 00 00 87 1b 8f 18 08 00 00 32 22 01 00 00 ...........2"... +22a0 00 00 00 65 00 00 00 00 b8 00 00 00 8f 1b f7 18 ...e............ +22b0 00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +22c0 b8 00 00 00 8f 1b ef 18 00 00 02 32 20 00 00 00 ...........2 ... +22d0 00 00 00 00 02 01 00 00 ad 00 00 00 bf 1b 8f 18 ................ +22e0 01 00 02 32 30 20 00 00 00 60 00 0d 06 00 00 00 ...20 ...`...... +22f0 e8 00 00 00 ef 1b ef 18 30 00 00 32 20 00 00 00 ........0..2 ... +2300 34 12 34 12 02 80 21 00 19 01 03 08 d0 1b 8e 18 4.4...!......... +2310 01 00 02 32 20 20 00 00 00 00 00 0c 01 80 1f 00 ...2 .......... +2320 19 01 07 07 c5 1b c3 18 01 00 02 32 20 20 00 00 ...........2 .. +2330 00 00 00 05 00 00 00 00 e6 00 00 00 93 1b d3 18 ................ +2340 00 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 ...("........... +2350 e6 00 00 00 93 1b cb 18 06 00 00 28 22 00 00 00 ...........("... +2360 00 00 00 00 1b 00 00 00 1a 01 00 00 a4 1b 9c 18 ................ +2370 00 00 00 0e 30 00 00 00 54 54 08 1c 00 00 00 00 ....0...TT...... +2380 e6 00 00 00 93 1b bf 18 00 00 00 28 22 00 00 00 ...........("... +2390 00 00 00 00 06 00 00 00 e8 00 00 00 2f 1c ef 18 ............/... +23a0 30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 0..2 ...4.4..... +23b0 0d 01 00 00 23 1d df 18 04 00 00 32 20 00 00 00 ....#......2 ... +23c0 77 66 55 00 00 00 00 00 c0 00 00 00 27 1d 87 18 wfU.........'... +23d0 04 00 05 32 22 00 00 00 00 00 00 00 2f 80 21 00 ...2"......./.!. +23e0 19 01 03 01 22 1d 81 18 05 00 02 32 20 20 00 00 ...."......2 .. +23f0 00 00 00 8e 1f 00 00 00 1a 01 00 00 1b 1d e7 18 ................ +2400 04 00 00 0e 30 00 00 00 35 34 10 1c 00 00 00 00 ....0...54...... +2410 e3 00 00 00 53 1d ef 18 00 00 00 32 20 00 00 00 ....S......2 ... +2420 00 00 00 00 33 01 00 00 ad 00 00 00 13 1d a7 18 ....3........... +2430 05 00 06 32 32 20 00 00 00 22 00 92 01 80 f8 00 ...22 ..."...... +2440 10 01 00 00 03 1d cf 18 04 00 01 32 22 20 00 00 ...........2" .. +2450 00 00 00 04 83 00 00 00 d2 00 00 00 3f 1d ff 18 ............?... +2460 00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 ...2 ........... +2470 d2 00 00 00 3f 1d bf 18 00 00 00 32 20 00 00 00 ....?......2 ... +2480 00 00 00 00 83 00 00 00 d2 00 00 00 7f 1d ff 18 ................ +2490 00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 ...2 ........... +24a0 d2 00 00 00 7f 1d bf 18 00 00 00 32 20 00 00 00 ...........2 ... +24b0 00 00 00 00 83 00 00 00 0d 01 00 00 23 1d ff 18 ............#... +24c0 04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 ...2 ...wfU..... +24d0 0d 01 00 00 23 1d 9f 18 04 00 00 32 20 00 00 00 ....#......2 ... +24e0 77 66 55 00 83 00 00 00 0d 01 00 00 23 1d bf 18 wfU.........#... +24f0 04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 ...2 ...wfU..... +2500 0d 01 00 00 23 1d df 18 04 00 00 32 20 00 00 00 ....#......2 ... +2510 77 66 55 00 2f 00 00 00 ff 00 00 00 3b 1d f5 18 wfU./.......;... +2520 00 00 00 00 20 00 00 00 00 00 00 8d 01 00 00 00 .... ........... +2530 f8 00 00 74 28 1d ce 18 04 00 00 32 20 00 00 00 ...t(......2 ... +2540 00 00 00 00 00 00 00 00 be 00 00 00 27 1d 8f 18 ............'... +2550 04 00 04 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +2560 be 00 00 00 27 1d 97 18 04 00 04 32 22 00 00 00 ....'......2"... +2570 00 00 00 00 00 00 00 00 be 00 00 00 27 1d 9f 18 ............'... +2580 04 00 05 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +2590 bb 00 00 00 27 1d 83 18 04 00 00 32 22 00 00 00 ....'......2"... +25a0 00 00 00 00 3f 00 00 00 d2 00 00 00 ff 1d ff 18 ....?........... +25b0 00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 ...2 .......?... +25c0 d2 00 00 00 bf 1d ff 18 00 00 00 32 20 00 00 00 ...........2 ... +25d0 00 00 00 00 3f 00 00 00 d2 00 00 00 ff 1d bf 18 ....?........... +25e0 00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 ...2 .......?... +25f0 d2 00 00 00 bf 1d bf 18 00 00 00 32 20 00 00 00 ...........2 ... +2600 00 00 00 00 17 80 16 01 dd 00 02 01 8b 1b 05 19 ................ +2610 10 00 03 0a a2 20 00 00 02 00 05 64 01 01 00 00 ..... .....d.... +2620 ad 00 00 00 bd 1b 64 19 01 00 05 32 30 20 00 00 ......d....20 .. +2630 00 e0 00 03 01 00 00 00 ff 00 00 00 8b 1b 03 19 ................ +2640 00 00 00 00 20 00 00 00 00 00 00 02 06 00 00 00 .... ........... +2650 e8 00 00 00 ef 1b 2f 19 30 00 00 32 20 00 00 00 ....../.0..2 ... +2660 34 12 34 12 06 00 00 00 e8 00 00 00 ef 1b 6f 19 4.4...........o. +2670 30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 0..2 ...4.4..... +2680 b8 00 00 00 8f 1b 1b 19 00 00 02 32 20 00 00 00 ...........2 ... +2690 00 00 00 00 00 00 00 00 b8 00 00 00 8f 1b 13 19 ................ +26a0 00 00 02 32 20 00 00 00 00 00 00 00 02 00 00 00 ...2 ........... +26b0 eb 00 00 00 9b 1b 07 19 00 00 00 00 a0 00 00 00 ................ +26c0 00 00 00 00 02 00 00 00 eb 00 00 00 bb 1b 07 19 ................ +26d0 00 00 00 00 a0 00 00 00 00 00 00 00 02 00 00 00 ................ +26e0 eb 00 00 00 cb 1b 07 19 00 00 00 00 a0 00 00 00 ................ +26f0 00 00 00 00 02 00 00 00 eb 00 00 00 ab 1b 07 19 ................ +2700 00 00 00 00 a0 00 00 00 00 00 00 00 02 00 00 00 ................ +2710 eb 00 00 00 db 1b 07 19 00 00 00 00 a0 00 00 00 ................ +2720 00 00 00 00 02 00 00 00 eb 00 00 00 eb 1b 07 19 ................ +2730 00 00 00 00 a0 00 00 00 00 00 00 00 02 00 00 00 ................ +2740 eb 00 00 00 fb 1b 07 19 00 00 00 00 a0 00 00 00 ................ +2750 00 00 00 00 00 00 00 00 e6 00 00 00 97 1b 43 19 ..............C. +2760 00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +2770 e6 00 00 00 a7 1b 43 19 00 00 00 28 20 00 00 00 ......C....( ... +2780 00 00 00 00 00 00 00 00 e6 00 00 00 97 1b 43 19 ..............C. +2790 06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +27a0 e6 00 00 00 a7 1b 43 19 06 00 00 28 20 00 00 00 ......C....( ... +27b0 00 00 00 00 00 00 00 00 e6 00 00 00 a7 1b 43 19 ..............C. +27c0 0c 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +27d0 bf 00 00 00 e7 1b 3f 19 00 00 00 32 20 00 00 00 ......?....2 ... +27e0 00 00 00 00 00 00 00 00 bf 00 00 00 d7 1b 3f 19 ..............?. +27f0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2800 bf 00 00 00 ef 1b 3f 19 08 54 00 32 20 00 00 00 ......?..T.2 ... +2810 00 00 00 00 00 00 00 00 bf 00 00 00 df 1b 3f 19 ..............?. +2820 08 55 00 32 20 00 00 00 00 00 00 00 06 00 00 00 .U.2 ........... +2830 e8 00 00 00 cf 1b 6b 19 1a 00 00 32 20 00 00 00 ......k....2 ... +2840 34 12 34 12 06 00 00 00 e8 00 00 00 2f 1c 2f 19 4.4........././. +2850 30 00 00 32 20 00 00 00 34 12 34 12 06 00 00 00 0..2 ...4.4..... +2860 e8 00 00 00 2f 1c 6f 19 30 00 00 32 20 00 00 00 ..../.o.0..2 ... +2870 34 12 34 12 0b 80 16 01 dc 00 02 01 8b 1c 0b 19 4.4............. +2880 14 00 00 0a a0 20 00 00 00 00 00 2f 1b 00 00 00 ..... ...../.... +2890 1e 01 00 00 d7 1c 57 19 06 00 00 32 22 00 00 00 ......W....2"... +28a0 00 00 00 00 00 00 00 00 b8 00 00 00 c3 1c 53 19 ..............S. +28b0 08 00 06 32 20 00 00 00 00 00 00 00 1b 00 00 00 ...2 ........... +28c0 18 01 89 06 cf 1c 23 19 04 00 00 32 20 00 00 00 ......#....2 ... +28d0 06 00 24 74 00 00 00 00 de 00 00 00 f3 1c 13 19 ..$t............ +28e0 04 00 00 32 20 20 00 00 00 00 00 00 00 00 00 00 ...2 .......... +28f0 de 00 00 00 d3 1c 13 19 04 00 00 32 20 20 00 00 ...........2 .. +2900 00 00 00 00 00 00 00 00 de 00 00 00 b3 1c 13 19 ................ +2910 04 00 00 32 20 20 00 00 00 00 00 00 00 00 00 00 ...2 .......... +2920 b0 00 00 00 af 1c 77 19 06 00 02 32 20 00 00 00 ......w....2 ... +2930 00 00 00 00 00 00 00 00 b0 00 00 00 b3 1c 7b 19 ..............{. +2940 0e 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2950 b0 00 00 00 b3 1c 53 19 0e 00 00 32 20 00 00 00 ......S....2 ... +2960 00 00 00 00 00 00 00 00 b4 00 00 00 af 1c 6b 19 ..............k. +2970 10 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +2980 b0 00 00 00 b3 1c 53 19 06 00 04 32 22 00 00 00 ......S....2"... +2990 00 00 00 00 20 81 00 00 ad 00 00 00 db 1c 77 19 .... .........w. +29a0 05 00 01 32 30 20 00 00 00 40 00 85 33 00 00 00 ...20 ...@..3... +29b0 1a 01 00 00 c7 1c 63 19 04 00 00 0e 30 00 00 00 ......c.....0... +29c0 35 34 10 1d 00 00 00 00 2b 01 00 80 9b 1c 57 19 54......+.....W. +29d0 04 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +29e0 c3 00 00 00 fb 1c 4b 19 00 00 00 28 a0 00 00 00 ......K....(.... +29f0 00 00 00 00 00 00 00 00 c3 00 00 00 ff 1c 5f 19 .............._. +2a00 00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +2a10 bb 00 00 00 27 1d 1f 19 04 00 00 32 22 00 00 00 ....'......2"... +2a20 00 00 00 00 2f 01 00 00 ad 00 00 00 04 1d 2b 19 ..../.........+. +2a30 05 00 07 32 32 20 00 00 00 13 00 8c 00 00 00 00 ...22 .......... +2a40 bc 00 00 00 23 1d 43 19 04 00 00 32 20 00 00 00 ....#.C....2 ... +2a50 00 00 00 00 00 00 00 00 bc 00 00 00 27 1d 3f 19 ............'.?. +2a60 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +2a70 bd 00 00 00 73 1d 7f 19 04 00 00 32 20 00 00 00 ....s......2 ... +2a80 00 00 00 00 1b 01 00 00 ad 00 00 00 13 1d 07 19 ................ +2a90 05 00 06 32 32 20 00 00 00 22 00 73 00 00 00 00 ...22 ...".s.... +2aa0 c0 00 00 00 03 1d 7f 19 04 00 00 32 20 00 00 00 ...........2 ... +2ab0 00 00 00 00 00 00 00 00 e3 00 00 00 23 1d 5f 19 ............#._. +2ac0 00 00 00 32 20 00 00 00 00 00 00 00 82 00 00 00 ...2 ........... +2ad0 d2 00 00 00 7f 1d 3f 19 00 00 00 32 20 00 00 00 ......?....2 ... +2ae0 00 00 00 00 82 00 00 00 d2 00 00 00 7f 1d 7f 19 ................ +2af0 00 00 00 32 20 00 00 00 00 00 00 00 82 00 00 00 ...2 ........... +2b00 d2 00 00 00 43 1d 3f 19 00 00 00 32 20 00 00 00 ....C.?....2 ... +2b10 00 00 00 00 82 00 00 00 d2 00 00 00 43 1d 7f 19 ............C... +2b20 00 00 00 32 20 00 00 00 00 00 00 00 82 00 00 00 ...2 ........... +2b30 0d 01 00 00 23 1d 3b 19 04 00 00 32 20 00 00 00 ....#.;....2 ... +2b40 77 66 55 00 82 00 00 00 0d 01 00 00 23 1d 17 19 wfU.........#... +2b50 04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +2b60 bc 00 00 00 03 1d 7b 19 04 00 00 32 22 00 00 00 ......{....2"... +2b70 00 00 00 00 00 00 00 00 bd 00 00 00 03 1d 5b 19 ..............[. +2b80 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +2b90 be 00 00 00 03 1d 4b 19 04 00 00 32 22 00 00 00 ......K....2"... +2ba0 00 00 00 00 00 00 00 00 bc 00 00 00 23 1d 7f 19 ............#... +2bb0 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2bc0 bb 00 00 00 63 1d 7f 19 04 00 00 32 20 00 00 00 ....c......2 ... +2bd0 00 00 00 00 00 00 00 00 c0 00 00 00 03 1d 43 19 ..............C. +2be0 04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2bf0 d2 00 00 00 bf 1d 3f 19 00 00 00 32 20 00 00 00 ......?....2 ... +2c00 00 00 00 00 00 00 00 00 d2 00 00 00 ff 1d 3f 19 ..............?. +2c10 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2c20 d2 00 00 00 bf 1d 7f 19 00 00 00 32 20 00 00 00 ...........2 ... +2c30 00 00 00 00 00 00 00 00 d2 00 00 00 ff 1d 7f 19 ................ +2c40 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2c50 bd 00 00 00 83 1d 7f 19 04 00 00 32 20 00 00 00 ...........2 ... +2c60 00 00 00 00 00 00 00 00 c7 00 00 00 0f 1b 9f 19 ................ +2c70 0e 00 00 32 a2 00 00 00 02 00 00 02 00 00 00 00 ...2............ +2c80 b7 00 00 00 1f 1b d7 19 00 00 00 32 20 00 00 00 ...........2 ... +2c90 00 00 00 00 00 00 00 00 b8 00 00 00 1f 1b d7 19 ................ +2ca0 08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2cb0 b5 00 00 00 13 1b d7 19 0a 00 00 32 20 00 00 00 ...........2 ... +2cc0 00 00 00 00 00 00 00 00 b0 00 00 00 57 1b f7 19 ............W... +2cd0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2ce0 bc 00 00 00 63 1b a3 19 00 00 00 32 22 00 00 00 ....c......2"... +2cf0 00 00 00 00 00 00 00 00 c0 00 00 00 63 1b a7 19 ............c... +2d00 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2d10 c3 00 00 00 13 1b a3 19 00 00 00 28 a0 00 00 00 ...........(.... +2d20 00 00 00 00 00 00 00 00 c3 00 00 00 19 1b 94 19 ................ +2d30 00 00 00 28 a0 00 00 00 00 00 00 00 1d 00 f4 00 ...(............ +2d40 ba 00 04 00 57 1b 87 19 0a 00 00 32 20 21 00 00 ....W......2 !.. +2d50 00 00 00 78 0b 00 00 00 24 01 00 00 7b 1b 8f 19 ...x....$...{... +2d60 00 00 00 14 20 01 00 00 00 00 00 5d 00 00 00 00 .... ......].... +2d70 e6 00 00 00 33 1b df 19 00 00 00 28 20 00 00 00 ....3......( ... +2d80 00 00 00 00 00 00 00 00 e6 00 00 00 33 1b df 19 ............3... +2d90 06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +2da0 d5 00 00 00 4f 1b d3 19 00 00 00 28 a0 00 00 00 ....O......(.... +2db0 00 00 00 00 00 00 00 00 c3 00 00 00 3f 1b db 19 ............?... +2dc0 00 00 00 28 a0 00 00 00 00 00 00 00 05 00 00 00 ...(............ +2dd0 e8 00 00 00 47 1b ff 19 1a 00 00 32 20 00 00 00 ....G......2 ... +2de0 34 12 34 12 00 00 00 00 2b 01 00 00 47 1b 97 19 4.4.....+...G... +2df0 00 00 00 28 a0 00 00 00 00 00 00 00 05 00 00 00 ...(............ +2e00 e8 00 00 00 47 1b c7 19 1a 00 00 32 20 00 00 00 ....G......2 ... +2e10 34 12 34 12 1d 00 00 00 f4 00 00 00 ff 1b d3 19 4.4............. +2e20 00 00 00 32 22 00 00 00 00 00 00 00 05 00 00 00 ...2"........... +2e30 1a 01 00 00 a7 1b af 19 00 00 00 0e 30 00 00 00 ............0... +2e40 35 34 10 1c 05 00 00 00 1a 01 00 00 eb 1b b7 19 54.............. +2e50 00 00 00 0e 30 00 00 00 31 34 08 1c 06 80 00 00 ....0...14...... +2e60 cc 00 00 00 ea 1b 94 19 00 00 00 32 20 00 00 00 ...........2 ... +2e70 06 0a 01 06 05 80 00 00 cc 00 00 00 e2 1b 94 19 ................ +2e80 00 00 00 32 20 00 00 00 05 0a 01 06 04 80 00 00 ...2 ........... +2e90 cc 00 00 00 d6 1b 94 19 00 00 00 32 20 00 00 00 ...........2 ... +2ea0 04 0a 01 06 03 80 00 00 cc 00 00 00 cc 1b 94 19 ................ +2eb0 00 00 00 32 20 00 00 00 03 0a 01 06 02 80 00 00 ...2 ........... +2ec0 cc 00 00 00 c1 1b 95 19 00 00 00 32 20 00 00 00 ...........2 ... +2ed0 02 0a 01 06 01 80 00 00 cc 00 00 00 b8 1b 95 19 ................ +2ee0 00 00 00 32 20 00 00 00 01 0a 01 06 00 00 00 00 ...2 ........... +2ef0 c0 00 00 00 a3 1b 97 19 00 00 00 32 20 00 00 00 ...........2 ... +2f00 00 00 00 00 00 00 00 00 bd 00 00 00 a3 1b 93 19 ................ +2f10 00 00 00 32 22 00 00 00 00 00 00 00 1d 00 00 00 ...2"........... +2f20 f4 00 00 00 ff 1b bb 19 00 00 00 32 22 00 00 00 ...........2"... +2f30 00 00 00 00 01 00 00 00 15 01 00 00 97 1b 94 19 ................ +2f40 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +2f50 b0 00 00 00 c3 1b f3 19 00 00 00 32 20 00 00 00 ...........2 ... +2f60 00 00 00 00 06 00 ac 00 ec 00 06 01 af 1b 87 19 ................ +2f70 0e 00 00 32 20 21 00 00 00 00 00 16 06 00 e8 00 ...2 !.......... +2f80 ac 00 04 00 cf 1b 83 19 00 00 00 4b 20 00 00 00 ...........K ... +2f90 00 00 00 15 05 00 00 00 e8 00 00 00 87 1b ff 19 ................ +2fa0 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 ...2 ...4.4..... +2fb0 e8 00 00 00 c7 1b ff 19 1a 00 00 32 20 00 00 00 ...........2 ... +2fc0 34 12 34 12 05 00 00 00 e8 00 00 00 87 1b c7 19 4.4............. +2fd0 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 ...2 ...4.4..... +2fe0 e8 00 00 00 c7 1b c7 19 1a 00 00 32 20 00 00 00 ...........2 ... +2ff0 34 12 34 12 05 00 00 00 e8 00 00 00 ff 1b c7 19 4.4............. +3000 1a 00 00 32 20 00 00 00 34 12 34 12 ff 00 00 00 ...2 ...4.4..... +3010 1a 01 00 00 85 1b d3 19 00 00 00 0e 30 00 00 00 ............0... +3020 31 34 40 1c 22 80 00 00 27 01 01 00 80 1b d4 19 14@."...'....... +3030 00 00 00 32 00 20 00 00 00 00 00 89 22 01 00 00 ...2. ......"... +3040 ad 00 00 00 cb 1b a7 19 01 00 0c 32 32 20 00 00 ...........22 .. +3050 00 44 00 88 06 00 00 00 e8 00 00 00 ef 1b af 19 .D.............. +3060 30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 0..2 ...4.4..... +3070 d1 00 00 00 77 1c 93 19 18 00 00 32 20 00 00 00 ....w......2 ... +3080 00 00 00 00 00 00 00 00 d1 00 00 00 67 1c 93 19 ............g... +3090 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +30a0 d1 00 00 00 0f 1c 93 19 18 00 00 32 20 00 00 00 ...........2 ... +30b0 00 00 00 00 00 00 00 00 d1 00 00 00 1f 1c 93 19 ................ +30c0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +30d0 d1 00 00 00 2f 1c 93 19 18 00 00 32 20 00 00 00 ..../......2 ... +30e0 00 00 00 00 00 00 00 00 d1 00 00 00 53 1c 93 19 ............S... +30f0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3100 d1 00 00 00 43 1c 93 19 18 00 00 32 20 00 00 00 ....C......2 ... +3110 00 00 00 00 0b 00 00 00 f4 00 00 00 7f 1c df 19 ................ +3120 00 00 00 32 22 00 00 00 00 00 00 00 1d 00 f4 00 ...2"........... +3130 ba 00 03 00 0f 1c 9b 19 0a 00 00 32 20 21 00 00 ...........2 !.. +3140 00 00 00 77 1e 01 00 00 ad 00 00 00 77 1c c7 19 ...w........w... +3150 01 00 02 32 32 20 00 00 00 06 00 79 0b 00 f4 00 ...22 .....y.... +3160 f3 00 04 00 5b 1c 9b 19 0f 00 01 32 20 21 00 00 ....[......2 !.. +3170 00 00 00 2e 05 00 00 00 e8 00 00 00 03 1c ff 19 ................ +3180 1a 00 00 32 20 00 00 00 34 12 34 12 06 00 00 00 ...2 ...4.4..... +3190 e8 00 00 00 03 1c 83 19 1a 00 00 32 20 00 00 00 ...........2 ... +31a0 34 12 34 12 0b 00 00 00 f4 00 00 00 7f 1c c7 19 4.4............. +31b0 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +31c0 c0 00 00 00 cb 1c 83 19 04 00 00 32 20 00 00 00 ...........2 ... +31d0 00 00 00 00 00 00 00 00 bf 00 00 00 cb 1c b7 19 ................ +31e0 08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +31f0 bf 00 00 00 bb 1c b7 19 08 55 00 32 20 00 00 00 .........U.2 ... +3200 00 00 00 00 00 00 00 00 bf 00 00 00 bb 1c bf 19 ................ +3210 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3220 bf 00 00 00 cb 1c bf 19 00 00 00 32 20 00 00 00 ...........2 ... +3230 00 00 00 00 00 00 00 00 bf 00 00 00 bb 1c af 19 ................ +3240 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3250 bf 00 00 00 cb 1c af 19 00 00 00 32 20 00 00 00 ...........2 ... +3260 00 00 00 00 1b 01 00 00 ad 00 00 00 bb 1c c5 19 ................ +3270 01 00 02 32 32 20 00 00 00 06 00 72 0b 00 00 00 ...22 .....r.... +3280 16 01 00 00 9b 1c a3 19 0e 00 00 32 20 01 00 00 ...........2 ... +3290 00 00 00 2d 00 00 00 00 b3 00 00 00 9f 1c a3 19 ...-............ +32a0 16 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +32b0 be 00 00 00 cb 1c 93 19 04 00 00 32 22 00 00 00 ...........2"... +32c0 00 00 00 00 00 00 00 00 be 00 00 00 cb 1c 8b 19 ................ +32d0 04 00 00 32 22 00 00 00 00 00 00 00 ff 00 00 00 ...2"........... +32e0 1a 01 00 00 bf 1c 8f 19 04 00 00 0e 30 00 00 00 ............0... +32f0 52 54 08 1d 00 00 00 00 be 00 00 00 cb 1c 9b 19 RT.............. +3300 04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3310 2b 01 00 80 53 1d d7 19 04 00 00 28 a2 00 00 00 +...S......(.... +3320 00 00 00 00 00 00 00 00 c3 00 00 00 63 1d df 19 ............c... +3330 00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +3340 e6 00 00 00 13 1d 8f 19 00 00 00 28 20 00 00 00 ...........( ... +3350 00 00 00 00 00 00 00 00 e6 00 00 00 23 1d 8f 19 ............#... +3360 00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +3370 e6 00 00 00 33 1d 8f 19 00 00 00 28 20 00 00 00 ....3......( ... +3380 00 00 00 00 00 00 00 00 e6 00 00 00 33 1d 8f 19 ............3... +3390 06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +33a0 e6 00 00 00 23 1d 8f 19 06 00 00 28 20 00 00 00 ....#......( ... +33b0 00 00 00 00 00 00 00 00 e6 00 00 00 13 1d 8f 19 ................ +33c0 06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +33d0 e6 00 00 00 13 1d 8f 19 0c 00 00 28 20 00 00 00 ...........( ... +33e0 00 00 00 00 00 00 00 00 e6 00 00 00 23 1d 8f 19 ............#... +33f0 0c 00 00 28 20 00 00 00 00 00 00 00 05 00 e8 00 ...( ........... +3400 ac 00 04 00 4b 1b 7f 1a 00 00 00 4b 20 00 00 00 ....K......K ... +3410 00 00 00 14 00 00 00 00 b9 00 00 00 57 1b 3f 1a ............W.?. +3420 00 00 00 32 20 00 00 00 00 00 00 00 05 01 00 00 ...2 ........... +3430 ad 00 00 00 37 1b 71 1a 01 00 06 32 32 20 00 00 ....7.q....22 .. +3440 00 22 00 13 05 00 00 00 1a 01 00 00 76 1b 38 1a ."..........v.8. +3450 00 00 00 0e 30 00 00 00 51 54 00 1c 00 00 00 00 ....0...QT...... +3460 b4 00 00 00 53 1b 0f 1a 02 00 00 32 22 00 00 00 ....S......2"... +3470 00 00 00 00 00 00 00 00 b0 00 00 00 57 1b 1f 1a ............W... +3480 08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3490 b0 00 00 00 57 1b 1f 1a 00 00 02 32 20 00 00 00 ....W......2 ... +34a0 00 00 00 00 01 00 00 00 15 01 00 00 13 1b 53 1a ..............S. +34b0 00 00 00 32 22 00 00 00 00 00 00 00 05 00 00 00 ...2"........... +34c0 e8 00 00 00 47 1b 7f 1a 1a 00 00 32 20 00 00 00 ....G......2 ... +34d0 34 12 34 12 05 00 00 00 e8 00 00 00 47 1b 3f 1a 4.4.........G.?. +34e0 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 ...2 ...4.4..... +34f0 e8 00 00 00 07 1b 7f 1a 1a 00 00 32 20 00 00 00 ...........2 ... +3500 34 12 34 12 05 00 00 00 e8 00 00 00 07 1b 3f 1a 4.4...........?. +3510 1a 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 ...2 ...4.4..... +3520 b0 00 00 00 c7 1b 1f 1a 08 00 02 32 20 00 00 00 ...........2 ... +3530 00 00 00 00 00 00 00 00 b4 00 00 00 bf 1b 0b 1a ................ +3540 02 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3550 b0 00 00 00 c3 1b 1b 1a 00 00 02 32 20 00 00 00 ...........2 ... +3560 00 00 00 00 00 00 00 00 d7 00 00 00 a3 1b 3f 1a ..............?. +3570 00 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3580 d7 00 00 00 c7 1b 3f 1a 00 00 00 32 20 00 00 00 ......?....2 ... +3590 00 00 00 00 05 00 00 00 e8 00 00 00 87 1b 7f 1a ................ +35a0 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 ...2 ...4.4..... +35b0 e8 00 00 00 c7 1b 7f 1a 1a 00 00 32 20 00 00 00 ...........2 ... +35c0 34 12 34 12 05 00 00 00 e8 00 00 00 ff 1b 7f 1a 4.4............. +35d0 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 ...2 ...4.4..... +35e0 e8 00 00 00 87 1b 3f 1a 1a 00 00 32 20 00 00 00 ......?....2 ... +35f0 34 12 34 12 05 00 00 00 e8 00 00 00 c7 1b 3f 1a 4.4...........?. +3600 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 ...2 ...4.4..... +3610 e8 00 00 00 ff 1b 3f 1a 1a 00 00 32 20 00 00 00 ......?....2 ... +3620 34 12 34 12 0e 00 00 00 e8 00 00 00 47 1b c3 1a 4.4.........G... +3630 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 1a 01 ...2 ...4.4..... +3640 1d 01 02 00 11 1b a6 1a 00 00 00 4b 20 00 00 00 ...........K ... +3650 00 00 00 12 05 00 ac 00 c2 00 06 01 58 1b 83 1a ............X... +3660 0b 00 00 32 20 21 00 00 00 00 00 11 10 80 00 00 ...2 !.......... +3670 e1 00 00 00 67 1b fb 1a 0e 00 00 32 20 00 00 00 ....g......2 ... +3680 00 00 00 4c 10 80 00 00 e2 00 00 00 47 1b fb 1a ...L........G... +3690 0e 00 00 32 20 00 00 00 00 00 00 4b 0e 00 00 00 ...2 ......K.... +36a0 1a 01 00 00 5b 1b ab 1a 00 00 00 0e 30 00 00 00 ....[.......0... +36b0 55 54 08 1c 0e 00 00 00 1a 01 00 00 20 1b ca 1a UT.......... ... +36c0 00 00 00 0e 30 00 00 00 53 54 00 1c 0f 00 00 00 ....0...ST...... +36d0 1a 01 00 00 43 1b b3 1a 00 00 00 0e 30 00 00 00 ....C.......0... +36e0 53 54 00 1c 13 00 00 00 bf 00 00 00 23 1b ef 1a ST..........#... +36f0 08 56 00 32 20 00 00 00 00 00 00 00 13 00 00 00 .V.2 ........... +3700 bf 00 00 00 13 1b ef 1a 08 55 00 32 20 00 00 00 .........U.2 ... +3710 00 00 00 00 00 00 00 00 bf 00 00 00 23 1b ef 1a ............#... +3720 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3730 bf 00 00 00 13 1b ef 1a 00 00 00 32 20 00 00 00 ...........2 ... +3740 00 00 00 00 12 00 00 00 bf 00 00 00 7b 1b db 1a ............{... +3750 00 00 00 32 20 00 00 00 00 00 00 00 12 00 00 00 ...2 ........... +3760 bf 00 00 00 67 1b e3 1a 00 00 00 32 20 00 00 00 ....g......2 ... +3770 00 00 00 00 00 00 00 00 bf 00 00 00 67 1b d3 1a ............g... +3780 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3790 bf 00 00 00 6b 1b df 1a 08 54 00 32 20 00 00 00 ....k....T.2 ... +37a0 00 00 00 00 05 00 00 00 e8 00 00 00 c3 1b 83 1a ................ +37b0 1a 00 00 32 20 00 00 00 34 12 34 12 0e 00 00 00 ...2 ...4.4..... +37c0 e8 00 00 00 83 1b c3 1a 1a 00 00 32 20 00 00 00 ...........2 ... +37d0 34 12 34 12 05 00 00 00 e8 00 00 00 03 1c 83 1a 4.4............. +37e0 1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 ...2 ...4.4..... +37f0 e8 00 00 00 3f 1c 83 1a 1a 00 00 32 20 00 00 00 ....?......2 ... +3800 34 12 34 12 20 00 00 00 e0 00 00 00 ea 1a 7a 1b 4.4. .........z. +3810 08 00 00 ff a0 00 00 00 04 00 01 01 0e 00 00 00 ................ +3820 e8 00 00 00 47 1b 03 1b 1a 00 00 32 20 00 00 00 ....G......2 ... +3830 34 12 34 12 0e 00 00 00 e8 00 00 00 47 1b 43 1b 4.4.........G.C. +3840 1a 00 00 32 20 00 00 00 34 12 34 12 10 00 ff 07 ...2 ...4.4..... +3850 ba 00 04 00 07 1b 17 1b 0a 00 00 32 22 21 00 00 ...........2"!.. +3860 00 00 00 4a 0e 01 00 00 ad 00 00 00 28 1b 52 1b ...J........(.R. +3870 01 00 09 32 30 20 00 00 00 82 00 46 00 00 00 00 ...20 .....F.... +3880 2c 01 00 00 47 1b 4b 1b 00 00 00 32 20 00 00 00 ,...G.K....2 ... +3890 00 00 00 00 00 00 00 00 2c 01 00 00 47 1b 4b 1b ........,...G.K. +38a0 06 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +38b0 2c 01 00 00 37 1b 4b 1b 00 00 00 32 20 00 00 00 ,...7.K....2 ... +38c0 00 00 00 00 00 00 00 00 2c 01 00 00 37 1b 4b 1b ........,...7.K. +38d0 06 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +38e0 2c 01 00 00 47 1b 4b 1b 0c 00 00 32 20 00 00 00 ,...G.K....2 ... +38f0 00 00 00 00 00 00 00 00 2c 01 00 00 37 1b 4b 1b ........,...7.K. +3900 0c 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3910 2c 01 00 00 57 1b 4b 1b 00 00 00 32 20 00 00 00 ,...W.K....2 ... +3920 00 00 00 00 00 00 00 00 2c 01 00 00 57 1b 4b 1b ........,...W.K. +3930 06 00 00 32 20 00 00 00 00 00 00 00 0e 00 00 00 ...2 ........... +3940 e8 00 00 00 83 1b 43 1b 1a 00 00 32 20 00 00 00 ......C....2 ... +3950 34 12 34 12 0e 00 00 00 e8 00 00 00 83 1b 03 1b 4.4............. +3960 1a 00 00 32 20 00 00 00 34 12 34 12 20 00 00 00 ...2 ...4.4. ... +3970 e8 00 00 00 c3 1a 83 1b 1a 00 00 32 20 00 00 00 ...........2 ... +3980 34 12 34 12 20 00 e8 00 db 00 04 00 df 1a 83 1b 4.4. ........... +3990 00 00 00 4b 20 00 00 00 00 00 00 84 20 00 e8 00 ...K ....... ... +39a0 db 00 04 00 ff 1a 83 1b 00 00 00 4b 20 00 00 00 ...........K ... +39b0 00 00 00 83 3a 00 00 00 2a 01 00 00 97 1a bb 1b ....:...*....... +39c0 06 00 00 32 20 01 00 00 1f 00 aa aa 40 00 00 00 ...2 .......@... +39d0 1a 01 00 00 f8 1a 99 1b 00 00 00 0e 30 00 00 00 ............0... +39e0 55 54 08 1c 20 00 00 00 29 01 00 00 d3 1a 8f 1b UT.. ...)....... +39f0 00 00 00 32 20 00 00 00 00 00 00 82 00 00 00 00 ...2 ........... +3a00 da 00 00 00 9b 1a d3 1b 06 00 00 32 22 00 00 00 ...........2"... +3a10 00 00 00 00 00 00 00 00 c6 00 00 00 8f 1a cf 1b ................ +3a20 06 00 00 32 22 21 00 00 00 00 00 00 00 00 00 00 ...2"!.......... +3a30 d1 00 00 00 9b 1a af 1b 18 00 00 32 20 00 00 00 ...........2 ... +3a40 00 00 00 00 00 00 00 00 b0 00 00 00 9b 1a 9b 1b ................ +3a50 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3a60 b0 00 00 00 9b 1a 9b 1b 08 00 00 32 20 00 00 00 ...........2 ... +3a70 00 00 00 00 00 00 00 00 b0 00 00 00 9b 1a 9b 1b ................ +3a80 10 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3a90 b0 00 00 00 9b 1a f3 1b 00 00 00 32 20 00 00 00 ...........2 ... +3aa0 00 00 00 00 00 00 00 00 b0 00 00 00 9b 1a f3 1b ................ +3ab0 08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3ac0 b0 00 00 00 ab 1a f3 1b 00 00 02 32 20 00 00 00 ...........2 ... +3ad0 00 00 00 00 00 00 00 00 b7 00 00 00 b7 1a ef 1b ................ +3ae0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3af0 b4 00 00 00 b3 1a 97 1b 02 00 01 32 20 00 00 00 ...........2 ... +3b00 00 00 00 00 00 00 00 00 b0 00 00 00 c3 1a 9b 1b ................ +3b10 00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3b20 b0 00 00 00 c7 1a 9f 1b 08 00 00 32 20 00 00 00 ...........2 ... +3b30 00 00 00 00 00 00 00 00 b8 00 00 00 c3 1a ab 1b ................ +3b40 08 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3b50 b7 00 00 00 c3 1a ab 1b 00 00 00 32 20 00 00 00 ...........2 ... +3b60 00 00 00 00 00 00 00 00 b6 00 00 00 ab 1a af 1b ................ +3b70 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3b80 b8 00 00 00 af 1a b3 1b 0e 00 02 32 22 00 00 00 ...........2"... +3b90 00 00 00 00 00 00 00 00 b3 00 00 00 bf 1a 87 1b ................ +3ba0 0e 00 00 32 20 00 00 00 00 00 00 00 0f 00 00 00 ...2 ........... +3bb0 e8 00 00 00 bf 1a f3 1b 30 00 00 32 20 00 00 00 ........0..2 ... +3bc0 34 12 34 12 0f 00 00 00 e8 00 00 00 ff 1a f3 1b 4.4............. +3bd0 30 00 00 32 20 00 00 00 34 12 34 12 20 00 00 00 0..2 ...4.4. ... +3be0 e8 00 00 00 03 1b 83 1b 1a 00 00 32 20 00 00 00 ...........2 ... +3bf0 34 12 34 12 41 00 00 00 1a 01 00 00 1c 1b a6 1b 4.4.A........... +3c00 00 00 00 0e 30 00 00 00 56 54 10 1c 0e 00 ac 00 ....0...VT...... +3c10 ba 00 06 01 0b 1b 87 1b 0a 00 00 32 20 21 00 00 ...........2 !.. +3c20 00 00 00 45 0e 00 00 00 e8 00 00 00 47 1b 83 1b ...E........G... +3c30 1a 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 ...2 ...4.4..... +3c40 b8 00 00 00 27 1b d7 1b 08 00 03 32 22 00 00 00 ....'......2"... +3c50 00 00 00 00 00 00 00 00 af 00 00 00 5b 1b f3 1b ............[... +3c60 00 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3c70 af 00 00 00 4f 1b 87 1b 00 00 01 32 20 00 00 00 ....O......2 ... +3c80 00 00 00 00 00 00 00 00 b2 00 00 00 4f 1b cf 1b ............O... +3c90 02 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3ca0 b0 00 00 00 5f 1b e7 1b 00 00 02 32 20 00 00 00 ...._......2 ... +3cb0 00 00 00 00 00 00 00 00 b0 00 00 00 63 1b e7 1b ............c... +3cc0 08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3cd0 b8 00 00 00 1f 1b 8f 1b 0e 00 02 32 22 00 00 00 ...........2"... +3ce0 00 00 00 00 0e 00 e8 00 ac 00 04 00 3b 1b 83 1b ............;... +3cf0 00 00 00 4b 20 00 00 00 00 00 00 44 00 00 00 00 ...K ......D.... +3d00 bd 00 00 00 1f 1b f7 1b 00 00 00 32 22 00 00 00 ...........2"... +3d10 00 00 00 00 00 00 00 00 bd 00 00 00 2b 1b f7 1b ............+... +3d20 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3d30 be 00 00 00 1f 1b e7 1b 00 00 00 32 22 00 00 00 ...........2"... +3d40 00 00 00 00 00 00 00 00 be 00 00 00 2b 1b e7 1b ............+... +3d50 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3d60 c0 00 00 00 1f 1b df 1b 00 00 00 32 20 00 00 00 ...........2 ... +3d70 00 00 00 00 00 00 00 00 c0 00 00 00 2b 1b df 1b ............+... +3d80 00 00 00 32 20 00 00 00 00 00 00 00 0e 00 1a 01 ...2 ........... +3d90 1d 01 02 00 50 1b 8b 1b 0a 00 00 4b 20 00 00 00 ....P......K ... +3da0 00 00 00 43 00 00 00 00 b6 00 00 00 1b 1b 8b 1b ...C............ +3db0 00 00 01 32 20 00 00 00 00 00 00 00 1c 00 00 00 ...2 ........... +3dc0 1e 01 00 00 3b 1b 97 1b 00 00 00 32 22 00 00 00 ....;......2"... +3dd0 00 00 00 00 00 00 00 00 b7 00 00 00 27 1b d3 1b ............'... +3de0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3df0 af 00 00 00 4f 1b ab 1b 00 00 01 32 20 00 00 00 ....O......2 ... +3e00 00 00 00 00 00 00 00 00 b8 00 00 00 4c 1b b8 1b ............L... +3e10 00 00 02 32 22 00 00 00 00 00 00 00 0e 00 00 00 ...2"........... +3e20 e8 00 00 00 83 1b 83 1b 1a 00 00 32 20 00 00 00 ...........2 ... +3e30 34 12 34 12 21 00 e8 00 ac 00 04 00 43 1a 77 1c 4.4.!.......C.w. +3e40 18 00 00 4b 20 00 00 00 00 00 00 87 01 00 00 00 ...K ........... +3e50 ff 00 00 00 43 1a 43 1c 18 00 00 00 20 00 00 00 ....C.C..... ... +3e60 00 00 00 01 16 81 1a 01 19 01 02 00 7f 1a 4f 1c ..............O. +3e70 19 00 01 32 20 20 00 00 00 00 00 61 c7 80 00 00 ...2 .....a.... +3e80 19 01 02 02 47 1a 73 1c 19 00 01 32 20 20 00 00 ....G.s....2 .. +3e90 00 00 00 a8 0f 80 ac 00 ba 00 06 01 63 1a 07 1c ............c... +3ea0 22 00 00 32 20 21 00 00 00 00 00 49 0f 00 e8 00 "..2 !.....I.... +3eb0 ac 00 04 00 7f 1a 4b 1c 18 00 00 4b 22 00 00 00 ......K....K"... +3ec0 00 00 00 48 11 00 00 00 11 01 00 00 3b 1a 0b 1c ...H........;... +3ed0 18 00 01 32 20 00 00 00 00 00 00 00 11 00 00 00 ...2 ........... +3ee0 11 01 00 00 33 1a 0b 1c 18 00 00 32 20 00 00 00 ....3......2 ... +3ef0 00 00 00 00 00 00 00 00 11 01 00 00 2b 1a 0b 1c ............+... +3f00 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +3f10 11 01 00 00 43 1a 0b 1c 18 00 00 32 20 00 00 00 ....C......2 ... +3f20 00 00 00 00 0a 00 00 00 c3 00 00 00 23 1a 0f 1c ............#... +3f30 18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +3f40 c3 00 00 00 13 1a 0f 1c 18 00 00 28 a0 00 00 00 ...........(.... +3f50 00 00 00 00 00 00 00 00 11 01 00 00 0b 1a 5f 1c .............._. +3f60 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3f70 11 01 00 00 0b 1a 57 1c 18 00 00 32 22 00 00 00 ......W....2"... +3f80 00 00 00 00 00 00 00 00 11 01 00 00 0b 1a 67 1c ..............g. +3f90 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3fa0 11 01 00 00 0b 1a 4f 1c 18 00 01 32 22 00 00 00 ......O....2"... +3fb0 00 00 00 00 00 00 00 00 11 01 00 00 0b 1a 2f 1c ............../. +3fc0 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +3fd0 11 01 00 00 0b 1a 27 1c 18 00 00 32 22 00 00 00 ......'....2"... +3fe0 00 00 00 00 41 00 00 00 11 01 00 00 0b 1a 1f 1c ....A........... +3ff0 18 00 01 32 22 00 00 00 00 00 00 00 0d 00 00 00 ...2"........... +4000 14 01 00 00 23 1a 7b 1c 24 00 00 32 20 01 00 00 ....#.{.$..2 ... +4010 00 00 00 3d 21 00 00 00 e8 00 00 00 7b 1a 73 1c ...=!.......{.s. +4020 30 00 00 32 20 00 00 00 34 12 34 12 3f 80 16 01 0..2 ...4.4.?... +4030 dc 00 02 01 0b 1a 0b 1c 2a 00 00 0a a0 20 00 00 ........*.... .. +4040 00 00 00 9d 21 00 00 00 1a 01 00 00 1f 1a 5c 1c ....!.........\. +4050 18 00 00 0e 30 00 00 00 53 54 00 1d 21 00 00 00 ....0...ST..!... +4060 1a 01 00 00 41 1a 21 1c 18 00 00 04 30 00 00 00 ....A.!.....0... +4070 01 05 00 08 21 00 00 00 e8 00 00 00 3b 1a 73 1c ....!.......;.s. +4080 30 00 00 32 20 00 00 00 34 12 34 12 21 00 00 00 0..2 ...4.4.!... +4090 e8 00 00 00 3b 1a 37 1c 30 00 00 32 20 00 00 00 ....;.7.0..2 ... +40a0 34 12 34 12 21 00 00 00 e8 00 00 00 7b 1a 33 1c 4.4.!.......{.3. +40b0 30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 0..2 ...4.4..... +40c0 11 01 00 00 4b 1a 0b 1c 18 00 01 32 20 00 00 00 ....K......2 ... +40d0 00 00 00 00 00 00 00 00 11 01 00 00 53 1a 0b 1c ............S... +40e0 18 00 00 32 20 00 00 00 00 00 00 00 21 00 00 00 ...2 .......!... +40f0 e8 00 00 00 7f 1a 73 1c 30 00 00 32 20 00 00 00 ......s.0..2 ... +4100 34 12 34 12 21 00 00 00 e8 00 00 00 7f 1a 33 1c 4.4.!.........3. +4110 30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 0..2 ...4.4..... +4120 e8 00 00 00 fb 1a 6f 1c 30 00 00 32 20 00 00 00 ......o.0..2 ... +4130 34 12 34 12 0f 00 00 00 e8 00 00 00 fb 1a 33 1c 4.4...........3. +4140 30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 0..2 ...4.4..... +4150 e8 00 00 00 bf 1a 7f 1c 30 00 00 32 20 00 00 00 ........0..2 ... +4160 34 12 34 12 20 80 00 00 27 01 01 00 cf 1a 3a 1c 4.4. ...'.....:. +4170 00 00 00 32 00 20 00 00 00 00 00 81 ff 00 00 00 ...2. .......... +4180 1a 01 00 00 cf 1a 43 1c 00 00 00 0e 30 00 00 00 ......C.....0... +4190 31 34 40 1d 00 00 00 00 c0 00 00 00 a3 1a 2f 1c 14@.........../. +41a0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +41b0 bc 00 00 00 c3 1a 53 1c 00 00 00 32 20 00 00 00 ......S....2 ... +41c0 00 00 00 00 00 00 00 00 c0 00 00 00 c7 1a 2f 1c ............../. +41d0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +41e0 bc 00 00 00 c3 1a 2f 1c 00 00 00 32 20 00 00 00 ....../....2 ... +41f0 00 00 00 00 00 00 00 00 d1 00 00 00 93 1a 17 1c ................ +4200 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4210 d1 00 00 00 a3 1a 17 1c 18 00 00 32 20 00 00 00 ...........2 ... +4220 00 00 00 00 00 00 00 00 d1 00 00 00 b3 1a 17 1c ................ +4230 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4240 d1 00 00 00 c3 1a 17 1c 18 00 00 32 20 00 00 00 ...........2 ... +4250 00 00 00 00 00 00 00 00 d1 00 00 00 d3 1a 17 1c ................ +4260 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4270 d1 00 00 00 e3 1a 17 1c 18 00 00 32 20 00 00 00 ...........2 ... +4280 00 00 00 00 00 00 00 00 ed 00 00 00 9f 1a 4b 1c ..............K. +4290 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +42a0 bd 00 00 00 8f 1a 53 1c 18 00 00 32 20 00 00 00 ......S....2 ... +42b0 00 00 00 00 00 00 00 00 bd 00 00 00 9f 1a 2f 1c ............../. +42c0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +42d0 bd 00 00 00 8f 1a 2f 1c 18 00 00 32 20 00 00 00 ....../....2 ... +42e0 00 00 00 00 13 80 00 00 ca 00 00 00 9f 1a 4f 1c ..............O. +42f0 16 00 00 32 20 00 00 00 00 01 00 57 00 00 00 00 ...2 ......W.... +4300 bd 00 00 00 9f 1a 53 1c 18 00 00 32 20 00 00 00 ......S....2 ... +4310 00 00 00 00 0c 00 00 00 be 00 00 00 a3 1a 3f 1c ..............?. +4320 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +4330 be 00 00 00 a3 1a 37 1c 18 00 00 32 22 00 00 00 ......7....2"... +4340 00 00 00 00 00 00 00 00 be 00 00 00 a3 1a 47 1c ..............G. +4350 18 00 00 32 22 00 00 00 00 00 00 00 3f 00 00 00 ...2".......?... +4360 16 01 00 00 83 1a 63 1c 0c 00 00 32 22 01 00 00 ......c....2"... +4370 00 00 00 9c 13 00 00 00 15 01 00 00 bf 1a 2b 1c ..............+. +4380 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4390 be 00 00 00 a3 1a 4f 1c 18 00 00 32 22 00 00 00 ......O....2"... +43a0 00 00 00 00 40 01 00 00 ad 00 00 00 b7 1a 43 1c ....@.........C. +43b0 02 00 07 32 32 20 00 00 00 13 00 9f 00 00 00 00 ...22 .......... +43c0 c0 00 00 00 c7 1a 53 1c 00 00 00 32 20 00 00 00 ......S....2 ... +43d0 00 00 00 00 00 00 00 00 c0 00 00 00 a3 1a 53 1c ..............S. +43e0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +43f0 15 01 00 00 db 1a 2b 1c 00 00 00 32 20 00 00 00 ......+....2 ... +4400 00 00 00 00 00 00 00 00 c3 00 00 00 eb 1a 6b 1c ..............k. +4410 00 00 00 28 a0 00 00 00 00 00 00 00 13 00 ca 00 ...(............ +4420 ba 00 02 00 83 1a 5b 1c 08 00 00 32 22 21 00 00 ......[....2"!.. +4430 00 00 00 55 0f 00 00 00 e8 00 00 00 bf 1a 33 1c ...U..........3. +4440 30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 0..2 ...4.4..... +4450 e8 00 00 00 bf 1a 73 1c 30 00 00 32 20 00 00 00 ......s.0..2 ... +4460 34 12 34 12 40 00 00 00 1a 01 00 00 40 1b 4a 1c 4.4.@.......@.J. +4470 00 00 00 04 30 00 00 00 37 34 00 09 00 00 00 00 ....0...74...... +4480 b0 00 00 00 2b 1b 07 1c 00 00 02 32 20 00 00 00 ....+......2 ... +4490 00 00 00 00 00 00 00 00 b0 00 00 00 5f 1b 37 1c ............_.7. +44a0 00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +44b0 af 00 00 00 5b 1b 17 1c 00 00 01 32 20 00 00 00 ....[......2 ... +44c0 00 00 00 00 00 00 00 00 b5 00 00 00 57 1b 27 1c ............W.'. +44d0 02 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +44e0 b0 00 00 00 1b 1b 07 1c 08 00 00 32 20 00 00 00 ...........2 ... +44f0 00 00 00 00 00 00 00 00 b0 00 00 00 1b 1b 07 1c ................ +4500 00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4510 b8 00 00 00 17 1b 13 1c 08 00 02 32 22 00 00 00 ...........2"... +4520 00 00 00 00 00 00 00 00 b7 00 00 00 17 1b 13 1c ................ +4530 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4540 b0 00 00 00 2b 1b 07 1c 08 00 02 32 22 00 00 00 ....+......2"... +4550 00 00 00 00 3f 00 00 00 b0 00 00 00 2b 1b 17 1c ....?.......+... +4560 00 00 02 32 22 00 00 00 00 00 00 00 1c 10 1e 01 ...2"........... +4570 ae 00 02 01 27 1b 13 1c 08 00 00 32 20 21 00 00 ....'......2 !.. +4580 00 00 00 76 20 00 00 00 ad 00 00 00 1f 1b 28 1c ...v .........(. +4590 01 00 09 32 30 20 00 00 00 72 00 80 0f 00 00 00 ...20 ...r...... +45a0 e8 00 00 00 3b 1b 6f 1c 30 00 00 32 20 00 00 00 ....;.o.0..2 ... +45b0 34 12 34 12 0f 00 00 00 e8 00 00 00 3b 1b 2f 1c 4.4.........;./. +45c0 30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 0..2 ...4.4..... +45d0 e8 00 00 00 7b 1b 6f 1c 30 00 00 32 20 00 00 00 ....{.o.0..2 ... +45e0 34 12 34 12 0f 00 00 00 e8 00 00 00 7b 1b 2f 1c 4.4.........{./. +45f0 30 00 00 32 20 00 00 00 34 12 34 12 1b 00 00 00 0..2 ...4.4..... +4600 24 01 00 00 0f 19 c3 1c 18 00 00 14 22 01 00 00 $..........."... +4610 00 00 00 9d 1a 00 00 00 24 01 00 00 0f 19 d3 1c ........$....... +4620 18 00 00 14 22 01 00 00 00 00 00 1e 11 00 00 00 ...."........... +4630 e8 00 00 00 3f 19 bf 1c 30 00 00 32 20 00 00 00 ....?...0..2 ... +4640 34 12 34 12 11 00 00 00 e8 00 00 00 3f 19 ff 1c 4.4.........?... +4650 30 00 00 32 20 00 00 00 34 12 34 12 ac 00 00 00 0..2 ...4.4..... +4660 1a 01 00 00 23 19 b7 1c 18 00 00 14 30 00 00 00 ....#.......0... +4670 25 24 10 4c 9b 80 ff 07 f1 00 00 00 3f 19 83 1c %$.L........?... +4680 18 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 ...2 ........... +4690 ee 00 00 00 2b 19 9b 1c 18 00 01 32 20 00 00 00 ....+......2 ... +46a0 00 00 00 00 9b 80 ff 07 ee 00 00 00 47 19 9b 1c ............G... +46b0 18 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 ...2 ........... +46c0 ef 00 37 37 3f 19 9f 1c 18 00 00 32 20 00 00 00 ..77?......2 ... +46d0 00 00 00 00 ac 00 00 00 1a 01 00 00 46 19 ca 1c ............F... +46e0 18 00 00 14 30 00 00 00 27 24 00 4c 00 00 00 00 ....0...'$.L.... +46f0 bf 00 00 00 57 19 93 1c 18 00 00 32 20 00 00 00 ....W......2 ... +4700 00 00 00 00 00 00 00 00 bf 00 00 00 23 19 93 1c ............#... +4710 20 54 00 32 20 00 00 00 00 00 00 00 00 00 00 00 T.2 ........... +4720 bf 00 00 00 13 19 93 1c 20 55 00 32 20 00 00 00 ........ U.2 ... +4730 00 00 00 00 9b 80 ff 07 f0 00 00 00 4b 19 9b 1c ............K... +4740 2e 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4750 bf 00 00 00 13 19 93 1c 18 00 00 32 20 00 00 00 ...........2 ... +4760 00 00 00 00 00 00 00 00 bf 00 00 00 23 19 93 1c ............#... +4770 18 00 00 32 20 00 00 00 00 00 00 00 11 00 00 00 ...2 ........... +4780 e8 00 00 00 7f 19 bf 1c 30 00 00 32 20 00 00 00 ........0..2 ... +4790 34 12 34 12 11 00 00 00 e8 00 00 00 7f 19 ff 1c 4.4............. +47a0 30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 0..2 ...4.4..... +47b0 d6 00 00 00 7b 1a c7 1c 18 00 00 32 22 00 00 00 ....{......2"... +47c0 00 00 00 00 00 00 00 00 d6 00 00 00 7b 1a 9f 1c ............{... +47d0 18 00 00 32 22 00 00 00 00 00 00 00 21 00 1a 01 ...2".......!... +47e0 1d 01 02 00 16 1a a2 1c 18 00 00 4b 20 00 00 00 ...........K ... +47f0 00 00 00 86 41 00 00 00 bd 00 00 00 13 1a e3 1c ....A........... +4800 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4810 c0 00 00 00 17 1a e3 1c 18 00 00 32 20 00 00 00 ...........2 ... +4820 00 00 00 00 00 00 00 00 bc 00 00 00 7b 1a e3 1c ............{... +4830 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4840 bc 00 00 00 5b 1a e3 1c 18 00 00 32 20 00 00 00 ....[......2 ... +4850 00 00 00 00 00 00 00 00 c0 00 00 00 3b 1a e3 1c ............;... +4860 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4870 c4 00 00 00 0f 1a c3 1c 28 00 01 32 22 00 00 00 ........(..2"... +4880 00 00 00 00 c7 00 00 00 1a 01 00 00 32 1a 95 1c ............2... +4890 18 00 00 0e 30 00 00 00 05 01 00 1c 0d 00 00 00 ....0........... +48a0 16 01 00 00 07 1a a8 1c 22 00 00 32 22 01 00 00 ........"..2"... +48b0 00 00 00 3c c7 81 21 00 19 01 03 01 39 1a e3 1c ...<..!.....9... +48c0 19 00 02 32 20 20 00 00 00 00 00 a7 0f 00 00 00 ...2 .......... +48d0 e8 00 00 00 ff 1a af 1c 30 00 00 32 20 00 00 00 ........0..2 ... +48e0 34 12 34 12 0f 00 00 00 e8 00 00 00 bf 1a bf 1c 4.4............. +48f0 30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 0..2 ...4.4..... +4900 e8 00 00 00 3f 1b af 1c 30 00 00 32 20 00 00 00 ....?...0..2 ... +4910 34 12 34 12 0f 00 00 00 e8 00 00 00 7f 1b af 1c 4.4............. +4920 30 00 00 32 20 00 00 00 34 12 34 12 0b 81 21 00 0..2 ...4.4...!. +4930 19 01 03 02 e3 1d ff 1c 03 00 02 32 20 20 00 00 ...........2 .. +4940 00 00 00 2c 27 80 00 00 ad 00 00 00 d8 1d f2 1c ...,'........... +4950 03 00 06 32 32 20 00 00 01 22 00 8b 00 00 00 00 ...22 ..."...... +4960 b3 00 00 00 c5 1d e3 1c 12 00 00 32 20 00 00 00 ...........2 ... +4970 00 00 00 00 1e 00 00 00 d8 00 00 00 97 1d ef 1c ................ +4980 04 00 00 32 20 00 00 00 00 00 00 00 1a 00 00 00 ...2 ........... +4990 ad 00 00 00 3d 19 6d 1d 19 00 03 32 30 20 00 00 ....=.m....20 .. +49a0 00 80 00 6d 11 00 00 00 e8 00 00 00 3f 19 3f 1d ...m........?.?. +49b0 30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 0..2 ...4.4..... +49c0 e8 00 00 00 3f 19 7f 1d 30 00 00 32 20 00 00 00 ....?...0..2 ... +49d0 34 12 34 12 00 00 00 00 d6 00 00 00 7b 19 67 1d 4.4.........{.g. +49e0 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +49f0 d6 00 00 00 1b 19 5f 1d 18 00 00 32 22 00 00 00 ......_....2"... +4a00 00 00 00 00 00 00 00 00 d6 00 00 00 7b 19 2b 1d ............{.+. +4a10 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +4a20 d6 00 00 00 1b 19 27 1d 18 00 00 32 22 00 00 00 ......'....2"... +4a30 00 00 00 00 00 00 00 00 0d 01 00 00 47 19 57 1d ............G.W. +4a40 18 00 01 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +4a50 c1 00 00 00 37 19 37 1d 18 00 00 32 20 00 00 00 ....7.7....2 ... +4a60 00 00 00 00 00 00 00 00 c1 00 00 00 47 19 37 1d ............G.7. +4a70 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4a80 c1 00 00 00 57 19 37 1d 18 00 00 32 20 00 00 00 ....W.7....2 ... +4a90 00 00 00 00 00 00 00 00 c1 00 00 00 57 19 47 1d ............W.G. +4aa0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4ab0 c1 00 00 00 57 19 57 1d 18 00 00 32 20 00 00 00 ....W.W....2 ... +4ac0 00 00 00 00 11 00 00 00 e8 00 00 00 7f 19 3f 1d ..............?. +4ad0 30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 0..2 ...4.4..... +4ae0 e8 00 00 00 7f 19 7f 1d 30 00 00 32 20 00 00 00 ........0..2 ... +4af0 34 12 34 12 02 00 00 00 16 01 00 00 07 19 79 1d 4.4...........y. +4b00 22 00 00 32 22 01 00 00 00 00 00 0b 00 00 00 00 "..2"........... +4b10 d2 00 00 00 5f 19 5f 1d 00 00 00 32 20 00 00 00 ...._._....2 ... +4b20 00 00 00 00 0d 80 14 01 c6 00 00 0a 58 1a 02 1d ............X... +4b30 20 00 01 32 22 21 00 00 00 10 14 3b 00 00 00 00 ..2"!.....;.... +4b40 c5 00 00 00 61 1a 07 1d 1e 00 01 32 22 00 00 00 ....a......2"... +4b50 00 00 00 00 14 00 00 00 d8 00 00 00 17 1a 03 1d ................ +4b60 1a 00 00 32 20 00 00 00 00 00 00 00 0d 00 00 00 ...2 ........... +4b70 1a 01 00 00 1c 1a 07 1d 1a 00 00 0e 30 00 00 00 ............0... +4b80 33 34 20 1c 00 00 00 00 1b 01 00 00 03 1a 63 1d 34 ...........c. +4b90 18 00 01 32 20 00 00 00 00 00 00 00 15 80 d8 00 ...2 ........... +4ba0 e4 00 00 00 1f 1a 0b 1d 1a 00 00 32 22 00 00 00 ...........2"... +4bb0 00 00 00 60 00 00 00 00 bd 00 00 00 13 1a 1b 1d ...`............ +4bc0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4bd0 c0 00 00 00 17 1a 1b 1d 18 00 00 32 20 00 00 00 ...........2 ... +4be0 00 00 00 00 00 00 00 00 bc 00 00 00 7b 1a 1b 1d ............{... +4bf0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4c00 bc 00 00 00 5b 1a 1b 1d 18 00 00 32 20 00 00 00 ....[......2 ... +4c10 00 00 00 00 10 00 00 00 c0 00 00 00 3b 1a 1b 1d ............;... +4c20 18 00 00 32 20 00 00 00 00 00 00 00 c7 00 00 00 ...2 ........... +4c30 e8 00 00 00 7f 1a 7f 1d 30 00 00 32 20 00 00 00 ........0..2 ... +4c40 34 12 34 12 c7 00 00 00 e8 00 00 00 3f 1a 7f 1d 4.4.........?... +4c50 30 00 00 32 20 00 00 00 34 12 34 12 0a 00 00 00 0..2 ...4.4..... +4c60 c4 00 00 00 0f 1a 43 1d 28 00 01 32 22 00 00 00 ......C.(..2"... +4c70 00 00 00 00 08 00 00 00 16 01 00 00 07 1a 5b 1d ..............[. +4c80 23 00 00 32 22 01 00 00 00 00 00 1b c7 00 00 00 #..2"........... +4c90 e8 00 00 00 7f 1a 3f 1d 30 00 00 32 20 00 00 00 ......?.0..2 ... +4ca0 34 12 34 12 c7 00 00 00 e8 00 00 00 3f 1a 3f 1d 4.4.........?.?. +4cb0 30 00 00 32 20 00 00 00 34 12 34 12 c7 01 00 00 0..2 ...4.4..... +4cc0 ad 00 00 00 38 1a 47 1d 19 00 0d 32 32 20 00 00 ....8.G....22 .. +4cd0 00 46 00 a6 27 80 00 00 ad 00 00 00 c3 1d 2f 1d .F..'........./. +4ce0 01 00 06 32 32 20 00 00 01 22 00 8a 00 00 00 00 ...22 ..."...... +4cf0 2b 01 00 00 bd 1d 7e 1d 00 00 00 28 a0 00 00 00 +.....~....(.... +4d00 00 00 00 00 00 00 00 00 c3 00 00 00 b7 1d 6e 1d ..............n. +4d10 00 00 00 28 a0 00 00 00 00 00 00 00 14 00 00 00 ...(............ +4d20 c6 00 00 00 af 1d 0f 1d 06 00 00 32 20 21 00 00 ...........2 !.. +4d30 00 00 1a 5e 00 00 00 00 da 00 00 00 b3 1d 1b 1d ...^............ +4d40 06 00 00 32 20 00 00 00 00 00 00 00 07 01 00 00 ...2 ........... +4d50 ad 00 00 00 db 1d 1b 1d 01 00 01 32 30 20 00 00 ...........20 .. +4d60 00 40 00 18 00 00 00 00 af 00 00 00 9f 1d 7b 1d .@............{. +4d70 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4d80 af 00 00 00 9f 1d 7b 1d 08 00 01 32 20 00 00 00 ......{....2 ... +4d90 00 00 00 00 00 00 00 00 b4 00 00 00 9b 1d 77 1d ..............w. +4da0 0a 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +4db0 af 00 00 00 9f 1d 5f 1d 08 00 01 32 20 00 00 00 ......_....2 ... +4dc0 00 00 00 00 00 00 00 00 af 00 00 00 9f 1d 5f 1d .............._. +4dd0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4de0 b0 00 00 00 d7 1d 5b 1d 00 00 02 32 22 00 00 00 ......[....2"... +4df0 00 00 00 00 00 00 00 00 b4 00 00 00 c7 1d 57 1d ..............W. +4e00 02 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4e10 b4 00 00 00 c7 1d 57 1d 0a 00 00 32 20 00 00 00 ......W....2 ... +4e20 00 00 00 00 00 00 00 00 b0 00 00 00 9f 1d 5b 1d ..............[. +4e30 08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4e40 b0 00 00 00 af 1d 5b 1d 08 00 00 32 22 00 00 00 ......[....2"... +4e50 00 00 00 00 00 00 00 00 b0 00 00 00 af 1d 5b 1d ..............[. +4e60 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +4e70 b0 00 00 00 9f 1d 5b 1d 00 00 00 32 22 00 00 00 ......[....2"... +4e80 00 00 00 00 05 00 00 00 c0 00 00 00 f3 1d 03 1d ................ +4e90 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4ea0 c0 00 00 00 c7 1d 03 1d 00 00 00 32 20 00 00 00 ...........2 ... +4eb0 00 00 00 00 00 00 00 00 be 00 00 00 fb 1d 03 1d ................ +4ec0 00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4ed0 b5 00 00 00 e7 1d 57 1d 0a 00 00 32 20 00 00 00 ......W....2 ... +4ee0 00 00 00 00 00 00 00 00 b8 00 00 00 f7 1d 5b 1d ..............[. +4ef0 0a 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +4f00 b7 00 00 00 f3 1d 57 1d 00 00 00 32 20 00 00 00 ......W....2 ... +4f10 00 00 00 00 00 00 00 00 b0 00 00 00 d7 1d 5b 1d ..............[. +4f20 08 00 00 32 22 00 00 00 00 00 00 00 ee 00 00 00 ...2"........... +4f30 ff 00 00 00 d8 1d 38 1d 00 00 00 00 20 00 00 00 ......8..... ... +4f40 00 00 00 ac 18 00 13 01 ae 00 02 01 ff 1d 57 1d ..............W. +4f50 08 00 00 32 20 21 00 00 00 00 00 68 0b 01 00 00 ...2 !.....h.... +4f60 ad 00 00 00 f7 1d 23 1d 01 00 01 32 32 20 00 00 ......#....22 .. +4f70 00 04 00 2b 00 00 00 00 bf 00 00 00 eb 1d 5b 1d ...+..........[. +4f80 00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +4f90 0f 01 00 00 8f 1d 3f 1d 00 00 00 32 20 20 00 00 ......?....2 .. +4fa0 00 00 00 00 fd 80 0c 01 0f 01 01 fe 8f 1d 2b 1d ..............+. +4fb0 00 00 00 32 20 20 00 00 00 00 00 b0 00 00 00 00 ...2 .......... +4fc0 0f 01 00 00 8f 1d 17 1d 00 00 00 32 20 20 00 00 ...........2 .. +4fd0 00 00 00 00 27 00 00 00 1a 01 00 00 d2 1d 75 1d ....'.........u. +4fe0 00 00 00 0e 30 00 00 00 35 34 08 1c 04 00 00 00 ....0...54...... +4ff0 24 01 00 00 a3 1d 33 1d 00 00 00 14 22 01 00 00 $.....3....."... +5000 00 00 00 a3 00 00 00 00 bc 00 00 00 c3 1d 03 1d ................ +5010 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5020 bc 00 00 00 a3 1d 03 1d 00 00 00 32 20 00 00 00 ...........2 ... +5030 00 00 00 00 00 00 00 00 b0 00 00 00 6b 1e 7b 1d ............k.{. +5040 00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5050 b0 00 00 00 6b 1e 6b 1d 00 00 02 32 22 00 00 00 ....k.k....2"... +5060 00 00 00 00 00 00 00 00 b0 00 00 00 6b 1e 5b 1d ............k.[. +5070 00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5080 00 01 00 00 6b 1e 17 1d 00 00 00 32 20 00 00 00 ....k......2 ... +5090 00 00 00 00 07 00 00 00 1a 01 00 00 1d 1e 70 1d ..............p. +50a0 00 00 00 0e 30 00 00 00 07 00 10 1d 00 00 00 00 ....0........... +50b0 b0 00 00 00 73 1e 63 1d 0c 00 02 32 22 00 00 00 ....s.c....2"... +50c0 00 00 00 00 00 00 00 00 b0 00 00 00 73 1e 73 1d ............s.s. +50d0 0c 00 02 32 22 00 00 00 00 00 00 00 12 01 00 00 ...2"........... +50e0 ad 00 00 00 1f 1e 43 1d 03 00 02 32 30 20 00 00 ......C....20 .. +50f0 00 60 00 54 12 00 00 00 b0 00 00 00 03 1e 5b 1d .`.T..........[. +5100 00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5110 c3 00 00 00 52 1e 76 1d 00 00 00 28 a0 00 00 00 ....R.v....(.... +5120 00 00 00 00 00 00 00 00 c3 00 00 00 57 1e 53 1d ............W.S. +5130 00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +5140 c3 00 00 00 47 1e 54 1d 00 00 00 28 a0 00 00 00 ....G.T....(.... +5150 00 00 00 00 27 00 00 00 1a 01 00 00 03 1e 30 1d ....'.........0. +5160 00 00 00 04 30 00 00 00 04 05 00 09 02 00 00 00 ....0........... +5170 24 01 00 00 03 1e 13 1d 00 00 00 14 20 01 00 00 $........... ... +5180 00 00 00 5e 14 00 00 00 16 01 00 00 3b 1e 07 1d ...^........;... +5190 0c 00 00 32 20 01 00 00 00 00 00 5d 9b 80 ff 07 ...2 ......].... +51a0 ee 00 00 00 0b 1e 1b 1d 00 00 01 32 20 00 00 00 ...........2 ... +51b0 00 00 00 00 9b 80 ff 07 ef 00 37 37 1f 1e 1f 1d ..........77.... +51c0 00 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 ...2 ........... +51d0 f1 00 00 00 1f 1e 03 1d 00 00 00 32 20 00 00 00 ...........2 ... +51e0 00 00 00 00 9b 80 ff 07 f0 00 00 00 2b 1e 1b 1d ............+... +51f0 16 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 ...2 ........... +5200 ee 00 00 00 27 1e 1b 1d 00 00 00 32 20 00 00 00 ....'......2 ... +5210 00 00 00 00 1a 00 00 00 c7 00 00 00 ff 18 9f 1d ................ +5220 24 00 00 32 a2 00 00 00 04 00 01 02 1a 00 00 00 $..2............ +5230 e8 00 00 00 ff 18 b3 1d 30 00 00 32 20 00 00 00 ........0..2 ... +5240 34 12 34 12 1a 00 e8 00 db 00 04 00 03 19 a3 1d 4.4............. +5250 18 00 00 4b 22 00 00 00 00 00 00 6c 1a 00 00 00 ...K"......l.... +5260 29 01 00 00 47 19 b3 1d 18 00 00 32 20 00 00 00 )...G......2 ... +5270 00 00 00 6b 11 00 00 00 e8 00 00 00 3f 19 bf 1d ...k........?... +5280 30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 0..2 ...4.4..... +5290 e8 00 00 00 3f 19 ff 1d 30 00 00 32 20 00 00 00 ....?...0..2 ... +52a0 34 12 34 12 11 00 00 00 1a 01 00 00 39 19 bc 1d 4.4.........9... +52b0 18 00 00 0e 30 00 00 00 13 14 00 1c 00 00 00 00 ....0........... +52c0 d6 00 00 00 1b 19 f3 1d 18 00 00 32 22 00 00 00 ...........2"... +52d0 00 00 00 00 11 00 00 00 1b 01 00 00 13 19 ab 1d ................ +52e0 18 00 00 32 20 00 00 00 00 00 00 51 11 00 00 00 ...2 ......Q.... +52f0 e8 00 00 00 7f 19 ff 1d 30 00 00 32 20 00 00 00 ........0..2 ... +5300 34 12 34 12 11 00 00 00 e8 00 00 00 7f 19 bf 1d 4.4............. +5310 30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 0..2 ...4.4..... +5320 b3 00 00 00 07 19 81 1d 2b 00 00 32 22 00 00 00 ........+..2"... +5330 00 00 00 00 00 00 00 00 c3 00 00 00 77 19 87 1d ............w... +5340 18 00 00 28 a0 00 00 00 00 00 00 00 11 80 21 00 ...(..........!. +5350 19 01 03 08 c3 19 cd 1d 19 00 02 32 20 20 00 00 ...........2 .. +5360 00 00 00 50 00 00 00 00 b3 00 00 00 97 19 87 1d ...P............ +5370 28 00 00 32 20 00 00 00 00 00 00 00 ac 01 00 00 (..2 ........... +5380 ad 00 00 00 9f 19 bf 1d 1b 00 09 32 32 20 00 00 ...........22 .. +5390 00 18 00 a3 11 00 00 00 e8 00 00 00 ff 19 ff 1d ................ +53a0 30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 0..2 ...4.4..... +53b0 e8 00 00 00 ff 19 bf 1d 30 00 00 32 20 00 00 00 ........0..2 ... +53c0 34 12 34 12 11 00 00 00 e8 00 00 00 bf 19 ff 1d 4.4............. +53d0 30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 0..2 ...4.4..... +53e0 e8 00 00 00 bf 19 bf 1d 30 00 00 32 20 00 00 00 ........0..2 ... +53f0 34 12 34 12 00 00 00 00 d4 00 00 00 9b 19 93 1d 4.4............. +5400 18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +5410 c3 00 00 00 87 19 8f 1d 18 00 00 28 a0 00 00 00 ...........(.... +5420 00 00 00 00 08 80 16 01 dd 00 02 01 69 1a 8b 1d ............i... +5430 28 00 00 0a a0 20 00 00 02 00 05 1a 0a 00 1a 01 (.... .......... +5440 1d 01 02 00 26 1a b4 1d 18 00 00 4b 20 00 00 00 ....&......K ... +5450 00 00 00 27 11 00 e8 00 db 00 04 00 03 1a cf 1d ...'............ +5460 18 00 00 4b 22 00 00 00 00 00 00 4f 0a 00 00 00 ...K"......O.... +5470 1a 01 00 00 1b 1a 9b 1d 19 00 00 0e 30 00 00 00 ............0... +5480 13 11 00 1c c7 00 db 00 c2 00 06 01 2c 1a 87 1d ............,... +5490 23 00 00 32 20 21 00 00 00 00 00 a5 0a 81 21 00 #..2 !........!. +54a0 19 01 03 01 4b 1a a7 1d 19 00 02 32 20 20 00 00 ....K......2 .. +54b0 00 00 00 26 ac 01 00 00 ad 00 00 00 2f 1a fb 1d ...&......../... +54c0 1b 00 03 32 30 20 00 00 00 80 00 a2 11 00 00 00 ...20 .......... +54d0 1b 01 00 00 13 1a b2 1d 18 00 00 32 20 00 00 00 ...........2 ... +54e0 00 00 00 4e 0a 00 00 00 e8 00 00 00 7f 1a ff 1d ...N............ +54f0 30 00 00 32 20 00 00 00 34 12 34 12 0a 00 00 00 0..2 ...4.4..... +5500 e8 00 00 00 3f 1a ff 1d 30 00 00 32 20 00 00 00 ....?...0..2 ... +5510 34 12 34 12 0a 00 00 00 e8 00 00 00 7f 1a bf 1d 4.4............. +5520 30 00 00 32 20 00 00 00 34 12 34 12 0a 00 00 00 0..2 ...4.4..... +5530 e8 00 00 00 3f 1a bf 1d 30 00 00 32 20 00 00 00 ....?...0..2 ... +5540 34 12 34 12 c7 00 e8 00 db 00 04 00 4f 1a 83 1d 4.4.........O... +5550 18 00 00 4b 20 00 00 00 00 00 00 a4 11 01 00 00 ...K ........... +5560 ad 00 00 00 33 1a d3 1d 1b 00 03 32 30 20 00 00 ....3......20 .. +5570 00 80 00 4d 04 00 00 00 c7 00 00 00 73 1c fb 1d ...M........s... +5580 0a 00 00 32 a0 00 00 00 03 00 00 02 04 00 00 00 ...2............ +5590 c7 00 00 00 f3 1c fb 1d 0a 00 00 32 a0 00 00 00 ...........2.... +55a0 03 00 00 02 00 00 00 00 bf 00 00 00 fb 1d fb 1d ................ +55b0 08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +55c0 bf 00 00 00 eb 1d fb 1d 08 56 00 32 20 00 00 00 .........V.2 ... +55d0 00 00 00 00 00 00 00 00 bf 00 00 00 fb 1d fb 1d ................ +55e0 00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +55f0 bf 00 00 00 eb 1d fb 1d 00 56 00 32 20 00 00 00 .........V.2 ... +5600 00 00 00 00 00 00 00 00 b0 00 00 00 9f 1d e3 1d ................ +5610 08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5620 b0 00 00 00 9f 1d e3 1d 00 00 02 32 20 00 00 00 ...........2 ... +5630 00 00 00 00 00 00 00 00 af 00 00 00 9f 1d d3 1d ................ +5640 08 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5650 af 00 00 00 9f 1d d3 1d 00 00 00 32 20 00 00 00 ...........2 ... +5660 00 00 00 00 14 00 00 00 b1 00 00 00 9b 1d cf 1d ................ +5670 0a 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5680 af 00 00 00 9f 1d 9f 1d 00 00 00 32 20 00 00 00 ...........2 ... +5690 00 00 00 00 00 00 00 00 af 00 00 00 9f 1d 9f 1d ................ +56a0 08 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +56b0 d7 00 00 00 7b 1e ab 1d 00 00 00 32 20 00 00 00 ....{......2 ... +56c0 00 00 00 00 18 00 00 00 13 01 00 00 37 1e af 1d ............7... +56d0 00 00 03 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +56e0 b0 00 00 00 03 1e a3 1d 00 00 00 32 22 00 00 00 ...........2"... +56f0 00 00 00 00 00 00 00 00 bf 00 00 00 0b 1e fb 1d ................ +5700 08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +5710 bf 00 00 00 0b 1e fb 1d 00 56 00 32 20 00 00 00 .........V.2 ... +5720 00 00 00 00 00 00 00 00 b0 00 00 00 03 1e 93 1d ................ +5730 10 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5740 b1 00 00 00 33 1e 8f 1d 0a 00 00 32 20 00 00 00 ....3......2 ... +5750 00 00 00 00 00 00 00 00 b0 00 00 00 03 1e 93 1d ................ +5760 08 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5770 b0 00 00 00 73 1e 83 1d 0c 00 02 32 22 00 00 00 ....s......2"... +5780 00 00 00 00 00 00 00 00 b0 00 00 00 03 1e 93 1d ................ +5790 00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +57a0 b0 00 00 00 6b 1e eb 1d 08 00 02 32 22 00 00 00 ....k......2"... +57b0 00 00 00 00 00 00 00 00 b0 00 00 00 6b 1e d3 1d ............k... +57c0 08 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +57d0 b1 00 00 00 33 1e 8f 1d 02 00 00 32 20 00 00 00 ....3......2 ... +57e0 00 00 00 00 00 00 00 00 b5 00 00 00 33 1e 8f 1d ............3... +57f0 12 00 00 32 20 00 00 00 00 00 00 00 1a 00 00 00 ...2 ........... +5800 1a 01 00 00 24 1e fb 1d 00 00 00 0e 30 00 00 00 ....$.......0... +5810 11 11 08 1c 00 00 00 00 b0 00 00 00 03 1e b3 1d ................ +5820 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5830 d5 00 00 00 4f 1e cf 1d 00 00 00 28 a0 00 00 00 ....O......(.... +5840 00 00 00 00 00 00 00 00 d4 00 00 00 4b 1e bb 1d ............K... +5850 00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +5860 d7 00 00 00 57 1e ab 1d 00 00 01 32 20 00 00 00 ....W......2 ... +5870 00 00 00 00 00 00 00 00 d2 00 00 00 3f 19 7f 1e ............?... +5880 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5890 d2 00 00 00 3f 19 3f 1e 00 00 00 32 20 00 00 00 ....?.?....2 ... +58a0 00 00 00 00 00 00 00 00 d2 00 00 00 7f 19 7f 1e ................ +58b0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +58c0 d2 00 00 00 7f 19 3f 1e 00 00 00 32 20 00 00 00 ......?....2 ... +58d0 00 00 00 00 00 00 00 00 d2 00 00 00 ff 19 7f 1e ................ +58e0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +58f0 d2 00 00 00 ff 19 3f 1e 00 00 00 32 20 00 00 00 ......?....2 ... +5900 00 00 00 00 00 00 00 00 d2 00 00 00 bf 19 7f 1e ................ +5910 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5920 d2 00 00 00 bf 19 3f 1e 00 00 00 32 20 00 00 00 ......?....2 ... +5930 00 00 00 00 00 00 00 00 e3 00 00 00 cb 19 27 1e ..............'. +5940 00 00 00 32 20 00 00 00 00 00 00 00 0c 00 00 00 ...2 ........... +5950 1a 01 00 00 4f 1a 4b 1e 18 00 00 0e 30 00 00 00 ....O.K.....0... +5960 13 14 08 1d 0a 00 1a 01 ec 00 02 00 21 1a 07 1e ............!... +5970 24 00 00 32 20 21 00 00 00 00 00 25 0c 00 00 00 $..2 !.....%.... +5980 1a 01 00 00 37 1a 4b 1e 18 00 00 0e 30 00 00 00 ....7.K.....0... +5990 17 14 10 1d 0a 00 e8 00 ac 00 04 00 3b 1a 03 1e ............;... +59a0 18 00 00 4b 20 00 00 00 00 00 00 24 00 00 00 00 ...K ......$.... +59b0 d2 00 00 00 7f 1a 7f 1e 00 00 00 32 20 00 00 00 ...........2 ... +59c0 00 00 00 00 00 00 00 00 d2 00 00 00 3f 1a 7f 1e ............?... +59d0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +59e0 d2 00 00 00 3f 1a 3f 1e 00 00 00 32 20 00 00 00 ....?.?....2 ... +59f0 00 00 00 00 00 00 00 00 d2 00 00 00 7f 1a 3f 1e ..............?. +5a00 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5a10 bb 00 00 00 63 1a 67 1e 18 00 00 32 20 00 00 00 ....c.g....2 ... +5a20 00 00 00 00 00 00 00 00 c0 00 00 00 5f 1a 43 1e ............_.C. +5a30 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5a40 c0 00 00 00 23 1a 67 1e 18 00 00 32 20 00 00 00 ....#.g....2 ... +5a50 00 00 00 00 00 00 00 00 bb 00 00 00 1b 1a 43 1e ..............C. +5a60 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5a70 bb 00 00 00 3f 1a 43 1e 18 00 00 32 22 00 00 00 ....?.C....2"... +5a80 00 00 00 00 00 00 00 00 c0 00 00 00 3f 1a 47 1e ............?.G. +5a90 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5aa0 c0 00 00 00 1b 1a 47 1e 18 00 00 32 20 00 00 00 ......G....2 ... +5ab0 00 00 00 00 3c 00 00 00 1a 01 00 00 c0 1a 2c 1e ....<.........,. +5ac0 18 00 00 04 30 00 00 00 03 05 00 09 0c 80 21 00 ....0.........!. +5ad0 19 01 03 01 a5 1a 52 1e 19 00 02 32 20 20 00 00 ......R....2 .. +5ae0 00 00 00 39 3c 00 00 00 1a 01 00 00 b8 1a 6c 1e ...9<.........l. +5af0 18 00 00 0e 30 00 00 00 02 04 00 1d 0c 01 00 00 ....0........... +5b00 1b 01 00 00 93 1a 37 1e 18 00 01 32 20 00 00 00 ......7....2 ... +5b10 00 00 00 38 0c 00 00 00 ff 00 00 00 9f 1a 37 1e ...8..........7. +5b20 18 00 00 00 20 00 00 00 00 00 00 37 00 00 00 00 .... ......7.... +5b30 c0 00 00 00 e7 1a 33 1e 18 00 00 32 20 00 00 00 ......3....2 ... +5b40 00 00 00 00 00 00 00 00 c4 00 00 00 ab 1a 0b 1e ................ +5b50 28 00 00 32 20 00 00 00 00 00 00 00 0a 00 00 00 (..2 ........... +5b60 c4 00 00 00 83 1a 0b 1e 28 00 02 32 20 00 00 00 ........(..2 ... +5b70 00 00 00 00 00 00 00 00 c4 00 00 00 df 1a 0b 1e ................ +5b80 28 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 (..2 ........... +5b90 c3 00 00 00 cc 1a 61 1e 24 00 00 28 a0 00 00 00 ......a.$..(.... +5ba0 00 00 00 00 00 00 00 00 2b 01 00 00 fb 1a 43 1e ........+.....C. +5bb0 18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +5bc0 d2 00 00 00 ff 1a 7f 1e 00 00 00 32 20 00 00 00 ...........2 ... +5bd0 00 00 00 00 00 00 00 00 d2 00 00 00 bf 1a 7f 1e ................ +5be0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5bf0 d2 00 00 00 bf 1a 3f 1e 00 00 00 32 20 00 00 00 ......?....2 ... +5c00 00 00 00 00 00 00 00 00 d2 00 00 00 ff 1a 3f 1e ..............?. +5c10 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5c20 c3 00 00 00 cc 1a 54 1e 18 00 00 28 a0 00 00 00 ......T....(.... +5c30 00 00 00 00 00 00 00 00 c3 00 00 00 c9 1a 60 1e ..............`. +5c40 18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +5c50 bb 00 00 00 df 1a 13 1e 18 00 00 32 20 00 00 00 ...........2 ... +5c60 00 00 00 00 00 00 00 00 c0 00 00 00 e3 1a 13 1e ................ +5c70 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5c80 c0 00 00 00 9f 1a 13 1e 18 00 00 32 20 00 00 00 ...........2 ... +5c90 00 00 00 00 00 00 00 00 c0 00 00 00 a3 1a 37 1e ..............7. +5ca0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5cb0 bb 00 00 00 9f 1a 43 1e 18 00 00 32 20 00 00 00 ......C....2 ... +5cc0 00 00 00 00 00 00 00 00 bb 00 00 00 a3 1a 67 1e ..............g. +5cd0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5ce0 c0 00 00 00 a3 1a 43 1e 18 00 00 32 20 00 00 00 ......C....2 ... +5cf0 00 00 00 00 00 00 00 00 c0 00 00 00 a7 1a 67 1e ..............g. +5d00 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5d10 c0 00 00 00 77 1b 57 1e 18 00 01 32 20 00 00 00 ....w.W....2 ... +5d20 00 00 00 00 00 00 00 00 be 00 00 00 7f 1b 57 1e ..............W. +5d30 18 00 02 32 20 00 00 00 00 00 00 00 3c 00 00 00 ...2 .......<... +5d40 1a 01 00 00 20 1b 4e 1e 18 00 00 0e 30 00 00 00 .... .N.....0... +5d50 33 34 10 1d 00 00 00 00 be 00 00 00 67 1b 5f 1e 34..........g._. +5d60 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +5d70 be 00 00 00 67 1b 67 1e 18 00 00 32 22 00 00 00 ....g.g....2"... +5d80 00 00 00 00 00 00 00 00 bd 00 00 00 67 1b 77 1e ............g.w. +5d90 18 00 00 32 22 00 00 00 00 00 00 00 0c 01 00 00 ...2"........... +5da0 ad 00 00 00 54 1b 55 1e 19 00 03 32 32 20 00 00 ....T.U....22 .. +5db0 00 08 00 36 00 00 00 00 c0 00 00 00 6b 1b 57 1e ...6........k.W. +5dc0 18 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5dd0 be 00 00 00 73 1b 57 1e 18 00 02 32 20 00 00 00 ....s.W....2 ... +5de0 00 00 00 00 ef 80 00 00 27 01 00 00 69 1b 45 1e ........'...i.E. +5df0 18 00 00 32 20 20 00 00 00 00 00 af 00 00 00 00 ...2 .......... +5e00 c0 00 00 00 67 1b 57 1e 18 00 00 32 20 00 00 00 ....g.W....2 ... +5e10 00 00 00 00 00 00 00 00 c0 00 00 00 67 1b 7b 1e ............g.{. +5e20 18 00 00 32 20 00 00 00 00 00 00 00 ff 00 00 00 ...2 ........... +5e30 1a 01 00 00 6b 1b 47 1e 18 00 00 0e 30 00 00 00 ....k.G.....0... +5e40 33 34 40 1c 00 00 00 00 c4 00 00 00 03 1b 0b 1e 34@............. +5e50 28 00 02 32 20 00 00 00 00 00 00 00 05 80 16 01 (..2 ........... +5e60 dd 00 02 01 4b 1b 0b 1e 28 00 00 0a a0 20 00 00 ....K...(.... .. +5e70 02 00 05 10 3c 00 00 00 ff 00 00 00 7e 1b 33 1e ....<.......~.3. +5e80 24 00 00 00 20 00 00 00 00 00 00 9b 00 00 00 00 $... ........... +5e90 d2 00 00 00 3f 1b 7f 1e 00 00 00 32 20 00 00 00 ....?......2 ... +5ea0 00 00 00 00 00 00 00 00 d2 00 00 00 3f 1b 3f 1e ............?.?. +5eb0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5ec0 d2 00 00 00 7f 1b 7f 1e 00 00 00 32 20 00 00 00 ...........2 ... +5ed0 00 00 00 00 00 00 00 00 d2 00 00 00 7f 1b 3f 1e ..............?. +5ee0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5ef0 d3 00 00 00 1b 1b 73 1e 18 00 00 28 a0 00 00 00 ......s....(.... +5f00 00 00 00 00 00 00 00 00 bb 00 00 00 7f 1b 37 1e ..............7. +5f10 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5f20 bb 00 00 00 3f 1b 37 1e 18 00 00 32 20 00 00 00 ....?.7....2 ... +5f30 00 00 00 00 00 00 00 00 c0 00 00 00 03 1b 3b 1e ..............;. +5f40 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +5f50 c3 00 00 00 9b 1b 6b 1e 18 00 00 28 a0 00 00 00 ......k....(.... +5f60 00 00 00 00 00 00 00 00 c3 00 00 00 a3 1b 77 1e ..............w. +5f70 18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 ...(............ +5f80 c3 00 00 00 93 1b 77 1e 18 00 00 28 a0 00 00 00 ......w....(.... +5f90 00 00 00 00 1f 01 00 00 ad 00 00 00 f7 1b 24 1e ..............$. +5fa0 01 00 02 32 32 20 00 00 00 06 00 7e 09 01 00 00 ...22 .....~.... +5fb0 ad 00 00 00 fe 1b 22 1e 01 00 02 32 32 20 00 00 ......"....22 .. +5fc0 00 06 00 20 3c 00 00 00 1b 01 00 00 87 1b 43 1e ... <.........C. +5fd0 18 00 01 32 20 00 00 00 00 00 00 9a 03 00 00 00 ...2 ........... +5fe0 24 01 00 00 93 1b 3b 1e 00 00 00 14 22 01 00 00 $.....;....."... +5ff0 00 00 00 5b 00 00 00 00 e6 00 00 00 9b 1b 57 1e ...[..........W. +6000 06 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 ...("........... +6010 e6 00 00 00 9f 1b 57 1e 00 00 00 28 22 00 00 00 ......W....("... +6020 00 00 00 00 00 00 00 00 e6 00 00 00 93 1b 57 1e ..............W. +6030 00 00 00 28 22 00 00 00 00 00 00 00 05 00 00 00 ...("........... +6040 16 01 00 00 9a 1b 08 1e 22 00 00 32 20 01 00 00 ........"..2 ... +6050 00 00 00 0f 00 00 00 00 bc 00 00 00 a3 1b 7b 1e ..............{. +6060 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6070 c0 00 00 00 83 1b 57 1e 18 00 00 32 20 00 00 00 ......W....2 ... +6080 00 00 00 00 00 00 00 00 bc 00 00 00 83 1b 77 1e ..............w. +6090 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +60a0 c0 00 00 00 a7 1b 7b 1e 18 00 00 32 20 00 00 00 ......{....2 ... +60b0 00 00 00 00 00 00 00 00 c0 00 00 00 83 1b 7b 1e ..............{. +60c0 18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +60d0 0d 01 00 00 a3 1b 77 1e 18 00 00 32 20 00 00 00 ......w....2 ... +60e0 77 66 55 00 00 00 00 00 c0 00 00 00 cb 1b 27 1e wfU...........'. +60f0 18 00 00 32 20 00 00 00 00 00 00 00 09 80 00 00 ...2 ........... +6100 ca 00 00 00 c7 1b 23 1e 16 00 00 32 20 00 00 00 ......#....2 ... +6110 00 01 00 1e 00 00 00 00 ed 00 00 00 c7 1b 23 1e ..............#. +6120 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6130 bc 00 00 00 a3 1b 27 1e 00 00 00 32 20 00 00 00 ......'....2 ... +6140 00 00 00 00 00 00 00 00 d1 00 00 00 93 1b 13 1e ................ +6150 18 00 00 32 20 00 00 00 00 00 00 00 09 00 ca 00 ...2 ........... +6160 ec 00 02 00 e3 1b 07 1e 0e 00 00 32 20 21 00 00 ...........2 !.. +6170 00 00 00 1d 15 00 00 00 b3 00 00 00 fb 1b 07 1e ................ +6180 2a 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 *..2 ........... +6190 0d 01 00 00 a3 1b 53 1e 18 00 00 32 20 00 00 00 ......S....2 ... +61a0 77 66 55 00 00 00 00 00 0d 01 00 00 a3 1b 33 1e wfU...........3. +61b0 18 00 00 32 20 00 00 00 77 66 55 00 1f 00 00 00 ...2 ...wfU..... +61c0 1a 01 00 00 e6 1b 48 1e 00 00 00 14 30 00 00 00 ......H.....0... +61d0 17 14 00 4c 3c 01 00 00 ad 00 00 00 a7 1b 17 1e ...L<........... +61e0 19 00 06 32 32 20 00 00 00 22 00 99 11 00 00 00 ...22 ..."...... +61f0 d1 00 00 00 a3 1b 13 1e 18 00 00 32 20 00 00 00 ...........2 ... +6200 00 00 00 00 00 00 00 00 bb 00 00 00 a7 1b 67 1e ..............g. +6210 18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +6220 bd 00 00 00 a7 1b 77 1e 18 00 00 32 22 00 00 00 ......w....2"... +6230 00 00 00 00 00 00 00 00 c0 00 00 00 c7 1b 27 1e ..............'. +6240 18 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6250 e6 00 00 00 9f 1b 6b 1e 00 00 00 28 22 00 00 00 ......k....("... +6260 00 00 00 00 00 00 00 00 e6 00 00 00 9f 1b 6b 1e ..............k. +6270 06 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 ...("........... +6280 e6 00 00 00 ab 1b 6b 1e 00 00 00 28 22 00 00 00 ......k....("... +6290 00 00 00 00 00 00 00 00 e6 00 00 00 ab 1b 6b 1e ..............k. +62a0 06 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 ...("........... +62b0 bc 00 00 00 c3 1b 27 1e 18 00 00 32 20 00 00 00 ......'....2 ... +62c0 00 00 00 00 00 00 00 00 0d 01 00 00 83 1b 57 1e ..............W. +62d0 18 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 ...2 ...wfU..... +62e0 c0 00 00 00 83 1b 37 1e 18 00 00 32 20 00 00 00 ......7....2 ... +62f0 00 00 00 00 02 80 00 00 db 00 00 2c 7f 1c 03 1e ...........,.... +6300 00 00 00 4b 20 00 00 00 00 00 00 0a 1f 80 00 00 ...K ........... +6310 ac 00 00 00 43 1c 33 1e 00 00 00 4b 22 00 00 00 ....C.3....K"... +6320 00 00 00 7d 1f 80 ac 00 ba 00 06 01 47 1c 47 1e ...}........G.G. +6330 0a 00 00 32 22 21 00 00 00 00 00 7c 00 00 00 00 ...2"!.....|.... +6340 c4 00 00 00 27 1c 0b 1e 28 00 02 32 20 00 00 00 ....'...(..2 ... +6350 00 00 00 00 1f 80 ff 07 19 01 06 03 2b 1c 52 1e ............+.R. +6360 01 00 02 32 20 20 00 00 00 00 00 7b 00 00 00 00 ...2 .....{.... +6370 e6 00 00 00 27 1c 0f 1e 00 00 00 28 20 00 00 00 ....'......( ... +6380 00 00 00 00 00 00 00 00 e6 00 00 00 27 1c 0f 1e ............'... +6390 06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +63a0 bd 00 00 00 9f 1c 7b 1e 00 00 00 32 22 00 00 00 ......{....2"... +63b0 00 00 00 00 02 80 00 00 db 00 00 2c ff 1c 03 1e ...........,.... +63c0 00 00 00 4b 20 00 00 00 00 00 00 09 00 00 00 00 ...K ........... +63d0 12 01 00 00 9f 1c 23 1e 06 00 00 32 20 00 00 00 ......#....2 ... +63e0 00 00 00 00 00 00 00 00 12 01 00 00 a7 1c 13 1e ................ +63f0 06 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6400 12 01 00 00 97 1c 13 1e 06 00 00 32 20 00 00 00 ...........2 ... +6410 00 00 00 00 00 00 00 00 12 01 00 00 9f 1c 23 1e ..............#. +6420 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6430 12 01 00 00 a7 1c 13 1e 00 00 00 32 20 00 00 00 ...........2 ... +6440 00 00 00 00 00 00 00 00 12 01 00 00 97 1c 13 1e ................ +6450 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6460 c0 00 00 00 9f 1c 4b 1e 00 00 00 32 20 00 00 00 ......K....2 ... +6470 00 00 00 00 00 00 00 00 bc 00 00 00 9f 1c 6b 1e ..............k. +6480 00 00 00 32 22 00 00 00 00 00 00 00 1f 01 00 00 ...2"........... +6490 ad 00 00 00 df 1c 33 1e 01 00 02 32 32 20 00 00 ......3....22 .. +64a0 00 06 00 7a 00 00 00 00 c4 00 00 00 a3 1c 0b 1e ...z............ +64b0 28 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 (..2 ........... +64c0 bf 00 00 00 83 1c 6b 1e 08 00 00 32 20 00 00 00 ......k....2 ... +64d0 00 00 00 00 00 00 00 00 bf 00 00 00 83 1c 67 1e ..............g. +64e0 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +64f0 bf 00 00 00 93 1c 6b 1e 00 54 00 32 20 00 00 00 ......k..T.2 ... +6500 00 00 00 00 00 00 00 00 bf 00 00 00 93 1c 6b 1e ..............k. +6510 08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +6520 bf 00 00 00 9b 1c 5b 1e 00 00 00 32 20 00 00 00 ......[....2 ... +6530 00 00 00 00 17 00 00 00 1a 01 00 00 f9 1c 2b 1e ..............+. +6540 00 00 00 04 30 00 00 00 04 05 00 08 02 81 db 00 ....0........... +6550 dd 00 06 01 b8 1c 0b 1e 10 00 00 0a a0 20 00 00 ............. .. +6560 02 00 01 08 00 00 00 00 bf 00 00 00 fb 1c 67 1e ..............g. +6570 00 00 00 32 20 00 00 00 00 00 00 00 17 00 00 00 ...2 ........... +6580 1a 01 00 00 54 1d 19 1e 00 00 00 0e 30 00 00 00 ....T.......0... +6590 55 54 10 1c 04 00 00 00 24 01 00 00 6c 1d 12 1e UT......$...l... +65a0 00 00 00 14 20 01 00 00 00 00 63 1f 00 00 00 00 .... .....c..... +65b0 c4 00 00 00 03 1d 0b 1e 28 00 00 32 20 00 00 00 ........(..2 ... +65c0 00 00 00 00 00 00 00 00 bf 00 00 00 3f 1d 13 1e ............?... +65d0 00 00 00 32 20 00 00 00 00 00 00 00 c8 80 16 01 ...2 ........... +65e0 dd 00 02 01 67 1d 0b 1e 14 00 00 0a a0 20 00 00 ....g........ .. +65f0 02 00 05 ab 00 00 00 00 e6 00 00 00 17 1d 0f 1e ................ +6600 00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +6610 e6 00 00 00 17 1d 1b 1e 00 00 00 28 20 00 00 00 ...........( ... +6620 00 00 00 00 00 00 00 00 e6 00 00 00 17 1d 0f 1e ................ +6630 06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +6640 e6 00 00 00 17 1d 1b 1e 06 00 00 28 20 00 00 00 ...........( ... +6650 00 00 00 00 00 00 00 00 e6 00 00 00 17 1d 0f 1e ................ +6660 0c 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 ...( ........... +6670 bf 00 00 00 2f 1d 13 1e 00 00 00 32 20 00 00 00 ..../......2 ... +6680 00 00 00 00 00 00 00 00 bf 00 00 00 1b 1d 63 1e ..............c. +6690 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +66a0 bf 00 00 00 0b 1d 63 1e 00 00 00 32 20 00 00 00 ......c....2 ... +66b0 00 00 00 00 00 00 00 00 bf 00 00 00 f3 1d 0b 1e ................ +66c0 08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 .V.2 ........... +66d0 bf 00 00 00 fb 1d 0b 1e 00 56 00 32 20 00 00 00 .........V.2 ... +66e0 00 00 00 00 00 00 00 00 bf 00 00 00 eb 1d 0b 1e ................ +66f0 00 56 00 32 20 00 00 00 00 00 00 00 c8 00 00 00 .V.2 ........... +6700 16 01 00 00 87 1d 1f 1e 0a 00 00 32 22 01 00 00 ...........2"... +6710 00 00 00 aa 00 00 00 00 d6 00 00 00 9f 1d 0b 1e ................ +6720 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +6730 b3 00 00 00 87 1d 23 1e 12 00 00 32 22 00 00 00 ......#....2"... +6740 00 00 00 00 17 80 21 00 19 01 03 02 bf 1d 47 1e ......!.......G. +6750 01 00 02 32 20 20 00 00 00 00 00 63 0b 00 00 00 ...2 .....c.... +6760 1a 01 00 00 fc 1d 1f 1e 00 00 00 0e 30 00 00 00 ............0... +6770 55 54 00 1d 00 00 00 00 d6 00 00 00 d7 1d 73 1e UT............s. +6780 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6790 d6 00 00 00 ab 1d 77 1e 00 00 00 32 20 00 00 00 ......w....2 ... +67a0 00 00 00 00 17 01 00 00 ad 00 00 00 f8 1d 23 1e ..............#. +67b0 01 00 12 32 30 20 00 00 00 ec 00 62 00 00 00 00 ...20 .....b.... +67c0 bf 00 00 00 0b 1e 0b 1e 00 56 00 32 20 00 00 00 .........V.2 ... +67d0 00 00 00 00 00 00 00 00 d6 00 00 00 73 1e 17 1e ............s... +67e0 00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 ...2"........... +67f0 d6 00 00 00 73 1e 3f 1e 00 00 00 32 22 00 00 00 ....s.?....2"... +6800 00 00 00 00 00 00 00 00 c3 00 00 00 05 1e 5d 1e ..............]. +6810 00 00 00 28 a0 00 00 00 00 00 00 00 ff 00 00 00 ...(............ +6820 1a 01 00 00 40 1e 40 1e 00 00 00 0e 30 00 00 00 ....@.@.....0... +6830 37 34 48 1c ef 80 00 00 27 01 00 00 3d 1e 3c 1e 74H.....'...=.<. +6840 00 00 00 32 20 20 00 00 00 00 00 ae 00 00 00 00 ...2 .......... +6850 c3 00 00 00 49 1e 2a 1e 00 00 00 28 a0 00 00 00 ....I.*....(.... +6860 00 00 00 00 00 00 00 00 d4 00 00 00 63 1e 53 1e ............c.S. +6870 00 00 00 28 a2 00 00 00 00 00 00 00 00 00 00 00 ...(............ +6880 d5 00 00 00 53 1e 63 1e 00 00 00 28 a0 00 00 00 ....S.c....(.... +6890 00 00 00 00 00 00 00 00 bf 00 00 00 03 1e 0b 1e ................ +68a0 08 56 00 32 20 00 00 00 00 00 00 00 26 00 00 00 .V.2 .......&... +68b0 d2 00 00 00 3f 19 ff 1e 00 00 00 32 20 00 00 00 ....?......2 ... +68c0 00 00 00 00 26 00 00 00 d2 00 00 00 7f 19 ff 1e ....&........... +68d0 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +68e0 d2 00 00 00 7f 19 bf 1e 00 00 00 32 20 00 00 00 ...........2 ... +68f0 00 00 00 00 26 00 00 00 d2 00 00 00 3f 19 bf 1e ....&.......?... +6900 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6910 d2 00 00 00 bf 19 ff 1e 00 00 00 32 20 00 00 00 ...........2 ... +6920 00 00 00 00 26 00 00 00 d2 00 00 00 ff 19 ff 1e ....&........... +6930 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6940 d2 00 00 00 ff 19 bf 1e 00 00 00 32 20 00 00 00 ...........2 ... +6950 00 00 00 00 26 00 00 00 d2 00 00 00 bf 19 bf 1e ....&........... +6960 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6970 e3 00 00 00 67 1a af 1e 00 00 00 32 20 00 00 00 ....g......2 ... +6980 00 00 00 00 26 00 00 00 d2 00 00 00 3f 1a ff 1e ....&.......?... +6990 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +69a0 d2 00 00 00 7f 1a ff 1e 00 00 00 32 20 00 00 00 ...........2 ... +69b0 00 00 00 00 26 00 00 00 d2 00 00 00 7f 1a bf 1e ....&........... +69c0 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +69d0 d2 00 00 00 3f 1a bf 1e 00 00 00 32 20 00 00 00 ....?......2 ... +69e0 00 00 00 00 26 00 00 00 d2 00 00 00 bf 1a ff 1e ....&........... +69f0 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6a00 d2 00 00 00 ff 1a ff 1e 00 00 00 32 20 00 00 00 ...........2 ... +6a10 00 00 00 00 26 00 00 00 d2 00 00 00 ff 1a bf 1e ....&........... +6a20 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6a30 d2 00 00 00 bf 1a bf 1e 00 00 00 32 20 00 00 00 ...........2 ... +6a40 00 00 00 00 00 00 00 00 e3 00 00 00 2f 1b a7 1e ............/... +6a50 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6a60 d2 00 00 00 3f 1b ff 1e 00 00 00 32 20 00 00 00 ....?......2 ... +6a70 00 00 00 00 26 00 00 00 d2 00 00 00 7f 1b ff 1e ....&........... +6a80 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6a90 d2 00 00 00 7f 1b bf 1e 00 00 00 32 20 00 00 00 ...........2 ... +6aa0 00 00 00 00 26 00 00 00 d2 00 00 00 3f 1b bf 1e ....&.......?... +6ab0 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6ac0 d2 00 00 00 bf 19 7f 1f 00 00 00 32 20 00 00 00 ...........2 ... +6ad0 00 00 00 00 26 00 00 00 d2 00 00 00 ff 19 7f 1f ....&........... +6ae0 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6af0 d2 00 00 00 ff 19 3f 1f 00 00 00 32 20 00 00 00 ......?....2 ... +6b00 00 00 00 00 26 00 00 00 d2 00 00 00 bf 19 3f 1f ....&.........?. +6b10 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6b20 d2 00 00 00 3f 1a 7f 1f 00 00 00 32 20 00 00 00 ....?......2 ... +6b30 00 00 00 00 26 00 00 00 d2 00 00 00 7f 1a 7f 1f ....&........... +6b40 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6b50 d2 00 00 00 7f 1a 3f 1f 00 00 00 32 20 00 00 00 ......?....2 ... +6b60 00 00 00 00 26 00 00 00 d2 00 00 00 3f 1a 3f 1f ....&.......?.?. +6b70 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6b80 d2 00 00 00 bf 1a 7f 1f 00 00 00 32 20 00 00 00 ...........2 ... +6b90 00 00 00 00 26 00 00 00 d2 00 00 00 ff 1a 7f 1f ....&........... +6ba0 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6bb0 d2 00 00 00 ff 1a 3f 1f 00 00 00 32 20 00 00 00 ......?....2 ... +6bc0 00 00 00 00 26 00 00 00 d2 00 00 00 bf 1a 3f 1f ....&.........?. +6bd0 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6be0 d2 00 00 00 3f 1b 7f 1f 00 00 00 32 20 00 00 00 ....?......2 ... +6bf0 00 00 00 00 26 00 00 00 d2 00 00 00 7f 1b 7f 1f ....&........... +6c00 00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 ...2 .......&... +6c10 d2 00 00 00 7f 1b 3f 1f 00 00 00 32 20 00 00 00 ......?....2 ... +6c20 00 00 00 00 26 00 00 00 d2 00 00 00 3f 1b 3f 1f ....&.......?.?. +6c30 00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 ...2 ........... +6c40 25 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 %..........2 ... +6c50 1b 00 aa aa 00 00 00 00 2a 01 00 00 00 00 00 00 ........*....... +6c60 00 00 00 32 20 01 00 00 1f 00 aa aa 00 00 00 00 ...2 ........... +6c70 fe 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6c80 1e 00 aa aa 00 00 00 00 07 01 00 00 00 00 00 00 ................ +6c90 00 00 00 32 20 01 00 00 1c 00 aa aa 00 00 00 00 ...2 ........... +6ca0 f9 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6cb0 20 00 aa aa 00 00 00 00 fa 00 00 00 00 00 00 00 ............... +6cc0 00 00 00 32 20 01 00 00 24 00 aa aa 00 00 00 00 ...2 ...$....... +6cd0 fb 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6ce0 23 00 aa aa 00 00 00 00 fc 00 00 00 00 00 00 00 #............... +6cf0 00 00 00 32 20 01 00 00 21 00 aa aa 00 00 00 00 ...2 ...!....... +6d00 fd 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6d10 22 00 aa aa 00 00 00 00 c8 00 00 00 00 00 00 00 "............... +6d20 00 00 00 32 20 01 00 00 01 00 aa aa 00 00 00 00 ...2 ........... +6d30 c8 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6d40 01 00 aa aa 00 00 00 00 c9 00 00 00 00 00 00 00 ................ +6d50 00 00 00 32 20 01 00 00 06 00 aa aa 00 00 00 00 ...2 ........... +6d60 08 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6d70 07 00 aa aa 00 00 00 00 26 01 00 00 00 00 00 00 ........&....... +6d80 00 00 00 32 20 01 00 00 1d 00 aa aa 00 00 00 00 ...2 ........... +6d90 09 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6da0 08 00 aa aa 00 00 00 00 0b 01 00 00 00 00 00 00 ................ +6db0 00 00 00 32 20 01 00 00 09 00 aa aa 00 00 00 00 ...2 ........... +6dc0 0a 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6dd0 0a 00 aa aa 00 00 00 00 23 01 00 00 00 00 00 00 ........#....... +6de0 00 00 00 32 20 01 00 00 0b 00 aa aa 00 00 00 00 ...2 ........... +6df0 21 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 !..........2 ... +6e00 0c 00 aa aa 00 00 00 00 22 01 00 00 00 00 00 00 ........"....... +6e10 00 00 00 32 20 01 00 00 0d 00 aa aa 00 00 00 00 ...2 ........... +6e20 03 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6e30 0e 00 aa aa 00 00 00 00 06 01 00 00 00 00 00 00 ................ +6e40 00 00 00 32 20 01 00 00 0f 00 aa aa 00 00 00 00 ...2 ........... +6e50 06 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6e60 0f 00 aa aa 00 00 00 00 06 01 00 00 00 00 00 00 ................ +6e70 00 00 00 32 20 01 00 00 0f 00 aa aa 00 00 00 00 ...2 ........... +6e80 04 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6e90 12 00 aa aa 00 00 00 00 01 01 00 00 00 00 00 00 ................ +6ea0 00 00 00 32 20 01 00 00 13 00 aa aa 00 00 00 00 ...2 ........... +6eb0 02 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6ec0 15 00 aa aa 00 00 00 00 05 01 00 00 00 00 00 00 ................ +6ed0 00 00 00 32 20 01 00 00 16 00 aa aa 00 00 00 00 ...2 ........... +6ee0 f6 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6ef0 17 00 aa aa 00 00 00 00 f7 00 00 00 00 00 00 00 ................ +6f00 00 00 00 32 20 01 00 00 18 00 aa aa 00 00 00 00 ...2 ........... +6f10 f5 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 ...........2 ... +6f20 19 00 aa aa 00 00 00 00 f5 00 00 00 00 00 00 00 ................ +6f30 00 00 00 32 20 01 00 00 19 00 aa aa 00 00 00 00 ...2 ........... +6f40 1c 01 00 00 00 00 00 00 00 00 00 32 20 00 00 00 ...........2 ... +6f50 25 00 aa aa 00 00 00 00 c8 00 00 00 00 00 00 00 %............... +6f60 00 00 01 32 20 01 00 00 02 00 aa aa 00 00 00 00 ...2 ........... +6f70 c8 00 00 00 00 00 00 00 00 00 02 32 20 01 00 00 ...........2 ... +6f80 03 00 aa aa 00 00 00 00 c8 00 00 00 00 00 00 00 ................ +6f90 00 00 03 32 20 01 00 00 04 00 aa aa 00 00 00 00 ...2 ........... +6fa0 21 00 00 00 00 00 00 00 00 00 00 ff 20 00 00 00 !........... ... +6fb0 00 00 00 00 00 00 00 00 27 00 00 00 00 00 00 00 ........'....... +6fc0 00 00 00 ff 20 00 00 00 00 00 00 00 00 00 00 00 .... ........... +6fd0 1f 00 00 00 00 00 00 00 00 00 00 ff ............ diff --git a/Crusader.rep/idata/00/~0000000a.db/change.data.gbf b/Crusader.rep/idata/00/~0000000a.db/change.data.gbf index c05f9d3..bb8233d 100644 Binary files a/Crusader.rep/idata/00/~0000000a.db/change.data.gbf and b/Crusader.rep/idata/00/~0000000a.db/change.data.gbf differ diff --git a/Crusader.rep/idata/00/~0000000a.db/change.map.gbf b/Crusader.rep/idata/00/~0000000a.db/change.map.gbf index db58354..7536fd2 100644 Binary files a/Crusader.rep/idata/00/~0000000a.db/change.map.gbf and b/Crusader.rep/idata/00/~0000000a.db/change.map.gbf differ diff --git a/Crusader.rep/idata/00/~0000000a.db/db.7.gbf b/Crusader.rep/idata/00/~0000000a.db/db.10.gbf similarity index 99% rename from Crusader.rep/idata/00/~0000000a.db/db.7.gbf rename to Crusader.rep/idata/00/~0000000a.db/db.10.gbf index 092d261..866a591 100644 Binary files a/Crusader.rep/idata/00/~0000000a.db/db.7.gbf and b/Crusader.rep/idata/00/~0000000a.db/db.10.gbf differ diff --git a/Crusader.rep/idata/00/~0000000a.db/db.8.gbf b/Crusader.rep/idata/00/~0000000a.db/db.9.gbf similarity index 99% rename from Crusader.rep/idata/00/~0000000a.db/db.8.gbf rename to Crusader.rep/idata/00/~0000000a.db/db.9.gbf index 2c363db..76b8b30 100644 Binary files a/Crusader.rep/idata/00/~0000000a.db/db.8.gbf and b/Crusader.rep/idata/00/~0000000a.db/db.9.gbf differ diff --git a/Crusader.rep/idata/01/0000001b.prp b/Crusader.rep/idata/01/0000001b.prp new file mode 100644 index 0000000..0a924f8 --- /dev/null +++ b/Crusader.rep/idata/01/0000001b.prp @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Crusader.rep/idata/01/0000001c.prp b/Crusader.rep/idata/01/0000001c.prp new file mode 100644 index 0000000..0ae8e0f --- /dev/null +++ b/Crusader.rep/idata/01/0000001c.prp @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Crusader.rep/idata/01/~00000015.db/change.data.gbf b/Crusader.rep/idata/01/~00000015.db/change.data.gbf index edb3d86..06682a8 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/change.data.gbf and b/Crusader.rep/idata/01/~00000015.db/change.data.gbf differ diff --git a/Crusader.rep/idata/01/~00000015.db/change.map.gbf b/Crusader.rep/idata/01/~00000015.db/change.map.gbf index fb73089..dedb90d 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/change.map.gbf and b/Crusader.rep/idata/01/~00000015.db/change.map.gbf differ diff --git a/Crusader.rep/idata/01/~00000015.db/db.33.gbf b/Crusader.rep/idata/01/~00000015.db/db.34.gbf similarity index 99% rename from Crusader.rep/idata/01/~00000015.db/db.33.gbf rename to Crusader.rep/idata/01/~00000015.db/db.34.gbf index e348407..f16452d 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/db.33.gbf and b/Crusader.rep/idata/01/~00000015.db/db.34.gbf differ diff --git a/Crusader.rep/idata/01/~00000015.db/db.32.gbf b/Crusader.rep/idata/01/~00000015.db/db.35.gbf similarity index 99% rename from Crusader.rep/idata/01/~00000015.db/db.32.gbf rename to Crusader.rep/idata/01/~00000015.db/db.35.gbf index 746e28c..41cb440 100644 Binary files a/Crusader.rep/idata/01/~00000015.db/db.32.gbf and b/Crusader.rep/idata/01/~00000015.db/db.35.gbf differ diff --git a/Crusader.rep/idata/01/~0000001b.db/db.7.gbf b/Crusader.rep/idata/01/~0000001b.db/db.7.gbf new file mode 100644 index 0000000..6d71f1b Binary files /dev/null and b/Crusader.rep/idata/01/~0000001b.db/db.7.gbf differ diff --git a/Crusader.rep/idata/01/~0000001b.db/db.8.gbf b/Crusader.rep/idata/01/~0000001b.db/db.8.gbf new file mode 100644 index 0000000..e77dba1 Binary files /dev/null and b/Crusader.rep/idata/01/~0000001b.db/db.8.gbf differ diff --git a/Crusader.rep/idata/01/~0000001c.db/db.2.gbf b/Crusader.rep/idata/01/~0000001c.db/db.2.gbf new file mode 100644 index 0000000..a37ee52 Binary files /dev/null and b/Crusader.rep/idata/01/~0000001c.db/db.2.gbf differ diff --git a/Crusader.rep/idata/01/~0000001c.db/db.3.gbf b/Crusader.rep/idata/01/~0000001c.db/db.3.gbf new file mode 100644 index 0000000..50d5020 Binary files /dev/null and b/Crusader.rep/idata/01/~0000001c.db/db.3.gbf differ diff --git a/Crusader.rep/idata/~index.dat b/Crusader.rep/idata/~index.dat index eac3748..6b21003 100644 --- a/Crusader.rep/idata/~index.dat +++ b/Crusader.rep/idata/~index.dat @@ -32,8 +32,13 @@ VERSION=1 0000000d:U8.EXE:c0a86451c284202637978076200 /orig_cd 00000014:CRUSADER.EXE:c0a86451c28b202638339220200 +/psx +/psx/prealpha + 0000001c:SLUS_002.68:c0a86451da1a44983408575900 +/psx/remorse + 0000001b:SLUS_002.68:c0a86451c52a19721794868600 /regret 00000009:ASYLUM.DLL:c0a86451c280202637798314100 0000000a:REGRET.EXE:c0a86451c281202637836837200 -NEXT-ID:1b +NEXT-ID:1d MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/Crusader.rep/projectState b/Crusader.rep/projectState index 0118242..2d71cb8 100644 --- a/Crusader.rep/projectState +++ b/Crusader.rep/projectState @@ -3,15 +3,524 @@ - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Crusader.rep/user/00/0000000d.prp b/Crusader.rep/user/00/0000000d.prp new file mode 100644 index 0000000..032b7cd --- /dev/null +++ b/Crusader.rep/user/00/0000000d.prp @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Crusader.rep/user/00/0000000e.prp b/Crusader.rep/user/00/0000000e.prp new file mode 100644 index 0000000..f277662 --- /dev/null +++ b/Crusader.rep/user/00/0000000e.prp @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Crusader.rep/user/00/~00000008.db/db.22.gbf b/Crusader.rep/user/00/~00000008.db/db.23.gbf similarity index 99% rename from Crusader.rep/user/00/~00000008.db/db.22.gbf rename to Crusader.rep/user/00/~00000008.db/db.23.gbf index 24c29ff..d669781 100644 Binary files a/Crusader.rep/user/00/~00000008.db/db.22.gbf and b/Crusader.rep/user/00/~00000008.db/db.23.gbf differ diff --git a/Crusader.rep/user/00/~00000008.db/db.21.gbf b/Crusader.rep/user/00/~00000008.db/db.24.gbf similarity index 99% rename from Crusader.rep/user/00/~00000008.db/db.21.gbf rename to Crusader.rep/user/00/~00000008.db/db.24.gbf index b2fc855..f8adc2a 100644 Binary files a/Crusader.rep/user/00/~00000008.db/db.21.gbf and b/Crusader.rep/user/00/~00000008.db/db.24.gbf differ diff --git a/Crusader.rep/user/00/~0000000a.db/db.3.gbf b/Crusader.rep/user/00/~0000000a.db/db.4.gbf similarity index 99% rename from Crusader.rep/user/00/~0000000a.db/db.3.gbf rename to Crusader.rep/user/00/~0000000a.db/db.4.gbf index 2ab8023..d77b23b 100644 Binary files a/Crusader.rep/user/00/~0000000a.db/db.3.gbf and b/Crusader.rep/user/00/~0000000a.db/db.4.gbf differ diff --git a/Crusader.rep/user/00/~0000000a.db/db.2.gbf b/Crusader.rep/user/00/~0000000a.db/db.5.gbf similarity index 99% rename from Crusader.rep/user/00/~0000000a.db/db.2.gbf rename to Crusader.rep/user/00/~0000000a.db/db.5.gbf index 8fdc066..06ba377 100644 Binary files a/Crusader.rep/user/00/~0000000a.db/db.2.gbf and b/Crusader.rep/user/00/~0000000a.db/db.5.gbf differ diff --git a/Crusader.rep/user/00/~0000000d.db/db.2.gbf b/Crusader.rep/user/00/~0000000d.db/db.2.gbf new file mode 100644 index 0000000..17f484d Binary files /dev/null and b/Crusader.rep/user/00/~0000000d.db/db.2.gbf differ diff --git a/Crusader.rep/user/00/~0000000d.db/db.3.gbf b/Crusader.rep/user/00/~0000000d.db/db.3.gbf new file mode 100644 index 0000000..1a381bf Binary files /dev/null and b/Crusader.rep/user/00/~0000000d.db/db.3.gbf differ diff --git a/Crusader.rep/user/00/~0000000e.db/db.2.gbf b/Crusader.rep/user/00/~0000000e.db/db.2.gbf new file mode 100644 index 0000000..b1dd2f7 Binary files /dev/null and b/Crusader.rep/user/00/~0000000e.db/db.2.gbf differ diff --git a/Crusader.rep/user/00/~0000000e.db/db.3.gbf b/Crusader.rep/user/00/~0000000e.db/db.3.gbf new file mode 100644 index 0000000..341681a Binary files /dev/null and b/Crusader.rep/user/00/~0000000e.db/db.3.gbf differ diff --git a/Crusader.rep/user/~index.dat b/Crusader.rep/user/~index.dat index 70771d4..82c5f5a 100644 --- a/Crusader.rep/user/~index.dat +++ b/Crusader.rep/user/~index.dat @@ -4,6 +4,7 @@ VERSION=1 0000000c:udf_c0a86451c285202638031072100:c0a86451fcd2547353220145000 00000008:udf_c0a86451c28c202638381579400:c0a86451f608205075819887000 0000000b:udf_c0a86451c28e202638509414500:ac18b01ab332438409229485800 + 0000000d:udf_c0a86451c52a19721794868600:c0a86451c52b19721868788800 00000006:udf_c0a86451f2583322595358500:c0a86451c1883616844258300 00000009:udf_c0a86451f6e9206725659389900:c0a86451ed04206884877489100 00000007:udf_c0a86451fc492611033559300:c0a86451cb1215992032385300 @@ -13,5 +14,5 @@ VERSION=1 00000000:udf_c0a8647bf0178892741854800:c0a8647bd36236342207469100 00000001:udf_c0a8647bf4b212984786819600:c0a8647bd36336342224113900 00000003:udf_c0a8647bfe7615910786193500:c0a8647bd36536342248279100 -NEXT-ID:d +NEXT-ID:e MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/Crusader.rep/user/~journal.dat b/Crusader.rep/user/~journal.dat new file mode 100644 index 0000000..d747a02 --- /dev/null +++ b/Crusader.rep/user/~journal.dat @@ -0,0 +1,2 @@ +IADD:0000000e:/udf_c0a86451da1a44983408575900 +IDSET:/udf_c0a86451da1a44983408575900:c0a86451da1b44983455342000 diff --git a/Crusader_Decomp.code-workspace b/Crusader_Decomp.code-workspace index c0b7716..82d9a03 100644 --- a/Crusader_Decomp.code-workspace +++ b/Crusader_Decomp.code-workspace @@ -17,6 +17,15 @@ }, { "path": "../Crusader_Decomp_Public" + }, + { + "path": "E:/emu/psx/Crusader - No Remorse" + }, + { + "path": "../crusader_map_viewer" + }, + { + "path": "E:/emu/psx/Crusader 2 Pre-Pre Alpha" } ], "settings": { diff --git a/__extract_l0.log b/__extract_l0.log new file mode 100644 index 0000000..0272b80 --- /dev/null +++ b/__extract_l0.log @@ -0,0 +1,2 @@ +usage: psx_extract_wdl.py [-h] [--output OUTPUT] input +psx_extract_wdl.py: error: unrecognized arguments: E:\emu\psx\Crusader - No Remorse\LSET1\L0.WDL --output-root out/psx_wdl diff --git a/__psx_extract_l0_run.log b/__psx_extract_l0_run.log new file mode 100644 index 0000000..d67fd10 --- /dev/null +++ b/__psx_extract_l0_run.log @@ -0,0 +1,22 @@ +file: E:\emu\psx\Crusader - No Remorse\LSET1\L0.WDL +kind: lset +header_size: 0x34 +audio_size: 0x6FDC +post_audio_start: 0x7010 +high_offset_boundaries: 0x7448, 0x34B6C, 0x72EC4, 0x7407C +regions: + audio_or_spu_blob: offset=0x34 size=0x6FDC tims=0 + post_audio_region_00: offset=0x7010 size=0x438 tims=0 + post_audio_region_01: offset=0x7448 size=0x2D724 tims=0 + post_audio_region_02: offset=0x34B6C size=0x3E358 tims=0 + post_audio_region_03: offset=0x72EC4 size=0x11B8 tims=0 + post_audio_region_04: offset=0x7407C size=0xCC6F4 tims=1 +tim_hits: + offset=0xBBA54 size=0x47 flags=0x0 +sprite_bundles: 159 + offset=0xE9168 mode=1 frames=2 data_offset=0x5C + offset=0x86810 mode=2 frames=1 data_offset=0x48 + offset=0xA9D4C mode=2 frames=1 data_offset=0x48 + offset=0x8813C mode=2 frames=1 data_offset=0x48 + offset=0x922D8 mode=2 frames=1 data_offset=0x48 + offset=0x93D40 mode=2 frames=1 data_offset=0x48 diff --git a/_tmp_psx_gpu_search.py b/_tmp_psx_gpu_search.py new file mode 100644 index 0000000..0ebd22b --- /dev/null +++ b/_tmp_psx_gpu_search.py @@ -0,0 +1,314 @@ +from __future__ import annotations + +import bisect +import json +import struct +import sys +from pathlib import Path + + +ROOT = Path(r"k:/ghidra/Crusader_Decomp") +BUNDLE_DIR = ROOT / "out/psx_wdl/L0/sprite_bundles/bundle_000A1B04" +FRAME_PATH = BUNDLE_DIR / "frame_000.bin" +BUNDLE_JSON = BUNDLE_DIR / "bundle.json" +GPU_PATH = ROOT / "binary/Crusader - No Remorse (USA) GPU RAM.bin" +L0_WDL_PATH = Path(r"e:/emu/psx/Crusader - No Remorse/LSET1/L0.WDL") +ROW_BYTES = 2048 +GPU_ROWS = 512 +TOP_N = 10 +FRAMEBUFFER_WIDTH = 320 +FRAMEBUFFER_HEIGHT = 240 +MATCH_TOP_N = 12 + +sys.path.insert(0, str(ROOT / "tools")) + +from psx_extract_wdl import colorize_indexed_pixels, psx_555_to_rgba, write_overview_grid, write_psx_16bpp_png + + +def find_all(haystack: bytes, needle: bytes): + start = 0 + while True: + index = haystack.find(needle, start) + if index < 0: + return + yield index + start = index + 1 + + +def count_row_mismatches(left: bytes, right: bytes) -> int: + return sum(a != b for a, b in zip(left, right)) + + +def is_exact_at(rows: list[bytes], candidate_rows: list[bytes], x: int, y: int, width: int) -> bool: + for dy, src in enumerate(candidate_rows): + if rows[y + dy][x : x + width] != src: + return False + return True + + +def near_score( + rows: list[bytes], + candidate_rows: list[bytes], + x: int, + y: int, + width: int, + cutoff: int | None, +) -> tuple[int, list[int], bool]: + total = 0 + row_mismatches: list[int] = [] + for dy, src in enumerate(candidate_rows): + seg = rows[y + dy][x : x + width] + mismatch = 0 if seg == src else count_row_mismatches(seg, src) + total += mismatch + row_mismatches.append(mismatch) + if cutoff is not None and total > cutoff: + return total, row_mismatches, True + return total, row_mismatches, False + + +def rgba_from_words(words: tuple[int, ...]) -> list[tuple[int, int, int]]: + return [psx_555_to_rgba(word)[:3] for word in words] + + +def candidate_match_score( + framebuffer_rgb: list[tuple[int, int, int]], + framebuffer_width: int, + framebuffer_height: int, + rgba: bytes, + width: int, + height: int, + guess_x: int, + guess_y: int, + radius: int = 12, + step: int = 2, +) -> tuple[int, int, int]: + best_score: int | None = None + best_x = -1 + best_y = -1 + x_min = max(0, guess_x - radius) + x_max = min(framebuffer_width - width, guess_x + radius) + y_min = max(0, guess_y - radius) + y_max = min(framebuffer_height - height, guess_y + radius) + for y in range(y_min, y_max + 1): + for x in range(x_min, x_max + 1): + score = 0 + samples = 0 + for sy in range(0, height, step): + screen_row = (y + sy) * framebuffer_width + sprite_row = sy * width * 4 + for sx in range(0, width, step): + src = sprite_row + sx * 4 + if rgba[src + 3] == 0: + continue + screen_r, screen_g, screen_b = framebuffer_rgb[screen_row + x + sx] + red = rgba[src] + green = rgba[src + 1] + blue = rgba[src + 2] + score += abs(screen_r - red) + abs(screen_g - green) + abs(screen_b - blue) + samples += 1 + if samples == 0: + continue + normalized = score // samples + if best_score is None or normalized < best_score: + best_score = normalized + best_x = x + best_y = y + if best_score is None: + return 1 << 30, -1, -1 + return best_score, best_x, best_y + + +def main() -> None: + bundle = json.loads(BUNDLE_JSON.read_text(encoding="ascii")) + frame_meta = next(frame for frame in bundle["exported_frames"] if frame["index"] == 0) + width = frame_meta["width"] + height = frame_meta["height"] + mode = bundle["mode"] + frame = FRAME_PATH.read_bytes() + expected = width * height + if len(frame) != expected: + raise SystemExit(f"frame byte size mismatch: got {len(frame)}, expected {expected}") + if mode != 1: + raise SystemExit(f"unexpected mode {mode}, expected 1 for 8bpp") + + gpu = GPU_PATH.read_bytes() + if len(gpu) != ROW_BYTES * GPU_ROWS: + raise SystemExit(f"unexpected GPU dump size {len(gpu)}") + + l0_data = L0_WDL_PATH.read_bytes() + palette_offset = int.from_bytes(l0_data[8:12], "little") + palette_size = int.from_bytes(l0_data[12:16], "little") + if palette_size != 0x1000: + raise SystemExit(f"unexpected palette size 0x{palette_size:X}") + palette_blob = l0_data[palette_offset : palette_offset + palette_size] + palettes_256 = [palette_blob[offset : offset + 0x200] for offset in range(0, len(palette_blob), 0x200)] + + rows = [gpu[y * ROW_BYTES : (y + 1) * ROW_BYTES] for y in range(GPU_ROWS)] + frame_rows = [frame[i * width : (i + 1) * width] for i in range(height)] + flip_rows = [row[::-1] for row in frame_rows] + + normal_hits: list[tuple[int, int]] = [] + flipped_hits: list[tuple[int, int]] = [] + for y in range(GPU_ROWS - height + 1): + row = rows[y] + normal_hits.extend((x, y) for x in find_all(row, frame_rows[0])) + flipped_hits.extend((x, y) for x in find_all(row, flip_rows[0])) + + exact_normal = [(x, y) for x, y in normal_hits if is_exact_at(rows, frame_rows, x, y, width)] + exact_flipped = [(x, y) for x, y in flipped_hits if is_exact_at(rows, flip_rows, x, y, width)] + + print(f"bundle_offset=0x{bundle['offset']:X} mode={mode} frame_count={bundle['frame_count']}") + print( + "frame0 " + f"width={width} height={height} origin=({frame_meta['origin_x']},{frame_meta['origin_y']}) " + f"data_start={frame_meta['data_start']} consumed={frame_meta['consumed']}" + ) + print(f"frame_bytes={len(frame)} gpu_dump_bytes={len(gpu)}") + print(f"row0_hits normal={len(normal_hits)} flipped={len(flipped_hits)}") + print(f"exact_full_matches_normal={len(exact_normal)}") + for x, y in exact_normal[:TOP_N]: + print(f" normal x={x} y={y} page=({x // 256},{y // 256}) in_page=({x % 256},{y % 256})") + print(f"exact_full_matches_flipped={len(exact_flipped)}") + for x, y in exact_flipped[:TOP_N]: + print(f" flipped x={x} y={y} page=({x // 256},{y // 256}) in_page=({x % 256},{y % 256})") + + live_palette_entries: list[dict[str, object]] = [] + live_palette_labels: list[str] = [] + for clut_row in range(8): + y = 0xF0 + clut_row + row_words = struct.unpack("<1024H", rows[y]) + for column in range(16): + x = column * 16 + palette = list(row_words[x : x + 256]) + rgba = colorize_indexed_pixels(frame, width, height, mode, palette) + live_palette_entries.append( + { + "width": width, + "height": height, + "rgba": rgba, + } + ) + live_palette_labels.append(f"index={clut_row * 16 + column} x={x} y={y}") + + atlas_path = BUNDLE_DIR / "live_vram_clut_atlas.png" + labels_path = BUNDLE_DIR / "live_vram_clut_atlas.txt" + write_overview_grid(atlas_path, live_palette_entries, columns=16) + labels_path.write_text("\n".join(live_palette_labels) + "\n", encoding="ascii") + print(f"live_vram_clut_atlas={atlas_path}") + print(f"live_vram_clut_labels={labels_path}") + + framebuffer_path = ROOT / "binary/psx_framebuffer_left.png" + framebuffer_crop_path = ROOT / "binary/psx_framebuffer_console_crop.png" + print(f"raw_palette_blocks_256={len(palettes_256)}") + for palette_index, palette in enumerate(palettes_256): + palette_hits: list[tuple[int, int]] = [] + for y in range(240, 256): + row = rows[y] + start = 0 + while True: + x = row.find(palette, start) + if x < 0: + break + palette_hits.append((x, y)) + start = x + 1 + print(f" palette_{palette_index}_hits={len(palette_hits)}") + for x, y in palette_hits[:TOP_N]: + print(f" palette_{palette_index} x={x} y={y} row_band={y - 240}") + + framebuffer_bytes = bytearray(FRAMEBUFFER_WIDTH * FRAMEBUFFER_HEIGHT * 2) + for y in range(FRAMEBUFFER_HEIGHT): + src_row = rows[y] + start = y * FRAMEBUFFER_WIDTH * 2 + framebuffer_bytes[start : start + FRAMEBUFFER_WIDTH * 2] = src_row[: FRAMEBUFFER_WIDTH * 2] + write_psx_16bpp_png(framebuffer_path, bytes(framebuffer_bytes), FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT) + framebuffer_words = struct.unpack(f"<{FRAMEBUFFER_WIDTH * FRAMEBUFFER_HEIGHT}H", bytes(framebuffer_bytes)) + framebuffer_rgb = rgba_from_words(framebuffer_words) + + crop_x = 70 + crop_y = 0 + crop_width = 210 + crop_height = 110 + crop_bytes = bytearray(crop_width * crop_height * 2) + for y in range(crop_height): + src = rows[crop_y + y] + src_start = crop_x * 2 + src_end = src_start + crop_width * 2 + dst_start = y * crop_width * 2 + crop_bytes[dst_start : dst_start + crop_width * 2] = src[src_start:src_end] + write_psx_16bpp_png(framebuffer_crop_path, bytes(crop_bytes), crop_width, crop_height) + print(f"framebuffer_left={framebuffer_path}") + print(f"framebuffer_console_crop={framebuffer_crop_path}") + + palette_rankings: list[tuple[int, int, int, int]] = [] + for palette_index, entry in enumerate(live_palette_entries): + score, best_x, best_y = candidate_match_score( + framebuffer_rgb, + FRAMEBUFFER_WIDTH, + FRAMEBUFFER_HEIGHT, + entry["rgba"], + width, + height, + guess_x=107, + guess_y=12, + ) + palette_rankings.append((score, palette_index, best_x, best_y)) + palette_rankings.sort() + ranking_path = BUNDLE_DIR / "live_vram_clut_rank.txt" + top_atlas_path = BUNDLE_DIR / "live_vram_clut_top_matches.png" + best_candidate_path = BUNDLE_DIR / "live_vram_clut_best.png" + ranking_lines = [] + print(f"best_live_vram_clut_matches_top_{MATCH_TOP_N}={min(MATCH_TOP_N, len(palette_rankings))}") + top_entries: list[dict[str, object]] = [] + for score, palette_index, best_x, best_y in palette_rankings[:MATCH_TOP_N]: + label = live_palette_labels[palette_index] + line = f"score={score} {label} screen=({best_x},{best_y})" + ranking_lines.append(line) + print(f" {line}") + top_entries.append(live_palette_entries[palette_index]) + ranking_path.write_text("\n".join(ranking_lines) + "\n", encoding="ascii") + print(f"live_vram_clut_rank={ranking_path}") + write_overview_grid(top_atlas_path, top_entries, columns=4) + print(f"live_vram_clut_top_matches={top_atlas_path}") + if palette_rankings: + best_palette_index = palette_rankings[0][1] + best_entry = live_palette_entries[best_palette_index] + write_overview_grid(best_candidate_path, [best_entry], columns=1) + print(f"live_vram_clut_best={best_candidate_path}") + + if exact_normal or exact_flipped: + return + + ranked: list[tuple[int, int, int, str, list[int]]] = [] + cutoff: int | None = None + for orientation, hits, candidate_rows in ( + ("normal", normal_hits, frame_rows), + ("flipped", flipped_hits, flip_rows), + ): + for x, y in hits: + total, row_mismatches, pruned = near_score(rows, candidate_rows, x, y, width, cutoff) + if pruned and len(ranked) >= TOP_N and total > ranked[-1][0]: + continue + entry = (total, y, x, orientation, row_mismatches) + insert_at = bisect.bisect_left(ranked, entry) + ranked.insert(insert_at, entry) + if len(ranked) > TOP_N: + ranked.pop() + if len(ranked) == TOP_N: + cutoff = ranked[-1][0] + + print(f"best_near_matches_top_{TOP_N}={len(ranked)}") + for total, y, x, orientation, row_mismatches in ranked: + nonzero_rows = [(index, mismatch) for index, mismatch in enumerate(row_mismatches) if mismatch] + sample = ", ".join(f"r{index}={mismatch}" for index, mismatch in nonzero_rows[:8]) + if len(nonzero_rows) > 8: + sample += ", ..." + if not sample: + sample = "all rows exact" + print( + f" {orientation} x={x} y={y} page=({x // 256},{y // 256}) in_page=({x % 256},{y % 256}) " + f"mismatches={total} details=[{sample}]" + ) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/_tmp_psx_mode1_live_row0_batch.py b/_tmp_psx_mode1_live_row0_batch.py new file mode 100644 index 0000000..3273e55 --- /dev/null +++ b/_tmp_psx_mode1_live_row0_batch.py @@ -0,0 +1,134 @@ +from __future__ import annotations + +import json +import struct +import sys +from pathlib import Path + + +ROOT = Path(r"k:/ghidra/Crusader_Decomp") +L0_WDL_PATH = Path(r"e:/emu/psx/Crusader - No Remorse/LSET1/L0.WDL") +GPU_PATH = ROOT / "binary/Crusader - No Remorse (USA) GPU RAM.bin" +OUTPUT_DIR = ROOT / "out/psx_wdl/L0/mode1_live_clut_row_f0_x0" +ROW_BYTES = 2048 +LIVE_CLUT_Y = 0xF0 +LIVE_CLUT_X = 0 + +sys.path.insert(0, str(ROOT / "tools")) + +from psx_extract_wdl import ( + colorize_indexed_pixels, + parse_lset_wdl, + scan_sprite_bundles, + write_bundle_atlas, + write_overview_grid, + write_png_rgba, +) + + +def main() -> None: + l0_data = L0_WDL_PATH.read_bytes() + gpu = GPU_PATH.read_bytes() + summary = parse_lset_wdl(l0_data) + if summary is None: + raise SystemExit("failed to parse L0.WDL") + + region = next(region for region in summary["regions"] if region["name"] == "post_audio_region_04") + region_data = l0_data[region["offset"] : region["offset"] + region["size"]] + bundles = scan_sprite_bundles(region_data, max_candidates=160) + + row = gpu[LIVE_CLUT_Y * ROW_BYTES : (LIVE_CLUT_Y + 1) * ROW_BYTES] + row_words = struct.unpack("<1024H", row) + palette = list(row_words[LIVE_CLUT_X : LIVE_CLUT_X + 256]) + + OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + entries: list[dict[str, object]] = [] + summary_rows: list[dict[str, object]] = [] + mode1_count = 0 + + for bundle in bundles: + if bundle["mode"] != 1 or not bundle["frames"]: + continue + mode1_count += 1 + bundle_dir = OUTPUT_DIR / f"bundle_{bundle['offset']:08X}" + bundle_dir.mkdir(parents=True, exist_ok=True) + rendered_frames: list[dict[str, object]] = [] + frame_rows: list[dict[str, object]] = [] + for frame in bundle["frames"]: + rgba = colorize_indexed_pixels(frame["pixels"], frame["width"], frame["height"], bundle["mode"], palette) + write_png_rgba(bundle_dir / f"frame_{frame['index']:03d}_live_row_f0_x0.png", rgba, frame["width"], frame["height"]) + rendered_frames.append( + { + "width": frame["width"], + "height": frame["height"], + "rgba": rgba, + } + ) + frame_rows.append( + { + "index": frame["index"], + "width": frame["width"], + "height": frame["height"], + "origin_x": frame["origin_x"], + "origin_y": frame["origin_y"], + "data_start": frame["data_start"], + "consumed": frame["consumed"], + } + ) + write_bundle_atlas(bundle_dir / "atlas_live_row_f0_x0.png", rendered_frames) + metadata = { + "offset": bundle["offset"], + "mode": bundle["mode"], + "palette_formula": "live_gpu_row_0xF0_x0_contiguous_256", + "palette_source": { + "gpu_dump": str(GPU_PATH), + "x": LIVE_CLUT_X, + "y": LIVE_CLUT_Y, + }, + "frame_count": bundle["frame_count"], + "exported_frames": frame_rows, + } + (bundle_dir / "palette_formula.json").write_text(json.dumps(metadata, indent=2), encoding="ascii") + first_frame = bundle["frames"][0] + first_rgba = rendered_frames[0]["rgba"] + entries.append( + { + "width": first_frame["width"], + "height": first_frame["height"], + "rgba": first_rgba, + "offset": bundle["offset"], + "area": first_frame["width"] * first_frame["height"], + } + ) + summary_rows.append( + { + "offset": bundle["offset"], + "width": first_frame["width"], + "height": first_frame["height"], + "frame_count": bundle["frame_count"], + } + ) + + entries.sort(key=lambda entry: entry["area"], reverse=True) + overview_entries = [{"width": entry["width"], "height": entry["height"], "rgba": entry["rgba"]} for entry in entries] + write_overview_grid(OUTPUT_DIR / "overview_live_row_f0_x0.png", overview_entries, columns=4) + summary_rows.sort(key=lambda row: row["width"] * row["height"], reverse=True) + (OUTPUT_DIR / "summary.json").write_text( + json.dumps( + { + "palette_formula": "live_gpu_row_0xF0_x0_contiguous_256", + "mode1_bundle_count": mode1_count, + "bundles": summary_rows, + }, + indent=2, + ), + encoding="ascii", + ) + + print(f"mode1_bundles={mode1_count}") + print(f"overview={OUTPUT_DIR / 'overview_live_row_f0_x0.png'}") + print(f"summary={OUTPUT_DIR / 'summary.json'}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/binary/Crusader - No Remorse (USA) GPU RAM.bin b/binary/Crusader - No Remorse (USA) GPU RAM.bin new file mode 100644 index 0000000..0593777 Binary files /dev/null and b/binary/Crusader - No Remorse (USA) GPU RAM.bin differ diff --git a/binary/Crusader - No Remorse (USA) memory dump.bin b/binary/Crusader - No Remorse (USA) memory dump.bin new file mode 100644 index 0000000..0bfe03b Binary files /dev/null and b/binary/Crusader - No Remorse (USA) memory dump.bin differ diff --git a/binary/psx_framebuffer_console_crop.png b/binary/psx_framebuffer_console_crop.png new file mode 100644 index 0000000..f19dbbb Binary files /dev/null and b/binary/psx_framebuffer_console_crop.png differ diff --git a/binary/psx_framebuffer_left.png b/binary/psx_framebuffer_left.png new file mode 100644 index 0000000..8a5bdb8 Binary files /dev/null and b/binary/psx_framebuffer_left.png differ diff --git a/binary/psx_vram_clut_rows.png b/binary/psx_vram_clut_rows.png new file mode 100644 index 0000000..cc0c305 Binary files /dev/null and b/binary/psx_vram_clut_rows.png differ diff --git a/binary/psx_vram_full_16bpp.png b/binary/psx_vram_full_16bpp.png new file mode 100644 index 0000000..ef8750e Binary files /dev/null and b/binary/psx_vram_full_16bpp.png differ diff --git a/crusader_decompilation_notes.md b/crusader_decompilation_notes.md index dbc267f..e0bff37 100644 --- a/crusader_decompilation_notes.md +++ b/crusader_decompilation_notes.md @@ -4,6 +4,10 @@ This file is an index. Detailed notes have been split into the `docs/` folder by Active live analysis target is now `CRUSADER.EXE`. Existing `CRUSADER-RAW.EXE` notes remain in scope as cross-reference evidence and should be cited alongside live NE addresses when they support a rename, variable role, or behavior claim. +Recent verified PSX pre-alpha batch: [docs/psx/prealpha.md](docs/psx/prealpha.md) now records a focused Ghidra pass on `/psx/prealpha/SLUS_002.68` plus a disc-tree comparison against the released PlayStation `Crusader: No Remorse` build. Current best read is that this pre-pre alpha still looks much more like a trimmed early No Remorse PSX branch than a clearly rebranded `Crusader 2` executable: it still carries direct `Crusader: No Remorse` save/quit text, the renamed `wdl_resource_bundle_load_by_index` still embeds the full retail `\LSET1\L` through `\LSET7\L` prefix table and the same `10/20/30/40/50/60` threshold ladder, and the mission/passcode UI scaffolding is still present with the same visible `15` mission briefing strings and consonant/digit passcode alphabet. The main concrete differences in this batch are the heavily reduced shipped content (`3` level bundles, `1` XA, no `.STR` movies) and the surviving architectural leftovers that no longer match the current disc literally, especially the missing-file `\AUDIO\TALK1.XA;1` path and the `LoadExec` helper for `MENU.EXE` / `ENGINE.EXE` / `PSX.EXE`. + +Recent verified PSX executable batch: [docs/psx/psx.md](docs/psx/psx.md) now records a focused Ghidra pass on `SLUS_002.68` for mission/map inventory, passcode handling, and catalog text. Current best read is that the PSX loader hardcodes seven `\LSETn\L` folder prefixes and the extracted disc ships `62` level bundles (`L0..L58`, `L62..L64`) with a real gap at `L59..L61`, while the executable still exposes only `15` plain-text `Mission Briefing ^Mission N` strings. The same pass closes the visible passcode-generation side too: mission-complete flow synthesizes `4`-character passcodes from the alphabet `BCDFGHJKLMNPQRSTVWXZ0123456789`, and the executable preserves direct ammo/item/weapon name tables. The hidden password-screen cheat codes remain less direct: public PSX references point to `XXXX` and `L0SR`/`L0SER`, but those values are not stored as plain ASCII in `SLUS_002.68`, so the compare path still looks numeric or transformed rather than table-driven. + Recent verified Japanese-build batch: [docs/jp-remorse-windows9x-investigation.md](docs/jp-remorse-windows9x-investigation.md) now records a focused live-Ghidra investigation of `/ja/CRUSADER.EXE` around the claim that the Japanese release runs natively on Windows 95 / Windows 9x instead of requiring a DOS boot path. Current best static-analysis read is strongly in favor: the JP executable is a flat Win32 image with PE-style sections, a Windows import table, native window creation, DirectDraw/DirectSound initialization, registry-backed config under `Software\Electronic Arts\Crusader: No Remorse\J1.21`, and a meaningful `GetVersion`-based Win9x compatibility branch that changes TLS allocation behavior when the classic Win9x high bit is set. The only remaining uncertainty is practical deployment rather than architecture: this pass did not runtime-test on real Win95 or prove which DirectX/runtime prerequisites are required. Recent verified Japanese-build follow-up: [docs/jp-remorse-cheats-and-launch-params.md](docs/jp-remorse-cheats-and-launch-params.md) now records a focused pass on the surviving cheat/debug and startup-argument lanes in `/ja/CRUSADER.EXE`. Current best read is that the JP Win32 build kept real executable cheat/debug machinery, not just leftover strings: `-laurie` is still a special parser case, the hidden `JASSICA16` sequence matcher still toggles the cheat-active state with live `Cheats are now active/inactive.` messages, the option-key handler still contains the immortality toggle path, and the command-line parser still executes live handlers for `-debug`, `-u `, `-warp `, `-skill `, `-mapoff `, `-egg `, and `-demo`. The same pass also narrows one important difference from older DOS-side notes: the JP Win32 parser has not yet been proven to support positional `-warp ` consumption, so that form should not currently be assumed for this build. @@ -24,6 +28,8 @@ New command-line argument batch: [docs/command-line-parameters.md](docs/command- Follow-up No Remorse cross-check: the same command-line note and [docs/first-mission-map-selection.md](docs/first-mission-map-selection.md) now record the matching live `CRUSADER.EXE` proof. `HandleCommandlineArgs` at `1048:0adc` uses the same positional `-warp [x y z]` syntax as Regret, and `Game_Start` at `1020:029e` / `1020:02d0` applies the same precedence rule where nonnegative `-egg` overrides beat the direct-coordinate `NPC_Teleport` path. +Latest warp-table follow-up: the same [docs/first-mission-map-selection.md](docs/first-mission-map-selection.md) and [docs/regret-game-start.md](docs/regret-game-start.md) notes now close the missing No Regret table details directly. Live `REGRET.EXE` `Game_RunNewGameFlow` indexes the `-warp mission` base-map table at `1480:075c`, and retail byte checks now show the same 17-word payload as No Remorse: `0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,40`, followed by a `0,0` terminator. The public renderer project now also has a dedicated extractor that writes both retail tables into `Crusader_Decomp_Public/map_renderer/.cache/mission-map-data.generated.json` for scene-metadata use. + Latest command-line follow-up: that same [docs/command-line-parameters.md](docs/command-line-parameters.md) note now closes the retail non-Japanese `-u` lane as well. In live `CRUSADER.EXE`, the parser case at `1048:0a46` copies the following token into `1478:065a`, and the newly named `startup_apply_u_override_if_present` at `1420:0cdf` consumes that buffer to load an alternate usecode/EUSECODE source into `1478:6611/6613` before rebuilding the cumulative slot-base words. Current best read is therefore `real startup usecode override`, not `JP-only feature` and not `dead parser-table residue`. The same follow-up also means the older consolidated `-setver` note is now weaker on the CRUSADER side and should be treated as needing a direct retail re-close. Latest `-u` deep dive: new note [docs/usecode-startup-override.md](docs/usecode-startup-override.md) now follows that retail override into the live usecode runtime itself. Current best read is that `-u` replaces the single live usecode root at `1478:6611/6613` rather than adding a parallel overlay. The same root is later consumed by `Usecode_ItemCallEvent`, `UsecodeProcess_CreateProcess`, `Interpreter_NextUsecodeOp`, and `Item_GetDamaged`, so the override reaches ordinary scripted gameplay behavior, not just a startup-only side lane. Current safest tooling implication is `runtime replacement for the existing Crusader usecode VM`, not `arbitrary native plug-in system`. @@ -67,6 +73,8 @@ The same `docs/ne-segment1.md` note now also has the first consolidated cheat/de | [docs/first-mission-map-selection.md](docs/first-mission-map-selection.md) | Focused note on fresh-game startup map selection: No Remorse `Game_Start`, No Regret's early and later mission-start selectors, the separate embedded `-warp mission` table, and the split between code-selected startup and external `FIXED.DAT` map content | | [docs/regret-game-start.md](docs/regret-game-start.md) | Detailed `REGRET.EXE` startup-flow note: `Game_Start`, `Game_RunNewGameFlow`, newly named helpers, startup override globals, and the current best explanation for the duplicated map-1 selector | | [docs/command-line-parameters.md](docs/command-line-parameters.md) | Consolidated startup/debug argument reference for the retail Crusader executables: live retail `-u` usecode override, the current `-setver` caution, `-debug`, `-asylum`, `-warp`, `-skill`, `-mapoff`, `-egg`, `-demo`, the `-laurie` cross-reference, and the evidence-backed direct-coordinate warp syntax/limits | +| [docs/psx/psx.md](docs/psx/psx.md) | PlayStation `SLUS_002.68` and disc-resource note: boot/load layout, `LSET`/menu WDL structure, executable-backed map inventory, passcode alphabet/display path, recovered PSX ammo/item/weapon tables, and current unresolved enemy/password-compare gaps | +| [docs/psx/prealpha.md](docs/psx/prealpha.md) | PlayStation pre-pre alpha `/psx/prealpha/SLUS_002.68` comparison note: reduced disc inventory, retained retail-style `LSET` loader, surviving No Remorse branding, stale `TALK1.XA` and `LoadExec` leftovers, and the current read that this build is closer to an unfinished No Remorse PSX branch than to a visibly rebranded sequel executable | | [docs/usecode-startup-override.md](docs/usecode-startup-override.md) | Focused retail `-u` deep dive: startup call order, why the override looks like full live-root replacement rather than addition, which event/process/interpreter consumers use that root, and what that implies for future custom usecode experiments | | [docs/usecode-roundtrip-ir.md](docs/usecode-roundtrip-ir.md) | ScummVM-to-binary USECODE cross-walk, owner-loaded class-layout and header/event-count reconciliation, conservative IR v0 plan, and the generated class-event/body-window outputs that now ground reversible `_BOOT`, `SURCAM*`, and environmental family decompile artifacts plus repeated-family regression checks | | [docs/usecode-pentagram-ghidra-path.md](docs/usecode-pentagram-ghidra-path.md) | Pentagram-derived Crusader USECODE parser plan, proof-of-concept workflow, canonical IR v1 goals, and the Ghidra-side annotation import path | @@ -76,3 +84,4 @@ The same `docs/ne-segment1.md` note now also has the first consolidated cheat/de | [docs/usecode-equipment-system.md](docs/usecode-equipment-system.md) | Evidence-backed note on Crusader's surviving `equip` / `unequip` event system, including live compiled-side dispatcher proof, corpus-wide slot counts, actor/turret/environment examples, and the current best model of `equip` as a generalized inherited Ultima-style item event | | [docs/usecode-alarmhat-analysis.md](docs/usecode-alarmhat-analysis.md) | Focused analysis of exported `ALARMHAT::equip`, the nearby `shape 0x04D0` equip loops, alarm-family comparisons, and the current gameplay-facing read of `ALARMHAT` as a local alarm-state driver | | [docs/usecode/windsurf-regret-vs-remorse.md](docs/usecode/windsurf-regret-vs-remorse.md) | Side-by-side comparison of `WINDSURF` in Regret and No Remorse, including shared slot behavior, helper-family drift, body-size differences, and the current best read of `WINDSURF` as a directional wind-force helper used by vent scripts | +| [docs/removed_items.md](docs/removed_items.md) | Evidence summary for suspicious removed item shapes in old No Remorse maps: grenade-family leftovers `0343/034E/034F/0350`, the inventory-labeled `0548` `Invalid` item, and unresolved non-pickup shapes `0110/0112` | diff --git a/docs/first-mission-map-selection.md b/docs/first-mission-map-selection.md index 3f2b459..395da4c 100644 --- a/docs/first-mission-map-selection.md +++ b/docs/first-mission-map-selection.md @@ -199,6 +199,56 @@ So the `-warp mission` path also uses code/data embedded in the executable, not `-mapoff` therefore matters only inside the manual/debug warp path. It does not affect the ordinary fresh-game selector when no `-warp` argument is present. +### 3a. No Regret cross-check: the live `REGRET.EXE` table is the same 17-word sequence at `1480:075c` + +The currently opened `REGRET.EXE` session now closes the missing cross-check directly. + +In `Game_RunNewGameFlow`, the debug/manual warp lane computes: + +```c +mapno = *(int *)(g_warpToLevelNoArg * 2 + 0x75c) + DAT_1480_0ad0; +``` + +So the live No Regret table base is: + +- `1480:075c` + +The retail bytes at that address are: + +```text +1480:075c: 00 00 01 00 03 00 05 00 07 00 09 00 0b 00 0d 00 +1480:076c: 0f 00 11 00 13 00 15 00 17 00 19 00 1b 00 1d 00 +1480:077c: 28 00 +``` + +Interpreted as little-endian words, that is the same 17-entry base-map sequence already recovered in No Remorse: + +- `0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 40` + +The next two words after the last entry are `0x0000, 0x0000`, so the retail table also has a clean double-zero terminator immediately after the `40` entry. + +Current best cross-game read is therefore tighter than the earlier one-sided Remorse note: + +- No Remorse and No Regret both keep the debug `-warp mission` base-map table in executable data +- the two currently checked retail tables carry the same 17-word payload +- the practical game-to-game difference in this startup area is not the mission table itself, but the surrounding startup control flow and data addresses + +### 3b. Renderer-side extracted JSON now records both retail tables + +The public renderer project now has a dedicated extractor for this table instead of keeping the mission mapping only in prose notes. + +Current generator and output: + +- script: `Crusader_Decomp_Public/map_renderer/src/generate-mission-map-data.js` +- generated cache file: `Crusader_Decomp_Public/map_renderer/.cache/mission-map-data.generated.json` + +That JSON captures both retail tables, their data-segment addresses, the per-mission base-map entries, and the reverse `map -> missions` lookup used by the renderer metadata. + +The renderer's scene metadata builder now consumes that generated table so usage notes can distinguish: + +- maps that are real base mission entries in the executable `-warp` table +- maps that are only reachable through `-mapoff` or some other non-table selector path + Practical implication for the earlier patch question: - if the goal was `start a normal new game on a different first map`, the executable patch was still required @@ -207,7 +257,7 @@ Practical implication for the earlier patch question: The No Remorse cross-check now makes that last point stronger: this eggless-map workaround is not just a Regret quirk. `CRUSADER.EXE` uses the same parser shape and the same consumer-side precedence. -### 3a. Why `-warp 0 28670 30718 0 -mapoff 246` likely lands in a bad spot in No Remorse +### 3c. Why `-warp 0 28670 30718 0 -mapoff 246` likely lands in a bad spot in No Remorse The current cached scene data from `Crusader_Decomp_Public/map_renderer/.cache/scene-cache/remorse/map-246/bb7e36195d39ac72/scene.json` confirms that map `246` is real and nonempty: @@ -366,4 +416,75 @@ For No Regret, the patcher now updates both hardcoded selectors so the later mis - No Regret hardcodes the same values twice: once in `Game_Start`, and again in the later `FUN_1030_032d` mission-start path that actually controls a real new game. - The debug `-warp mission` path uses an executable-embedded mission-to-map word table at `1478:0488`, plus `-mapoff`. - External files such as `FIXED.DAT` hold the actual map contents. -- `CRUSADER.CFG` does not control which map a new game starts on. \ No newline at end of file +- `CRUSADER.CFG` does not control which map a new game starts on. + +# Maps mapping by Candy + +These entries might be shifted by 1 + +28: Rebel base +29: destroyed Rebel base + +Mission 1: +0: level 1, looks complete +34: level 1, most complete +56: level 1 + +Mission 2: +2: mission 2 +3: mission 2 incomplete + +Mission 3: +4: thermatron manufacturing plant +38: thermatron manufacturing plant +43: thermatron manuf plant +45: thermatron manuf plant +5: thermatron plant broken + +Mission 4: +6: blow up comms +44: incomplete mission 5 + +Mission 5: +8: first half +9: second half + +Mission 6: +10: + +Mission 7: +11: Blow up nerve gas stockpile +12: Blow up nerve gas stockpile + +Mission 8: Save prof Willmar who dies on telepad +13,14: first mission with extra protection stuff, 5? + +Mission 9: +15: +36: + +Mission 10: +16: mission 10 + +Mission 11: Download plans for platform +17: first half +35: no idea, looks mostly complete level +37: incomplete cipher chip level +31: incomplete mission 6 +20: Looks like part of a mission but incomplete. Has that big computer thing + +Mission 12: +19: ????? Third done mission. Start matches. + +Mission 13: +21: mission 13 +22: incomplete mission 13 +39: mission 13 incomplete +40: mission 13 very incomplete + +Mission 14: +23: mission 14 +24: mission 14 with cheese fart + +Mission 15: +25: mission 15 \ No newline at end of file diff --git a/docs/map_renderer/bounding-box-feature.md b/docs/map_renderer/bounding-box-feature.md new file mode 100644 index 0000000..61cdd06 --- /dev/null +++ b/docs/map_renderer/bounding-box-feature.md @@ -0,0 +1,137 @@ +# Bounding Box Feature + +## Goal + +Add a checkbox to the map renderer web app that shows the white object bounding boxes players could toggle in the original Crusader debug view. + +## Research + +### ScummVM + +Relevant engine path: + +- `K:\misc\scummvm\engines\ultima\ultima8\world\item_sorter.cpp` +- `K:\misc\scummvm\engines\ultima\ultima8\world\sort_item.cpp` + +Useful findings: + +- The Ultima 8 / Crusader sorter keeps explicit screen-space bbox corner values such as `_sxLeft`, `_sxRight`, `_sxTop`, `_sxBot`, `_syTop`, and `_syBot`. +- The debug drawing path is labeled `Draw wire frame footpads` and uses white lines (`0xFF, 0xFF, 0xFF`). +- The wireframe is not just a flat sprite rectangle. It is built from the projected 3D item extents derived from the shape dimensions and the item world position. + +Important excerpt of behavior: + +- top diamond edges are drawn first +- if the item has height, vertical edges and lower edges are added +- the result is closer to an isometric wireframe box / footpad than a simple 2D selection rectangle + +### Pentagram + +Relevant engine path: + +- `K:\misc\pentagram\world\ItemSorter.cpp` +- `K:\misc\pentagram\world\CurrentMap.cpp` + +Useful findings: + +- Pentagram uses the same core bbox projection model: world-space `x/y/z` extents become screen-space bbox extents. +- The formulas match the ScummVM sorter closely enough to use them as a second reference for the projection math. +- This confirmed that the current renderer should not invent a brand-new bbox model; it should reuse the original item extent math where possible. + +## Implementation + +Renderer changes were made in: + +- `src/public/index.html` +- `src/public/dom-elements.js` +- `src/public/ui-controls.js` +- `src/public/app.js` +- `src/lib/build-manager.js` + +What changed: + +1. Added a `Show white bounding boxes` checkbox in the side-panel view toggles. +2. Added an `F` hotkey that toggles bounding boxes on and off unless the current focus is inside an editable text control. +3. Added bbox visibility to the metadata panel so the current view state is explicit. +4. Promoted shape `x/y/z` dimensions from the decoded typeflag info into `shapeDefinitions` inside the scene JSON. +5. Added a client-side bbox overlay renderer that: + - respects the same visibility filters as normal rendering + - skips hidden items + - draws after sprites so boxes remain visible + - uses white wireframe lines based on projected item extents when the scene payload includes dimensions +6. Changed hover and click selection to use the projected bounding-box polygon instead of the sprite image rectangle whenever shape dimensions are available. +7. Replaced the old DOM rectangle highlight with a canvas-drawn bbox highlight: + - when global bounding boxes are disabled, the focused item shows a white bbox highlight by itself + - when global bounding boxes are enabled, the focused item is redrawn in blue above the white global boxes + - hover enter fades in quickly and hover exit fades out more slowly +8. Added a compatibility fallback for older cached scenes: if a scene JSON does not yet contain shape dimensions, the client falls back to rectangle-based selection/highlighting instead of failing. + +## Issues Encountered + +### Issue 1: Existing scene payload was missing shape extents + +Initial problem: + +- The viewer already had `item.screen.left/top/right/bottom`, so a quick rectangle overlay was easy. +- That was enough for a first pass, but it did not match the original Crusader-style wireframe closely. +- It also meant hover selection was based on the sprite image rectangle instead of the projected bbox volume. + +Resolution: + +- The build pipeline already had access to the underlying shape dimensions from `typeflag.dat` decoding. +- Those dimensions were added to `shapeDefinitions`, which let the client reconstruct a closer isometric wireframe and switch hover hit-testing over to bbox geometry without using Ghidra or adding a new server endpoint. + +### Issue 2: Cache compatibility + +Problem: + +- Existing cached scene JSON files and static exports were built before the new `dimensions` field existed. + +Resolution: + +- The client now detects missing dimensions and falls back to rectangle-based selection/highlighting. +- Rebuilding a map or regenerating the static site will upgrade scenes to the wireframe path automatically. + +### Issue 3: Hover highlight behavior changed once boxes stopped being a DOM element + +Problem: + +- The original inspect highlight was an absolutely positioned DOM rectangle. +- Once the focus outline moved to wireframe bbox geometry, the highlight had to be drawn in the same canvas render path as the scene or it would drift away from the new hit-test model. + +Resolution: + +- The highlight is now rendered directly on the canvas from the same bbox geometry used by hit-testing. +- This made it straightforward to add the requested quick fade-in and slower fade-out timings. + +### Issue 4: Highlight animation state was being reset every render + +Problem: + +- The inspect/highlight state is recomputed during each render pass. +- The first bbox animation implementation reset the highlight timer every frame, which kept the highlight alpha at zero and made the selected bbox appear to never draw. + +Resolution: + +- The highlight animation state now resets only when the focused item actually changes. +- This lets hovered inspect targets and hoverable editor objects animate correctly while still being recomputed from live bbox geometry. + +### Issue 5: Keep exports unchanged + +Problem: + +- The bbox checkbox is a debug/viewer affordance, not part of the canonical map export. + +Resolution: + +- Bounding boxes are drawn only in the interactive viewport path. +- The PNG export path remains unchanged and does not bake the bbox overlay into the exported map image. + +## Result + +The web app now has a bbox checkbox that behaves like a renderer-side debug overlay and is grounded in the same item extent math used by ScummVM/Pentagram. It does not require Ghidra fallback work for the current implementation. + +## Follow-up Notes + +- To see the closer wireframe result everywhere, rebuild dynamic caches or rerun the static export so scenes include the new `shapeDefinitions[].dimensions` data. +- If exact parity with the original executable is still needed later, the next step would be verifying the original hotkey/toggle path in the game binary or locating a more explicit Crusader-specific debug toggle in engine code. That was not required for this implementation pass. diff --git a/docs/map_renderer/editor-object-survey.md b/docs/map_renderer/editor-object-survey.md new file mode 100644 index 0000000..f49194c --- /dev/null +++ b/docs/map_renderer/editor-object-survey.md @@ -0,0 +1,42 @@ +# Editor/Helper Object Survey + +This pass widened the renderer research beyond egg and NPC spawner objects and focused on editor/helper shapes that already carry useful classification data in the exported scene payload. + +## Evidence Base + +- The renderer already exports `shapeDefinitions[*]` entries with `kind`, `family`, `dimensions`, `visibilityTags`, `traits`, and the matching catalog entry. +- The public catalogs already distinguish many non-gameplay helper families that are currently easy to miss in the UI. +- Representative catalog anchors in Remorse include: + - `0x005A`, `0x005B`, `0x005C`, `0x005D`, `0x0066`-`0x0069`: invisible/editor wall objects + - `0x01B8`: `camera` + - `0x0290`, `0x0336`: `LIGHT_BRIDGE_*` + - `0x0251`, `0x0318`, `0x0337`, `0x0361`: placeholder cubes and placeholder UI/editor markers + - `0x0108`, `0x0113`, `0x01B9`, `0x01BA`, `0x025F`, `0x0260`, `0x02F0`, `0x0373`, `0x0399`, `0x03A1`, `0x04C8`: `wallgun_shape_*` helper cluster + +## What This Means For The Renderer + +- A lot of the useful information is already present without more reverse-engineering. The main problem was presentation, not raw data availability. +- Editor/helper objects often carry meaningful `mapNum`, `npcNum`, `quality`, or `nextItem` values even when they are not DTABLE-backed NPC spawners. Those raw linkage values are worth exposing because they help separate placeholder geometry from logic markers. +- Catalog names already identify several broad classes that deserve different handling in the UI: + - invisible walls/editor walls + - camera/helper markers + - light bridge / forcefield / editor-authored bridge surfaces + - placeholder cubes and placeholder UI markers + - auto-derived helper shapes tied to specific USECODE families like `WALLGUN` + +## Implemented UI Enrichment + +The tooltip now exposes generalized metadata for editor/helper objects instead of reserving extra detail almost entirely for NPC spawners: + +- `Dimensions`: shape dimensions from the exported shape definition +- `Tags`: exported visibility tags such as `editor`, `helper`, `egg`, `roof`, and `oob` +- `Traits`: exported rendering/collision traits such as `occluding`, `translucent`, `solid`, `fixed`, and nonzero animation type +- `Role hint`: a cautious catalog-backed note for important helper families like invisible walls, cameras, light bridges, placeholders, `WALLGUN` helper shapes, `0x04D0` NPC spawners, and `0x024F` monster eggs +- `Raw linkage`: `map`, `npc`, `quality`, and `next` fields for editor/helper/egg objects so unresolved objects still expose their control data + +## Practical Next Targets + +- Add dedicated filters or list views for helper subfamilies such as invisible walls, camera markers, light bridges, and placeholder cubes. +- Add shape-family frequency summaries so repeated helper markers can be audited across a map. +- Decode more shape-specific field semantics for unresolved editor objects like `0x04B1`, `0x0011`, `0x04C9`, `0x04CA`, and `0x04E3`. +- Find the No Regret replacement for the Remorse `0x024F` monster-egg workflow instead of assuming the same shape is reused. \ No newline at end of file diff --git a/docs/map_renderer/egg-identification.md b/docs/map_renderer/egg-identification.md new file mode 100644 index 0000000..a8bfdb6 --- /dev/null +++ b/docs/map_renderer/egg-identification.md @@ -0,0 +1,145 @@ +# Egg Identification Investigation + +## Goal + +Add a reliable egg browser to the map renderer and clarify what the game means by an egg "ID". + +## Short Answer + +- Fresh-game startup is hardcoded to map `1`, egg `0x1e`. +- That startup egg is not read from `CRUSADER.CFG` or another external mission map. +- For Crusader teleport eggs, the destination number that gameplay matches against is the low byte of the item `quality` field. +- The broader egg families use different payload fields depending on egg type, so the renderer should not assume that every egg-family item uses the same number source. + +## Fresh-Game Default Start Egg + +The existing reverse-engineering note in [docs/first-mission-map-selection.md](k:/ghidra/Crusader_Decomp/docs/first-mission-map-selection.md) already establishes the startup path: + +- normal new game calls `Teleporter_CreateProcessDirect(1, 0x1e, 1)` +- the controlling call site is in `Game_Start` +- this is a code-selected default, not a config-file mapping + +That means the known first-map spawn uses teleport egg id `0x1e` on map `1`. + +## ScummVM Crusader Egg Model + +The ScummVM Crusader engine in `engines/ultima/ultima8` maps Crusader egg families as follows: + +- family `3` = `SF_GLOBEGG` +- family `4` = `SF_UNKEGG` (usecode trigger egg) +- family `7` = `SF_MONSTEREGG` +- family `8` = `SF_TELEPORTEGG` + +Relevant files: + +- [shape_info.h](k:/misc/scummvm/engines/ultima/ultima8/gfx/shape_info.h) +- [item_factory.cpp](k:/misc/scummvm/engines/ultima/ultima8/world/item_factory.cpp) +- [egg.cpp](k:/misc/scummvm/engines/ultima/ultima8/world/egg.cpp) +- [egg.h](k:/misc/scummvm/engines/ultima/ultima8/world/egg.h) +- [monster_egg.h](k:/misc/scummvm/engines/ultima/ultima8/world/monster_egg.h) +- [monster_egg.cpp](k:/misc/scummvm/engines/ultima/ultima8/world/monster_egg.cpp) +- [teleport_egg.h](k:/misc/scummvm/engines/ultima/ultima8/world/teleport_egg.h) +- [teleport_egg.cpp](k:/misc/scummvm/engines/ultima/ultima8/world/teleport_egg.cpp) +- [current_map.cpp](k:/misc/scummvm/engines/ultima/ultima8/world/current_map.cpp) + +One structural detail matters here: generic trigger eggs and teleport eggs inherit from `Egg`, but `MonsterEgg` is its own `Item` subclass instead of an `Egg` subclass. That helps explain why Crusader monster eggs do not line up perfectly with the generic egg-field conventions. + +## Which Field Holds The Number? + +There is not one universal answer for every egg-family item. + +### Teleport eggs + +Teleport eggs are the important case for spawn/start locations. + +ScummVM uses: + +- `TeleportEgg::getTeleportId()` = `(_quality & 0xFF)` +- `MainActor::teleport(mapNum, teleport_id)` to move to a destination egg +- `CurrentMap::findDestination(id)` to find a teleport egg target with matching low-byte quality + +It also distinguishes two teleport egg roles: + +- `frame != 1` = active teleporter trigger +- `frame == 1` = destination marker + +So for renderer purposes, the gameplay-relevant teleport egg id is the low byte of `quality`, not `mapNum`. + +### Generic/usecode eggs + +ScummVM's generic egg intrinsics expose: + +- `Egg::I_getEggId()` -> `getMapNum()` + +So family `4` eggs use `mapNum` as their generic egg id in the engine interface. + +### Monster eggs + +ScummVM's monster egg accessor exposes: + +- `MonsterEgg::I_getMonId()` -> `getMapNum() >> 3` + +That is a separate meaning from teleport ids. + +There is an important Crusader-specific wrinkle for renderer work: + +- the generic ScummVM `MonsterEgg` model stores monster shape in `quality & 0x7FF` and activity in the low three bits of `mapNum` +- but exported No Remorse `0x024F` frame `0` monster eggs often have `quality = 0` and still carry non-zero `npcNum` values that line up with useful DTABLE rows +- concrete exported examples include Remorse map 69 (`npcNum = 2` and `npcNum = 6`) and Remorse map 2 (`rawNpcNum = 5`) +- No Remorse frame `1` `0x024F` entries also exist, but the checked cases were zeroed placeholders with no useful `npcNum`, `mapNum`, or `quality` payload +- exported No Regret `0x024F` currently diverges earlier: its shape definition resolves to `family: 0`, `kind: terrain` rather than `family: 7`, `kind: egg`, so the renderer should not assume that Remorse monster-egg semantics carry over unchanged + +So the renderer keeps two interpretations side by side for family `7` eggs: + +- the egg-family label remains `monster id = mapNum >> 3`, matching the engine intrinsic surface +- the NPC preview for evidence-backed `0x024F` frame `0` eggs comes from `npcNum`, because that field matches observed spawn identity better than the zero-heavy `quality` field in current Remorse exports + +### Glob eggs + +Glob eggs expand glob contents using the item `quality` value as the glob reference. + +## Renderer Decision + +The new map-renderer egg UI treats all egg-family items as eggs, but labels each one with the field that matches its ScummVM family behavior: + +- family `8`: teleport id = `quality & 0xFF` +- family `4`: egg id = `mapNum` +- family `7`: monster id = `mapNum >> 3` +- family `3`: glob id = `quality` + +That keeps the viewer useful for teleport/start-point work without flattening all egg families into one misleading scheme. + +For the NPC preview overlay, the renderer now makes one additional evidence-backed exception: + +- `0x024F` frame `0` monster eggs with a non-zero `npcNum` get the same DTABLE-backed blue NPC preview as `0x04D0` spawners + +That exception is intentionally narrower than the generic egg browser labels. It reflects the currently verified Remorse data, not a blanket claim that every family `7` egg in every game uses `npcNum` as its authoritative spawn row. + +## Current Cross-Game State Of `0x024F` + +- No Remorse: exported shape definition resolves to `family: 7`, `kind: egg`, and scene items produce `egg.type = monster-spawn` +- No Regret: exported shape definition currently resolves to `family: 0`, `kind: terrain`, and scene items do not produce egg metadata + +That is the strongest current reason to keep the new monster-egg preview support scoped to the evidence-backed Remorse path instead of enabling it globally for both games. + +## Weapon Room `250` + +The current renderer catalog data already contains egg-oriented notes that include `250` in the known egg-id lists for Crusader egg shapes, which is consistent with the user-observed convention that egg `250` is the weapons room/test room marker. + +Those catalog references are evidence for the workflow and UI, but the renderer should still treat them as conventions layered on top of the raw egg-family decoding above. + +## Outcome For The Feature + +The egg browser added to the renderer now: + +- lists every egg-family item in the loaded map +- shows the decoded id appropriate to that egg family +- can center the camera on a chosen egg and pin-select it +- can draw zoom-stable id labels over eggs in the viewport + +## Remaining Uncertainty + +Two things are still worth keeping in mind: + +- family `7` Crusader handling is still marked in ScummVM as partly suspicious because those records can also behave container-like +- `250 = weapons room` is a strong workflow convention, but this investigation did not add a new executable-side proof beyond the catalog evidence and known reverse-engineering notes \ No newline at end of file diff --git a/docs/map_renderer/map-editing.md b/docs/map_renderer/map-editing.md new file mode 100644 index 0000000..bf8d165 --- /dev/null +++ b/docs/map_renderer/map-editing.md @@ -0,0 +1,123 @@ +# Map Editing Workflow + +## Current Scope + +The browser renderer now supports these in-memory map edits: + +- add a new teleporter egg to the currently loaded map +- add a new teleport destination egg to the currently loaded map +- edit the teleport id for existing or newly placed teleporter and teleport destination eggs + +This works in both dynamic and static site modes because the edit only changes the client-side map source held in memory. Nothing is written back to the original Crusader data files from the browser. + +## Browser Behavior + +### Add Teleporter Or Destination Egg + +- Open the `Eggs` panel. +- The `New teleport ID` field is prefilled with the next free teleport id the renderer can find. +- Change it if you want a different id. +- Click `Add Teleporter` or `Add Destination`. +- Move the cursor over the map. A preview egg follows the pointer. +- Click to place the egg. +- Press `Esc` or click the active button again to cancel placement. + +Placement rules: + +- if the cursor is over empty space, the new egg is placed at `Z = 0` +- if the cursor is over a rendered item, the new egg uses the top height of that item: `item.world.z + shape_definition.dimensions.z * 8` +- the world position is reconstructed from the current screen point and chosen `Z` using the same isometric projection the renderer already uses for scene items + +The current implementation uses the scene's default teleport-egg template shape plus the teleporter or destination frame from the Crusader data set. + +If the chosen teleport id is already used by another teleporter or destination egg, the UI warns but still allows the placement. + +After a successful placement, the field advances to the next free id again. + +### Edit Teleport IDs + +- Pin a teleporter or teleport destination egg. +- Click the pen button in the tooltip header. +- Use the modal editor that opens. +- Change the `Teleport ID` and save. + +The duplicate-id check is warning-only. The edit is still applied so you can intentionally create or inspect collisions. + +For teleport destination eggs, this edits the destination egg's own id. + +These edits do not require admin mode because they only change the in-memory FIXED map payload used by the renderer and exports. + +### Downloads + +The `Downloads` panel now includes: + +- `Download Map Binary`: exports the current map as a raw per-map FIXED payload (`16` bytes per item record) +- `Download Map JSON`: exports the current scene JSON, including the editable `mapSource` block + +The binary export is the direct payload for a single map entry inside `FIXED.DAT`, not a full rebuilt archive. + +## Lossless Map Source + +Each built scene now carries a `mapSource` block. That block is the source of truth for editing/export and contains: + +- the game id and map id +- the original per-map byte length +- the fixed record size (`16`) +- the default teleport egg template shape/frame +- the full list of FIXED item records decoded into JSON fields + +This exists because the painted scene is not a lossless representation of `FIXED.DAT`: invalid or fully occluded records can be dropped during scene generation. + +## Offline Split/Rebuild Tool + +Use the new npm entry point: + +```text +npm run map-compiler -- split --game=remorse +npm run map-compiler -- rebuild --game=remorse --from=json +npm run map-compiler -- rebuild --game=remorse --from=binary +``` + +If no parameters are supplied, the tool enters an interactive console mode. + +### Split Output + +Default split output: + +```text +generated/map-compiler//split/ +``` + +Each map is written to its own folder: + +```text +map-/map.bin +map-/map.json +``` + +`map.bin` is the raw per-map FIXED payload. `map.json` is the decoded JSON form using the same item structure as the browser `mapSource`. + +If you changed teleport ids or placed new teleport-related eggs in the browser before exporting, those in-memory changes are reflected in the exported JSON and map binary output. + +### Rebuild Output + +Default rebuild output: + +```text +generated/map-compiler//rebuilt/FIXED.DAT +``` + +The tool always writes rebuilt archives into a generated subfolder and refuses to overwrite the original `FIXED.DAT`. + +Rebuild modes: + +- `--from=json`: rebuild each map payload from `map.json` +- `--from=binary`: rebuild each map payload from `map.bin` + +Maps without a replacement file keep their original payload from the source archive. + +## Notes + +- The browser does not currently write changes back into the source static asset tree. +- The browser edit path currently only creates teleport eggs. +- The archive rebuild preserves the original non-map header region and rewrites the map table/payload layout into a generated output directory. \ No newline at end of file diff --git a/docs/map_renderer/npc-spawners.md b/docs/map_renderer/npc-spawners.md new file mode 100644 index 0000000..d736eec --- /dev/null +++ b/docs/map_renderer/npc-spawners.md @@ -0,0 +1,216 @@ +# NPC Spawner Investigation + +## Goal + +Recover the meaning of the `npcNum` field on Crusader editor and egg-side helper objects, determine which shapes really use DTABLE-backed NPC records, and surface only the evidence-backed lookup data in the public map renderer. + +## Short Answer + +- Shape `0x04D0` editor objects are not backed by a hardcoded executable-only NPC name list. +- For `0x04D0`, the `npcNum` field indexes external NPC metadata stored in `STATIC/DTABLE.FLX` for No Remorse and `STATIC_REGRET/DTABLE.FLX` for No Regret. +- The relevant DTABLE layout matches ScummVM's Crusader `NPCDat` loader: + - object `0` = fixed `142`-byte NPC rows + - object `2` = parallel `32`-byte NUL-terminated names +- Current evidence does not justify applying that same DTABLE lookup to every shape that happens to carry an `npcNum` byte. +- The renderer now exposes the recovered DTABLE name and spawn shape only for the evidence-backed `0x04D0` path. + +## Verified File Layout + +ScummVM's Crusader engine already documents the DTABLE structure in `world/actors/npc_dat.cpp`: + +- row size = `142` bytes +- name size = `32` bytes +- shape offset = `0x3e` +- min/max HP = `0x00/0x02` +- default weapon slots = `0x18/0x1a` +- default activities = `0x1e`, `0x40`, `0x42` + +Its `filesys/flex_file.cpp` also confirms the Flex header shape used to read the archive index: + +- entry count at file offset `0x54` +- object table at file offset `0x80` + +Those offsets were used to extract the local retail DTABLE rows directly. + +## Executable-Side Corroboration + +The live `CRUSADER.EXE` session already had the core DTABLE helper names recovered: + +- `1118:0075` = `DTable_Load` +- `1118:056a` = `DTable_GetNameForShapeNo` +- `10e8:0152` = `NPC_SetDataFromDTable` +- `10e8:336d` = `NPC_DTable_GetMaxHPForNPC` + +That function cluster is consistent with `npcNum` being an index into external DTABLE-backed NPC records, not a local `0x04D0`-specific switch table. + +## Shape Review + +This pass specifically re-checked the shapes that came up during renderer work: `0x04D0`, `0x024F`, `0x04B1`, and `0x0011`. + +### `0x04D0` + +- The old Crusader disassembly corpus labels usecode class `0x04D0` as `MONSTER`. +- Existing local analysis in `docs/usecode-alarmhat-analysis.md` shows multiple scripts scanning nearby shape `0x04D0` objects and driving them through monster/helper behavior. +- In the current script evidence, those nearby scans explicitly require frame `0` on the found `0x04D0` object before calling the equip/activation helper. +- The executable-side DTABLE helper cluster and the extracted DTABLE rows line up cleanly with the renderer's `npcNum` observations for this shape. + +Current conclusion: `0x04D0` is the confirmed DTABLE-backed NPC spawner/controller shape, so DTABLE name lookup is appropriate here. Frame `0` is the better-supported actionable/helper state. Frame `1` still appears as a paired variant in map data, but this pass does not yet pin down its exact semantics. + +### `0x024F` + +- In No Remorse, the current renderer and ScummVM family mapping both classify `0x024F` as a family `7` monster egg shape. +- Exported Remorse scene data shows frame `0` `0x024F` eggs with non-zero `npcNum` values and family `7` egg metadata. Example cases include Remorse map 69 with `npcNum = 2` and `npcNum = 6`, and Remorse map 2 with `rawNpcNum = 5` on another `0x024F` monster egg. +- The preview path now treats those frame `0` monster eggs as a second evidence-backed DTABLE consumer. After rebuilding cache, Remorse map 69 produces a concrete preview case where a `0x024F` frame `0` egg with `npcNum = 6` resolves to `Observer` and emits `npcPreview.shapeDefId = shape:828`. +- Frame `1` `0x024F` records also appear in No Remorse, but the concrete checked cases were zeroed placeholders with `mapNum = 0`, `npcNum = 0`, `quality = 0`, and no preview metadata. The current renderer therefore only enables the preview for frame `0` monster eggs with a non-zero `npcNum`. +- In current exported No Regret data, `0x024F` is not only visually categorized differently. The exported shape definition itself resolves to `family: 0`, `kind: terrain`, unlike the No Remorse definition which resolves to `family: 7`, `kind: egg`. That means the present Regret difference is coming from the underlying typeflag/family data, not from a UI-only catalog mismatch. + +Current conclusion: `0x024F` frame `0` monster eggs are not the same authoring form as `0x04D0`, but in Remorse they do carry usable DTABLE-style `npcNum` rows. That is strong enough to preview the spawned NPC for those eggs, while keeping the broader egg-family interpretation separate from the `0x04D0` editor/controller path. + +### `0x04D0` Field Ambiguity Notes + +- The strongest current activation control lives in `MONSTER.slot_0F enterFastArea`, not in DTABLE. That script only checks `0x04D0` objects when `frame == 0`, then blocks the automatic enter-area lane if `mapNum & 0x08` is set. +- Current safest read: `frame 0` is the only state that participates in the automatic `enterFastArea` spawn path, while `frame 1` skips that hook and is therefore more likely to be used in paired or externally signaled setups. +- `mapNum` is not consistently populated across `0x04D0` objects. Some records carry a non-zero map value and others leave it at `0`, so the field is probably contextual control data rather than a universal NPC selector. +- Within that contextual control data, bit `0x08` is now evidence-backed as an `auto-enter disabled` flag for the `MONSTER.enterFastArea` lane. +- `quality` is also not specific to the DTABLE row. For example, `quality = 1285` shows up on unrelated non-`0x04D0` shapes in the exported scenes, so that value should not be read as proof of a particular NPC identity. +- `quality` low byte still does not look like the primary `spawn immediately vs wait` control. The current exported scripts do not use it in `MONSTER.enterFastArea`, although Regret `ALARMHAT` does compare nearby `0x04D0` `Item.getQLo(...)` values against difficulty lanes `0/1/2` before equipping those helpers. +- DTABLE row `0` is named `Crusader`, but the open-source engine does not use DTABLE row `0` to bootstrap the player. ScummVM's `CruGame::startGame()` takes the main actor stats from `getNPCDataForShape(1)`, while the generic Crusader actor-creation path accepts `npcNum = 0` as an ordinary DTABLE index. +- Exported scene data shows a repeatable authored pattern where a `0x04D0` frame `0` record with `npcNum = 0` is colocated with a frame `1` record carrying the non-zero NPC row. Example pairs include exported Remorse map 246 and map 9, where the frame `0` record stays at `npcNum = 0` while the frame `1` partner carries rows `8` and `2` respectively. +- Current working model: `npcNum = 0` on `0x04D0` is a real authored state, but not strong evidence that the object literally means "spawn the player". It is safer to present it as DTABLE row `0` with a caution note than to relabel it as a special player-only sentinel. + +### `0x04B1` + +- `0x04B1` is catalogued as an editor object in both games. +- In the recovered usecode exports, `TRIGGER.slot_20` iterates nearby `shape=0x04B1` items, compares `Item.getQLo(item)` against a base-link id, then branches on `Item.getMapNum(item)` flag bits before dispatching more trigger logic. +- That makes `0x04B1` look like a trigger/link controller object rather than a plain NPC-row selector. + +Current conclusion: `0x04B1` does use the standard item fields, including `mapNum` and low-quality link data, but this pass did not find evidence that its `npcNum` byte should be decoded through DTABLE/NPCDat. The renderer should keep showing the raw fields, not an inferred NPC name. + +### `0x0011` + +- `0x0011` is catalogued as an egg-side editor trigger shape in the public renderer catalogs. +- The usecode export corpus references `0x0011` in several trigger-oriented constant sets, but this pass did not recover a clean DTABLE/NPCDat correlation for that shape. +- The current evidence is therefore weaker than for `0x04D0` and does not support treating `0x0011` as just another DTABLE NPC spawner. + +Current conclusion: `0x0011` should continue to display its raw `npcNum` field for inspection, but not receive automatic DTABLE name resolution unless later RE work proves the mapping. + +## Recovered No Remorse Examples + +Direct extraction from `STATIC/DTABLE.FLX` produced these representative rows: + +| npcNum | Name | Shape | +| --- | --- | --- | +| 4 | `GUARD` | `0x02fd` | +| 6 | `Observer` | `0x033c` | +| 10 | `Thermatron` | `0x0338` | +| 15 | `EliteStormTrooper` | `0x04d1` | +| 19 | `Vetron` | `0x04e6` | +| 33 | `FemaleOfficeWorker` | `0x0597` | + +The original user hunch was effectively correct: No Remorse entry `6` is an otherwise obscure NPC that uses shape `0x033c`. The recovered DTABLE name for that row is `Observer`. + +## Recovered No Regret Differences + +No Regret keeps the same storage scheme but changes several rows: + +| npcNum | Name | Shape | +| --- | --- | --- | +| 4 | `LMC Guard` | `0x0308` | +| 6 | `HQ Guards` | `0x057a` | +| 14 | `LMC Roll Out` | `0x05f0` | +| 30 | `Colonel Shepherd` | `0x0463` | +| 35 | `RoboDraygon` | `0x05b1` | +| 38 | `Cryotron` | `0x05e2` | + +Because the public renderer supports both games, the UI lookup is keyed by game id rather than assuming a single shared NPC table. + +## Relationship To Monster Eggs + +These `0x04D0` NPC spawners are related to monster eggs only in the broad sense that both can result in actor creation. + +They are not the same data path. + +- The existing egg investigation showed that Crusader monster eggs use the egg-family path where the monster id is derived from `mapNum >> 3`. +- The `0x04D0` spawner path instead uses the item's `npcNum` byte as a DTABLE/NPCDat record index. +- Remorse `0x024F` frame `0` monster eggs appear to bridge those two worlds: they are still family `7` eggs, but exported scene data shows that they can also carry a non-zero `npcNum` that matches a useful DTABLE row for preview and inspection. +- That means a renderer should not label `0x04D0` editor objects as monster eggs or try to decode their `npcNum` through egg-family rules. +- `0x0011` remains in the broader egg/editor lane, but this pass did not find evidence that its `npcNum` field reuses the `0x04D0` DTABLE path. + +Current safest model: + +- monster eggs = egg-family object with monster id packed through the egg fields +- `0x024F` frame `0` monster eggs in Remorse = family `7` eggs that also expose a useful DTABLE-backed `npcNum` for preview +- `0x04D0` NPC spawners = editor objects pointing into DTABLE/NPCDat rows + +Current practical difference between the two monster-spawn styles: + +- `0x04D0` is the more explicit editor/controller spawner path. It carries larger visible editor-object state, shows paired frame behavior, and matches the recovered DTABLE helper cluster directly. +- `0x024F` is the egg-family monster spawn path. In Remorse frame `0`, it still exposes enough `npcNum` information to recover the spawned NPC for renderer preview, but it remains an egg-trigger object rather than the broader `0x04D0` controller form. + +## Renderer Change + +The tooltip now resolves recovered DTABLE metadata by game id and shows, for confirmed DTABLE-backed shapes: + +- raw `npcNum` +- recovered DTABLE name when known +- DTABLE spawn shape when known +- a short frame note for `0x04D0` items so frame `0` vs `1` stays visible during inspection +- a decoded activation summary for `0x04D0` showing the current best read of `frame` plus `mapNum & 0x08` + +For editable fixed-record `0x04D0` items, the inspector now also exposes two evidence-backed export controls: + +- `Spawner frame`: switches between the `frame 0` enter-area checked state and the `frame 1` skip-enter-area state +- `Enter-area lane`: clears or sets `mapNum` bit `0x08`, which is the verified automatic-spawn suppression bit used by `MONSTER.enterFastArea` + +The side panel now also exposes a dedicated `Monster Spawners` audit list for `0x04D0` records, including a filter for the `auto-enter blocked` subset. Clicking an entry centers and pins that spawner so its raw fields and editable controls can be audited quickly. + +The viewport's `Show verified link arrows` overlay now draws two evidence-backed link families: + +- teleport eggs point from teleporter eggs to teleport destinations that share the same teleport ID +- focused `0x04D0` items draw dashed arrows to nearby opposite-frame `0x04D0` candidates that share the same low-quality link key, reflecting the current paired-spawner hypothesis without claiming a stronger global linkage than the usecode proves + +Current script-side corroboration for external `0x04D0` signaling is broader than `ALARMHAT` alone. The extracted public pseudocode also shows `ITEM.slot_2D`, `FUSPAC.slot_01 use`, and `MISS8.slot_20` scanning nearby `0x04D0` objects and keying off frame plus `Item.getQLo(...)`, which is why the renderer treats the low-quality byte as a local signal key rather than a guaranteed direct object pointer. + +The lookup is no longer intended to be hand-maintained. `src/generate-npc-spawner-data.js` now extracts both games' rows from `STATIC/DTABLE.FLX` and `STATIC_REGRET/DTABLE.FLX` and writes the generated JSON file into the renderer cache at `.cache/npc-spawner-data.generated.json`. + +The frontend consumes that JSON through `src/public/npc-spawner-data.js`, so the runtime data file is plain generated content rather than JavaScript codegen. + +When a valid DTABLE row is present, the viewport renders a semitransparent blue preview of the target NPC shape above every visible eligible spawner whenever editor objects are visible. Hovered or pinned spawners are still drawn slightly stronger, but preview ghosts are no longer hover-only. The current renderer enables this for: + +- `0x04D0` DTABLE-backed editor spawners +- `0x024F` frame `0` Remorse monster eggs that carry a non-zero `npcNum` + +The current renderer uses frame `0` for NPC previews by default, except for `Observer`, which is forced to frame `0x00F` because the earlier frames are blank/broken in the retail assets. + +Representative exported scene pairs: + +- Remorse map 246: frame `0` item `item:162` uses `npcNum = 0`, `mapNum = 8`, `quality = 256`, while colocated frame `1` item `item:163` uses `npcNum = 8` with the same quality. +- Remorse map 9: frame `0` item `item:338` uses `npcNum = 0`, `mapNum = 0`, `quality = 1829`, while colocated frame `1` item `item:339` uses `npcNum = 2`. +- The same frame-paired authoring pattern also appears in Regret exports, although the exact non-zero partner row differs by map. + +Serving paths now match the renderer modes: + +- dynamic mode serves the cached JSON through `/api/npc-spawner-data` +- static export copies the cached JSON to `site/data/npc-spawner-data.json` and points `site-config.json` at that exported file + +Current regeneration paths: + +- `npm run generate-npc-data` +- `npm run build-cache` +- `npm run export-static` + +Examples: + +- No Remorse `npcNum 6` now displays as `6 (Observer)` with NPC shape `0x033c` +- No Regret `npcNum 35` resolves to `RoboDraygon` with NPC shape `0x05b1` + +## Remaining Uncertainty + +- This note closes where the `0x04D0` NPC list lives and how to recover names, but it does not yet prove every gameplay path that can instantiate those DTABLE rows. +- `0x04B1` has strong trigger/link evidence but still needs a fuller write-up tying its item fields to specific map-editing behavior. +- `0x0011` is still only partially characterized here; it is clearly in the egg/editor lane, but its relationship to `npcNum` remains unresolved. +- Shape `0x04D0` still uses the `MONSTER` usecode class in the old disassembly corpus, so there is still room to document how that script/controller layer cooperates with the DTABLE-backed actor creation path. + +## TODO + +- Do a deeper pass on `0x04B1` and `0x0011` so the raw `npcNum` field can be documented more precisely without overfitting DTABLE assumptions. \ No newline at end of file diff --git a/docs/map_renderer/vue-refactor-plan.md b/docs/map_renderer/vue-refactor-plan.md new file mode 100644 index 0000000..7259694 --- /dev/null +++ b/docs/map_renderer/vue-refactor-plan.md @@ -0,0 +1,281 @@ +# Vue Refactor Plan + +## Purpose + +Refactor the map renderer from a large vanilla JavaScript application into a Vue application while preserving its two deployment modes: + +- Static mode for GitHub Pages and other read-only deployments +- Dynamic local mode for catalog editing and local data updates + +The refactor should reduce the size and complexity of the current `src/public/app.js` entrypoint without breaking the existing viewer behavior, static export workflow, or catalog editing workflow. + +## Current Baseline + +The renderer already has a useful split between source files and deployment artifacts: + +- `src/public/app.js` currently orchestrates most of the browser app. +- `src/public/map-catalog-ui.js`, `src/lib/catalog.js`, and related modules already isolate some catalog logic. +- `site/` contains the committed static bundle used for GitHub Pages. +- `package.json` already exposes separate static and dynamic scripts. +- The root README already documents static versus dynamic usage. + +That means the migration should be an incremental extraction, not a from-scratch rewrite. + +## Non-Negotiable Requirements + +1. Keep a static deployable build that can run from committed artifacts with no file-system write capability. +2. Keep a dynamic local build that can edit the Catalog and write changes back to disk. +3. Preserve the existing viewer workflow during migration so the app remains usable at every step. +4. Keep catalog editing opt-in and unavailable in static deployments. +5. Avoid coupling the UI framework change to data format changes unless a boundary must move for architectural reasons. + +## Target Architecture + +The Vue refactor should split the app into four layers: + +1. App shell and routing-like mode selection +- Owns top-level mode detection: static versus dynamic. +- Chooses the correct feature set, status messages, and edit affordances. +- Remains thin and delegates real work to feature components and composables. + +2. View components +- Replace the current procedural DOM wiring with Vue components for the map controls, viewport, catalog panel, tooltips, modal editor, and export actions. +- Keep components small and purpose-specific. +- Prefer composition over a single mega component. + +3. Composables and state services +- Move map selection, build triggers, UI flags, and interaction state into composables or store-like modules. +- Keep business rules out of templates. +- Preserve existing helper modules where they already work. + +4. Data access adapters +- Introduce a strict boundary between read-only data access and writable catalog access. +- Static mode uses read-only adapters only. +- Dynamic mode uses writable adapters for catalog updates and local server APIs. + +## Mode Model + +The app should continue to behave as one codebase with two runtime modes. + +### Static Mode + +- Serves prebuilt assets from `site/` or equivalent deployed output. +- Allows viewing, filtering, inspecting, and downloading data. +- Does not expose any actions that would write to disk or call write-enabled server endpoints. +- Can still show the Catalog UI if the data is available, but all editing controls must be removed or disabled. + +### Dynamic Mode + +- Runs against the local Node server. +- Can edit Catalog data through the UI. +- Can write CSV updates to disk. +- Can refresh or rebuild derived data as needed after edits. +- Must preserve the same viewer experience as static mode wherever the data model overlaps. + +## Proposed Migration Phases + +### Phase 0: Freeze the boundary + +Goal: identify the stable interfaces before moving UI code. + +- Inventory the current `app.js` responsibilities. +- Group code into categories: rendering, state mutation, map loading, catalog updates, overlays, modals, downloads, and notifications. +- Identify the minimum data contracts between the viewer, catalog, and scene APIs. +- Decide which existing helper modules stay unchanged and which become composables or services. + +Deliverable: + +- A written boundary map for the current app and a component breakdown for Vue. + +### Phase 1: Scaffold Vue without changing behavior + +Goal: get Vue running while preserving the current app. + +- Create a Vue 3 application shell. +- Move the current page layout into Vue root components. +- Keep the existing data modules and API helpers in place. +- Mount the viewer in Vue but continue using the current scene and catalog logic. +- Add a compatibility layer so existing DOM-driven utilities can be replaced one section at a time. + +Deliverable: + +- The app loads through Vue, but functionality remains equivalent to the current version. + +### Phase 2: Split the UI into feature components + +Goal: remove the largest chunks of imperative DOM code. + +- Break the viewer into components such as header/control bar, map selector, viewport, catalog panel, export area, status area, and editor modal. +- Move local UI state into Vue reactive state or composables. +- Replace direct DOM updates with props, emits, and computed state. +- Keep the map rendering and scene logic isolated so the UI migration does not change map semantics. + +Deliverable: + +- The main app flow no longer depends on a monolithic procedural entrypoint. + +### Phase 3: Formalize static and dynamic adapters + +Goal: separate read-only rendering from writable editing behavior. + +- Introduce a read-only adapter for static deploys. +- Introduce a writable adapter for the local Catalog editor. +- Make the app choose adapters based on mode, not scattered conditionals. +- Ensure static mode cannot accidentally call writable endpoints. +- Ensure dynamic mode can still perform all current editor actions. + +Deliverable: + +- The same Vue UI can run in both modes without leaking write capability into static builds. + +### Phase 4: Migrate Catalog editing carefully + +Goal: preserve catalog edit power while moving to Vue. + +- Port the current catalog editor interactions into Vue components. +- Keep edit forms, validation, and confirmation behavior intact. +- Preserve undo or session history behavior if it exists in the current app. +- Verify that write operations remain local-only and mode-gated. +- Confirm that static builds either hide the edit UI or render it inert. + +Deliverable: + +- Catalog editing works in dynamic mode and is unreachable in static mode. + +### Phase 5: Clean up the old entrypoint + +Goal: remove dead code and simplify maintenance. + +- Delete or shrink the legacy procedural bootstrap code only after feature parity is reached. +- Move any remaining helpers into reusable modules or composables. +- Remove duplicate state management paths. +- Keep the public API surface stable where external scripts or tests depend on it. + +Deliverable: + +- Vue owns the app; the old entrypoint is no longer the main coordination layer. + +## Suggested Component Breakdown + +The exact component names can change, but the refactor should likely include: + +- AppShell: top-level mode detection, configuration, and page layout. +- MapSelector: map and game selection, navigation, and load triggers. +- ViewerViewport: canvas or scene host, pointer handling, and zoom state. +- EditorToolbar: view toggles, overlays, and map display controls. +- CatalogPanel: catalog browsing, download buttons, and edit affordances. +- CatalogEditModal: edit form and validation. +- StatusBar: loading, build, and error feedback. +- TooltipOverlay: pinned or hover inspection UI. +- DownloadActions: export buttons and static bundle downloads. + +## Data and State Boundaries + +The refactor should make these boundaries explicit: + +- Scene loading state: selected map, build progress, current assets, and error state. +- View state: zoom, pan, overlays, tooltip pinning, and selection. +- Catalog state: active game, catalog entries, edit permissions, and pending writes. +- Environment state: static versus dynamic mode, feature flags, and API base URLs. + +Rule of thumb: + +- If state is shared across multiple UI regions, it belongs in a composable or store. +- If state only matters inside one panel or modal, keep it local to that component. + +## Static Build Plan + +The static build must remain a first-class deployment target. + +- Keep the committed site output deployable without server writes. +- Make the Vue build emit a static artifact suitable for GitHub Pages. +- Ensure all catalog editing UI is absent or disabled in the static bundle. +- Keep download links and read-only inspection available. +- Preserve the existing export workflow so the static bundle can be regenerated from local source assets. + +## Dynamic Build Plan + +The dynamic build must preserve local editing capability. + +- Keep the local server as the source of truth for writable catalog changes. +- Preserve file write paths and validation rules. +- Continue to support local refresh or rebuild behavior after edits. +- Keep the editing workflow explicit so the writable mode cannot be mistaken for the static deploy. + +## Suggested Repo Changes + +The migration will probably require these changes: + +- Introduce a Vue source directory under `map_renderer/src` or a sibling frontend directory. +- Add a Vue build pipeline and update package scripts. +- Split the current DOM utility modules into composables, services, and small components. +- Add a mode/config module that clearly states whether the app is static or dynamic. +- Update export scripts so the static site still writes the correct committed artifacts. +- Update the README with the new build and deployment flow once the migration is stable. + +## Risks + +- The biggest risk is mixing UI migration with behavior changes and losing parity. +- The second risk is accidentally allowing edit controls into the static bundle. +- The third risk is over-centralizing state in one large Vue store and recreating the same maintainability problem in a new framework. +- The fourth risk is changing the export pipeline before the static and dynamic modes are fully separated. + +## Acceptance Criteria + +The refactor is complete when all of the following are true: + +1. The app runs as a Vue application. +2. The static bundle still deploys and remains read-only. +3. The dynamic local build still supports Catalog editing and writes to disk. +4. The main viewer flows match the current behavior closely enough that no feature regression is visible in normal use. +5. The old procedural entrypoint is no longer the primary app coordinator. +6. The codebase is easier to extend because UI, state, and data access are separated. + +## Recommended Order of Work + +1. Inventory the current app responsibilities and define component boundaries. +2. Scaffold Vue and mount the existing app behind it. +3. Extract the largest UI regions into Vue components. +4. Introduce explicit static and dynamic data adapters. +5. Port catalog editing into Vue while keeping write capability local-only. +6. Remove the leftover procedural bootstrap code. +7. Update the docs and deployment instructions. + +## Concrete Implementation Checklist + +### Phase 1 Checklist + +1. Add Vue 3 and Vite dependencies to the renderer package. +2. Add Vite scripts for development and production builds without removing the existing Node server scripts. +3. Create a new Vue entrypoint that mounts a root app shell into the current page layout. +4. Keep the existing static HTML usable during the transition by preserving the current shell structure and mount target. +5. Split the top-level UI into a Vue root component plus a small compatibility layer for existing state and API helpers. +6. Keep read-only viewer behavior intact during the initial scaffold so the app still loads maps exactly as before. +7. Confirm that static mode still hides all write-capable catalog controls. +8. Confirm that dynamic mode still exposes catalog-edit affordances after the Vue shell is in place. + +### Phase 1 Exit Criteria + +1. The renderer can be built and served through Vue/Vite. +2. The current viewer still loads and renders maps. +3. The static deployment path remains read-only. +4. The dynamic deployment path remains capable of catalog editing. +5. The old entrypoint is no longer the only place that owns page-level structure. + +### Phase 1 Progress + +- Vue 3 and Vite scripts have been added to the renderer package. +- A Vue shell now renders the existing viewer DOM structure. +- The Vue shell loads the legacy browser app after mount so the current viewer logic remains active. +- The Vue production build completes successfully. +- The local dev and admin launchers now wait for the Vue build output and then start the server on the Vue-preferred path. + +### Phase 2 Progress + +- The Vue shell has been split into separate shell components for the side panel, viewport, and egg editor modal. +- The root Vue app now composes those feature components instead of keeping the entire shell in one template file. +- The default local runtime path now serves the Vue build when it exists, so the componentized shell is the main entry for dev and admin modes. + +## Final Notes + +The best outcome here is not a perfect one-shot rewrite. It is a controlled migration that keeps the current app working, makes the static and dynamic deployment split explicit, and steadily moves the renderer toward a maintainable Vue architecture. diff --git a/docs/psx/prealpha.md b/docs/psx/prealpha.md new file mode 100644 index 0000000..325bbe9 --- /dev/null +++ b/docs/psx/prealpha.md @@ -0,0 +1,240 @@ +# Crusader 2 Pre-Pre Alpha (PlayStation) Recon + +## Scope + +- Target disc tree: `E:\emu\psx\Crusader 2 Pre-Pre Alpha` +- Active Ghidra program for this pass: `/psx/prealpha/SLUS_002.68` +- Comparison baseline: retail PlayStation `Crusader: No Remorse` findings in `docs/psx/psx.md` +- Goal of this pass: identify concrete differences from the released PSX build and record any interesting early-build leftovers visible in the executable and disc layout. + +## Immediate Conclusions + +- This pre-alpha does **not** currently look like a fully distinct `Crusader 2` executable identity. +- The executable still carries direct `Crusader: No Remorse` branding and other No Remorse-facing UI text. +- The level-loader code is already very close to the retail PSX loader: it still embeds all seven `\LSETn\L` prefixes and the same threshold split at map indices `10/20/30/40/50/60`. +- The disc content is dramatically reduced compared with retail: only `3` shipped level bundles, `1` XA file, no shipped movie `.STR` files, and no `LICENSEA.DAT` or `ZZZ.ZZZ` root files. +- The executable still retains content/system references that do not match the current unpacked pre-alpha disc, including `\AUDIO\TALK1.XA;1` and a `LoadExec` helper for `MENU.EXE`, `ENGINE.EXE`, and `PSX.EXE`. +- Current safest read: this build looks more like an earlier trimmed branch of the No Remorse PSX code/content pipeline than a clearly rebranded or content-rich standalone `Crusader 2` PSX build. + +## Disc Tree Differences From Retail PSX + +Top-level inventory contrast from the unpacked trees: + +| Area | Retail `Crusader: No Remorse` | Pre-pre alpha | Current read | +|---|---:|---:|---| +| `SLUS_002.68` size | `675,840` bytes | `667,648` bytes | pre-alpha executable is smaller by `8,192` bytes | +| `.WDL` files | `66` | `7` | heavy content reduction | +| `.STR` files | `33` | `0` | no shipped movie streams in the pre-alpha tree | +| `.XA` files | `2` | `1` | only `MULTI8.XA` remains | +| `LSET` folders | `LSET1` through `LSET7` | `LSET1` only | only `L0.WDL`, `L1.WDL`, `L2.WDL` shipped | +| `MOVIES/` contents | populated | empty | folder exists but no `.STR` payloads | +| root extras | `LICENSEA.DAT`, `ZZZ.ZZZ` present | both absent | pre-alpha root is much leaner | + +Pre-alpha top-level tree at this point: + +- `AUDIO/MULTI8.XA` +- `FMV.BIN` +- `LEGAL.SCR` +- `LSET1/L0.WDL` +- `LSET1/L1.WDL` +- `LSET1/L2.WDL` +- `MENUS/M13.WDL` +- `MENUS/M21.WDL` +- `MENUS/M5.WDL` +- `SLUS_002.68` +- `SPEC_A.WDL` +- `SYSTEM.CNF` + +Important contrast with retail: + +- retail ships `62` level bundles across `LSET1..LSET7` +- this pre-alpha tree currently ships only `3` level bundles in `LSET1` +- retail ships `33` movie streams; this pre-alpha has an empty `MOVIES/` folder +- retail ships `MULTI8.XA` and `TALK1.XA`; this pre-alpha tree currently exposes only `MULTI8.XA` + +## Executable Findings + +### 1. Executable identity still says `No Remorse` + +The strongest branding strings in `/psx/prealpha/SLUS_002.68` still point at the first game, not a visible `Crusader 2` identity. + +Relevant strings: + +- `80061d08`: `Crusader: No Remorse (save# ` +- `80010944`: `This is no time to show Remorse! ... Are you sure you want to Quit?` + +Negative checks from this pass: + +- no recovered `Crusader II` string +- no recovered `Regret` string +- no recovered alternate save-title branding + +Current safest read: + +- at least at the executable/UI-string layer, this pre-alpha still looks branded as a No Remorse derivative rather than a separately named sequel build + +### 2. The level loader is already essentially retail-shaped + +Function `80038084` was renamed in Ghidra during this pass to `wdl_resource_bundle_load_by_index`. + +Why the rename is justified: + +- the function loads one of seven hardcoded level-path prefixes based on map-index thresholds +- it appends the decimal map index and the shared extension tail to form the final level path +- it also loads `\SPEC_A.WDL` during the same setup path + +Direct evidence: + +- `80010de0..80010e30` contains the contiguous prefix table: + - `\LSET1\L` + - `\LSET2\L` + - `\LSET3\L` + - `\LSET4\L` + - `\LSET5\L` + - `\LSET6\L` + - `\LSET7\L` +- `80010e34` contains `\SPEC_A.WDL` +- the decompiled threshold ladder in `wdl_resource_bundle_load_by_index` still splits on `9`, `0x13`, `0x1d`, `0x27`, `0x31`, and `0x3b`, which is the same practical `10/20/30/40/50/60` bucket logic previously closed in the retail PSX note + +Important contrast with the disc tree: + +- the code still expects the full seven-folder retail-style layout +- the current pre-alpha disc only ships `LSET1/L0..L2` + +This is one of the strongest current signs that the executable pipeline was still aligned with a much larger planned content set than the media actually present in this build. + +### 3. Mission and passcode scaffolding are still close to retail No Remorse + +Recovered strings show that the pre-alpha executable still preserves the same visible mission/passcode UI scaffolding seen in the retail PSX work. + +Relevant strings: + +- `800101a4..80010340`: `Mission Briefing ^Mission 1` through `Mission Briefing ^Mission 15` +- `80060b70`: `Congratulations! You have completed your mission. The passcode for the next mission is:` +- `80060bd4`: the alternate completion message without the visible passcode line +- `80060b50`: `BCDFGHJKLMNPQRSTVWXZ0123456789` + +Current read: + +- the same `15` mission-facing text slots are still present +- the same consonant/digit passcode alphabet is still present +- this does **not** look like a radically different mission-shell rewrite + +This pushes the current pre-alpha closer to `early/reduced No Remorse PSX branch` than to `already content-diverged sequel shell`. + +### 4. Audio and movie state looks incomplete relative to both retail code and the current disc + +The pre-alpha tree contains only one XA file: + +- `AUDIO/MULTI8.XA` + +But function `80045648` still contains the two-path XA switch logic: + +- param `0` selects `\AUDIO\MULTI8.XA;1` +- nonzero selects `\AUDIO\TALK1.XA;1` + +That function was annotated in Ghidra during this pass because the current unpacked disc does **not** contain `TALK1.XA`. + +Interesting consequence: + +- the executable still expects a second XA stream family that is absent from the current pre-alpha disc tree + +Movie side status is even more reduced: + +- `MOVIES/` exists but is empty +- no `.STR` files are present in the pre-alpha tree +- the main executable did **not** yield `FMV` or `MDEC` strings in this pass +- `FMV.BIN` still exists on disk, but the current main executable looks less movie-facing than retail at the string level + +Current safest read: + +- the audio/movie pipeline was not fully stripped from code expectations, but the shipped pre-alpha disc content is notably incomplete compared with retail + +### 5. A split-executable `LoadExec` path still exists + +Function `80046aac` was not renamed yet, but it was comment-annotated in Ghidra during this pass. + +That helper selects one of three executable paths: + +- `cdrom:\ENGINE.EXE;1` +- `cdrom:\MENU.EXE;1` +- `cdrom:\PSX.EXE;1` + +Then it performs a PSX `LoadExec(...)` handoff after shutting down active systems. + +Important contrast with the current pre-alpha disc tree: + +- none of `ENGINE.EXE`, `MENU.EXE`, or `PSX.EXE` exist in the unpacked root +- only `SLUS_002.68` is present as the obvious boot executable + +Current safest read: + +- this build still preserves a real split-executable chainload helper from an earlier architecture or earlier content-layout plan +- the current unpacked disc no longer matches that design literally + +I did **not** yet promote a stronger functional name for `80046aac` because the surviving call sites were not fully classified in this pass. + +### 6. Content-name tables remain close to retail rather than showing obvious sequel-only replacements + +The nearby item/ammo/gun tables are broadly familiar from the retail PSX note. + +Recovered examples: + +- ammo table still includes `JL-2 AMMO`, `AR-7 AMMO`, `GL-303 AMMO`, `RP-22 AMMO`, `SG-A1 AMMO` +- item table still includes `INHIBITOR`, `CREDITS`, `SCI PLANS`, `BLAST PAC`, `DET PAC`, `DATA LINK`, `LAND MINE`, `SPIDER BOMB`, `MEDICAL KIT`, `ENERGY CUBE`, `FUSION PAC`, `CHEMICAL BATTERY`, `FISSION BATTERY`, `FUSION BATTERY`, `GRAVITON GENERATOR`, `IONIC GENERATOR`, `PLASMA GENERATOR` +- gun table still includes `RP-16`, `RP-22`, `RP-32`, `SG-A1`, `AC-88`, `PA-31`, `EM-4`, `PL-1`, `UV-9`, `GL-303`, `AR-7`, `JL-2`, `JL-9` + +Current read: + +- the visible catalog tables are still basically in the retail No Remorse family +- this pass did **not** surface any obviously new `Crusader 2`-specific naming layer in the executable text + +### 7. Developer-facing PSYQ graphics/debug strings are still present + +This is not necessarily unique to the pre-alpha, but it is worth preserving because it may help later graphics-focused passes. + +Recovered strings include: + +- `ResetGraph(%d)...` +- `SetGraphReverse(%d)...` +- `SetGraphDebug:level:%d,type:%d reverse:%d` +- `LoadImage` +- `StoreImage` +- `MoveImage` + +The recovered function `SetGraphDebug` simply stores the requested debug level and prints the diagnostic line when nonzero. + +Current practical value: + +- if later PSX rendering work needs debug/graphics control anchors, these strings and helpers are already easy to relocate in the pre-alpha database + +## Interesting Build-Level Implications + +The combined disc-plus-executable picture currently supports a fairly specific interpretation. + +Most likely current model: + +1. the pre-alpha executable is still largely a No Remorse-derived PSX codebase +2. the content payload is heavily reduced compared with retail +3. some earlier architectural leftovers survived into this build, especially the split-`LoadExec` helper and the missing-file `TALK1.XA` path +4. the loader still expects a much larger planned level inventory than the current disc actually ships + +That does **not** yet prove there is no meaningful `Crusader 2` gameplay/content divergence hidden deeper in the WDL data or untyped runtime tables. It does mean the first clean static answer is: this build is still much closer to `unfinished No Remorse PSX branch with reduced assets` than to an already distinctively rebranded sequel executable. + +## Ghidra Updates From This Pass + +Applied in the live `/psx/prealpha/SLUS_002.68` database: + +- renamed `80038084` to `wdl_resource_bundle_load_by_index` +- added a disassembly comment at `80046aac` documenting the `LoadExec` targets `MENU.EXE`, `ENGINE.EXE`, and `PSX.EXE` +- added a disassembly comment at `80045648` documenting the `MULTI8.XA` vs `TALK1.XA` selection and the current missing-file mismatch + +## Highest-Value Next Steps + +1. Decompile and classify the callers around `80046aac` so the surviving `MENU.EXE` / `ENGINE.EXE` / `PSX.EXE` path can be labeled as boot flow, frontend transition, or dead leftover with less ambiguity. +2. Compare the pre-alpha `L0.WDL`, `L1.WDL`, and `L2.WDL` structure against the retail `LSET` extractor results to see whether they are just reduced No Remorse maps or genuinely divergent content/layout revisions. +3. Diff the pre-alpha `SPEC_A.WDL` and `MENUS/*.WDL` files against the retail PSX note to see whether the menu/front-end assets changed more than the executable strings did. +4. Trace the mission-briefing and passcode consumers directly in `/psx/prealpha/SLUS_002.68` to see whether the pre-alpha still uses the same mission ordering and password-generation rules as retail. +5. Search the pre-alpha executable for early script/event-dispatch tables or type/resource tables that differ from the retail PSX resource-stream model, especially around the WDL loader outputs. +6. Inspect `FMV.BIN` separately in Ghidra or as raw data to determine whether it still contains movie-system code/data even though the current disc ships no `.STR` files. +7. Run a first asset-focused comparison pass on the three shipped pre-alpha maps in the public renderer/export tooling once the bundle/resource bindings are stable enough to avoid the earlier invalid direct-bundle hypothesis. \ No newline at end of file diff --git a/docs/psx/psx.md b/docs/psx/psx.md new file mode 100644 index 0000000..ec7ac49 --- /dev/null +++ b/docs/psx/psx.md @@ -0,0 +1,806 @@ +# Crusader: No Remorse (PlayStation) Recon + +## Scope + +- Target disc tree: `E:\emu\psx\Crusader - No Remorse` +- Goal of this pass: identify the boot executable, separate likely code from content, and find the most practical first extraction routes for PS1 assets. + +## Immediate Conclusions + +- `SYSTEM.CNF` is the disc boot file and points directly at `cdrom:\SLUS_002.68;1`. +- `SLUS_002.68` is the main game executable. It begins with a valid `PS-X EXE` header. +- No other top-level file currently looks like a second normal PS1 executable. +- Disc content is dominated by standard PS1 media (`.STR`, `.XA`) plus a large number of game-specific `.WDL` blobs. +- `FMV.BIN` looks like movie-playback support data or a resource blob, not a bootable executable. +- `ZZZ.ZZZ` looks much more like media/container data than code, and its size exactly matches `MOVIES/FMV3.STR`. + +## Disc Boot Evidence + +`SYSTEM.CNF` contents: + +```ini +BOOT = cdrom:\SLUS_002.68;1 +TCB = 4 +EVENT = 10 +STACK = 801FFFFC +``` + +`SLUS_002.68` header evidence: + +- Magic: `PS-X EXE` +- Initial PC: `0x8004BD90` +- Load address: `0x80010000` +- Image size: `0x000A4800` (`675,840` bytes) + +This is the clearest Ghidra import candidate for code analysis. + +## Top-Level File Classification + +Top-level items: + +- `SLUS_002.68` +- `SYSTEM.CNF` +- `FMV.BIN` +- `ZZZ.ZZZ` +- `SPEC_A.WDL` +- `LEGAL.SCR` +- `LICENSEA.DAT` +- `AUDIO/` +- `MOVIES/` +- `MENUS/` +- `LSET1/` through `LSET7/` + +Recursive extension summary from the extracted disc tree: + +| Extension | Count | Total bytes | Current classification | +|---|---:|---:|---| +| `.STR` | 33 | 415,027,744 | PS1 movie streams | +| `.XA` | 2 | 91,897,856 | PS1 XA audio | +| `.WDL` | 66 | 76,198,860 | custom game asset/level blobs | +| `.ZZZ` | 1 | 26,148,984 | likely media/container data | +| `.68` | 1 | 675,840 | main PS1 executable | +| `.SCR` | 1 | 153,600 | data asset | +| `.BIN` | 1 | 90,812 | support/resource blob | +| `.DAT` | 1 | 28,032 | data asset | +| `.CNF` | 1 | 70 | boot config | + +## File Family Findings + +### 1. `SLUS_002.68` + +- This is the boot target from `SYSTEM.CNF`. +- It has a normal PS1 executable header. +- It should be the first import into Ghidra. +- Current working assumption: this is the only primary native code binary on the disc. + +### 2. `AUDIO/*.XA` + +- Files found: + - `AUDIO/MULTI8.XA` + - `AUDIO/TALK1.XA` +- These are standard PS1 XA audio files. +- `MULTI8.XA` is divisible by both `2352` and `2048`, which is consistent with sector-oriented media data. +- `TALK1.XA` is divisible by `2048` but not exactly by `2352`. +- Most practical extraction route: use standard PS1/XA tooling rather than custom RE first. + +### 3. `MOVIES/*.STR` + +- Files found: `FMV0.STR` through `FMV32.STR`. +- These are the strongest candidates for standard PS1 video streams. +- The raw headers look consistent with sectorized PS1 stream data rather than executable code. +- Most practical extraction route: treat them as PS1 STR video and run them through PS1 media tooling first. + +### 4. `FMV.BIN` + +This file does not look like a normal executable. + +First bytes begin with: + +```text +\MOVIES\FMV%d.STR +MDEC_rest:bad option(%d) +MDEC_in_sync +MDEC_out_sync +DMA=(%d,%d), ADDR=(0x%08x->0x%08x) +FIFO=(%d,%d),BUSY=%d,DREQ=(%d,%d),RGB24=%d,STP=%d +``` + +Current best read: + +- `FMV.BIN` is movie-related support data, code tables, or debug/resource text for the MDEC/FMVs. +- It clearly references the external movie path pattern `\MOVIES\FMV%d.STR`. +- It is worth a secondary Ghidra import only if the goal is to understand the movie subsystem specifically. +- It is not the disc boot executable. + +### 5. `ZZZ.ZZZ` + +Key findings: + +- Size: `26,148,984` bytes +- That size exactly matches `MOVIES/FMV3.STR`. +- The file begins with stream-like binary data rather than an executable header. +- It also yielded movie-adjacent string evidence such as `MDEC`. + +Current best read: + +- `ZZZ.ZZZ` is probably not code. +- It is a strong candidate for either: + - a renamed movie stream, or + - a duplicate/alternate copy of `FMV3.STR` + +Most practical next check: + +1. compare a few sectors or hashes against `MOVIES/FMV3.STR` +2. try opening `ZZZ.ZZZ` directly in PS1 STR-capable tooling + +### 6. `LSET*/L*.WDL` + +These are the most important unknown asset family for content extraction. + +Representative level sample: `LSET1/L0.WDL` + +- Size: `1,312,624` bytes +- Header starts with structured values, not raw pixels: + +```text +0x00000034 0x00006FDC 0x0000376C 0x00001000 +0x00000160 0x00000498 0x0000025C 0x00000FE0 +0x00000070 0x00072EC4 0x00034B6C 0x00007448 +0x0007407C 0x00010824 0x00000002 0x00000000 +``` + +- This does not behave like a flat framebuffer dump. +- It looks more like a custom structured level/container blob with internal offsets, lengths, or section pointers. +- Additional offset targets inside the file, such as `0x376C`, `0x6FDC`, and `0x10824`, land on repeating structured records rather than code. + +Strict TIM-style scan results for `L0.WDL` found plausible embedded PS1 image headers at: + +- `0xE7A84` +- `0x117DEC` +- `0x12CECC` +- `0x135F18` +- `0x1369F4` +- `0x136B38` +- `0x136C40` + +Current best read: + +- `LSET*.WDL` likely holds mixed level resources. +- At least some of those resources may include standard embedded PS1 TIM-like image blocks. +- These files are the strongest current target for a custom extractor. + +Executable-guided extraction status: + +- `lset_level_bundle_load` in the imported PSX executable now confirms the executable builds `\LSETn\Lx.WDL` paths directly and treats those files as the live level-bundle format. +- The same loader reads a small level header blob first, then a large SPU/audio blob, then dispatches the remaining level resource stream through `level_resource_stream_load`. +- `image_resource_bind_vram_slot` and `image_bundle_load_to_vram` show that resource types `4` and `5` are image/sprite-oriented resources: they resolve VRAM placement and upload image data through `LoadImage`. +- `sprite_rle_decode_rows` is now confirmed as the row-based decompressor used when a type-5 frame record has its compressed bit set. +- Current consequence: sprite extraction now has a real executable-backed path, while map extraction has a reliable raw-carving path even though the full tile/object semantics are not decoded yet. + +### 7. `MENUS/*.WDL` and `SPEC_A.WDL` + +Representative menu sample: `MENUS/M13.WDL` + +- Size: `1,475,928` bytes +- Starts with dense repeating values like: + +```text +0x9D499D29 0x9D299D29 0x9D4A9D4A 0xA14A9D4A +0x9D49A14A 0x9D299D29 0x9D4A9D4A 0xA14A9D4A +``` + +Representative special sample: `SPEC_A.WDL` + +- Size: `545,424` bytes +- Starts with the same raw-looking pattern as `M13.WDL`. + +Current best read: + +- These do not begin with obvious pointer tables. +- They look more like raw or lightly wrapped image/screen asset data than like level containers. +- `M13.WDL` had no strict TIM hits in the quick scan. +- `SPEC_A.WDL` did have a few plausible stricter TIM-style hits at: + - `0x449A8` + - `0x80ED8` + +So the `.WDL` family probably is not one single uniform format. Current evidence supports at least two subfamilies: + +- structured level/resource blobs (`LSET*/*.WDL`) +- raw-looking menu/special screen blobs (`MENUS/*.WDL`, `SPEC_A.WDL`) + +Executable-guided extraction status: + +- `SPEC_A.WDL` does not behave like the `LSET*.WDL` container family. +- The executable-backed extractor work currently treats it as a raw blob with embedded image candidates rather than as a contiguous section table. +- A validated carve on `SPEC_A.WDL` currently finds strict TIM-style hits at `0x1B5CC` and `0x80ED8`. + +## Executable-Backed Extraction Model + +These findings are now grounded in both file inspection and the imported `SLUS_002.68` executable. + +### Level bundles: `LSET*/*.WDL` + +Validated current extraction model for `LSET1/L0.WDL`: + +- top-level header size: `0x34` +- immediately following blob: `0x6FDC` bytes +- post-audio resource area starts at: `0x7010` +- high-confidence internal boundaries recovered from the header and validated with the extractor: + - `0x7448` + - `0x34B6C` + - `0x72EC4` + - `0x7407C` + +Current carved regions from `L0.WDL`: + +| Region | Offset | Size | Current interpretation | +|---|---:|---:|---| +| `audio_or_spu_blob` | `0x34` | `0x6FDC` | SPU/sequence data loaded by the audio init path | +| `post_audio_region_00` | `0x7010` | `0x438` | small table/directory block | +| `post_audio_region_01` | `0x7448` | `0x2D724` | strong map/placement candidate | +| `post_audio_region_02` | `0x34B6C` | `0x3E358` | strong map/placement candidate | +| `post_audio_region_03` | `0x72EC4` | `0x11B8` | small control/index block | +| `post_audio_region_04` | `0x7407C` | `0xCC6F4` | strongest current sprite/graphics bank candidate | + +Important consequence: + +- for map work, the best current extraction targets are `post_audio_region_01` and `post_audio_region_02` +- for sprite/graphics work, the best current extraction target is `post_audio_region_04` + +Important correction from the next executable pass: + +- a previously suspected text-like block in the broader PSX resource system is now confirmed separately in executable analysis as a menu/prompt text resource, not map data +- a heavily used level-side table is also now confirmed as a per-type flag/behavior table used by collision/order logic, not a raw map grid +- so the late-level extraction focus stays on `LSET*.WDL` post-audio regions, not on every large runtime table seen in the executable + +The validated strict TIM carver currently finds one confirmed embedded TIM block in `L0.WDL` at: + +- `0xBBA54` + +That hit lands inside `post_audio_region_04`, which supports treating the late large region as the current best graphics bank candidate. + +The same structure now reproduces on `LSET1/L1.WDL` too: + +- header size: `0x34` +- audio blob: `0x3244` +- post-audio start: `0x3278` +- high-confidence boundaries: `0x6F48`, `0x334D8`, `0x602C4`, `0x732D4` +- late graphics candidate region: `0x732D4 .. EOF` +- current strict TIM hit: `0xB4DC8` + +So the current working model is no longer based on just one level file: `LSET` bundles appear to share a stable pattern of: + +1. fixed `0x34` header +2. SPU/audio blob +3. several map/meta candidate regions +4. one large late graphics-oriented region + +What is still not stable yet: + +- the internal semantics of `post_audio_region_01` and `post_audio_region_02` are still unresolved +- `L0.WDL` starts with rows that look structured when viewed as `u16x6`, but `L1.WDL` does not preserve the same obvious interpretation at the same region boundary +- current safest reading is that these are still raw candidate map/meta payloads, not yet a decoded placement format + +### Menu / special blobs: `SPEC_A.WDL`, `MENUS/*.WDL` + +These currently behave like raw image-oriented blobs, not like the structured `LSET` family. + +Validated current extraction model for `SPEC_A.WDL`: + +- whole-file raw blob fallback works cleanly +- strict TIM hits currently validate at: + - `0x1B5CC` + - `0x80ED8` + +Representative secondary check on `MENUS/M13.WDL`: + +- whole-file raw blob fallback also works cleanly there +- current strict TIM hit validates at: + - `0x493EC` + +This keeps menus/special screens as a secondary image-carving problem instead of a map/container problem. + +## Working Extractor + +Current extractor script: + +- `tools/psx_extract_wdl.py` + +What it does right now: + +- recognizes the validated `LSET*.WDL` top-level layout +- carves the audio blob and header-directed post-audio regions +- scans the whole file for strict TIM blocks and extracts them +- falls back to raw-blob carving for `SPEC_A.WDL` / menu-like files +- emits an exploratory `u16x6` CSV view for the first post-audio LSET candidate region so raw row patterns can be inspected without claiming final semantics +- scans the large late LSET graphics region for type-5 sprite bundle headers +- decodes row-RLE compressed sprite frames and writes raw frame payloads plus grayscale preview images +- writes carved output under `out/psx_wdl//` + +Current practical usage: + +```powershell +c:/Users/Maddo/.PYENV/PYENV-WIN/versions/3.14.3/python.exe tools/psx_extract_wdl.py "E:/emu/psx/Crusader - No Remorse/LSET1/L0.WDL" +c:/Users/Maddo/.PYENV/PYENV-WIN/versions/3.14.3/python.exe tools/psx_extract_wdl.py "E:/emu/psx/Crusader - No Remorse/SPEC_A.WDL" +``` + +This is enough to start extracting: + +- raw map-candidate blocks from level bundles +- strict TIM sprite/image blocks from both level and menu/special blobs +- exploratory raw row exports for the first LSET post-audio candidate region +- actual extracted sprite frames from at least some type-5 bundles inside the late LSET graphics region + +Current caution: + +- the `u16x6` export is only a raw inspection aid +- `L0.WDL` gives structured-looking rows such as `0041,177B,0F7F,0000,0002,0020`, but `L1.WDL` shows very different values at the same relative region +- so this export should be treated as evidence-gathering for map decoding, not as a solved object-placement parser yet + +## Confirmed Sprite Extraction + +The extractor now produces actual sprite-frame outputs from at least part of the late LSET graphics bank. + +The late-graphics scan is now widened beyond the original first-32-bundle probe. Current `L0.WDL` extraction finds `159` candidate bundles in `post_audio_region_04`, and the larger-first overview now clearly includes not just floor/wall tiles but also several object/UI-like assets such as framed panels, cabinets, a portrait, a hand-shaped sprite, a bone, and other small pickup-like art. + +Confirmed current example from `LSET1/L0.WDL`: + +- graphics-region-relative bundle offset: `0xE5B8` +- whole-file bundle offset: `0x82634` +- mode: `2` (current best read: 4bpp indexed) +- frame count: `3` +- first extracted frame dimensions: `40 x 66` +- runtime default bundle palette index: `12` + +Confirmed output files: + +- raw frame bytes: `out/psx_wdl/L0/sprite_bundles/bundle_0000E5B8/frame_000.bin` +- preview image: `out/psx_wdl/L0/sprite_bundles/bundle_0000E5B8/frame_000.png` +- colored preview image: `out/psx_wdl/L0/sprite_bundles/bundle_0000E5B8/frame_000_color.png` +- colored sprite atlas: `out/psx_wdl/L0/sprite_bundles/bundle_0000E5B8/atlas_color.png` +- bundle metadata: `out/psx_wdl/L0/sprite_bundles/bundle_0000E5B8/bundle.json` +- palette metadata: `out/psx_wdl/L0/sprite_bundles/bundle_0000E5B8/palette.json` + +Current result: + +- this is no longer just a graphics-bank hypothesis +- the workflow can now extract actual sprite/image frame payloads and render preview images from at least some LSET graphics bundles +- the workflow can now also render colored previews and a proper per-bundle RGBA atlas using the bundle default palette index recovered from the PSX executable +- widened grayscale overviews now confirm that the late graphics bank contains recognizable object and UI art, not just texture/noise candidates + +Current palette model: + +- the executable-backed palette source for `LSET*.WDL` is the first `0x1000` bytes loaded into `DAT_800676d8` by `lset_level_bundle_load` +- `level_palette_upload_cluts` uploads that `0x1000` block as `8 x 16` raw 16-color CLUTs and then caches the raw CLUT handles in `DAT_800a9f48` +- `level_palette_expand_5bit_to_16color` separately builds a second `0x1000` grayscale-expanded table, but `DAT_800a9f48` is populated only from the first 8 raw rows +- the bundle header field at `+0x14` is the default palette-table index used when no override is supplied at draw time +- the remaining blocker is not locating the raw CLUT block anymore; it is recovering the per-placement palette override metadata that can replace the bundle default during map/tile rendering + +Current color blocker: + +- both main texture draw helpers (`FUN_80044bdc` and `FUN_80044e9c`) fall back to the bundle default palette index only when no override is present +- the important caller path at `FUN_80041458` ORs in a high-byte palette override from object/tile metadata pointed to by object field `+0xa0` +- that means standalone bundle previews can still be wrong even when the bundle parser and raw CLUT table are both correct +- the extractor now emits wider `u16x12` raw CSV views for `post_audio_region_01` and `post_audio_region_02` because the relevant override state appears to live beyond the first 6 words of those candidate placement records +- the current top-ranked portrait bundle (`bundle_00064478`, default palette index `106`) is a useful color-validation anchor because the grayscale frame is obviously correct while all raw-palette candidates remain visibly wrong +- another important unresolved issue is the exact on-disk location of the second-stage runtime header after the initial `0x3520` front image block. The loader assembly proves the runtime sequence is: `0x3520` front block -> `12`-byte header -> palette blob -> audio blob -> `4`-byte stream count, but the raw file bytes at offset `0x3520` do not yet reconcile cleanly with those expected sizes. +- `cd_file_read` itself does not transform or decompress bytes; it performs sector-based buffered CD reads. So the remaining palette-source problem is now narrowed to file-layout interpretation rather than hidden read-time decoding. + +### Runtime Dump Grounding: cabinet console bundle + +The new RAM/VRAM dump pair was used to ground the known-colored cabinet console bundle against live runtime state instead of continuing static palette guessing. + +Verified cabinet anchor: + +- bundle: `out/psx_wdl/L0/sprite_bundles/bundle_000A1B04` +- mode: `1` +- frame `0`: `56 x 68` +- default bundle palette index: `0` + +Verified live-texture result from `binary/Crusader - No Remorse (USA) GPU RAM.bin`: + +- the frame payload from `bundle_000A1B04/frame_000.bin` exists in live VRAM as one exact `8bpp` texture match +- exact match location: texel `x=258`, `y=256` +- texture page: `(1,1)` +- in-page offset: `(2,0)` +- no flipped exact match was found + +This is a strong confirmation that the current `mode 1` pixel decode is correct. The remaining problem is CLUT selection, not texture extraction. + +Verified CLUT result from the same dump: + +- the active CLUT band used by `level_palette_upload_cluts` still sits at rows `0xF0..0xF7` +- the important successful step was simpler than the later screen-match ranking pass: in `live_vram_clut_atlas.png`, the very first candidate at the top-left corner is the correct formula for this visible cabinet family +- that top-left candidate is the contiguous `256`-entry palette taken directly from live GPU row `0xF0` at `x=0` +- in other words, current best read for this `mode 1` family is: `byte value -> direct index into the 256-word slice [row 0xF0, x 0..255]` +- equivalently, this behaves like `16` adjacent live `16-color` CLUTs flattened into one `256`-entry lookup table for the sprite byte stream +- the later numeric ranking pass that preferred handle `64` / row `0xF4` was misleading for this case and should not be treated as the correct palette formula + +Important consequence: + +- the dump-grounded success case is not `bundle default row 0` from `L0.WDL` and not the later `row 0xF4` ranking result +- the working palette source is the live VRAM CLUT row `0xF0`, `x=0`, treated as one contiguous `256`-entry table +- this means the current extractor problem for `mode 1` bundles is better described as `recover the runtime CLUT-row formula` rather than `pick one cached CLUT handle index` +- for the visible wall-console bundle, that runtime formula now has a concrete verified answer even though the higher-level metadata path that selects it is still unresolved + +Wider decode result using the corrected formula: + +- a focused batch renderer was run over the detected `mode 1` bundles in `LSET1/L0.WDL` post-audio graphics region `04` +- using the same live palette source `row 0xF0 / x=0`, the pass rendered `92` `mode 1` bundles with plausible colored output instead of only the single cabinet proof case +- the strongest batch proof is the generated overview: + - `out/psx_wdl/L0/mode1_live_clut_row_f0_x0/overview_live_row_f0_x0.png` +- per-bundle outputs and summary metadata now live under: + - `out/psx_wdl/L0/mode1_live_clut_row_f0_x0/` + - `out/psx_wdl/L0/mode1_live_clut_row_f0_x0/summary.json` +- that wider pass now shows many object-like assets decoding plausibly under the same rule: cabinets, panels, tanks, wall fixtures, floor markers, weapons, pickups, and small machinery props + +Generated runtime-grounded artifacts: + +- `binary/psx_framebuffer_left.png` +- `binary/psx_framebuffer_console_crop.png` +- `out/psx_wdl/L0/sprite_bundles/bundle_000A1B04/live_vram_clut_atlas.png` +- `out/psx_wdl/L0/sprite_bundles/bundle_000A1B04/live_vram_clut_top_matches.png` +- `out/psx_wdl/L0/sprite_bundles/bundle_000A1B04/live_vram_clut_best.png` +- `out/psx_wdl/L0/sprite_bundles/bundle_000A1B04/live_vram_clut_rank.txt` +- `out/psx_wdl/L0/mode1_live_clut_row_f0_x0/overview_live_row_f0_x0.png` +- `out/psx_wdl/L0/mode1_live_clut_row_f0_x0/summary.json` + +One important caveat from the dump-grounded pass: + +- none of the `8` raw `256-color` palette blocks carved from `LSET1/L0.WDL` matched the live CLUT rows byte-for-byte in this dump +- that means either the dump was captured from a different loaded level/resource set, or the active runtime palette source for this on-screen console is not the raw `L0.WDL` palette blob currently being tested + +Palette follow-up note: + +- most extracted PSX sprite data is now structurally correct, but palette selection is still only partially solved +- the current exporter should therefore be treated as `good enough to continue map work`, not as a final automatic color pipeline +- we need a later pass to recover the runtime palette-selection rule well enough to assign the correct palette automatically for every bundle family instead of relying on the currently verified `mode 1` rule plus heuristics + +## PSX Map Decode Plan + +Current objective: + +- decode the PSX `LSET*.WDL` map/resource layout well enough to render PSX maps through the existing public map renderer pipeline instead of building a one-off viewer + +Current working split: + +- `post_audio_region_01` is now the first high-confidence map-placement candidate +- `post_audio_region_02` still looks more like compressed or mixed resource payload than directly renderable placement rows +- `post_audio_region_04` remains the late graphics bank and should be treated as the PSX art source for any eventual renderer integration + +Immediate working hypothesis: + +- `post_audio_region_01` is a fixed-row authored layout stream +- the raw `u16x12` view is already showing that each `24`-byte row behaves like two adjacent `6`-word records with similar field structure +- the strongest early evidence is that neighboring left/right halves carry similar value ranges and repeat the same small control words in the tail fields, which is what we would expect from paired cell/object placements rather than opaque compressed data + +Practical renderer goal: + +- adapt the PSX decode into the same broad source model the public renderer already uses for PC fixed maps: coordinates, shape/frame identity, and a few raw metadata bytes/words kept for inspection +- do not block on fully naming every field before producing a first renderer-fed PSX map source + +Planned work order: + +1. Lock down `post_audio_region_01` row structure across more `LSET` files and confirm whether `24` bytes is the true authored row size. +2. Separate the two half-rows into individual candidate placement records and track stable min/max ranges for each word position. +3. Identify which words are likely coordinates by checking for bounded map-like ranges and local spatial continuity between neighboring rows. +4. Identify which words are likely tile/object ids by checking whether the same values recur in ways that match repeated wall/floor/object motifs. +5. Correlate the placement stream against `post_audio_region_04` bundle offsets or bundle-local ids to recover the art linkage. +6. Determine whether `post_audio_region_02` is a secondary map layer, a lookup table for region `01`, or a different compressed resource class entirely. +7. Prototype a PSX map-source exporter that emits JSON in a renderer-friendly form even if some fields are still labeled as raw words. +8. Add a PSX-specific loader path to the existing map renderer instead of creating a separate PSX viewer. +9. Once the first map renders, iterate on field naming, layer semantics, and art binding rather than trying to solve the whole format up front. + +Current evidence-backed next step: + +- the extractor now needs to keep emitting a paired-record export for `post_audio_region_01` so the candidate row model can be checked quickly across multiple maps without reinterpreting the CSV by hand each time + +Current renderer-compatibility result: + +- a first PSX-compatible static real-art probe scene is now exported for the public map renderer +- exporter script: + - `tools/psx_export_map_debug_scene.py` +- current generated public-report outputs: + - `k:\ghidra\Crusader_Decomp_Public\map_renderer\site\data\maps\psx-remorse\map-0\scene.json` + - multiple copied frame atlases such as `k:\ghidra\Crusader_Decomp_Public\map_renderer\site\data\maps\psx-remorse\map-0\bundle_0003917C_frame_000.png` + - `k:\ghidra\Crusader_Decomp_Public\map_renderer\site\data\catalog.json` + - `k:\ghidra\Crusader_Decomp_Public\map_renderer\site\data\catalogs\psx-remorse.csv` +- current scene characteristics: + - source: filtered `LSET1/L0.WDL` `post_audio_region_01` paired-record candidates + - rendered items: `1050` + - unique bundle-backed shape definitions: `49` + - copied atlas/frame PNGs: `62` + - bounds: `3896 x 8431` + - scene format version: `psx-region01-bundle-probe-v1` + - current probe stats: `u0` span `62..111`, fallback frame count `187` + +Current art-binding hypothesis used by this probe: + +- region-01 `u0` is treated as a provisional direct bundle index into the extracted `sprite_bundles/` set +- region-01 `u4` is treated as a provisional frame index within that bundle, clamped to the highest available frame when out of range +- this is evidence-backed enough to render real PSX art in the existing map renderer, but not strong enough yet to call the binding solved +- the strongest negative check so far is that the region-01 `u5` values (`0x20`, `0x22`, `0x30`) do not match the bundle default palette indexes, so the palette-selection/control path is still missing + +Current invalidation result: + +- this direct `u0 -> bundle index` mapping is now considered invalid for real renderer output +- the produced scene repeats a small set of obviously wrong assets, including portrait/UI-like art, in places that do not make spatial sense for the map +- executable-side tracing shows that art selection is type-driven through `DAT_800758cc/d0/d4/d8` resource tables loaded by `level_resource_stream_load`, not by directly indexing the raw `post_audio_region_04` bundle scan + +New loader/data evidence from this pass: + +- `post_audio_region_00` now has dedicated extractor diagnostics: + - `out/psx_wdl/L0/post_audio_region_00_00007010_u16x6.csv` + - `out/psx_wdl/L0/post_audio_region_00_00007010_u16x12.csv` + - `out/psx_wdl/L0/post_audio_region_00_00007010_u32x5.csv` + - `out/psx_wdl/L0/post_audio_region_00_00007010_stream_probe.json` +- the new raw probe confirms that `post_audio_region_00` begins with a little-endian count value `0x20` +- after an initial short header/preamble, the bytes from about `0x3c` onward look like tightly packed `12`-byte records in the same broad shape family as the old candidate placement rows: + - example bytes at `0x3c`: `4a 00 03 16 e7 0e 00 00 01 00 20 00` + - little-endian words: `0x004A, 0x1603, 0x0EE7, 0x0000, 0x0001, 0x0020` +- that record family is a better next target than the invalidated direct bundle probe because it already exposes a small type-like word (`0x004A`) plus coordinate-like words without forcing an arbitrary raw-bundle index + +What this first public renderer pass means: + +- the existing renderer app can now load a PSX scene bundle from the static report without any PC `FIXED.DAT` dependency +- this is currently a real-art probe of filtered placement candidates, not a final decoded PSX map +- the renderer now displays extracted bundle art from `post_audio_region_04` instead of synthetic colored stand-ins +- the current output is still useful because it shows that filtered region-01 records can drive recognizable, repeatedly used PSX art through the existing renderer pipeline +- one bad extracted origin (`1x6` sprite with `xoff=65535`) initially blew out the fit bounds; the exporter now sanitizes implausible origins before writing scene metadata + +Current app compatibility notes: + +- the public renderer app was updated so non-`FIXED.DAT` map sources do not advertise a bogus binary export path +- for the PSX probe scene, `Download Map Binary` is intentionally disabled while `Download PNG`, `Download Map JSON`, and `Download Atlas PNG` remain available +- the static app successfully loads the `PSX LSET1/L0 Region 01 Art Probe` catalog entry and currently fits it at about `8%` zoom instead of the earlier collapsed `2%` fit + +Immediate implications for the next decode pass: + +- the public renderer integration path is now proven enough to use as a live debug target for PSX map-format work +- the next priority is to replace the invalidated `u0 -> bundle index` hypothesis with a real type/resource lookup recovered from `level_resource_stream_load` +- `post_audio_region_00` is now a top-tier candidate for that work because its new diagnostics expose a count-prefixed preamble plus compact typed records that look more loader-compatible than the old region-01 art probe +- the palette override path is still the main blocker to correct final color selection even when the bundle/frame choice is plausible +- once the bundle key and palette control path are recovered, the same scene-export path can graduate from `real-art probe` to actual PSX map rendering + +## PSX Script / Usecode Equivalent + +Current status: + +- there is no evidence yet that the PSX build carries the exact same external `USECODE`/`EUSECODE.FLX` style asset pipeline used by the DOS version +- the current PSX executable-backed work has mostly exposed compiled resource loaders, animation/audio handlers, and image upload/decode paths rather than a separate obvious bytecode container + +Current working question: + +- the likely PSX equivalent, if one exists, may be either: + - compiled gameplay logic directly inside `SLUS_002.68`, or + - a separate embedded event/script resource format inside the `LSET`/other disc blobs that is not yet isolated + +Immediate plan: + +1. scan the PSX executable and current renamed function set for script/event-dispatch terminology or obvious VM-style control loops +2. compare any candidate dispatch path against the DOS usecode model only at the behavioral level, not by assuming the asset format is shared +3. keep this as a secondary track while map decoding takes priority + +## Practical Extraction Paths + +### Standard media first + +The easiest wins are the standard PS1 media formats: + +- `MOVIES/*.STR`: treat as PS1 video streams +- `AUDIO/*.XA`: treat as XA audio +- `ZZZ.ZZZ`: try as a movie stream too, especially against `FMV3.STR` + +This does not need custom reverse engineering first. + +### Custom `.WDL` extraction second + +The `.WDL` files are the main custom-content frontier. + +Current executable-backed extraction order: + +1. run `tools/psx_extract_wdl.py` over representative `LSET*.WDL` files +2. treat `post_audio_region_01` and `post_audio_region_02` as the current best map-data extraction targets +3. treat `post_audio_region_04` as the current best sprite/graphics extraction target +4. carve any strict TIM blocks first, because those now have executable support via the type `4` / type `5` image handlers +5. separately carve `SPEC_A.WDL` / `MENUS/*.WDL` as raw image-oriented blobs + +The level files and menu/special files should not be assumed to share one parser until that is proven. + +## Recommended Ghidra Import Candidates + +### Primary + +1. `E:\emu\psx\Crusader - No Remorse\SLUS_002.68` + +Reason: + +- confirmed by `SYSTEM.CNF` +- valid `PS-X EXE` +- main native code image + +### Secondary, only if useful for subsystem RE + +2. `E:\emu\psx\Crusader - No Remorse\FMV.BIN` + +Reason: + +- clearly tied to FMV playback +- contains path and MDEC-related strings +- could be worth importing as a raw binary/data blob if the movie subsystem becomes a target + +### Not primary code imports + +These currently look like content, not executables: + +- `E:\emu\psx\Crusader - No Remorse\ZZZ.ZZZ` +- `E:\emu\psx\Crusader - No Remorse\SPEC_A.WDL` +- `E:\emu\psx\Crusader - No Remorse\LSET1\L0.WDL` +- `E:\emu\psx\Crusader - No Remorse\MENUS\M13.WDL` + +They may still be worth loading as raw binaries later for format RE, but they are not first-choice code imports. + +## Current Working Model + +- `SLUS_002.68` = main PS1 executable +- `FMV.BIN` = FMV helper/support blob +- `MOVIES/*.STR` = standard movie streams +- `AUDIO/*.XA` = standard XA audio +- `ZZZ.ZZZ` = likely renamed or duplicated movie stream data +- `LSET*.WDL` = structured level/resource containers +- `MENUS/*.WDL` and `SPEC_A.WDL` = raw-looking screen/menu resource blobs, possibly with some embedded standard PS1 image content + +## Executable Catalog Findings + +This batch focused on the imported `SLUS_002.68` executable as a catalog source rather than on the raw `WDL` bundles alone. + +### Map inventory and mission-facing structure + +Current executable-backed map findings: + +- `wdl_resource_bundle_load_by_index` now has a direct string-backed proof for the shipped folder layout. The loader copies one of seven hardcoded path prefixes `\LSET1\L` through `\LSET7\L` based on map-index thresholds `10`, `20`, `30`, `40`, `50`, and `60`, then formats the final `.WDL` path. +- The extracted disc tree currently ships `62` level bundles total: + - `LSET1`: `L0` through `L9` + - `LSET2`: `L10` through `L19` + - `LSET3`: `L20` through `L29` + - `LSET4`: `L30` through `L39` + - `LSET5`: `L40` through `L49` + - `LSET6`: `L50` through `L58` + - `LSET7`: `L62` through `L64` +- So the shipped PSX map-bundle range is `L0..L64` with a real on-disc gap at `L59..L61`. +- The executable also preserves only `15` plain-text `Mission Briefing ^Mission N` strings, for `Mission 1` through `Mission 15`. + +Current safest read: + +- the PSX disc contains `62` shipped map/resource bundles used by the `LSET` loader +- the player-facing campaign/briefing flow exposed by the executable is `15` numbered missions +- any extra bundle coverage beyond that mission-facing set is currently better treated as lower-level map/resource inventory, not automatically as `15 == all shipped WDLs` + +Per-bundle shipped inventory from the extracted disc tree: + +| Bundle range | Folder | Count | Size range (bytes) | +|---|---|---:|---:| +| `L0..L9` | `LSET1` | 10 | `987,932 .. 1,312,624` | +| `L10..L19` | `LSET2` | 10 | `1,107,380 .. 1,314,992` | +| `L20..L29` | `LSET3` | 10 | `904,384 .. 1,221,556` | +| `L30..L39` | `LSET4` | 10 | `1,104,316 .. 1,321,656` | +| `L40..L49` | `LSET5` | 10 | `1,120,084 .. 1,303,732` | +| `L50..L58` | `LSET6` | 9 | `1,012,956 .. 1,341,684` | +| `L62..L64` | `LSET7` | 3 | `965,072 .. 1,150,428` | + +### Passcodes and password-screen cheat status + +Current executable-backed passcode findings: + +- The mission-complete passcode display path at `80022cd4` and `80022f1c` synthesizes a `4`-character code from generated indexes. +- Those indexes are mapped through the hardcoded alphabet at `80063ef0`: + +```text +BCDFGHJKLMNPQRSTVWXZ0123456789 +``` + +- The resulting `4` characters are written into the temporary display buffer at `80063f6e..80063f71`, null-terminated at `80063f72`, and shown through the completion message at `80063f10`: + +```text +^Congratulations!^ You have completed your mission.^^The passcode for the next mission is:^ +``` + +- So PSX mission passcodes are definitely real executable-generated `4`-character values, not just external manual text. + +Current best password-screen cheat list from public PSX references: + +- `XXXX` = hidden pictures +- `L0SR` or `L0SER` = cheat-mode password reported by public sources; the conflicting transcription is almost certainly a `0` vs `O` issue and is not yet closed directly from the executable + +Important executable-side caveat: + +- none of the known public PSX mission passwords checked in this pass (`FWQP`, `HWQP`, `LRTN`) appear as plain ASCII strings inside `SLUS_002.68` +- the same is true for the public cheat-password candidates `XXXX`, `L0SR`, and `L0SER` +- current safest read is therefore `password entry and/or validation is numeric or transformed`, not `a plain embedded string table of passcodes` +- this pass closed the visible generation/display side, but it did **not** yet directly close the hidden cheat-password compare path + +### Weapons and items + +The executable does preserve user-facing text tables for equipment. + +Recovered ammo names: + +- `INVALID AMMO` +- `JL-2 AMMO` +- `AR-7 AMMO` +- `GL-303 AMMO` +- `RP-22 AMMO` +- `SG-A1 AMMO` + +Recovered item names: + +- `NULL ITEM` +- `INHIBITOR` +- `CREDITS` +- `SCI PLANS` +- `BLAST PAC` +- `DET PAC` +- `DATA LINK` +- `LAND MINE` +- `SPIDER BOMB` +- `MEDICAL KIT` +- `ENERGY CUBE` +- `FUSION PAC` +- `CHEMICAL BATTERY` +- `FISSION BATTERY` +- `FUSION BATTERY` +- `GRAVITON GENERATOR` +- `IONIC GENERATOR` +- `PLASMA GENERATOR` + +Recovered weapon names: + +- `RP-16` +- `RP-22` +- `RP-32` +- `SG-A1` +- `AC-88` +- `PA-31` +- `EM-4` +- `PL-1` +- `UV-9` +- `GL-303` +- `AR-7` +- `JL-2` +- `JL-9` + +Current safest read: + +- these are real executable-backed display-name tables, not guessed carryovers from the DOS build +- the PSX build still uses a recognizable Crusader equipment taxonomy even where some item labels differ from the more familiar DOS-side vocabulary + +JL-2 / JL-9 follow-up: + +- neither `JL-2` nor `JL-9` appears in the known DOS `Weapon_GetNameForShapeNo` tables already extracted in this repo for retail Remorse or Regret; those tables stop at the older DOS weapon families such as `BA-40`, `BA-41`, `PA-21`, `EM-4`, `SG-A1`, `RP-22`, `RP-32`, `AR-7`, `GL-303`, `PA-31`, `PL-1`, `AC-88`, `UV-9`, and the Regret-only additions `BK-16`, `LNR-81`, `XP-5` +- that makes `JL-2` and `JL-9` strong PSX-only naming additions rather than inherited PC names +- `JL-2` is also the only one of the two with an explicit PSX ammo label (`JL-2 AMMO`) in the nearby executable text table, while no matching `JL-9 AMMO` string has been recovered +- the extracted PSX `pickups_and_weapons` sprite category contains repeated weapon-pickup art across a large spread of maps, but this pass still does not have a defensible sprite-to-name mapping for specific `JL-2` or `JL-9` pickup appearances + +### Enemies + +This pass did **not** recover a comparable plain-text enemy-name table from `SLUS_002.68`. + +What is closed: + +- the PSX executable has clean user-facing text for mission briefings, passcode UI, ammo, items, and weapons +- the same executable does **not** expose an equally obvious plain-text enemy catalog in its main printable-string regions + +Current safest read: + +- enemy identities in the PSX build are probably carried primarily as numeric resource/type ids, spawn tables, or script/resource references rather than as a direct display-name list +- the next enemy-focused pass should start from enemy spawn/type dispatch or resource-stream type tables, not from more blind string hunting + +## Highest-Value Next Steps + +1. Run `tools/psx_extract_wdl.py` over more `LSET*.WDL` samples and compare whether the high-offset region pattern stays stable across level sets. +2. Recover the password-entry validation path directly so the hidden PSX cheat-password compare logic can be proven from code instead of only cross-referenced from public password lists. +3. Focus map decoding on `post_audio_region_01` and `post_audio_region_02`, starting with table structures, coordinate ranges, and repeated record widths. +4. Focus sprite/graphics decoding on `post_audio_region_04`, including more aggressive TIM validation and possible packed-image expansion. +5. Recover the exact type IDs consumed by `level_resource_stream_load` so the sprite/image resource records can be labeled more precisely. +6. Compare carved `post_audio_region_04` image assets against on-screen level graphics to separate sprite sheets from tiles. +7. Run the raw-blob fallback across `MENUS/*.WDL` to identify which menu files contain usable embedded TIM data and which are likely packed 15-bit images. diff --git a/docs/regret-game-start.md b/docs/regret-game-start.md index fa7a080..a1ea997 100644 --- a/docs/regret-game-start.md +++ b/docs/regret-game-start.md @@ -119,6 +119,30 @@ The key parser detail is that there are no separately recovered `-x`, `-y`, or ` There is one important precedence rule in `Game_RunNewGameFlow`: `-egg` wins over the coordinate override path. When X is present but the egg override is nonnegative, the code still routes back into the egg-based teleporter lane. The direct `NPC_Teleport` path only runs when X/Y/Z are present and the egg override is still negative. +The live `REGRET.EXE` table backing that `-warp mission` branch is now closed directly too. + +In `Game_RunNewGameFlow`, the target map comes from: + +```c +mapno = *(int *)(g_warpToLevelNoArg * 2 + 0x75c) + DAT_1480_0ad0; +``` + +So the current retail No Regret mission-table base is `1480:075c`. + +Static bytes at that address: + +```text +1480:075c: 00 00 01 00 03 00 05 00 07 00 09 00 0b 00 0d 00 +1480:076c: 0f 00 11 00 13 00 15 00 17 00 19 00 1b 00 1d 00 +1480:077c: 28 00 +``` + +Interpreted as little-endian words, the current recovered base-map table is: + +- `0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 40` + +That is the same 17-word sequence already recovered from No Remorse at `1478:0488`, so the two games currently match on the embedded mission-to-base-map table even though the surrounding startup control flow differs. + ## Could Parameters Replace The Executable Hack? For a normal fresh game, no. diff --git a/docs/removed_items.md b/docs/removed_items.md index e0a94f9..a7aa777 100644 --- a/docs/removed_items.md +++ b/docs/removed_items.md @@ -17,6 +17,8 @@ The working split is: - Remorse usecode export: `Crusader_Decomp_Public/USECODE_REMORSE/**` - Regret usecode export: `Crusader_Decomp_Public/USECODE_REGRET/**` for comparison only - Retail disassembly export: `Crusader_Decomp/exports/CRUSADER.EXE.xml` +- Generated retail dtable dump: `Crusader_Decomp/tools/dump_dtable_names.py` -> `Crusader_Decomp/out/dtable_get_name_dump.json` plus companion CSVs +- Generated Regret dtable dump: `Crusader_Decomp/tools/dump_dtable_names.py regret` -> `Crusader_Decomp/out/regret_dtable_get_name_dump.json` plus companion CSVs ## High-Level Conclusions @@ -51,7 +53,7 @@ Current best read: `0343` is a surviving but heavily stripped grenade-family obj - `LAND MINE` - `BLAST PAC` - `FUSION PAC` -- The repeated `INVALID` placeholders inside that same array are also informative: `1478:22BC` is a `char *[41]` table, and slots `0`, `15`, `27`, and `33` all point to the same `INVALID` string. The removed grenade names live immediately after one of those placeholder boundaries. +- The repeated `INVALID` placeholders inside that same array are also informative: the verified retail dump from `tools/dump_dtable_names.py` shows `1478:22BC` is a `char *[41]` table whose global slots `0`, `14`, `26`, and `32` all point to the same `INVALID` string. The removed grenade names then occupy bomb-family slots `33..40` as `GRENADE`, `CONCUSSION GRENADE`, `NERVE GAS GRENADE`, `EMP GRENADE`, `SPIDER BOMB`, `LAND MINE`, `BLAST PAC`, and `FUSION PAC`. - This means the removed grenade family is not just a renderer/catalog naming artifact. The retail executable still knows those display strings even though the distinct Remorse scripted classes appear to be gone. Current best read: these are old grenade-family placements left in maps and editor-era data whose exact inventory/display names still survive in the retail executable, but whose distinct Remorse behavior has likely been removed or collapsed away before retail. The user-observed behavior where some can be forced into inventory but do nothing is consistent with a leftover shape/name path surviving after the actual item logic was cut. @@ -65,7 +67,7 @@ Current best read: these are old grenade-family placements left in maps and edit - its fallback branch at `1118:05D5` returns `DS:238C`, which is the string `INVALID` - `Weasel_OnPaint` at `13E0:0932` calls `DTable_GetNameForShapeNo`, so this is a real inventory/display UI path rather than an isolated dead string helper - The backing data segment confirms the same model. In segment `1478`, the item-name table at `1478:22BC` is a `char *[41]` array whose placeholder slots point at the `INVALID` string at `1478:238C`. -- I still have not closed the exact shape-to-table-index mapping for `0548`, but the retail executable evidence now cleanly supports the user report that at least some bad/unmapped inventory entries resolve to visible label text `Invalid` in-game. +- The verified dump also closes one open point: `0x0548` does **not** appear in the resolved dtable category tables at all. Its visible in-game `Invalid` label is therefore best explained as a plain `DTable_GetNameForShapeNo` fallback for an unmapped shape, not as a dedicated `0548` name-table entry. Current best read: `0548` is a real leftover item-like record that still resolves through at least one executable-side text/name path, but no meaningful use behavior has been recovered yet. @@ -101,6 +103,26 @@ The retail name table behind `DTable_GetNameForShapeNo` was useful beyond the or Current best read: these are active explosive inventory objects, not additional removed-item discoveries. The current catalog simply does not label all of them clearly. +### Reusable dump status + +- The retail `DTable_GetNameForShapeNo` mapping is now exported in reusable form for downstream tooling: + - `out/dtable_get_name_dump.json` + - `out/dtable_global_name_slots.csv` + - `out/dtable_category_entries.csv` + - `out/dtable_resolved_shapes.csv` +- That dump is generated by `tools/dump_dtable_names.py` directly from retail `CRUSADER.EXE` bytes plus `exports/CRUSADER.EXE.xml` relocations, so it is suitable for feeding the map renderer and shape catalogs without keeping the mapping only in prose notes. + +### Regret-side DTable comparison + +- The same dumper now also supports live `REGRET.EXE`, with the recovered helper at `1130:056a` and the Regret dtable island in segment `1480`. +- The Regret dump closes the shifted layout directly from raw bytes even without a local `REGRET.EXE.xml` export: pointer table `1480:2856`, string pool `1480:2926`, and category tables at `1480:2590` (ammo), `1480:2614` (weapons), `1480:2792` (misc items), and `1480:27DE` (bombs). +- Regret also repeats a single `INVALID` string through four global slots, but at a different expanded layout: indices `0`, `17`, `36`, and `44` all point back to `1480:2926`. +- That expanded Regret table preserves several names that do not appear in the earlier Remorse dump, including weapons `BK-16`, `LNR-81`, `XP-5`; items `IONIC SHIELD`, `PLASMA SHIELD`, `DISRUPTER`, `SPIDER MINE`, `DATA PICK`, `MINE DET`, `PORTABLE BETTY`, `RADIATION SHIELD`, and `VIR IMAGER`; and ammo `BK-16 CLIP`, `LNR-81 CLIP`. +- The resolved Regret bomb rows are also narrower than a naive string scan suggests: `0x0343` = `GRENADE`, `0x0350` = `EMP GRENADE`, `0x0560` = `SPIDER BOMB`, `0x039A` = `LAND MINE`, and `0x039C` = `FUSION PAC`. +- `BLAST PAC` is notably absent from the recovered Regret dtable output. In other words, the Regret executable still carries `LAND MINE` and `FUSION PAC`, but not a `BLAST PAC` bomb-table slot analogous to the Remorse block. + +Current best read: the Regret comparison strengthens the claim that these explosive names come from a real retail inventory/display lookup family rather than renderer-only catalog text, but it also shows that the two games do not preserve the exact same bomb/item naming inventory. + ### Spider bomb: stronger Regret-side evidence than Remorse-side evidence - The same retail name table includes `SPIDER BOMB`. @@ -144,7 +166,7 @@ Current best read: these are real leftover placeholder objects worth a future de ## Open Questions -1. What exact shape or category values land on the four `INVALID` placeholder slots in the retail `1478:22BC` dtable array, and is `0548` one of them directly? +1. What code path allows `0548` and similar bad/unmapped shapes to reach the inventory/display UI if they are not direct entries in the retail `1478:22BC` dtable mapping? 2. Do `034E`, `034F`, and `0350` still have dead executable-side item-definition records even though no separate Remorse usecode classes were recovered? 3. Is the observed forced-pickup behavior using a generic item acquisition path that bypasses normal `invitem` rules and therefore reaches the `DTable_GetNameForShapeNo` fallback path? 4. What are `0110` and `0112` visually or functionally in the old maps, beyond being non-pickup leftovers? diff --git a/plan-mid.md b/plan-mid.md index bbb2213..d909b2b 100644 --- a/plan-mid.md +++ b/plan-mid.md @@ -30,6 +30,9 @@ Detailed completed analysis belongs in the files under `docs/`, not in this plan - The latest USECODE pass justified another small VM-lane bump: the gameplay-side wrapper ladder now extends through slots `0x10..0x14` with verified mixed payload shapes (`none` vs extra signed word), the new slot-only Ghidra names keep that taxonomy visible without overpromoting event labels, and the `000d:22bc` stage is now comment-backed as a sequencer-internal link-matrix/pushback consumer over decoded workspace bytes rather than a direct descriptor-row reader. - The immortality follow-up justified another small tooling-and-confidence bump: the extractor now emits a dedicated target-body scan, the strongest current USECODE candidates show no inline `0x410` / `0x00000410` literal, and the remaining frontier is narrowed to data-driven decoding of `EVENT` slot `0x0a` plus `NPCTRIG` slots `0x0a` / `0x20` rather than the older wider trigger family set. - The latest owner-loaded range pass justified another small confidence bump too: the owner-resource child selector now matches extracted `class_id + 2` exactly, the class header/subentry math at `000d:5066/51fd/53b4` is closed against the extractor's raw headers and event rows, and the surviving immortality uncertainty has moved from `can the loader fit NPCTRIG arithmetic at all?` to the narrower `which class family is actually selected upstream?` question. +- The PSX sprite-extraction side is also less speculative now: a dump-grounded pass proved the known-colored wall-console bundle `bundle_000A1B04` already exists verbatim in live VRAM at texture page `(1,1)`, and the corrected working color formula is the top-left live CLUT candidate from the atlas, namely the contiguous `256`-entry slice at GPU row `0xF0`, `x=0`; the same rule now produces plausible output across a wider `92`-bundle `mode 1` batch instead of only the single cabinet proof case. +- The PSX executable-side catalog lane is tighter too: `SLUS_002.68` now has comment-backed proof that `wdl_resource_bundle_load_by_index` selects seven hardcoded `\LSETn\L` prefixes across thresholds `10/20/30/40/50/60`, the extracted disc currently ships `62` level bundles (`L0..L58`, `L62..L64`) with a real gap at `L59..L61`, the executable exposes only `15` plain-text `Mission Briefing ^Mission N` strings, and the mission-complete passcode path now has a closed `4`-character consonant/digit alphabet at `80063ef0` plus direct ammo/item/weapon name tables. The remaining PSX passcode gap is now narrower: public cheat-password candidates `XXXX` and `L0SR`/`L0SER` are not stored as plain ASCII in `SLUS_002.68`, so the compare path likely uses numeric or transformed validation instead of a flat string table. +- The new PSX pre-alpha comparison lane is also anchored now: `/psx/prealpha/SLUS_002.68` still carries direct `Crusader: No Remorse` branding, the same retail-style `wdl_resource_bundle_load_by_index` `\LSET1\L .. \LSET7\L` threshold ladder, and the same `15` mission-briefing/passcode shell, but the unpacked `Crusader 2 Pre-Pre Alpha` disc currently ships only `3` level bundles, `1` XA, and no `.STR` movies. The most interesting current mismatches are architectural leftovers that no longer match the disc literally, especially the missing-file `\AUDIO\TALK1.XA;1` path and the surviving `LoadExec` helper for `MENU.EXE` / `ENGINE.EXE` / `PSX.EXE`. - That closes one live top-priority section and justifies a small headline increase even though the remaining work is still breadth-heavy. ## Current Verified State @@ -49,11 +52,14 @@ Detailed completed analysis belongs in the files under `docs/`, not in this plan - 000a/000d tracked-handle, cache, allocator, dispatch-entry, and startup/display support lanes now have a coherent partial map. - 000e parser and animation subsystems have a real partial map. - The auxiliary local disassembly corpus at `K:/ghidra/crusader-disasm` is now inventoried and integrated as a separate evidence source for shape metadata, static map/object dumps, opcode names, and older Remorse/Regret intrinsic-function vocabularies; its safe-reuse rules and porting implications are captured in `docs/crusader-disasm-reference.md`. +- The PSX side now has a first explicit pre-alpha comparison note too. `docs/psx/prealpha.md` records that `/psx/prealpha/SLUS_002.68` is still much closer to a reduced No Remorse PSX branch than to a visibly rebranded sequel executable: the live database now has `wdl_resource_bundle_load_by_index` renamed at `80038084`, and comment-backed notes on the stale `TALK1.XA` selector helper and the split-`LoadExec` `MENU.EXE` / `ENGINE.EXE` / `PSX.EXE` path that no longer matches the current unpacked disc tree. - The workspace now also has a first dedicated offline map-rendering/tooling lane: `tools/render_crusader_map.py` can load a chosen `FIXED.DAT`, expand `GLOB.FLX`, decode required `SHAPES.FLX` frames, apply `GAMEPAL.PAL`, and emit a first-pass PNG from either static set, while `docs/map-rendering.md` captures the current format contracts, the `--fixed-dat` override, and the intentionally limited compositor model. - The map/editor-visibility lane is now tighter too. New note `docs/editor-object-visibility.md` records live `CRUSADER.EXE` proof that the downstream item draw helper `1198:02e4` (`Item_PaintSprite`) explicitly returns early on `ShapeData.flags2 & 1` (`SI_EDITOR`), but the follow-up render-path pass also found the controlling upstream skip at `1180:0951..095c` in the world-item builder. Current best read is therefore `editor-tagged shapes are filtered before draw-node allocation in the normal world-item renderer, with a second downstream paint-time guard still present`, which also explains why a first patch that only flipped `1198:033b` produced no visible change in-game. No recovered retail `-debug`, cheat/debug hotkey, Laurie/usecode-debugger path, or `0x410` lane currently re-enables those objects. The closest confirmed toggle remains ScummVM's own `_showEditorItems` debugger command, which is engine-added rather than retail. - The localized-build comparison lane now covers the Japanese Windows-native executable too. New note `docs/jp-remorse-windows9x-investigation.md` records that `/ja/CRUSADER.EXE` is a PE-style Win32 image with native window creation, DirectDraw/DirectSound init, registry-backed config under `Software\Electronic Arts\Crusader: No Remorse\J1.21`, IME/DBCS-facing imports, and a `GetVersion`-driven Win9x compatibility branch that retries `TlsAlloc()` until the slot is above `2` when the classic Win9x version bit is set. Current best read is `real Windows 9x-native port with likely Win95 intent`, with runtime prerequisites still left to test. +- The removed-item lane is tighter now too. `docs/removed_items.md` now records a live `CRUSADER.EXE` close on the inventory/display name path: retail `1118:056A` is `DTable_GetNameForShapeNo`, `1118:05D5` is its `INVALID` fallback returning `1478:238C`, and `Weasel_OnPaint` uses that same lookup family. The backing `1478:22BC` `char *[41]` array preserves exact explosive names inline, including `CONCUSSION GRENADE`, `NERVE GAS GRENADE`, `EMP GRENADE`, `SPIDER BOMB`, `LAND MINE`, `BLAST PAC`, and `FUSION PAC`, while repeating `INVALID` at slots `0/14/26/32`. The reusable Remorse dump at `out/dtable_get_name_dump.json` plus companion CSVs now closes the direct-table question too: `0548` is not a named dtable entry, so its in-game `Invalid` label is best explained as a plain fallback for an unmapped shape. The same tooling now also closes the Regret comparison side: live `REGRET.EXE` uses helper `1130:056a`, its recovered segment-`1480` dtable island expands the slot layout to `52` names with repeated `INVALID` at `0/17/36/44`, preserves Regret-only names such as `BK-16`, `LNR-81`, `XP-5`, `IONIC SHIELD`, `PLASMA SHIELD`, `RADIATION SHIELD`, and `VIR IMAGER`, and resolves bomb rows `0343`, `0350`, `0560`, `039A`, and `039C` while notably omitting `BLAST PAC`. Current best read remains narrower than the first pass: the removed grenade variants are real retail dtable names plus map leftovers, `LANDMINE`/`BLASTPAC`/`FUSPAC` are active Remorse classes rather than new removed items, and `SPIDER BOMB` is currently stronger as a cross-game dtable/comparison signal than as a fully closed Remorse finding. - The Japanese localized-build lane now also covers surviving cheat/debug and startup-argument behavior. New note `docs/jp-remorse-cheats-and-launch-params.md` records that the JP Win32 build still has a live `-laurie` special-case, a live `JASSICA16` cheat-state matcher, a still-executable immortality toggle path, and a working Win32 parser for `-debug`, `-u`, `-warp`, `-skill`, `-mapoff`, `-egg`, and `-demo`. The same pass also adds one important caveat relative to the older DOS-side docs: the JP Win32 parser is only directly closed for mission-only `-warp ` so far, not for positional `-warp `. - The startup map-selection lane is now tighter across both retail games too: No Remorse still hardcodes `Teleporter_CreateProcessDirect(1, 0x1e, 1)` inside `Game_Start`, while No Regret keeps the same literal selector in two live places, the early `Game_Start` site at `1008:1448` and the later authoritative new-game hop in `Game_RunNewGameFlow` at `1030:05c5`. The separate `-warp mission` path still uses an executable-embedded word table plus `-mapoff`, and the repo docs now include the dedicated REGRET-side note `docs/regret-game-start.md`. Current best read remains `startup map choice in code, map contents in external FIXED.DAT resources`, not `mission-start map configured in CRUSADER.CFG`. +- That same warp-table lane is now exact across both retail DOS executables too. Byte checks against `CRUSADER.EXE` and `REGRET.EXE` now show matching 17-word `-warp mission` base-map tables (`0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,40`) at `1478:0488` and `1480:075c`, each followed by a `0,0` terminator. The public map renderer now also has a dedicated mission-table extractor and generated JSON cache, so scene metadata no longer has to treat mission/base-map usage as an unknown ownership question. - That same startup lane is now tighter at the argument level too. Current best parser/control-flow read in `REGRET.EXE` is `-warp [x y z]`, with X/Y/Z carried as positional argv tokens after the mission number rather than as separate recovered switches. The corresponding runtime branch in `Game_RunNewGameFlow` is also clearer: nonnegative `-egg` overrides beat the coordinate path, while the real eggless-map workaround is `-warp ` plus `-mapoff` with `-egg` omitted so the game falls into direct `NPC_Teleport` instead of the teleporter-egg lookup. - The matching No Remorse cross-check is now closed too. Live `CRUSADER.EXE` `HandleCommandlineArgs` at `1048:0adc` uses the same positional `-warp [x y z]` parser shape, and `Game_Start` at `1020:029e` / `1020:02d0` uses the same runtime precedence: direct coordinates only win when the egg override is still negative, otherwise the code falls back to `Teleporter_CreateProcessDirect`. The parameter-only eggless-map workaround is therefore shared across both retail games, not Regret-specific. - The command-line lane is tighter around `-u` now too. In live non-Japanese `CRUSADER.EXE`, the parser case at `1048:0a46` copies the following token into `1478:065a`, and the renamed `startup_apply_u_override_if_present` at `1420:0cdf` later consumes that buffer to resolve/load an alternate usecode/EUSECODE source into `1478:6611/6613`, mark `1478:6615`, and rebuild the cumulative slot-base words at `1478:8c7c..8c82`. Current best read is `real retail startup usecode override`, not `JP-only` and not `dead string-table residue`; the paired consequence is that the older CRUSADER-side `-setver` attribution should now be treated as reopened until its exact retail consumer is isolated directly. @@ -188,16 +194,17 @@ Detailed completed analysis belongs in the files under `docs/`, not in this plan 7. Revisit the `0x4588` callback object only when caller-side evidence is strong enough to support behavioral naming. 8. Exercise `tools/render_crusader_map.py` on a few representative No Remorse and No Regret maps, then tighten the paint order using `TYPEFLAG.DAT` footpads and any mismatches visible against in-game screenshots or `crusader-disasm` map evidence. 9. If the map/editor-visibility lane is revisited, start from `docs/editor-object-visibility.md` and the upstream `1180:0951..095c` world-item builder gate first; rule in or rule out a second debug-only world-item builder before spending more time on cheat or command-line searches. +10. Continue the PSX pre-alpha lane from `docs/psx/prealpha.md`: classify the surviving `LoadExec` callers around `80046aac`, confirm whether the `TALK1.XA` path is still reachable in practice, and compare the three shipped `LSET1` bundles against the retail extractor outputs before assuming the build is only a content-pruned No Remorse branch. -10. Recover the real upstream caller/selector path into `entity_vm_opcode_sequence_run`, most likely by finding the first non-recursive `0x6714` context-method caller or vtable dispatch site rather than by repeating raw xref queries that still return no direct edges. -11. Recover real caller roles for `entity_vm_context_try_create_mask_0400_slot0a_with_offset` and `entity_vm_context_try_create_mask_0800_slot0b_with_offset` by treating them as the remaining dark members of the now-verified signed-additive masked-materializer subfamily and comparing them against the newly anchored slot-`0x12` caller pattern. -12. Tighten the newly surfaced higher-slot wrapper ladder around `0005:3115..31da`, especially the two slot-`0x12` caller sites at `0005:1776` / `0005:1945` and the slot-`0x10` guarded callsite, so any future promotion to `leaveFastArea` / `func11|cast` / `justMoved` / `AvatarStoleSomething` / `animGetHit` is driven by binary caller behavior rather than by external tables alone. -13. Tighten the outward caller chains around the renamed seg006 masked helpers `entity_vm_context_try_create_mask_0008_slot30_with_offset` (`0006:0ba4`) and `entity_vm_context_try_create_mask_0010_slot08_with_offset_if_ready` (`0006:108c`) so the local state-selector lane and the adjacent class-linked value family can be tied back to concrete gameplay subsystems rather than only to class-detail fields. -14. Tighten the paired-file-family reading of the seg070 twin loops at `0009:67b6` and `0009:6916` by recovering which temporary buffer and record schema each family populates behind `entity_vm_runtime_owner_resource_create`. -15. Promote additional ledger rows where the current docs already justify `Foothold`, `Partial`, or `Deep`. -16. If the VM lane stalls again, revisit `000e:ffb0` from the now-verified `00db/00dc` caller windows and try to recover an adjacent non-overlapped helper before attempting any boundary repair. -17. If the immortality lane is revisited, stay focused on `NPCTRIG` slot `0x0a` first, with slot `0x20` still treated as the typed/setup companion and `EVENT` only as the generic hub baseline; the three currently recovered direct `0005:295f` caller families are now all closed and comment-backed in the live NE program at `10f0:02d9`, `10f0:0379`, `10f0:03c3`, `10f0:03e5`, `1128:0ff0`, and `1138:1384`, so the next defensible step is an earlier producer that assigns subtype `0x20b/0x20c` into field `+0x3c` or otherwise chooses the owner-loaded class family before these generic damage consumers run. -18. Use the new Pentagram-derived parser proof of concept as the first tooling bridge for raw class/slot bodies: extend opcode coverage conservatively, emit IR v1 artifacts, and only then prototype a Ghidra-side annotation importer against compiled anchors like `000d:51fd`, `000d:5572`, `000d:46ec`, `000d:22bc`, and `000d:ebe3`. +11. Recover the real upstream caller/selector path into `entity_vm_opcode_sequence_run`, most likely by finding the first non-recursive `0x6714` context-method caller or vtable dispatch site rather than by repeating raw xref queries that still return no direct edges. +12. Recover real caller roles for `entity_vm_context_try_create_mask_0400_slot0a_with_offset` and `entity_vm_context_try_create_mask_0800_slot0b_with_offset` by treating them as the remaining dark members of the now-verified signed-additive masked-materializer subfamily and comparing them against the newly anchored slot-`0x12` caller pattern. +13. Tighten the newly surfaced higher-slot wrapper ladder around `0005:3115..31da`, especially the two slot-`0x12` caller sites at `0005:1776` / `0005:1945` and the slot-`0x10` guarded callsite, so any future promotion to `leaveFastArea` / `func11|cast` / `justMoved` / `AvatarStoleSomething` / `animGetHit` is driven by binary caller behavior rather than by external tables alone. +14. Tighten the outward caller chains around the renamed seg006 masked helpers `entity_vm_context_try_create_mask_0008_slot30_with_offset` (`0006:0ba4`) and `entity_vm_context_try_create_mask_0010_slot08_with_offset_if_ready` (`0006:108c`) so the local state-selector lane and the adjacent class-linked value family can be tied back to concrete gameplay subsystems rather than only to class-detail fields. +15. Tighten the paired-file-family reading of the seg070 twin loops at `0009:67b6` and `0009:6916` by recovering which temporary buffer and record schema each family populates behind `entity_vm_runtime_owner_resource_create`. +16. Promote additional ledger rows where the current docs already justify `Foothold`, `Partial`, or `Deep`. +17. If the VM lane stalls again, revisit `000e:ffb0` from the now-verified `00db/00dc` caller windows and try to recover an adjacent non-overlapped helper before attempting any boundary repair. +18. If the immortality lane is revisited, stay focused on `NPCTRIG` slot `0x0a` first, with slot `0x20` still treated as the typed/setup companion and `EVENT` only as the generic hub baseline; the three currently recovered direct `0005:295f` caller families are now all closed and comment-backed in the live NE program at `10f0:02d9`, `10f0:0379`, `10f0:03c3`, `10f0:03e5`, `1128:0ff0`, and `1138:1384`, so the next defensible step is an earlier producer that assigns subtype `0x20b/0x20c` into field `+0x3c` or otherwise chooses the owner-loaded class family before these generic damage consumers run. +19. Use the new Pentagram-derived parser proof of concept as the first tooling bridge for raw class/slot bodies: extend opcode coverage conservatively, emit IR v1 artifacts, and only then prototype a Ghidra-side annotation importer against compiled anchors like `000d:51fd`, `000d:5572`, `000d:46ec`, `000d:22bc`, and `000d:ebe3`. ## Remaining Work To Reach A Reasonably Complete Decompilation State diff --git a/stdout b/stdout new file mode 100644 index 0000000..0dd5a00 --- /dev/null +++ b/stdout @@ -0,0 +1,1790 @@ +24 08 01 00 02 00 00 00 00 00 00 00 00 00 00 00 +97 1d ef 1c 04 00 00 00 20 00 00 00 00 00 00 00 +00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 a9 04 00 00 00 00 00 00 +20 01 00 00 3f 16 9b 0e 00 00 00 28 22 00 00 00 +00 00 00 00 01 00 00 00 24 01 00 00 12 16 c0 0e +00 00 00 14 22 01 00 00 00 00 00 63 0b 00 00 00 +e8 00 00 00 3f 16 bf 0e 18 00 00 32 20 00 00 00 +34 12 34 12 0b 00 00 00 e8 00 00 00 7f 16 bf 0e +18 00 00 32 20 00 00 00 34 12 34 12 0b 00 00 00 +e8 00 00 00 3f 16 ff 0e 18 00 00 32 20 00 00 00 +34 12 34 12 0b 00 00 00 e8 00 00 00 7f 16 ff 0e +18 00 00 32 20 00 00 00 34 12 34 12 0b 00 00 00 +1a 01 00 00 4e 16 bb 0e 00 00 00 14 30 00 00 00 +33 34 08 4d 00 00 00 00 1f 01 00 00 0f 16 e3 0e +00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +1f 01 00 00 0f 16 d7 0e 00 00 00 28 20 00 00 00 +00 00 00 00 02 00 00 00 24 01 00 00 5b 16 92 0e +00 00 00 14 20 01 00 00 00 00 00 24 00 00 00 00 +12 01 00 00 13 16 9b 0e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 20 01 00 00 2f 16 9b 0e +00 00 00 28 22 00 00 00 00 00 00 00 0b 00 00 00 +1a 01 00 00 36 16 ce 0e 00 00 00 14 30 00 00 00 +23 24 10 4d 00 00 00 00 20 01 00 00 9b 16 f3 0e +0c 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +20 01 00 00 9b 16 eb 0e 06 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 20 01 00 00 9b 16 f7 0e +06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +20 01 00 00 9b 16 eb 0e 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 20 01 00 00 9b 16 f7 0e +00 00 00 28 20 00 00 00 00 00 00 00 0b 00 e8 00 +db 00 04 00 83 16 c7 0e 00 00 00 4b 22 00 00 00 +00 00 00 35 00 00 00 00 1f 01 00 00 93 16 97 0e +00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +1f 01 00 00 93 16 a3 0e 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 a3 16 ab 0e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 a3 16 a7 0e 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 e3 16 a3 0e +00 00 00 32 20 00 00 00 00 00 00 00 c7 80 df 00 +de 00 04 00 f3 16 9b 0e 00 00 00 32 20 20 00 00 +00 00 00 a9 c7 00 00 00 df 00 00 00 d7 16 8f 0e +0e 00 00 32 22 00 00 00 ef cd ef cd 00 00 00 00 +de 00 00 00 bf 16 9b 0e 00 00 00 32 20 20 00 00 +00 00 00 00 00 00 00 00 f5 00 00 00 4f 17 9c 0e +06 00 00 32 20 01 00 00 19 00 aa aa 03 00 00 00 +fa 00 00 00 59 17 97 0e 06 00 00 32 20 01 00 00 +24 00 aa aa 00 00 00 00 bb 00 00 00 23 17 a3 0e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +de 00 00 00 23 17 9b 0e 00 00 00 32 20 20 00 00 +00 00 00 00 c7 00 00 00 df 00 00 00 0b 17 8f 0e +0e 00 00 32 22 00 00 00 ef cd ef cd 00 00 00 00 +bc 00 00 00 27 17 a7 0e 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 27 17 ab 0e +00 00 00 32 20 00 00 00 00 00 00 00 0b 80 db 00 +ba 00 06 01 3c 17 87 0e 0a 00 00 32 20 21 00 00 +00 00 00 34 11 00 00 00 1a 01 00 00 1f 17 eb 0e +00 00 00 04 30 00 00 00 25 25 00 09 11 00 f4 00 +ba 00 04 00 6e 16 07 0f 0a 00 00 32 20 21 00 00 +00 00 00 53 15 00 00 00 d8 00 00 00 23 16 36 0f +02 00 00 32 20 00 00 00 00 00 00 00 14 80 d8 00 +e4 00 00 00 28 16 3d 0f 02 00 00 32 22 00 00 00 +00 00 00 5f 11 00 00 00 f4 00 00 00 7f 16 27 0f +00 00 00 32 22 00 00 00 00 00 00 00 11 00 00 00 +f4 00 00 00 7f 16 3f 0f 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 a3 16 43 0f +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 9f 16 43 0f 00 00 00 32 20 00 00 00 +00 00 00 00 11 00 00 00 1a 01 00 00 e7 16 24 0f +02 00 00 04 30 00 00 00 25 25 00 09 0b 01 00 00 +ad 00 00 00 ab 16 27 0f 03 00 01 32 32 20 00 00 +00 04 00 33 00 00 00 00 bc 00 00 00 a3 16 0f 0f +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 a7 16 0f 0f 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 de 00 00 00 a7 16 6f 0f +00 00 00 32 20 20 00 00 00 00 00 00 0e 80 df 00 +de 00 04 00 cf 16 6f 0f 00 00 00 32 20 20 00 00 +00 00 00 47 0d 80 df 00 de 00 04 00 fb 16 6f 0f +00 00 00 32 20 20 00 00 00 00 00 42 0d 00 00 00 +df 00 00 00 e7 16 63 0f 0e 00 00 32 22 00 00 00 +ef cd ef cd 0e 00 00 00 df 00 00 00 bf 16 63 0f +0e 00 00 32 22 00 00 00 ef cd ef cd 0b 00 00 00 +e9 00 00 00 08 17 07 0f 00 00 00 32 a0 00 00 00 +00 00 00 00 0c 80 df 00 de 00 04 00 27 17 6f 0f +00 00 00 32 20 20 00 00 00 00 00 3a 0b 80 df 00 +de 00 04 00 53 17 6f 0f 00 00 00 32 20 20 00 00 +00 00 00 32 0b 00 00 00 df 00 00 00 3f 17 63 0f +0e 00 00 32 22 00 00 00 ef cd ef cd 0c 00 00 00 +df 00 00 00 13 17 63 0f 0e 00 00 32 22 00 00 00 +ef cd ef cd 0b 00 00 00 c8 00 00 00 bf 18 47 15 +00 00 01 32 20 01 00 00 02 00 aa aa 1f 80 d8 00 +e4 00 1f 00 1b 1d a3 15 02 00 00 32 22 00 00 00 +00 00 00 7f 13 00 e8 00 ac 00 04 00 4b 1d ff 15 +00 00 00 4b 20 00 00 00 00 00 00 5c 00 00 00 00 +20 01 00 00 f3 1c 57 16 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 20 01 00 00 f3 1c 57 16 +06 00 00 28 20 00 00 00 00 00 00 00 13 00 00 00 +24 01 00 00 e7 1c 67 16 00 00 00 14 22 01 00 00 +00 1f 1c 1b 13 00 e8 00 db 00 04 00 ff 1c 7f 16 +00 00 00 4b 22 00 00 00 00 00 00 5b 09 00 00 00 +e8 00 00 00 3f 1d 3f 16 18 00 00 32 20 00 00 00 +34 12 34 12 09 00 00 00 e8 00 00 00 7f 1d 7f 16 +18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 +e8 00 00 00 3f 1d 7f 16 18 00 00 32 20 00 00 00 +34 12 34 12 09 00 00 00 e8 00 00 00 7f 1d 3f 16 +18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 +1a 01 00 00 47 1d 19 16 00 00 00 0e 30 00 00 00 +13 14 00 1c 3f 01 00 00 ad 00 00 00 45 1d 06 16 +01 00 00 32 30 20 00 00 00 20 00 9e 0a 00 00 00 +16 01 00 00 03 1d 0f 16 08 00 00 32 22 01 00 00 +00 00 00 2a 0a 80 21 00 19 01 03 01 47 1d 5f 16 +01 00 02 32 20 20 00 00 00 00 00 29 00 00 00 00 +bf 00 00 00 5b 1d 7f 16 00 56 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 6b 1d 7f 16 +00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 5b 1d 7f 16 08 54 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 6b 1d 7f 16 +08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 13 1d 43 16 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 13 1d 33 16 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 13 1d 33 16 08 55 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 13 1d 43 16 +08 54 00 32 20 00 00 00 00 00 00 00 13 00 ff 07 +c2 00 06 03 2f 1d 03 16 08 00 00 32 20 21 00 00 +00 00 00 5a 13 00 00 00 e8 00 00 00 fb 1c c7 16 +18 00 00 32 20 00 00 00 34 12 34 12 13 00 00 00 +e8 00 00 00 fb 1c 87 16 18 00 00 32 20 00 00 00 +34 12 34 12 09 00 00 00 e8 00 00 00 ff 1c f7 16 +18 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +c7 00 00 00 e7 1c 86 16 0c 00 00 32 a2 00 00 00 +02 00 00 02 00 00 00 00 20 01 00 00 eb 1c 83 16 +00 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 +20 01 00 00 eb 1c 9b 16 00 00 00 28 22 00 00 00 +00 00 00 00 13 00 e8 00 db 00 04 00 ff 1c 9f 16 +00 00 00 4b 22 00 00 00 00 00 00 59 44 81 00 00 +ad 00 00 00 36 1d f4 16 01 00 00 32 30 20 00 00 +00 20 00 a0 09 00 00 00 e8 00 00 00 7f 1d ff 16 +18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 +e8 00 00 00 3f 1d ff 16 18 00 00 32 20 00 00 00 +34 12 34 12 09 00 00 00 e8 00 00 00 7f 1d bf 16 +18 00 00 32 20 00 00 00 34 12 34 12 09 00 00 00 +e8 00 00 00 3f 1d bf 16 18 00 00 32 20 00 00 00 +34 12 34 12 13 00 db 00 dd 00 06 01 07 1d e3 16 +12 00 01 0a a2 20 00 00 02 00 01 58 00 00 00 00 +bf 00 00 00 13 1d bb 16 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 27 1d bb 16 +00 54 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 6b 1d 93 16 00 55 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 5b 1d 93 16 +00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 5b 1d 93 16 08 55 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 6b 1d 8f 16 +08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 13 1d bb 16 08 55 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 23 1d bb 16 +08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +0e 01 00 00 93 1a 4f 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 0e 01 00 00 93 1a 63 17 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 b3 1a 43 17 00 00 00 28 a0 00 00 00 +00 00 00 00 0b 00 00 00 e7 00 00 00 c3 1a 07 17 +00 00 01 32 20 00 00 00 00 00 00 02 41 00 00 00 +c4 00 00 00 df 1a 0b 17 0e 00 02 32 20 00 00 00 +00 00 00 00 08 00 00 00 ff 00 00 00 ef 1a 6b 17 +00 00 00 00 20 00 00 00 03 00 00 1c 00 00 00 00 +c4 00 00 00 8b 1a 7f 17 12 00 00 32 22 00 00 00 +00 00 00 00 1a 00 00 00 e8 00 00 00 ff 1a 7f 17 +18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 +e8 00 00 00 ff 1a 3f 17 18 00 00 32 20 00 00 00 +34 12 34 12 1a 00 00 00 e8 00 00 00 bf 1a 7f 17 +18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 +e8 00 00 00 bf 1a 3f 17 18 00 00 32 20 00 00 00 +34 12 34 12 ee 80 ff 00 17 01 20 00 f7 1a 13 17 +00 00 00 32 20 21 00 00 00 00 00 ad 1b 01 00 00 +ad 00 00 00 b3 1a 7b 17 01 00 02 32 30 20 00 00 +00 60 00 75 00 00 00 00 da 00 00 00 9b 1a 23 17 +06 00 00 32 22 00 00 00 00 00 00 00 0b 80 14 01 +c6 00 00 12 8e 1a 1f 17 06 00 00 32 22 21 00 00 +00 10 1c 31 0b 00 00 00 14 01 00 00 cb 1a 07 17 +0c 00 00 32 20 01 00 00 00 00 00 30 00 00 00 00 +bc 00 00 00 2f 1b 27 17 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 17 1b 17 17 +08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 17 1b 17 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b3 00 00 00 0f 1b 07 17 +12 00 00 32 20 00 00 00 00 00 00 00 05 00 00 00 +24 01 00 00 27 1b 13 17 00 00 00 14 22 01 00 00 +00 00 1f 9b 0d 01 ac 00 d9 00 06 01 3f 1b 4f 17 +00 00 04 32 20 00 00 00 77 66 55 41 1a 00 00 00 +e8 00 00 00 7f 1b 7f 17 18 00 00 32 20 00 00 00 +34 12 34 12 1a 00 00 00 e8 00 00 00 3f 1b 7f 17 +18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 +e8 00 00 00 7f 1b 3f 17 18 00 00 32 20 00 00 00 +34 12 34 12 1a 00 00 00 e8 00 00 00 3f 1b 3f 17 +18 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +0f 01 00 00 43 1b 17 17 00 00 01 32 20 20 00 00 +00 00 00 00 00 00 00 00 0f 01 00 00 5b 1b 17 17 +00 00 00 32 20 20 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 7f 1b 1b 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 3f 1b 1b 17 +00 00 00 32 20 00 00 00 00 00 00 00 17 80 16 01 +dd 00 02 01 33 1b 0b 17 12 00 00 0a a0 20 00 00 +02 00 05 67 00 00 00 00 be 00 00 00 2f 1b 63 17 +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 2f 1b 5b 17 00 00 00 32 22 00 00 00 +00 00 00 00 0d 80 ff 07 0c 01 06 03 63 1b 67 17 +08 00 02 32 22 21 00 00 00 00 00 40 0d 00 00 00 +e8 00 00 00 ff 1b 03 17 18 00 00 32 20 00 00 00 +34 12 34 12 04 00 00 00 24 01 00 00 8f 1b 5b 17 +00 00 00 14 22 01 00 00 00 00 00 1e 11 01 00 00 +ad 00 00 00 8b 1b 37 17 01 00 01 32 32 20 00 00 +00 04 00 52 0d 00 e8 00 ac 00 04 00 83 1b 43 17 +00 00 01 4b 22 00 00 00 00 00 00 3f 00 00 00 00 +c4 00 00 00 9f 1b 0b 17 10 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 c4 00 00 00 e3 1b 0b 17 +10 00 01 32 20 00 00 00 00 00 00 00 9b 80 ff 07 +ee 00 00 00 8b 1b 1f 17 00 00 01 32 20 00 00 00 +00 00 00 00 9b 80 ff 07 ef 00 37 37 9f 1b 23 17 +00 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 +ee 00 00 00 a7 1b 1f 17 00 00 00 32 20 00 00 00 +00 00 00 00 9b 80 ff 07 f0 00 00 00 ab 1b 1f 17 +16 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 +f1 00 00 00 9f 1b 07 17 00 00 00 32 20 00 00 00 +00 00 00 00 0d 00 00 00 1a 01 00 00 cd 1b 1a 17 +02 00 00 0e 30 00 00 00 55 54 20 1c 0d 00 00 00 +e8 00 00 00 ff 1b 43 17 18 00 00 32 20 00 00 00 +34 12 34 12 0d 00 00 00 e8 00 00 00 bf 1b 43 17 +18 00 00 32 20 00 00 00 34 12 34 12 0d 00 00 00 +e8 00 00 00 ff 1b 7f 17 18 00 00 32 20 00 00 00 +34 12 34 12 0d 00 00 00 e8 00 00 00 bf 1b 7f 17 +18 00 00 32 20 00 00 00 34 12 34 12 0d 00 00 00 +ff 00 00 00 bf 1b 27 17 00 00 00 00 20 00 00 00 +02 00 00 3e 0d 00 00 00 e8 00 00 00 bf 1b 03 17 +18 00 00 32 20 00 00 00 34 12 34 12 7c 00 00 00 +d2 00 00 00 3f 1d 7f 17 00 00 00 32 20 00 00 00 +00 00 00 00 7c 00 00 00 d2 00 00 00 3f 1d 3f 17 +00 00 00 32 20 00 00 00 00 00 00 00 7c 00 00 00 +d2 00 00 00 7f 1d 7f 17 00 00 00 32 20 00 00 00 +00 00 00 00 7c 00 00 00 d2 00 00 00 7f 1d 3f 17 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +e3 00 00 00 4f 1d 6f 17 00 00 00 32 20 00 00 00 +00 00 00 00 32 00 00 00 1a 01 00 00 1d 1d 2b 17 +04 00 00 0e 30 00 00 00 15 14 00 1c 00 00 00 00 +0d 01 00 00 23 1d 5b 17 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 b0 00 00 00 23 1d 17 17 +04 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 13 1d 17 17 04 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 23 1d 17 17 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 13 1d 17 17 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 27 1d 47 17 +04 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 2b 1d 47 17 04 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 4f 1d 43 17 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +0d 01 00 00 4f 1d 43 17 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 0d 01 00 00 4f 1d 23 17 +04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +0d 01 00 00 23 1d 3b 17 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 0d 01 00 00 23 1d 7f 17 +04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +c0 00 00 00 27 1d 63 17 04 00 01 32 22 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 27 1d 5b 17 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 27 1d 4b 17 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 4f 1d 47 17 +04 00 00 32 20 00 00 00 00 00 00 00 35 81 21 00 +19 01 03 00 24 1d 41 17 05 00 02 32 20 20 00 00 +00 00 00 97 35 01 00 00 ad 00 00 00 30 1d 2c 17 +05 00 01 32 30 20 00 00 00 40 00 96 00 00 00 00 +bc 00 00 00 4f 1d 23 17 04 00 00 32 22 00 00 00 +00 00 00 00 09 00 e8 00 ac 00 04 00 4b 1d 03 17 +04 00 00 4b 20 00 00 00 00 00 00 23 09 00 00 00 +16 01 00 00 07 1d 2f 17 10 00 00 32 22 01 00 00 +00 00 00 22 00 00 00 00 bc 00 00 00 4b 1d 47 17 +04 00 00 32 20 00 00 00 00 00 00 00 32 00 00 00 +1a 01 00 00 1b 1d 4f 17 04 00 00 0e 30 00 00 00 +15 14 08 1c 01 00 00 00 1b 01 00 00 73 1d 2b 17 +05 00 00 32 20 00 00 00 00 00 00 07 09 00 ac 00 +c2 00 06 01 2e 1d 07 17 0e 00 00 32 20 21 00 00 +00 00 00 21 40 00 00 00 d2 00 00 00 ff 1d 7f 17 +00 00 00 32 20 00 00 00 00 00 00 00 40 00 00 00 +d2 00 00 00 bf 1d 7f 17 00 00 00 32 20 00 00 00 +00 00 00 00 40 00 00 00 d2 00 00 00 ff 1d 3f 17 +00 00 00 32 20 00 00 00 00 00 00 00 40 00 00 00 +d2 00 00 00 bf 1d 3f 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 0d 01 00 00 8f 1d 23 17 +04 00 00 32 20 00 00 00 77 66 55 00 01 00 00 00 +e0 00 00 00 8c 1d 20 17 0c 00 00 ff a0 00 00 00 +02 00 00 01 00 00 00 00 b3 00 00 00 87 1a 97 17 +12 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +00 01 00 00 f3 1a 9b 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 cf 1a 83 17 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 d7 1a 83 17 00 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 df 1a 83 17 +00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 ff 1a 83 17 00 00 00 32 20 00 00 00 +00 00 00 00 1a 00 00 00 e8 00 00 00 ff 1a ff 17 +18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 +e8 00 00 00 bf 1a ff 17 18 00 00 32 20 00 00 00 +34 12 34 12 1a 00 00 00 e8 00 00 00 bf 1a bf 17 +18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 +e8 00 00 00 ff 1a bf 17 18 00 00 32 20 00 00 00 +34 12 34 12 00 00 00 00 e5 00 00 00 f5 1a ac 17 +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +cb 00 00 00 87 1a df 17 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 ea 00 00 00 93 1a 97 17 +00 00 00 32 22 00 00 00 00 00 00 00 1a 00 00 00 +1a 01 00 00 a7 1a 8b 17 00 00 00 0e 30 00 00 00 +53 54 08 1d 1a 00 00 00 1a 01 00 00 bf 1a c9 17 +00 00 00 0e 30 00 00 00 51 54 00 1c 00 00 00 00 +0e 01 00 00 fb 1a e3 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 0e 01 00 00 df 1a e3 17 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 7b 1b 87 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 77 1b 87 17 +00 00 00 32 20 00 00 00 00 00 00 00 1a 00 00 00 +1a 01 00 00 21 1b c1 17 00 00 00 04 30 00 00 00 +13 15 00 08 00 00 00 00 00 01 00 00 4b 1b 9b 17 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +00 01 00 00 1f 1b 9b 17 00 00 00 32 20 00 00 00 +00 00 00 00 1a 00 00 00 e8 00 00 00 7f 1b ff 17 +18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 +e8 00 00 00 3f 1b ff 17 18 00 00 32 20 00 00 00 +34 12 34 12 1a 00 00 00 e8 00 00 00 7f 1b bf 17 +18 00 00 32 20 00 00 00 34 12 34 12 1a 00 00 00 +e8 00 00 00 3f 1b bf 17 18 00 00 32 20 00 00 00 +34 12 34 12 00 00 00 00 e5 00 00 00 44 1b aa 17 +00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +e5 00 00 00 19 1b ac 17 00 00 01 32 22 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 57 1b 87 17 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 67 1b 87 17 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 2f 1b 83 17 +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +c4 00 00 00 9f 1b 8b 17 12 00 02 32 20 00 00 00 +00 00 00 00 90 80 ff 07 cd 00 00 00 cb 1b 9b 17 +00 00 00 32 20 00 00 00 00 00 00 00 90 80 ff 07 +d0 00 00 00 c7 1b 9f 17 14 00 00 32 20 00 00 00 +00 00 00 00 90 80 ff 07 cd 00 00 00 a7 1b 9b 17 +00 00 01 32 20 00 00 00 00 00 00 00 90 80 ff 07 +ce 00 00 00 bb 1b 87 17 00 00 00 32 20 00 00 00 +00 00 00 00 90 80 ff 07 cf 00 2c 2c c3 1b 9b 17 +00 00 00 32 20 00 00 00 00 00 00 00 37 00 00 00 +1a 01 00 00 9a 1b d0 17 02 00 00 0e 30 00 00 00 +53 54 20 1c 00 00 00 00 c4 00 00 00 d7 1b 8b 17 +12 00 02 32 20 00 00 00 00 00 00 00 37 01 00 00 +ad 00 00 00 bf 1b f7 17 01 00 02 32 30 20 00 00 +00 60 00 98 32 80 21 00 19 01 03 01 22 1d a7 17 +05 00 02 32 20 20 00 00 00 00 00 91 00 00 00 00 +bd 00 00 00 27 1d 93 17 04 00 00 32 22 00 00 00 +00 00 00 00 61 80 f8 00 10 01 03 00 03 1d cf 17 +04 00 01 32 22 20 00 00 00 00 00 a1 83 00 00 00 +d2 00 00 00 3f 1d ff 17 00 00 00 32 20 00 00 00 +00 00 00 00 83 00 00 00 d2 00 00 00 3f 1d bf 17 +00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 +d2 00 00 00 7f 1d ff 17 00 00 00 32 20 00 00 00 +00 00 00 00 83 00 00 00 d2 00 00 00 7f 1d bf 17 +00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 +0d 01 00 00 23 1d ff 17 04 00 00 32 20 00 00 00 +77 66 55 00 83 00 00 00 0d 01 00 00 23 1d 9f 17 +04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 +0d 01 00 00 23 1d bf 17 04 00 00 32 20 00 00 00 +77 66 55 00 83 00 00 00 0d 01 00 00 23 1d df 17 +04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +c0 00 00 00 6b 1d fb 17 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 27 1d fb 17 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 67 1d fb 17 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 0d 01 00 00 23 1d ff 17 +04 00 00 32 20 00 00 00 77 66 55 00 35 00 00 00 +1a 01 00 00 1e 1d fd 17 04 00 00 0e 30 00 00 00 +11 11 00 1c 00 00 00 00 bc 00 00 00 27 1d 83 17 +04 00 00 32 22 00 00 00 00 00 00 00 61 00 00 00 +f8 00 00 44 28 1d d0 17 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 27 1d 9b 17 +04 00 05 32 22 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 27 1d f7 17 04 00 01 32 22 00 00 00 +00 00 00 00 35 80 21 00 19 01 03 01 23 1d 87 17 +05 00 02 32 20 20 00 00 00 00 00 95 00 00 00 00 +c0 00 00 00 af 1d af 17 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 8b 1d af 17 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 af 1d b7 17 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 8b 1d b7 17 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 af 1d c7 17 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 8b 1d c7 17 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 af 1d e7 17 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 8b 1d e7 17 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +0d 01 00 00 ab 1d cb 17 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 e3 00 00 00 87 1d e3 17 +00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 +d2 00 00 00 ff 1d ff 17 00 00 00 32 20 00 00 00 +00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d ff 17 +00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 +d2 00 00 00 ff 1d bf 17 00 00 00 32 20 00 00 00 +00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d bf 17 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +0d 01 00 00 ab 1d eb 17 04 00 00 32 20 00 00 00 +77 66 55 00 18 00 00 00 e8 00 00 00 ff 1a 7f 18 +18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 +e8 00 00 00 ff 1a 3f 18 18 00 00 32 20 00 00 00 +34 12 34 12 18 00 00 00 e8 00 00 00 bf 1a 03 18 +18 00 00 32 20 00 00 00 34 12 34 12 04 00 00 00 +1a 01 00 00 e3 1a 1c 18 00 00 00 7d 30 00 00 00 +05 00 00 45 00 00 00 00 00 01 00 00 d3 1a 63 18 +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +e5 00 00 00 ee 1a 5a 18 00 00 02 32 22 00 00 00 +00 00 00 00 04 00 00 00 28 01 00 00 eb 1a 27 18 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c4 00 00 00 fb 1a 0b 18 10 00 02 32 20 00 00 00 +00 00 00 00 04 00 ff 00 17 01 20 00 07 1b 17 18 +00 00 00 32 20 21 00 00 00 00 00 0e 00 00 00 00 +b3 00 00 00 1b 1b 07 18 12 00 00 32 20 00 00 00 +00 00 00 00 18 00 00 00 e8 00 00 00 3f 1b 3f 18 +18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 +e8 00 00 00 3f 1b 7f 18 18 00 00 32 20 00 00 00 +34 12 34 12 18 00 00 00 e8 00 00 00 7f 1b 3f 18 +18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 +e8 00 00 00 7f 1b 7f 18 18 00 00 32 20 00 00 00 +34 12 34 12 04 00 00 00 f2 00 00 00 0e 1b 28 18 +00 00 00 32 20 00 00 00 00 00 00 00 1a 00 e8 00 +ac 00 04 00 43 1b 03 18 00 00 01 4b 20 00 00 00 +00 00 00 71 1a 00 ff 07 c2 00 06 03 52 1b 07 18 +0b 00 00 32 20 21 00 00 00 00 00 70 19 00 00 00 +1a 01 00 00 39 1b 52 18 00 00 00 04 30 00 00 00 +25 25 00 09 1a 01 ff 07 1d 01 02 00 30 1b 11 18 +00 00 00 4b 20 00 00 00 00 00 00 6f 1a 80 ac 00 +d9 00 06 01 7f 1b 3f 18 00 00 04 32 20 00 00 00 +77 66 55 6e 18 00 e8 00 ac 00 04 00 83 1b 3f 18 +00 00 01 4b 22 00 00 00 00 00 00 6a 00 00 00 00 +b3 00 00 00 af 1b 03 18 10 00 00 32 20 00 00 00 +00 00 00 00 01 00 00 00 1a 01 00 00 bf 1b 50 18 +00 00 00 04 30 00 00 00 15 15 00 09 02 00 00 00 +1a 01 00 00 c2 1b 37 18 00 00 00 0e 30 00 00 00 +15 14 00 1d 06 00 00 00 c7 00 00 00 eb 1b 0b 18 +0a 00 00 32 a0 00 00 00 02 00 00 02 18 80 ac 00 +c2 00 06 01 87 1b 4b 18 0c 00 00 32 22 21 00 00 +00 00 00 69 17 80 16 01 dd 00 02 01 8b 1b 6b 18 +10 00 00 0a a2 20 00 00 02 00 05 66 00 00 00 00 +c4 00 00 00 93 1b 07 18 10 00 01 32 20 00 00 00 +00 00 00 00 02 00 00 00 1a 01 00 00 c3 1b 1f 18 +00 00 00 0e 30 00 00 00 11 14 10 1d 00 00 00 00 +b0 00 00 00 4f 1d 3b 18 04 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 3b 1d 3b 18 +04 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 63 1d 3b 18 04 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b8 00 00 00 4f 1d 0b 18 +04 00 03 32 20 00 00 00 00 00 00 00 07 00 00 00 +13 01 00 00 44 1d 11 18 04 00 00 32 22 00 00 00 +00 00 00 00 32 01 00 00 ad 00 00 00 74 1d 1d 18 +05 00 0c 32 32 20 00 00 00 33 00 90 32 80 21 00 +19 01 03 03 23 1d 6b 18 05 00 02 32 20 20 00 00 +00 00 00 8f 2f 00 00 00 1a 01 00 00 1c 1d 42 18 +04 00 00 0e 30 00 00 00 15 11 00 1c 00 00 00 00 +e3 00 00 00 5f 1d 7f 18 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 5f 1d 0f 18 +04 00 02 32 20 00 00 00 00 00 00 00 33 80 21 00 +19 01 03 03 6b 1d 2b 18 05 00 02 32 20 20 00 00 +00 00 00 93 00 00 00 00 c0 00 00 00 6b 1d 07 18 +04 00 01 32 22 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 6b 1d 33 18 04 00 01 32 22 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 6b 1d 0b 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 6b 1d 2f 18 04 00 00 32 20 00 00 00 +00 00 00 00 83 00 00 00 d2 00 00 00 3f 1d 7f 18 +00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 +d2 00 00 00 3f 1d 3f 18 00 00 00 32 20 00 00 00 +00 00 00 00 83 00 00 00 d2 00 00 00 7f 1d 7f 18 +00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 +d2 00 00 00 7f 1d 3f 18 00 00 00 32 20 00 00 00 +00 00 00 00 83 00 00 00 0d 01 00 00 23 1d 7f 18 +04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 +0d 01 00 00 23 1d 1f 18 04 00 00 32 20 00 00 00 +77 66 55 00 83 00 00 00 0d 01 00 00 23 1d 3f 18 +04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 +0d 01 00 00 23 1d 5f 18 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 0d 01 00 00 47 1d 3b 18 +04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +0d 01 00 00 47 1d 1b 18 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 0d 01 00 00 67 1d 3b 18 +04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +0d 01 00 00 67 1d 1b 18 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 c0 00 00 00 27 1d 3f 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 6b 1d 3f 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 27 1d 43 18 +04 00 01 32 22 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 47 1d 3f 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 57 1d 3f 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 67 1d 3f 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 6b 1d 03 18 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 6b 1d 3b 18 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 b6 00 00 00 0f 1d 0b 18 +04 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +b8 00 00 00 0f 1d 0b 18 10 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 77 1d 0b 18 +04 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 6f 1d 0b 18 04 00 01 32 20 00 00 00 +00 00 00 00 35 00 00 00 ff 00 00 00 3b 1d 4b 18 +00 00 00 00 20 00 00 00 00 00 00 94 01 01 00 00 +ad 00 00 00 14 1d 3d 18 05 00 07 32 32 20 00 00 +00 14 00 06 00 00 00 00 bb 00 00 00 eb 1d 2f 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +0d 01 00 00 cb 1d 2b 18 04 00 00 32 20 00 00 00 +77 66 55 00 33 00 00 00 1a 01 00 00 ad 1d 23 18 +04 00 00 0e 30 00 00 00 17 14 00 1c 00 00 00 00 +e3 00 00 00 c3 1d 4f 18 00 00 00 32 20 00 00 00 +00 00 00 00 07 10 13 01 ae 00 02 01 d7 1d 1f 18 +0c 00 00 32 20 21 00 00 00 00 00 19 00 00 00 00 +b0 00 00 00 db 1d 23 18 04 00 02 32 20 00 00 00 +00 00 00 00 02 00 00 00 0d 01 00 00 eb 1d 2b 18 +04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +0d 01 00 00 ab 1d 2b 18 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 0d 01 00 00 8b 1d 2b 18 +04 00 00 32 20 00 00 00 77 66 55 00 3f 00 00 00 +d2 00 00 00 ff 1d 7f 18 00 00 00 32 20 00 00 00 +00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d 7f 18 +00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 +d2 00 00 00 ff 1d 3f 18 00 00 00 32 20 00 00 00 +00 00 00 00 3f 00 00 00 d2 00 00 00 bf 1d 3f 18 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +0d 01 00 00 ab 1d 07 18 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 c0 00 00 00 8b 1d 0b 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 87 1d 0b 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 8b 1d 07 18 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 af 1d 07 18 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 ef 1d 0b 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 af 1d 0b 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 ab 1d 2f 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 ef 1d 2f 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 f3 1d 0b 18 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 f3 1d 2f 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 f3 1d 2b 18 +04 00 00 32 22 00 00 00 00 00 00 00 18 00 00 00 +e8 00 00 00 ff 1a 87 18 18 00 00 32 20 00 00 00 +34 12 34 12 18 00 00 00 e8 00 00 00 7f 1b 85 18 +18 00 00 32 20 00 00 00 34 12 34 12 18 00 00 00 +e8 00 00 00 3f 1b 86 18 18 00 00 32 20 00 00 00 +34 12 34 12 06 01 00 00 ad 00 00 00 bd 1b b7 18 +01 00 03 32 30 20 00 00 00 80 00 17 17 00 00 00 +16 01 00 00 87 1b 8f 18 08 00 00 32 22 01 00 00 +00 00 00 65 00 00 00 00 b8 00 00 00 8f 1b f7 18 +00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b8 00 00 00 8f 1b ef 18 00 00 02 32 20 00 00 00 +00 00 00 00 02 01 00 00 ad 00 00 00 bf 1b 8f 18 +01 00 02 32 30 20 00 00 00 60 00 0d 06 00 00 00 +e8 00 00 00 ef 1b ef 18 30 00 00 32 20 00 00 00 +34 12 34 12 02 80 21 00 19 01 03 08 d0 1b 8e 18 +01 00 02 32 20 20 00 00 00 00 00 0c 01 80 1f 00 +19 01 07 07 c5 1b c3 18 01 00 02 32 20 20 00 00 +00 00 00 05 00 00 00 00 e6 00 00 00 93 1b d3 18 +00 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 93 1b cb 18 06 00 00 28 22 00 00 00 +00 00 00 00 1b 00 00 00 1a 01 00 00 a4 1b 9c 18 +00 00 00 0e 30 00 00 00 54 54 08 1c 00 00 00 00 +e6 00 00 00 93 1b bf 18 00 00 00 28 22 00 00 00 +00 00 00 00 06 00 00 00 e8 00 00 00 2f 1c ef 18 +30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +0d 01 00 00 23 1d df 18 04 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 c0 00 00 00 27 1d 87 18 +04 00 05 32 22 00 00 00 00 00 00 00 2f 80 21 00 +19 01 03 01 22 1d 81 18 05 00 02 32 20 20 00 00 +00 00 00 8e 1f 00 00 00 1a 01 00 00 1b 1d e7 18 +04 00 00 0e 30 00 00 00 35 34 10 1c 00 00 00 00 +e3 00 00 00 53 1d ef 18 00 00 00 32 20 00 00 00 +00 00 00 00 33 01 00 00 ad 00 00 00 13 1d a7 18 +05 00 06 32 32 20 00 00 00 22 00 92 01 80 f8 00 +10 01 00 00 03 1d cf 18 04 00 01 32 22 20 00 00 +00 00 00 04 83 00 00 00 d2 00 00 00 3f 1d ff 18 +00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 +d2 00 00 00 3f 1d bf 18 00 00 00 32 20 00 00 00 +00 00 00 00 83 00 00 00 d2 00 00 00 7f 1d ff 18 +00 00 00 32 20 00 00 00 00 00 00 00 83 00 00 00 +d2 00 00 00 7f 1d bf 18 00 00 00 32 20 00 00 00 +00 00 00 00 83 00 00 00 0d 01 00 00 23 1d ff 18 +04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 +0d 01 00 00 23 1d 9f 18 04 00 00 32 20 00 00 00 +77 66 55 00 83 00 00 00 0d 01 00 00 23 1d bf 18 +04 00 00 32 20 00 00 00 77 66 55 00 83 00 00 00 +0d 01 00 00 23 1d df 18 04 00 00 32 20 00 00 00 +77 66 55 00 2f 00 00 00 ff 00 00 00 3b 1d f5 18 +00 00 00 00 20 00 00 00 00 00 00 8d 01 00 00 00 +f8 00 00 74 28 1d ce 18 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 27 1d 8f 18 +04 00 04 32 22 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 27 1d 97 18 04 00 04 32 22 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 27 1d 9f 18 +04 00 05 32 22 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 27 1d 83 18 04 00 00 32 22 00 00 00 +00 00 00 00 3f 00 00 00 d2 00 00 00 ff 1d ff 18 +00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 +d2 00 00 00 bf 1d ff 18 00 00 00 32 20 00 00 00 +00 00 00 00 3f 00 00 00 d2 00 00 00 ff 1d bf 18 +00 00 00 32 20 00 00 00 00 00 00 00 3f 00 00 00 +d2 00 00 00 bf 1d bf 18 00 00 00 32 20 00 00 00 +00 00 00 00 17 80 16 01 dd 00 02 01 8b 1b 05 19 +10 00 03 0a a2 20 00 00 02 00 05 64 01 01 00 00 +ad 00 00 00 bd 1b 64 19 01 00 05 32 30 20 00 00 +00 e0 00 03 01 00 00 00 ff 00 00 00 8b 1b 03 19 +00 00 00 00 20 00 00 00 00 00 00 02 06 00 00 00 +e8 00 00 00 ef 1b 2f 19 30 00 00 32 20 00 00 00 +34 12 34 12 06 00 00 00 e8 00 00 00 ef 1b 6f 19 +30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +b8 00 00 00 8f 1b 1b 19 00 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b8 00 00 00 8f 1b 13 19 +00 00 02 32 20 00 00 00 00 00 00 00 02 00 00 00 +eb 00 00 00 9b 1b 07 19 00 00 00 00 a0 00 00 00 +00 00 00 00 02 00 00 00 eb 00 00 00 bb 1b 07 19 +00 00 00 00 a0 00 00 00 00 00 00 00 02 00 00 00 +eb 00 00 00 cb 1b 07 19 00 00 00 00 a0 00 00 00 +00 00 00 00 02 00 00 00 eb 00 00 00 ab 1b 07 19 +00 00 00 00 a0 00 00 00 00 00 00 00 02 00 00 00 +eb 00 00 00 db 1b 07 19 00 00 00 00 a0 00 00 00 +00 00 00 00 02 00 00 00 eb 00 00 00 eb 1b 07 19 +00 00 00 00 a0 00 00 00 00 00 00 00 02 00 00 00 +eb 00 00 00 fb 1b 07 19 00 00 00 00 a0 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 97 1b 43 19 +00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 a7 1b 43 19 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 97 1b 43 19 +06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 a7 1b 43 19 06 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 a7 1b 43 19 +0c 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 e7 1b 3f 19 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 d7 1b 3f 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 ef 1b 3f 19 08 54 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 df 1b 3f 19 +08 55 00 32 20 00 00 00 00 00 00 00 06 00 00 00 +e8 00 00 00 cf 1b 6b 19 1a 00 00 32 20 00 00 00 +34 12 34 12 06 00 00 00 e8 00 00 00 2f 1c 2f 19 +30 00 00 32 20 00 00 00 34 12 34 12 06 00 00 00 +e8 00 00 00 2f 1c 6f 19 30 00 00 32 20 00 00 00 +34 12 34 12 0b 80 16 01 dc 00 02 01 8b 1c 0b 19 +14 00 00 0a a0 20 00 00 00 00 00 2f 1b 00 00 00 +1e 01 00 00 d7 1c 57 19 06 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 b8 00 00 00 c3 1c 53 19 +08 00 06 32 20 00 00 00 00 00 00 00 1b 00 00 00 +18 01 89 06 cf 1c 23 19 04 00 00 32 20 00 00 00 +06 00 24 74 00 00 00 00 de 00 00 00 f3 1c 13 19 +04 00 00 32 20 20 00 00 00 00 00 00 00 00 00 00 +de 00 00 00 d3 1c 13 19 04 00 00 32 20 20 00 00 +00 00 00 00 00 00 00 00 de 00 00 00 b3 1c 13 19 +04 00 00 32 20 20 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 af 1c 77 19 06 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 b3 1c 7b 19 +0e 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 b3 1c 53 19 0e 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b4 00 00 00 af 1c 6b 19 +10 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 b3 1c 53 19 06 00 04 32 22 00 00 00 +00 00 00 00 20 81 00 00 ad 00 00 00 db 1c 77 19 +05 00 01 32 30 20 00 00 00 40 00 85 33 00 00 00 +1a 01 00 00 c7 1c 63 19 04 00 00 0e 30 00 00 00 +35 34 10 1d 00 00 00 00 2b 01 00 80 9b 1c 57 19 +04 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 fb 1c 4b 19 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 ff 1c 5f 19 +00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 27 1d 1f 19 04 00 00 32 22 00 00 00 +00 00 00 00 2f 01 00 00 ad 00 00 00 04 1d 2b 19 +05 00 07 32 32 20 00 00 00 13 00 8c 00 00 00 00 +bc 00 00 00 23 1d 43 19 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 27 1d 3f 19 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 73 1d 7f 19 04 00 00 32 20 00 00 00 +00 00 00 00 1b 01 00 00 ad 00 00 00 13 1d 07 19 +05 00 06 32 32 20 00 00 00 22 00 73 00 00 00 00 +c0 00 00 00 03 1d 7f 19 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 e3 00 00 00 23 1d 5f 19 +00 00 00 32 20 00 00 00 00 00 00 00 82 00 00 00 +d2 00 00 00 7f 1d 3f 19 00 00 00 32 20 00 00 00 +00 00 00 00 82 00 00 00 d2 00 00 00 7f 1d 7f 19 +00 00 00 32 20 00 00 00 00 00 00 00 82 00 00 00 +d2 00 00 00 43 1d 3f 19 00 00 00 32 20 00 00 00 +00 00 00 00 82 00 00 00 d2 00 00 00 43 1d 7f 19 +00 00 00 32 20 00 00 00 00 00 00 00 82 00 00 00 +0d 01 00 00 23 1d 3b 19 04 00 00 32 20 00 00 00 +77 66 55 00 82 00 00 00 0d 01 00 00 23 1d 17 19 +04 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +bc 00 00 00 03 1d 7b 19 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 03 1d 5b 19 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 03 1d 4b 19 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 23 1d 7f 19 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 63 1d 7f 19 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 03 1d 43 19 +04 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 bf 1d 3f 19 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 ff 1d 3f 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 bf 1d 7f 19 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 ff 1d 7f 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 83 1d 7f 19 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c7 00 00 00 0f 1b 9f 19 +0e 00 00 32 a2 00 00 00 02 00 00 02 00 00 00 00 +b7 00 00 00 1f 1b d7 19 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b8 00 00 00 1f 1b d7 19 +08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b5 00 00 00 13 1b d7 19 0a 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 57 1b f7 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 63 1b a3 19 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 63 1b a7 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 13 1b a3 19 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 19 1b 94 19 +00 00 00 28 a0 00 00 00 00 00 00 00 1d 00 f4 00 +ba 00 04 00 57 1b 87 19 0a 00 00 32 20 21 00 00 +00 00 00 78 0b 00 00 00 24 01 00 00 7b 1b 8f 19 +00 00 00 14 20 01 00 00 00 00 00 5d 00 00 00 00 +e6 00 00 00 33 1b df 19 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 33 1b df 19 +06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +d5 00 00 00 4f 1b d3 19 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 3f 1b db 19 +00 00 00 28 a0 00 00 00 00 00 00 00 05 00 00 00 +e8 00 00 00 47 1b ff 19 1a 00 00 32 20 00 00 00 +34 12 34 12 00 00 00 00 2b 01 00 00 47 1b 97 19 +00 00 00 28 a0 00 00 00 00 00 00 00 05 00 00 00 +e8 00 00 00 47 1b c7 19 1a 00 00 32 20 00 00 00 +34 12 34 12 1d 00 00 00 f4 00 00 00 ff 1b d3 19 +00 00 00 32 22 00 00 00 00 00 00 00 05 00 00 00 +1a 01 00 00 a7 1b af 19 00 00 00 0e 30 00 00 00 +35 34 10 1c 05 00 00 00 1a 01 00 00 eb 1b b7 19 +00 00 00 0e 30 00 00 00 31 34 08 1c 06 80 00 00 +cc 00 00 00 ea 1b 94 19 00 00 00 32 20 00 00 00 +06 0a 01 06 05 80 00 00 cc 00 00 00 e2 1b 94 19 +00 00 00 32 20 00 00 00 05 0a 01 06 04 80 00 00 +cc 00 00 00 d6 1b 94 19 00 00 00 32 20 00 00 00 +04 0a 01 06 03 80 00 00 cc 00 00 00 cc 1b 94 19 +00 00 00 32 20 00 00 00 03 0a 01 06 02 80 00 00 +cc 00 00 00 c1 1b 95 19 00 00 00 32 20 00 00 00 +02 0a 01 06 01 80 00 00 cc 00 00 00 b8 1b 95 19 +00 00 00 32 20 00 00 00 01 0a 01 06 00 00 00 00 +c0 00 00 00 a3 1b 97 19 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 a3 1b 93 19 +00 00 00 32 22 00 00 00 00 00 00 00 1d 00 00 00 +f4 00 00 00 ff 1b bb 19 00 00 00 32 22 00 00 00 +00 00 00 00 01 00 00 00 15 01 00 00 97 1b 94 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 c3 1b f3 19 00 00 00 32 20 00 00 00 +00 00 00 00 06 00 ac 00 ec 00 06 01 af 1b 87 19 +0e 00 00 32 20 21 00 00 00 00 00 16 06 00 e8 00 +ac 00 04 00 cf 1b 83 19 00 00 00 4b 20 00 00 00 +00 00 00 15 05 00 00 00 e8 00 00 00 87 1b ff 19 +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 +e8 00 00 00 c7 1b ff 19 1a 00 00 32 20 00 00 00 +34 12 34 12 05 00 00 00 e8 00 00 00 87 1b c7 19 +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 +e8 00 00 00 c7 1b c7 19 1a 00 00 32 20 00 00 00 +34 12 34 12 05 00 00 00 e8 00 00 00 ff 1b c7 19 +1a 00 00 32 20 00 00 00 34 12 34 12 ff 00 00 00 +1a 01 00 00 85 1b d3 19 00 00 00 0e 30 00 00 00 +31 34 40 1c 22 80 00 00 27 01 01 00 80 1b d4 19 +00 00 00 32 00 20 00 00 00 00 00 89 22 01 00 00 +ad 00 00 00 cb 1b a7 19 01 00 0c 32 32 20 00 00 +00 44 00 88 06 00 00 00 e8 00 00 00 ef 1b af 19 +30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +d1 00 00 00 77 1c 93 19 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 67 1c 93 19 +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 0f 1c 93 19 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 1f 1c 93 19 +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 2f 1c 93 19 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 53 1c 93 19 +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 43 1c 93 19 18 00 00 32 20 00 00 00 +00 00 00 00 0b 00 00 00 f4 00 00 00 7f 1c df 19 +00 00 00 32 22 00 00 00 00 00 00 00 1d 00 f4 00 +ba 00 03 00 0f 1c 9b 19 0a 00 00 32 20 21 00 00 +00 00 00 77 1e 01 00 00 ad 00 00 00 77 1c c7 19 +01 00 02 32 32 20 00 00 00 06 00 79 0b 00 f4 00 +f3 00 04 00 5b 1c 9b 19 0f 00 01 32 20 21 00 00 +00 00 00 2e 05 00 00 00 e8 00 00 00 03 1c ff 19 +1a 00 00 32 20 00 00 00 34 12 34 12 06 00 00 00 +e8 00 00 00 03 1c 83 19 1a 00 00 32 20 00 00 00 +34 12 34 12 0b 00 00 00 f4 00 00 00 7f 1c c7 19 +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 cb 1c 83 19 04 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 cb 1c b7 19 +08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 bb 1c b7 19 08 55 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 bb 1c bf 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 cb 1c bf 19 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 bb 1c af 19 +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 cb 1c af 19 00 00 00 32 20 00 00 00 +00 00 00 00 1b 01 00 00 ad 00 00 00 bb 1c c5 19 +01 00 02 32 32 20 00 00 00 06 00 72 0b 00 00 00 +16 01 00 00 9b 1c a3 19 0e 00 00 32 20 01 00 00 +00 00 00 2d 00 00 00 00 b3 00 00 00 9f 1c a3 19 +16 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 cb 1c 93 19 04 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 cb 1c 8b 19 +04 00 00 32 22 00 00 00 00 00 00 00 ff 00 00 00 +1a 01 00 00 bf 1c 8f 19 04 00 00 0e 30 00 00 00 +52 54 08 1d 00 00 00 00 be 00 00 00 cb 1c 9b 19 +04 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +2b 01 00 80 53 1d d7 19 04 00 00 28 a2 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 63 1d df 19 +00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 13 1d 8f 19 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 23 1d 8f 19 +00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 33 1d 8f 19 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 33 1d 8f 19 +06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 23 1d 8f 19 06 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 13 1d 8f 19 +06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 13 1d 8f 19 0c 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 23 1d 8f 19 +0c 00 00 28 20 00 00 00 00 00 00 00 05 00 e8 00 +ac 00 04 00 4b 1b 7f 1a 00 00 00 4b 20 00 00 00 +00 00 00 14 00 00 00 00 b9 00 00 00 57 1b 3f 1a +00 00 00 32 20 00 00 00 00 00 00 00 05 01 00 00 +ad 00 00 00 37 1b 71 1a 01 00 06 32 32 20 00 00 +00 22 00 13 05 00 00 00 1a 01 00 00 76 1b 38 1a +00 00 00 0e 30 00 00 00 51 54 00 1c 00 00 00 00 +b4 00 00 00 53 1b 0f 1a 02 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 57 1b 1f 1a +08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 57 1b 1f 1a 00 00 02 32 20 00 00 00 +00 00 00 00 01 00 00 00 15 01 00 00 13 1b 53 1a +00 00 00 32 22 00 00 00 00 00 00 00 05 00 00 00 +e8 00 00 00 47 1b 7f 1a 1a 00 00 32 20 00 00 00 +34 12 34 12 05 00 00 00 e8 00 00 00 47 1b 3f 1a +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 +e8 00 00 00 07 1b 7f 1a 1a 00 00 32 20 00 00 00 +34 12 34 12 05 00 00 00 e8 00 00 00 07 1b 3f 1a +1a 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +b0 00 00 00 c7 1b 1f 1a 08 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b4 00 00 00 bf 1b 0b 1a +02 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 c3 1b 1b 1a 00 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 d7 00 00 00 a3 1b 3f 1a +00 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +d7 00 00 00 c7 1b 3f 1a 00 00 00 32 20 00 00 00 +00 00 00 00 05 00 00 00 e8 00 00 00 87 1b 7f 1a +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 +e8 00 00 00 c7 1b 7f 1a 1a 00 00 32 20 00 00 00 +34 12 34 12 05 00 00 00 e8 00 00 00 ff 1b 7f 1a +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 +e8 00 00 00 87 1b 3f 1a 1a 00 00 32 20 00 00 00 +34 12 34 12 05 00 00 00 e8 00 00 00 c7 1b 3f 1a +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 +e8 00 00 00 ff 1b 3f 1a 1a 00 00 32 20 00 00 00 +34 12 34 12 0e 00 00 00 e8 00 00 00 47 1b c3 1a +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 1a 01 +1d 01 02 00 11 1b a6 1a 00 00 00 4b 20 00 00 00 +00 00 00 12 05 00 ac 00 c2 00 06 01 58 1b 83 1a +0b 00 00 32 20 21 00 00 00 00 00 11 10 80 00 00 +e1 00 00 00 67 1b fb 1a 0e 00 00 32 20 00 00 00 +00 00 00 4c 10 80 00 00 e2 00 00 00 47 1b fb 1a +0e 00 00 32 20 00 00 00 00 00 00 4b 0e 00 00 00 +1a 01 00 00 5b 1b ab 1a 00 00 00 0e 30 00 00 00 +55 54 08 1c 0e 00 00 00 1a 01 00 00 20 1b ca 1a +00 00 00 0e 30 00 00 00 53 54 00 1c 0f 00 00 00 +1a 01 00 00 43 1b b3 1a 00 00 00 0e 30 00 00 00 +53 54 00 1c 13 00 00 00 bf 00 00 00 23 1b ef 1a +08 56 00 32 20 00 00 00 00 00 00 00 13 00 00 00 +bf 00 00 00 13 1b ef 1a 08 55 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 23 1b ef 1a +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 13 1b ef 1a 00 00 00 32 20 00 00 00 +00 00 00 00 12 00 00 00 bf 00 00 00 7b 1b db 1a +00 00 00 32 20 00 00 00 00 00 00 00 12 00 00 00 +bf 00 00 00 67 1b e3 1a 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 67 1b d3 1a +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 6b 1b df 1a 08 54 00 32 20 00 00 00 +00 00 00 00 05 00 00 00 e8 00 00 00 c3 1b 83 1a +1a 00 00 32 20 00 00 00 34 12 34 12 0e 00 00 00 +e8 00 00 00 83 1b c3 1a 1a 00 00 32 20 00 00 00 +34 12 34 12 05 00 00 00 e8 00 00 00 03 1c 83 1a +1a 00 00 32 20 00 00 00 34 12 34 12 05 00 00 00 +e8 00 00 00 3f 1c 83 1a 1a 00 00 32 20 00 00 00 +34 12 34 12 20 00 00 00 e0 00 00 00 ea 1a 7a 1b +08 00 00 ff a0 00 00 00 04 00 01 01 0e 00 00 00 +e8 00 00 00 47 1b 03 1b 1a 00 00 32 20 00 00 00 +34 12 34 12 0e 00 00 00 e8 00 00 00 47 1b 43 1b +1a 00 00 32 20 00 00 00 34 12 34 12 10 00 ff 07 +ba 00 04 00 07 1b 17 1b 0a 00 00 32 22 21 00 00 +00 00 00 4a 0e 01 00 00 ad 00 00 00 28 1b 52 1b +01 00 09 32 30 20 00 00 00 82 00 46 00 00 00 00 +2c 01 00 00 47 1b 4b 1b 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 2c 01 00 00 47 1b 4b 1b +06 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +2c 01 00 00 37 1b 4b 1b 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 2c 01 00 00 37 1b 4b 1b +06 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +2c 01 00 00 47 1b 4b 1b 0c 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 2c 01 00 00 37 1b 4b 1b +0c 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +2c 01 00 00 57 1b 4b 1b 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 2c 01 00 00 57 1b 4b 1b +06 00 00 32 20 00 00 00 00 00 00 00 0e 00 00 00 +e8 00 00 00 83 1b 43 1b 1a 00 00 32 20 00 00 00 +34 12 34 12 0e 00 00 00 e8 00 00 00 83 1b 03 1b +1a 00 00 32 20 00 00 00 34 12 34 12 20 00 00 00 +e8 00 00 00 c3 1a 83 1b 1a 00 00 32 20 00 00 00 +34 12 34 12 20 00 e8 00 db 00 04 00 df 1a 83 1b +00 00 00 4b 20 00 00 00 00 00 00 84 20 00 e8 00 +db 00 04 00 ff 1a 83 1b 00 00 00 4b 20 00 00 00 +00 00 00 83 3a 00 00 00 2a 01 00 00 97 1a bb 1b +06 00 00 32 20 01 00 00 1f 00 aa aa 40 00 00 00 +1a 01 00 00 f8 1a 99 1b 00 00 00 0e 30 00 00 00 +55 54 08 1c 20 00 00 00 29 01 00 00 d3 1a 8f 1b +00 00 00 32 20 00 00 00 00 00 00 82 00 00 00 00 +da 00 00 00 9b 1a d3 1b 06 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c6 00 00 00 8f 1a cf 1b +06 00 00 32 22 21 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 9b 1a af 1b 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 9b 1a 9b 1b +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 9b 1a 9b 1b 08 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 9b 1a 9b 1b +10 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 9b 1a f3 1b 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 9b 1a f3 1b +08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 ab 1a f3 1b 00 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b7 00 00 00 b7 1a ef 1b +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b4 00 00 00 b3 1a 97 1b 02 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 c3 1a 9b 1b +00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 c7 1a 9f 1b 08 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b8 00 00 00 c3 1a ab 1b +08 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +b7 00 00 00 c3 1a ab 1b 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b6 00 00 00 ab 1a af 1b +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b8 00 00 00 af 1a b3 1b 0e 00 02 32 22 00 00 00 +00 00 00 00 00 00 00 00 b3 00 00 00 bf 1a 87 1b +0e 00 00 32 20 00 00 00 00 00 00 00 0f 00 00 00 +e8 00 00 00 bf 1a f3 1b 30 00 00 32 20 00 00 00 +34 12 34 12 0f 00 00 00 e8 00 00 00 ff 1a f3 1b +30 00 00 32 20 00 00 00 34 12 34 12 20 00 00 00 +e8 00 00 00 03 1b 83 1b 1a 00 00 32 20 00 00 00 +34 12 34 12 41 00 00 00 1a 01 00 00 1c 1b a6 1b +00 00 00 0e 30 00 00 00 56 54 10 1c 0e 00 ac 00 +ba 00 06 01 0b 1b 87 1b 0a 00 00 32 20 21 00 00 +00 00 00 45 0e 00 00 00 e8 00 00 00 47 1b 83 1b +1a 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +b8 00 00 00 27 1b d7 1b 08 00 03 32 22 00 00 00 +00 00 00 00 00 00 00 00 af 00 00 00 5b 1b f3 1b +00 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +af 00 00 00 4f 1b 87 1b 00 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 b2 00 00 00 4f 1b cf 1b +02 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 5f 1b e7 1b 00 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 63 1b e7 1b +08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b8 00 00 00 1f 1b 8f 1b 0e 00 02 32 22 00 00 00 +00 00 00 00 0e 00 e8 00 ac 00 04 00 3b 1b 83 1b +00 00 00 4b 20 00 00 00 00 00 00 44 00 00 00 00 +bd 00 00 00 1f 1b f7 1b 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 2b 1b f7 1b +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 1f 1b e7 1b 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 2b 1b e7 1b +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 1f 1b df 1b 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 2b 1b df 1b +00 00 00 32 20 00 00 00 00 00 00 00 0e 00 1a 01 +1d 01 02 00 50 1b 8b 1b 0a 00 00 4b 20 00 00 00 +00 00 00 43 00 00 00 00 b6 00 00 00 1b 1b 8b 1b +00 00 01 32 20 00 00 00 00 00 00 00 1c 00 00 00 +1e 01 00 00 3b 1b 97 1b 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 b7 00 00 00 27 1b d3 1b +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +af 00 00 00 4f 1b ab 1b 00 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 b8 00 00 00 4c 1b b8 1b +00 00 02 32 22 00 00 00 00 00 00 00 0e 00 00 00 +e8 00 00 00 83 1b 83 1b 1a 00 00 32 20 00 00 00 +34 12 34 12 21 00 e8 00 ac 00 04 00 43 1a 77 1c +18 00 00 4b 20 00 00 00 00 00 00 87 01 00 00 00 +ff 00 00 00 43 1a 43 1c 18 00 00 00 20 00 00 00 +00 00 00 01 16 81 1a 01 19 01 02 00 7f 1a 4f 1c +19 00 01 32 20 20 00 00 00 00 00 61 c7 80 00 00 +19 01 02 02 47 1a 73 1c 19 00 01 32 20 20 00 00 +00 00 00 a8 0f 80 ac 00 ba 00 06 01 63 1a 07 1c +22 00 00 32 20 21 00 00 00 00 00 49 0f 00 e8 00 +ac 00 04 00 7f 1a 4b 1c 18 00 00 4b 22 00 00 00 +00 00 00 48 11 00 00 00 11 01 00 00 3b 1a 0b 1c +18 00 01 32 20 00 00 00 00 00 00 00 11 00 00 00 +11 01 00 00 33 1a 0b 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 11 01 00 00 2b 1a 0b 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +11 01 00 00 43 1a 0b 1c 18 00 00 32 20 00 00 00 +00 00 00 00 0a 00 00 00 c3 00 00 00 23 1a 0f 1c +18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 13 1a 0f 1c 18 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 11 01 00 00 0b 1a 5f 1c +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +11 01 00 00 0b 1a 57 1c 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 11 01 00 00 0b 1a 67 1c +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +11 01 00 00 0b 1a 4f 1c 18 00 01 32 22 00 00 00 +00 00 00 00 00 00 00 00 11 01 00 00 0b 1a 2f 1c +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +11 01 00 00 0b 1a 27 1c 18 00 00 32 22 00 00 00 +00 00 00 00 41 00 00 00 11 01 00 00 0b 1a 1f 1c +18 00 01 32 22 00 00 00 00 00 00 00 0d 00 00 00 +14 01 00 00 23 1a 7b 1c 24 00 00 32 20 01 00 00 +00 00 00 3d 21 00 00 00 e8 00 00 00 7b 1a 73 1c +30 00 00 32 20 00 00 00 34 12 34 12 3f 80 16 01 +dc 00 02 01 0b 1a 0b 1c 2a 00 00 0a a0 20 00 00 +00 00 00 9d 21 00 00 00 1a 01 00 00 1f 1a 5c 1c +18 00 00 0e 30 00 00 00 53 54 00 1d 21 00 00 00 +1a 01 00 00 41 1a 21 1c 18 00 00 04 30 00 00 00 +01 05 00 08 21 00 00 00 e8 00 00 00 3b 1a 73 1c +30 00 00 32 20 00 00 00 34 12 34 12 21 00 00 00 +e8 00 00 00 3b 1a 37 1c 30 00 00 32 20 00 00 00 +34 12 34 12 21 00 00 00 e8 00 00 00 7b 1a 33 1c +30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +11 01 00 00 4b 1a 0b 1c 18 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 11 01 00 00 53 1a 0b 1c +18 00 00 32 20 00 00 00 00 00 00 00 21 00 00 00 +e8 00 00 00 7f 1a 73 1c 30 00 00 32 20 00 00 00 +34 12 34 12 21 00 00 00 e8 00 00 00 7f 1a 33 1c +30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 +e8 00 00 00 fb 1a 6f 1c 30 00 00 32 20 00 00 00 +34 12 34 12 0f 00 00 00 e8 00 00 00 fb 1a 33 1c +30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 +e8 00 00 00 bf 1a 7f 1c 30 00 00 32 20 00 00 00 +34 12 34 12 20 80 00 00 27 01 01 00 cf 1a 3a 1c +00 00 00 32 00 20 00 00 00 00 00 81 ff 00 00 00 +1a 01 00 00 cf 1a 43 1c 00 00 00 0e 30 00 00 00 +31 34 40 1d 00 00 00 00 c0 00 00 00 a3 1a 2f 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 c3 1a 53 1c 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 c7 1a 2f 1c +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 c3 1a 2f 1c 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 93 1a 17 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 a3 1a 17 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 b3 1a 17 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 c3 1a 17 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 d3 1a 17 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d1 00 00 00 e3 1a 17 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 ed 00 00 00 9f 1a 4b 1c +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 8f 1a 53 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 9f 1a 2f 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 8f 1a 2f 1c 18 00 00 32 20 00 00 00 +00 00 00 00 13 80 00 00 ca 00 00 00 9f 1a 4f 1c +16 00 00 32 20 00 00 00 00 01 00 57 00 00 00 00 +bd 00 00 00 9f 1a 53 1c 18 00 00 32 20 00 00 00 +00 00 00 00 0c 00 00 00 be 00 00 00 a3 1a 3f 1c +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 a3 1a 37 1c 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 a3 1a 47 1c +18 00 00 32 22 00 00 00 00 00 00 00 3f 00 00 00 +16 01 00 00 83 1a 63 1c 0c 00 00 32 22 01 00 00 +00 00 00 9c 13 00 00 00 15 01 00 00 bf 1a 2b 1c +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 a3 1a 4f 1c 18 00 00 32 22 00 00 00 +00 00 00 00 40 01 00 00 ad 00 00 00 b7 1a 43 1c +02 00 07 32 32 20 00 00 00 13 00 9f 00 00 00 00 +c0 00 00 00 c7 1a 53 1c 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 a3 1a 53 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +15 01 00 00 db 1a 2b 1c 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 eb 1a 6b 1c +00 00 00 28 a0 00 00 00 00 00 00 00 13 00 ca 00 +ba 00 02 00 83 1a 5b 1c 08 00 00 32 22 21 00 00 +00 00 00 55 0f 00 00 00 e8 00 00 00 bf 1a 33 1c +30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 +e8 00 00 00 bf 1a 73 1c 30 00 00 32 20 00 00 00 +34 12 34 12 40 00 00 00 1a 01 00 00 40 1b 4a 1c +00 00 00 04 30 00 00 00 37 34 00 09 00 00 00 00 +b0 00 00 00 2b 1b 07 1c 00 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 5f 1b 37 1c +00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +af 00 00 00 5b 1b 17 1c 00 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 b5 00 00 00 57 1b 27 1c +02 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 1b 1b 07 1c 08 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 1b 1b 07 1c +00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b8 00 00 00 17 1b 13 1c 08 00 02 32 22 00 00 00 +00 00 00 00 00 00 00 00 b7 00 00 00 17 1b 13 1c +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 2b 1b 07 1c 08 00 02 32 22 00 00 00 +00 00 00 00 3f 00 00 00 b0 00 00 00 2b 1b 17 1c +00 00 02 32 22 00 00 00 00 00 00 00 1c 10 1e 01 +ae 00 02 01 27 1b 13 1c 08 00 00 32 20 21 00 00 +00 00 00 76 20 00 00 00 ad 00 00 00 1f 1b 28 1c +01 00 09 32 30 20 00 00 00 72 00 80 0f 00 00 00 +e8 00 00 00 3b 1b 6f 1c 30 00 00 32 20 00 00 00 +34 12 34 12 0f 00 00 00 e8 00 00 00 3b 1b 2f 1c +30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 +e8 00 00 00 7b 1b 6f 1c 30 00 00 32 20 00 00 00 +34 12 34 12 0f 00 00 00 e8 00 00 00 7b 1b 2f 1c +30 00 00 32 20 00 00 00 34 12 34 12 1b 00 00 00 +24 01 00 00 0f 19 c3 1c 18 00 00 14 22 01 00 00 +00 00 00 9d 1a 00 00 00 24 01 00 00 0f 19 d3 1c +18 00 00 14 22 01 00 00 00 00 00 1e 11 00 00 00 +e8 00 00 00 3f 19 bf 1c 30 00 00 32 20 00 00 00 +34 12 34 12 11 00 00 00 e8 00 00 00 3f 19 ff 1c +30 00 00 32 20 00 00 00 34 12 34 12 ac 00 00 00 +1a 01 00 00 23 19 b7 1c 18 00 00 14 30 00 00 00 +25 24 10 4c 9b 80 ff 07 f1 00 00 00 3f 19 83 1c +18 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 +ee 00 00 00 2b 19 9b 1c 18 00 01 32 20 00 00 00 +00 00 00 00 9b 80 ff 07 ee 00 00 00 47 19 9b 1c +18 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 +ef 00 37 37 3f 19 9f 1c 18 00 00 32 20 00 00 00 +00 00 00 00 ac 00 00 00 1a 01 00 00 46 19 ca 1c +18 00 00 14 30 00 00 00 27 24 00 4c 00 00 00 00 +bf 00 00 00 57 19 93 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 23 19 93 1c +20 54 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 13 19 93 1c 20 55 00 32 20 00 00 00 +00 00 00 00 9b 80 ff 07 f0 00 00 00 4b 19 9b 1c +2e 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 13 19 93 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 23 19 93 1c +18 00 00 32 20 00 00 00 00 00 00 00 11 00 00 00 +e8 00 00 00 7f 19 bf 1c 30 00 00 32 20 00 00 00 +34 12 34 12 11 00 00 00 e8 00 00 00 7f 19 ff 1c +30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +d6 00 00 00 7b 1a c7 1c 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 d6 00 00 00 7b 1a 9f 1c +18 00 00 32 22 00 00 00 00 00 00 00 21 00 1a 01 +1d 01 02 00 16 1a a2 1c 18 00 00 4b 20 00 00 00 +00 00 00 86 41 00 00 00 bd 00 00 00 13 1a e3 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 17 1a e3 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 7b 1a e3 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 5b 1a e3 1c 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 3b 1a e3 1c +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c4 00 00 00 0f 1a c3 1c 28 00 01 32 22 00 00 00 +00 00 00 00 c7 00 00 00 1a 01 00 00 32 1a 95 1c +18 00 00 0e 30 00 00 00 05 01 00 1c 0d 00 00 00 +16 01 00 00 07 1a a8 1c 22 00 00 32 22 01 00 00 +00 00 00 3c c7 81 21 00 19 01 03 01 39 1a e3 1c +19 00 02 32 20 20 00 00 00 00 00 a7 0f 00 00 00 +e8 00 00 00 ff 1a af 1c 30 00 00 32 20 00 00 00 +34 12 34 12 0f 00 00 00 e8 00 00 00 bf 1a bf 1c +30 00 00 32 20 00 00 00 34 12 34 12 0f 00 00 00 +e8 00 00 00 3f 1b af 1c 30 00 00 32 20 00 00 00 +34 12 34 12 0f 00 00 00 e8 00 00 00 7f 1b af 1c +30 00 00 32 20 00 00 00 34 12 34 12 0b 81 21 00 +19 01 03 02 e3 1d ff 1c 03 00 02 32 20 20 00 00 +00 00 00 2c 27 80 00 00 ad 00 00 00 d8 1d f2 1c +03 00 06 32 32 20 00 00 01 22 00 8b 00 00 00 00 +b3 00 00 00 c5 1d e3 1c 12 00 00 32 20 00 00 00 +00 00 00 00 1e 00 00 00 d8 00 00 00 97 1d ef 1c +04 00 00 32 20 00 00 00 00 00 00 00 1a 00 00 00 +ad 00 00 00 3d 19 6d 1d 19 00 03 32 30 20 00 00 +00 80 00 6d 11 00 00 00 e8 00 00 00 3f 19 3f 1d +30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 +e8 00 00 00 3f 19 7f 1d 30 00 00 32 20 00 00 00 +34 12 34 12 00 00 00 00 d6 00 00 00 7b 19 67 1d +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +d6 00 00 00 1b 19 5f 1d 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 d6 00 00 00 7b 19 2b 1d +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +d6 00 00 00 1b 19 27 1d 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 0d 01 00 00 47 19 57 1d +18 00 01 32 20 00 00 00 77 66 55 00 00 00 00 00 +c1 00 00 00 37 19 37 1d 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c1 00 00 00 47 19 37 1d +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c1 00 00 00 57 19 37 1d 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c1 00 00 00 57 19 47 1d +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c1 00 00 00 57 19 57 1d 18 00 00 32 20 00 00 00 +00 00 00 00 11 00 00 00 e8 00 00 00 7f 19 3f 1d +30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 +e8 00 00 00 7f 19 7f 1d 30 00 00 32 20 00 00 00 +34 12 34 12 02 00 00 00 16 01 00 00 07 19 79 1d +22 00 00 32 22 01 00 00 00 00 00 0b 00 00 00 00 +d2 00 00 00 5f 19 5f 1d 00 00 00 32 20 00 00 00 +00 00 00 00 0d 80 14 01 c6 00 00 0a 58 1a 02 1d +20 00 01 32 22 21 00 00 00 10 14 3b 00 00 00 00 +c5 00 00 00 61 1a 07 1d 1e 00 01 32 22 00 00 00 +00 00 00 00 14 00 00 00 d8 00 00 00 17 1a 03 1d +1a 00 00 32 20 00 00 00 00 00 00 00 0d 00 00 00 +1a 01 00 00 1c 1a 07 1d 1a 00 00 0e 30 00 00 00 +33 34 20 1c 00 00 00 00 1b 01 00 00 03 1a 63 1d +18 00 01 32 20 00 00 00 00 00 00 00 15 80 d8 00 +e4 00 00 00 1f 1a 0b 1d 1a 00 00 32 22 00 00 00 +00 00 00 60 00 00 00 00 bd 00 00 00 13 1a 1b 1d +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 17 1a 1b 1d 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 7b 1a 1b 1d +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 5b 1a 1b 1d 18 00 00 32 20 00 00 00 +00 00 00 00 10 00 00 00 c0 00 00 00 3b 1a 1b 1d +18 00 00 32 20 00 00 00 00 00 00 00 c7 00 00 00 +e8 00 00 00 7f 1a 7f 1d 30 00 00 32 20 00 00 00 +34 12 34 12 c7 00 00 00 e8 00 00 00 3f 1a 7f 1d +30 00 00 32 20 00 00 00 34 12 34 12 0a 00 00 00 +c4 00 00 00 0f 1a 43 1d 28 00 01 32 22 00 00 00 +00 00 00 00 08 00 00 00 16 01 00 00 07 1a 5b 1d +23 00 00 32 22 01 00 00 00 00 00 1b c7 00 00 00 +e8 00 00 00 7f 1a 3f 1d 30 00 00 32 20 00 00 00 +34 12 34 12 c7 00 00 00 e8 00 00 00 3f 1a 3f 1d +30 00 00 32 20 00 00 00 34 12 34 12 c7 01 00 00 +ad 00 00 00 38 1a 47 1d 19 00 0d 32 32 20 00 00 +00 46 00 a6 27 80 00 00 ad 00 00 00 c3 1d 2f 1d +01 00 06 32 32 20 00 00 01 22 00 8a 00 00 00 00 +2b 01 00 00 bd 1d 7e 1d 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 b7 1d 6e 1d +00 00 00 28 a0 00 00 00 00 00 00 00 14 00 00 00 +c6 00 00 00 af 1d 0f 1d 06 00 00 32 20 21 00 00 +00 00 1a 5e 00 00 00 00 da 00 00 00 b3 1d 1b 1d +06 00 00 32 20 00 00 00 00 00 00 00 07 01 00 00 +ad 00 00 00 db 1d 1b 1d 01 00 01 32 30 20 00 00 +00 40 00 18 00 00 00 00 af 00 00 00 9f 1d 7b 1d +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +af 00 00 00 9f 1d 7b 1d 08 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 b4 00 00 00 9b 1d 77 1d +0a 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +af 00 00 00 9f 1d 5f 1d 08 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 af 00 00 00 9f 1d 5f 1d +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 d7 1d 5b 1d 00 00 02 32 22 00 00 00 +00 00 00 00 00 00 00 00 b4 00 00 00 c7 1d 57 1d +02 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b4 00 00 00 c7 1d 57 1d 0a 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 9f 1d 5b 1d +08 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 af 1d 5b 1d 08 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 af 1d 5b 1d +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 9f 1d 5b 1d 00 00 00 32 22 00 00 00 +00 00 00 00 05 00 00 00 c0 00 00 00 f3 1d 03 1d +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 c7 1d 03 1d 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 fb 1d 03 1d +00 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b5 00 00 00 e7 1d 57 1d 0a 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b8 00 00 00 f7 1d 5b 1d +0a 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b7 00 00 00 f3 1d 57 1d 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 d7 1d 5b 1d +08 00 00 32 22 00 00 00 00 00 00 00 ee 00 00 00 +ff 00 00 00 d8 1d 38 1d 00 00 00 00 20 00 00 00 +00 00 00 ac 18 00 13 01 ae 00 02 01 ff 1d 57 1d +08 00 00 32 20 21 00 00 00 00 00 68 0b 01 00 00 +ad 00 00 00 f7 1d 23 1d 01 00 01 32 32 20 00 00 +00 04 00 2b 00 00 00 00 bf 00 00 00 eb 1d 5b 1d +00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +0f 01 00 00 8f 1d 3f 1d 00 00 00 32 20 20 00 00 +00 00 00 00 fd 80 0c 01 0f 01 01 fe 8f 1d 2b 1d +00 00 00 32 20 20 00 00 00 00 00 b0 00 00 00 00 +0f 01 00 00 8f 1d 17 1d 00 00 00 32 20 20 00 00 +00 00 00 00 27 00 00 00 1a 01 00 00 d2 1d 75 1d +00 00 00 0e 30 00 00 00 35 34 08 1c 04 00 00 00 +24 01 00 00 a3 1d 33 1d 00 00 00 14 22 01 00 00 +00 00 00 a3 00 00 00 00 bc 00 00 00 c3 1d 03 1d +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 a3 1d 03 1d 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 6b 1e 7b 1d +00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 6b 1e 6b 1d 00 00 02 32 22 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 6b 1e 5b 1d +00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +00 01 00 00 6b 1e 17 1d 00 00 00 32 20 00 00 00 +00 00 00 00 07 00 00 00 1a 01 00 00 1d 1e 70 1d +00 00 00 0e 30 00 00 00 07 00 10 1d 00 00 00 00 +b0 00 00 00 73 1e 63 1d 0c 00 02 32 22 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 73 1e 73 1d +0c 00 02 32 22 00 00 00 00 00 00 00 12 01 00 00 +ad 00 00 00 1f 1e 43 1d 03 00 02 32 30 20 00 00 +00 60 00 54 12 00 00 00 b0 00 00 00 03 1e 5b 1d +00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 52 1e 76 1d 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 57 1e 53 1d +00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 47 1e 54 1d 00 00 00 28 a0 00 00 00 +00 00 00 00 27 00 00 00 1a 01 00 00 03 1e 30 1d +00 00 00 04 30 00 00 00 04 05 00 09 02 00 00 00 +24 01 00 00 03 1e 13 1d 00 00 00 14 20 01 00 00 +00 00 00 5e 14 00 00 00 16 01 00 00 3b 1e 07 1d +0c 00 00 32 20 01 00 00 00 00 00 5d 9b 80 ff 07 +ee 00 00 00 0b 1e 1b 1d 00 00 01 32 20 00 00 00 +00 00 00 00 9b 80 ff 07 ef 00 37 37 1f 1e 1f 1d +00 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 +f1 00 00 00 1f 1e 03 1d 00 00 00 32 20 00 00 00 +00 00 00 00 9b 80 ff 07 f0 00 00 00 2b 1e 1b 1d +16 00 00 32 20 00 00 00 00 00 00 00 9b 80 ff 07 +ee 00 00 00 27 1e 1b 1d 00 00 00 32 20 00 00 00 +00 00 00 00 1a 00 00 00 c7 00 00 00 ff 18 9f 1d +24 00 00 32 a2 00 00 00 04 00 01 02 1a 00 00 00 +e8 00 00 00 ff 18 b3 1d 30 00 00 32 20 00 00 00 +34 12 34 12 1a 00 e8 00 db 00 04 00 03 19 a3 1d +18 00 00 4b 22 00 00 00 00 00 00 6c 1a 00 00 00 +29 01 00 00 47 19 b3 1d 18 00 00 32 20 00 00 00 +00 00 00 6b 11 00 00 00 e8 00 00 00 3f 19 bf 1d +30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 +e8 00 00 00 3f 19 ff 1d 30 00 00 32 20 00 00 00 +34 12 34 12 11 00 00 00 1a 01 00 00 39 19 bc 1d +18 00 00 0e 30 00 00 00 13 14 00 1c 00 00 00 00 +d6 00 00 00 1b 19 f3 1d 18 00 00 32 22 00 00 00 +00 00 00 00 11 00 00 00 1b 01 00 00 13 19 ab 1d +18 00 00 32 20 00 00 00 00 00 00 51 11 00 00 00 +e8 00 00 00 7f 19 ff 1d 30 00 00 32 20 00 00 00 +34 12 34 12 11 00 00 00 e8 00 00 00 7f 19 bf 1d +30 00 00 32 20 00 00 00 34 12 34 12 00 00 00 00 +b3 00 00 00 07 19 81 1d 2b 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 77 19 87 1d +18 00 00 28 a0 00 00 00 00 00 00 00 11 80 21 00 +19 01 03 08 c3 19 cd 1d 19 00 02 32 20 20 00 00 +00 00 00 50 00 00 00 00 b3 00 00 00 97 19 87 1d +28 00 00 32 20 00 00 00 00 00 00 00 ac 01 00 00 +ad 00 00 00 9f 19 bf 1d 1b 00 09 32 32 20 00 00 +00 18 00 a3 11 00 00 00 e8 00 00 00 ff 19 ff 1d +30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 +e8 00 00 00 ff 19 bf 1d 30 00 00 32 20 00 00 00 +34 12 34 12 11 00 00 00 e8 00 00 00 bf 19 ff 1d +30 00 00 32 20 00 00 00 34 12 34 12 11 00 00 00 +e8 00 00 00 bf 19 bf 1d 30 00 00 32 20 00 00 00 +34 12 34 12 00 00 00 00 d4 00 00 00 9b 19 93 1d +18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 87 19 8f 1d 18 00 00 28 a0 00 00 00 +00 00 00 00 08 80 16 01 dd 00 02 01 69 1a 8b 1d +28 00 00 0a a0 20 00 00 02 00 05 1a 0a 00 1a 01 +1d 01 02 00 26 1a b4 1d 18 00 00 4b 20 00 00 00 +00 00 00 27 11 00 e8 00 db 00 04 00 03 1a cf 1d +18 00 00 4b 22 00 00 00 00 00 00 4f 0a 00 00 00 +1a 01 00 00 1b 1a 9b 1d 19 00 00 0e 30 00 00 00 +13 11 00 1c c7 00 db 00 c2 00 06 01 2c 1a 87 1d +23 00 00 32 20 21 00 00 00 00 00 a5 0a 81 21 00 +19 01 03 01 4b 1a a7 1d 19 00 02 32 20 20 00 00 +00 00 00 26 ac 01 00 00 ad 00 00 00 2f 1a fb 1d +1b 00 03 32 30 20 00 00 00 80 00 a2 11 00 00 00 +1b 01 00 00 13 1a b2 1d 18 00 00 32 20 00 00 00 +00 00 00 4e 0a 00 00 00 e8 00 00 00 7f 1a ff 1d +30 00 00 32 20 00 00 00 34 12 34 12 0a 00 00 00 +e8 00 00 00 3f 1a ff 1d 30 00 00 32 20 00 00 00 +34 12 34 12 0a 00 00 00 e8 00 00 00 7f 1a bf 1d +30 00 00 32 20 00 00 00 34 12 34 12 0a 00 00 00 +e8 00 00 00 3f 1a bf 1d 30 00 00 32 20 00 00 00 +34 12 34 12 c7 00 e8 00 db 00 04 00 4f 1a 83 1d +18 00 00 4b 20 00 00 00 00 00 00 a4 11 01 00 00 +ad 00 00 00 33 1a d3 1d 1b 00 03 32 30 20 00 00 +00 80 00 4d 04 00 00 00 c7 00 00 00 73 1c fb 1d +0a 00 00 32 a0 00 00 00 03 00 00 02 04 00 00 00 +c7 00 00 00 f3 1c fb 1d 0a 00 00 32 a0 00 00 00 +03 00 00 02 00 00 00 00 bf 00 00 00 fb 1d fb 1d +08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 eb 1d fb 1d 08 56 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 fb 1d fb 1d +00 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 eb 1d fb 1d 00 56 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 9f 1d e3 1d +08 00 02 32 20 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 9f 1d e3 1d 00 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 af 00 00 00 9f 1d d3 1d +08 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +af 00 00 00 9f 1d d3 1d 00 00 00 32 20 00 00 00 +00 00 00 00 14 00 00 00 b1 00 00 00 9b 1d cf 1d +0a 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +af 00 00 00 9f 1d 9f 1d 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 af 00 00 00 9f 1d 9f 1d +08 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +d7 00 00 00 7b 1e ab 1d 00 00 00 32 20 00 00 00 +00 00 00 00 18 00 00 00 13 01 00 00 37 1e af 1d +00 00 03 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 03 1e a3 1d 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 0b 1e fb 1d +08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 0b 1e fb 1d 00 56 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 03 1e 93 1d +10 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b1 00 00 00 33 1e 8f 1d 0a 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 03 1e 93 1d +08 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 73 1e 83 1d 0c 00 02 32 22 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 03 1e 93 1d +00 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +b0 00 00 00 6b 1e eb 1d 08 00 02 32 22 00 00 00 +00 00 00 00 00 00 00 00 b0 00 00 00 6b 1e d3 1d +08 00 02 32 22 00 00 00 00 00 00 00 00 00 00 00 +b1 00 00 00 33 1e 8f 1d 02 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 b5 00 00 00 33 1e 8f 1d +12 00 00 32 20 00 00 00 00 00 00 00 1a 00 00 00 +1a 01 00 00 24 1e fb 1d 00 00 00 0e 30 00 00 00 +11 11 08 1c 00 00 00 00 b0 00 00 00 03 1e b3 1d +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +d5 00 00 00 4f 1e cf 1d 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 d4 00 00 00 4b 1e bb 1d +00 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +d7 00 00 00 57 1e ab 1d 00 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 3f 19 7f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 3f 19 3f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 7f 19 7f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 7f 19 3f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 ff 19 7f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 ff 19 3f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 bf 19 7f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 bf 19 3f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 e3 00 00 00 cb 19 27 1e +00 00 00 32 20 00 00 00 00 00 00 00 0c 00 00 00 +1a 01 00 00 4f 1a 4b 1e 18 00 00 0e 30 00 00 00 +13 14 08 1d 0a 00 1a 01 ec 00 02 00 21 1a 07 1e +24 00 00 32 20 21 00 00 00 00 00 25 0c 00 00 00 +1a 01 00 00 37 1a 4b 1e 18 00 00 0e 30 00 00 00 +17 14 10 1d 0a 00 e8 00 ac 00 04 00 3b 1a 03 1e +18 00 00 4b 20 00 00 00 00 00 00 24 00 00 00 00 +d2 00 00 00 7f 1a 7f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 3f 1a 7f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 3f 1a 3f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 7f 1a 3f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 63 1a 67 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 5f 1a 43 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 23 1a 67 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 1b 1a 43 1e +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 3f 1a 43 1e 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 3f 1a 47 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 1b 1a 47 1e 18 00 00 32 20 00 00 00 +00 00 00 00 3c 00 00 00 1a 01 00 00 c0 1a 2c 1e +18 00 00 04 30 00 00 00 03 05 00 09 0c 80 21 00 +19 01 03 01 a5 1a 52 1e 19 00 02 32 20 20 00 00 +00 00 00 39 3c 00 00 00 1a 01 00 00 b8 1a 6c 1e +18 00 00 0e 30 00 00 00 02 04 00 1d 0c 01 00 00 +1b 01 00 00 93 1a 37 1e 18 00 01 32 20 00 00 00 +00 00 00 38 0c 00 00 00 ff 00 00 00 9f 1a 37 1e +18 00 00 00 20 00 00 00 00 00 00 37 00 00 00 00 +c0 00 00 00 e7 1a 33 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c4 00 00 00 ab 1a 0b 1e +28 00 00 32 20 00 00 00 00 00 00 00 0a 00 00 00 +c4 00 00 00 83 1a 0b 1e 28 00 02 32 20 00 00 00 +00 00 00 00 00 00 00 00 c4 00 00 00 df 1a 0b 1e +28 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 cc 1a 61 1e 24 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 2b 01 00 00 fb 1a 43 1e +18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 ff 1a 7f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 bf 1a 7f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 bf 1a 3f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 ff 1a 3f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 cc 1a 54 1e 18 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 c9 1a 60 1e +18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 df 1a 13 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 e3 1a 13 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 9f 1a 13 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 a3 1a 37 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 9f 1a 43 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 a3 1a 67 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 a3 1a 43 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 a7 1a 67 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 77 1b 57 1e 18 00 01 32 20 00 00 00 +00 00 00 00 00 00 00 00 be 00 00 00 7f 1b 57 1e +18 00 02 32 20 00 00 00 00 00 00 00 3c 00 00 00 +1a 01 00 00 20 1b 4e 1e 18 00 00 0e 30 00 00 00 +33 34 10 1d 00 00 00 00 be 00 00 00 67 1b 5f 1e +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 67 1b 67 1e 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 bd 00 00 00 67 1b 77 1e +18 00 00 32 22 00 00 00 00 00 00 00 0c 01 00 00 +ad 00 00 00 54 1b 55 1e 19 00 03 32 32 20 00 00 +00 08 00 36 00 00 00 00 c0 00 00 00 6b 1b 57 1e +18 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +be 00 00 00 73 1b 57 1e 18 00 02 32 20 00 00 00 +00 00 00 00 ef 80 00 00 27 01 00 00 69 1b 45 1e +18 00 00 32 20 20 00 00 00 00 00 af 00 00 00 00 +c0 00 00 00 67 1b 57 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 67 1b 7b 1e +18 00 00 32 20 00 00 00 00 00 00 00 ff 00 00 00 +1a 01 00 00 6b 1b 47 1e 18 00 00 0e 30 00 00 00 +33 34 40 1c 00 00 00 00 c4 00 00 00 03 1b 0b 1e +28 00 02 32 20 00 00 00 00 00 00 00 05 80 16 01 +dd 00 02 01 4b 1b 0b 1e 28 00 00 0a a0 20 00 00 +02 00 05 10 3c 00 00 00 ff 00 00 00 7e 1b 33 1e +24 00 00 00 20 00 00 00 00 00 00 9b 00 00 00 00 +d2 00 00 00 3f 1b 7f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 3f 1b 3f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d2 00 00 00 7f 1b 7f 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d2 00 00 00 7f 1b 3f 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d3 00 00 00 1b 1b 73 1e 18 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 7f 1b 37 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bb 00 00 00 3f 1b 37 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 03 1b 3b 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 9b 1b 6b 1e 18 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 a3 1b 77 1e +18 00 00 28 a0 00 00 00 00 00 00 00 00 00 00 00 +c3 00 00 00 93 1b 77 1e 18 00 00 28 a0 00 00 00 +00 00 00 00 1f 01 00 00 ad 00 00 00 f7 1b 24 1e +01 00 02 32 32 20 00 00 00 06 00 7e 09 01 00 00 +ad 00 00 00 fe 1b 22 1e 01 00 02 32 32 20 00 00 +00 06 00 20 3c 00 00 00 1b 01 00 00 87 1b 43 1e +18 00 01 32 20 00 00 00 00 00 00 9a 03 00 00 00 +24 01 00 00 93 1b 3b 1e 00 00 00 14 22 01 00 00 +00 00 00 5b 00 00 00 00 e6 00 00 00 9b 1b 57 1e +06 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 9f 1b 57 1e 00 00 00 28 22 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 93 1b 57 1e +00 00 00 28 22 00 00 00 00 00 00 00 05 00 00 00 +16 01 00 00 9a 1b 08 1e 22 00 00 32 20 01 00 00 +00 00 00 0f 00 00 00 00 bc 00 00 00 a3 1b 7b 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 83 1b 57 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 83 1b 77 1e +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 a7 1b 7b 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 83 1b 7b 1e +18 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +0d 01 00 00 a3 1b 77 1e 18 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 c0 00 00 00 cb 1b 27 1e +18 00 00 32 20 00 00 00 00 00 00 00 09 80 00 00 +ca 00 00 00 c7 1b 23 1e 16 00 00 32 20 00 00 00 +00 01 00 1e 00 00 00 00 ed 00 00 00 c7 1b 23 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 a3 1b 27 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d1 00 00 00 93 1b 13 1e +18 00 00 32 20 00 00 00 00 00 00 00 09 00 ca 00 +ec 00 02 00 e3 1b 07 1e 0e 00 00 32 20 21 00 00 +00 00 00 1d 15 00 00 00 b3 00 00 00 fb 1b 07 1e +2a 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +0d 01 00 00 a3 1b 53 1e 18 00 00 32 20 00 00 00 +77 66 55 00 00 00 00 00 0d 01 00 00 a3 1b 33 1e +18 00 00 32 20 00 00 00 77 66 55 00 1f 00 00 00 +1a 01 00 00 e6 1b 48 1e 00 00 00 14 30 00 00 00 +17 14 00 4c 3c 01 00 00 ad 00 00 00 a7 1b 17 1e +19 00 06 32 32 20 00 00 00 22 00 99 11 00 00 00 +d1 00 00 00 a3 1b 13 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bb 00 00 00 a7 1b 67 1e +18 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 a7 1b 77 1e 18 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c0 00 00 00 c7 1b 27 1e +18 00 01 32 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 9f 1b 6b 1e 00 00 00 28 22 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 9f 1b 6b 1e +06 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 ab 1b 6b 1e 00 00 00 28 22 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 ab 1b 6b 1e +06 00 00 28 22 00 00 00 00 00 00 00 00 00 00 00 +bc 00 00 00 c3 1b 27 1e 18 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 0d 01 00 00 83 1b 57 1e +18 00 00 32 20 00 00 00 77 66 55 00 00 00 00 00 +c0 00 00 00 83 1b 37 1e 18 00 00 32 20 00 00 00 +00 00 00 00 02 80 00 00 db 00 00 2c 7f 1c 03 1e +00 00 00 4b 20 00 00 00 00 00 00 0a 1f 80 00 00 +ac 00 00 00 43 1c 33 1e 00 00 00 4b 22 00 00 00 +00 00 00 7d 1f 80 ac 00 ba 00 06 01 47 1c 47 1e +0a 00 00 32 22 21 00 00 00 00 00 7c 00 00 00 00 +c4 00 00 00 27 1c 0b 1e 28 00 02 32 20 00 00 00 +00 00 00 00 1f 80 ff 07 19 01 06 03 2b 1c 52 1e +01 00 02 32 20 20 00 00 00 00 00 7b 00 00 00 00 +e6 00 00 00 27 1c 0f 1e 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 27 1c 0f 1e +06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +bd 00 00 00 9f 1c 7b 1e 00 00 00 32 22 00 00 00 +00 00 00 00 02 80 00 00 db 00 00 2c ff 1c 03 1e +00 00 00 4b 20 00 00 00 00 00 00 09 00 00 00 00 +12 01 00 00 9f 1c 23 1e 06 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 12 01 00 00 a7 1c 13 1e +06 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +12 01 00 00 97 1c 13 1e 06 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 12 01 00 00 9f 1c 23 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +12 01 00 00 a7 1c 13 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 12 01 00 00 97 1c 13 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +c0 00 00 00 9f 1c 4b 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bc 00 00 00 9f 1c 6b 1e +00 00 00 32 22 00 00 00 00 00 00 00 1f 01 00 00 +ad 00 00 00 df 1c 33 1e 01 00 02 32 32 20 00 00 +00 06 00 7a 00 00 00 00 c4 00 00 00 a3 1c 0b 1e +28 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 83 1c 6b 1e 08 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 83 1c 67 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 93 1c 6b 1e 00 54 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 93 1c 6b 1e +08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 9b 1c 5b 1e 00 00 00 32 20 00 00 00 +00 00 00 00 17 00 00 00 1a 01 00 00 f9 1c 2b 1e +00 00 00 04 30 00 00 00 04 05 00 08 02 81 db 00 +dd 00 06 01 b8 1c 0b 1e 10 00 00 0a a0 20 00 00 +02 00 01 08 00 00 00 00 bf 00 00 00 fb 1c 67 1e +00 00 00 32 20 00 00 00 00 00 00 00 17 00 00 00 +1a 01 00 00 54 1d 19 1e 00 00 00 0e 30 00 00 00 +55 54 10 1c 04 00 00 00 24 01 00 00 6c 1d 12 1e +00 00 00 14 20 01 00 00 00 00 63 1f 00 00 00 00 +c4 00 00 00 03 1d 0b 1e 28 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 3f 1d 13 1e +00 00 00 32 20 00 00 00 00 00 00 00 c8 80 16 01 +dd 00 02 01 67 1d 0b 1e 14 00 00 0a a0 20 00 00 +02 00 05 ab 00 00 00 00 e6 00 00 00 17 1d 0f 1e +00 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 17 1d 1b 1e 00 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 17 1d 0f 1e +06 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +e6 00 00 00 17 1d 1b 1e 06 00 00 28 20 00 00 00 +00 00 00 00 00 00 00 00 e6 00 00 00 17 1d 0f 1e +0c 00 00 28 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 2f 1d 13 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 1b 1d 63 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 0b 1d 63 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 f3 1d 0b 1e +08 56 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +bf 00 00 00 fb 1d 0b 1e 00 56 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 eb 1d 0b 1e +00 56 00 32 20 00 00 00 00 00 00 00 c8 00 00 00 +16 01 00 00 87 1d 1f 1e 0a 00 00 32 22 01 00 00 +00 00 00 aa 00 00 00 00 d6 00 00 00 9f 1d 0b 1e +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +b3 00 00 00 87 1d 23 1e 12 00 00 32 22 00 00 00 +00 00 00 00 17 80 21 00 19 01 03 02 bf 1d 47 1e +01 00 02 32 20 20 00 00 00 00 00 63 0b 00 00 00 +1a 01 00 00 fc 1d 1f 1e 00 00 00 0e 30 00 00 00 +55 54 00 1d 00 00 00 00 d6 00 00 00 d7 1d 73 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +d6 00 00 00 ab 1d 77 1e 00 00 00 32 20 00 00 00 +00 00 00 00 17 01 00 00 ad 00 00 00 f8 1d 23 1e +01 00 12 32 30 20 00 00 00 ec 00 62 00 00 00 00 +bf 00 00 00 0b 1e 0b 1e 00 56 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 d6 00 00 00 73 1e 17 1e +00 00 00 32 22 00 00 00 00 00 00 00 00 00 00 00 +d6 00 00 00 73 1e 3f 1e 00 00 00 32 22 00 00 00 +00 00 00 00 00 00 00 00 c3 00 00 00 05 1e 5d 1e +00 00 00 28 a0 00 00 00 00 00 00 00 ff 00 00 00 +1a 01 00 00 40 1e 40 1e 00 00 00 0e 30 00 00 00 +37 34 48 1c ef 80 00 00 27 01 00 00 3d 1e 3c 1e +00 00 00 32 20 20 00 00 00 00 00 ae 00 00 00 00 +c3 00 00 00 49 1e 2a 1e 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 d4 00 00 00 63 1e 53 1e +00 00 00 28 a2 00 00 00 00 00 00 00 00 00 00 00 +d5 00 00 00 53 1e 63 1e 00 00 00 28 a0 00 00 00 +00 00 00 00 00 00 00 00 bf 00 00 00 03 1e 0b 1e +08 56 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 3f 19 ff 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 7f 19 ff 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 7f 19 bf 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 3f 19 bf 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 bf 19 ff 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 ff 19 ff 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 ff 19 bf 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 bf 19 bf 1e +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +e3 00 00 00 67 1a af 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 3f 1a ff 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 7f 1a ff 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 7f 1a bf 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 3f 1a bf 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 bf 1a ff 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 ff 1a ff 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 ff 1a bf 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 bf 1a bf 1e 00 00 00 32 20 00 00 00 +00 00 00 00 00 00 00 00 e3 00 00 00 2f 1b a7 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 3f 1b ff 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 7f 1b ff 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 7f 1b bf 1e 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 3f 1b bf 1e +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 bf 19 7f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 ff 19 7f 1f +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 ff 19 3f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 bf 19 3f 1f +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 3f 1a 7f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 7f 1a 7f 1f +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 7f 1a 3f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 3f 1a 3f 1f +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 bf 1a 7f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 ff 1a 7f 1f +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 ff 1a 3f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 bf 1a 3f 1f +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 3f 1b 7f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 7f 1b 7f 1f +00 00 00 32 20 00 00 00 00 00 00 00 26 00 00 00 +d2 00 00 00 7f 1b 3f 1f 00 00 00 32 20 00 00 00 +00 00 00 00 26 00 00 00 d2 00 00 00 3f 1b 3f 1f +00 00 00 32 20 00 00 00 00 00 00 00 00 00 00 00 +25 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +1b 00 aa aa 00 00 00 00 2a 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 1f 00 aa aa 00 00 00 00 +fe 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +1e 00 aa aa 00 00 00 00 07 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 1c 00 aa aa 00 00 00 00 +f9 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +20 00 aa aa 00 00 00 00 fa 00 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 24 00 aa aa 00 00 00 00 +fb 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +23 00 aa aa 00 00 00 00 fc 00 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 21 00 aa aa 00 00 00 00 +fd 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +22 00 aa aa 00 00 00 00 c8 00 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 01 00 aa aa 00 00 00 00 +c8 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +01 00 aa aa 00 00 00 00 c9 00 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 06 00 aa aa 00 00 00 00 +08 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +07 00 aa aa 00 00 00 00 26 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 1d 00 aa aa 00 00 00 00 +09 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +08 00 aa aa 00 00 00 00 0b 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 09 00 aa aa 00 00 00 00 +0a 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +0a 00 aa aa 00 00 00 00 23 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 0b 00 aa aa 00 00 00 00 +21 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +0c 00 aa aa 00 00 00 00 22 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 0d 00 aa aa 00 00 00 00 +03 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +0e 00 aa aa 00 00 00 00 06 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 0f 00 aa aa 00 00 00 00 +06 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +0f 00 aa aa 00 00 00 00 06 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 0f 00 aa aa 00 00 00 00 +04 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +12 00 aa aa 00 00 00 00 01 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 13 00 aa aa 00 00 00 00 +02 01 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +15 00 aa aa 00 00 00 00 05 01 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 16 00 aa aa 00 00 00 00 +f6 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +17 00 aa aa 00 00 00 00 f7 00 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 18 00 aa aa 00 00 00 00 +f5 00 00 00 00 00 00 00 00 00 00 32 20 01 00 00 +19 00 aa aa 00 00 00 00 f5 00 00 00 00 00 00 00 +00 00 00 32 20 01 00 00 19 00 aa aa 00 00 00 00 +1c 01 00 00 00 00 00 00 00 00 00 32 20 00 00 00 +25 00 aa aa 00 00 00 00 c8 00 00 00 00 00 00 00 +00 00 01 32 20 01 00 00 02 00 aa aa 00 00 00 00 +c8 00 00 00 00 00 00 00 00 00 02 32 20 01 00 00 +03 00 aa aa 00 00 00 00 c8 00 00 00 00 00 00 00 +00 00 03 32 20 01 00 00 04 00 aa aa 00 00 00 00 +21 00 00 00 00 00 00 00 00 00 00 ff 20 00 00 00 +00 00 00 00 00 00 00 00 27 00 00 00 00 00 00 00 +00 00 00 ff 20 00 00 00 00 00 00 00 00 00 00 00 +1f 00 00 00 00 00 00 00 00 00 00 ff diff --git a/tmp_extract_asset_strings.py b/tmp_extract_asset_strings.py new file mode 100644 index 0000000..3243adb --- /dev/null +++ b/tmp_extract_asset_strings.py @@ -0,0 +1,13 @@ +import re +from pathlib import Path + +path = Path(r"E:\\emu\\psx\\Crusader - No Remorse\\SLUS_002.68") +data = path.read_bytes() +pattern = re.compile(rb"[ -~]{4,}") +needle = re.compile(r"WDL|LSET|MENU|SPEC|MAP|SPR|TILE", re.I) +seen = set() +for m in pattern.finditer(data): + s = m.group().decode("ascii", errors="ignore") + if needle.search(s) and s not in seen: + seen.add(s) + print(f"0x{m.start():08X}\t{s}") diff --git a/tools/dump_dtable_names.py b/tools/dump_dtable_names.py new file mode 100644 index 0000000..8008ea1 --- /dev/null +++ b/tools/dump_dtable_names.py @@ -0,0 +1,458 @@ +from __future__ import annotations + +import argparse +import csv +import json +import re +from dataclasses import dataclass +from pathlib import Path + + +@dataclass(frozen=True) +class CategorySpec: + name: str + table_offset: int + entry_size: int + entry_count: int + display_frame_offset: int + display_frame_size: int + name_base_global_index: int + helper_name: str + + +@dataclass(frozen=True) +class TargetProfile: + target: str + exe_name: str + xml_name: str | None + data_segment: str + helper_function_address: str + data_segment_file_offset: int + pointer_table_offset: int + global_slot_count: int + string_pool_offset: int + sequential_string_count: int | None + invalid_alias_indices: frozenset[int] + output_prefix: str + categories: tuple[CategorySpec, ...] + notes: tuple[str, ...] + + +REMORSE_CATEGORIES: tuple[CategorySpec, ...] = ( + CategorySpec( + name="weapon", + table_offset=0x20C6, + entry_size=0x12, + entry_count=14, + display_frame_offset=0x0D, + display_frame_size=1, + name_base_global_index=0, + helper_name="Weapon_GetNameForShapeNo", + ), + CategorySpec( + name="misc_item", + table_offset=0x2244, + entry_size=0x04, + entry_count=12, + display_frame_offset=0x02, + display_frame_size=2, + name_base_global_index=14, + helper_name="MiscTable_GetNameForItemShapeNo", + ), + CategorySpec( + name="bomb", + table_offset=0x2274, + entry_size=0x08, + entry_count=9, + display_frame_offset=0x06, + display_frame_size=2, + name_base_global_index=32, + helper_name="MiscTable_GetNameForBombShapeNo", + ), + CategorySpec( + name="ammo", + table_offset=0x2042, + entry_size=0x08, + entry_count=6, + display_frame_offset=0x06, + display_frame_size=2, + name_base_global_index=26, + helper_name="Ammo_GetNameForShapeNo", + ), +) + + +REGRET_CATEGORIES: tuple[CategorySpec, ...] = ( + CategorySpec( + name="weapon", + table_offset=0x2614, + entry_size=0x12, + entry_count=17, + display_frame_offset=0x0D, + display_frame_size=1, + name_base_global_index=0, + helper_name="Weapon_GetNameForShapeNo", + ), + CategorySpec( + name="misc_item", + table_offset=0x2792, + entry_size=0x04, + entry_count=19, + display_frame_offset=0x02, + display_frame_size=2, + name_base_global_index=17, + helper_name="MiscTable_GetNameForItemShapeNo", + ), + CategorySpec( + name="bomb", + table_offset=0x27DE, + entry_size=0x08, + entry_count=8, + display_frame_offset=0x06, + display_frame_size=2, + name_base_global_index=44, + helper_name="MiscTable_GetNameForBombShapeNo", + ), + CategorySpec( + name="ammo", + table_offset=0x2590, + entry_size=0x08, + entry_count=8, + display_frame_offset=0x06, + display_frame_size=2, + name_base_global_index=36, + helper_name="Ammo_GetNameForShapeNo", + ), +) + + +PROFILES: dict[str, TargetProfile] = { + "remorse": TargetProfile( + target="remorse", + exe_name="CRUSADER.EXE", + xml_name="CRUSADER.EXE.xml", + data_segment="1478", + helper_function_address="1118:056a", + data_segment_file_offset=0xE3C00, + pointer_table_offset=0x22BC, + global_slot_count=41, + string_pool_offset=0x238C, + sequential_string_count=None, + invalid_alias_indices=frozenset({0, 14, 26, 32}), + output_prefix="", + categories=REMORSE_CATEGORIES, + notes=( + "Each category uses local index 0 as a reserved INVALID slot.", + "DTable_GetNameForShapeNo tests categories in order: weapon, misc_item, bomb, ammo, then falls back to INVALID.", + "The dump is derived from live retail CRUSADER.EXE bytes plus the named helper structure recovered in segment 1118.", + ), + ), + "regret": TargetProfile( + target="regret", + exe_name="REGRET.EXE", + xml_name=None, + data_segment="1480", + helper_function_address="1130:056a", + data_segment_file_offset=0xE2400, + pointer_table_offset=0x2856, + global_slot_count=52, + string_pool_offset=0x2926, + sequential_string_count=49, + invalid_alias_indices=frozenset({0, 17, 36, 44}), + output_prefix="regret_", + categories=REGRET_CATEGORIES, + notes=( + "Each category uses local index 0 as a reserved INVALID slot, but Regret stores only one physical INVALID string and aliases it into later category starts.", + "DTable_GetNameForShapeNo is recovered in the live REGRET.EXE helper cluster at 1130:056a, alongside the same 1130:0145..0474 name-helper family seen in Remorse.", + "This dump is derived from live retail REGRET.EXE bytes. No local REGRET.EXE XML export was required once the 1480 data-segment base, pointer table, and string pool were recovered from the binary.", + ), + ), +} + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Dump Crusader DTable_GetNameForShapeNo mappings.") + parser.add_argument("target", nargs="?", default="remorse", choices=sorted(PROFILES.keys())) + return parser.parse_args() + + +def read_u16(data: bytes, start: int) -> int: + return int.from_bytes(data[start : start + 2], "little") + + +def read_u8(data: bytes, start: int) -> int: + return data[start] + + +def read_cstring(data: bytes, start: int) -> str: + end = data.index(0, start) + return data[start:end].decode("ascii") + + +def segment_abs(profile: TargetProfile, offset: int) -> str: + return f"{profile.data_segment}:{offset:04x}" + + +def load_global_names_from_xml(profile: TargetProfile, segment_data: bytes, xml_text: str) -> list[dict[str, object]]: + relocations: dict[int, int] = {} + pattern = re.compile( + rf' list[dict[str, object]]: + if profile.sequential_string_count is None: + raise ValueError(f"Profile {profile.target} does not define a sequential string count") + + unique_strings: list[tuple[int, str]] = [] + cursor = profile.string_pool_offset + for _ in range(profile.sequential_string_count): + text = read_cstring(segment_data, cursor) + unique_strings.append((cursor, text)) + cursor += len(text) + 1 + + invalid_offset, invalid_name = unique_strings[0] + next_unique_index = 1 + names: list[dict[str, object]] = [] + for global_index in range(profile.global_slot_count): + slot_offset = profile.pointer_table_offset + (global_index * 4) + if global_index in profile.invalid_alias_indices: + target_offset = invalid_offset + text = invalid_name + else: + target_offset, text = unique_strings[next_unique_index] + next_unique_index += 1 + names.append( + { + "global_index": global_index, + "slot_address": segment_abs(profile, slot_offset), + "address": segment_abs(profile, target_offset), + "name": text, + } + ) + + if next_unique_index != len(unique_strings): + raise ValueError( + f"Profile {profile.target} consumed {next_unique_index} strings but extracted {len(unique_strings)} unique strings" + ) + return names + + +def load_global_names(profile: TargetProfile, repo_root: Path, segment_data: bytes) -> list[dict[str, object]]: + if profile.xml_name: + xml_path = repo_root / "exports" / profile.xml_name + xml_text = xml_path.read_text(encoding="utf-8") + return load_global_names_from_xml(profile, segment_data, xml_text) + return load_global_names_from_string_pool(profile, segment_data) + + +def load_category_entries( + profile: TargetProfile, + segment_data: bytes, + global_names: list[dict[str, object]], +) -> dict[str, list[dict[str, object]]]: + category_entries: dict[str, list[dict[str, object]]] = {} + for spec in profile.categories: + entries: list[dict[str, object]] = [] + for local_index in range(spec.entry_count): + entry_offset = spec.table_offset + (local_index * spec.entry_size) + shape = read_u16(segment_data, entry_offset) + if spec.display_frame_size == 1: + display_frame = read_u8(segment_data, entry_offset + spec.display_frame_offset) + else: + display_frame = read_u16(segment_data, entry_offset + spec.display_frame_offset) + global_name_index = spec.name_base_global_index + local_index + name_entry = global_names[global_name_index] + entries.append( + { + "category": spec.name, + "helper_name": spec.helper_name, + "local_index": local_index, + "reserved_zero_slot": local_index == 0, + "table_address": segment_abs(profile, entry_offset), + "shape": shape, + "shape_hex": f"0x{shape:04X}", + "display_frame": display_frame, + "display_frame_hex": f"0x{display_frame:04X}", + "global_name_index": global_name_index, + "global_name_slot_address": name_entry["slot_address"], + "global_name_address": name_entry["address"], + "name": name_entry["name"], + } + ) + category_entries[spec.name] = entries + return category_entries + + +def resolve_shapes( + profile: TargetProfile, + category_entries: dict[str, list[dict[str, object]]], + fallback_name: str, +) -> list[dict[str, object]]: + shape_membership: dict[int, list[dict[str, object]]] = {} + for spec in profile.categories: + for entry in category_entries[spec.name]: + shape_membership.setdefault(int(entry["shape"]), []).append(entry) + + resolved: list[dict[str, object]] = [] + for shape in sorted(shape_membership): + if shape == 0: + continue + memberships = shape_membership[shape] + chosen: dict[str, object] | None = None + for spec in profile.categories: + for entry in memberships: + if entry["category"] == spec.name and not entry["reserved_zero_slot"] and int(entry["shape"]) != 0: + chosen = entry + break + if chosen is not None: + break + + resolved.append( + { + "shape": shape, + "shape_hex": f"0x{shape:04X}", + "resolved_name": chosen["name"] if chosen is not None else fallback_name, + "resolved_category": chosen["category"] if chosen is not None else "fallback_invalid", + "resolved_helper_name": chosen["helper_name"] if chosen is not None else "DTable_GetNameForShapeNo fallback", + "resolved_local_index": chosen["local_index"] if chosen is not None else None, + "resolved_global_name_index": chosen["global_name_index"] if chosen is not None else 0, + "resolved_global_name_slot_address": chosen["global_name_slot_address"] if chosen is not None else segment_abs(profile, profile.pointer_table_offset), + "resolved_global_name_address": chosen["global_name_address"] if chosen is not None else segment_abs(profile, profile.string_pool_offset), + "display_frame": chosen["display_frame"] if chosen is not None else None, + "display_frame_hex": chosen["display_frame_hex"] if chosen is not None else None, + "memberships": memberships, + } + ) + + return resolved + + +def write_slot_csv(path: Path, global_names: list[dict[str, object]]) -> None: + with path.open("w", newline="", encoding="utf-8") as handle: + writer = csv.DictWriter(handle, fieldnames=["global_index", "slot_address", "address", "name"]) + writer.writeheader() + for row in global_names: + writer.writerow(row) + + +def write_table_csv(path: Path, categories: tuple[CategorySpec, ...], category_entries: dict[str, list[dict[str, object]]]) -> None: + fieldnames = [ + "category", + "helper_name", + "local_index", + "reserved_zero_slot", + "table_address", + "shape", + "shape_hex", + "display_frame", + "display_frame_hex", + "global_name_index", + "global_name_slot_address", + "global_name_address", + "name", + ] + with path.open("w", newline="", encoding="utf-8") as handle: + writer = csv.DictWriter(handle, fieldnames=fieldnames) + writer.writeheader() + for category in (spec.name for spec in categories): + for row in category_entries[category]: + writer.writerow({key: row[key] for key in fieldnames}) + + +def write_resolved_csv(path: Path, resolved_rows: list[dict[str, object]]) -> None: + fieldnames = [ + "shape", + "shape_hex", + "resolved_name", + "resolved_category", + "resolved_helper_name", + "resolved_local_index", + "resolved_global_name_index", + "resolved_global_name_slot_address", + "resolved_global_name_address", + "display_frame", + "display_frame_hex", + ] + with path.open("w", newline="", encoding="utf-8") as handle: + writer = csv.DictWriter(handle, fieldnames=fieldnames) + writer.writeheader() + for row in resolved_rows: + writer.writerow({key: row[key] for key in fieldnames}) + + +def output_basename(profile: TargetProfile) -> str: + return f"{profile.output_prefix}dtable" + + +def main() -> None: + args = parse_args() + profile = PROFILES[args.target] + + repo_root = Path(__file__).resolve().parent.parent + exe_path = repo_root / profile.exe_name + out_dir = repo_root / "out" + out_dir.mkdir(parents=True, exist_ok=True) + + exe_bytes = exe_path.read_bytes() + segment_data = exe_bytes[profile.data_segment_file_offset :] + + global_names = load_global_names(profile, repo_root, segment_data) + category_entries = load_category_entries(profile, segment_data, global_names) + resolved_rows = resolve_shapes(profile, category_entries, fallback_name=str(global_names[0]["name"])) + + json_path = out_dir / f"{output_basename(profile)}_get_name_dump.json" + payload = { + "target": profile.target, + "function": "DTable_GetNameForShapeNo", + "function_address": profile.helper_function_address, + "segment": profile.data_segment, + "segment_file_offset_hex": f"0x{profile.data_segment_file_offset:05X}", + "pointer_table_address": segment_abs(profile, profile.pointer_table_offset), + "string_pool_address": segment_abs(profile, profile.string_pool_offset), + "lookup_order": [spec.name for spec in profile.categories], + "global_name_slots": global_names, + "category_entries": category_entries, + "resolved_shapes": resolved_rows, + "fallback_name": global_names[0]["name"], + "fallback_global_index": global_names[0]["global_index"], + "notes": list(profile.notes), + } + json_path.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + slots_csv_path = out_dir / f"{output_basename(profile)}_global_name_slots.csv" + tables_csv_path = out_dir / f"{output_basename(profile)}_category_entries.csv" + resolved_csv_path = out_dir / f"{output_basename(profile)}_resolved_shapes.csv" + + write_slot_csv(slots_csv_path, global_names) + write_table_csv(tables_csv_path, profile.categories, category_entries) + write_resolved_csv(resolved_csv_path, resolved_rows) + + print(f"Wrote {json_path}") + print(f"Wrote {slots_csv_path}") + print(f"Wrote {tables_csv_path}") + print(f"Wrote {resolved_csv_path}") + + +if __name__ == "__main__": + main() diff --git a/tools/psx_dump_all_lset_sprites.py b/tools/psx_dump_all_lset_sprites.py new file mode 100644 index 0000000..1291083 --- /dev/null +++ b/tools/psx_dump_all_lset_sprites.py @@ -0,0 +1,254 @@ +from __future__ import annotations + +import argparse +import struct +import sys +from dataclasses import dataclass +from pathlib import Path + + +ROOT = Path(r"k:/ghidra/Crusader_Decomp") +DEFAULT_DISC_ROOT = Path(r"e:/emu/psx/Crusader - No Remorse") +DEFAULT_GPU_DUMP = ROOT / "binary/Crusader - No Remorse (USA) GPU RAM.bin" +DEFAULT_OUTPUT = ROOT / "out/psx_wdl/all_lset_sprite_categories" +ROW_BYTES = 2048 +LIVE_CLUT_Y = 0xF0 +LIVE_CLUT_X = 0 +ATLAS_MAX_WIDTH = 1024 +ATLAS_MAX_HEIGHT = 1024 +ATLAS_PADDING = 4 + +sys.path.insert(0, str(ROOT / "tools")) + +from psx_extract_wdl import ( + choose_palette, + colorize_indexed_pixels, + extract_palette_sets, + parse_lset_wdl, + scan_sprite_bundles, + write_png_rgba, +) + + +@dataclass +class SpriteFrame: + source_tag: str + source_name: str + bundle_offset: int + absolute_offset: int + frame_index: int + width: int + height: int + mode: int + frame_count: int + rgba: bytes + opaque_pixels: int + + @property + def area(self) -> int: + return self.width * self.height + + @property + def opaque_ratio(self) -> float: + if self.area == 0: + return 0.0 + return self.opaque_pixels / self.area + + @property + def aspect_ratio(self) -> float: + if self.height == 0: + return 0.0 + return self.width / self.height + + @property + def stem(self) -> str: + return ( + f"{self.source_tag}_off_{self.absolute_offset:08X}_bundle_{self.bundle_offset:08X}" + f"_frame_{self.frame_index:03d}_m{self.mode}" + ) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Dump all LSET sprite bundles from the PSX game files into category folders and packed atlases." + ) + parser.add_argument("--disc-root", type=Path, default=DEFAULT_DISC_ROOT) + parser.add_argument("--gpu-dump", type=Path, default=DEFAULT_GPU_DUMP) + parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT) + parser.add_argument("--max-candidates", type=int, default=0) + return parser.parse_args() + + +def load_live_palette(gpu_dump_path: Path) -> list[int]: + gpu = gpu_dump_path.read_bytes() + row = gpu[LIVE_CLUT_Y * ROW_BYTES : (LIVE_CLUT_Y + 1) * ROW_BYTES] + row_words = struct.unpack("<1024H", row) + return list(row_words[LIVE_CLUT_X : LIVE_CLUT_X + 256]) + + +def count_opaque_pixels(rgba: bytes) -> int: + opaque = 0 + for offset in range(3, len(rgba), 4): + if rgba[offset] != 0: + opaque += 1 + return opaque + + +def classify_frame(frame: SpriteFrame) -> str: + if frame.opaque_pixels <= 96 or (frame.area <= 512 and frame.opaque_ratio < 0.22): + return "effects_and_particles" + if frame.width >= 72 or frame.height >= 72 or frame.area >= 3200: + return "large_props" + if frame.aspect_ratio >= 1.85 and frame.height <= 32: + return "panels_and_strips" + if frame.aspect_ratio <= 0.55 and frame.height >= 28: + return "tall_fixtures" + if frame.height <= 18 and frame.width <= 48: + return "pickups_and_weapons" + if frame.height <= 28 and frame.width <= 40 and frame.area <= 900: + return "small_items" + if frame.frame_count >= 4 and frame.area <= 1600: + return "animated_small_props" + return "medium_props" + + +def pack_pages(frames: list[SpriteFrame]) -> list[list[tuple[SpriteFrame, int, int]]]: + sorted_frames = sorted(frames, key=lambda item: (item.height, item.width, item.area), reverse=True) + pages: list[list[tuple[SpriteFrame, int, int]]] = [] + current_page: list[tuple[SpriteFrame, int, int]] = [] + cursor_x = 0 + cursor_y = 0 + shelf_height = 0 + + for frame in sorted_frames: + needed_width = frame.width + (ATLAS_PADDING if cursor_x else 0) + if cursor_x and cursor_x + needed_width > ATLAS_MAX_WIDTH: + cursor_x = 0 + cursor_y += shelf_height + ATLAS_PADDING + shelf_height = 0 + if cursor_y and cursor_y + frame.height > ATLAS_MAX_HEIGHT: + pages.append(current_page) + current_page = [] + cursor_x = 0 + cursor_y = 0 + shelf_height = 0 + place_x = cursor_x + (ATLAS_PADDING if cursor_x else 0) + current_page.append((frame, place_x, cursor_y)) + cursor_x = place_x + frame.width + shelf_height = max(shelf_height, frame.height) + + if current_page: + pages.append(current_page) + return pages + + +def write_packed_atlas(path: Path, placements: list[tuple[SpriteFrame, int, int]]) -> None: + atlas_width = max(x + frame.width for frame, x, _ in placements) + atlas_height = max(y + frame.height for frame, _, y in placements) + atlas = bytearray(atlas_width * atlas_height * 4) + for frame, origin_x, origin_y in placements: + for y in range(frame.height): + src_start = y * frame.width * 4 + dst_start = ((origin_y + y) * atlas_width + origin_x) * 4 + atlas[dst_start : dst_start + frame.width * 4] = frame.rgba[src_start : src_start + frame.width * 4] + write_png_rgba(path, bytes(atlas), atlas_width, atlas_height) + + +def export_category(output_dir: Path, category: str, frames: list[SpriteFrame]) -> None: + category_dir = output_dir / category + category_dir.mkdir(parents=True, exist_ok=True) + for frame in frames: + write_png_rgba(category_dir / f"{frame.stem}.png", frame.rgba, frame.width, frame.height) + for page_index, placements in enumerate(pack_pages(frames)): + write_packed_atlas(category_dir / f"atlas_{page_index:02d}.png", placements) + + +def source_tag_from_path(disc_root: Path, path: Path) -> str: + relative = path.relative_to(disc_root) + parts = [part.lower().replace(".wdl", "") for part in relative.parts] + return "_".join(parts) + + +def collect_frames_from_lset( + disc_root: Path, + path: Path, + live_palette: list[int], + max_candidates: int, +) -> list[SpriteFrame]: + data = path.read_bytes() + summary = parse_lset_wdl(data) + if summary is None: + return [] + graphics_region = next( + (region for region in summary["regions"] if region["name"] == "post_audio_region_04"), + None, + ) + if graphics_region is None: + return [] + + region_data = data[graphics_region["offset"] : graphics_region["offset"] + graphics_region["size"]] + palettes_16 = extract_palette_sets(data, summary) + source_tag = source_tag_from_path(disc_root, path) + limit = None if max_candidates <= 0 else max_candidates + frames: list[SpriteFrame] = [] + + for bundle in scan_sprite_bundles(region_data, max_candidates=limit): + if bundle["mode"] == 1: + palette = live_palette + elif bundle["mode"] == 2: + palette_index = bundle.get("palette_index") + if palette_index is None or palette_index >= len(palettes_16): + palette_index = choose_palette(palettes_16, bundle["frames"], bundle["mode"]) + if palette_index is None or palette_index >= len(palettes_16): + continue + palette = palettes_16[palette_index] + else: + continue + + absolute_bundle_offset = graphics_region["offset"] + bundle["offset"] + for frame in bundle["frames"]: + rgba = colorize_indexed_pixels(frame["pixels"], frame["width"], frame["height"], bundle["mode"], palette) + frames.append( + SpriteFrame( + source_tag=source_tag, + source_name=str(path.relative_to(disc_root)), + bundle_offset=bundle["offset"], + absolute_offset=absolute_bundle_offset, + frame_index=frame["index"], + width=frame["width"], + height=frame["height"], + mode=bundle["mode"], + frame_count=bundle["frame_count"], + rgba=rgba, + opaque_pixels=count_opaque_pixels(rgba), + ) + ) + return frames + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + live_palette = load_live_palette(args.gpu_dump) + wdl_paths = sorted(args.disc_root.glob("LSET*/L*.WDL")) + + all_frames: list[SpriteFrame] = [] + for path in wdl_paths: + all_frames.extend(collect_frames_from_lset(args.disc_root, path, live_palette, args.max_candidates)) + + categories: dict[str, list[SpriteFrame]] = {} + for frame in all_frames: + categories.setdefault(classify_frame(frame), []).append(frame) + + for category, frames in sorted(categories.items()): + export_category(args.output, category, frames) + + print(f"source_files={len(wdl_paths)}") + print(f"frames={len(all_frames)}") + for category, frames in sorted(categories.items()): + print(f"{category}={len(frames)}") + print(f"folder={args.output / category}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tools/psx_dump_mode1_live_clut_categories.py b/tools/psx_dump_mode1_live_clut_categories.py new file mode 100644 index 0000000..8a4e113 --- /dev/null +++ b/tools/psx_dump_mode1_live_clut_categories.py @@ -0,0 +1,202 @@ +from __future__ import annotations + +import argparse +import struct +from dataclasses import dataclass +from pathlib import Path + + +ROOT = Path(r"k:/ghidra/Crusader_Decomp") +DEFAULT_L0_WDL = Path(r"e:/emu/psx/Crusader - No Remorse/LSET1/L0.WDL") +DEFAULT_GPU_DUMP = ROOT / "binary/Crusader - No Remorse (USA) GPU RAM.bin" +DEFAULT_OUTPUT = ROOT / "out/psx_wdl/L0/mode1_live_clut_categories" +ROW_BYTES = 2048 +LIVE_CLUT_Y = 0xF0 +LIVE_CLUT_X = 0 +ATLAS_MAX_WIDTH = 1024 +ATLAS_MAX_HEIGHT = 1024 +ATLAS_PADDING = 4 + + +import sys + +sys.path.insert(0, str(ROOT / "tools")) + +from psx_extract_wdl import colorize_indexed_pixels, parse_lset_wdl, scan_sprite_bundles, write_png_rgba + + +@dataclass +class SpriteFrame: + bundle_offset: int + frame_index: int + width: int + height: int + frame_count: int + rgba: bytes + opaque_pixels: int + + @property + def area(self) -> int: + return self.width * self.height + + @property + def opaque_ratio(self) -> float: + if self.area == 0: + return 0.0 + return self.opaque_pixels / self.area + + @property + def aspect_ratio(self) -> float: + if self.height == 0: + return 0.0 + return self.width / self.height + + @property + def stem(self) -> str: + return f"bundle_{self.bundle_offset:08X}_frame_{self.frame_index:03d}" + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Export mode-1 PSX L0 sprites into category folders using the verified live CLUT row formula." + ) + parser.add_argument("--wdl", type=Path, default=DEFAULT_L0_WDL) + parser.add_argument("--gpu-dump", type=Path, default=DEFAULT_GPU_DUMP) + parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT) + parser.add_argument("--max-candidates", type=int, default=160) + return parser.parse_args() + + +def load_live_palette(gpu_dump_path: Path) -> list[int]: + gpu = gpu_dump_path.read_bytes() + row = gpu[LIVE_CLUT_Y * ROW_BYTES : (LIVE_CLUT_Y + 1) * ROW_BYTES] + row_words = struct.unpack("<1024H", row) + return list(row_words[LIVE_CLUT_X : LIVE_CLUT_X + 256]) + + +def count_opaque_pixels(rgba: bytes) -> int: + opaque = 0 + for offset in range(3, len(rgba), 4): + if rgba[offset] != 0: + opaque += 1 + return opaque + + +def classify_frame(frame: SpriteFrame) -> str: + if frame.opaque_pixels <= 96 or (frame.area <= 512 and frame.opaque_ratio < 0.22): + return "effects_and_particles" + if frame.width >= 72 or frame.height >= 72 or frame.area >= 3200: + return "large_props" + if frame.aspect_ratio >= 1.85 and frame.height <= 32: + return "panels_and_strips" + if frame.aspect_ratio <= 0.55 and frame.height >= 28: + return "tall_fixtures" + if frame.height <= 18 and frame.width <= 48: + return "pickups_and_weapons" + if frame.height <= 28 and frame.width <= 40 and frame.area <= 900: + return "small_items" + if frame.frame_count >= 4 and frame.area <= 1600: + return "animated_small_props" + return "medium_props" + + +def pack_pages(frames: list[SpriteFrame]) -> list[list[tuple[SpriteFrame, int, int]]]: + sorted_frames = sorted(frames, key=lambda item: (item.height, item.width, item.area), reverse=True) + pages: list[list[tuple[SpriteFrame, int, int]]] = [] + current_page: list[tuple[SpriteFrame, int, int]] = [] + cursor_x = 0 + cursor_y = 0 + shelf_height = 0 + + for frame in sorted_frames: + needed_width = frame.width + (ATLAS_PADDING if cursor_x else 0) + if cursor_x and cursor_x + needed_width > ATLAS_MAX_WIDTH: + cursor_x = 0 + cursor_y += shelf_height + ATLAS_PADDING + shelf_height = 0 + if cursor_y and cursor_y + frame.height > ATLAS_MAX_HEIGHT: + pages.append(current_page) + current_page = [] + cursor_x = 0 + cursor_y = 0 + shelf_height = 0 + place_x = cursor_x + (ATLAS_PADDING if cursor_x else 0) + current_page.append((frame, place_x, cursor_y)) + cursor_x = place_x + frame.width + shelf_height = max(shelf_height, frame.height) + + if current_page: + pages.append(current_page) + return pages + + +def write_packed_atlas(path: Path, placements: list[tuple[SpriteFrame, int, int]]) -> None: + atlas_width = max(x + frame.width for frame, x, _ in placements) + atlas_height = max(y + frame.height for frame, _, y in placements) + atlas = bytearray(atlas_width * atlas_height * 4) + for frame, origin_x, origin_y in placements: + for y in range(frame.height): + src_start = y * frame.width * 4 + dst_start = ((origin_y + y) * atlas_width + origin_x) * 4 + atlas[dst_start : dst_start + frame.width * 4] = frame.rgba[src_start : src_start + frame.width * 4] + write_png_rgba(path, bytes(atlas), atlas_width, atlas_height) + + +def export_category(output_dir: Path, category: str, frames: list[SpriteFrame]) -> None: + category_dir = output_dir / category + category_dir.mkdir(parents=True, exist_ok=True) + for frame in frames: + write_png_rgba(category_dir / f"{frame.stem}.png", frame.rgba, frame.width, frame.height) + for page_index, placements in enumerate(pack_pages(frames)): + write_packed_atlas(category_dir / f"atlas_{page_index:02d}.png", placements) + + +def collect_mode1_frames(wdl_path: Path, gpu_dump_path: Path, max_candidates: int) -> list[SpriteFrame]: + l0_data = wdl_path.read_bytes() + palette = load_live_palette(gpu_dump_path) + summary = parse_lset_wdl(l0_data) + if summary is None: + raise SystemExit(f"failed to parse {wdl_path}") + region = next(region for region in summary["regions"] if region["name"] == "post_audio_region_04") + region_data = l0_data[region["offset"] : region["offset"] + region["size"]] + + frames: list[SpriteFrame] = [] + for bundle in scan_sprite_bundles(region_data, max_candidates=max_candidates): + if bundle["mode"] != 1: + continue + for frame in bundle["frames"]: + rgba = colorize_indexed_pixels(frame["pixels"], frame["width"], frame["height"], 1, palette) + frames.append( + SpriteFrame( + bundle_offset=bundle["offset"], + frame_index=frame["index"], + width=frame["width"], + height=frame["height"], + frame_count=bundle["frame_count"], + rgba=rgba, + opaque_pixels=count_opaque_pixels(rgba), + ) + ) + return frames + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + frames = collect_mode1_frames(args.wdl, args.gpu_dump, args.max_candidates) + + categories: dict[str, list[SpriteFrame]] = {} + for frame in frames: + categories.setdefault(classify_frame(frame), []).append(frame) + + for category, category_frames in sorted(categories.items()): + export_category(args.output, category, category_frames) + + print(f"frames={len(frames)}") + for category, category_frames in sorted(categories.items()): + print(f"{category}={len(category_frames)}") + print(f"folder={args.output / category}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tools/psx_export_map_debug_scene.py b/tools/psx_export_map_debug_scene.py new file mode 100644 index 0000000..ca5829f --- /dev/null +++ b/tools/psx_export_map_debug_scene.py @@ -0,0 +1,559 @@ +from __future__ import annotations + +import argparse +import json +import shutil +import sys +from dataclasses import dataclass +from pathlib import Path + + +if __package__ in (None, ""): + sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +DEFAULT_INPUT = Path(r"k:\ghidra\Crusader_Decomp\out\psx_wdl\L0\post_audio_region_01_00007448_paired_u16x6.json") +DEFAULT_SUMMARY = Path(r"k:\ghidra\Crusader_Decomp\out\psx_wdl\L0\summary.json") +DEFAULT_SPRITE_ROOT = Path(r"k:\ghidra\Crusader_Decomp\out\psx_wdl\L0\sprite_bundles") +DEFAULT_OUTPUT_ROOT = Path(r"k:\ghidra\Crusader_Decomp_Public\map_renderer\site\data") +DEFAULT_MAP_ID = 0 +DEBUG_SCENE_VERSION = "psx-region01-unverified-bundle-probe-v2" +SCREEN_SCALE = 2 +ALLOWED_U5 = {0x20, 0x22, 0x30} + + +@dataclass(frozen=True) +class PlacementRecord: + side: str + row_index: int + record_index: int + u0: int + u1: int + u2: int + u3: int + u4: int + u5: int + + +@dataclass(frozen=True) +class BundleFrame: + bundle_index: int + bundle_offset: int + frame_index: int + frame_count: int + width: int + height: int + origin_x: int + origin_y: int + palette_index: int + source_png: Path + + +def sanitize_origin(origin_x: int, origin_y: int, width: int, height: int) -> tuple[int, int]: + clean_x = origin_x + clean_y = origin_y + if clean_x < 0 or clean_x > width * 4: + clean_x = width // 2 + if clean_y < 0 or clean_y > height * 4: + clean_y = max(0, height - 1) + return clean_x, clean_y + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Export a PSX LSET region-01 debug scene for the public map renderer.") + parser.add_argument("--input", type=Path, default=DEFAULT_INPUT, help="Path to paired_u16x6 JSON export") + parser.add_argument("--summary", type=Path, default=DEFAULT_SUMMARY, help="Path to LSET summary.json with sprite bundle metadata") + parser.add_argument("--sprite-root", type=Path, default=DEFAULT_SPRITE_ROOT, help="Path to extracted sprite_bundles directory") + parser.add_argument("--output-root", type=Path, default=DEFAULT_OUTPUT_ROOT, help="Public renderer site/data root") + parser.add_argument("--game-id", default="psx-remorse", help="Catalog game id to write") + parser.add_argument("--game-label", default="No Remorse (PSX)", help="Catalog game label") + parser.add_argument("--map-id", type=int, default=DEFAULT_MAP_ID, help="Numeric map id for the static scene") + parser.add_argument( + "--map-label", + default="PSX LSET1/L0 Unverified Art Probe", + help="Human-readable map label for the catalog entry", + ) + return parser.parse_args() + + +def load_records(path: Path) -> list[PlacementRecord]: + payload = json.loads(path.read_text(encoding="utf-8")) + records: list[PlacementRecord] = [] + for row in payload.get("rows", []): + row_index = int(row["index"]) + for side_index, side in enumerate(("left", "right")): + values = row.get(side) + if not isinstance(values, dict): + continue + record = PlacementRecord( + side=side, + row_index=row_index, + record_index=row_index * 2 + side_index, + u0=int(values.get("u0", 0)), + u1=int(values.get("u1", 0)), + u2=int(values.get("u2", 0)), + u3=int(values.get("u3", 0)), + u4=int(values.get("u4", 0)), + u5=int(values.get("u5", 0)), + ) + if is_structured_candidate(record): + records.append(record) + records.sort(key=lambda record: (record.u2, record.u1, record.u0, record.record_index)) + return records + + +def is_structured_candidate(record: PlacementRecord) -> bool: + if record.u0 >= 0x200: + return False + if record.u1 == 0 and record.u2 == 0: + return False + if record.u1 >= 0x4000 or record.u2 >= 0x4000: + return False + if record.u3 > 0x20 or record.u4 > 0x04: + return False + if record.u5 not in ALLOWED_U5: + return False + return True + + +def load_bundle_frames(summary_path: Path, sprite_root: Path) -> list[BundleFrame]: + bundle_frames: list[BundleFrame] = [] + bundle_dirs = sorted(path for path in sprite_root.iterdir() if path.is_dir() and path.name.startswith("bundle_")) + for bundle_index, bundle_dir in enumerate(bundle_dirs): + bundle = json.loads((bundle_dir / "bundle.json").read_text(encoding="utf-8")) + bundle_offset = int(bundle.get("offset", 0)) + palette_index = int(bundle.get("palette_index", 0)) + frame_count = int(bundle.get("frame_count", 0)) + for frame in bundle.get("exported_frames", []): + frame_index = int(frame.get("index", 0)) + width = int(frame.get("width", 1)) + height = int(frame.get("height", 1)) + origin_x, origin_y = sanitize_origin( + int(frame.get("origin_x", 0)), + int(frame.get("origin_y", 0)), + width, + height, + ) + source_png = bundle_dir / f"frame_{frame_index:03d}_color.png" + if not source_png.exists(): + source_png = bundle_dir / f"frame_{frame_index:03d}.png" + if not source_png.exists(): + continue + bundle_frames.append( + BundleFrame( + bundle_index=bundle_index, + bundle_offset=bundle_offset, + frame_index=frame_index, + frame_count=frame_count, + width=width, + height=height, + origin_x=origin_x, + origin_y=origin_y, + palette_index=palette_index, + source_png=source_png, + ) + ) + if not bundle_frames: + raise ValueError("No extracted sprite bundle PNGs were found under sprite_bundles.") + return bundle_frames + + +def build_bundle_frame_lookup(bundle_frames: list[BundleFrame]) -> dict[int, list[BundleFrame]]: + lookup: dict[int, list[BundleFrame]] = {} + for bundle_frame in bundle_frames: + lookup.setdefault(bundle_frame.bundle_index, []).append(bundle_frame) + for frames in lookup.values(): + frames.sort(key=lambda frame: frame.frame_index) + return lookup + + +def build_scene(records: list[PlacementRecord], bundle_frames: list[BundleFrame], game_id: str, game_label: str, map_id: int) -> tuple[dict[str, object], list[tuple[Path, str]]]: + if not records: + raise ValueError("No structured PSX placement records survived the debug filter.") + + min_x = min(record.u1 for record in records) + max_x = max(record.u1 for record in records) + min_y = min(record.u2 for record in records) + max_y = max(record.u2 for record in records) + + bundle_lookup = build_bundle_frame_lookup(bundle_frames) + requested_bundles = sorted({record.u0 for record in records}) + missing_bundle_indexes = [bundle_index for bundle_index in requested_bundles if bundle_index not in bundle_lookup] + if missing_bundle_indexes: + raise ValueError(f"Missing extracted PNGs for bundle indexes: {missing_bundle_indexes[:10]}") + + shape_by_bundle = {bundle_index: 0x9000 + index for index, bundle_index in enumerate(requested_bundles)} + sprite_frames: dict[tuple[int, int], BundleFrame] = {} + sprite_copies: list[tuple[Path, str]] = [] + atlases: list[dict[str, object]] = [] + sprites: list[dict[str, object]] = [] + + for bundle_index in requested_bundles: + frames = bundle_lookup[bundle_index] + used_frame_indexes = sorted({min(record.u4, len(frames) - 1) for record in records if record.u0 == bundle_index}) + shape = shape_by_bundle[bundle_index] + for used_frame_index in used_frame_indexes: + bundle_frame = frames[used_frame_index] + sprite_frames[(bundle_index, used_frame_index)] = bundle_frame + atlas_id = f"atlas-{bundle_index:03d}-{used_frame_index:03d}" + file_name = f"bundle_{bundle_frame.bundle_offset:08X}_frame_{bundle_frame.frame_index:03d}.png" + sprite_copies.append((bundle_frame.source_png, file_name)) + atlases.append( + { + "id": atlas_id, + "fileName": file_name, + "width": bundle_frame.width, + "height": bundle_frame.height, + } + ) + sprites.append( + { + "id": f"sprite:{shape}:{used_frame_index}", + "atlasId": atlas_id, + "shape": shape, + "frame": used_frame_index, + "x": 0, + "y": 0, + "width": bundle_frame.width, + "height": bundle_frame.height, + "xoff": bundle_frame.origin_x, + "yoff": bundle_frame.origin_y, + } + ) + + shape_definitions: list[dict[str, object]] = [] + for bundle_index in requested_bundles: + frames = bundle_lookup[bundle_index] + bundle_frame = frames[0] + shape = shape_by_bundle[bundle_index] + shape_definitions.append( + { + "id": f"shape:{shape}", + "shape": shape, + "shapeHex": f"0x{shape:04x}", + "family": None, + "label": "Terrain", + "kind": "terrain", + "displayName": f"PSX unverified bundle probe u0={bundle_index:04X} -> bundle {bundle_index}", + "description": f"Unverified PSX art probe using region-01 u0 as direct sprite bundle index (bundle offset 0x{bundle_frame.bundle_offset:08X}).", + "dimensions": {"x": bundle_frame.width, "y": bundle_frame.height, "z": 1}, + "visibilityTags": [], + "traits": { + "editor": False, + "roof": False, + "oob": False, + "occluding": False, + "translucent": False, + "solid": False, + "fixed": False, + "land": True, + "draw": True, + "invitem": False, + "animType": 0, + }, + "catalogEntry": { + "humanReadableId": "", + "description": "", + "roof": None, + "semitransparency": None, + "oob": None, + }, + "catalogOverrides": { + "roof": None, + "semitransparency": None, + "oob": None, + }, + "tableFallback": None, + } + ) + + items: list[dict[str, object]] = [] + min_screen_left = None + min_screen_top = None + screen_right = None + screen_bottom = None + fallback_frame_count = 0 + for draw_order, record in enumerate(records): + anchor_x = (record.u1 - min_x) * SCREEN_SCALE + anchor_y = (max_y - record.u2) * SCREEN_SCALE + frames = bundle_lookup[record.u0] + chosen_frame_index = min(record.u4, len(frames) - 1) + if chosen_frame_index != record.u4: + fallback_frame_count += 1 + bundle_frame = sprite_frames[(record.u0, chosen_frame_index)] + screen_left = anchor_x - bundle_frame.origin_x + screen_top = anchor_y - bundle_frame.origin_y + screen_right = screen_left + bundle_frame.width if screen_right is None else max(screen_right, screen_left + bundle_frame.width) + screen_bottom = screen_top + bundle_frame.height if screen_bottom is None else max(screen_bottom, screen_top + bundle_frame.height) + min_screen_left = screen_left if min_screen_left is None else min(min_screen_left, screen_left) + min_screen_top = screen_top if min_screen_top is None else min(min_screen_top, screen_top) + shape = shape_by_bundle[record.u0] + items.append( + { + "id": f"item:{draw_order}:psx-region01:{record.side}:{record.row_index}", + "mapSourceIndex": draw_order, + "drawOrder": draw_order, + "kind": "terrain", + "label": "Terrain", + "source": "psx-region01", + "world": { + "x": record.u1, + "y": record.u2, + "z": record.u0, + }, + "mapNum": record.u5, + "npcNum": record.u4, + "nextItem": 0, + "quality": record.u0, + "frame": chosen_frame_index, + "screen": { + "left": screen_left, + "top": screen_top, + "right": screen_left + bundle_frame.width, + "bottom": screen_top + bundle_frame.height, + "width": bundle_frame.width, + "height": bundle_frame.height, + "anchorX": anchor_x, + "anchorY": anchor_y, + }, + "flags": { + "raw": record.u3, + "hex": f"0x{record.u3:04X}", + "invisible": False, + "flipped": False, + }, + "presentation": { + "opacity": 1, + "visibilityDefault": True, + }, + "notes": [ + f"PSX region-01 art probe record {record.side} row {record.row_index}", + f"raw words: {record.u0:04X} {record.u1:04X} {record.u2:04X} {record.u3:04X} {record.u4:04X} {record.u5:04X}", + f"provisional art mapping: bundle_index={record.u0} bundle_offset=0x{bundle_frame.bundle_offset:08X} requested_frame={record.u4} chosen_frame={chosen_frame_index} palette_index={bundle_frame.palette_index}", + ], + "frameSize": { + "width": bundle_frame.width, + "height": bundle_frame.height, + "xoff": bundle_frame.origin_x, + "yoff": bundle_frame.origin_y, + }, + "egg": None, + "npcPreview": None, + "itemPreview": None, + "shapeDefId": f"shape:{shape}", + "spriteId": f"sprite:{shape}:{chosen_frame_index}", + } + ) + + x_shift = -min(0, min_screen_left or 0) + y_shift = -min(0, min_screen_top or 0) + final_right = 0 + final_bottom = 0 + for item in items: + screen = item["screen"] + screen["left"] += x_shift + screen["right"] += x_shift + screen["top"] += y_shift + screen["bottom"] += y_shift + screen["anchorX"] += x_shift + screen["anchorY"] += y_shift + final_right = max(final_right, screen["right"]) + final_bottom = max(final_bottom, screen["bottom"]) + + map_source_items = [] + for record, item in zip(records, items): + chosen_frame_index = item["frame"] + bundle_frame = sprite_frames[(record.u0, chosen_frame_index)] + map_source_items.append( + { + "x": record.u1, + "y": record.u2, + "z": record.u0, + "shape": shape_by_bundle[record.u0], + "frame": chosen_frame_index, + "flags": record.u3, + "quality": record.u0, + "npcNum": record.u4, + "mapNum": record.u5, + "nextItem": 0, + "source": "psx-region01", + "rawWords": [record.u0, record.u1, record.u2, record.u3, record.u4, record.u5], + "recordSide": record.side, + "rowIndex": record.row_index, + "bundleOffset": bundle_frame.bundle_offset, + "paletteIndex": bundle_frame.palette_index, + "screenLeft": item["screen"]["left"], + "screenTop": item["screen"]["top"], + } + ) + + scene = { + "build": { + "version": DEBUG_SCENE_VERSION, + "fingerprint": "psx-lset1-l0-region01-debug", + "generatedAt": "2026-03-29T00:00:00.000Z", + "cacheMode": "single-scene", + }, + "metadata": { + "game": game_id, + "gameLabel": game_label, + "map": map_id, + "rawItemCount": len(records), + "itemCount": len(records), + "paintedItemCount": len(records), + "occludedItemCount": 0, + "invalidItemCount": 0, + "invalidItems": [], + "sceneSummary": { + "atlasCount": len(atlases), + "spriteCount": len(sprites), + "helperCount": 0, + "kindCounts": {"terrain": len(records)}, + "sourceCounts": {"psx-region01": len(records)}, + "topFamilies": [{"family": None, "count": len(records)}], + }, + "usage": { + "status": "research", + "confidence": "low", + "knownHints": [ + "Uses real extracted LSET sprite bundle PNGs as an explicitly unverified art probe.", + "Current hypothesis is direct region-01 u0 -> sprite bundle index and u4 -> frame index.", + "This mapping is known to be incoherent and should not be treated as final art placement." + ], + "itemMapNums": sorted({record.u5 for record in records}), + "nonzeroItemMapNums": sorted({record.u5 for record in records if record.u5 != 0}), + "npcLinkedItemCount": sum(1 for record in records if record.u4 != 0), + "note": "This is an unverified real-art PSX probe scene from filtered region-01 placement candidates, not a final decoded map format.", + "hasRenderableContent": True, + "game": game_id, + "map": map_id, + }, + "baseItemSummary": { + "roofItems": 0, + "editorItems": 0, + "eggFamilyItems": 0, + "invisibleFlaggedItems": 0, + "npcLinkedItems": sum(1 for record in records if record.u4 != 0), + }, + "sorter": "psx_region01_debug", + "isEmpty": False, + "emptyReason": None, + "bounds": { + "screenLeft": 0, + "screenTop": 0, + "screenRight": final_right, + "screenBottom": final_bottom, + "width": final_right, + "height": final_bottom, + }, + "zoom": { + "min": 0.01, + "max": 8, + "step": 0.1, + "initial": 1, + }, + "buildFingerprint": "psx-lset1-l0-region01-unverified-art-probe", + "generatedAt": "2026-03-29T00:00:00.000Z", + "probeStats": { + "fallbackFrameCount": fallback_frame_count, + "bundleIndexMin": requested_bundles[0], + "bundleIndexMax": requested_bundles[-1], + "bundleCountUsed": len(requested_bundles), + }, + }, + "atlases": atlases, + "sprites": sprites, + "shapeDefinitions": sorted(shape_definitions, key=lambda entry: entry["shape"]), + "items": items, + "mapSource": { + "formatVersion": DEBUG_SCENE_VERSION, + "game": game_id, + "mapId": map_id, + "itemRecordSize": 12, + "itemCount": len(map_source_items), + "originalByteLength": len(map_source_items) * 12, + "exportFileName": None, + "defaultTeleportEggShape": None, + "defaultTeleportEggShapeHex": None, + "defaultTeleportEggFrame": None, + "defaultTeleporterEggFrame": None, + "defaultTeleportDestinationEggFrame": None, + "binaryExportSupported": False, + "items": map_source_items, + }, + } + return scene, sprite_copies + + +def write_catalog_entry(output_root: Path, game_id: str, game_label: str, map_id: int, map_label: str, raw_item_count: int, shape_definitions: list[dict[str, object]]) -> None: + catalog_path = output_root / "catalog.json" + catalog = json.loads(catalog_path.read_text(encoding="utf-8")) if catalog_path.exists() else {"games": []} + games = [game for game in catalog.get("games", []) if game.get("id") != game_id] + games.append( + { + "id": game_id, + "label": game_label, + "mapCount": 1, + "maps": [ + { + "id": map_id, + "label": map_label, + "rawItemCount": raw_item_count, + } + ], + } + ) + games.sort(key=lambda game: game["label"]) + catalog["games"] = games + catalog_path.write_text(json.dumps(catalog, indent=2) + "\n", encoding="utf-8") + + catalogs_dir = output_root / "catalogs" + catalogs_dir.mkdir(parents=True, exist_ok=True) + csv_lines = [ + "shape_code,human_readable_id,description,roof,semitransparency,OOB,categorization,qualities" + ] + for definition in shape_definitions: + csv_lines.append( + ",".join( + [ + definition["shapeHex"], + definition["displayName"], + definition["description"], + "", + "", + "", + definition["kind"], + "", + ] + ) + ) + (catalogs_dir / f"{game_id}.csv").write_text("\n".join(csv_lines) + "\n", encoding="utf-8") + + +def main() -> int: + args = parse_args() + records = load_records(args.input) + bundle_frames = load_bundle_frames(args.summary, args.sprite_root) + scene, sprite_copies = build_scene(records, bundle_frames, args.game_id, args.game_label, args.map_id) + + maps_root = args.output_root / "maps" / args.game_id / f"map-{args.map_id}" + maps_root.mkdir(parents=True, exist_ok=True) + for source_png, file_name in sprite_copies: + shutil.copyfile(source_png, maps_root / file_name) + (maps_root / "scene.json").write_text(json.dumps(scene, indent=2) + "\n", encoding="utf-8") + write_catalog_entry( + args.output_root, + args.game_id, + args.game_label, + args.map_id, + args.map_label, + len(records), + scene["shapeDefinitions"], + ) + print( + f"wrote PSX art probe scene: game={args.game_id} map={args.map_id} items={len(records)} unique_shapes={len(scene['shapeDefinitions'])} atlases={len(scene['atlases'])}" + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) \ No newline at end of file diff --git a/tools/psx_extract_wdl.py b/tools/psx_extract_wdl.py new file mode 100644 index 0000000..17dcf7d --- /dev/null +++ b/tools/psx_extract_wdl.py @@ -0,0 +1,1087 @@ +from __future__ import annotations + +import argparse +import csv +import json +import struct +import zlib +from pathlib import Path + + +KNOWN_TIM_FLAGS = {0, 1, 2, 3, 8, 9, 10, 11} + + +def u32(data: bytes, offset: int) -> int: + return struct.unpack_from(" dict[str, int] | None: + if offset + 12 > len(data) or u32(data, offset) != 0x10: + return None + + flags = u32(data, offset + 4) + if flags not in KNOWN_TIM_FLAGS: + return None + + cursor = offset + 8 + has_clut = (flags & 0x8) != 0 + if has_clut: + if cursor + 12 > len(data): + return None + clut_size = u32(data, cursor) + if clut_size < 12 or cursor + clut_size > len(data): + return None + cursor += clut_size + + if cursor + 12 > len(data): + return None + + image_size = u32(data, cursor) + if image_size < 12 or cursor + image_size > len(data): + return None + + cursor += image_size + return { + "offset": offset, + "size": cursor - offset, + "flags": flags, + "has_clut": has_clut, + } + + +def scan_tims(data: bytes) -> list[dict[str, int]]: + hits: list[dict[str, int]] = [] + offset = 0 + while offset <= len(data) - 12: + hit = carve_tim(data, offset) + if hit is None: + offset += 4 + continue + hits.append(hit) + offset = hit["offset"] + max(hit["size"], 4) + return hits + + +def write_blob(path: Path, data: bytes) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + + +def write_u16x6_csv(path: Path, data: bytes) -> None: + usable_size = len(data) - (len(data) % 12) + if usable_size < 12: + return + + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", newline="", encoding="ascii") as handle: + writer = csv.writer(handle) + writer.writerow(["index", "offset", "field0", "field1", "field2", "field3", "field4", "field5"]) + for index, offset in enumerate(range(0, usable_size, 12)): + fields = struct.unpack_from("<6H", data, offset) + writer.writerow( + [ + index, + f"0x{offset:X}", + *(f"0x{value:04X}" for value in fields), + ] + ) + + +def write_u16x12_csv(path: Path, data: bytes) -> None: + usable_size = len(data) - (len(data) % 24) + if usable_size < 24: + return + + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", newline="", encoding="ascii") as handle: + writer = csv.writer(handle) + writer.writerow( + [ + "index", + "offset", + "field0", + "field1", + "field2", + "field3", + "field4", + "field5", + "field6", + "field7", + "field8", + "field9", + "field10", + "field11", + ] + ) + for index, offset in enumerate(range(0, usable_size, 24)): + fields = struct.unpack_from("<12H", data, offset) + writer.writerow( + [ + index, + f"0x{offset:X}", + *(f"0x{value:04X}" for value in fields), + ] + ) + + +def write_u32x5_csv(path: Path, data: bytes) -> None: + usable_size = len(data) - (len(data) % 20) + if usable_size < 20: + return + + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", newline="", encoding="ascii") as handle: + writer = csv.writer(handle) + writer.writerow(["index", "offset", "field0", "field1", "field2", "field3", "field4"]) + for index, offset in enumerate(range(0, usable_size, 20)): + fields = struct.unpack_from("<5I", data, offset) + writer.writerow([index, f"0x{offset:X}", *(f"0x{value:08X}" for value in fields)]) + + +def write_lset_stream_probe_json(path: Path, data: bytes) -> None: + if len(data) < 4: + return + + stream_count = u32(data, 0) + headers: list[dict[str, object]] = [] + max_headers = min(stream_count, 64) + for index in range(max_headers): + offset = 4 + index * 20 + if offset + 20 > len(data): + break + chunk = data[offset : offset + 20] + headers.append( + { + "index": index, + "offset": offset, + "hex": chunk.hex(), + "u32le": [u32(chunk, word_offset) for word_offset in range(0, 20, 4)], + } + ) + + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text( + json.dumps( + { + "stream_count_le": stream_count, + "header_region_size": len(data), + "header_chunk_size": 20, + "note": "Raw loader-grounded probe for the LSET post-audio region that begins with the level_resource_stream_load count.", + "headers": headers, + }, + indent=2, + ) + + "\n", + encoding="ascii", + ) + + +def write_paired_u16x6_json(path: Path, data: bytes) -> None: + usable_size = len(data) - (len(data) % 24) + if usable_size < 24: + return + + rows: list[dict[str, object]] = [] + for index, offset in enumerate(range(0, usable_size, 24)): + left = struct.unpack_from("<6H", data, offset) + right = struct.unpack_from("<6H", data, offset + 12) + rows.append( + { + "index": index, + "offset": offset, + "left": { + "u0": left[0], + "u1": left[1], + "u2": left[2], + "u3": left[3], + "u4": left[4], + "u5": left[5], + }, + "right": { + "u0": right[0], + "u1": right[1], + "u2": right[2], + "u3": right[3], + "u4": right[4], + "u5": right[5], + }, + } + ) + + field_ranges: dict[str, dict[str, int]] = {} + for side in ("left", "right"): + for field_index in range(6): + key = f"{side}.u{field_index}" + values = [row[side][f"u{field_index}"] for row in rows] + nontrivial = [value for value in values if value not in {0x0000, 0xFFFF}] + stats: dict[str, int | None] = { + "min": min(values), + "max": max(values), + "unique_count": len(set(values)), + } + if nontrivial: + stats["nontrivial_min"] = min(nontrivial) + stats["nontrivial_max"] = max(nontrivial) + stats["nontrivial_unique_count"] = len(set(nontrivial)) + else: + stats["nontrivial_min"] = None + stats["nontrivial_max"] = None + stats["nontrivial_unique_count"] = 0 + field_ranges[key] = stats + + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text( + json.dumps( + { + "record_size": 24, + "row_count": len(rows), + "layout_note": "Each row is exported as two adjacent 6-word candidate placement records.", + "field_ranges": field_ranges, + "rows": rows, + }, + indent=2, + ), + encoding="ascii", + ) + + +def write_pgm(path: Path, pixels: bytes, width: int, height: int) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + header = f"P5\n{width} {height}\n255\n".encode("ascii") + path.write_bytes(header + pixels) + + +def write_png_grayscale(path: Path, pixels: bytes, width: int, height: int) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + + def chunk(tag: bytes, payload: bytes) -> bytes: + crc = zlib.crc32(tag) + crc = zlib.crc32(payload, crc) & 0xFFFFFFFF + return struct.pack( + ">I", len(payload) + ) + tag + payload + struct.pack(">I", crc) + + scanlines = bytearray() + stride = width + for row in range(height): + start = row * stride + scanlines.append(0) + scanlines.extend(pixels[start : start + stride]) + + ihdr = struct.pack(">IIBBBBB", width, height, 8, 0, 0, 0, 0) + idat = zlib.compress(bytes(scanlines), level=9) + png = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", idat) + chunk(b"IEND", b"") + path.write_bytes(png) + + +def write_png_rgba(path: Path, pixels: bytes, width: int, height: int) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + + def chunk(tag: bytes, payload: bytes) -> bytes: + crc = zlib.crc32(tag) + crc = zlib.crc32(payload, crc) & 0xFFFFFFFF + return struct.pack(">I", len(payload)) + tag + payload + struct.pack(">I", crc) + + stride = width * 4 + scanlines = bytearray() + for row in range(height): + start = row * stride + scanlines.append(0) + scanlines.extend(pixels[start : start + stride]) + + ihdr = struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0) + idat = zlib.compress(bytes(scanlines), level=9) + png = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", idat) + chunk(b"IEND", b"") + path.write_bytes(png) + + +def psx_555_to_rgba(color: int) -> tuple[int, int, int, int]: + red = (color & 0x1F) * 255 // 31 + green = ((color >> 5) & 0x1F) * 255 // 31 + blue = ((color >> 10) & 0x1F) * 255 // 31 + alpha = 0 if (color & 0x7FFF) == 0 else 255 + return red, green, blue, alpha + + +def write_psx_16bpp_png(path: Path, data: bytes, width: int, height: int) -> None: + pixel_count = width * height + usable_size = min(len(data) // 2, pixel_count) + rgba = bytearray(pixel_count * 4) + for pixel_index in range(usable_size): + color = struct.unpack_from(" list[list[int]]: + if summary["kind"] != "lset": + return [] + + header_words = summary["header_words"] + if len(header_words) < 4: + return [] + + palette_offset = header_words[2] + palette_size = header_words[3] + if palette_size != 0x1000 or palette_offset + palette_size > len(data): + return [] + + blob = data[palette_offset : palette_offset + palette_size] + palettes: list[list[int]] = [] + for offset in range(0, len(blob), 0x20): + if offset + 0x20 > len(blob): + break + palette = list(struct.unpack_from("<16H", blob, offset)) + palettes.append(palette) + return palettes + + +def extract_palette_blocks_256(data: bytes, summary: dict[str, object]) -> list[list[int]]: + if summary["kind"] != "lset": + return [] + + header_words = summary["header_words"] + if len(header_words) < 4: + return [] + + palette_offset = header_words[2] + palette_size = header_words[3] + if palette_size != 0x1000 or palette_offset + palette_size > len(data): + return [] + + blob = data[palette_offset : palette_offset + palette_size] + palettes: list[list[int]] = [] + for offset in range(0, len(blob), 0x200): + if offset + 0x200 > len(blob): + break + palette = list(struct.unpack_from("<256H", blob, offset)) + palettes.append(palette) + return palettes + + +def choose_palette(palettes: list[list[int]], frames: list[dict[str, object]], mode: int) -> int | None: + if mode != 2 or not palettes: + return None + + used_indices: set[int] = set() + for frame in frames: + for byte in frame["pixels"]: + used_indices.add(byte & 0x0F) + used_indices.add((byte >> 4) & 0x0F) + + used_indices.discard(0) + if not used_indices: + return 0 + + best_index: int | None = None + best_score = -1 + for palette_index, palette in enumerate(palettes): + distinct = {palette[i] & 0x7FFF for i in used_indices} + nonzero = {value for value in distinct if value != 0} + if not nonzero: + continue + channel_spread = 0 + for value in nonzero: + red, green, blue, _ = psx_555_to_rgba(value) + channel_spread += red + green + blue + score = len(nonzero) * 100000 + channel_spread + if score > best_score: + best_score = score + best_index = palette_index + return best_index + + +def colorize_indexed_pixels( + raw: bytes, + width: int, + height: int, + mode: int, + palette: list[int], + high_nibble_first: bool = False, +) -> bytes: + rgba = bytearray(width * height * 4) + if mode == 2: + row_bytes = (width + 1) // 2 + src = 0 + dst = 0 + for _ in range(height): + row = raw[src : src + row_bytes] + src += row_bytes + for byte in row: + if high_nibble_first: + indices = ((byte >> 4) & 0x0F, byte & 0x0F) + else: + indices = (byte & 0x0F, (byte >> 4) & 0x0F) + for index in indices: + if dst >= len(rgba): + break + red, green, blue, _ = psx_555_to_rgba(palette[index]) + alpha = 0 if index == 0 else 255 + rgba[dst : dst + 4] = bytes((red, green, blue, alpha)) + dst += 4 + return bytes(rgba) + + for pixel_index, value in enumerate(raw[: width * height]): + red, green, blue, _ = psx_555_to_rgba(palette[value]) + alpha = 0 if value == 0 else 255 + dst = pixel_index * 4 + rgba[dst : dst + 4] = bytes((red, green, blue, alpha)) + return bytes(rgba) + + +def write_bundle_atlas(path: Path, frames: list[dict[str, object]]) -> None: + if not frames: + return + padding = 2 + atlas_width = sum(frame["width"] for frame in frames) + padding * (len(frames) - 1) + atlas_height = max(frame["height"] for frame in frames) + atlas = bytearray(atlas_width * atlas_height * 4) + cursor_x = 0 + for frame in frames: + width = frame["width"] + height = frame["height"] + rgba = frame["rgba"] + for y in range(height): + src_start = y * width * 4 + dst_start = (y * atlas_width + cursor_x) * 4 + atlas[dst_start : dst_start + width * 4] = rgba[src_start : src_start + width * 4] + cursor_x += width + padding + write_png_rgba(path, bytes(atlas), atlas_width, atlas_height) + + +def write_overview_grid(path: Path, entries: list[dict[str, object]], columns: int = 4) -> None: + if not entries: + return + padding = 4 + cell_width = max(entry["width"] for entry in entries) + cell_height = max(entry["height"] for entry in entries) + rows = (len(entries) + columns - 1) // columns + atlas_width = columns * cell_width + padding * (columns - 1) + atlas_height = rows * cell_height + padding * (rows - 1) + atlas = bytearray(atlas_width * atlas_height * 4) + for entry_index, entry in enumerate(entries): + col = entry_index % columns + row = entry_index // columns + origin_x = col * (cell_width + padding) + origin_y = row * (cell_height + padding) + rgba = entry["rgba"] + for y in range(entry["height"]): + src_start = y * entry["width"] * 4 + dst_start = ((origin_y + y) * atlas_width + origin_x) * 4 + atlas[dst_start : dst_start + entry["width"] * 4] = rgba[src_start : src_start + entry["width"] * 4] + write_png_rgba(path, bytes(atlas), atlas_width, atlas_height) + + +def write_palette_row_sweep( + path: Path, + frame: dict[str, object], + palettes: list[list[int]], + base_palette_index: int, + mode: int, +) -> None: + if mode != 2: + return + column = base_palette_index % 16 + variants: list[dict[str, object]] = [] + for row in range(8): + palette_index = row * 16 + column + if palette_index >= len(palettes): + continue + rgba = colorize_indexed_pixels(frame["pixels"], frame["width"], frame["height"], mode, palettes[palette_index]) + variants.append( + { + "width": frame["width"], + "height": frame["height"], + "rgba": rgba, + } + ) + write_bundle_atlas(path, variants) + + +def decode_indexed_pixels( + raw: bytes, width: int, height: int, mode: int, high_nibble_first: bool = False +) -> bytes: + if mode == 2: + row_bytes = (width + 1) // 2 + out = bytearray(width * height) + src = 0 + dst = 0 + for _ in range(height): + row = raw[src : src + row_bytes] + src += row_bytes + for byte in row: + if high_nibble_first: + indices = ((byte >> 4) & 0x0F, byte & 0x0F) + else: + indices = (byte & 0x0F, (byte >> 4) & 0x0F) + for index in indices: + if dst < len(out): + out[dst] = index * 17 + dst += 1 + return bytes(out) + + return raw[: width * height] + + +def decode_rle_rows(data: bytes, start: int, width: int, height: int, mode: int) -> tuple[bytes, int] | None: + row_bytes = (width + 1) // 2 if mode == 2 else width + expected_size = row_bytes * height + out = bytearray() + cursor = start + rows = 0 + + while rows < height: + if cursor >= len(data): + return None + control = data[cursor] + cursor += 1 + signed = control if control < 0x80 else control - 0x100 + + if signed == 0: + rows += 1 + continue + + if signed < 0: + count = control & 0x7F + if cursor + count > len(data): + return None + out.extend(data[cursor : cursor + count]) + cursor += count + else: + if cursor >= len(data): + return None + out.extend(bytes([data[cursor]]) * signed) + cursor += 1 + + if len(out) > expected_size: + return None + + if len(out) != expected_size: + return None + return bytes(out), cursor - start + + +def try_parse_sprite_bundle(data: bytes, base_offset: int) -> dict[str, object] | None: + if base_offset + 0x34 > len(data): + return None + + mode = u32(data, base_offset + 0x10) + if mode not in {1, 2}: + return None + + palette_index = u32(data, base_offset + 0x14) + if palette_index > 127: + return None + + frame_count = u32(data, base_offset + 0x20) + if frame_count == 0 or frame_count > 512: + return None + + data_offset = u32(data, base_offset + 0x1C) + record_table_size = frame_count * 20 + if data_offset < 0x34 + record_table_size or base_offset + data_offset >= len(data): + return None + + frames: list[dict[str, object]] = [] + for frame_index in range(min(frame_count, 12)): + record_offset = base_offset + 0x34 + frame_index * 20 + if record_offset + 20 > len(data): + return None + + flags = u32(data, record_offset) + data_rel = u32(data, record_offset + 8) + width, height, origin_x, origin_y = struct.unpack_from("<4H", data, record_offset + 12) + if width == 0 or height == 0 or width > 512 or height > 512: + return None + + row_bytes = (width + 1) // 2 if mode == 2 else width + data_start = base_offset + data_offset + (data_rel * 4 if (flags & 1) else data_rel) + if data_start >= len(data): + return None + + if flags & 1: + decoded = decode_rle_rows(data, data_start, width, height, mode) + if decoded is None: + return None + raw_pixels, consumed = decoded + else: + raw_size = row_bytes * height + if data_start + raw_size > len(data): + return None + raw_pixels = data[data_start : data_start + raw_size] + consumed = raw_size + + frames.append( + { + "index": frame_index, + "flags": flags, + "data_rel": data_rel, + "width": width, + "height": height, + "origin_x": origin_x, + "origin_y": origin_y, + "data_start": data_start, + "consumed": consumed, + "pixels": raw_pixels, + } + ) + + return { + "offset": base_offset, + "mode": mode, + "palette_index": palette_index, + "frame_count": frame_count, + "data_offset": data_offset, + "frames": frames, + } + + +def scan_sprite_bundles(data: bytes, max_candidates: int | None = None) -> list[dict[str, object]]: + candidates: list[dict[str, object]] = [] + seen_ranges: list[tuple[int, int]] = [] + for offset in range(0, len(data) - 0x34, 4): + bundle = try_parse_sprite_bundle(data, offset) + if bundle is None: + continue + + end = offset + bundle["data_offset"] + if any(existing_start <= offset < existing_end for existing_start, existing_end in seen_ranges): + continue + seen_ranges.append((offset, end)) + candidates.append(bundle) + if max_candidates is not None and len(candidates) >= max_candidates: + break + return candidates + + +def export_sprite_bundle(bundle: dict[str, object], target_dir: Path) -> dict[str, object]: + bundle_dir = target_dir / f"bundle_{bundle['offset']:08X}" + bundle_dir.mkdir(parents=True, exist_ok=True) + frame_rows: list[dict[str, object]] = [] + for frame in bundle["frames"]: + raw_path = bundle_dir / f"frame_{frame['index']:03d}.bin" + raw_path.write_bytes(frame["pixels"]) + image = decode_indexed_pixels(frame["pixels"], frame["width"], frame["height"], bundle["mode"]) + write_pgm(bundle_dir / f"frame_{frame['index']:03d}.pgm", image, frame["width"], frame["height"]) + write_png_grayscale(bundle_dir / f"frame_{frame['index']:03d}.png", image, frame["width"], frame["height"]) + frame_rows.append( + { + "index": frame["index"], + "flags": frame["flags"], + "width": frame["width"], + "height": frame["height"], + "origin_x": frame["origin_x"], + "origin_y": frame["origin_y"], + "data_start": frame["data_start"], + "consumed": frame["consumed"], + } + ) + + metadata = { + "offset": bundle["offset"], + "mode": bundle["mode"], + "palette_index": bundle["palette_index"], + "frame_count": bundle["frame_count"], + "data_offset": bundle["data_offset"], + "exported_frames": frame_rows, + } + (bundle_dir / "bundle.json").write_text(json.dumps(metadata, indent=2), encoding="ascii") + return metadata + + +def export_colored_sprite_bundle( + bundle: dict[str, object], + target_dir: Path, + palettes_16: list[list[int]], + palettes_256: list[list[int]], +) -> dict[str, object] | None: + palette_index = bundle.get("palette_index") + if bundle["mode"] == 2: + if palette_index is None or palette_index >= len(palettes_16): + palette_index = choose_palette(palettes_16, bundle["frames"], bundle["mode"]) + if palette_index is None: + return None + palette = palettes_16[palette_index] + elif bundle["mode"] == 1: + if palette_index is None or palette_index >= len(palettes_256): + if not palettes_256: + return None + palette_index = 0 + palette = palettes_256[palette_index] + else: + return None + + bundle_dir = target_dir / f"bundle_{bundle['offset']:08X}" + bundle_dir.mkdir(parents=True, exist_ok=True) + + exported_frames: list[dict[str, object]] = [] + exported_frames_flip: list[dict[str, object]] = [] + for frame in bundle["frames"]: + rgba = colorize_indexed_pixels(frame["pixels"], frame["width"], frame["height"], bundle["mode"], palette) + write_png_rgba(bundle_dir / f"frame_{frame['index']:03d}_color.png", rgba, frame["width"], frame["height"]) + rgba_flip = colorize_indexed_pixels( + frame["pixels"], + frame["width"], + frame["height"], + bundle["mode"], + palette, + high_nibble_first=True, + ) + write_png_rgba( + bundle_dir / f"frame_{frame['index']:03d}_color_flip.png", + rgba_flip, + frame["width"], + frame["height"], + ) + frame_copy = dict(frame) + frame_copy["rgba"] = rgba + exported_frames.append(frame_copy) + frame_copy_flip = dict(frame) + frame_copy_flip["rgba"] = rgba_flip + exported_frames_flip.append(frame_copy_flip) + + write_bundle_atlas(bundle_dir / "atlas_color.png", exported_frames) + write_bundle_atlas(bundle_dir / "atlas_color_flip.png", exported_frames_flip) + if exported_frames and bundle["mode"] == 2: + write_palette_row_sweep( + bundle_dir / "palette_row_sweep.png", + exported_frames[0], + palettes_16, + palette_index, + bundle["mode"], + ) + metadata = { + "palette_index": palette_index, + "palette_preview": [f"0x{value:04X}" for value in palette[:16]], + "frame_count": len(exported_frames), + } + (bundle_dir / "palette.json").write_text(json.dumps(metadata, indent=2), encoding="ascii") + return metadata + + +def annotate_region_tim_counts( + regions: list[dict[str, int]], tim_hits: list[dict[str, int]] +) -> None: + for region in regions: + start = region["offset"] + end = start + region["size"] + region["tim_count"] = sum(1 for hit in tim_hits if start <= hit["offset"] < end) + + +def parse_lset_wdl(data: bytes) -> dict[str, object] | None: + if len(data) < 0x34: + return None + + header_size = u32(data, 0) + if header_size != 0x34 or header_size > len(data): + return None + + header_words = [u32(data, offset) for offset in range(0, header_size, 4)] + audio_size = header_words[1] + post_audio_start = header_size + audio_size + high_boundaries = sorted( + { + value + for value in header_words[2:] + if post_audio_start <= value < len(data) + } + ) + + regions: list[dict[str, int | str]] = [] + if audio_size and post_audio_start <= len(data): + regions.append( + { + "name": "audio_or_spu_blob", + "offset": header_size, + "size": audio_size, + } + ) + + boundaries = [post_audio_start] + high_boundaries + [len(data)] + for index in range(len(boundaries) - 1): + start = boundaries[index] + end = boundaries[index + 1] + if end <= start: + continue + regions.append( + { + "name": f"post_audio_region_{index:02d}", + "offset": start, + "size": end - start, + } + ) + + tim_hits = scan_tims(data) + annotate_region_tim_counts(regions, tim_hits) + + return { + "kind": "lset", + "header_size": header_size, + "header_words": header_words, + "audio_size": audio_size, + "post_audio_start": post_audio_start, + "high_offset_boundaries": high_boundaries, + "regions": regions, + "tim_hits": tim_hits, + } + + +def parse_contiguous_section_wdl(data: bytes) -> dict[str, object] | None: + header_size = 0x38 + if len(data) < header_size: + return None + + section_sizes = [u32(data, offset) for offset in range(0, header_size, 4)] + cursor = header_size + regions: list[dict[str, int | str]] = [] + for index, size in enumerate(section_sizes): + if size == 0: + regions.append({"name": f"section_{index:02d}", "offset": cursor, "size": 0}) + continue + if cursor + size > len(data): + return None + regions.append({"name": f"section_{index:02d}", "offset": cursor, "size": size}) + cursor += size + + tim_hits = scan_tims(data) + annotate_region_tim_counts(regions, tim_hits) + return { + "kind": "contiguous_sections", + "header_size": header_size, + "section_sizes": section_sizes, + "regions": regions, + "tim_hits": tim_hits, + "trailing_bytes": len(data) - cursor, + } + + +def parse_raw_blob_wdl(data: bytes) -> dict[str, object]: + tim_hits = scan_tims(data) + regions: list[dict[str, int | str]] = [ + { + "name": "raw_blob", + "offset": 0, + "size": len(data), + } + ] + annotate_region_tim_counts(regions, tim_hits) + return { + "kind": "raw_blob", + "regions": regions, + "tim_hits": tim_hits, + } + + +def summarize(path: Path, summary: dict[str, object]) -> str: + lines = [f"file: {path}", f"kind: {summary['kind']}"] + if summary["kind"] == "lset": + lines.append(f"header_size: 0x{summary['header_size']:X}") + lines.append(f"audio_size: 0x{summary['audio_size']:X}") + lines.append(f"post_audio_start: 0x{summary['post_audio_start']:X}") + lines.append( + "high_offset_boundaries: " + + ", ".join(f"0x{value:X}" for value in summary["high_offset_boundaries"]) + ) + elif summary["kind"] == "contiguous_sections": + lines.append(f"header_size: 0x{summary['header_size']:X}") + lines.append(f"trailing_bytes: 0x{summary['trailing_bytes']:X}") + + lines.append("regions:") + for region in summary["regions"]: + tim_count = region.get("tim_count", 0) + lines.append( + " " + + f"{region['name']}: offset=0x{region['offset']:X} size=0x{region['size']:X} tims={tim_count}" + ) + + lines.append("tim_hits:") + for hit in summary["tim_hits"]: + lines.append( + " " + + f"offset=0x{hit['offset']:X} size=0x{hit['size']:X} flags=0x{hit['flags']:X}" + ) + + if len(summary["tim_hits"]) == 0: + lines.append(" none") + + sprite_bundles = summary.get("sprite_bundles", []) + lines.append(f"sprite_bundles: {len(sprite_bundles)}") + for bundle in sprite_bundles[:6]: + lines.append( + " " + + f"offset=0x{bundle['offset']:X} mode={bundle['mode']} frames={bundle['frame_count']} data_offset=0x{bundle['data_offset']:X}" + ) + return "\n".join(lines) + + +def extract(path: Path, output_dir: Path) -> dict[str, object]: + data = path.read_bytes() + summary = parse_lset_wdl(data) + if summary is None: + summary = parse_contiguous_section_wdl(data) + if summary is None: + summary = parse_raw_blob_wdl(data) + + target_dir = output_dir / path.stem + target_dir.mkdir(parents=True, exist_ok=True) + + # The runtime loads the first 0x3520 bytes of each LSET/WDL directly into VRAM + # as a 0x88 x 0x32 halfword image block before reading later stream sections. + if len(data) >= 0x3520: + write_psx_16bpp_png(target_dir / "front_vram_page_16bpp.png", data[:0x3520], 0x88, 0x32) + + for region in summary["regions"]: + start = region["offset"] + end = start + region["size"] + if end <= start: + continue + filename = f"{region['name']}_{start:08X}.bin" + region_path = target_dir / filename + region_bytes = data[start:end] + write_blob(region_path, region_bytes) + if summary["kind"] == "lset" and region["name"] == "post_audio_region_00": + write_u16x6_csv(target_dir / f"{region['name']}_{start:08X}_u16x6.csv", region_bytes) + write_u16x12_csv(target_dir / f"{region['name']}_{start:08X}_u16x12.csv", region_bytes) + write_u32x5_csv(target_dir / f"{region['name']}_{start:08X}_u32x5.csv", region_bytes) + write_lset_stream_probe_json(target_dir / f"{region['name']}_{start:08X}_stream_probe.json", region_bytes) + if summary["kind"] == "lset" and region["name"] == "post_audio_region_01": + write_u16x6_csv(target_dir / f"{region['name']}_{start:08X}_u16x6.csv", region_bytes) + write_u16x12_csv(target_dir / f"{region['name']}_{start:08X}_u16x12.csv", region_bytes) + write_paired_u16x6_json(target_dir / f"{region['name']}_{start:08X}_paired_u16x6.json", region_bytes) + if summary["kind"] == "lset" and region["name"] == "post_audio_region_02": + write_u16x12_csv(target_dir / f"{region['name']}_{start:08X}_u16x12.csv", region_bytes) + if summary["kind"] == "lset" and region["name"] == "post_audio_region_03": + write_u16x12_csv(target_dir / f"{region['name']}_{start:08X}_u16x12.csv", region_bytes) + palettes = extract_palette_sets(data, summary) + palettes_256 = extract_palette_blocks_256(data, summary) + sprite_bundles: list[dict[str, object]] = [] + if summary["kind"] == "lset": + graphics_region = next( + (region for region in summary["regions"] if region["name"] == "post_audio_region_04"), + None, + ) + if graphics_region is not None: + region_data = data[graphics_region["offset"] : graphics_region["offset"] + graphics_region["size"]] + for bundle in scan_sprite_bundles(region_data, max_candidates=160): + exported = export_sprite_bundle(bundle, target_dir / "sprite_bundles") + color_metadata = export_colored_sprite_bundle( + bundle, + target_dir / "sprite_bundles", + palettes, + palettes_256, + ) + exported["offset"] += graphics_region["offset"] + if color_metadata is not None: + exported["color_palette"] = color_metadata + sprite_bundles.append(exported) + + if sprite_bundles: + sprite_bundles.sort( + key=lambda bundle: ( + bundle["exported_frames"][0]["width"] * bundle["exported_frames"][0]["height"] + if bundle["exported_frames"] + else 0, + bundle["frame_count"], + ), + reverse=True, + ) + summary["sprite_bundles"] = sprite_bundles + + overview_entries_gray: list[dict[str, object]] = [] + overview_entries_color: list[dict[str, object]] = [] + overview_entries_color_flip: list[dict[str, object]] = [] + for bundle in sprite_bundles[:48]: + bundle_dir = target_dir / "sprite_bundles" / f"bundle_{bundle['offset'] - graphics_region['offset']:08X}" + if bundle["exported_frames"]: + frame = bundle["exported_frames"][0] + gray_png = bundle_dir / "frame_000.png" + color_png = bundle_dir / "frame_000_color.png" + raw_gray = decode_indexed_pixels( + (bundle_dir / "frame_000.bin").read_bytes(), + frame["width"], + frame["height"], + bundle["mode"], + ) + rgba_gray = bytearray() + for value in raw_gray: + rgba_gray.extend((value, value, value, 255 if value != 0 else 0)) + overview_entries_gray.append( + {"width": frame["width"], "height": frame["height"], "rgba": bytes(rgba_gray)} + ) + if color_png.exists(): + # Rebuild from the already-exported color png source data is unnecessary here; + # instead reuse the colorized frame by regenerating it from the saved metadata path. + palette_json = bundle.get("color_palette") + if palette_json is not None: + palette_index = palette_json["palette_index"] + if bundle["mode"] == 1: + if palette_index >= len(palettes_256): + continue + palette = palettes_256[palette_index] + else: + if palette_index >= len(palettes): + continue + palette = palettes[palette_index] + raw_frame = (bundle_dir / "frame_000.bin").read_bytes() + rgba_color = colorize_indexed_pixels( + raw_frame, + frame["width"], + frame["height"], + bundle["mode"], + palette, + ) + overview_entries_color.append( + {"width": frame["width"], "height": frame["height"], "rgba": rgba_color} + ) + if bundle["mode"] == 2: + rgba_color_flip = colorize_indexed_pixels( + raw_frame, + frame["width"], + frame["height"], + bundle["mode"], + palette, + high_nibble_first=True, + ) + overview_entries_color_flip.append( + {"width": frame["width"], "height": frame["height"], "rgba": rgba_color_flip} + ) + + if overview_entries_gray: + write_overview_grid(target_dir / "sprite_bundles" / "overview_gray.png", overview_entries_gray) + if overview_entries_color: + write_overview_grid(target_dir / "sprite_bundles" / "overview_color.png", overview_entries_color) + if overview_entries_color_flip: + write_overview_grid(target_dir / "sprite_bundles" / "overview_color_flip.png", overview_entries_color_flip) + + metadata_path = target_dir / "summary.json" + metadata_path.write_text(json.dumps(summary, indent=2), encoding="ascii") + + tim_dir = target_dir / "tims" + for index, hit in enumerate(summary["tim_hits"]): + start = hit["offset"] + end = start + hit["size"] + write_blob(tim_dir / f"tim_{index:03d}_{start:08X}.tim", data[start:end]) + + return summary + + +def main() -> int: + parser = argparse.ArgumentParser(description="Inspect and carve Crusader PSX WDL files.") + parser.add_argument("input", type=Path, help="Path to a .WDL file") + parser.add_argument( + "--output", + type=Path, + default=Path("out") / "psx_wdl", + help="Directory where carved blocks and metadata are written", + ) + args = parser.parse_args() + + summary = extract(args.input, args.output) + print(summarize(args.input, summary)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) \ No newline at end of file