| ofs | hex dump | ascii |
|---|
| 0000 | 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 | MZ......................@....... |
| 0020 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 | ................................ |
| 0040 | 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f | ........!..L.!This.program.canno |
| 0060 | 74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 | t.be.run.in.DOS.mode....$....... |
| 0080 | 50 45 00 00 4c 01 03 00 10 42 07 58 00 00 00 00 00 00 00 00 e0 00 02 21 0b 01 08 00 00 a6 00 00 | PE..L....B.X...........!........ |
| 00a0 | 00 08 00 00 00 00 00 00 ce c4 00 00 00 20 00 00 00 00 00 00 00 00 40 00 00 20 00 00 00 02 00 00 | ......................@......... |
| 00c0 | 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 20 01 00 00 02 00 00 5e d4 00 00 03 00 40 85 | ........................^.....@. |
| 00e0 | 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 | ................................ |
| 0100 | 7c c4 00 00 4f 00 00 00 00 e0 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |...O........................... |
| 0120 | 00 00 01 00 0c 00 00 00 10 c4 00 00 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................................ |
| 0140 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 08 00 00 00 | ................................ |
| 0160 | 00 00 00 00 00 00 00 00 08 20 00 00 48 00 00 00 00 00 00 00 00 00 00 00 2e 74 65 78 74 00 00 00 | ............H............text... |
| 0180 | d4 a4 00 00 00 20 00 00 00 a6 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 60 | ...............................` |
| 01a0 | 2e 72 73 72 63 00 00 00 00 06 00 00 00 e0 00 00 00 06 00 00 00 a8 00 00 00 00 00 00 00 00 00 00 | .rsrc........................... |
| 01c0 | 00 00 00 00 40 00 00 40 2e 72 65 6c 6f 63 00 00 0c 00 00 00 00 00 01 00 00 02 00 00 00 ae 00 00 | ....@..@.reloc.................. |
| 01e0 | 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ............@..B................ |
| 0200 | b0 c4 00 00 00 00 00 00 48 00 00 00 02 00 05 00 20 67 00 00 f0 5c 00 00 09 00 00 00 00 00 00 00 | ........H........g...\.......... |
| 0220 | 00 00 00 00 00 00 00 00 a0 66 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | .........f...................... |
| 0240 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 30 01 00 0f 00 00 00 01 00 00 11 02 28 0a 00 | .................0...........(.. |
| 0260 | 00 06 0a 12 00 28 01 00 00 0a 2a 00 22 02 03 28 02 00 00 0a 2a 00 00 00 5a 02 7e 03 00 00 0a 28 | .....(....*."..(....*...Z.~....( |
| 0280 | 04 00 00 0a 2d 07 02 73 02 00 00 06 2a 14 2a 00 13 30 02 00 0a 00 00 00 02 00 00 11 02 12 00 28 | ....-..s....*.*..0.............( |
| 02a0 | 0b 00 00 06 06 2a 00 00 22 02 03 28 0c 00 00 06 2a 00 00 00 13 30 06 00 32 00 00 00 01 00 00 11 | .....*.."..(....*....0..2....... |
| 02c0 | 02 7b 05 00 00 0a 03 28 06 00 00 0a 04 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b 5a 58 4d 29 | .{.....(......{....M........ZXM) |
| 02e0 | 03 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 13 30 05 00 31 00 00 00 01 00 00 11 | ....(.......(....*...0..1....... |
| 0300 | 02 7b 05 00 00 0a 03 28 06 00 00 0a 02 7b 05 00 00 0a 4d 1a d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 | .{.....(.....{....M........ZXM). |
| 0320 | 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 04 00 2b 00 00 00 01 00 00 11 | ...(.......(....*....0..+....... |
| 0340 | 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 | .{.....{....M........ZXM)....(.. |
| 0360 | 00 0a 0a 12 00 28 08 00 00 0a 2a 00 13 30 04 00 2b 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b | .....(....*..0..+........{.....{ |
| 0380 | 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 | ....M........ZXM)....(.......(.. |
| 03a0 | 00 0a 2a 00 13 30 04 00 25 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1d d3 fe | ..*..0..%........{.....{....M... |
| 03c0 | 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a 06 2a 00 00 00 13 30 05 00 32 00 00 00 | .....ZXM)....(......*....0..2... |
| 03e0 | 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1e d3 fe 1c 01 00 00 1b 5a 58 4d | .......{.......{....M........ZXM |
| 0400 | 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 13 30 05 00 2d 00 00 00 | )....(..........(....*...0..-... |
| 0420 | 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 0a 4d 1f 09 d3 fe 1c 01 00 00 1b 5a 58 4d 29 07 | .....{......{....M.........ZXM). |
| 0440 | 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 8a 02 28 09 00 00 0a 7e 01 00 00 04 | ...(.......(....*.....(....~.... |
| 0460 | 17 d0 02 00 00 02 28 0a 00 00 0a 28 0b 00 00 0a 02 28 0c 00 00 0a 2a 00 42 72 01 00 00 70 73 0d | ......(....(.....(....*.Br...ps. |
| 0480 | 00 00 0a 80 01 00 00 04 2a 00 00 00 3e 02 28 09 00 00 0a 03 04 02 6f e8 00 00 06 2a 13 30 01 00 | ........*...>.(.......o....*.0.. |
| 04a0 | 0f 00 00 00 01 00 00 11 02 28 18 00 00 06 0a 12 00 28 01 00 00 0a 2a 00 22 02 03 28 02 00 00 0a | .........(.......(....*."..(.... |
| 04c0 | 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a 2d 07 02 73 11 00 00 06 2a 14 2a 00 22 02 03 28 | *...Z.~....(....-..s....*.*."..( |
| 04e0 | 16 00 00 06 2a 00 00 00 22 02 03 28 17 00 00 06 2a 00 00 00 13 30 02 00 0a 00 00 00 02 00 00 11 | ....*..."..(....*....0.......... |
| 0500 | 02 12 00 28 19 00 00 06 06 2a 00 00 13 30 05 00 2c 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 | ...(.....*...0..,........{...... |
| 0520 | 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 | {....M........ZXM)....(.......(. |
| 0540 | 00 00 0a 2a 13 30 05 00 2c 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 0a 4d 1a d3 | ...*.0..,........{......{....M.. |
| 0560 | fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 13 30 04 00 | ......ZXM)....(.......(....*.0.. |
| 0580 | 25 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d | %........{.....{....M........ZXM |
| 05a0 | 29 05 00 00 11 28 07 00 00 0a 0a 06 2a 00 00 00 13 30 05 00 32 00 00 00 06 00 00 11 03 0b 02 7b | )....(......*....0..2..........{ |
| 05c0 | 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 | .......{....M........ZXM)....(.. |
| 05e0 | 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 8a 02 28 09 00 00 0a 7e 02 00 00 04 17 d0 04 00 | ........(....*....(....~........ |
| 0600 | 00 02 28 0a 00 00 0a 28 0b 00 00 0a 02 28 0c 00 00 0a 2a 00 22 02 03 28 02 00 00 0a 2a 00 00 00 | ..(....(.....(....*."..(....*... |
| 0620 | 5a 02 7e 03 00 00 0a 28 04 00 00 0a 2d 07 02 73 1b 00 00 06 2a 14 2a 00 13 30 06 00 4d 00 00 00 | Z.~....(....-..s....*.*..0..M... |
| 0640 | 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 12 01 e0 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 | ....~......{.........{....M..... |
| 0660 | 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 | ...ZXM)....(......~....(....-..s |
| 0680 | 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 00 00 00 13 30 06 00 4d 00 00 00 09 00 00 11 | ....+.....(.....*....0..M....... |
| 06a0 | 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 12 01 e0 02 7b 05 00 00 0a 4d 1a d3 fe 1c 01 00 00 1b 5a | ~......{.........{....M........Z |
| 06c0 | 58 4d 29 0a 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 00 00 06 | XM)....(......~....(....-..s.... |
| 06e0 | 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 00 00 00 13 30 08 00 4f 00 00 00 09 00 00 11 7e 03 00 00 | +.....(.....*....0..O.......~... |
| 0700 | 0a 0b 02 7b 05 00 00 0a 03 04 05 12 01 e0 02 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d | ...{...........{....M........ZXM |
| 0720 | 29 0b 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 | )....(......~....(....-..s....+. |
| 0740 | 14 0a 12 02 28 08 00 00 0a 06 2a 00 13 30 07 00 4e 00 00 00 09 00 00 11 7e 03 00 00 0a 0b 02 7b | ....(.....*..0..N.......~......{ |
| 0760 | 05 00 00 0a 03 04 12 01 e0 02 7b 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 0c 00 00 11 | ..........{....M........ZXM).... |
| 0780 | 28 07 00 00 0a 0c 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 14 0a 12 02 28 | (......~....(....-..s....+.....( |
| 07a0 | 08 00 00 0a 06 2a 00 00 13 30 07 00 4e 00 00 00 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a | .....*...0..N.......~......{.... |
| 07c0 | 03 04 12 01 e0 02 7b 05 00 00 0a 4d 1d d3 fe 1c 01 00 00 1b 5a 58 4d 29 0c 00 00 11 28 07 00 00 | ......{....M........ZXM)....(... |
| 07e0 | 0a 0c 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a | ...~....(....-..s....+.....(.... |
| 0800 | 06 2a 00 00 13 30 07 00 4e 00 00 00 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 04 12 01 | .*...0..N.......~......{........ |
| 0820 | e0 02 7b 05 00 00 0a 4d 1e d3 fe 1c 01 00 00 1b 5a 58 4d 29 0c 00 00 11 28 07 00 00 0a 0c 07 7e | ..{....M........ZXM)....(......~ |
| 0840 | 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 00 00 | ....(....-..s....+.....(.....*.. |
| 0860 | 13 30 0a 00 54 00 00 00 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 04 05 0e 04 0e 05 12 | .0..T.......~......{............ |
| 0880 | 01 e0 02 7b 05 00 00 0a 4d 1f 09 d3 fe 1c 01 00 00 1b 5a 58 4d 29 0d 00 00 11 28 07 00 00 0a 0c | ...{....M.........ZXM)....(..... |
| 08a0 | 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a | .~....(....-..s....+.....(.....* |
| 08c0 | 13 30 09 00 52 00 00 00 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 04 05 0e 04 12 01 e0 | .0..R.......~......{............ |
| 08e0 | 02 7b 05 00 00 0a 4d 1f 0a d3 fe 1c 01 00 00 1b 5a 58 4d 29 0e 00 00 11 28 07 00 00 0a 0c 07 7e | .{....M.........ZXM)....(......~ |
| 0900 | 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 00 00 | ....(....-..s....+.....(.....*.. |
| 0920 | 13 30 06 00 4e 00 00 00 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 12 01 e0 02 7b 05 00 | .0..N.......~......{.........{.. |
| 0940 | 00 0a 4d 1f 0b d3 fe 1c 01 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 00 0a | ..M.........ZXM)....(......~.... |
| 0960 | 28 04 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 00 00 13 30 08 00 | (....-..s....+.....(.....*...0.. |
| 0980 | 50 00 00 00 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 04 05 12 01 e0 02 7b 05 00 00 0a | P.......~......{...........{.... |
| 09a0 | 4d 1f 0c d3 fe 1c 01 00 00 1b 5a 58 4d 29 0b 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 00 0a 28 04 | M.........ZXM)....(......~....(. |
| 09c0 | 00 00 0a 2d 08 07 73 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 13 30 07 00 4f 00 00 00 | ...-..s....+.....(.....*.0..O... |
| 09e0 | 09 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 04 12 01 e0 02 7b 05 00 00 0a 4d 1f 0d d3 fe | ....~......{..........{....M.... |
| 0a00 | 1c 01 00 00 1b 5a 58 4d 29 0c 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 | .....ZXM)....(......~....(....-. |
| 0a20 | 07 73 11 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 00 13 30 08 00 50 00 00 00 09 00 00 11 | .s....+.....(.....*..0..P....... |
| 0a40 | 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 04 05 12 01 e0 02 7b 05 00 00 0a 4d 1f 0e d3 fe 1c 01 00 | ~......{...........{....M....... |
| 0a60 | 00 1b 5a 58 4d 29 0b 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 00 0a 28 04 00 00 0a 2d 08 07 73 11 | ..ZXM)....(......~....(....-..s. |
| 0a80 | 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 42 72 4b 00 00 70 73 0d 00 00 0a 80 02 00 00 04 | ...+.....(.....*BrK..ps......... |
| 0aa0 | 2a 00 00 00 22 02 03 7d 04 00 00 04 2a 00 00 00 46 15 73 0f 00 00 0a 73 2a 00 00 06 80 03 00 00 | *..."..}....*...F.s....s*....... |
| 0ac0 | 04 2a 00 00 1e 02 28 01 00 00 2b 2a 1a 7e 05 00 00 04 2a 00 1e 02 7b 07 00 00 04 2a 22 02 03 7d | .*....(...+*.~....*...{....*"..} |
| 0ae0 | 07 00 00 04 2a 00 00 00 66 02 7b 06 00 00 04 2c 0f 02 7b 06 00 00 04 03 04 05 6f 7c 00 00 06 2a | ....*...f.{....,..{.......o|...* |
| 0b00 | 16 2a 00 00 96 03 2c 1a 02 28 2e 00 00 06 2c 12 02 28 2e 00 00 06 6f 12 00 00 0a 02 14 28 2f 00 | .*....,..(....,..(....o......(/. |
| 0b20 | 00 06 02 03 28 13 00 00 0a 2a 00 00 1e 02 28 14 00 00 0a 2a 2e 73 34 00 00 06 80 05 00 00 04 2a | ....(....*....(....*.s4........* |
| 0b40 | 6a 02 17 28 15 00 00 0a 02 14 fe 06 35 00 00 06 73 36 00 00 06 28 16 00 00 0a 2a 00 1b 30 04 00 | j..(........5...s6...(....*..0.. |
| 0b60 | 43 00 00 00 0f 00 00 11 02 28 02 00 00 2b 0a 06 6f 18 00 00 0a 74 1f 00 00 02 0b 07 03 04 05 6f | C........(...+..o....t.........o |
| 0b80 | a2 00 00 06 2d 07 7e 19 00 00 0a 2b 05 7e 1a 00 00 0a 0c de 14 0d 09 28 1b 00 00 0a 28 1c 00 00 | ....-.~....+.~.........(....(... |
| 0ba0 | 0a 28 07 00 00 0a 0c de 00 08 2a 00 01 10 00 00 00 00 00 00 2d 2d 00 14 14 00 00 01 22 02 03 28 | .(........*.........--......"..( |
| 0bc0 | 02 00 00 0a 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a 2d 07 02 73 3a 00 00 06 2a 14 2a 00 | ....*...Z.~....(....-..s:...*.*. |
| 0be0 | 13 30 02 00 0a 00 00 00 02 00 00 11 02 12 00 28 41 00 00 06 06 2a 00 00 22 02 03 28 40 00 00 06 | .0.............(A....*.."..(@... |
| 0c00 | 2a 00 00 00 13 30 02 00 0a 00 00 00 02 00 00 11 02 12 00 28 42 00 00 06 06 2a 00 00 13 30 06 00 | *....0.............(B....*...0.. |
| 0c20 | 2d 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 04 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b 5a | -........{.......{....M........Z |
| 0c40 | 58 4d 29 10 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 05 00 2c 00 00 00 | XM)....(.......(....*....0..,... |
| 0c60 | 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 0a 4d 1a d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 | .....{......{....M........ZXM).. |
| 0c80 | 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 13 30 05 00 32 00 00 00 06 00 00 11 03 0b 02 7b | ..(.......(....*.0..2..........{ |
| 0ca0 | 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 | .......{....M........ZXM)....(.. |
| 0cc0 | 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 13 30 05 00 32 00 00 00 06 00 00 11 03 0b 02 7b | ........(....*...0..2..........{ |
| 0ce0 | 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 | .......{....M........ZXM)....(.. |
| 0d00 | 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 13 30 06 00 30 00 00 00 11 00 00 11 02 7b 05 00 | ........(....*...0..0........{.. |
| 0d20 | 00 0a 03 12 00 e0 02 7b 05 00 00 0a 4d 1d d3 fe 1c 01 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 | .......{....M........ZXM)....(.. |
| 0d40 | 00 0a 0b 12 01 28 08 00 00 0a 06 2a 13 30 06 00 30 00 00 00 11 00 00 11 02 7b 05 00 00 0a 03 12 | .....(.....*.0..0........{...... |
| 0d60 | 00 e0 02 7b 05 00 00 0a 4d 1e d3 fe 1c 01 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 00 0a 0b 12 | ...{....M........ZXM)....(...... |
| 0d80 | 01 28 08 00 00 0a 06 2a 13 30 07 00 41 00 00 00 12 00 00 11 03 0b 04 0c 05 0d 02 7b 05 00 00 0a | .(.....*.0..A..............{.... |
| 0da0 | 07 d3 08 d3 09 d3 02 7b 05 00 00 0a 4d 1f 09 d3 fe 1c 01 00 00 1b 5a 58 4d 29 13 00 00 11 28 07 | .......{....M.........ZXM)....(. |
| 0dc0 | 00 00 0a 0a 16 e0 0d 16 e0 0c 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 00 22 02 03 28 02 00 00 0a | ...............(....*..."..(.... |
| 0de0 | 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a 2d 07 02 73 46 00 00 06 2a 14 2a 00 13 30 02 00 | *...Z.~....(....-..sF...*.*..0.. |
| 0e00 | 0a 00 00 00 14 00 00 11 02 12 00 28 4b 00 00 06 06 2a 00 00 13 30 02 00 0a 00 00 00 02 00 00 11 | ...........(K....*...0.......... |
| 0e20 | 02 12 00 28 4e 00 00 06 06 2a 00 00 22 02 03 28 4d 00 00 06 2a 00 00 00 13 30 05 00 32 00 00 00 | ...(N....*.."..(M...*....0..2... |
| 0e40 | 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b 5a 58 4d | .......{.......{....M........ZXM |
| 0e60 | 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 13 30 07 00 67 00 00 00 | )....(..........(....*...0..g... |
| 0e80 | 15 00 00 11 03 25 0c 2c 05 08 8e 69 2d 05 16 e0 0b 2b 08 08 16 8f 1c 00 00 01 0b 04 25 13 04 2c | .....%.,...i-....+..........%.., |
| 0ea0 | 06 11 04 8e 69 2d 05 16 e0 0d 2b 09 11 04 16 8f 1c 00 00 01 0d 02 7b 05 00 00 0a 07 d3 09 d3 05 | ....i-....+...........{......... |
| 0ec0 | 02 7b 05 00 00 0a 4d 1a d3 fe 1c 01 00 00 1b 5a 58 4d 29 16 00 00 11 28 07 00 00 0a 0a 16 e0 0d | .{....M........ZXM)....(........ |
| 0ee0 | 16 e0 0b 12 00 28 08 00 00 0a 2a 00 13 30 05 00 2c 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 | .....(....*..0..,........{...... |
| 0f00 | 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 | {....M........ZXM)....(.......(. |
| 0f20 | 00 00 0a 2a 13 30 05 00 32 00 00 00 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a | ...*.0..2..........{.......{.... |
| 0f40 | 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 | M........ZXM)....(..........(... |
| 0f60 | 0a 2a 00 00 13 30 06 00 48 00 00 00 17 00 00 11 03 25 0c 2c 05 08 8e 69 2d 05 16 e0 0b 2b 08 08 | .*...0..H........%.,...i-....+.. |
| 0f80 | 16 8f 1c 00 00 01 0b 02 7b 05 00 00 0a 07 d3 04 02 7b 05 00 00 0a 4d 1d d3 fe 1c 01 00 00 1b 5a | ........{........{....M........Z |
| 0fa0 | 58 4d 29 03 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 13 30 07 00 49 00 00 00 | XM)....(..........(....*.0..I... |
| 0fc0 | 17 00 00 11 04 25 0c 2c 05 08 8e 69 2d 05 16 e0 0b 2b 08 08 16 8f 1c 00 00 01 0b 02 7b 05 00 00 | .....%.,...i-....+..........{... |
| 0fe0 | 0a 03 07 d3 05 02 7b 05 00 00 0a 4d 1e d3 fe 1c 01 00 00 1b 5a 58 4d 29 18 00 00 11 28 07 00 00 | ......{....M........ZXM)....(... |
| 1000 | 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 00 13 30 07 00 4a 00 00 00 17 00 00 11 04 25 0c 2c | .......(....*....0..J........%., |
| 1020 | 05 08 8e 69 2d 05 16 e0 0b 2b 08 08 16 8f 1c 00 00 01 0b 02 7b 05 00 00 0a 03 07 d3 05 02 7b 05 | ...i-....+..........{.........{. |
| 1040 | 00 00 0a 4d 1f 09 d3 fe 1c 01 00 00 1b 5a 58 4d 29 18 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 | ...M.........ZXM)....(.......... |
| 1060 | 28 08 00 00 0a 2a 00 00 13 30 06 00 42 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f | (....*...0..B........{.....,..o. |
| 1080 | 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 04 02 7b 05 00 00 0a 4d 1f 0a d3 fe 1c 01 00 00 1b | ...+.~....(......{....M......... |
| 10a0 | 5a 58 4d 29 03 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 13 30 07 00 41 00 00 00 | ZXM)....(.......(....*...0..A... |
| 10c0 | 12 00 00 11 03 0b 04 0c 05 0d 02 7b 05 00 00 0a 07 d3 08 d3 09 d3 02 7b 05 00 00 0a 4d 1f 0b d3 | ...........{...........{....M... |
| 10e0 | fe 1c 01 00 00 1b 5a 58 4d 29 13 00 00 11 28 07 00 00 0a 0a 16 e0 0d 16 e0 0c 16 e0 0b 12 00 28 | ......ZXM)....(................( |
| 1100 | 08 00 00 0a 2a 00 00 00 22 02 03 28 02 00 00 0a 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a | ....*..."..(....*...Z.~....(.... |
| 1120 | 2d 07 02 73 54 00 00 06 2a 14 2a 00 13 30 02 00 0a 00 00 00 19 00 00 11 02 12 00 28 61 00 00 06 | -..sT...*.*..0.............(a... |
| 1140 | 06 2a 00 00 22 02 03 28 62 00 00 06 2a 00 00 00 22 02 03 28 6a 00 00 06 2a 00 00 00 13 30 06 00 | .*.."..(b...*..."..(j...*....0.. |
| 1160 | 3c 00 00 00 1a 00 00 11 7e 03 00 00 0a 0a 02 7b 05 00 00 0a 03 12 00 e0 02 7b 05 00 00 0a 4d 19 | <.......~......{.........{....M. |
| 1180 | d3 fe 1c 01 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 00 0a 0b 04 06 6f 20 00 00 0a 12 01 28 08 | .......ZXM)....(.......o......(. |
| 11a0 | 00 00 0a 2a 13 30 07 00 56 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b | ...*.0..V........{.....,..o....+ |
| 11c0 | 05 7e 03 00 00 0a 28 06 00 00 0a 04 2c 08 04 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a | .~....(.....,..o....+.~....(.... |
| 11e0 | 05 02 7b 05 00 00 0a 4d 1a d3 fe 1c 01 00 00 1b 5a 58 4d 29 1b 00 00 11 28 07 00 00 0a 0a 12 00 | ..{....M........ZXM)....(....... |
| 1200 | 28 08 00 00 0a 2a 00 00 13 30 05 00 3b 00 00 00 1a 00 00 11 7e 03 00 00 0a 0a 02 7b 05 00 00 0a | (....*...0..;.......~......{.... |
| 1220 | 12 00 e0 02 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0b | ....{....M........ZXM)....(..... |
| 1240 | 03 06 6f 20 00 00 0a 12 01 28 08 00 00 0a 2a 00 13 30 05 00 2c 00 00 00 01 00 00 11 02 7b 05 00 | ..o......(....*..0..,........{.. |
| 1260 | 00 0a 03 02 7b 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a | ....{....M........ZXM)....(..... |
| 1280 | 12 00 28 08 00 00 0a 2a 13 30 04 00 2b 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a | ..(....*.0..+........{.....{.... |
| 12a0 | 4d 1d d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 | M........ZXM)....(.......(....*. |
| 12c0 | 13 30 06 00 30 00 00 00 1c 00 00 11 02 7b 05 00 00 0a 03 12 00 e0 02 7b 05 00 00 0a 4d 1e d3 fe | .0..0........{.........{....M... |
| 12e0 | 1c 01 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 00 0a 0b 12 01 28 08 00 00 0a 06 2a 13 30 07 00 | .....ZXM)....(.......(.....*.0.. |
| 1300 | 54 00 00 00 1d 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 28 06 00 00 0a 04 12 01 e0 02 7b | T.......~......{.....(.........{ |
| 1320 | 05 00 00 0a 4d 1f 09 d3 fe 1c 01 00 00 1b 5a 58 4d 29 1e 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 | ....M.........ZXM)....(......~.. |
| 1340 | 00 0a 28 04 00 00 0a 2d 08 07 73 03 01 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 13 30 07 00 | ..(....-..s....+.....(.....*.0.. |
| 1360 | 54 00 00 00 1f 00 00 11 7e 03 00 00 0a 0b 02 7b 05 00 00 0a 03 28 06 00 00 0a 04 12 01 e0 02 7b | T.......~......{.....(.........{ |
| 1380 | 05 00 00 0a 4d 1f 0a d3 fe 1c 01 00 00 1b 5a 58 4d 29 1e 00 00 11 28 07 00 00 0a 0c 07 7e 03 00 | ....M.........ZXM)....(......~.. |
| 13a0 | 00 0a 28 04 00 00 0a 2d 08 07 73 a6 00 00 06 2b 01 14 0a 12 02 28 08 00 00 0a 06 2a 13 30 05 00 | ..(....-..s....+.....(.....*.0.. |
| 13c0 | 33 00 00 00 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1f 0b d3 fe 1c 01 00 | 3..........{.......{....M....... |
| 13e0 | 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 13 30 05 00 | ..ZXM)....(..........(....*..0.. |
| 1400 | 2d 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 0a 4d 1f 0c d3 fe 1c 01 00 00 1b 5a | -........{......{....M.........Z |
| 1420 | 58 4d 29 07 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 04 00 2c 00 00 00 | XM)....(.......(....*....0..,... |
| 1440 | 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1f 0d d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 | .....{.....{....M.........ZXM).. |
| 1460 | 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 13 30 04 00 2c 00 00 00 01 00 00 11 02 7b 05 00 | ..(.......(....*.0..,........{.. |
| 1480 | 00 0a 02 7b 05 00 00 0a 4d 1f 0e d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a | ...{....M.........ZXM)....(..... |
| 14a0 | 12 00 28 08 00 00 0a 2a 13 30 05 00 32 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 28 06 00 00 0a | ..(....*.0..2........{.....(.... |
| 14c0 | 02 7b 05 00 00 0a 4d 1f 0f d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 | .{....M.........ZXM)....(....... |
| 14e0 | 28 08 00 00 0a 2a 00 00 13 30 05 00 32 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 28 06 00 00 0a | (....*...0..2........{.....(.... |
| 1500 | 02 7b 05 00 00 0a 4d 1f 10 d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 | .{....M.........ZXM)....(....... |
| 1520 | 28 08 00 00 0a 2a 00 00 13 30 05 00 32 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 28 06 00 00 0a | (....*...0..2........{.....(.... |
| 1540 | 02 7b 05 00 00 0a 4d 1f 11 d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 | .{....M.........ZXM)....(....... |
| 1560 | 28 08 00 00 0a 2a 00 00 13 30 05 00 32 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 28 06 00 00 0a | (....*...0..2........{.....(.... |
| 1580 | 02 7b 05 00 00 0a 4d 1f 12 d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 | .{....M.........ZXM)....(....... |
| 15a0 | 28 08 00 00 0a 2a 00 00 13 30 05 00 32 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 28 06 00 00 0a | (....*...0..2........{.....(.... |
| 15c0 | 02 7b 05 00 00 0a 4d 1f 13 d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 | .{....M.........ZXM)....(....... |
| 15e0 | 28 08 00 00 0a 2a 00 00 13 30 05 00 2d 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 | (....*...0..-........{......{... |
| 1600 | 0a 4d 1f 14 d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a | .M.........ZXM)....(.......(.... |
| 1620 | 2a 00 00 00 13 30 04 00 2c 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1f 15 d3 | *....0..,........{.....{....M... |
| 1640 | fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 8a 02 28 09 | ......ZXM)....(.......(....*..(. |
| 1660 | 00 00 0a 7e 3a 00 00 04 17 d0 18 00 00 02 28 0a 00 00 0a 28 0b 00 00 0a 02 28 0c 00 00 0a 2a 00 | ...~:.........(....(.....(....*. |
| 1680 | 13 30 03 00 41 00 00 00 00 00 00 00 02 7b 3b 00 00 04 2d 1c 02 73 4f 01 00 06 7d 3b 00 00 04 02 | .0..A........{;...-..sO...};.... |
| 16a0 | 02 7b 3b 00 00 04 28 49 01 00 06 28 65 00 00 06 02 7b 3b 00 00 04 25 7b 42 00 00 04 03 28 21 00 | .{;...(I...(e....{;...%{B....(!. |
| 16c0 | 00 0a 74 19 00 00 02 7d 42 00 00 04 2a 00 00 00 13 30 03 00 56 00 00 00 00 00 00 00 02 7b 3b 00 | ..t....}B...*....0..V........{;. |
| 16e0 | 00 04 2d 01 2a 02 7b 3b 00 00 04 25 7b 42 00 00 04 03 28 22 00 00 0a 74 19 00 00 02 7d 42 00 00 | ..-.*.{;...%{B....("...t....}B.. |
| 1700 | 04 02 7b 3b 00 00 04 7b 42 00 00 04 6f 23 00 00 0a 8e 2d 1d 02 7e 03 00 00 0a 28 65 00 00 06 02 | ..{;...{B...o#....-..~....(e.... |
| 1720 | 7b 3b 00 00 04 6f 24 00 00 0a 02 14 7d 3b 00 00 04 2a 00 00 13 30 04 00 61 00 00 00 00 00 00 00 | {;...o$.....};...*...0..a....... |
| 1740 | 03 2c 38 02 7b 3c 00 00 04 2d 23 02 73 32 00 00 06 25 03 7d 06 00 00 04 7d 3c 00 00 04 02 02 7b | .,8.{<...-#.s2...%.}....}<.....{ |
| 1760 | 3c 00 00 04 28 2c 00 00 06 28 66 00 00 06 02 7b 3c 00 00 04 03 7d 06 00 00 04 2a 02 7b 3c 00 00 | <...(,...(f....{<....}....*.{<.. |
| 1780 | 04 2c 1d 02 7e 03 00 00 0a 28 66 00 00 06 02 7b 3c 00 00 04 6f 24 00 00 0a 02 14 7d 3c 00 00 04 | .,..~....(f....{<...o$.....}<... |
| 17a0 | 2a 00 00 00 13 30 04 00 61 00 00 00 00 00 00 00 03 2c 38 02 7b 3d 00 00 04 2d 23 02 73 32 00 00 | *....0..a........,8.{=...-#.s2.. |
| 17c0 | 06 25 03 7d 06 00 00 04 7d 3d 00 00 04 02 02 7b 3d 00 00 04 28 2c 00 00 06 28 67 00 00 06 02 7b | .%.}....}=.....{=...(,...(g....{ |
| 17e0 | 3d 00 00 04 03 7d 06 00 00 04 2a 02 7b 3d 00 00 04 2c 1d 02 7e 03 00 00 0a 28 67 00 00 06 02 7b | =....}....*.{=...,..~....(g....{ |
| 1800 | 3d 00 00 04 6f 24 00 00 0a 02 14 7d 3d 00 00 04 2a 00 00 00 13 30 04 00 61 00 00 00 00 00 00 00 | =...o$.....}=...*....0..a....... |
| 1820 | 03 2c 38 02 7b 3e 00 00 04 2d 23 02 73 32 00 00 06 25 03 7d 06 00 00 04 7d 3e 00 00 04 02 02 7b | .,8.{>...-#.s2...%.}....}>.....{ |
| 1840 | 3e 00 00 04 28 2c 00 00 06 28 68 00 00 06 02 7b 3e 00 00 04 03 7d 06 00 00 04 2a 02 7b 3e 00 00 | >...(,...(h....{>....}....*.{>.. |
| 1860 | 04 2c 1d 02 7e 03 00 00 0a 28 68 00 00 06 02 7b 3e 00 00 04 6f 24 00 00 0a 02 14 7d 3e 00 00 04 | .,..~....(h....{>...o$.....}>... |
| 1880 | 2a 00 00 00 13 30 04 00 61 00 00 00 00 00 00 00 03 2c 38 02 7b 3d 00 00 04 2d 23 02 73 32 00 00 | *....0..a........,8.{=...-#.s2.. |
| 18a0 | 06 25 03 7d 06 00 00 04 7d 3d 00 00 04 02 02 7b 3d 00 00 04 28 2c 00 00 06 28 69 00 00 06 02 7b | .%.}....}=.....{=...(,...(i....{ |
| 18c0 | 3d 00 00 04 03 7d 06 00 00 04 2a 02 7b 3d 00 00 04 2c 1d 02 7e 03 00 00 0a 28 69 00 00 06 02 7b | =....}....*.{=...,..~....(i....{ |
| 18e0 | 3d 00 00 04 6f 24 00 00 0a 02 14 7d 3d 00 00 04 2a 00 00 00 1b 30 03 00 21 00 00 00 20 00 00 11 | =...o$.....}=...*....0..!....... |
| 1900 | 04 28 25 00 00 0a 0a 02 06 28 26 00 00 0a 03 28 5f 00 00 06 0b de 08 12 00 28 27 00 00 0a dc 07 | .(%......(&....(_........('..... |
| 1920 | 2a 00 00 00 01 10 00 00 02 00 07 00 10 17 00 08 00 00 00 00 1b 30 03 00 21 00 00 00 21 00 00 11 | *....................0..!...!... |
| 1940 | 04 28 25 00 00 0a 0a 02 06 28 26 00 00 0a 03 28 60 00 00 06 0b de 08 12 00 28 27 00 00 0a dc 07 | .(%......(&....(`........('..... |
| 1960 | 2a 00 00 00 01 10 00 00 02 00 07 00 10 17 00 08 00 00 00 00 13 30 02 00 c1 00 00 00 00 00 00 00 | *....................0.......... |
| 1980 | 02 7b 3b 00 00 04 2c 1d 02 7e 03 00 00 0a 28 65 00 00 06 02 7b 3b 00 00 04 6f 24 00 00 0a 02 14 | .{;...,..~....(e....{;...o$..... |
| 19a0 | 7d 3b 00 00 04 02 7b 3c 00 00 04 2c 1d 02 7e 03 00 00 0a 28 66 00 00 06 02 7b 3c 00 00 04 6f 24 | };....{<...,..~....(f....{<...o$ |
| 19c0 | 00 00 0a 02 14 7d 3c 00 00 04 02 7b 3d 00 00 04 2c 1d 02 7e 03 00 00 0a 28 69 00 00 06 02 7b 3d | .....}<....{=...,..~....(i....{= |
| 19e0 | 00 00 04 6f 24 00 00 0a 02 14 7d 3d 00 00 04 02 7b 3e 00 00 04 2c 1d 02 7e 03 00 00 0a 28 68 00 | ...o$.....}=....{>...,..~....(h. |
| 1a00 | 00 06 02 7b 3e 00 00 04 6f 24 00 00 0a 02 14 7d 3e 00 00 04 02 7b 3d 00 00 04 2c 1d 02 7e 03 00 | ...{>...o$.....}>....{=...,..~.. |
| 1a20 | 00 0a 28 69 00 00 06 02 7b 3d 00 00 04 6f 24 00 00 0a 02 14 7d 3d 00 00 04 02 03 28 28 00 00 0a | ..(i....{=...o$.....}=.....((... |
| 1a40 | 2a 00 00 00 42 72 95 00 00 70 73 0d 00 00 0a 80 3a 00 00 04 2a 00 00 00 22 02 03 28 02 00 00 0a | *...Br...ps.....:...*..."..(.... |
| 1a60 | 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a 2d 07 02 73 7f 00 00 06 2a 14 2a 00 13 30 02 00 | *...Z.~....(....-..s....*.*..0.. |
| 1a80 | 0a 00 00 00 19 00 00 11 02 12 00 28 92 00 00 06 06 2a 00 00 22 02 03 28 93 00 00 06 2a 00 00 00 | ...........(.....*.."..(....*... |
| 1aa0 | 22 02 03 28 97 00 00 06 2a 00 00 00 22 02 03 28 98 00 00 06 2a 00 00 00 22 02 03 28 99 00 00 06 | "..(....*..."..(....*..."..(.... |
| 1ac0 | 2a 00 00 00 22 02 03 28 9a 00 00 06 2a 00 00 00 22 02 03 28 9b 00 00 06 2a 00 00 00 13 30 07 00 | *..."..(....*..."..(....*....0.. |
| 1ae0 | 69 00 00 00 22 00 00 11 7e 03 00 00 0a 0a 03 25 0d 2c 05 09 8e 69 2d 05 16 e0 0c 2b 08 09 16 8f | i..."...~......%.,...i-....+.... |
| 1b00 | 1c 00 00 01 0c 02 7b 05 00 00 0a 08 d3 04 12 00 e0 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b | ......{...........{....M........ |
| 1b20 | 5a 58 4d 29 1e 00 00 11 28 07 00 00 0a 0b 16 e0 0c 05 06 7e 03 00 00 0a 28 04 00 00 0a 2d 08 06 | ZXM)....(..........~....(....-.. |
| 1b40 | 73 20 01 00 06 2b 01 14 51 12 01 28 08 00 00 0a 2a 00 00 00 13 30 06 00 4d 00 00 00 1a 00 00 11 | s....+..Q..(....*....0..M....... |
| 1b60 | 7e 03 00 00 0a 0a 02 7b 05 00 00 0a 03 12 00 e0 02 7b 05 00 00 0a 4d 1a d3 fe 1c 01 00 00 1b 5a | ~......{.........{....M........Z |
| 1b80 | 58 4d 29 0a 00 00 11 28 07 00 00 0a 0b 04 06 7e 03 00 00 0a 28 04 00 00 0a 2d 08 06 73 20 01 00 | XM)....(.......~....(....-..s... |
| 1ba0 | 06 2b 01 14 51 12 01 28 08 00 00 0a 2a 00 00 00 13 30 07 00 56 00 00 00 01 00 00 11 02 7b 05 00 | .+..Q..(....*....0..V........{.. |
| 1bc0 | 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 04 2c 08 04 6f 1f 00 00 0a | ...,..o....+.~....(.....,..o.... |
| 1be0 | 2b 05 7e 03 00 00 0a 28 06 00 00 0a 05 02 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d 29 | +.~....(......{....M........ZXM) |
| 1c00 | 1b 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 13 30 05 00 4c 00 00 00 1a 00 00 11 | ....(.......(....*...0..L....... |
| 1c20 | 7e 03 00 00 0a 0a 02 7b 05 00 00 0a 12 00 e0 02 7b 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 | ~......{........{....M........ZX |
| 1c40 | 4d 29 04 00 00 11 28 07 00 00 0a 0b 03 06 7e 03 00 00 0a 28 04 00 00 0a 2d 08 06 73 c0 00 00 06 | M)....(.......~....(....-..s.... |
| 1c60 | 2b 01 14 51 12 01 28 08 00 00 0a 2a 13 30 05 00 2c 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 | +..Q..(....*.0..,........{...... |
| 1c80 | 7b 05 00 00 0a 4d 1d d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 | {....M........ZXM)....(.......(. |
| 1ca0 | 00 00 0a 2a 13 30 04 00 2b 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1e d3 fe | ...*.0..+........{.....{....M... |
| 1cc0 | 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 13 30 06 00 | .....ZXM)....(.......(....*..0.. |
| 1ce0 | 34 00 00 00 06 00 00 11 04 0b 02 7b 05 00 00 0a 03 07 d3 02 7b 05 00 00 0a 4d 1f 09 d3 fe 1c 01 | 4..........{........{....M...... |
| 1d00 | 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 13 30 07 00 | ...ZXM)....(..........(....*.0.. |
| 1d20 | 63 00 00 00 1a 00 00 11 7e 03 00 00 0a 0a 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e | c.......~......{.....,..o....+.~ |
| 1d40 | 03 00 00 0a 28 06 00 00 0a 04 12 00 e0 02 7b 05 00 00 0a 4d 1f 0a d3 fe 1c 01 00 00 1b 5a 58 4d | ....(.........{....M.........ZXM |
| 1d60 | 29 1e 00 00 11 28 07 00 00 0a 0b 05 06 7e 03 00 00 0a 28 04 00 00 0a 2d 08 06 73 20 01 00 06 2b | )....(.......~....(....-..s....+ |
| 1d80 | 01 14 51 12 01 28 08 00 00 0a 2a 00 13 30 07 00 63 00 00 00 1a 00 00 11 7e 03 00 00 0a 0a 02 7b | ..Q..(....*..0..c.......~......{ |
| 1da0 | 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 04 12 00 e0 02 7b 05 | .....,..o....+.~....(.........{. |
| 1dc0 | 00 00 0a 4d 1f 0b d3 fe 1c 01 00 00 1b 5a 58 4d 29 1e 00 00 11 28 07 00 00 0a 0b 05 06 7e 03 00 | ...M.........ZXM)....(.......~.. |
| 1de0 | 00 0a 28 04 00 00 0a 2d 08 06 73 c0 00 00 06 2b 01 14 51 12 01 28 08 00 00 0a 2a 00 13 30 05 00 | ..(....-..s....+..Q..(....*..0.. |
| 1e00 | 33 00 00 00 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1f 0c d3 fe 1c 01 00 | 3..........{.......{....M....... |
| 1e20 | 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 13 30 05 00 | ..ZXM)....(..........(....*..0.. |
| 1e40 | 33 00 00 00 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1f 0d d3 fe 1c 01 00 | 3..........{.......{....M....... |
| 1e60 | 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 13 30 05 00 | ..ZXM)....(..........(....*..0.. |
| 1e80 | 2d 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 0a 4d 1f 0e d3 fe 1c 01 00 00 1b 5a | -........{......{....M.........Z |
| 1ea0 | 58 4d 29 07 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 04 00 2c 00 00 00 | XM)....(.......(....*....0..,... |
| 1ec0 | 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1f 0f d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 | .....{.....{....M.........ZXM).. |
| 1ee0 | 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 13 30 04 00 2c 00 00 00 01 00 00 11 02 7b 05 00 | ..(.......(....*.0..,........{.. |
| 1f00 | 00 0a 02 7b 05 00 00 0a 4d 1f 10 d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a | ...{....M.........ZXM)....(..... |
| 1f20 | 12 00 28 08 00 00 0a 2a 13 30 06 00 33 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 28 06 00 00 0a | ..(....*.0..3........{.....(.... |
| 1f40 | 04 02 7b 05 00 00 0a 4d 1f 11 d3 fe 1c 01 00 00 1b 5a 58 4d 29 23 00 00 11 28 07 00 00 0a 0a 12 | ..{....M.........ZXM)#...(...... |
| 1f60 | 00 28 08 00 00 0a 2a 00 13 30 05 00 41 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f | .(....*..0..A........{.....,..o. |
| 1f80 | 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 02 7b 05 00 00 0a 4d 1f 12 d3 fe 1c 01 00 00 1b 5a | ...+.~....(.....{....M.........Z |
| 1fa0 | 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 05 00 41 00 00 00 | XM)....(.......(....*....0..A... |
| 1fc0 | 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 02 | .....{.....,..o....+.~....(..... |
| 1fe0 | 7b 05 00 00 0a 4d 1f 13 d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 28 | {....M.........ZXM)....(.......( |
| 2000 | 08 00 00 0a 2a 00 00 00 13 30 05 00 41 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f | ....*....0..A........{.....,..o. |
| 2020 | 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 02 7b 05 00 00 0a 4d 1f 14 d3 fe 1c 01 00 00 1b 5a | ...+.~....(.....{....M.........Z |
| 2040 | 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 05 00 41 00 00 00 | XM)....(.......(....*....0..A... |
| 2060 | 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 02 | .....{.....,..o....+.~....(..... |
| 2080 | 7b 05 00 00 0a 4d 1f 15 d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 28 | {....M.........ZXM)....(.......( |
| 20a0 | 08 00 00 0a 2a 00 00 00 13 30 05 00 2d 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 | ....*....0..-........{......{... |
| 20c0 | 0a 4d 1f 16 d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a | .M.........ZXM)....(.......(.... |
| 20e0 | 2a 00 00 00 13 30 04 00 2c 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1f 17 d3 | *....0..,........{.....{....M... |
| 2100 | fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 22 02 03 28 | ......ZXM)....(.......(....*"..( |
| 2120 | 02 00 00 0a 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a 2d 07 02 73 9e 00 00 06 2a 14 2a 00 | ....*...Z.~....(....-..s....*.*. |
| 2140 | 13 30 0a 00 34 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 04 05 0e 04 0e 05 0e 06 02 7b 05 00 00 | .0..4........{..............{... |
| 2160 | 0a 4d 19 d3 fe 1c 01 00 00 1b 5a 58 4d 29 24 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a | .M........ZXM)$...(.......(....* |
| 2180 | 13 30 0a 00 34 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 04 05 0e 04 0e 05 0e 06 02 7b 05 00 00 | .0..4........{..............{... |
| 21a0 | 0a 4d 1a d3 fe 1c 01 00 00 1b 5a 58 4d 29 24 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a | .M........ZXM)$...(.......(....* |
| 21c0 | 22 02 03 28 02 00 00 0a 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a 2d 07 02 73 a3 00 00 06 | "..(....*...Z.~....(....-..s.... |
| 21e0 | 2a 14 2a 00 13 30 07 00 56 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b | *.*..0..V........{.....,..o....+ |
| 2200 | 05 7e 03 00 00 0a 28 06 00 00 0a 04 2c 08 04 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a | .~....(.....,..o....+.~....(.... |
| 2220 | 05 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b 5a 58 4d 29 16 00 00 11 28 07 00 00 0a 0a 12 00 | ..{....M........ZXM)....(....... |
| 2240 | 28 08 00 00 0a 2a 00 00 22 02 03 28 02 00 00 0a 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a | (....*.."..(....*...Z.~....(.... |
| 2260 | 2d 07 02 73 a6 00 00 06 2a 14 2a 00 22 02 03 28 b2 00 00 06 2a 00 00 00 13 30 02 00 0a 00 00 00 | -..s....*.*."..(....*....0...... |
| 2280 | 25 00 00 11 02 12 00 28 b9 00 00 06 06 2a 00 00 13 30 02 00 0a 00 00 00 02 00 00 11 02 12 00 28 | %......(.....*...0.............( |
| 22a0 | ba 00 00 06 06 2a 00 00 13 30 06 00 55 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f | .....*...0..U........{.....,..o. |
| 22c0 | 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 04 2c 08 04 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 | ...+.~....(.....,..o....+.~....( |
| 22e0 | 06 00 00 0a 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b 5a 58 4d 29 26 00 00 11 28 07 00 00 0a | .....{....M........ZXM)&...(.... |
| 2300 | 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 07 00 3b 00 00 00 27 00 00 11 12 00 fe 15 05 00 00 02 | ...(....*....0..;...'........... |
| 2320 | 02 7b 05 00 00 0a 0f 01 e0 04 12 00 e0 02 7b 05 00 00 0a 4d 1a d3 fe 1c 01 00 00 1b 5a 58 4d 29 | .{............{....M........ZXM) |
| 2340 | 28 00 00 11 28 07 00 00 0a 0b 12 01 28 08 00 00 0a 06 2a 00 13 30 06 00 4c 00 00 00 27 00 00 11 | (...(.......(.....*..0..L...'... |
| 2360 | 12 00 fe 15 05 00 00 02 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 | .........{.....,..o....+.~....(. |
| 2380 | 00 00 0a 12 00 e0 02 7b 05 00 00 0a 4d 1b d3 fe 1c 01 00 00 1b 5a 58 4d 29 26 00 00 11 28 07 00 | .......{....M........ZXM)&...(.. |
| 23a0 | 00 0a 0b 12 01 28 08 00 00 0a 06 2a 13 30 07 00 58 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c | .....(.....*.0..X........{....., |
| 23c0 | 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 04 2c 08 04 6f 1f 00 00 0a 2b 05 7e 03 | ..o....+.~....(.....,..o....+.~. |
| 23e0 | 00 00 0a 28 06 00 00 0a 0f 03 e0 02 7b 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 13 00 | ...(........{....M........ZXM).. |
| 2400 | 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 13 30 08 00 5b 00 00 00 01 00 00 11 02 7b 05 00 | ..(.......(....*.0..[........{.. |
| 2420 | 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 04 2c 08 04 6f 1f 00 00 0a | ...,..o....+.~....(.....,..o.... |
| 2440 | 2b 05 7e 03 00 00 0a 28 06 00 00 0a 0f 03 e0 0f 04 e0 02 7b 05 00 00 0a 4d 1d d3 fe 1c 01 00 00 | +.~....(...........{....M....... |
| 2460 | 1b 5a 58 4d 29 29 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 13 30 07 00 32 00 00 00 | .ZXM))...(.......(....*..0..2... |
| 2480 | 01 00 00 11 02 7b 05 00 00 0a 0f 01 e0 0f 02 e0 05 02 7b 05 00 00 0a 4d 1e d3 fe 1c 01 00 00 1b | .....{............{....M........ |
| 24a0 | 5a 58 4d 29 16 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 13 30 05 00 41 00 00 00 | ZXM)....(.......(....*...0..A... |
| 24c0 | 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 02 | .....{.....,..o....+.~....(..... |
| 24e0 | 7b 05 00 00 0a 4d 1f 09 d3 fe 1c 01 00 00 1b 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 28 | {....M.........ZXM)....(.......( |
| 2500 | 08 00 00 0a 2a 00 00 00 13 30 05 00 2d 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 | ....*....0..-........{......{... |
| 2520 | 0a 4d 1f 0a d3 fe 1c 01 00 00 1b 5a 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a | .M.........ZXM)....(.......(.... |
| 2540 | 2a 00 00 00 13 30 06 00 31 00 00 00 2a 00 00 11 02 7b 05 00 00 0a 03 12 00 e0 02 7b 05 00 00 0a | *....0..1...*....{.........{.... |
| 2560 | 4d 1f 0b d3 fe 1c 01 00 00 1b 5a 58 4d 29 0a 00 00 11 28 07 00 00 0a 0b 12 01 28 08 00 00 0a 06 | M.........ZXM)....(.......(..... |
| 2580 | 2a 00 00 00 13 30 04 00 2c 00 00 00 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1f 0c d3 | *....0..,........{.....{....M... |
| 25a0 | fe 1c 01 00 00 1b 5a 58 4d 29 05 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 13 30 05 00 | ......ZXM)....(.......(....*.0.. |
| 25c0 | 2d 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 02 7b 05 00 00 0a 4d 1f 0d d3 fe 1c 01 00 00 1b 5a | -........{......{....M.........Z |
| 25e0 | 58 4d 29 08 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 04 00 2c 00 00 00 | XM)....(.......(....*....0..,... |
| 2600 | 01 00 00 11 02 7b 05 00 00 0a 02 7b 05 00 00 0a 4d 1f 0e d3 fe 1c 01 00 00 1b 5a 58 4d 29 05 00 | .....{.....{....M.........ZXM).. |
| 2620 | 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 13 30 06 00 33 00 00 00 01 00 00 11 02 7b 05 00 | ..(.......(....*.0..3........{.. |
| 2640 | 00 0a 03 28 06 00 00 0a 04 02 7b 05 00 00 0a 4d 1f 0f d3 fe 1c 01 00 00 1b 5a 58 4d 29 03 00 00 | ...(......{....M.........ZXM)... |
| 2660 | 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 13 30 06 00 3a 00 00 00 2b 00 00 11 03 0b 04 0c | .(.......(....*..0..:...+....... |
| 2680 | 02 7b 05 00 00 0a 07 d3 08 d3 02 7b 05 00 00 0a 4d 1f 10 d3 fe 1c 01 00 00 1b 5a 58 4d 29 26 00 | .{.........{....M.........ZXM)&. |
| 26a0 | 00 11 28 07 00 00 0a 0a 16 e0 0c 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 13 30 05 00 33 00 00 00 | ..(.............(....*...0..3... |
| 26c0 | 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1f 11 d3 fe 1c 01 00 00 1b 5a 58 | .......{.......{....M.........ZX |
| 26e0 | 4d 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 13 30 05 00 33 00 00 00 | M)....(..........(....*..0..3... |
| 2700 | 06 00 00 11 03 0b 02 7b 05 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1f 12 d3 fe 1c 01 00 00 1b 5a 58 | .......{.......{....M.........ZX |
| 2720 | 4d 29 04 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 13 30 05 00 32 00 00 00 | M)....(..........(....*..0..2... |
| 2740 | 01 00 00 11 02 7b 05 00 00 0a 03 28 06 00 00 0a 02 7b 05 00 00 0a 4d 1f 13 d3 fe 1c 01 00 00 1b | .....{.....(.....{....M......... |
| 2760 | 5a 58 4d 29 04 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 3a 02 28 09 00 00 0a 03 | ZXM)....(.......(....*..:.(..... |
| 2780 | 02 6f 5b 00 00 06 2a 00 2a 02 03 04 05 28 b0 00 00 06 2a 00 13 30 03 00 3e 00 00 00 2c 00 00 11 | .o[...*.*....(....*..0..>...,... |
| 27a0 | 7e 03 00 00 0a 0a 02 12 00 12 01 28 b8 00 00 06 06 7e 03 00 00 0a 28 2a 00 00 0a 2c 0e 06 28 2b | ~..........(.....~....(*...,..(+ |
| 27c0 | 00 00 0a 0c 12 02 28 27 00 00 0a 02 03 28 25 00 00 0a 28 26 00 00 0a 04 28 b7 00 00 06 2a 00 00 | ......('.....(%...(&....(....*.. |
| 27e0 | 13 30 03 00 1a 00 00 00 2d 00 00 11 02 12 00 04 28 b8 00 00 06 03 06 28 2b 00 00 0a 0b 12 01 28 | .0......-.......(......(+......( |
| 2800 | 2c 00 00 0a 51 2a 00 00 22 02 03 28 02 00 00 0a 2a 00 00 00 5a 02 7e 03 00 00 0a 28 04 00 00 0a | ,...Q*.."..(....*...Z.~....(.... |
| 2820 | 2d 07 02 73 c0 00 00 06 2a 14 2a 00 22 02 03 28 cd 00 00 06 2a 00 00 00 22 02 03 28 ce 00 00 06 | -..s....*.*."..(....*..."..(.... |
| 2840 | 2a 00 00 00 13 30 02 00 0a 00 00 00 25 00 00 11 02 12 00 28 d5 00 00 06 06 2a 00 00 13 30 02 00 | *....0......%......(.....*...0.. |
| 2860 | 0a 00 00 00 02 00 00 11 02 12 00 28 d6 00 00 06 06 2a 00 00 13 30 06 00 55 00 00 00 01 00 00 11 | ...........(.....*...0..U....... |
| 2880 | 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 04 2c 08 04 6f | .{.....,..o....+.~....(.....,..o |
| 28a0 | 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 02 7b 05 00 00 0a 4d 19 d3 fe 1c 01 00 00 1b 5a | ....+.~....(.....{....M........Z |
| 28c0 | 58 4d 29 26 00 00 11 28 07 00 00 0a 0a 12 00 28 08 00 00 0a 2a 00 00 00 13 30 07 00 3d 00 00 00 | XM)&...(.......(....*....0..=... |
| 28e0 | 06 00 00 11 05 fe 15 05 00 00 02 05 0b 02 7b 05 00 00 0a 0f 01 e0 04 07 d3 02 7b 05 00 00 0a 4d | ..............{...........{....M |
| 2900 | 1a d3 fe 1c 01 00 00 1b 5a 58 4d 29 28 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a | ........ZXM)(...(..........(.... |
| 2920 | 2a 00 00 00 13 30 06 00 4e 00 00 00 06 00 00 11 04 fe 15 05 00 00 02 04 0b 02 7b 05 00 00 0a 03 | *....0..N.................{..... |
| 2940 | 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 07 d3 02 7b 05 00 00 0a 4d 1b d3 fe | ,..o....+.~....(.......{....M... |
| 2960 | 1c 01 00 00 1b 5a 58 4d 29 26 00 00 11 28 07 00 00 0a 0a 16 e0 0b 12 00 28 08 00 00 0a 2a 00 00 | .....ZXM)&...(..........(....*.. |
| 2980 | 13 30 07 00 58 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b 05 7e 03 00 | .0..X........{.....,..o....+.~.. |
| 29a0 | 00 0a 28 06 00 00 0a 04 2c 08 04 6f 1f 00 00 0a 2b 05 7e 03 00 00 0a 28 06 00 00 0a 0f 03 e0 02 | ..(.....,..o....+.~....(........ |
| 29c0 | 7b 05 00 00 0a 4d 1c d3 fe 1c 01 00 00 1b 5a 58 4d 29 13 00 00 11 28 07 00 00 0a 0a 12 00 28 08 | {....M........ZXM)....(.......(. |
| 29e0 | 00 00 0a 2a 13 30 08 00 5b 00 00 00 01 00 00 11 02 7b 05 00 00 0a 03 2c 08 03 6f 1f 00 00 0a 2b | ...*.0..[........{.....,..o...// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Rendering
{
/// <summary>
/// A virtualizing panel producing+showing <see cref="VisualLine"/>s for a <see cref="TextDocument"/>.
///
/// This is the heart of the text editor, this class controls the text rendering process.
///
/// Taken as a standalone control, it's a text viewer without any editing capability.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
Justification = "The user usually doesn't work with TextView but with TextEditor; and nulling the Document property is sufficient to dispose everything.")]
public class TextView : FrameworkElement, IScrollInfo, IWeakEventListener, ITextEditorComponent, IServiceProvider
{
#region Constructor
static TextView()
{
ClipToBoundsProperty.OverrideMetadata(typeof(TextView), new FrameworkPropertyMetadata(Boxes.True));
FocusableProperty.OverrideMetadata(typeof(TextView), new FrameworkPropertyMetadata(Boxes.False));
}
ColumnRulerRenderer columnRulerRenderer;
/// <summary>
/// Creates a new TextView instance.
/// </summary>
public TextView()
{
services.AddService(typeof(TextView), this);
textLayer = new TextLayer(this);
elementGenerators = new ObserveAddRemoveCollection<VisualLineElementGenerator>(ElementGenerator_Added, ElementGenerator_Removed);
lineTransformers = new ObserveAddRemoveCollection<IVisualLineTransformer>(LineTransformer_Added, LineTransformer_Removed);
backgroundRenderers = new ObserveAddRemoveCollection<IBackgroundRenderer>(BackgroundRenderer_Added, BackgroundRenderer_Removed);
columnRulerRenderer = new ColumnRulerRenderer(this);
this.Options = new TextEditorOptions();
Debug.Assert(singleCharacterElementGenerator != null); // assert that the option change created the builtin element generators
layers = new LayerCollection(this);
InsertLayer(textLayer, KnownLayer.Text, LayerInsertionPosition.Replace);
this.hoverLogic = new MouseHoverLogic(this);
this.hoverLogic.MouseHover += (sender, e) => RaiseHoverEventPair(e, PreviewMouseHoverEvent, MouseHoverEvent);
this.hoverLogic.MouseHoverStopped += (sender, e) => RaiseHoverEventPair(e, PreviewMouseHoverStoppedEvent, MouseHoverStoppedEvent);
}
#endregion
#region Document Property
/// <summary>
/// Document property.
/// </summary>
public static readonly DependencyProperty DocumentProperty =
DependencyProperty.Register("Document", typeof(TextDocument), typeof(TextView),
new FrameworkPropertyMetadata(OnDocumentChanged));
TextDocument document;
HeightTree heightTree;
/// <summary>
/// Gets/Sets the document displayed by the text editor.
/// </summary>
public TextDocument Document {
get { return (TextDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
static void OnDocumentChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
((TextView)dp).OnDocumentChanged((TextDocument)e.OldValue, (TextDocument)e.NewValue);
}
internal double FontSize {
get {
return (double)GetValue(TextBlock.FontSizeProperty);
}
}
/// <summary>
/// Occurs when the document property has changed.
/// </summary>
public event EventHandler DocumentChanged;
void OnDocumentChanged(TextDocument oldValue, TextDocument newValue)
{
if (oldValue != null) {
heightTree.Dispose();
heightTree = null;
formatter.Dispose();
formatter = null;
cachedElements.Dispose();
cachedElements = null;
TextDocumentWeakEventManager.Changing.RemoveListener(oldValue, this);
}
this.document = newValue;
ClearScrollData();
ClearVisualLines();
if (newValue != null) {
TextDocumentWeakEventManager.Changing.AddListener(newValue, this);
formatter = TextFormatterFactory.Create(this);
InvalidateDefaultTextMetrics(); // measuring DefaultLineHeight depends on formatter
heightTree = new HeightTree(newValue, DefaultLineHeight);
cachedElements = new TextViewCachedElements();
}
InvalidateMeasure(DispatcherPriority.Normal);
if (DocumentChanged != null)
DocumentChanged(this, EventArgs.Empty);
}
/// <summary>
/// Recreates the text formatter that is used internally
/// by calling <see cref="TextFormatterFactory.Create"/>.
/// </summary>
void RecreateTextFormatter()
{
if (formatter != null) {
formatter.Dispose();
formatter = TextFormatterFactory.Create(this);
Redraw();
}
}
void RecreateCachedElements()
{
if (cachedElements != null) {
cachedElements.Dispose();
cachedElements = new TextViewCachedElements();
}
}
/// <inheritdoc cref="IWeakEventListener.ReceiveWeakEvent"/>
protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if (managerType == typeof(TextDocumentWeakEventManager.Changing)) {
// TODO: put redraw into background so that other input events can be handled before the redraw.
// Unfortunately the "easy" approach (just use DispatcherPriority.Background) here makes the editor twice as slow because
// the caret position change forces an immediate redraw, and the text input then forces a background redraw.
// When fixing this, make sure performance on the SharpDevelop "type text in C# comment" stress test doesn't get significantly worse.
DocumentChangeEventArgs change = (DocumentChangeEventArgs)e;
Redraw(change.Offset, change.RemovalLength, DispatcherPriority.Normal);
return true;
} else if (managerType == typeof(PropertyChangedWeakEventManager)) {
OnOptionChanged((PropertyChangedEventArgs)e);
return true;
}
return false;
}
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
return ReceiveWeakEvent(managerType, sender, e);
}
#endregion
#region Options property
/// <summary>
/// Options property.
/// </summary>
public static readonly DependencyProperty OptionsProperty =
DependencyProperty.Register("Options", typeof(TextEditorOptions), typeof(TextView),
new FrameworkPropertyMetadata(OnOptionsChanged));
/// <summary>
/// Gets/Sets the options used by the text editor.
/// </summary>
public TextEditorOptions Options {
get { return (TextEditorOptions)GetValue(OptionsProperty); }
set { SetValue(OptionsProperty, value); }
}
/// <summary>
/// Occurs when a text editor option has changed.
/// </summary>
public event PropertyChangedEventHandler OptionChanged;
/// <summary>
/// Raises the <see cref="OptionChanged"/> event.
/// </summary>
protected virtual void OnOptionChanged(PropertyChangedEventArgs e)
{
if (OptionChanged != null) {
OptionChanged(this, e);
}
if (Options.ShowColumnRuler)
columnRulerRenderer.SetRuler(Options.ColumnRulerPosition, ColumnRulerPen);
else
columnRulerRenderer.SetRuler(-1, ColumnRulerPen);
UpdateBuiltinElementGeneratorsFromOptions();
Redraw();
}
static void OnOptionsChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
((TextView)dp).OnOptionsChanged((TextEditorOptions)e.OldValue, (TextEditorOptions)e.NewValue);
}
void OnOptionsChanged(TextEditorOptions oldValue, TextEditorOptions newValue)
{
if (oldValue != null) {
PropertyChangedWeakEventManager.RemoveListener(oldValue, this);
}
if (newValue != null) {
PropertyChangedWeakEventManager.AddListener(newValue, this);
}
OnOptionChanged(new PropertyChangedEventArgs(null));
}
#endregion
#region ElementGenerators+LineTransformers Properties
readonly ObserveAddRemoveCollection<VisualLineElementGenerator> elementGenerators;
/// <summary>
/// Gets a collection where element generators can be registered.
/// </summary>
public IList<VisualLineElementGenerator> ElementGenerators {
get { return elementGenerators; }
}
void ElementGenerator_Added(VisualLineElementGenerator generator)
{
ConnectToTextView(generator);
Redraw();
}
void ElementGenerator_Removed(VisualLineElementGenerator generator)
{
DisconnectFromTextView(generator);
Redraw();
}
readonly ObserveAddRemoveCollection<IVisualLineTransformer> lineTransformers;
/// <summary>
/// Gets a collection where line transformers can be registered.
/// </summary>
public IList<IVisualLineTransformer> LineTransformers {
get { return lineTransformers; }
}
void LineTransformer_Added(IVisualLineTransformer lineTransformer)
{
ConnectToTextView(lineTransformer);
Redraw();
}
void LineTransformer_Removed(IVisualLineTransformer lineTransformer)
{
DisconnectFromTextView(lineTransformer);
Redraw();
}
#endregion
#region Builtin ElementGenerators
// NewLineElementGenerator newLineElementGenerator;
SingleCharacterElementGenerator singleCharacterElementGenerator;
LinkElementGenerator linkElementGenerator;
MailLinkElementGenerator mailLinkElementGenerator;
void UpdateBuiltinElementGeneratorsFromOptions()
{
TextEditorOptions options = this.Options;
// AddRemoveDefaultElementGeneratorOnDemand(ref newLineElementGenerator, options.ShowEndOfLine);
AddRemoveDefaultElementGeneratorOnDemand(ref singleCharacterElementGenerator, options.ShowBoxForControlCharacters || options.ShowSpaces || options.ShowTabs);
AddRemoveDefaultElementGeneratorOnDemand(ref linkElementGenerator, options.EnableHyperlinks);
AddRemoveDefaultElementGeneratorOnDemand(ref mailLinkElementGenerator, options.EnableEmailHyperlinks);
}
void AddRemoveDefaultElementGeneratorOnDemand<T>(ref T generator, bool demand)
where T : VisualLineElementGenerator, IBuiltinElementGenerator, new()
{
bool hasGenerator = generator != null;
if (hasGenerator != demand) {
if (demand) {
generator = new T();
this.ElementGenerators.Add(generator);
} else {
this.ElementGenerators.Remove(generator);
generator = null;
}
}
if (generator != null)
generator.FetchOptions(this.Options);
}
#endregion
#region Layers
internal readonly TextLayer textLayer;
readonly LayerCollection layers;
/// <summary>
/// Gets the list of layers displayed in the text view.
/// </summary>
public UIElementCollection Layers {
get { return layers; }
}
sealed class LayerCollection : UIElementCollection
{
readonly TextView textView;
public LayerCollection(TextView textView)
: base(textView, textView)
{
this.textView = textView;
}
public override void Clear()
{
base.Clear();
textView.LayersChanged();
}
public override int Add(UIElement element)
{
int r = base.Add(element);
textView.LayersChanged();
return r;
}
public override void RemoveAt(int index)
{
base.RemoveAt(index);
textView.LayersChanged();
}
public override void RemoveRange(int index, int count)
{
base.RemoveRange(index, count);
textView.LayersChanged();
}
}
void LayersChanged()
{
textLayer.index = layers.IndexOf(textLayer);
}
/// <summary>
/// Inserts a new layer at a position specified relative to an existing layer.
/// </summary>
/// <param name="layer">The new layer to insert.</param>
/// <param name="referencedLayer">The existing layer</param>
/// <param name="position">Specifies whether the layer is inserted above,below, or replaces the referenced layer</param>
public void InsertLayer(UIElement layer, KnownLayer referencedLayer, LayerInsertionPosition position)
{
if (layer == null)
throw new ArgumentNullException("layer");
if (!Enum.IsDefined(typeof(KnownLayer), referencedLayer))
throw new InvalidEnumArgumentException("referencedLayer", (int)referencedLayer, typeof(KnownLayer));
if (!Enum.IsDefined(typeof(LayerInsertionPosition), position))
throw new InvalidEnumArgumentException("position", (int)position, typeof(LayerInsertionPosition));
if (referencedLayer == KnownLayer.Background && position != LayerInsertionPosition.Above)
throw new InvalidOperationException("Cannot replace or insert below the background layer.");
LayerPosition newPosition = new LayerPosition(referencedLayer, position);
LayerPosition.SetLayerPosition(layer, newPosition);
for (int i = 0; i < layers.Count; i++) {
LayerPosition p = LayerPosition.GetLayerPosition(layers[i]);
if (p != null) {
if (p.KnownLayer == referencedLayer && p.Position == LayerInsertionPosition.Replace) {
// found the referenced layer
switch (position) {
case LayerInsertionPosition.Below:
layers.Insert(i, layer);
return;
case LayerInsertionPosition.Above:
layers.Insert(i + 1, layer);
return;
case LayerInsertionPosition.Replace:
layers[i] = layer;
return;
}
} else if (p.KnownLayer == referencedLayer && p.Position == LayerInsertionPosition.Above
|| p.KnownLayer > referencedLayer) {
// we skipped the insertion position (referenced layer does not exist?)
layers.Insert(i, layer);
return;
}
}
}
// inserting after all existing layers:
layers.Add(layer);
}
/// <inheritdoc/>
protected override int VisualChildrenCount {
get { return layers.Count + inlineObjects.Count; }
}
/// <inheritdoc/>
protected override Visual GetVisualChild(int index)
{
int cut = textLayer.index + 1;
if (index < cut)
return layers[index];
else if (index < cut + inlineObjects.Count)
return inlineObjects[index - cut].Element;
else
return layers[index - inlineObjects.Count];
}
/// <inheritdoc/>
protected override System.Collections.IEnumerator LogicalChildren {
get {
return inlineObjects.Select(io => io.Element).Concat(layers.Cast<UIElement>()).GetEnumerator();
}
}
#endregion
#region Inline object handling
List<InlineObjectRun> inlineObjects = new List<InlineObjectRun>();
/// <summary>
/// Adds a new inline object.
/// </summary>
internal void AddInlineObject(InlineObjectRun inlineObject)
{
Debug.Assert(inlineObject.VisualLine != null);
// Remove inline object if its already added, can happen e.g. when recreating textrun for word-wrapping
bool alreadyAdded = false;
for (int i = 0; i < inlineObjects.Count; i++) {
if (inlineObjects[i].Element == inlineObject.Element) {
RemoveInlineObjectRun(inlineObjects[i], true);
inlineObjects.RemoveAt(i);
alreadyAdded = true;
break;
}
}
inlineObjects.Add(inlineObject);
if (!alreadyAdded) {
AddVisualChild(inlineObject.Element);
}
inlineObject.Element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
inlineObject.desiredSize = inlineObject.Element.DesiredSize;
}
void MeasureInlineObjects()
{
// As part of MeasureOverride(), re-measure the inline objects
foreach (InlineObjectRun inlineObject in inlineObjects) {
if (inlineObject.VisualLine.IsDisposed) {
// Don't re-measure inline objects that are going to be removed anyways.
// If the inline object will be reused in a different VisualLine, we'll measure it in the AddInlineObject() call.
continue;
}
inlineObject.Element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
if (!inlineObject.Element.DesiredSize.IsClose(inlineObject.desiredSize)) {
// the element changed size -> recreate its parent visual line
inlineObject.desiredSize = inlineObject.Element.DesiredSize;
if (allVisualLines.Remove(inlineObject.VisualLine)) {
DisposeVisualLine(inlineObject.VisualLine);
}
}
}
}
List<VisualLine> visualLinesWithOutstandingInlineObjects = new List<VisualLine>();
void RemoveInlineObjects(VisualLine visualLine)
{
// Delay removing inline objects:
// A document change immediately invalidates affected visual lines, but it does not
// cause an immediate redraw.
// To prevent inline objects from flickering when they are recreated, we delay removing
// inline objects until the next redraw.
if (visualLine.hasInlineObjects) {
visualLinesWithOutstandingInlineObjects.Add(visualLine);
}
}
/// <summary>
/// Remove the inline objects that were marked for removal.
/// </summary>
void RemoveInlineObjectsNow()
{
if (visualLinesWithOutstandingInlineObjects.Count == 0)
return;
inlineObjects.RemoveAll(
ior => {
if (visualLinesWithOutstandingInlineObjects.Contains(ior.VisualLine)) {
RemoveInlineObjectRun(ior, false);
return true;
}
return false;
});
visualLinesWithOutstandingInlineObjects.Clear();
}
// Remove InlineObjectRun.Element from TextLayer.
// Caller of RemoveInlineObjectRun will remove it from inlineObjects collection.
void RemoveInlineObjectRun(InlineObjectRun ior, bool keepElement)
{
if (!keepElement && ior.Element.IsKeyboardFocusWithin) {
// When the inline element that has the focus is removed, WPF will reset the
// focus to the main window without raising appropriate LostKeyboardFocus events.
// To work around this, we manually set focus to the next focusable parent.
UIElement element = this;
while (element != null && !element.Focusable) {
element = VisualTreeHelper.GetParent(element) as UIElement;
}
if (element != null)
Keyboard.Focus(element);
}
ior.VisualLine = null;
if (!keepElement)
RemoveVisualChild(ior.Element);
}
#endregion
#region Brushes
/// <summary>
/// NonPrintableCharacterBrush dependency property.
/// </summary>
public static readonly DependencyProperty NonPrintableCharacterBrushProperty =
DependencyProperty.Register("NonPrintableCharacterBrush", typeof(Brush), typeof(TextView),
new FrameworkPropertyMetadata(Brushes.LightGray));
/// <summary>
/// Gets/sets the Brush used for displaying non-printable characters.
/// </summary>
public Brush NonPrintableCharacterBrush {
get { return (Brush)GetValue(NonPrintableCharacterBrushProperty); }
set { SetValue(NonPrintableCharacterBrushProperty, value); }
}
/// <summary>
/// LinkTextForegroundBrush dependency property.
/// </summary>
public static readonly DependencyProperty LinkTextForegroundBrushProperty =
DependencyProperty.Register("LinkTextForegroundBrush", typeof(Brush), typeof(TextView),
new FrameworkPropertyMetadata(Brushes.Blue));
/// <summary>
/// Gets/sets the Brush used for displaying link texts.
/// </summary>
public Brush LinkTextForegroundBrush {
get { return (Brush)GetValue(LinkTextForegroundBrushProperty); }
set { SetValue(LinkTextForegroundBrushProperty, value); }
}
/// <summary>
/// LinkTextBackgroundBrush dependency property.
/// </summary>
public static readonly DependencyProperty LinkTextBackgroundBrushProperty =
DependencyProperty.Register("LinkTextBackgroundBrush", typeof(Brush), typeof(TextView),
new FrameworkPropertyMetadata(Brushes.Transparent));
/// <summary>
/// Gets/sets the Brush used for the background of link texts.
/// </summary>
public Brush LinkTextBackgroundBrush {
get { return (Brush)GetValue(LinkTextBackgroundBrushProperty); }
set { SetValue(LinkTextBackgroundBrushProperty, value); }
}
#endregion
#region Redraw methods / VisualLine invalidation
/// <summary>
/// Causes the text editor to regenerate all visual lines.
/// </summary>
public void Redraw()
{
Redraw(DispatcherPriority.Normal);
}
/// <summary>
/// Causes the text editor to regenerate all visual lines.
/// </summary>
public void Redraw(DispatcherPriority redrawPriority)
{
VerifyAccess();
ClearVisualLines();
InvalidateMeasure(redrawPriority);
}
/// <summary>
/// Causes the text editor to regenerate the specified visual line.
/// </summary>
public void Redraw(VisualLine visualLine, DispatcherPriority redrawPriority = DispatcherPriority.Normal)
{
VerifyAccess();
if (allVisualLines.Remove(visualLine)) {
DisposeVisualLine(visualLine);
InvalidateMeasure(redrawPriority);
}
}
/// <summary>
/// Causes the text editor to redraw all lines overlapping with the specified segment.
/// </summary>
public void Redraw(int offset, int length, DispatcherPriority redrawPriority = DispatcherPriority.Normal)
{
VerifyAccess();
bool changedSomethingBeforeOrInLine = false;
for (int i = 0; i < allVisualLines.Count; i++) {
VisualLine visualLine = allVisualLines[i];
int lineStart = visualLine.FirstDocumentLine.Offset;
int lineEnd = visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength;
if (offset <= lineEnd) {
changedSomethingBeforeOrInLine = true;
if (offset + length >= lineStart) {
allVisualLines.RemoveAt(i--);
DisposeVisualLine(visualLine);
}
}
}
if (changedSomethingBeforeOrInLine) {
// Repaint not only when something in visible area was changed, but also when anything in front of it
// was changed. We might have to redraw the line number margin. Or the highlighting changed.
// However, we'll try to reuse the existing VisualLines.
InvalidateMeasure(redrawPriority);
}
}
/// <summary>
/// Causes a known layer to redraw.
/// This method does not invalidate visual lines;
/// use the <see cref="Redraw()"/> method to do that.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "knownLayer",
Justification="This method is meant to invalidate only a specific layer - I just haven't figured out how to do that, yet.")]
public void InvalidateLayer(KnownLayer knownLayer)
{
InvalidateMeasure(DispatcherPriority.Normal);
}
/// <summary>
/// Causes a known layer to redraw.
/// This method does not invalidate visual lines;
/// use the <see cref="Redraw()"/> method to do that.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "knownLayer",
Justification="This method is meant to invalidate only a specific layer - I just haven't figured out how to do that, yet.")]
public void InvalidateLayer(KnownLayer knownLayer, DispatcherPriority priority)
{
InvalidateMeasure(priority);
}
/// <summary>
/// Causes the text editor to redraw all lines overlapping with the specified segment.
/// Does nothing if segment is null.
/// </summary>
public void Redraw(ISegment segment, DispatcherPriority redrawPriority = DispatcherPriority.Normal)
{
if (segment != null) {
Redraw(segment.Offset, segment.Length, redrawPriority);
}
}
/// <summary>
/// Invalidates all visual lines.
/// The caller of ClearVisualLines() must also call InvalidateMeasure() to ensure
/// that the visual lines will be recreated.
/// </summary>
void ClearVisualLines()
{
visibleVisualLines = null;
if (allVisualLines.Count != 0) {
foreach (VisualLine visualLine in allVisualLines) {
DisposeVisualLine(visualLine);
}
allVisualLines.Clear();
}
}
void DisposeVisualLine(VisualLine visualLine)
{
if (newVisualLines != null && newVisualLines.Contains(visualLine)) {
throw new ArgumentException("Cannot dispose visual line because it is in construction!");
}
visibleVisualLines = null;
visualLine.Dispose();
RemoveInlineObjects(visualLine);
}
#endregion
#region InvalidateMeasure(DispatcherPriority)
DispatcherOperation invalidateMeasureOperation;
void InvalidateMeasure(DispatcherPriority priority)
{
if (priority >= DispatcherPriority.Render) {
if (invalidateMeasureOperation != null) {
invalidateMeasureOperation.Abort();
invalidateMeasureOperation = null;
}
base.InvalidateMeasure();
} else {
if (invalidateMeasureOperation != null) {
invalidateMeasureOperation.Priority = priority;
} else {
invalidateMeasureOperation = Dispatcher.BeginInvoke(
priority,
new Action(
delegate {
invalidateMeasureOperation = null;
base.InvalidateMeasure();
}
)
);
}
}
}
#endregion
#region Get(OrConstruct)VisualLine
/// <summary>
/// Gets the visual line that contains the document line with the specified number.
/// Returns null if the document line is outside the visible range.
/// </summary>
public VisualLine GetVisualLine(int documentLineNumber)
{
// TODO: EnsureVisualLines() ?
foreach (VisualLine visualLine in allVisualLines) {
Debug.Assert(visualLine.IsDisposed == false);
int start = visualLine.FirstDocumentLine.LineNumber;
int end = visualLine.LastDocumentLine.LineNumber;
if (documentLineNumber >= start && documentLineNumber <= end)
return visualLine;
}
return null;
}
/// <summary>
/// Gets the visual line that contains the document line with the specified number.
/// If that line is outside the visible range, a new VisualLine for that document line is constructed.
/// </summary>
public VisualLine GetOrConstructVisualLine(DocumentLine documentLine)
{
if (documentLine == null)
throw new ArgumentNullException("documentLine");
if (!this.Document.Lines.Contains(documentLine))
throw new InvalidOperationException("Line belongs to wrong document");
VerifyAccess();
VisualLine l = GetVisualLine(documentLine.LineNumber);
if (l == null) {
TextRunProperties globalTextRunProperties = CreateGlobalTextRunProperties();
VisualLineTextParagraphProperties paragraphProperties = CreateParagraphProperties(globalTextRunProperties);
while (heightTree.GetIsCollapsed(documentLine.LineNumber)) {
documentLine = documentLine.PreviousLine;
}
l = BuildVisualLine(documentLine,
globalTextRunProperties, paragraphProperties,
elementGenerators.ToArray(), lineTransformers.ToArray(),
lastAvailableSize);
allVisualLines.Add(l);
// update all visual top values (building the line might have changed visual top of other lines due to word wrapping)
foreach (var line in allVisualLines) {
line.VisualTop = heightTree.GetVisualPosition(line.FirstDocumentLine);
}
}
return l;
}
#endregion
#region Visual Lines (fields and properties)
List<VisualLine> allVisualLines = new List<VisualLine>();
ReadOnlyCollection<VisualLine> visibleVisualLines;
double clippedPixelsOnTop;
List<VisualLine> newVisualLines;
/// <summary>
/// Gets the currently visible visual lines.
/// </summary>
/// <exception cref="VisualLinesInvalidException">
/// Gets thrown if there are invalid visual lines when this property is accessed.
/// You can use the <see cref="VisualLinesValid"/> property to check for this case,
/// or use the <see cref="EnsureVisualLines()"/> method to force creating the visual lines
/// when they are invalid.
/// </exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
public ReadOnlyCollection<VisualLine> VisualLines {
get {
if (visibleVisualLines == null)
throw new VisualLinesInvalidException();
return visibleVisualLines;
}
}
/// <summary>
/// Gets whether the visual lines are valid.
/// Will return false after a call to Redraw().
/// Accessing the visual lines property will cause a <see cref="VisualLinesInvalidException"/>
/// if this property is <c>false</c>.
/// </summary>
public bool VisualLinesValid {
get { return visibleVisualLines != null; }
}
/// <summary>
/// Occurs when the TextView is about to be measured and will regenerate its visual lines.
/// This event may be used to mark visual lines as invalid that would otherwise be reused.
/// </summary>
public event EventHandler<VisualLineConstructionStartEventArgs> VisualLineConstructionStarting;
/// <summary>
/// Occurs when the TextView was measured and changed its visual lines.
/// </summary>
public event EventHandler VisualLinesChanged;
/// <summary>
/// If the visual lines are invalid, creates new visual lines for the visible part
/// of the document.
/// If all visual lines are valid, this method does nothing.
/// </summary>
/// <exception cref="InvalidOperationException">The visual line build process is already running.
/// It is not allowed to call this method during the construction of a visual line.</exception>
public void EnsureVisualLines()
{
Dispatcher.VerifyAccess();
if (inMeasure)
throw new InvalidOperationException("The visual line build process is already running! Cannot EnsureVisualLines() during Measure!");
if (!VisualLinesValid) {
// increase priority for re-measure
InvalidateMeasure(DispatcherPriority.Normal);
// force immediate re-measure
UpdateLayout();
}
// Sometimes we still have invalid lines after UpdateLayout - work around the problem
// by calling MeasureOverride directly.
if (!VisualLinesValid) {
Debug.WriteLine("UpdateLayout() failed in EnsureVisualLines");
MeasureOverride(lastAvailableSize);
}
if (!VisualLinesValid)
throw new VisualLinesInvalidException("Internal error: visual lines invalid after EnsureVisualLines call");
}
#endregion
#region Measure
/// <summary>
/// Additonal amount that allows horizontal scrolling past the end of the longest line.
/// This is necessary to ensure the caret always is visible, even when it is at the end of the longest line.
/// </summary>
const double AdditionalHorizontalScrollAmount = 3;
Size lastAvailableSize;
bool inMeasure;
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
// We don't support infinite available width, so we'll limit it to 32000 pixels.
if (availableSize.Width > 32000)
availableSize.Width = 32000;
if (!canHorizontallyScroll && !availableSize.Width.IsClose(lastAvailableSize.Width))
ClearVisualLines();
lastAvailableSize = availableSize;
foreach (UIElement layer in layers) {
layer.Measure(availableSize);
}
MeasureInlineObjects();
InvalidateVisual(); // = InvalidateArrange+InvalidateRender
double maxWidth;
if (document == null) {
// no document -> create empty list of lines
allVisualLines = new List<VisualLine>();
visibleVisualLines = allVisualLines.AsReadOnly();
maxWidth = 0;
} else {
inMeasure = true;
try {
maxWidth = CreateAndMeasureVisualLines(availableSize);
} finally {
inMeasure = false;
}
}
// remove inline objects only at the end, so that inline objects that were re-used are not removed from the editor
RemoveInlineObjectsNow();
maxWidth += AdditionalHorizontalScrollAmount;
double heightTreeHeight = this.DocumentHeight;
TextEditorOptions options = this.Options;
if (options.AllowScrollBelowDocument) {
if (!double.IsInfinity(scrollViewport.Height)) {
heightTreeHeight = Math.Max(heightTreeHeight, Math.Min(heightTreeHeight - 50, scrollOffset.Y) + scrollViewport.Height);
}
}
textLayer.SetVisualLines(visibleVisualLines);
SetScrollData(availableSize,
new Size(maxWidth, heightTreeHeight),
scrollOffset);
if (VisualLinesChanged != null)
VisualLinesChanged(this, EventArgs.Empty);
return new Size(Math.Min(availableSize.Width, maxWidth), Math.Min(availableSize.Height, heightTreeHeight));
}
/// <summary>
/// Build all VisualLines in the visible range.
/// </summary>
/// <returns>Width the longest line</returns>
double CreateAndMeasureVisualLines(Size availableSize)
{
TextRunProperties globalTextRunProperties = CreateGlobalTextRunProperties();
VisualLineTextParagraphProperties paragraphProperties = CreateParagraphProperties(globalTextRunProperties);
Debug.WriteLine("Measure availableSize=" + availableSize + ", scrollOffset=" + scrollOffset);
var firstLineInView = heightTree.GetLineByVisualPosition(scrollOffset.Y);
// number of pixels clipped from the first visual line(s)
clippedPixelsOnTop = scrollOffset.Y - heightTree.GetVisualPosition(firstLineInView);
// clippedPixelsOnTop should be >= 0, except for floating point inaccurracy.
Debug.Assert(clippedPixelsOnTop >= -ExtensionMethods.Epsilon);
newVisualLines = new List<VisualLine>();
if (VisualLineConstructionStarting != null)
VisualLineConstructionStarting(this, new VisualLineConstructionStartEventArgs(firstLineInView));
var elementGeneratorsArray = elementGenerators.ToArray();
var lineTransformersArray = lineTransformers.ToArray();
var nextLine = firstLineInView;
double maxWidth = 0;
double yPos = -clippedPixelsOnTop;
while (yPos < availableSize.Height && nextLine != null) {
VisualLine visualLine = GetVisualLine(nextLine.LineNumber);
if (visualLine == null) {
visualLine = BuildVisualLine(nextLine,
globalTextRunProperties, paragraphProperties,
elementGeneratorsArray, lineTransformersArray,
availableSize);
}
visualLine.VisualTop = scrollOffset.Y + yPos;
nextLine = visualLine.LastDocumentLine.NextLine;
yPos += visualLine.Height;
foreach (TextLine textLine in visualLine.TextLines) {
if (textLine.WidthIncludingTrailingWhitespace > maxWidth)
maxWidth = textLine.WidthIncludingTrailingWhitespace;
}
newVisualLines.Add(visualLine);
}
foreach (VisualLine line in allVisualLines) {
Debug.Assert(line.IsDisposed == false);
if (!newVisualLines.Contains(line))
DisposeVisualLine(line);
}
allVisualLines = newVisualLines;
// visibleVisualLines = readonly copy of visual lines
visibleVisualLines = new ReadOnlyCollection<VisualLine>(newVisualLines.ToArray());
newVisualLines = null;
if (allVisualLines.Any(line => line.IsDisposed)) {
throw new InvalidOperationException("A visual line was disposed even though it is still in use.\n" +
"This can happen when Redraw() is called during measure for lines " +
"that are already constructed.");
}
return maxWidth;
}
#endregion
#region BuildVisualLine
TextFormatter formatter;
internal TextViewCachedElements cachedElements;
TextRunProperties CreateGlobalTextRunProperties()
{
var p = new GlobalTextRunProperties();
p.typeface = this.CreateTypeface();
p.fontRenderingEmSize = FontSize;
p.foregroundBrush = (Brush)GetValue(Control.ForegroundProperty);
ExtensionMethods.CheckIsFrozen(p.foregroundBrush);
p.cultureInfo = CultureInfo.CurrentCulture;
return p;
}
VisualLineTextParagraphProperties CreateParagraphProperties(TextRunProperties defaultTextRunProperties)
{
return new VisualLineTextParagraphProperties {
defaultTextRunProperties = defaultTextRunProperties,
textWrapping = canHorizontallyScroll ? TextWrapping.NoWrap : TextWrapping.Wrap,
tabSize = Options.IndentationSize * WideSpaceWidth
};
}
VisualLine BuildVisualLine(DocumentLine documentLine,
TextRunProperties globalTextRunProperties,
VisualLineTextParagraphProperties paragraphProperties,
VisualLineElementGenerator[] elementGeneratorsArray,
IVisualLineTransformer[] lineTransformersArray,
Size availableSize)
{
if (heightTree.GetIsCollapsed(documentLine.LineNumber))
throw new InvalidOperationException("Trying to build visual line from collapsed line");
Debug.WriteLine("Building line " + documentLine.LineNumber);
VisualLine visualLine = new VisualLine(this, documentLine);
VisualLineTextSource textSource = new VisualLineTextSource(visualLine) {
Document = document,
GlobalTextRunProperties = globalTextRunProperties,
TextView = this
};
visualLine.ConstructVisualElements(textSource, elementGeneratorsArray);
if (visualLine.FirstDocumentLine != visualLine.LastDocumentLine) {
// Check whether the lines are collapsed correctly:
double firstLinePos = heightTree.GetVisualPosition(visualLine.FirstDocumentLine.NextLine);
double lastLinePos = heightTree.GetVisualPosition(visualLine.LastDocumentLine.NextLine ?? visualLine.LastDocumentLine);
if (!firstLinePos.IsClose(lastLinePos)) {
for (int i = visualLine.FirstDocumentLine.LineNumber + 1; i <= visualLine.LastDocumentLine.LineNumber; i++) {
if (!heightTree.GetIsCollapsed(i))
throw new InvalidOperationException("Line " + i + " was skipped by a VisualLineElementGenerator, but it is not collapsed.");
}
throw new InvalidOperationException("All lines collapsed but visual pos different - height tree inconsistency?");
}
}
visualLine.RunTransformers(textSource, lineTransformersArray);
// now construct textLines:
int textOffset = 0;
TextLineBreak lastLineBreak = null;
var textLines = new List<TextLine>();
paragraphProperties.indent = 0;
paragraphProperties.firstLineInParagraph = true;
while (textOffset <= visualLine.VisualLengthWithEndOfLineMarker) {
TextLine textLine = formatter.FormatLine(
textSource,
textOffset,
availableSize.Width,
paragraphProperties,
lastLineBreak
);
textLines.Add(textLine);
textOffset += textLine.Length;
// exit loop so that we don't do the indentation calculation if there's only a single line
if (textOffset >= visualLine.VisualLengthWithEndOfLineMarker)
break;
if (paragraphProperties.firstLineInParagraph) {
paragraphProperties.firstLineInParagraph = false;
TextEditorOptions options = this.Options;
double indentation = 0;
if (options.InheritWordWrapIndentation) {
// determine indentation for next line:
int indentVisualColumn = GetIndentationVisualColumn(visualLine);
if (indentVisualColumn > 0 && indentVisualColumn < textOffset) {
indentation = textLine.GetDistanceFromCharacterHit(new CharacterHit(indentVisualColumn, 0));
}
}
indentation += options.WordWrapIndentation;
// apply the calculated indentation unless it's more than half of the text editor size:
if (indentation > 0 && indentation * 2 < availableSize.Width)
paragraphProperties.indent = indentation;
}
lastLineBreak = textLine.GetTextLineBreak();
}
visualLine.SetTextLines(textLines);
heightTree.SetHeight(visualLine.FirstDocumentLine, visualLine.Height);
return visualLine;
}
static int GetIndentationVisualColumn(VisualLine visualLine)
{
if (visualLine.Elements.Count == 0)
return 0;
int column = 0;
int elementIndex = 0;
VisualLineElement element = visualLine.Elements[elementIndex];
while (element.IsWhitespace(column)) {
column++;
if (column == element.VisualColumn + element.VisualLength) {
elementIndex++;
if (elementIndex == visualLine.Elements.Count)
break;
element = visualLine.Elements[elementIndex];
}
}
return column;
}
#endregion
#region Arrange
/// <summary>
/// Arrange implementation.
/// </summary>
protected override Size ArrangeOverride(Size finalSize)
{
EnsureVisualLines();
foreach (UIElement layer in layers) {
layer.Arrange(new Rect(new Point(0, 0), finalSize));
}
if (document == null || allVisualLines.Count == 0)
return finalSize;
// validate scroll position
Vector newScrollOffset = scrollOffset;
if (scrollOffset.X + finalSize.Width > scrollExtent.Width) {
newScrollOffset.X = Math.Max(0, scrollExtent.Width - finalSize.Width);
}
if (scrollOffset.Y + finalSize.Height > scrollExtent.Height) {
newScrollOffset.Y = Math.Max(0, scrollExtent.Height - finalSize.Height);
}
if (SetScrollData(scrollViewport, scrollExtent, newScrollOffset))
InvalidateMeasure(DispatcherPriority.Normal);
//Debug.WriteLine("Arrange finalSize=" + finalSize + ", scrollOffset=" + scrollOffset);
// double maxWidth = 0;
if (visibleVisualLines != null) {
Point pos = new Point(-scrollOffset.X, -clippedPixelsOnTop);
foreach (VisualLine visualLine in visibleVisualLines) {
int offset = 0;
foreach (TextLine textLine in visualLine.TextLines) {
foreach (var span in textLine.GetTextRunSpans()) {
InlineObjectRun inline = span.Value as InlineObjectRun;
if (inline != null && inline.VisualLine != null) {
Debug.Assert(inlineObjects.Contains(inline));
double distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(offset, 0));
inline.Element.Arrange(new Rect(new Point(pos.X + distance, pos.Y), inline.Element.DesiredSize));
}
offset += span.Length;
}
pos.Y += textLine.Height;
}
}
}
InvalidateCursor();
return finalSize;
}
#endregion
#region Render
readonly ObserveAddRemoveCollection<IBackgroundRenderer> backgroundRenderers;
/// <summary>
/// Gets the list of background renderers.
/// </summary>
public IList<IBackgroundRenderer> BackgroundRenderers {
get { return backgroundRenderers; }
}
void BackgroundRenderer_Added(IBackgroundRenderer renderer)
{
ConnectToTextView(renderer);
InvalidateLayer(renderer.Layer);
}
void BackgroundRenderer_Removed(IBackgroundRenderer renderer)
{
DisconnectFromTextView(renderer);
InvalidateLayer(renderer.Layer);
}
/// <inheritdoc/>
protected override void OnRender(DrawingContext drawingContext)
{
RenderBackground(drawingContext, KnownLayer.Background);
foreach (var line in visibleVisualLines) {
Brush currentBrush = null;
int startVC = 0;
int length = 0;
foreach (var element in line.Elements) {
if (currentBrush == null || !currentBrush.Equals(element.BackgroundBrush)) {
if (currentBrush != null) {
BackgroundGeometryBuilder builder = new BackgroundGeometryBuilder();
builder.AlignToWholePixels = true;
builder.CornerRadius = 3;
foreach (var rect in BackgroundGeometryBuilder.GetRectsFromVisualSegment(this, line, startVC, startVC + length))
builder.AddRectangle(this, rect);
Geometry geometry = builder.CreateGeometry();
if (geometry != null) {
drawingContext.DrawGeometry(currentBrush, null, geometry);
}
}
startVC = element.VisualColumn;
length = element.DocumentLength;
currentBrush = element.BackgroundBrush;
} else {
length += element.VisualLength;
}
}
if (currentBrush != null) {
BackgroundGeometryBuilder builder = new BackgroundGeometryBuilder();
builder.AlignToWholePixels = true;
builder.CornerRadius = 3;
foreach (var rect in BackgroundGeometryBuilder.GetRectsFromVisualSegment(this, line, startVC, startVC + length))
builder.AddRectangle(this, rect);
Geometry geometry = builder.CreateGeometry();
if (geometry != null) {
drawingContext.DrawGeometry(currentBrush, null, geometry);
}
}
}
}
internal void RenderBackground(DrawingContext drawingContext, KnownLayer layer)
{
foreach (IBackgroundRenderer bg in backgroundRenderers) {
if (bg.Layer == layer) {
bg.Draw(this, drawingContext);
}
}
}
internal void ArrangeTextLayer(IList<VisualLineDrawingVisual> visuals)
{
Point pos = new Point(-scrollOffset.X, -clippedPixelsOnTop);
foreach (VisualLineDrawingVisual visual in visuals) {
TranslateTransform t = visual.Transform as TranslateTransform;
if (t == null || t.X != pos.X || t.Y != pos.Y) {
visual.Transform = new TranslateTransform(pos.X, pos.Y);
visual.Transform.Freeze();
}
pos.Y += visual.Height;
}
}
#endregion
#region IScrollInfo implementation
/// <summary>
/// Size of the document, in pixels.
/// </summary>
Size scrollExtent;
/// <summary>
/// Offset of the scroll position.
/// </summary>
Vector scrollOffset;
/// <summary>
/// Size of the viewport.
/// </summary>
Size scrollViewport;
void ClearScrollData()
{
SetScrollData(new Size(), new Size(), new Vector());
}
bool SetScrollData(Size viewport, Size extent, Vector offset)
{
if (!(viewport.IsClose(this.scrollViewport)
&& extent.IsClose(this.scrollExtent)
&& offset.IsClose(this.scrollOffset)))
{
this.scrollViewport = viewport;
this.scrollExtent = extent;
SetScrollOffset(offset);
this.OnScrollChange();
return true;
}
return false;
}
void OnScrollChange()
{
ScrollViewer scrollOwner = ((IScrollInfo)this).ScrollOwner;
if (scrollOwner != null) {
scrollOwner.InvalidateScrollInfo();
}
}
bool canVerticallyScroll;
bool IScrollInfo.CanVerticallyScroll {
get { return canVerticallyScroll; }
set {
if (canVerticallyScroll != value) {
canVerticallyScroll = value;
InvalidateMeasure(DispatcherPriority.Normal);
}
}
}
bool canHorizontallyScroll;
bool IScrollInfo.CanHorizontallyScroll {
get { return canHorizontallyScroll; }
set {
if (canHorizontallyScroll != value) {
canHorizontallyScroll = value;
ClearVisualLines();
InvalidateMeasure(DispatcherPriority.Normal);
}
}
}
double IScrollInfo.ExtentWidth {
get { return scrollExtent.Width; }
}
double IScrollInfo.ExtentHeight {
get { return scrollExtent.Height; }
}
double IScrollInfo.ViewportWidth {
get { return scrollViewport.Width; }
}
double IScrollInfo.ViewportHeight {
get { return scrollViewport.Height; }
}
/// <summary>
/// Gets the horizontal scroll offset.
/// </summary>
public double HorizontalOffset {
get { return scrollOffset.X; }
}
/// <summary>
/// Gets the vertical scroll offset.
/// </summary>
public double VerticalOffset {
get { return scrollOffset.Y; }
}
/// <summary>
/// Gets the scroll offset;
/// </summary>
public Vector ScrollOffset {
get { return scrollOffset; }
}
/// <summary>
/// Occurs when the scroll offset has changed.
/// </summary>
public event EventHandler ScrollOffsetChanged;
void SetScrollOffset(Vector vector)
{
if (!canHorizontallyScroll)
vector.X = 0;
if (!canVerticallyScroll)
vector.Y = 0;
if (!scrollOffset.IsClose(vector)) {
scrollOffset = vector;
if (ScrollOffsetChanged != null)
ScrollOffsetChanged(this, EventArgs.Empty);
}
}
ScrollViewer IScrollInfo.ScrollOwner { get; set; }
void IScrollInfo.LineUp()
{
((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y - DefaultLineHeight);
}
void IScrollInfo.LineDown()
{
((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y + DefaultLineHeight);
}
void IScrollInfo.LineLeft()
{
((IScrollInfo)this).SetHorizontalOffset(scrollOffset.X - WideSpaceWidth);
}
void IScrollInfo.LineRight()
{
((IScrollInfo)this).SetHorizontalOffset(scrollOffset.X + WideSpaceWidth);
}
void IScrollInfo.PageUp()
{
((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y - scrollViewport.Height);
}
void IScrollInfo.PageDown()
{
((IScrollInfo)this).SetVerticalOffset(scrollOffset.Y + scrollViewport.Height);
}
void IScrollInfo.PageLeft()
{
((IScrollInfo)this).SetHorizontalOffset(scrollOffset.X - scrollViewport.Width);
}
void IScrollInfo.PageRight()
{
((IScrollInfo)this).SetHorizontalOffset(scrollOffset.X + scrollViewport.Width);
}
void IScrollInfo.MouseWheelUp()
{
((IScrollInfo)this).SetVerticalOffset(
scrollOffset.Y - (SystemParameters.WheelScrollLines * DefaultLineHeight));
OnScrollChange();
}
void IScrollInfo.MouseWheelDown()
{
((IScrollInfo)this).SetVerticalOffset(
scrollOffset.Y + (SystemParameters.WheelScrollLines * DefaultLineHeight));
OnScrollChange();
}
void IScrollInfo.MouseWheelLeft()
{
((IScrollInfo)this).SetHorizontalOffset(
scrollOffset.X - (SystemParameters.WheelScrollLines * WideSpaceWidth));
OnScrollChange();
}
void IScrollInfo.MouseWheelRight()
{
((IScrollInfo)this).SetHorizontalOffset(
scrollOffset.X + (SystemParameters.WheelScrollLines * WideSpaceWidth));
OnScrollChange();
}
bool defaultTextMetricsValid;
double wideSpaceWidth; // Width of an 'x'. Used as basis for the tab width, and for scrolling.
double defaultLineHeight; // Height of a line containing 'x'. Used for scrolling.
double defaultBaseline; // Baseline of a line containing 'x'. Used for TextTop/TextBottom calculation.
/// <summary>
/// Gets the width of a 'wide space' (the space width used for calculating the tab size).
/// </summary>
/// <remarks>
/// This is the width of an 'x' in the current font.
/// We do not measure the width of an actual space as that would lead to tiny tabs in
/// some proportional fonts.
/// For monospaced fonts, this property will return the expected value, as 'x' and ' ' have the same width.
/// </remarks>
public double WideSpaceWidth {
get {
CalculateDefaultTextMetrics();
return wideSpaceWidth;
}
}
/// <summary>
/// Gets the default line height. This is the height of an empty line or a line containing regular text.
/// Lines that include formatted text or custom UI elements may have a different line height.
/// </summary>
public double DefaultLineHeight {
get {
CalculateDefaultTextMetrics();
return defaultLineHeight;
}
}
/// <summary>
/// Gets the default baseline position. This is the difference between <see cref="VisualYPosition.TextTop"/>
/// and <see cref="VisualYPosition.Baseline"/> for a line containing regular text.
/// Lines that include formatted text or custom UI elements may have a different baseline.
/// </summary>
public double DefaultBaseline {
get {
CalculateDefaultTextMetrics();
return defaultBaseline;
}
}
void InvalidateDefaultTextMetrics()
{
defaultTextMetricsValid = false;
if (heightTree != null) {
// calculate immediately so that height tree gets updated
CalculateDefaultTextMetrics();
}
}
void CalculateDefaultTextMetrics()
{
if (defaultTextMetricsValid)
return;
defaultTextMetricsValid = true;
if (formatter != null) {
var textRunProperties = CreateGlobalTextRunProperties();
using (var line = formatter.FormatLine(
new SimpleTextSource("x", textRunProperties),
0, 32000,
new VisualLineTextParagraphProperties { defaultTextRunProperties = textRunProperties },
null))
{
wideSpaceWidth = Math.Max(1, line.WidthIncludingTrailingWhitespace);
defaultBaseline = Math.Max(1, line.Baseline);
defaultLineHeight = Math.Max(1, line.Height);
}
} else {
wideSpaceWidth = FontSize / 2;
defaultBaseline = FontSize;
defaultLineHeight = FontSize + 3;
}
// Update heightTree.DefaultLineHeight, if a document is loaded.
if (heightTree != null)
heightTree.DefaultLineHeight = defaultLineHeight;
}
static double ValidateVisualOffset(double offset)
{
if (double.IsNaN(offset))
throw new ArgumentException("offset must not be NaN");
if (offset < 0)
return 0;
else
return offset;
}
void IScrollInfo.SetHorizontalOffset(double offset)
{
offset = ValidateVisualOffset(offset);
if (!scrollOffset.X.IsClose(offset)) {
SetScrollOffset(new Vector(offset, scrollOffset.Y));
InvalidateVisual();
textLayer.InvalidateVisual();
}
}
void IScrollInfo.SetVerticalOffset(double offset)
{
offset = ValidateVisualOffset(offset);
if (!scrollOffset.Y.IsClose(offset)) {
SetScrollOffset(new Vector(scrollOffset.X, offset));
InvalidateMeasure(DispatcherPriority.Normal);
}
}
Rect IScrollInfo.MakeVisible(Visual visual, Rect rectangle)
{
if (rectangle.IsEmpty || visual == null || visual == this || !this.IsAncestorOf(visual)) {
return Rect.Empty;
}
// Convert rectangle into our coordinate space.
GeneralTransform childTransform = visual.TransformToAncestor(this);
rectangle = childTransform.TransformBounds(rectangle);
MakeVisible(Rect.Offset(rectangle, scrollOffset));
return rectangle;
}
/// <summary>
/// Scrolls the text view so that the specified rectangle gets visible.
/// </summary>
public void MakeVisible(Rect rectangle)
{
Rect visibleRectangle = new Rect(scrollOffset.X, scrollOffset.Y,
scrollViewport.Width, scrollViewport.Height);
Vector newScrollOffset = scrollOffset;
if (rectangle.Left < visibleRectangle.Left) {
if (rectangle.Right > visibleRectangle.Right) {
newScrollOffset.X = rectangle.Left + rectangle.Width / 2;
} else {
newScrollOffset.X = rectangle.Left;
}
} else if (rectangle.Right > visibleRectangle.Right) {
newScrollOffset.X = rectangle.Right - scrollViewport.Width;
}
if (rectangle.Top < visibleRectangle.Top) {
if (rectangle.Bottom > visibleRectangle.Bottom) {
newScrollOffset.Y = rectangle.Top + rectangle.Height / 2;
} else {
newScrollOffset.Y = rectangle.Top;
}
} else if (rectangle.Bottom > visibleRectangle.Bottom) {
newScrollOffset.Y = rectangle.Bottom - scrollViewport.Height;
}
newScrollOffset.X = ValidateVisualOffset(newScrollOffset.X);
newScrollOffset.Y = ValidateVisualOffset(newScrollOffset.Y);
if (!scrollOffset.IsClose(newScrollOffset)) {
SetScrollOffset(newScrollOffset);
this.OnScrollChange();
InvalidateMeasure(DispatcherPriority.Normal);
}
}
#endregion
#region Visual element mouse handling
/// <inheritdoc/>
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
// accept clicks even where the text area draws no background
return new PointHitTestResult(this, hitTestParameters.HitPoint);
}
[ThreadStatic] static bool invalidCursor;
/// <summary>
/// Updates the mouse cursor by calling <see cref="Mouse.UpdateCursor"/>, but with input priority.
/// </summary>
public static void InvalidateCursor()
{
if (!invalidCursor) {
invalidCursor = true;
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Input,
new Action(
delegate {
invalidCursor = false;
Mouse.UpdateCursor();
}));
}
}
/// <inheritdoc/>
protected override void OnQueryCursor(QueryCursorEventArgs e)
{
VisualLineElement element = GetVisualLineElementFromPosition(e.GetPosition(this) + scrollOffset);
if (element != null) {
element.OnQueryCursor(e);
}
}
/// <inheritdoc/>
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
if (!e.Handled) {
EnsureVisualLines();
VisualLineElement element = GetVisualLineElementFromPosition(e.GetPosition(this) + scrollOffset);
if (element != null) {
element.OnMouseDown(e);
}
}
}
/// <inheritdoc/>
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
if (!e.Handled) {
EnsureVisualLines();
VisualLineElement element = GetVisualLineElementFromPosition(e.GetPosition(this) + scrollOffset);
if (element != null) {
element.OnMouseUp(e);
}
}
}
#endregion
#region Getting elements from Visual Position
/// <summary>
/// Gets the visual line at the specified document position (relative to start of document).
/// Returns null if there is no visual line for the position (e.g. the position is outside the visible
/// text area).
/// </summary>
public VisualLine GetVisualLineFromVisualTop(double visualTop)
{
// TODO: change this method to also work outside the visible range -
// required to make GetPosition work as expected!
EnsureVisualLines();
foreach (VisualLine vl in this.VisualLines) {
if (visualTop < vl.VisualTop)
continue;
if (visualTop < vl.VisualTop + vl.Height)
return vl;
}
return null;
}
/// <summary>
/// Gets the visual top position (relative to start of document) from a document line number.
/// </summary>
public double GetVisualTopByDocumentLine(int line)
{
VerifyAccess();
if (heightTree == null)
throw ThrowUtil.NoDocumentAssigned();
return heightTree.GetVisualPosition(heightTree.GetLineByNumber(line));
}
VisualLineElement GetVisualLineElementFromPosition(Point visualPosition)
{
VisualLine vl = GetVisualLineFromVisualTop(visualPosition.Y);
if (vl != null) {
int column = vl.GetVisualColumnFloor(visualPosition);
// Debug.WriteLine(vl.FirstDocumentLine.LineNumber + " vc " + column);
foreach (VisualLineElement element in vl.Elements) {
if (element.VisualColumn + element.VisualLength <= column)
continue;
return element;
}
}
return null;
}
#endregion
#region Visual Position <-> TextViewPosition
/// <summary>
/// Gets the visual position from a text view position.
/// </summary>
/// <param name="position">The text view position.</param>
/// <param name="yPositionMode">The mode how to retrieve the Y position.</param>
/// <returns>The position in WPF device-independent pixels relative
/// to the top left corner of the document.</returns>
public Point GetVisualPosition(TextViewPosition position, VisualYPosition yPositionMode)
{
VerifyAccess();
if (this.Document == null)
throw ThrowUtil.NoDocumentAssigned();
DocumentLine documentLine = this.Document.GetLineByNumber(position.Line);
VisualLine visualLine = GetOrConstructVisualLine(documentLine);
int visualColumn = position.VisualColumn;
if (visualColumn < 0) {
int offset = documentLine.Offset + position.Column - 1;
visualColumn = visualLine.GetVisualColumn(offset - visualLine.FirstDocumentLine.Offset);
}
return visualLine.GetVisualPosition(visualColumn, yPositionMode);
}
/// <summary>
/// Gets the text view position from the specified visual position.
/// If the position is within a character, it is rounded to the next character boundary.
/// </summary>
/// <param name="visualPosition">The position in WPF device-independent pixels relative
/// to the top left corner of the document.</param>
/// <returns>The logical position, or null if the position is outside the document.</returns>
public TextViewPosition? GetPosition(Point visualPosition)
{
VerifyAccess();
if (this.Document == null)
throw ThrowUtil.NoDocumentAssigned();
VisualLine line = GetVisualLineFromVisualTop(visualPosition.Y);
if (line == null)
return null;
int visualColumn = line.GetVisualColumn(visualPosition);
int documentOffset = line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
return new TextViewPosition(document.GetLocation(documentOffset), visualColumn);
}
/// <summary>
/// Gets the text view position from the specified visual position.
/// If the position is inside a character, the position in front of the character is returned.
/// </summary>
/// <param name="visualPosition">The position in WPF device-independent pixels relative
/// to the top left corner of the document.</param>
/// <returns>The logical position, or null if the position is outside the document.</returns>
public TextViewPosition? GetPositionFloor(Point visualPosition)
{
VerifyAccess();
if (this.Document == null)
throw ThrowUtil.NoDocumentAssigned();
VisualLine line = GetVisualLineFromVisualTop(visualPosition.Y);
if (line == null)
return null;
int visualColumn = line.GetVisualColumnFloor(visualPosition);
int documentOffset = line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
return new TextViewPosition(document.GetLocation(documentOffset), visualColumn);
}
#endregion
#region Service Provider
readonly ServiceContainer services = new ServiceContainer();
/// <summary>
/// Gets a service container used to associate services with the text view.
/// </summary>
public ServiceContainer Services {
get { return services; }
}
object IServiceProvider.GetService(Type serviceType)
{
return services.GetService(serviceType);
}
void ConnectToTextView(object obj)
{
ITextViewConnect c = obj as ITextViewConnect;
if (c != null)
c.AddToTextView(this);
}
void DisconnectFromTextView(object obj)
{
ITextViewConnect c = obj as ITextViewConnect;
if (c != null)
c.RemoveFromTextView(this);
}
#endregion
#region MouseHover
/// <summary>
/// The PreviewMouseHover event.
/// </summary>
public static readonly RoutedEvent PreviewMouseHoverEvent =
EventManager.RegisterRoutedEvent("PreviewMouseHover", RoutingStrategy.Tunnel,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// The MouseHover event.
/// </summary>
public static readonly RoutedEvent MouseHoverEvent =
EventManager.RegisterRoutedEvent("MouseHover", RoutingStrategy.Bubble,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// The PreviewMouseHoverStopped event.
/// </summary>
public static readonly RoutedEvent PreviewMouseHoverStoppedEvent =
EventManager.RegisterRoutedEvent("PreviewMouseHoverStopped", RoutingStrategy.Tunnel,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// The MouseHoverStopped event.
/// </summary>
public static readonly RoutedEvent MouseHoverStoppedEvent =
EventManager.RegisterRoutedEvent("MouseHoverStopped", RoutingStrategy.Bubble,
typeof(MouseEventHandler), typeof(TextView));
/// <summary>
/// Occurs when the mouse has hovered over a fixed location for some time.
/// </summary>
public event MouseEventHandler PreviewMouseHover {
add { AddHandler(PreviewMouseHoverEvent, value); }
remove { RemoveHandler(PreviewMouseHoverEvent, value); }
}
/// <summary>
/// Occurs when the mouse has hovered over a fixed location for some time.
/// </summary>
public event MouseEventHandler MouseHover {
add { AddHandler(MouseHoverEvent, value); }
remove { RemoveHandler(MouseHoverEvent, value); }
}
/// <summary>
/// Occurs when the mouse had previously hovered but now started moving again.
/// </summary>
public event MouseEventHandler PreviewMouseHoverStopped {
add { AddHandler(PreviewMouseHoverStoppedEvent, value); }
remove { RemoveHandler(PreviewMouseHoverStoppedEvent, value); }
}
/// <summary>
/// Occurs when the mouse had previously hovered but now started moving again.
/// </summary>
public event MouseEventHandler MouseHoverStopped {
add { AddHandler(MouseHoverStoppedEvent, value); }
remove { RemoveHandler(MouseHoverStoppedEvent, value); }
}
MouseHoverLogic hoverLogic;
void RaiseHoverEventPair(MouseEventArgs e, RoutedEvent tunnelingEvent, RoutedEvent bubblingEvent)
{
var mouseDevice = e.MouseDevice;
var stylusDevice = e.StylusDevice;
int inputTime = Environment.TickCount;
var args1 = new MouseEventArgs(mouseDevice, inputTime, stylusDevice) {
RoutedEvent = tunnelingEvent,
Source = this
};
RaiseEvent(args1);
var args2 = new MouseEventArgs(mouseDevice, inputTime, stylusDevice) {
RoutedEvent = bubblingEvent,
Source = this,
Handled = args1.Handled
};
RaiseEvent(args2);
}
#endregion
/// <summary>
/// Collapses lines for the purpose of scrolling. <see cref="DocumentLine"/>s marked as collapsed will be hidden
/// and not used to start the generation of a <see cref="VisualLine"/>.
/// </summary>
/// <remarks>
/// This method is meant for <see cref="VisualLineElementGenerator"/>s that cause <see cref="VisualLine"/>s to span
/// multiple <see cref="DocumentLine"/>s. Do not call it without providing a corresponding
/// <see cref="VisualLineElementGenerator"/>.
/// If you want to create collapsible text sections, see <see cref="Folding.FoldingManager"/>.
///
/// Note that if you want a VisualLineElement to span from line N to line M, then you need to collapse only the lines
/// N+1 to M. Do not collapse line N itself.
///
/// When you no longer need the section to be collapsed, call <see cref="CollapsedLineSection.Uncollapse()"/> on the
/// <see cref="CollapsedLineSection"/> returned from this method.
/// </remarks>
public CollapsedLineSection CollapseLines(DocumentLine start, DocumentLine end)
{
VerifyAccess();
if (heightTree == null)
throw ThrowUtil.NoDocumentAssigned();
return heightTree.CollapseText(start, end);
}
/// <summary>
/// Gets the height of the document.
/// </summary>
public double DocumentHeight {
get {
// return 0 if there is no document = no heightTree
return heightTree != null ? heightTree.TotalHeight : 0;
}
}
/// <summary>
/// Gets the document line at the specified visual position.
/// </summary>
public DocumentLine GetDocumentLineByVisualTop(double visualTop)
{
VerifyAccess();
if (heightTree == null)
throw ThrowUtil.NoDocumentAssigned();
return heightTree.GetLineByVisualPosition(visualTop);
}
/// <inheritdoc/>
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (TextFormatterFactory.PropertyChangeAffectsTextFormatter(e.Property)) {
// first, create the new text formatter:
RecreateTextFormatter();
// changing text formatter requires recreating the cached elements
RecreateCachedElements();
// and we need to re-measure the font metrics:
InvalidateDefaultTextMetrics();
} else if (e.Property == Control.ForegroundProperty
|| e.Property == TextView.NonPrintableCharacterBrushProperty
|| e.Property == TextView.LinkTextBackgroundBrushProperty
|| e.Property == TextView.LinkTextForegroundBrushProperty)
{
// changing brushes requires recreating the cached elements
RecreateCachedElements();
Redraw();
}
if (e.Property == Control.FontFamilyProperty
|| e.Property == Control.FontSizeProperty
|| e.Property == Control.FontStretchProperty
|| e.Property == Control.FontStyleProperty
|| e.Property == Control.FontWeightProperty)
{
// changing font properties requires recreating cached elements
RecreateCachedElements();
// and we need to re-measure the font metrics:
InvalidateDefaultTextMetrics();
Redraw();
}
if (e.Property == ColumnRulerPenProperty) {
columnRulerRenderer.SetRuler(this.Options.ColumnRulerPosition, this.ColumnRulerPen);
}
}
/// <summary>
/// The pen used to draw the column ruler.
/// <seealso cref="TextEditorOptions.ShowColumnRuler"/>
/// </summary>
public static readonly DependencyProperty ColumnRulerPenProperty =
DependencyProperty.Register("ColumnRulerBrush", typeof(Pen), typeof(TextView),
new FrameworkPropertyMetadata(CreateFrozenPen(Brushes.LightGray)));
static Pen CreateFrozenPen(SolidColorBrush brush)
{
Pen pen = new Pen(brush, 1);
pen.Freeze();
return pen;
}
/// <summary>
/// Gets/Sets the pen used to draw the column ruler.
/// <seealso cref="TextEditorOptions.ShowColumnRuler"/>
/// </summary>
public Pen ColumnRulerPen {
get { return (Pen)GetValue(ColumnRulerPenProperty); }
set { SetValue(ColumnRulerPenProperty, value); }
}
}
}
|