EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: DiTBho on January 03, 2021, 03:08:32 pm

Title: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 03, 2021, 03:08:32 pm
So I am playing with SDL on a machine that doesn't have X11 installed.
My goal is to write a very simple and basic application for sketching and note taking on a Linux-PDA using a stylus.

SDL_GetMouseState(&x, &y) points to "/dev/input/event1", but it returns rotated coordinates (x,y).
I am using "tslib" and I have already launched the "ts_calibrate tool", but it doesn't solve the problem. I correctly see things on the screen, but when I touch the touchscreen ... (x,y) are returned rotated like if I was touching the screen anti clockwise rotated.

Weird, and I am a bit lost with that.

Does anyone happen to have experience with that?
Thanks  :D
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 03, 2021, 03:42:35 pm
Do you have the necessary environment variables set?
    TSLIB_TSDEVICE=/dev/input/event1
    TSLIB_TSEVENTTYPE=INPUT
    TSLIB_CONFFILE=path to tslib configuration file
    TSLIB_CALIBFILE=path to tslib calibration file
    SDL_MOUSEDRV=TSLIB
    SDL_MOUSEDEV=/dev/input/event1
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 03, 2021, 04:57:27 pm
Code: [Select]
export SDL_VIDEO_FBCON_ROTATION="NONE"
export SDL_TOUCHSCREEN=1
export SDL_VIDEODRIVER=fbcon
export SDL_FBDEV=/dev/fb0
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_CONSOLEDEVICE="none"
export TSLIB_TSDEVICE=/dev/input/event1
export TSLIB_TSEVENTTYPE=INPUT
export TSLIB_CONFFILE=/etc/ts.conf       #path to tslib configuration file
export TSLIB_CALIBFILE=/etc/pointercal   #path to tslib calibration file
export SDL_MOUSEDRV=TSLIB
export SDL_MOUSEDEV=/dev/input/event1

mostly yes, but I had to add these two  :D

Code: [Select]
export SDL_MOUSEDRV=TSLIB
export SDL_MOUSEDEV=/dev/input/event1

Now it works, I mean the (x,y) are not rotated, but ... coordinates are noisy, and the five buttons on the screen don't work.

Umm, I wonder why (x,y) are covered by noise, and what I can do to solve it
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 03, 2021, 05:10:34 pm
what is this?

Code: [Select]
VT=7
...
chvt $VT

I found it in an old example before invoking the SDL app

Code: [Select]
NAME
       chvt - change foreground virtual terminal

SYNOPSIS
       chvt N

DESCRIPTION
       The  command chvt N makes /dev/ttyN the foreground terminal.  (The corresponding screen is created if
       it did not exist yet.  To get rid of unused VTs, use deallocvt(1).)  The key combination (Ctrl-)Left-
       Alt-FN (with N in the range 1-12) usually has a similar effe
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 03, 2021, 06:36:27 pm
Now it works, I mean the (x,y) are not rotated, but ... coordinates are noisy, and the five buttons on the screen don't work.
Better not use tslib, then.  If I were you, I'd adjust the coordinates in your SDL application.

Basically, the six floating-point values c1, ..., c6 are used to obtain xuse and yuse from xraw and yraw via
    xuse = c1 xraw + c2 yraw + c3
    yuse = c4 xraw + c5 yraw + c6

By default, c1 = c5 = 1, and c2 = c3 = c4 = c6 = 0.  (That is, c = { 1, 0, 0, 0, 1, 0 };.)

Use a command-line parameter to define the six floating-point numbers. Then it is just a matter of fine-tuning it to get touch coordinates correct; probably 0 1 0 -1 0 H or 0 -1 W 0 1 0 0, where W is the display width, and H is the display height.

This way the display buttons should still work, and you can compensate for the touch coordinates within your SDL application using a command-line option.

Something like
Code: [Select]
static double  xytrans[6] = { 1.0, 0.0, 0.0,  0.0, 1.0, 0.0 };

static inline Uint32 GetMouse(int *xp, int *yp)
{
    Uint32  retval;
    int  xc, int yc;

    retval = SDL_GetGlobalMouseState(&xc, &yc);
    if (xp) *xp = (int)( xc*xytrans[0] + yc*xytrans[1] + xytrans[2]);
    if (yp) *yp = (int)( xc*xytrans[3] + yc*xytrans[4] + xytrans[5]);

    return retval;
}

static int parse_xytrans(const char *from)
{
    double c[6] = { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0 };
    const char *next;
    if (!from)
        return errno = EINVAL;
    for (int i = 0; i < 6; i++) {
        const char *next = from;
        errno = 0;
        c[i] = strtod(curr, (char **)(&next));
        if (errno)
            return errno;
        if (next == from)
            return errno = EINVAL;
        from = next;
        if (*from == ':')
            from++;
    }
    if (*from != '\0')
        return errno = EINVAL;

    for (int i = 0; i < 6; i++)
        xytrans[i] = c[i];

    return 0;
}
where you use GetMouse(&x,&y) instead of SDL_Get*MouseState(&x,&y).

When parsing command line options (or an environment variable), just pass the string to parse_xytrans().  If it returns zero, it had an acceptable transform, otherwise the current transform is unchanged.  (The components can be separated by whitespace or by a colon, so the default can be written as e.g "1:0:0:0:1:0" or "1+0+0:0+1+0".)

what is this?

Code: [Select]
VT=7
...
chvt $VT

I found it in an old example before invoking the SDL app
It switches to a specific console (/dev/tty7), just as if you pressed Alt+F7 on the console terminal.  The first few consoles (/dev/tty1 and up) usually have a console login (getty) running, and that makes sure the SDL application does not interfere with those.  X11 and Wayland etc. do the same.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 04, 2021, 06:11:45 pm
Now it works in a "usable way" :D


I wonder, is there a way to have two layers with SDL?

I'd like to load a bitmap on layer0, and to draw on layer1, with layer1 displayed on the top of layer0, but with its pixels not "fused" with layer0.

So basically I want to save layer1 to a dedicated file.

What do you think about this?
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 05, 2021, 05:23:11 am
I wonder, is there a way to have two layers with SDL?
Of course, except SDL talks about SDL_Surfaces instead.  Consider the following example.c:
Code: [Select]
// SPDX-License-Identifier: CC0-1.0

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "SDL.h"
#include "SDL_image.h"

/* Surface-specific RGB color; use 0xRRGGBB for HTML color #RRGGBB. */
static inline Uint32 RGB(SDL_Surface *s, unsigned int rgb)
{
    return SDL_MapRGB(s->format, (rgb >> 16) & 255, (rgb >> 8) & 255, rgb & 255);
}

/* Surface-specific RGBA color; use 0xRRGGBBAA for HTML color #RRGGBB with opacity 0xAA/255. */
static inline Uint32 RGBA(SDL_Surface *s, unsigned int rgba)
{
    return SDL_MapRGBA(s->format, (rgba >> 24) & 255, (rgba >> 16) & 255, (rgba >> 8) & 255, rgba & 255);
}

int main(int argc, char *argv[])
{
    if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        const char *arg0 = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", arg0);
        fprintf(stderr, "       %s IMAGE-FILE\n", arg0);
        fprintf(stderr, "\n");
        return EXIT_FAILURE;
    }

    /* Initialize SDL. */
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) == -1) {
        fprintf(stderr, "Cannot initialize SDL2: %s.\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    /* Default to best possible scaling. */
    SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, "2", SDL_HINT_DEFAULT);

    /* Load the desired image file. */
    SDL_Surface  *image = IMG_Load(argv[1]);
    if (!image) {
        fprintf(stderr, "%s: %s.\n", argv[1], IMG_GetError());
        SDL_Quit();
        return EXIT_FAILURE;
    }
    if (SDL_SetSurfaceBlendMode(image, SDL_BLENDMODE_NONE)) {
        fprintf(stderr, "Image surface cannot be copied as is: %s.\n", SDL_GetError());
        SDL_FreeSurface(image);
        SDL_Quit();
        return EXIT_FAILURE;
    }

    /* Create a window using the image dimensions. */
    SDL_Window  *window = SDL_CreateWindow("Example",
                                           SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                                           image->w, image->h,
                                           SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
    if (!window) {
        fprintf(stderr, "Cannot create an SDL window (%dx%d): %s.\n",
                        image->w, image->h, SDL_GetError());
        SDL_FreeSurface(image);
        SDL_Quit();
        return EXIT_FAILURE;
    }

    /* Obtain the window surface (target).
       Note: This is owned by the window; never SDL_FreeSurface() this.
             This will also be invalidated if the window size changes.
    */
    SDL_Surface  *target = SDL_GetWindowSurface(window);
    if (!target) {
        fprintf(stderr, "Cannot obtain SDL window surface: %s.\n", SDL_GetError());
        SDL_DestroyWindow(window);
        SDL_FreeSurface(image);
        SDL_Quit();
        return EXIT_FAILURE;
    }
    /* Fill it initially with a neutral grey. */
    SDL_FillRect(target, NULL, RGB(target, 0xCCCCCC));


    /* TODO: Better bit depth and pixel format, optimized for current window?
             It should have alpha, unless we use color keying.
    */
    int  drawable_bitdepth = 32;
    int  drawable_format = SDL_PIXELFORMAT_RGBA32;

    /* Create a surface we can draw on.
       TODO: Better bit depth and pixel format for the given window? Should have alpha, though.
    */
    SDL_Surface  *drawable = SDL_CreateRGBSurfaceWithFormat(0, image->w, image->h,
                                                            drawable_bitdepth, drawable_format);
    if (!drawable) {
        fprintf(stderr, "Cannot create a drawable SDL surface: %s.\n", SDL_GetError());
        SDL_DestroyWindow(window);
        SDL_FreeSurface(image);
        SDL_Quit();
        return EXIT_FAILURE;
    }
    if (SDL_SetSurfaceBlendMode(drawable, SDL_BLENDMODE_BLEND) == -1) {
        fprintf(stderr, "Drawable SDL surface does not support alpha blending: %s.\n", SDL_GetError());
        SDL_FreeSurface(drawable);
        SDL_DestroyWindow(window);
        SDL_FreeSurface(image);
        SDL_Quit();
        return EXIT_FAILURE;
    }
    /* Clear the surface to transparent white. */
    SDL_FillRect(drawable, NULL, RGBA(drawable, 0xFFFFFF00));

    /* Main event loop */
    while (1) {
        SDL_Event  event;

        if (SDL_WaitEvent(&event) == 1) {
            if (event.type == SDL_QUIT) {
                break;
            } else
            if (event.type == SDL_MOUSEBUTTONDOWN) {
                if (event.button.button == SDL_BUTTON_LEFT) {
                    const SDL_Rect  r = { .x = event.button.x - 1, .y = event.button.y - 1, .w = 3, .h = 3 };
                    SDL_FillRect(drawable, &r, RGBA(drawable, 0xFF0000FF));
                }
            } else
            if (event.type == SDL_MOUSEMOTION) {
                if (event.motion.state & SDL_BUTTON_LMASK) {
                    SDL_Rect  r = { .x = event.motion.x, .y = event.motion.y, .w = 1, .h = 1 };
                    SDL_FillRect(drawable, &r, RGBA(drawable, 0xFF0000FF));
                }
            } else
            if (event.type == SDL_WINDOWEVENT) {
                if (event.window.event == SDL_WINDOWEVENT_RESIZED ||
                    event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
                    int  new_width = event.window.data1;
                    int  new_height = event.window.data2;

                    /* The old window surface was invalidated. Refresh it. */
                    target = SDL_GetWindowSurface(window);

                    /* And fill it with a neutral grey. */
                    SDL_FillRect(target, NULL, RGB(target, 0xCCCCCC));

                    /* Expand?  (We never shrink our drawable size, since it'd be lossy.) */
                    if (drawable->w < new_width || drawable->h < new_height) {
                        /* Don't shrink the drawable, as that'd be lossy. */
                        if (new_width < drawable->w)
                            new_width = drawable->w;
                        if (new_height < drawable->h)
                            new_height = drawable->h;

                        SDL_Surface  *new_drawable = SDL_CreateRGBSurfaceWithFormat(0, new_width, new_height,
                                                                                    drawable_bitdepth, drawable_format);
                        if (!new_drawable) {
                            fprintf(stderr, "Warning: Cannot extend drawable from %dx%d to %dx%d: %s.\n",
                                            drawable->w, drawable->h, new_width, new_height, SDL_GetError());
                        } else {
                            SDL_SetSurfaceBlendMode(new_drawable, SDL_BLENDMODE_BLEND);
                            SDL_FillRect(new_drawable, NULL, RGBA(new_drawable, 0xFFFFFF00));
                            /* Blit the current contents of the drawable to the new drawable, */
                            SDL_BlitSurface(drawable, NULL, new_drawable, NULL);
                            /* and replace it with this new one. */
                            SDL_FreeSurface(drawable);
                            drawable = new_drawable;
                        }
                    }
                }
            }
        }

        /* Assume all events require a window content update. Normally, we'd only do this if and only if
            event.type == SDL_WINDOWEVENT && (event.window.event == SDL_WINDOWEVENT_RESIZED ||
                                              event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ||
                                              event.window.event == SDL_WINDOWEVENT_SHOWN ||
                                              event.window.event == SDL_WINDOWEVENT_EXPOSED)
           but we'll keep things simple here. */

        /* Blit the underlying image there. */
        SDL_BlitSurface(image, NULL, target, NULL);

        /* Then blit the drawable on top. */
        SDL_BlitSurface(drawable, NULL, target, NULL);

        /* Finally, update window contents. */
        SDL_UpdateWindowSurface(window);
    }

    /* We could save the drawable as an image here. */

    SDL_FreeSurface(drawable);
    SDL_DestroyWindow(window);
    SDL_FreeSurface(image);
    SDL_Quit();
    return EXIT_SUCCESS;
}


I use the following Makefile for it:
Code: [Select]
CC      := gcc
CFLAGS  := -Wall -Wextra -O2 `pkg-config --cflags sdl2 SDL2_image`
LDFLAGS := `pkg-config --libs sdl2 SDL2_image`
PROGS   := example

.PHONY: all clean

all: clean $(PROGS)

clean:
rm -f *.o $(PROGS)

example: example.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@

It is safe to run sed -e 's|^  *|\t|' -i Makefile to fix the tab-indentation on it.Run
    make clean all
to build the example.

To run the example, supply a path to some image to use as a basis, say
    ./example $(find /usr/share/backgrounds/ -name '*.png' -o -name '*.jpg' | sort -R | head -n 1)
Left-clicking leaves small red droppings on the image.  If you add code to save the drawable surface to a file (using SDL_image), it will only have those red droppings.  You'll want to use PNG, to keep the alpha channel.

No, I did not do your work for you.  ;)

You'll notice it is slow, not very responsive. That is because redrawing the entire window contents when only a small part is changed is wasteful.  I also forgot to include the mouse/pointer coordinate transforms into it.

You should modify it so that the full window is only redrawn when a full window content update (certain SDL_WINDOWEVENTs) occurs.
When you draw something to the drawable, you save the SDL_Rect(s) that cover the modified area, and pass that/those instead of NULLs to the blit operations, so only the modified regions need to be transferred.

If you don't need alpha blending, investigate SDL_SetColorKey (https://wiki.libsdl.org/SDL_SetColorKey) on the drawable surface.  Could be faster.

If you want better use of hardware acceleration, you'll need to use an SDL_Renderer and SDL_Textures instead of SDL_Surfaces.  I don't know how much faster/efficient it is than blitting SDL_Surfaces, though.

There's lots there to investigate and experiment with, to get a nice, snappy app you like; this really is just enough to get you going. ^-^
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: ebclr on January 05, 2021, 11:04:30 am
What is SDL ?
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Ed.Kloonk on January 05, 2021, 11:06:07 am
What is SDL ?

Quote
Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.

https://www.libsdl.org/ (https://www.libsdl.org/)
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 05, 2021, 12:45:58 pm
SDL can be used to create fullscreen and/or windowed games and (simple) applicationson.  It is not a widget toolkit like Gtk+, Qt, or FLTK, though; it provides a much simpler interface.

Embedded Linux devices can use SDL on a raw framebuffer, with OpenGL/OpenGL ES hardware acceleration, without X or Wayland.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: janoc on January 05, 2021, 12:57:20 pm
Now it works in a "usable way" :D


I wonder, is there a way to have two layers with SDL?

I'd like to load a bitmap on layer0, and to draw on layer1, with layer1 displayed on the top of layer0, but with its pixels not "fused" with layer0.

So basically I want to save layer1 to a dedicated file.

What do you think about this?

That is not really how SDL works. It is not Photoshop or Flash where you work in layers.

In SDL you have a Surface you draw into - which is usually an on screen window, texture or framebuffer. And you are running a loop that will clear the surface at the start, draw whatever is needed there and then flip the back buffer and front buffer (most of the time double buffering is used to avoid flicker) to actually display the new graphics. SDL is designed to redraw the entire screen on every frame - the same as most games, Vulkan, OpenGL or DirectX do.

So if you want to have "layers", you need to implement them yourself. You clear the surface, you draw one thing ("background") and then you draw the other "layers" on top, overwriting parts of what was drawn in the buffer already. E.g. an image or whatever you want. You can enable alpha blending too to make sure transparency ("cutouts") is handled correctly.

That is what the example given by Nominal Animal does.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 05, 2021, 04:14:53 pm
I am new to SDL, I haven't done anything similar before.

Today I have made some progress, but one thing is not clear: there are five buttons designed on the right-side of my LCD, their labels are { F1, F2, F3, F4, F5 }, so I tried to map them as { DLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5 }, but they are not recognized at all.

Code: [Select]
    case SDL_KEYDOWN:
        switch (event.key.keysym.sym)
        {
        case SDLK_ESCAPE:
            debug ("Escape pressed\n");
            return 1;
        case SDLK_1:
            debug ("1 pressed\n");
            clear_screen ();
            break;
            ...

I mean none of these "virtual? buttons" cause a event, while pressing physical buttons on the keyboard does cause event, and the code reacts as expected.

So I wonder what should I have to investigate. SDL? Some config? Or the kernel driver?  :-//
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 05, 2021, 05:56:04 pm
I mean none of these "virtual? buttons" cause a event, while pressing physical buttons on the keyboard does cause event, and the code reacts as expected.
First, run
Code: [Select]
for D in /sys/class/input/event* ; do echo "$D: " "'$(cat $D/device/name)'" ; done
to list all input event devices the machine knows about.  One of them should be the touch display; let's say event3.

Run, as root,
Code: [Select]
hexdump -C /dev/input/event3
and touch the display buttons.  Do you get any output?  There should be at least one event device that generates something when you touch the buttons.

On some of the display modules I have, there are four "icons" at the bottom edge of the display.  These are implemented simply by extending the touch sensor further than the display itself, with the icons drawn on the display glass (beneath the resistive touch surface).  They are not really buttons at all, just report higher Y coordinate than anything within the display itself.  So, to support these, one just treats them as mouse button (or touch) events that happen to occur outside the visible display region.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: janoc on January 05, 2021, 05:56:20 pm

I mean none of these "virtual? buttons" cause a event, while pressing physical buttons on the keyboard does cause event, and the code reacts as expected.

So I wonder what should I have to investigate. SDL? Some config? Or the kernel driver?  :-//

If it was to work "out of the box", that touchscreen would need to work as a HID device and feed keyboard/button press events to Linux - that's where SDL gets those from.

Print out all events you are getting (not only keyboard events - those buttons don't have to generate keyboard events!) and check whether you are getting anything at all when pressing those soft buttons. You will need to react to those events, that doesn't get automagically mapped to an arbitrary keyboard event you have found. They may not be (and likely aren't!) keyboard events at all, more like mouse buttons.

It is also well possible that there isn't anything generated at all. In that case Linux or SDL has no means to know that some part of your LCD is labeled as a soft button. That is up to you to manage, using the coordinates from the touchscreen.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 05, 2021, 06:20:48 pm
It's a very old kernel, and for a lot of reasons, I cannot upgrade it.
It's a 2.6.23.

The device folder contains this:

Code: [Select]
/sys/class/input/event0/device/
bus/          driver/       input:input0/ modalias      power/        subsystem/    uevent

There is no "name" exported, and there is no event2/event3, only these:

Code: [Select]
/dev/input/
by-path/ event0   event1 mice mouse0

:-//
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 05, 2021, 06:22:47 pm
On some of the display modules I have, there are four "icons" at the bottom edge of the display.  These are implemented simply by extending the touch sensor further than the display itself, with the icons drawn on the display glass (beneath the resistive touch surface).  They are not really buttons at all, just report higher Y coordinate than anything within the display itself.  So, to support these, one just treats them as mouse button (or touch) events that happen to occur outside the visible display region.

This seems my case, five "icons" at the the right edge of the display  :D
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 05, 2021, 06:26:22 pm
Code: [Select]
# hexdump -C /dev/input/event1


Code: [Select]
00000000  ed 5a f7 5f e0 0e 05 00  03 00 00 00 82 06 00 00  |.Z._............|
00000010  ed 5a f7 5f f7 0e 05 00  03 00 01 00 b7 06 00 00  |.Z._............|
00000020  ed 5a f7 5f fd 0e 05 00  03 00 18 00 7d 38 00 00  |.Z._........}8..|
00000030  ed 5a f7 5f 07 0f 05 00  00 00 00 00 00 00 00 00  |.Z._............|
00000040  ed 5a f7 5f ee 23 05 00  03 00 00 00 83 06 00 00  |.Z._.#..........|
00000050  ed 5a f7 5f fd 23 05 00  03 00 18 00 f0 31 00 00  |.Z._.#.......1..|
00000060  ed 5a f7 5f 07 24 05 00  00 00 00 00 00 00 00 00  |.Z._.$..........|
00000070  ed 5a f7 5f fe 4a 05 00  03 00 00 00 b4 06 00 00  |.Z._.J..........|
00000080  ed 5a f7 5f 0b 4b 05 00  03 00 01 00 93 06 00 00  |.Z._.K..........|
00000090  ed 5a f7 5f 10 4b 05 00  03 00 18 00 13 23 00 00  |.Z._.K.......#..|
000000a0  ed 5a f7 5f 19 4b 05 00  00 00 00 00 00 00 00 00  |.Z._.K..........|
000000b0  ed 5a f7 5f 08 72 05 00  03 00 00 00 d4 06 00 00  |.Z._.r..........|
000000c0  ed 5a f7 5f 13 72 05 00  03 00 01 00 4f 06 00 00  |.Z._.r......O...|
000000d0  ed 5a f7 5f 19 72 05 00  03 00 18 00 cb 23 00 00  |.Z._.r.......#..|
000000e0  ed 5a f7 5f 22 72 05 00  00 00 00 00 00 00 00 00  |.Z._"r..........|
000000f0  ed 5a f7 5f 97 e5 05 00  03 00 18 00 00 00 00 00  |.Z._............|
00000100  ed 5a f7 5f bd e5 05 00  00 00 00 00 00 00 00 00  |.Z._............|
00000110  ed 5a f7 5f 11 0e 06 00  03 00 00 00 ec 07 00 00  |.Z._............|
00000120  ed 5a f7 5f 34 0e 06 00  03 00 01 00 0a 07 00 00  |.Z._4...........|
00000130  ed 5a f7 5f 3a 0e 06 00  03 00 18 00 80 29 00 00  |.Z._:........)..|
00000140  ed 5a f7 5f 44 0e 06 00  00 00 00 00 00 00 00 00  |.Z._D...........|
00000150  ed 5a f7 5f 42 35 06 00  03 00 00 00 0a 08 00 00  |.Z._B5..........|
00000160  ed 5a f7 5f 66 35 06 00  03 00 01 00 26 07 00 00  |.Z._f5......&...|
00000170  ed 5a f7 5f 6b 35 06 00  03 00 18 00 8b 11 00 00  |.Z._k5..........|
00000180  ed 5a f7 5f 76 35 06 00  00 00 00 00 00 00 00 00  |.Z._v5..........|
00000190  ed 5a f7 5f 44 5c 06 00  03 00 00 00 10 08 00 00  |.Z._D\..........|
000001a0  ed 5a f7 5f 6a 5c 06 00  03 00 01 00 25 07 00 00  |.Z._j\......%...|
000001b0  ed 5a f7 5f 6f 5c 06 00  03 00 18 00 bc 11 00 00  |.Z._o\..........|
000001c0  ed 5a f7 5f 79 5c 06 00  00 00 00 00 00 00 00 00  |.Z._y\..........|
000001d0  ed 5a f7 5f 5c 83 06 00  03 00 00 00 17 08 00 00  |.Z._\...........|
000001e0  ed 5a f7 5f 81 83 06 00  03 00 01 00 1c 07 00 00  |.Z._............|
000001f0  ed 5a f7 5f 86 83 06 00  03 00 18 00 7b 17 00 00  |.Z._........{...|
00000200  ed 5a f7 5f 90 83 06 00  00 00 00 00 00 00 00 00  |.Z._............|
00000210  ed 5a f7 5f 62 aa 06 00  03 00 00 00 3b 08 00 00  |.Z._b.......;...|
00000220  ed 5a f7 5f 84 aa 06 00  03 00 01 00 2b 07 00 00  |.Z._........+...|
00000230  ed 5a f7 5f 8a aa 06 00  03 00 18 00 a0 11 00 00  |.Z._............|
00000240  ed 5a f7 5f 94 aa 06 00  00 00 00 00 00 00 00 00  |.Z._............|
00000250  ed 5a f7 5f 7d d1 06 00  03 00 00 00 4a 08 00 00  |.Z._}.......J...|
00000260  ed 5a f7 5f a0 d1 06 00  03 00 01 00 2f 07 00 00  |.Z._......../...|
00000270  ed 5a f7 5f a6 d1 06 00  03 00 18 00 fa 0f 00 00  |.Z._............|
00000280  ed 5a f7 5f b0 d1 06 00  00 00 00 00 00 00 00 00  |.Z._............|
00000290  ed 5a f7 5f 24 45 07 00  03 00 18 00 00 00 00 00  |.Z._$E..........|
000002a0  ed 5a f7 5f 4b 45 07 00  00 00 00 00 00 00 00 00  |.Z._KE..........|
000002b0  ed 5a f7 5f 17 5d 09 00  03 00 00 00 73 0a 00 00  |.Z._.]......s...|
000002c0  ed 5a f7 5f 3b 5d 09 00  03 00 01 00 fa 08 00 00  |.Z._;]..........|
000002d0  ed 5a f7 5f 41 5d 09 00  03 00 18 00 c3 32 00 00  |.Z._A].......2..|
000002e0  ed 5a f7 5f 4b 5d 09 00  00 00 00 00 00 00 00 00  |.Z._K]..........|
000002f0  ed 5a f7 5f b4 69 09 00  03 00 00 00 7d 0a 00 00  |.Z._.i......}...|
00000300  ed 5a f7 5f dc 69 09 00  03 00 01 00 fd 08 00 00  |.Z._.i..........|
00000310  ed 5a f7 5f e1 69 09 00  03 00 18 00 32 21 00 00  |.Z._.i......2!..|
00000320  ed 5a f7 5f eb 69 09 00  00 00 00 00 00 00 00 00  |.Z._.i..........|
00000330  ed 5a f7 5f 9d 90 09 00  03 00 00 00 81 0a 00 00  |.Z._............|
00000340  ed 5a f7 5f c2 90 09 00  03 00 01 00 0a 09 00 00  |.Z._............|
00000350  ed 5a f7 5f c7 90 09 00  03 00 18 00 d7 16 00 00  |.Z._............|
00000360  ed 5a f7 5f d1 90 09 00  00 00 00 00 00 00 00 00  |.Z._............|
00000370  ed 5a f7 5f a2 b7 09 00  03 00 00 00 80 0a 00 00  |.Z._............|
00000380  ed 5a f7 5f c5 b7 09 00  03 00 01 00 04 09 00 00  |.Z._............|
00000390  ed 5a f7 5f ca b7 09 00  03 00 18 00 51 12 00 00  |.Z._........Q...|
000003a0  ed 5a f7 5f d4 b7 09 00  00 00 00 00 00 00 00 00  |.Z._............|
000003b0  ed 5a f7 5f be de 09 00  03 00 00 00 86 0a 00 00  |.Z._............|
000003c0  ed 5a f7 5f e3 de 09 00  03 00 01 00 09 09 00 00  |.Z._............|
000003d0  ed 5a f7 5f e8 de 09 00  03 00 18 00 d4 10 00 00  |.Z._............|
000003e0  ed 5a f7 5f f2 de 09 00  00 00 00 00 00 00 00 00  |.Z._............|
000003f0  ed 5a f7 5f c4 05 0a 00  03 00 00 00 87 0a 00 00  |.Z._............|
00000400  ed 5a f7 5f e7 05 0a 00  03 00 01 00 e8 08 00 00  |.Z._............|
00000410  ed 5a f7 5f ec 05 0a 00  03 00 18 00 7f 10 00 00  |.Z._............|
00000420  ed 5a f7 5f f7 05 0a 00  00 00 00 00 00 00 00 00  |.Z._............|
00000430  ed 5a f7 5f dd 2c 0a 00  03 00 00 00 8c 0a 00 00  |.Z._.,..........|
00000440  ed 5a f7 5f 00 2d 0a 00  03 00 01 00 9c 08 00 00  |.Z._.-..........|
00000450  ed 5a f7 5f 06 2d 0a 00  03 00 18 00 23 0e 00 00  |.Z._.-......#...|
00000460  ed 5a f7 5f 10 2d 0a 00  00 00 00 00 00 00 00 00  |.Z._.-..........|
00000470  ed 5a f7 5f e0 53 0a 00  03 00 00 00 8a 0a 00 00  |.Z._.S..........|
00000480  ed 5a f7 5f 01 54 0a 00  03 00 01 00 70 08 00 00  |.Z._.T......p...|
00000490  ed 5a f7 5f 07 54 0a 00  03 00 18 00 cf 0b 00 00  |.Z._.T..........|
000004a0  ed 5a f7 5f 11 54 0a 00  00 00 00 00 00 00 00 00  |.Z._.T..........|
000004b0  ed 5a f7 5f fb 7a 0a 00  03 00 00 00 82 0a 00 00  |.Z._.z..........|
000004c0  ed 5a f7 5f 1f 7b 0a 00  03 00 01 00 58 08 00 00  |.Z._.{......X...|
000004d0  ed 5a f7 5f 24 7b 0a 00  03 00 18 00 26 0b 00 00  |.Z._${......&...|
000004e0  ed 5a f7 5f 2e 7b 0a 00  00 00 00 00 00 00 00 00  |.Z._.{..........|
000004f0  ed 5a f7 5f ff a1 0a 00  03 00 00 00 7c 0a 00 00  |.Z._........|...|
00000500  ed 5a f7 5f 20 a2 0a 00  03 00 01 00 37 08 00 00  |.Z._ .......7...|
00000510  ed 5a f7 5f 26 a2 0a 00  03 00 18 00 f1 0a 00 00  |.Z._&...........|
00000520  ed 5a f7 5f 30 a2 0a 00  00 00 00 00 00 00 00 00  |.Z._0...........|
00000530  ed 5a f7 5f 1d c9 0a 00  03 00 00 00 76 0a 00 00  |.Z._........v...|
00000540  ed 5a f7 5f 41 c9 0a 00  03 00 01 00 0d 08 00 00  |.Z._A...........|
00000550  ed 5a f7 5f 46 c9 0a 00  03 00 18 00 28 0b 00 00  |.Z._F.......(...|
00000560  ed 5a f7 5f 50 c9 0a 00  00 00 00 00 00 00 00 00  |.Z._P...........|
00000570  ed 5a f7 5f 1f f0 0a 00  03 00 00 00 68 0a 00 00  |.Z._........h...|
00000580  ed 5a f7 5f 42 f0 0a 00  03 00 01 00 e8 07 00 00  |.Z._B...........|
00000590  ed 5a f7 5f 47 f0 0a 00  03 00 18 00 32 0b 00 00  |.Z._G.......2...|
000005a0  ed 5a f7 5f 51 f0 0a 00  00 00 00 00 00 00 00 00  |.Z._Q...........|
000005b0  ed 5a f7 5f 3a 17 0b 00  03 00 00 00 41 0a 00 00  |.Z._:.......A...|
000005c0  ed 5a f7 5f 5e 17 0b 00  03 00 01 00 c5 07 00 00  |.Z._^...........|
000005d0  ed 5a f7 5f 64 17 0b 00  03 00 18 00 c0 09 00 00  |.Z._d...........|
000005e0  ed 5a f7 5f 6e 17 0b 00  00 00 00 00 00 00 00 00  |.Z._n...........|
000005f0  ed 5a f7 5f 41 3e 0b 00  03 00 00 00 25 0a 00 00  |.Z._A>......%...|
00000600  ed 5a f7 5f 64 3e 0b 00  03 00 01 00 b4 07 00 00  |.Z._d>..........|
00000610  ed 5a f7 5f 69 3e 0b 00  03 00 18 00 a8 09 00 00  |.Z._i>..........|
00000620  ed 5a f7 5f 73 3e 0b 00  00 00 00 00 00 00 00 00  |.Z._s>..........|
00000630  ed 5a f7 5f 59 65 0b 00  03 00 00 00 0c 0a 00 00  |.Z._Ye..........|
00000640  ed 5a f7 5f 7c 65 0b 00  03 00 01 00 a8 07 00 00  |.Z._|e..........|
00000650  ed 5a f7 5f 82 65 0b 00  03 00 18 00 68 09 00 00  |.Z._.e......h...|
00000660  ed 5a f7 5f 8c 65 0b 00  00 00 00 00 00 00 00 00  |.Z._.e..........|
00000670  ed 5a f7 5f 63 8c 0b 00  03 00 00 00 e6 09 00 00  |.Z._c...........|
00000680  ed 5a f7 5f 84 8c 0b 00  03 00 01 00 90 07 00 00  |.Z._............|
00000690  ed 5a f7 5f 8a 8c 0b 00  03 00 18 00 44 09 00 00  |.Z._........D...|
000006a0  ed 5a f7 5f 94 8c 0b 00  00 00 00 00 00 00 00 00  |.Z._............|
000006b0  ed 5a f7 5f 79 b3 0b 00  03 00 00 00 c0 09 00 00  |.Z._y...........|
000006c0  ed 5a f7 5f 9e b3 0b 00  03 00 01 00 81 07 00 00  |.Z._............|
000006d0  ed 5a f7 5f a3 b3 0b 00  03 00 18 00 08 09 00 00  |.Z._............|
000006e0  ed 5a f7 5f ad b3 0b 00  00 00 00 00 00 00 00 00  |.Z._............|
000006f0  ed 5a f7 5f 80 da 0b 00  03 00 00 00 94 09 00 00  |.Z._............|
00000700  ed 5a f7 5f a2 da 0b 00  03 00 01 00 6b 07 00 00  |.Z._........k...|
00000710  ed 5a f7 5f a8 da 0b 00  03 00 18 00 d3 08 00 00  |.Z._............|
00000720  ed 5a f7 5f b1 da 0b 00  00 00 00 00 00 00 00 00  |.Z._............|
00000730  ed 5a f7 5f 9c 01 0c 00  03 00 00 00 60 09 00 00  |.Z._........`...|
00000740  ed 5a f7 5f c0 01 0c 00  03 00 01 00 5c 07 00 00  |.Z._........\...|
00000750  ed 5a f7 5f c5 01 0c 00  03 00 18 00 e5 08 00 00  |.Z._............|
00000760  ed 5a f7 5f cf 01 0c 00  00 00 00 00 00 00 00 00  |.Z._............|
00000770  ed 5a f7 5f a0 28 0c 00  03 00 00 00 2a 09 00 00  |.Z._.(......*...|
00000780  ed 5a f7 5f c2 28 0c 00  03 00 01 00 4d 07 00 00  |.Z._.(......M...|
00000790  ed 5a f7 5f c8 28 0c 00  03 00 18 00 52 08 00 00  |.Z._.(......R...|
000007a0  ed 5a f7 5f d2 28 0c 00  00 00 00 00 00 00 00 00  |.Z._.(..........|
000007b0  ed 5a f7 5f bc 4f 0c 00  03 00 00 00 fb 08 00 00  |.Z._.O..........|
000007c0  ed 5a f7 5f e0 4f 0c 00  03 00 01 00 48 07 00 00  |.Z._.O......H...|
000007d0  ed 5a f7 5f e6 4f 0c 00  03 00 18 00 7d 08 00 00  |.Z._.O......}...|
000007e0  ed 5a f7 5f f0 4f 0c 00  00 00 00 00 00 00 00 00  |.Z._.O..........|
000007f0  ed 5a f7 5f c3 76 0c 00  03 00 00 00 c6 08 00 00  |.Z._.v..........|
00000800  ed 5a f7 5f e5 76 0c 00  03 00 01 00 40 07 00 00  |.Z._.v......@...|
00000810  ed 5a f7 5f eb 76 0c 00  03 00 18 00 77 08 00 00  |.Z._.v......w...|
00000820  ed 5a f7 5f f5 76 0c 00  00 00 00 00 00 00 00 00  |.Z._.v..........|
00000830  ed 5a f7 5f dc 9d 0c 00  03 00 00 00 84 08 00 00  |.Z._............|
00000840  ed 5a f7 5f 00 9e 0c 00  03 00 01 00 39 07 00 00  |.Z._........9...|
00000850  ed 5a f7 5f 06 9e 0c 00  03 00 18 00 20 08 00 00  |.Z._........ ...|
00000860  ed 5a f7 5f 10 9e 0c 00  00 00 00 00 00 00 00 00  |.Z._............|
00000870  ed 5a f7 5f e3 c4 0c 00  03 00 00 00 3f 08 00 00  |.Z._........?...|
00000880  ed 5a f7 5f 05 c5 0c 00  03 00 01 00 44 07 00 00  |.Z._........D...|
00000890  ed 5a f7 5f 0b c5 0c 00  03 00 18 00 45 08 00 00  |.Z._........E...|
000008a0  ed 5a f7 5f 14 c5 0c 00  00 00 00 00 00 00 00 00  |.Z._............|
000008b0  ed 5a f7 5f f9 eb 0c 00  03 00 00 00 ee 07 00 00  |.Z._............|
000008c0  ed 5a f7 5f 1d ec 0c 00  03 00 01 00 50 07 00 00  |.Z._........P...|
000008d0  ed 5a f7 5f 23 ec 0c 00  03 00 18 00 6a 08 00 00  |.Z._#.......j...|
000008e0  ed 5a f7 5f 2d ec 0c 00  00 00 00 00 00 00 00 00  |.Z._-...........|
000008f0  ed 5a f7 5f 00 13 0d 00  03 00 00 00 a0 07 00 00  |.Z._............|
00000900  ed 5a f7 5f 22 13 0d 00  03 00 01 00 58 07 00 00  |.Z._".......X...|
00000910  ed 5a f7 5f 27 13 0d 00  03 00 18 00 4a 08 00 00  |.Z._'.......J...|
00000920  ed 5a f7 5f 32 13 0d 00  00 00 00 00 00 00 00 00  |.Z._2...........|
00000930  ed 5a f7 5f 1f 3a 0d 00  03 00 00 00 5e 07 00 00  |.Z._.:......^...|
00000940  ed 5a f7 5f 44 3a 0d 00  03 00 01 00 5c 07 00 00  |.Z._D:......\...|
00000950  ed 5a f7 5f 49 3a 0d 00  03 00 18 00 03 08 00 00  |.Z._I:..........|
00000960  ed 5a f7 5f 53 3a 0d 00  00 00 00 00 00 00 00 00  |.Z._S:..........|
00000970  ed 5a f7 5f 22 61 0d 00  03 00 00 00 22 07 00 00  |.Z._"a......"...|
00000980  ed 5a f7 5f 44 61 0d 00  03 00 01 00 5e 07 00 00  |.Z._Da......^...|
00000990  ed 5a f7 5f 4a 61 0d 00  03 00 18 00 ef 07 00 00  |.Z._Ja..........|
000009a0  ed 5a f7 5f 54 61 0d 00  00 00 00 00 00 00 00 00  |.Z._Ta..........|
000009b0  ed 5a f7 5f 3d 88 0d 00  03 00 00 00 f1 06 00 00  |.Z._=...........|
000009c0  ed 5a f7 5f 63 88 0d 00  03 00 01 00 75 07 00 00  |.Z._c.......u...|
000009d0  ed 5a f7 5f 68 88 0d 00  03 00 18 00 02 08 00 00  |.Z._h...........|
000009e0  ed 5a f7 5f 72 88 0d 00  00 00 00 00 00 00 00 00  |.Z._r...........|
000009f0  ed 5a f7 5f 41 af 0d 00  03 00 00 00 bb 06 00 00  |.Z._A...........|
00000a00  ed 5a f7 5f 63 af 0d 00  03 00 01 00 6e 07 00 00  |.Z._c.......n...|
00000a10  ed 5a f7 5f 69 af 0d 00  03 00 18 00 f4 07 00 00  |.Z._i...........|
00000a20  ed 5a f7 5f 73 af 0d 00  00 00 00 00 00 00 00 00  |.Z._s...........|
00000a30  ed 5a f7 5f 5b d6 0d 00  03 00 00 00 90 06 00 00  |.Z._[...........|
00000a40  ed 5a f7 5f 7f d6 0d 00  03 00 01 00 80 07 00 00  |.Z._............|
00000a50  ed 5a f7 5f 85 d6 0d 00  03 00 18 00 0f 08 00 00  |.Z._............|
00000a60  ed 5a f7 5f 8f d6 0d 00  00 00 00 00 00 00 00 00  |.Z._............|
00000a70  ed 5a f7 5f 5f fd 0d 00  03 00 00 00 5a 06 00 00  |.Z.__.......Z...|
00000a80  ed 5a f7 5f 84 fd 0d 00  03 00 18 00 0b 08 00 00  |.Z._............|
00000a90  ed 5a f7 5f 8e fd 0d 00  00 00 00 00 00 00 00 00  |.Z._............|
00000aa0  ed 5a f7 5f 7d 24 0e 00  03 00 00 00 27 06 00 00  |.Z._}$......'...|
00000ab0  ed 5a f7 5f a0 24 0e 00  03 00 01 00 92 07 00 00  |.Z._.$..........|
00000ac0  ed 5a f7 5f a6 24 0e 00  03 00 18 00 80 08 00 00  |.Z._.$..........|
00000ad0  ed 5a f7 5f b0 24 0e 00  00 00 00 00 00 00 00 00  |.Z._.$..........|
00000ae0  ed 5a f7 5f 84 4b 0e 00  03 00 00 00 fc 05 00 00  |.Z._.K..........|
00000af0  ed 5a f7 5f a6 4b 0e 00  03 00 01 00 8c 07 00 00  |.Z._.K..........|
00000b00  ed 5a f7 5f ac 4b 0e 00  03 00 18 00 61 08 00 00  |.Z._.K......a...|
00000b10  ed 5a f7 5f b6 4b 0e 00  00 00 00 00 00 00 00 00  |.Z._.K..........|
00000b20  ed 5a f7 5f 98 72 0e 00  03 00 00 00 ea 05 00 00  |.Z._.r..........|
00000b30  ed 5a f7 5f bb 72 0e 00  03 00 01 00 8e 07 00 00  |.Z._.r..........|
00000b40  ed 5a f7 5f c0 72 0e 00  03 00 18 00 30 08 00 00  |.Z._.r......0...|
00000b50  ed 5a f7 5f cb 72 0e 00  00 00 00 00 00 00 00 00  |.Z._.r..........|
00000b60  ed 5a f7 5f 9f 99 0e 00  03 00 00 00 e7 05 00 00  |.Z._............|
00000b70  ed 5a f7 5f c0 99 0e 00  03 00 01 00 92 07 00 00  |.Z._............|
00000b80  ed 5a f7 5f c6 99 0e 00  03 00 18 00 1a 08 00 00  |.Z._............|
00000b90  ed 5a f7 5f d0 99 0e 00  00 00 00 00 00 00 00 00  |.Z._............|
00000ba0  ed 5a f7 5f bf c0 0e 00  03 00 00 00 e5 05 00 00  |.Z._............|
00000bb0  ed 5a f7 5f e4 c0 0e 00  03 00 01 00 95 07 00 00  |.Z._............|
00000bc0  ed 5a f7 5f e9 c0 0e 00  03 00 18 00 ef 07 00 00  |.Z._............|
00000bd0  ed 5a f7 5f f3 c0 0e 00  00 00 00 00 00 00 00 00  |.Z._............|
00000be0  ed 5a f7 5f c4 e7 0e 00  03 00 00 00 e2 05 00 00  |.Z._............|
00000bf0  ed 5a f7 5f e9 e7 0e 00  03 00 18 00 a1 07 00 00  |.Z._............|
00000c00  ed 5a f7 5f f4 e7 0e 00  00 00 00 00 00 00 00 00  |.Z._............|
00000c10  ed 5a f7 5f da 0e 0f 00  03 00 00 00 d5 05 00 00  |.Z._............|
00000c20  ed 5a f7 5f fe 0e 0f 00  03 00 01 00 85 07 00 00  |.Z._............|
00000c30  ed 5a f7 5f 04 0f 0f 00  03 00 18 00 fb 06 00 00  |.Z._............|
00000c40  ed 5a f7 5f 0e 0f 0f 00  00 00 00 00 00 00 00 00  |.Z._............|
00000c50  ed 5a f7 5f e0 35 0f 00  03 00 00 00 d3 05 00 00  |.Z._.5..........|
00000c60  ed 5a f7 5f 02 36 0f 00  03 00 01 00 80 07 00 00  |.Z._.6..........|
00000c70  ed 5a f7 5f 08 36 0f 00  03 00 18 00 cb 06 00 00  |.Z._.6..........|
00000c80  ed 5a f7 5f 11 36 0f 00  00 00 00 00 00 00 00 00  |.Z._.6..........|
00000c90  ee 5a f7 5f be 1a 00 00  03 00 00 00 d4 05 00 00  |.Z._............|
00000ca0  ee 5a f7 5f e3 1a 00 00  03 00 01 00 7c 07 00 00  |.Z._........|...|
00000cb0  ee 5a f7 5f e8 1a 00 00  03 00 18 00 b5 06 00 00  |.Z._............|
00000cc0  ee 5a f7 5f f2 1a 00 00  00 00 00 00 00 00 00 00  |.Z._............|
00000cd0  ee 5a f7 5f c7 41 00 00  03 00 00 00 d8 05 00 00  |.Z._.A..........|
00000ce0  ee 5a f7 5f ec 41 00 00  03 00 18 00 a0 06 00 00  |.Z._.A..........|
00000cf0  ee 5a f7 5f f7 41 00 00  00 00 00 00 00 00 00 00  |.Z._.A..........|
00000d00  ee 5a f7 5f dc 68 00 00  03 00 00 00 e4 05 00 00  |.Z._.h..........|
00000d10  ee 5a f7 5f 04 69 00 00  03 00 18 00 92 06 00 00  |.Z._.i..........|
00000d20  ee 5a f7 5f 0e 69 00 00  00 00 00 00 00 00 00 00  |.Z._.i..........|
00000d30  ee 5a f7 5f e3 8f 00 00  03 00 00 00 09 06 00 00  |.Z._............|
00000d40  ee 5a f7 5f 05 90 00 00  03 00 01 00 80 07 00 00  |.Z._............|
00000d50  ee 5a f7 5f 0a 90 00 00  03 00 18 00 70 06 00 00  |.Z._........p...|
00000d60  ee 5a f7 5f 14 90 00 00  00 00 00 00 00 00 00 00  |.Z._............|
00000d70  ee 5a f7 5f fd b6 00 00  03 00 00 00 38 06 00 00  |.Z._........8...|
00000d80  ee 5a f7 5f 22 b7 00 00  03 00 01 00 8b 07 00 00  |.Z._"...........|
00000d90  ee 5a f7 5f 28 b7 00 00  03 00 18 00 63 06 00 00  |.Z._(.......c...|
00000da0  ee 5a f7 5f 31 b7 00 00  00 00 00 00 00 00 00 00  |.Z._1...........|
00000db0  ee 5a f7 5f 00 de 00 00  03 00 00 00 72 06 00 00  |.Z._........r...|
00000dc0  ee 5a f7 5f 22 de 00 00  03 00 01 00 95 07 00 00  |.Z._"...........|
00000dd0  ee 5a f7 5f 28 de 00 00  03 00 18 00 2f 06 00 00  |.Z._(......./...|
00000de0  ee 5a f7 5f 32 de 00 00  00 00 00 00 00 00 00 00  |.Z._2...........|
00000df0  ee 5a f7 5f 1c 05 01 00  03 00 00 00 a8 06 00 00  |.Z._............|
00000e00  ee 5a f7 5f 41 05 01 00  03 00 01 00 b2 07 00 00  |.Z._A...........|
00000e10  ee 5a f7 5f 46 05 01 00  03 00 18 00 07 06 00 00  |.Z._F...........|
00000e20  ee 5a f7 5f 50 05 01 00  00 00 00 00 00 00 00 00  |.Z._P...........|
00000e30  ee 5a f7 5f 21 2c 01 00  03 00 00 00 d9 06 00 00  |.Z._!,..........|
00000e40  ee 5a f7 5f 43 2c 01 00  03 00 01 00 ca 07 00 00  |.Z._C,..........|
00000e50  ee 5a f7 5f 48 2c 01 00  03 00 18 00 fa 05 00 00  |.Z._H,..........|
00000e60  ee 5a f7 5f 53 2c 01 00  00 00 00 00 00 00 00 00  |.Z._S,..........|
00000e70  ee 5a f7 5f 3e 53 01 00  03 00 00 00 05 07 00 00  |.Z._>S..........|
00000e80  ee 5a f7 5f 63 53 01 00  03 00 01 00 d7 07 00 00  |.Z._cS..........|
00000e90  ee 5a f7 5f 69 53 01 00  03 00 18 00 06 06 00 00  |.Z._iS..........|
00000ea0  ee 5a f7 5f 73 53 01 00  00 00 00 00 00 00 00 00  |.Z._sS..........|
00000eb0  ee 5a f7 5f 42 7a 01 00  03 00 00 00 31 07 00 00  |.Z._Bz......1...|
00000ec0  ee 5a f7 5f 64 7a 01 00  03 00 01 00 e2 07 00 00  |.Z._dz..........|
00000ed0  ee 5a f7 5f 69 7a 01 00  03 00 18 00 f3 05 00 00  |.Z._iz..........|
00000ee0  ee 5a f7 5f 73 7a 01 00  00 00 00 00 00 00 00 00  |.Z._sz..........|
00000ef0  ee 5a f7 5f 77 a1 01 00  03 00 00 00 5e 07 00 00  |.Z._w.......^...|
00000f00  ee 5a f7 5f 8a a1 01 00  03 00 01 00 eb 07 00 00  |.Z._............|
00000f10  ee 5a f7 5f 8f a1 01 00  03 00 18 00 e0 05 00 00  |.Z._............|
00000f20  ee 5a f7 5f 99 a1 01 00  00 00 00 00 00 00 00 00  |.Z._............|
00000f30  ee 5a f7 5f 62 c8 01 00  03 00 00 00 94 07 00 00  |.Z._b...........|
00000f40  ee 5a f7 5f 84 c8 01 00  03 00 01 00 fa 07 00 00  |.Z._............|
00000f50  ee 5a f7 5f 8a c8 01 00  03 00 18 00 d1 05 00 00  |.Z._............|
00000f60  ee 5a f7 5f 94 c8 01 00  00 00 00 00 00 00 00 00  |.Z._............|
00000f70  ee 5a f7 5f 7a ef 01 00  03 00 00 00 c2 07 00 00  |.Z._z...........|
00000f80  ee 5a f7 5f 9f ef 01 00  03 00 01 00 0b 08 00 00  |.Z._............|
00000f90  ee 5a f7 5f a4 ef 01 00  03 00 18 00 aa 05 00 00  |.Z._............|
00000fa0  ee 5a f7 5f ae ef 01 00  00 00 00 00 00 00 00 00  |.Z._............|
00000fb0  ee 5a f7 5f 80 16 02 00  03 00 00 00 ee 07 00 00  |.Z._............|
00000fc0  ee 5a f7 5f a1 16 02 00  03 00 01 00 23 08 00 00  |.Z._........#...|
00000fd0  ee 5a f7 5f a7 16 02 00  03 00 18 00 9e 05 00 00  |.Z._............|
00000fe0  ee 5a f7 5f b1 16 02 00  00 00 00 00 00 00 00 00  |.Z._............|
00000ff0  ee 5a f7 5f 9d 3d 02 00  03 00 00 00 2c 08 00 00  |.Z._.=......,...|
00001000  ee 5a f7 5f c2 3d 02 00  03 00 01 00 32 08 00 00  |.Z._.=......2...|
00001010  ee 5a f7 5f c7 3d 02 00  03 00 18 00 d8 05 00 00  |.Z._.=..........|
00001020  ee 5a f7 5f d1 3d 02 00  00 00 00 00 00 00 00 00  |.Z._.=..........|
00001030  ee 5a f7 5f 9f 64 02 00  03 00 00 00 80 08 00 00  |.Z._.d..........|
00001040  ee 5a f7 5f c1 64 02 00  03 00 01 00 40 08 00 00  |.Z._.d......@...|
00001050  ee 5a f7 5f c7 64 02 00  03 00 18 00 4e 06 00 00  |.Z._.d......N...|
00001060  ee 5a f7 5f d0 64 02 00  00 00 00 00 00 00 00 00  |.Z._.d..........|
00001070  ee 5a f7 5f bc 8b 02 00  03 00 00 00 e9 08 00 00  |.Z._............|
00001080  ee 5a f7 5f e4 8b 02 00  03 00 18 00 09 06 00 00  |.Z._............|
00001090  ee 5a f7 5f ee 8b 02 00  00 00 00 00 00 00 00 00  |.Z._............|
000010a0  ee 5a f7 5f c0 b2 02 00  03 00 00 00 1a 09 00 00  |.Z._............|
000010b0  ee 5a f7 5f e2 b2 02 00  03 00 01 00 4c 08 00 00  |.Z._........L...|
000010c0  ee 5a f7 5f e7 b2 02 00  03 00 18 00 7a 06 00 00  |.Z._........z...|
000010d0  ee 5a f7 5f f2 b2 02 00  00 00 00 00 00 00 00 00  |.Z._............|
000010e0  ee 5a f7 5f d9 d9 02 00  03 00 00 00 34 09 00 00  |.Z._........4...|
000010f0  ee 5a f7 5f fe d9 02 00  03 00 01 00 52 08 00 00  |.Z._........R...|
00001100  ee 5a f7 5f 03 da 02 00  03 00 18 00 d1 07 00 00  |.Z._............|
00001110  ee 5a f7 5f 0d da 02 00  00 00 00 00 00 00 00 00  |.Z._............|
00001120  ee 5a f7 5f de 00 03 00  03 00 00 00 91 09 00 00  |.Z._............|
00001130  ee 5a f7 5f 00 01 03 00  03 00 01 00 3d 08 00 00  |.Z._........=...|
00001140  ee 5a f7 5f 06 01 03 00  03 00 18 00 04 08 00 00  |.Z._............|
00001150  ee 5a f7 5f 10 01 03 00  00 00 00 00 00 00 00 00  |.Z._............|
00001160  ee 5a f7 5f fa 27 03 00  03 00 00 00 b7 09 00 00  |.Z._.'..........|
00001170  ee 5a f7 5f 1e 28 03 00  03 00 01 00 5d 08 00 00  |.Z._.(......]...|
00001180  ee 5a f7 5f 23 28 03 00  03 00 18 00 a0 07 00 00  |.Z._#(..........|
00001190  ee 5a f7 5f 2c 28 03 00  00 00 00 00 00 00 00 00  |.Z._,(..........|
000011a0  ee 5a f7 5f ff 4e 03 00  03 00 00 00 a6 09 00 00  |.Z._.N..........|
000011b0  ee 5a f7 5f 21 4f 03 00  03 00 01 00 61 08 00 00  |.Z._!O......a...|
000011c0  ee 5a f7 5f 26 4f 03 00  03 00 18 00 62 0a 00 00  |.Z._&O......b...|
000011d0  ee 5a f7 5f 30 4f 03 00  00 00 00 00 00 00 00 00  |.Z._0O..........|
000011e0  ee 5a f7 5f 1c 76 03 00  03 00 00 00 d7 09 00 00  |.Z._.v..........|
000011f0  ee 5a f7 5f 40 76 03 00  03 00 01 00 80 08 00 00  |.Z._@v..........|
00001200  ee 5a f7 5f 45 76 03 00  03 00 18 00 af 08 00 00  |.Z._Ev..........|
00001210  ee 5a f7 5f 50 76 03 00  00 00 00 00 00 00 00 00  |.Z._Pv..........|
00001220  ee 5a f7 5f 1f 9d 03 00  03 00 00 00 dc 09 00 00  |.Z._............|
00001230  ee 5a f7 5f 41 9d 03 00  03 00 01 00 85 08 00 00  |.Z._A...........|
00001240  ee 5a f7 5f 47 9d 03 00  03 00 18 00 29 08 00 00  |.Z._G.......)...|
00001250  ee 5a f7 5f 50 9d 03 00  00 00 00 00 00 00 00 00  |.Z._P...........|
00001260  ee 5a f7 5f 40 c4 03 00  03 00 01 00 89 08 00 00  |.Z._@...........|
00001270  ee 5a f7 5f 65 c4 03 00  03 00 18 00 33 09 00 00  |.Z._e.......3...|
00001280  ee 5a f7 5f 6e c4 03 00  00 00 00 00 00 00 00 00  |.Z._n...........|
00001290  ee 5a f7 5f 42 eb 03 00  03 00 00 00 ce 09 00 00  |.Z._B...........|
000012a0  ee 5a f7 5f 65 eb 03 00  03 00 01 00 8f 08 00 00  |.Z._e...........|
000012b0  ee 5a f7 5f 6a eb 03 00  03 00 18 00 68 0b 00 00  |.Z._j.......h...|
000012c0  ee 5a f7 5f 74 eb 03 00  00 00 00 00 00 00 00 00  |.Z._t...........|
000012d0  ee 5a f7 5f 5c 12 04 00  03 00 00 00 e0 09 00 00  |.Z._\...........|
000012e0  ee 5a f7 5f 80 12 04 00  03 00 01 00 92 08 00 00  |.Z._............|
000012f0  ee 5a f7 5f 85 12 04 00  03 00 18 00 9c 17 00 00  |.Z._............|
00001300  ee 5a f7 5f 90 12 04 00  00 00 00 00 00 00 00 00  |.Z._............|
00001310  ee 5a f7 5f 05 86 04 00  03 00 18 00 00 00 00 00  |.Z._............|
00001320  ee 5a f7 5f 2c 86 04 00  00 00 00 00 00 00 00 00  |.Z._,...........|
00001330  ee 5a f7 5f 25 2e 07 00  03 00 00 00 16 06 00 00  |.Z._%...........|
00001340  ee 5a f7 5f 39 2e 07 00  03 00 01 00 46 02 00 00  |.Z._9.......F...|
00001350  ee 5a f7 5f 3f 2e 07 00  03 00 18 00 9e 36 00 00  |.Z._?........6..|
00001360  ee 5a f7 5f 49 2e 07 00  00 00 00 00 00 00 00 00  |.Z._I...........|
00001370  ee 5a f7 5f a0 46 07 00  03 00 00 00 1c 06 00 00  |.Z._.F..........|
00001380  ee 5a f7 5f c6 46 07 00  03 00 01 00 49 02 00 00  |.Z._.F......I...|
00001390  ee 5a f7 5f cb 46 07 00  03 00 18 00 34 19 00 00  |.Z._.F......4...|
000013a0  ee 5a f7 5f d5 46 07 00  00 00 00 00 00 00 00 00  |.Z._.F..........|
000013b0  ee 5a f7 5f bd 6d 07 00  03 00 00 00 26 06 00 00  |.Z._.m......&...|
000013c0  ee 5a f7 5f e2 6d 07 00  03 00 01 00 5a 02 00 00  |.Z._.m......Z...|
000013d0  ee 5a f7 5f e7 6d 07 00  03 00 18 00 ea 18 00 00  |.Z._.m..........|
000013e0  ee 5a f7 5f f2 6d 07 00  00 00 00 00 00 00 00 00  |.Z._.m..........|
000013f0  ee 5a f7 5f c0 94 07 00  03 00 00 00 38 06 00 00  |.Z._........8...|
00001400  ee 5a f7 5f e1 94 07 00  03 00 01 00 8b 02 00 00  |.Z._............|
00001410  ee 5a f7 5f e7 94 07 00  03 00 18 00 b1 15 00 00  |.Z._............|
00001420  ee 5a f7 5f f1 94 07 00  00 00 00 00 00 00 00 00  |.Z._............|
00001430  ee 5a f7 5f db bb 07 00  03 00 00 00 69 06 00 00  |.Z._........i...|
00001440  ee 5a f7 5f ff bb 07 00  03 00 01 00 ef 02 00 00  |.Z._............|
00001450  ee 5a f7 5f 05 bc 07 00  03 00 18 00 9e 0d 00 00  |.Z._............|
00001460  ee 5a f7 5f 0e bc 07 00  00 00 00 00 00 00 00 00  |.Z._............|
00001470  ee 5a f7 5f e1 e2 07 00  03 00 00 00 73 06 00 00  |.Z._........s...|
00001480  ee 5a f7 5f 04 e3 07 00  03 00 01 00 3f 03 00 00  |.Z._........?...|
00001490  ee 5a f7 5f 09 e3 07 00  03 00 18 00 77 0b 00 00  |.Z._........w...|
000014a0  ee 5a f7 5f 13 e3 07 00  00 00 00 00 00 00 00 00  |.Z._............|
000014b0  ee 5a f7 5f ff 09 08 00  03 00 00 00 82 06 00 00  |.Z._............|
000014c0  ee 5a f7 5f 23 0a 08 00  03 00 01 00 a3 03 00 00  |.Z._#...........|
000014d0  ee 5a f7 5f 28 0a 08 00  03 00 18 00 65 0b 00 00  |.Z._(.......e...|
000014e0  ee 5a f7 5f 33 0a 08 00  00 00 00 00 00 00 00 00  |.Z._3...........|
000014f0  ee 5a f7 5f 02 31 08 00  03 00 00 00 9e 06 00 00  |.Z._.1..........|
00001500  ee 5a f7 5f 24 31 08 00  03 00 01 00 ee 03 00 00  |.Z._$1..........|
00001510  ee 5a f7 5f 2a 31 08 00  03 00 18 00 0a 0b 00 00  |.Z._*1..........|
00001520  ee 5a f7 5f 34 31 08 00  00 00 00 00 00 00 00 00  |.Z._41..........|
00001530  ee 5a f7 5f 1f 58 08 00  03 00 00 00 c0 06 00 00  |.Z._.X..........|
00001540  ee 5a f7 5f 43 58 08 00  03 00 01 00 68 04 00 00  |.Z._CX......h...|
00001550  ee 5a f7 5f 49 58 08 00  03 00 18 00 b2 0a 00 00  |.Z._IX..........|
00001560  ee 5a f7 5f 53 58 08 00  00 00 00 00 00 00 00 00  |.Z._SX..........|
00001570  ee 5a f7 5f 23 7f 08 00  03 00 00 00 c9 06 00 00  |.Z._#...........|
00001580  ee 5a f7 5f 46 7f 08 00  03 00 01 00 b8 04 00 00  |.Z._F...........|
00001590  ee 5a f7 5f 4b 7f 08 00  03 00 18 00 78 09 00 00  |.Z._K.......x...|
000015a0  ee 5a f7 5f 55 7f 08 00  00 00 00 00 00 00 00 00  |.Z._U...........|
000015b0  ee 5a f7 5f 3d a6 08 00  03 00 00 00 ce 06 00 00  |.Z._=...........|
000015c0  ee 5a f7 5f 60 a6 08 00  03 00 01 00 ee 04 00 00  |.Z._`...........|
000015d0  ee 5a f7 5f 66 a6 08 00  03 00 18 00 00 09 00 00  |.Z._f...........|
000015e0  ee 5a f7 5f 70 a6 08 00  00 00 00 00 00 00 00 00  |.Z._p...........|
000015f0  ee 5a f7 5f 43 cd 08 00  03 00 00 00 e8 06 00 00  |.Z._C...........|
00001600  ee 5a f7 5f 65 cd 08 00  03 00 01 00 34 05 00 00  |.Z._e.......4...|
00001610  ee 5a f7 5f 6b cd 08 00  03 00 18 00 3d 08 00 00  |.Z._k.......=...|
00001620  ee 5a f7 5f 75 cd 08 00  00 00 00 00 00 00 00 00  |.Z._u...........|
00001630  ee 5a f7 5f 5f f4 08 00  03 00 00 00 09 07 00 00  |.Z.__...........|
00001640  ee 5a f7 5f 83 f4 08 00  03 00 01 00 a9 05 00 00  |.Z._............|
00001650  ee 5a f7 5f 88 f4 08 00  03 00 18 00 50 08 00 00  |.Z._........P...|
00001660  ee 5a f7 5f 92 f4 08 00  00 00 00 00 00 00 00 00  |.Z._............|
00001670  ee 5a f7 5f 60 1b 09 00  03 00 00 00 29 07 00 00  |.Z._`.......)...|
00001680  ee 5a f7 5f 83 1b 09 00  03 00 01 00 0f 06 00 00  |.Z._............|
00001690  ee 5a f7 5f 88 1b 09 00  03 00 18 00 8c 08 00 00  |.Z._............|
000016a0  ee 5a f7 5f 93 1b 09 00  00 00 00 00 00 00 00 00  |.Z._............|
000016b0  ee 5a f7 5f 78 42 09 00  03 00 00 00 4e 07 00 00  |.Z._xB......N...|
000016c0  ee 5a f7 5f 9d 42 09 00  03 00 01 00 77 06 00 00  |.Z._.B......w...|
000016d0  ee 5a f7 5f a3 42 09 00  03 00 18 00 c6 08 00 00  |.Z._.B..........|
000016e0  ee 5a f7 5f ad 42 09 00  00 00 00 00 00 00 00 00  |.Z._.B..........|
000016f0  ee 5a f7 5f 82 69 09 00  03 00 00 00 6c 07 00 00  |.Z._.i......l...|
00001700  ee 5a f7 5f a4 69 09 00  03 00 01 00 d2 06 00 00  |.Z._.i..........|
00001710  ee 5a f7 5f aa 69 09 00  03 00 18 00 22 0c 00 00  |.Z._.i......"...|
00001720  ee 5a f7 5f b4 69 09 00  00 00 00 00 00 00 00 00  |.Z._.i..........|
00001730  ee 5a f7 5f 9c 90 09 00  03 00 00 00 d0 07 00 00  |.Z._............|
00001740  ee 5a f7 5f c0 90 09 00  03 00 01 00 a8 07 00 00  |.Z._............|
00001750  ee 5a f7 5f c5 90 09 00  03 00 18 00 b9 09 00 00  |.Z._............|
00001760  ee 5a f7 5f cf 90 09 00  00 00 00 00 00 00 00 00  |.Z._............|
00001770  ee 5a f7 5f a0 b7 09 00  03 00 00 00 1c 08 00 00  |.Z._............|
00001780  ee 5a f7 5f c2 b7 09 00  03 00 01 00 64 08 00 00  |.Z._........d...|
00001790  ee 5a f7 5f c8 b7 09 00  03 00 18 00 bb 0a 00 00  |.Z._............|
000017a0  ee 5a f7 5f d2 b7 09 00  00 00 00 00 00 00 00 00  |.Z._............|
000017b0  ee 5a f7 5f bc de 09 00  03 00 00 00 38 08 00 00  |.Z._........8...|
000017c0  ee 5a f7 5f e1 de 09 00  03 00 01 00 06 09 00 00  |.Z._............|
000017d0  ee 5a f7 5f e6 de 09 00  03 00 18 00 86 08 00 00  |.Z._............|
000017e0  ee 5a f7 5f f1 de 09 00  00 00 00 00 00 00 00 00  |.Z._............|
000017f0  ee 5a f7 5f c1 05 0a 00  03 00 00 00 52 08 00 00  |.Z._........R...|
00001800  ee 5a f7 5f e3 05 0a 00  03 00 01 00 7c 09 00 00  |.Z._........|...|
00001810  ee 5a f7 5f e9 05 0a 00  03 00 18 00 18 08 00 00  |.Z._............|
00001820  ee 5a f7 5f f3 05 0a 00  00 00 00 00 00 00 00 00  |.Z._............|
00001830  ee 5a f7 5f f1 2c 0a 00  03 00 00 00 71 08 00 00  |.Z._.,......q...|
00001840  ee 5a f7 5f 15 2d 0a 00  03 00 01 00 e1 09 00 00  |.Z._.-..........|
00001850  ee 5a f7 5f 1b 2d 0a 00  03 00 18 00 ba 07 00 00  |.Z._.-..........|
00001860  ee 5a f7 5f 24 2d 0a 00  00 00 00 00 00 00 00 00  |.Z._$-..........|
00001870  ee 5a f7 5f e0 53 0a 00  03 00 00 00 82 08 00 00  |.Z._.S..........|
00001880  ee 5a f7 5f 03 54 0a 00  03 00 01 00 1c 0a 00 00  |.Z._.T..........|
00001890  ee 5a f7 5f 08 54 0a 00  03 00 18 00 be 07 00 00  |.Z._.T..........|
000018a0  ee 5a f7 5f 12 54 0a 00  00 00 00 00 00 00 00 00  |.Z._.T..........|
000018b0  ee 5a f7 5f fe 7a 0a 00  03 00 00 00 96 08 00 00  |.Z._.z..........|
000018c0  ee 5a f7 5f 23 7b 0a 00  03 00 01 00 78 0a 00 00  |.Z._#{......x...|
000018d0  ee 5a f7 5f 28 7b 0a 00  03 00 18 00 e8 07 00 00  |.Z._({..........|
000018e0  ee 5a f7 5f 32 7b 0a 00  00 00 00 00 00 00 00 00  |.Z._2{..........|
000018f0  ee 5a f7 5f 01 a2 0a 00  03 00 00 00 a4 08 00 00  |.Z._............|
00001900  ee 5a f7 5f 23 a2 0a 00  03 00 01 00 93 0a 00 00  |.Z._#...........|
00001910  ee 5a f7 5f 28 a2 0a 00  03 00 18 00 da 07 00 00  |.Z._(...........|
00001920  ee 5a f7 5f 33 a2 0a 00  00 00 00 00 00 00 00 00  |.Z._3...........|
00001930  ee 5a f7 5f 19 c9 0a 00  03 00 00 00 af 08 00 00  |.Z._............|
00001940  ee 5a f7 5f 3d c9 0a 00  03 00 01 00 c7 0a 00 00  |.Z._=...........|
00001950  ee 5a f7 5f 43 c9 0a 00  03 00 18 00 4c 07 00 00  |.Z._C.......L...|
00001960  ee 5a f7 5f 4d c9 0a 00  00 00 00 00 00 00 00 00  |.Z._M...........|
00001970  ee 5a f7 5f 20 f0 0a 00  03 00 00 00 b5 08 00 00  |.Z._ ...........|
00001980  ee 5a f7 5f 42 f0 0a 00  03 00 01 00 d0 0a 00 00  |.Z._B...........|
00001990  ee 5a f7 5f 48 f0 0a 00  03 00 18 00 44 07 00 00  |.Z._H.......D...|
000019a0  ee 5a f7 5f 52 f0 0a 00  00 00 00 00 00 00 00 00  |.Z._R...........|
000019b0  ee 5a f7 5f 3c 17 0b 00  03 00 00 00 ba 08 00 00  |.Z._<...........|
000019c0  ee 5a f7 5f 5e 17 0b 00  03 00 01 00 c6 0a 00 00  |.Z._^...........|
000019d0  ee 5a f7 5f 64 17 0b 00  03 00 18 00 23 07 00 00  |.Z._d.......#...|
000019e0  ee 5a f7 5f 6e 17 0b 00  00 00 00 00 00 00 00 00  |.Z._n...........|
000019f0  ee 5a f7 5f 40 3e 0b 00  03 00 00 00 bf 08 00 00  |.Z._@>..........|
00001a00  ee 5a f7 5f 61 3e 0b 00  03 00 01 00 be 0a 00 00  |.Z._a>..........|
00001a10  ee 5a f7 5f 68 3e 0b 00  03 00 18 00 29 07 00 00  |.Z._h>......)...|
00001a20  ee 5a f7 5f 71 3e 0b 00  00 00 00 00 00 00 00 00  |.Z._q>..........|
00001a30  ee 5a f7 5f 5c 65 0b 00  03 00 00 00 c3 08 00 00  |.Z._\e..........|
00001a40  ee 5a f7 5f 80 65 0b 00  03 00 01 00 b8 0a 00 00  |.Z._.e..........|
00001a50  ee 5a f7 5f 85 65 0b 00  03 00 18 00 27 07 00 00  |.Z._.e......'...|
00001a60  ee 5a f7 5f 8f 65 0b 00  00 00 00 00 00 00 00 00  |.Z._.e..........|
00001a70  ee 5a f7 5f 64 8c 0b 00  03 00 00 00 c8 08 00 00  |.Z._d...........|
00001a80  ee 5a f7 5f 87 8c 0b 00  03 00 01 00 9a 0a 00 00  |.Z._............|
00001a90  ee 5a f7 5f 8c 8c 0b 00  03 00 18 00 27 08 00 00  |.Z._........'...|
00001aa0  ee 5a f7 5f 96 8c 0b 00  00 00 00 00 00 00 00 00  |.Z._............|
00001ab0  ee 5a f7 5f 7b b3 0b 00  03 00 00 00 ba 08 00 00  |.Z._{...........|
00001ac0  ee 5a f7 5f 9f b3 0b 00  03 00 01 00 50 0a 00 00  |.Z._........P...|
00001ad0  ee 5a f7 5f a4 b3 0b 00  03 00 18 00 37 09 00 00  |.Z._........7...|
00001ae0  ee 5a f7 5f af b3 0b 00  00 00 00 00 00 00 00 00  |.Z._............|
00001af0  ee 5a f7 5f 7f da 0b 00  03 00 00 00 a2 08 00 00  |.Z._............|
00001b00  ee 5a f7 5f a1 da 0b 00  03 00 01 00 ca 09 00 00  |.Z._............|
00001b10  ee 5a f7 5f a6 da 0b 00  03 00 18 00 67 0b 00 00  |.Z._........g...|
00001b20  ee 5a f7 5f b0 da 0b 00  00 00 00 00 00 00 00 00  |.Z._............|
00001b30  ee 5a f7 5f 9c 01 0c 00  03 00 00 00 5f 08 00 00  |.Z._........_...|
00001b40  ee 5a f7 5f c0 01 0c 00  03 00 01 00 30 09 00 00  |.Z._........0...|
00001b50  ee 5a f7 5f c6 01 0c 00  03 00 18 00 f4 1b 00 00  |.Z._............|
00001b60  ee 5a f7 5f d0 01 0c 00  00 00 00 00 00 00 00 00  |.Z._............|
00001b70  ee 5a f7 5f a1 28 0c 00  03 00 00 00 30 08 00 00  |.Z._.(......0...|
00001b80  ee 5a f7 5f c4 28 0c 00  03 00 01 00 36 08 00 00  |.Z._.(......6...|
00001b90  ee 5a f7 5f ca 28 0c 00  03 00 18 00 2b 14 00 00  |.Z._.(......+...|
00001ba0  ee 5a f7 5f d4 28 0c 00  00 00 00 00 00 00 00 00  |.Z._.(..........|
00001bb0  ee 5a f7 5f 56 9c 0c 00  03 00 18 00 00 00 00 00  |.Z._V...........|
00001bc0  ee 5a f7 5f 7e 9c 0c 00  00 00 00 00 00 00 00 00  |.Z._~...........|
00001bd0  ff 5a f7 5f 43 ae 04 00  03 00 00 00 d0 0e 00 00  |.Z._C...........|
00001be0  ff 5a f7 5f 5a ae 04 00  03 00 01 00 7f 0a 00 00  |.Z._Z...........|
00001bf0  ff 5a f7 5f 60 ae 04 00  03 00 18 00 ff 28 00 00  |.Z._`........(..|
00001c00  ff 5a f7 5f 69 ae 04 00  00 00 00 00 00 00 00 00  |.Z._i...........|
00001c10  ff 5a f7 5f 79 fc 04 00  03 00 00 00 de 0e 00 00  |.Z._y...........|
00001c20  ff 5a f7 5f 9c fc 04 00  03 00 01 00 79 0a 00 00  |.Z._........y...|
00001c30  ff 5a f7 5f a2 fc 04 00  03 00 18 00 16 14 00 00  |.Z._............|
00001c40  ff 5a f7 5f ac fc 04 00  00 00 00 00 00 00 00 00  |.Z._............|
00001c50  ff 5a f7 5f ce 23 05 00  03 00 00 00 dd 0e 00 00  |.Z._.#..........|
00001c60  ff 5a f7 5f f2 23 05 00  03 00 01 00 73 0a 00 00  |.Z._.#......s...|
00001c70  ff 5a f7 5f f8 23 05 00  03 00 18 00 78 12 00 00  |.Z._.#......x...|
00001c80  ff 5a f7 5f 02 24 05 00  00 00 00 00 00 00 00 00  |.Z._.$..........|
00001c90  ff 5a f7 5f d0 4a 05 00  03 00 00 00 d9 0e 00 00  |.Z._.J..........|
00001ca0  ff 5a f7 5f f2 4a 05 00  03 00 01 00 6f 0a 00 00  |.Z._.J......o...|
00001cb0  ff 5a f7 5f f7 4a 05 00  03 00 18 00 52 12 00 00  |.Z._.J......R...|
00001cc0  ff 5a f7 5f 02 4b 05 00  00 00 00 00 00 00 00 00  |.Z._.K..........|
00001cd0  ff 5a f7 5f ef 71 05 00  03 00 01 00 68 0a 00 00  |.Z._.q......h...|
00001ce0  ff 5a f7 5f 13 72 05 00  03 00 18 00 25 12 00 00  |.Z._.r......%...|
00001cf0  ff 5a f7 5f 1d 72 05 00  00 00 00 00 00 00 00 00  |.Z._.r..........|
00001d00  ff 5a f7 5f f2 98 05 00  03 00 00 00 d6 0e 00 00  |.Z._............|
00001d10  ff 5a f7 5f 14 99 05 00  03 00 01 00 62 0a 00 00  |.Z._........b...|
00001d20  ff 5a f7 5f 1a 99 05 00  03 00 18 00 0e 12 00 00  |.Z._............|
00001d30  ff 5a f7 5f 24 99 05 00  00 00 00 00 00 00 00 00  |.Z._$...........|
00001d40  ff 5a f7 5f 31 c0 05 00  03 00 01 00 5d 0a 00 00  |.Z._1.......]...|
00001d50  ff 5a f7 5f 56 c0 05 00  03 00 18 00 df 11 00 00  |.Z._V...........|
00001d60  ff 5a f7 5f 60 c0 05 00  00 00 00 00 00 00 00 00  |.Z._`...........|
00001d70  ff 5a f7 5f 13 e7 05 00  03 00 00 00 d4 0e 00 00  |.Z._............|
00001d80  ff 5a f7 5f 35 e7 05 00  03 00 01 00 57 0a 00 00  |.Z._5.......W...|
00001d90  ff 5a f7 5f 3b e7 05 00  03 00 18 00 c6 11 00 00  |.Z._;...........|
00001da0  ff 5a f7 5f 45 e7 05 00  00 00 00 00 00 00 00 00  |.Z._E...........|
00001db0  ff 5a f7 5f 28 0e 06 00  03 00 00 00 d0 0e 00 00  |.Z._(...........|
00001dc0  ff 5a f7 5f 4d 0e 06 00  03 00 01 00 52 0a 00 00  |.Z._M.......R...|
00001dd0  ff 5a f7 5f 53 0e 06 00  03 00 18 00 91 11 00 00  |.Z._S...........|
00001de0  ff 5a f7 5f 5d 0e 06 00  00 00 00 00 00 00 00 00  |.Z._]...........|
00001df0  ff 5a f7 5f 2f 35 06 00  03 00 00 00 ce 0e 00 00  |.Z._/5..........|
00001e00  ff 5a f7 5f 51 35 06 00  03 00 01 00 4c 0a 00 00  |.Z._Q5......L...|
00001e10  ff 5a f7 5f 57 35 06 00  03 00 18 00 8a 11 00 00  |.Z._W5..........|
00001e20  ff 5a f7 5f 61 35 06 00  00 00 00 00 00 00 00 00  |.Z._a5..........|
00001e30  ff 5a f7 5f 50 5c 06 00  03 00 00 00 cc 0e 00 00  |.Z._P\..........|
00001e40  ff 5a f7 5f 74 5c 06 00  03 00 01 00 46 0a 00 00  |.Z._t\......F...|
00001e50  ff 5a f7 5f 79 5c 06 00  03 00 18 00 2f 11 00 00  |.Z._y\....../...|
00001e60  ff 5a f7 5f 83 5c 06 00  00 00 00 00 00 00 00 00  |.Z._.\..........|
00001e70  ff 5a f7 5f 53 83 06 00  03 00 00 00 c6 0e 00 00  |.Z._S...........|
00001e80  ff 5a f7 5f 75 83 06 00  03 00 01 00 40 0a 00 00  |.Z._u.......@...|
00001e90  ff 5a f7 5f 7b 83 06 00  03 00 18 00 72 11 00 00  |.Z._{.......r...|
00001ea0  ff 5a f7 5f 85 83 06 00  00 00 00 00 00 00 00 00  |.Z._............|
00001eb0  ff 5a f7 5f 6d aa 06 00  03 00 00 00 c7 0e 00 00  |.Z._m...........|
00001ec0  ff 5a f7 5f 91 aa 06 00  03 00 01 00 3d 0a 00 00  |.Z._........=...|
00001ed0  ff 5a f7 5f 97 aa 06 00  03 00 18 00 3c 11 00 00  |.Z._........<...|
00001ee0  ff 5a f7 5f a1 aa 06 00  00 00 00 00 00 00 00 00  |.Z._............|
00001ef0  ff 5a f7 5f 72 d1 06 00  03 00 00 00 c6 0e 00 00  |.Z._r...........|
00001f00  ff 5a f7 5f 94 d1 06 00  03 00 01 00 3c 0a 00 00  |.Z._........<...|
00001f10  ff 5a f7 5f 9a d1 06 00  03 00 18 00 07 11 00 00  |.Z._............|
00001f20  ff 5a f7 5f a4 d1 06 00  00 00 00 00 00 00 00 00  |.Z._............|
00001f30  ff 5a f7 5f 8d f8 06 00  03 00 00 00 c4 0e 00 00  |.Z._............|
00001f40  ff 5a f7 5f b2 f8 06 00  03 00 01 00 39 0a 00 00  |.Z._........9...|
00001f50  ff 5a f7 5f b8 f8 06 00  03 00 18 00 e1 10 00 00  |.Z._............|
00001f60  ff 5a f7 5f c2 f8 06 00  00 00 00 00 00 00 00 00  |.Z._............|
00001f70  ff 5a f7 5f 8f 1f 07 00  03 00 00 00 c6 0e 00 00  |.Z._............|
00001f80  ff 5a f7 5f b1 1f 07 00  03 00 01 00 38 0a 00 00  |.Z._........8...|
00001f90  ff 5a f7 5f b7 1f 07 00  03 00 18 00 eb 10 00 00  |.Z._............|
00001fa0  ff 5a f7 5f c0 1f 07 00  00 00 00 00 00 00 00 00  |.Z._............|
00001fb0  ff 5a f7 5f a9 46 07 00  03 00 00 00 c5 0e 00 00  |.Z._.F..........|
00001fc0  ff 5a f7 5f cd 46 07 00  03 00 01 00 34 0a 00 00  |.Z._.F......4...|
00001fd0  ff 5a f7 5f d4 46 07 00  03 00 18 00 e7 10 00 00  |.Z._.F..........|
00001fe0  ff 5a f7 5f dd 46 07 00  00 00 00 00 00 00 00 00  |.Z._.F..........|
00001ff0  ff 5a f7 5f b4 6d 07 00  03 00 00 00 c3 0e 00 00  |.Z._.m..........|
00002000  ff 5a f7 5f d5 6d 07 00  03 00 01 00 33 0a 00 00  |.Z._.m......3...|
00002010  ff 5a f7 5f db 6d 07 00  03 00 18 00 e0 10 00 00  |.Z._.m..........|
00002020  ff 5a f7 5f e5 6d 07 00  00 00 00 00 00 00 00 00  |.Z._.m..........|
00002030  ff 5a f7 5f cc 94 07 00  03 00 00 00 c2 0e 00 00  |.Z._............|
00002040  ff 5a f7 5f f1 94 07 00  03 00 01 00 34 0a 00 00  |.Z._........4...|
00002050  ff 5a f7 5f f6 94 07 00  03 00 18 00 c5 10 00 00  |.Z._............|
00002060  ff 5a f7 5f 00 95 07 00  00 00 00 00 00 00 00 00  |.Z._............|
00002070  ff 5a f7 5f d1 bb 07 00  03 00 00 00 c3 0e 00 00  |.Z._............|
00002080  ff 5a f7 5f f3 bb 07 00  03 00 01 00 32 0a 00 00  |.Z._........2...|
00002090  ff 5a f7 5f f8 bb 07 00  03 00 18 00 ad 10 00 00  |.Z._............|
000020a0  ff 5a f7 5f 03 bc 07 00  00 00 00 00 00 00 00 00  |.Z._............|
000020b0  ff 5a f7 5f ee e2 07 00  03 00 00 00 c1 0e 00 00  |.Z._............|
000020c0  ff 5a f7 5f 13 e3 07 00  03 00 01 00 31 0a 00 00  |.Z._........1...|
000020d0  ff 5a f7 5f 19 e3 07 00  03 00 18 00 c7 10 00 00  |.Z._............|
000020e0  ff 5a f7 5f 23 e3 07 00  00 00 00 00 00 00 00 00  |.Z._#...........|
000020f0  ff 5a f7 5f f3 09 08 00  03 00 01 00 32 0a 00 00  |.Z._........2...|
00002100  ff 5a f7 5f 15 0a 08 00  03 00 18 00 e0 10 00 00  |.Z._............|
00002110  ff 5a f7 5f 1f 0a 08 00  00 00 00 00 00 00 00 00  |.Z._............|
00002120  ff 5a f7 5f 0c 31 08 00  03 00 00 00 c0 0e 00 00  |.Z._.1..........|
00002130  ff 5a f7 5f 34 31 08 00  03 00 18 00 f2 10 00 00  |.Z._41..........|
00002140  ff 5a f7 5f 3e 31 08 00  00 00 00 00 00 00 00 00  |.Z._>1..........|
00002150  ff 5a f7 5f 13 58 08 00  03 00 00 00 c2 0e 00 00  |.Z._.X..........|
00002160  ff 5a f7 5f 34 58 08 00  03 00 01 00 38 0a 00 00  |.Z._4X......8...|
00002170  ff 5a f7 5f 3a 58 08 00  03 00 18 00 9f 11 00 00  |.Z._:X..........|
00002180  ff 5a f7 5f 44 58 08 00  00 00 00 00 00 00 00 00  |.Z._DX..........|
00002190  ff 5a f7 5f 2d 7f 08 00  03 00 00 00 c4 0e 00 00  |.Z._-...........|
000021a0  ff 5a f7 5f 51 7f 08 00  03 00 01 00 3c 0a 00 00  |.Z._Q.......<...|
000021b0  ff 5a f7 5f 56 7f 08 00  03 00 18 00 0c 18 00 00  |.Z._V...........|
000021c0  ff 5a f7 5f 61 7f 08 00  00 00 00 00 00 00 00 00  |.Z._a...........|
000021d0  ff 5a f7 5f d5 f2 08 00  03 00 18 00 00 00 00 00  |.Z._............|
000021e0  ff 5a f7 5f fc f2 08 00  00 00 00 00 00 00 00 00  |.Z._............|
000021f0  ff 5a f7 5f dc a4 0c 00  03 00 00 00 e5 0e 00 00  |.Z._............|
00002200  ff 5a f7 5f 00 a5 0c 00  03 00 01 00 af 0a 00 00  |.Z._............|
00002210  ff 5a f7 5f 06 a5 0c 00  03 00 18 00 92 13 00 00  |.Z._............|
00002220  ff 5a f7 5f 10 a5 0c 00  00 00 00 00 00 00 00 00  |.Z._............|
00002230  ff 5a f7 5f e3 c4 0c 00  03 00 00 00 e1 0e 00 00  |.Z._............|
00002240  ff 5a f7 5f 06 c5 0c 00  03 00 01 00 ae 0a 00 00  |.Z._............|
00002250  ff 5a f7 5f 0b c5 0c 00  03 00 18 00 bd 11 00 00  |.Z._............|
00002260  ff 5a f7 5f 15 c5 0c 00  00 00 00 00 00 00 00 00  |.Z._............|
00002270  ff 5a f7 5f 14 ec 0c 00  03 00 00 00 de 0e 00 00  |.Z._............|
00002280  ff 5a f7 5f 27 ec 0c 00  03 00 01 00 b0 0a 00 00  |.Z._'...........|
00002290  ff 5a f7 5f 2d ec 0c 00  03 00 18 00 6c 12 00 00  |.Z._-.......l...|
000022a0  ff 5a f7 5f 37 ec 0c 00  00 00 00 00 00 00 00 00  |.Z._7...........|
000022b0  ff 5a f7 5f 02 13 0d 00  03 00 00 00 e5 0e 00 00  |.Z._............|
000022c0  ff 5a f7 5f 28 13 0d 00  03 00 18 00 ca 10 00 00  |.Z._(...........|
000022d0  ff 5a f7 5f 32 13 0d 00  00 00 00 00 00 00 00 00  |.Z._2...........|
000022e0  ff 5a f7 5f 1c 3a 0d 00  03 00 00 00 e7 0e 00 00  |.Z._.:..........|
000022f0  ff 5a f7 5f 40 3a 0d 00  03 00 01 00 af 0a 00 00  |.Z._@:..........|
00002300  ff 5a f7 5f 46 3a 0d 00  03 00 18 00 c0 10 00 00  |.Z._F:..........|
00002310  ff 5a f7 5f 50 3a 0d 00  00 00 00 00 00 00 00 00  |.Z._P:..........|
00002320  ff 5a f7 5f 20 61 0d 00  03 00 00 00 e8 0e 00 00  |.Z._ a..........|
00002330  ff 5a f7 5f 42 61 0d 00  03 00 01 00 ae 0a 00 00  |.Z._Ba..........|
00002340  ff 5a f7 5f 48 61 0d 00  03 00 18 00 b4 10 00 00  |.Z._Ha..........|
00002350  ff 5a f7 5f 52 61 0d 00  00 00 00 00 00 00 00 00  |.Z._Ra..........|
00002360  ff 5a f7 5f 3f 88 0d 00  03 00 01 00 ab 0a 00 00  |.Z._?...........|
00002370  ff 5a f7 5f 65 88 0d 00  03 00 18 00 8a 10 00 00  |.Z._e...........|
00002380  ff 5a f7 5f 6f 88 0d 00  00 00 00 00 00 00 00 00  |.Z._o...........|
00002390  ff 5a f7 5f 43 af 0d 00  03 00 01 00 a9 0a 00 00  |.Z._C...........|
000023a0  ff 5a f7 5f 65 af 0d 00  03 00 18 00 78 10 00 00  |.Z._e.......x...|
000023b0  ff 5a f7 5f 6f af 0d 00  00 00 00 00 00 00 00 00  |.Z._o...........|
000023c0  ff 5a f7 5f 5c d6 0d 00  03 00 01 00 a6 0a 00 00  |.Z._\...........|
000023d0  ff 5a f7 5f 80 d6 0d 00  03 00 18 00 7a 10 00 00  |.Z._........z...|
000023e0  ff 5a f7 5f 8a d6 0d 00  00 00 00 00 00 00 00 00  |.Z._............|
000023f0  ff 5a f7 5f 61 fd 0d 00  03 00 00 00 ea 0e 00 00  |.Z._a...........|
00002400  ff 5a f7 5f 84 fd 0d 00  03 00 01 00 a5 0a 00 00  |.Z._............|
00002410  ff 5a f7 5f 92 fd 0d 00  00 00 00 00 00 00 00 00  |.Z._............|
00002420  ff 5a f7 5f 7b 24 0e 00  03 00 00 00 e8 0e 00 00  |.Z._{$..........|
00002430  ff 5a f7 5f a0 24 0e 00  03 00 01 00 a1 0a 00 00  |.Z._.$..........|
00002440  ff 5a f7 5f a5 24 0e 00  03 00 18 00 76 10 00 00  |.Z._.$......v...|
00002450  ff 5a f7 5f af 24 0e 00  00 00 00 00 00 00 00 00  |.Z._.$..........|
00002460  ff 5a f7 5f 88 4b 0e 00  03 00 18 00 78 10 00 00  |.Z._.K......x...|
00002470  ff 5a f7 5f ae 4b 0e 00  00 00 00 00 00 00 00 00  |.Z._.K..........|
00002480  ff 5a f7 5f 9a 72 0e 00  03 00 00 00 e6 0e 00 00  |.Z._.r..........|
00002490  ff 5a f7 5f be 72 0e 00  03 00 01 00 a0 0a 00 00  |.Z._.r..........|
000024a0  ff 5a f7 5f c3 72 0e 00  03 00 18 00 b4 10 00 00  |.Z._.r..........|
000024b0  ff 5a f7 5f cd 72 0e 00  00 00 00 00 00 00 00 00  |.Z._.r..........|
000024c0  ff 5a f7 5f a4 99 0e 00  03 00 00 00 df 0e 00 00  |.Z._............|
000024d0  ff 5a f7 5f c6 99 0e 00  03 00 01 00 9f 0a 00 00  |.Z._............|
000024e0  ff 5a f7 5f cb 99 0e 00  03 00 18 00 6d 11 00 00  |.Z._........m...|
000024f0  ff 5a f7 5f d5 99 0e 00  00 00 00 00 00 00 00 00  |.Z._............|
00002500  ff 5a f7 5f bb c0 0e 00  03 00 00 00 cd 0e 00 00  |.Z._............|
00002510  ff 5a f7 5f df c0 0e 00  03 00 01 00 9c 0a 00 00  |.Z._............|
00002520  ff 5a f7 5f e5 c0 0e 00  03 00 18 00 71 2a 00 00  |.Z._........q*..|
00002530  ff 5a f7 5f ef c0 0e 00  00 00 00 00 00 00 00 00  |.Z._............|
00002540  ff 5a f7 5f 64 34 0f 00  03 00 18 00 00 00 00 00  |.Z._d4..........|
00002550  ff 5a f7 5f 8a 34 0f 00  00 00 00 00 00 00 00 00  |.Z._.4..........|
00002560  00 5b f7 5f 6c 92 01 00  03 00 00 00 c4 0e 00 00  |.[._l...........|
00002570  00 5b f7 5f 82 92 01 00  03 00 18 00 02 14 00 00  |.[._............|
00002580  00 5b f7 5f 8c 92 01 00  00 00 00 00 00 00 00 00  |.[._............|
00002590  00 5b f7 5f 79 a1 01 00  03 00 00 00 ca 0e 00 00  |.[._y...........|
000025a0  00 5b f7 5f 8f a1 01 00  03 00 01 00 9d 0a 00 00  |.[._............|
000025b0  00 5b f7 5f 94 a1 01 00  03 00 18 00 a3 11 00 00  |.[._............|
000025c0  00 5b f7 5f 9d a1 01 00  00 00 00 00 00 00 00 00  |.[._............|
000025d0  00 5b f7 5f 6b c8 01 00  03 00 00 00 bb 0e 00 00  |.[._k...........|
000025e0  00 5b f7 5f 8f c8 01 00  03 00 01 00 98 0a 00 00  |.[._............|
000025f0  00 5b f7 5f 95 c8 01 00  03 00 18 00 b9 12 00 00  |.[._............|
00002600  00 5b f7 5f 9f c8 01 00  00 00 00 00 00 00 00 00  |.[._............|
00002610  00 5b f7 5f 74 ef 01 00  03 00 00 00 c3 0e 00 00  |.[._t...........|
00002620  00 5b f7 5f 96 ef 01 00  03 00 01 00 94 0a 00 00  |.[._............|
00002630  00 5b f7 5f 9c ef 01 00  03 00 18 00 17 11 00 00  |.[._............|
00002640  00 5b f7 5f a6 ef 01 00  00 00 00 00 00 00 00 00  |.[._............|
00002650  00 5b f7 5f 8d 16 02 00  03 00 00 00 c5 0e 00 00  |.[._............|
00002660  00 5b f7 5f b2 16 02 00  03 00 01 00 90 0a 00 00  |.[._............|
00002670  00 5b f7 5f b8 16 02 00  03 00 18 00 ce 10 00 00  |.[._............|
00002680  00 5b f7 5f c2 16 02 00  00 00 00 00 00 00 00 00  |.[._............|
00002690  00 5b f7 5f 8e 3d 02 00  03 00 00 00 c6 0e 00 00  |.[._.=..........|
000026a0  00 5b f7 5f af 3d 02 00  03 00 01 00 8c 0a 00 00  |.[._.=..........|
000026b0  00 5b f7 5f b5 3d 02 00  03 00 18 00 c9 10 00 00  |.[._.=..........|
000026c0  00 5b f7 5f bf 3d 02 00  00 00 00 00 00 00 00 00  |.[._.=..........|
000026d0  00 5b f7 5f a8 64 02 00  03 00 00 00 c7 0e 00 00  |.[._.d..........|
000026e0  00 5b f7 5f cd 64 02 00  03 00 01 00 89 0a 00 00  |.[._.d..........|
000026f0  00 5b f7 5f d3 64 02 00  03 00 18 00 a9 10 00 00  |.[._.d..........|
00002700  00 5b f7 5f dc 64 02 00  00 00 00 00 00 00 00 00  |.[._.d..........|
00002710  00 5b f7 5f b4 8b 02 00  03 00 00 00 c4 0e 00 00  |.[._............|
00002720  00 5b f7 5f d6 8b 02 00  03 00 01 00 87 0a 00 00  |.[._............|
00002730  00 5b f7 5f dc 8b 02 00  03 00 18 00 96 10 00 00  |.[._............|
00002740  00 5b f7 5f e5 8b 02 00  00 00 00 00 00 00 00 00  |.[._............|
00002750  00 5b f7 5f ca b2 02 00  03 00 00 00 c8 0e 00 00  |.[._............|
00002760  00 5b f7 5f ee b2 02 00  03 00 01 00 86 0a 00 00  |.[._............|
00002770  00 5b f7 5f f4 b2 02 00  03 00 18 00 7a 10 00 00  |.[._........z...|
00002780  00 5b f7 5f fe b2 02 00  00 00 00 00 00 00 00 00  |.[._............|
00002790  00 5b f7 5f d2 d9 02 00  03 00 00 00 c6 0e 00 00  |.[._............|
000027a0  00 5b f7 5f f4 d9 02 00  03 00 01 00 84 0a 00 00  |.[._............|
000027b0  00 5b f7 5f f9 d9 02 00  03 00 18 00 6b 10 00 00  |.[._........k...|
000027c0  00 5b f7 5f 03 da 02 00  00 00 00 00 00 00 00 00  |.[._............|
000027d0  00 5b f7 5f f2 00 03 00  03 00 18 00 7f 10 00 00  |.[._............|
000027e0  00 5b f7 5f 1b 01 03 00  00 00 00 00 00 00 00 00  |.[._............|
000027f0  00 5b f7 5f ef 27 03 00  03 00 00 00 bc 0e 00 00  |.[._.'..........|
00002800  00 5b f7 5f 12 28 03 00  03 00 01 00 82 0a 00 00  |.[._.(..........|
00002810  00 5b f7 5f 17 28 03 00  03 00 18 00 c7 11 00 00  |.[._.(..........|
00002820  00 5b f7 5f 21 28 03 00  00 00 00 00 00 00 00 00  |.[._!(..........|
00002830  00 5b f7 5f a6 9b 03 00  03 00 18 00 00 00 00 00  |.[._............|
00002840  00 5b f7 5f cf 9b 03 00  00 00 00 00 00 00 00 00  |.[._............|
00002850  00 5b f7 5f 44 06 05 00  03 00 00 00 d6 0e 00 00  |.[._D...........|
00002860  00 5b f7 5f 66 06 05 00  03 00 01 00 74 0a 00 00  |.[._f.......t...|
00002870  00 5b f7 5f 6c 06 05 00  03 00 18 00 46 12 00 00  |.[._l.......F...|
00002880  00 5b f7 5f 76 06 05 00  00 00 00 00 00 00 00 00  |.[._v...........|
00002890  00 5b f7 5f ce 23 05 00  03 00 01 00 73 0a 00 00  |.[._.#......s...|
000028a0  00 5b f7 5f f4 23 05 00  03 00 18 00 c9 10 00 00  |.[._.#..........|
000028b0  00 5b f7 5f fd 23 05 00  00 00 00 00 00 00 00 00  |.[._.#..........|
000028c0  00 5b f7 5f d0 4a 05 00  03 00 00 00 d4 0e 00 00  |.[._.J..........|
000028d0  00 5b f7 5f f2 4a 05 00  03 00 01 00 74 0a 00 00  |.[._.J......t...|
000028e0  00 5b f7 5f f8 4a 05 00  03 00 18 00 c7 10 00 00  |.[._.J..........|
000028f0  00 5b f7 5f 01 4b 05 00  00 00 00 00 00 00 00 00  |.[._.K..........|
00002900  00 5b f7 5f ec 71 05 00  03 00 00 00 de 0e 00 00  |.[._.q..........|
00002910  00 5b f7 5f 14 72 05 00  03 00 18 00 91 10 00 00  |.[._.r..........|
00002920  00 5b f7 5f 1e 72 05 00  00 00 00 00 00 00 00 00  |.[._.r..........|
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 05, 2021, 06:30:33 pm
This python script works with /dev/input/event1 and with /dev/input/mice.
It's mute with /dev/input/event0

Code: [Select]
import struct

#f = open("/dev/input/mice", "rb");
f = open("/dev/input/event1", "rb");
while 1:
  data = f.read(3)
  print struct.unpack('3b',data)

Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 05, 2021, 06:44:19 pm
All the GetMouse(x,y) functions offered by SDL are  noisy. If I put the pen stick in a fixed position, the coordinates (x,y) oscillate both around 6 values.

I have developed a C module to read the (x,y) coordinates directly from /dev/input/event1. Of course these values are still noisy but things go better when they pass through a function that evaluates their mean value. It needs to sum 16 times before producing anything stable.

It is also well possible that there isn't anything generated at all. In that case Linux or SDL has no means to know that some part of your LCD is labeled as a soft button. That is up to you to manage, using the coordinates from the touchscreen.

umm, I have also noticed that if I move the pen-stick to the position of one of five the icon-buttons, I see its (x,y) coordinates.

It loos like the kernel is not processing soft-buttons. But I am not sure  :-//
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 05, 2021, 07:09:17 pm
Linux input events are defined in /usr/include/linux/input.h: struct input_event (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input.h).  On a 32-bit system with 32-bit time, each event is 16 bytes long:
    uint32_t  seconds;
    uint32_t  nanoseconds;
    uint16_t  type;
    uint16_t  code;
    uint32_t  value;
where:
This is a binary interface provided by the Linux kernel, and is stable.  (Well, except that years and years ago, certain developers insisted adding an ioctl()-based interface, "deprecating" the standard read interface, because a certain daemon system prefers ioctl()s, and they thought the interface might change at some point, at which time having an ioctl() interface would allow supporting both binary event formats.  The interface hasn't changed for two decades; it has only been extended in a completely backwards compatible fashion.)

If I put the pen stick in a fixed position, the coordinates (x,y) oscillate both around 6 values.
That is quite typical for resistive touch panels, I guess.

I have also noticed that if I move the pen-stick to the position of one of five the icon-buttons, I see its (x,y) coordinates.
Yup, so they are not buttons at all, just drawings in an area outside the display, but within the touch panel.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 07, 2021, 12:08:04 am
Note that the jitter in the coordinates is usually not because of the touch panel itself, but more because of the low precision of the ADCs used.  So, switching to a different panel is unlikely to help.

If there is any room in the enclosure, and it has SPI/I2C/serial pins you can interface to, you can use the same panel but your own touch controller, say based on TI TSC2046EIPWR or similar, maybe interfaced to a small microcontroller (ATtiny24?).  If you have USB available, that would be perfect, because then you only need a native USB microcontroller to provide a USB HID interface, and you don't need any software drivers or anything.
If you are TRULY lucky, maybe it uses an older touch screen controller that is pin-compatible with a newer, better one, that you could just replace?

The purpose for the small microcontroller is to do in hardware what you would need to do in software on the Linux side, producing events only when something interesting occurs instead of all the time.  (Low-power microcontrollers are optimal.)

The idea is that when there is no touch, the axes are disconnected (resistance very high).  Typical resistive panels axis resistance is between 100 and 1000 ohms, by the way; you can measure those if you can access its four-wire flat panel connector.  The measurements are ratiometric, because we want to know the effective resistance, instead of any particular voltage.  A little noise, say 1-2 LSB, is also not a problem.  When you do touch, one axis acts like a voltage divider, and the touch point along that axis can be read by measuring the voltage on the other axis.

You sample the axes say 100-1000 times a second.  This rate determines the touch latency, 10ms to 1ms; you don't want it to be too long, because then the display feels "laggy".

When you do detect a touch, you up the sample rate to say 10,000 samples a second, so that you can filter the results and provide a new event whenever the touch point truly moves.  I guess you could do with an 8-bit ENOB ADC, if the sample rate was high enough, as you only need a couple of extra bits of precision; so perhaps, perhaps, an ATtiny84 could do this by itself.

(I do happen to have an ATtiny84 (a DigiSpark clone) and some 2.4" displays with resistive touch panels, so really I should have tested whether an ATtiny84 and its 8-bit ADC alone would suffice – they're tiny, so you should be able to tuck one somewhere, with one or two ceramic caps (0.1µF and 1µF as is typical) to stabilize its operating voltage – but hey, I'm just another hobbyist; even if I couldn't do it, does not mean it is not possible.)

So, really, it all boils down to whether you can add that small microcontroller to the device, and hijack the touch screen from whatever crappy controller it is now using.
If you have a free USB, you don't need any software, just a native-USB microcontroller providing an USB HID interface, and the Linux kernel will do the work for you.  If you use I2C, SPI, or serial, you only need a very simple and lightweight uinput daemon.  That I can help with: it'd take me less than an hour to write one for you.  (The uinput daemon takes the serial data, and tells the Linux kernel about the input events; it has to have read/write access to the /dev/uinput device to do this.  These will then be available to any program as normal input events, including to SDL.)

(Also, instead of doing the touch screen adjustments and filtering in SDL, it is possible to use a simple daemon that grabs the input event device, and provides its own filtered input device.  Grabbing prevents other processes from seeing the read input events, and the daemon produces a new input event device that looks and behaves exactly like the hardware ones.  It can do the filtering in software, avoiding all the mess elsewhere, and is really quite lightweight.  Maybe this is worth experimenting with first?  It would have to provide initial touch immediately to avoid latencies, and differentiate between movement and positioning jitter, but that's a simple numerical filtering problem rather easily solved – although you would definitely need to experiment a bit with it.  Let me know if you want to proceed with this instead.)
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 07, 2021, 10:00:59 am
Note that the jitter in the coordinates is usually not because of the touch panel itself, but more because of the low precision of the ADCs used.

Don't know, I bought it second hand deal. I know it was priced 500 euro back in 2000. Crappy ADC? Too early technology with the touchscreen film? Who knows. And on the top of this, every ADC is affected by noise in a way you have to filter its samples. Which brings me to question about the kernel driver module, which is not the official one because the dropped the support after the last kernel v2.4, the v2.6 was never support, so what(1) I am using is clearly made by an hobbyist and it doesn't filter anything.

(1)
Code: [Select]
uname -r
2.6.23-proof

If there is any room in the enclosure, and it has SPI/I2C/serial pins you can interface to, you can use the same panel but your own touch controller, say based on TI TSC2046EIPWR or similar

Unfortunately there is no space anywhere inside the plastic enclosure. The PDA is so small that it literally fits in a shirt pocket  :o

However, this is a great idea for a second similar project: take my old 14.1" laptop, and convert it into a tablet by adding a resistive touchscreen film on the top of the screen.

In this case it needs a controller, so bingo! We can add a good one on a free usb port, or even on a serial port :D
 
Also, instead of doing the touch screen adjustments and filtering in SDL, it is possible to use a simple daemon that grabs the input event device, and provides its own filtered input device.

Great great idea! Thanks  :D
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 08, 2021, 02:53:39 am
Don't know, I bought it second hand deal. I know it was priced 500 euro back in 2000. Crappy ADC? Too early technology with the touchscreen film? Who knows. And on the top of this, every ADC is affected by noise in a way you have to filter its samples. Which brings me to question about the kernel driver module, which is not the official one because the dropped the support after the last kernel v2.4, the v2.6 was never support, so what(1) I am using is clearly made by an hobbyist and it doesn't filter anything.
Do you have the sources for the driver?  I'd like to take a looksee.

Of course an userspace uinput daemon can additionally handle the four buttons, producing keyboard events for those, and do the X/Y mapping and calibration.  That'll make the touch interface usable everywhere.  But, depending on the hardware integration, all that could be done in the driver, too.

Usually, these drivers are not so complicated that porting them to current kernels is too difficult, so I could take a looksee.  Which kernel version can you run, otherwise, on that hardware?  Have you opened the device to look at what chip handles the touchscreen?  Because of how these resistive touch panels are accessed, all four wires will go to the same chip; usually a dedicated resistive touch panel controller chip.  XPT2046 (https://www.buydisplay.com/download/ic/XPT2046.pdf) is a very common one (from 2007), and because your event1 also reports pressure, it really looks like something very similar is being used... If the driver uses SPI to read it, then it should be simple to up the sample rate for filtering the sampled coordinates; and providing the X/Y coefficients and button locations via module parameters (so they'd be very easy to maintain) is quite straightforward.

(To calibrate, one would unload the driver, load it with no mappings, then run a small calibration application, then unload the driver, and load it with the calibrated settings.  If the settings are acceptable, stick an options touchmodule name1=value1 name2=value2 ... line in /etc/modprobe.conf or /etc/modprobe.d/touchmodule.conf, and the parameters will be passed to the touch driver whenever the module is loaded.)

However, this is a great idea for a second similar project: take my old 14.1" laptop, and convert it into a tablet by adding a resistive touchscreen film on the top of the screen.
Capacitive multitouch panels are nicer, though; I recommend one with an integrated USB controller.  They should provide a standard USB HID touch panel interface, so no drivers should be needed at all.  At 14.1" inches, I think a resistive one will be much cheaper, though.  (I do believe a Teensy LC (https://www.pjrc.com/store/teensylc.html) would make for a pretty good resistive touch controller; its ADC has 12+ bits (16 bits, but 12-13 effective/noise-free bits), it's cheap and small, has native USB (so will support USB HID, and no drivers needed!), and it is very nice to program in Arduino via Teensyduino add-on.  All you need is to connect the four resistive touch panel connectors to suitable pins on the Teensy LC.)

I've bought some displays from BuyDisplay (EastRising), and I like the displays and documentation they provide.  They also have quite a selection of smaller capacitive and resistive touch panels (https://www.buydisplay.com/accessory/touch-panel), but I haven't played with those yet.

(I'd also love to play with a surface acoustic wave touch panel kit: it is a glass panel, with ultrasonic transducers and sensors at the corners, and detect touch by how it affects the acoustic waves on the surface of the panel.  A multitouch wide-but-not-tall tempered glass one might make for a very fancy transparent keyboard, you see..)
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 08, 2021, 12:04:22 pm
Do you have the sources for the driver?  I'd like to take a looksee.

At the moment I only have the hardware, I mean the official support kernel was v2.4.*, then the company fist made the support entirely decommissioned then stop selling the product, and for a some years hobbyists tried to maintain the interest by privately selling second hand PDAs on eBay and by trying to support some versions in the v2.6 family.

Practically, after the v2.4 decommission, there were only five major releases, of which the 2.6.23 is the last one with everything working in a usable way.

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>

#define EVENT_DEVICE    "/dev/input/event1"
#define EVENT_TYPE      EV_ABS
#define EVENT_CODE_X    ABS_X
#define EVENT_CODE_Y    ABS_Y

int main()
{
    struct input_event ev;
    int                fd;
    char               name[256] = "Unknown";

    fd = open(EVENT_DEVICE, O_RDONLY);
    if (fd == -1)
    {
        fprintf(stderr, "%s is not a vaild device\n", EVENT_DEVICE);
        return EXIT_FAILURE;
    }

    ioctl(fd, EVIOCGNAME(sizeof(name)), name);
    printf("%s\n", name);

    return EXIT_SUCCESS;
}

I wrote this simple program to see the device-name.

Which is reported as:

Code: [Select]
 # ./devicename
Corgi Touchscreen

Which kernel version can you run, otherwise, on that hardware?

Only 2.6.23, I mean without investing hundred hours fixing a lot a lot stuff with other kernel versions :o

Have you opened the device to look at what chip handles the touchscreen?

I will. I still have to understand how to open the plastic without breaking it :D
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: janoc on January 08, 2021, 12:58:32 pm
I wrote this simple program to see the device-name.

Which is reported as:

Code: [Select]
 # ./devicename
Corgi Touchscreen


Why don't you say straight away that you have a Sharp Zaurus?

I still have my  SL-C760 (Husky) somewhere.

However, given how ancient the hardware is now (20 years some models!) and pretty much zero support for the XScale CPUs in these things (ancient ARMv5 architecture - yes, Intel made ARM processors ...), I wouldn't have high hopes for getting this usable. Even GCC has deprecated and removed support for this architecture, so no wonder there is no way to get more recent kernels working.

I remember that taking the device apart was not quite trivial, I don't think I have actually managed myself - also didn't want to break it.

It was (and still is) a cute and cool little device, I have used mine for a quite a long time as both a PDA and effectively a laptop once I have got wifi working on it and even ported some software to it (such as the Dolphin C64 emulator - also used SDL).

However, unless you have a specific need to get your project working on this hardware, I would strongly suggest focusing your efforts elsewhere (e.g. a cheap Android tablet). With no software support and 32MB (!) of RAM or so you are going to be constantly hitting your head against a wall. Heck, even getting a wifi or ethernet compact flash card for it will be a challenge today.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 08, 2021, 12:59:58 pm
I wrote this simple program to see the device-name.
I would have thought that
  cat /sys/class/input/event1/device/name
would have been easier!  ;D

Besides, realpath /sys/class/input/event1/device/device/driver tells the most interesting thing, the input event driver sysfs path.

So, I assume corgi_ts.c v2.6.23.17 (https://elixir.bootlin.com/linux/v2.6.23.17/source/drivers/input/touchscreen/corgi_ts.c) is the driver you're using, with v2.6.34.15 (https://elixir.bootlin.com/linux/v2.6.34.15/source/drivers/input/touchscreen/corgi_ts.c) being its latest known version?  (There are only minor changes between the two versions; include paths and macro name changes.)

If so, you'll find a TI ADS7846 (https://www.ti.com/product/ADS7846) (PDF datasheet (https://www.ti.com/lit/ds/symlink/ads7846.pdf)) or a fully compatible IC inside that PDA.  However, it is on the same SSP interface the LCD controller and the battery monitoring are, see arch/arm/mach-pxa/corgi_ssp.c (https://elixir.bootlin.com/linux/v2.6.34.15/source/arch/arm/mach-pxa/corgi_ssp.c), and I wonder why they synchronize it with the horizontal retrace (the higher-rate one).  Other than that, it shouldn't be difficult at all to mangle that driver to provide adjusted filtered events.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 08, 2021, 01:11:00 pm
I would have thought that
  cat /sys/class/input/event1/device/name
would have been easier!  ;D

yup, but for certain incomprehensible reasons it's not supported  :o

Code: [Select]
cat /sys/class/input/event1/device/name
cat: /sys/class/input/event1/device/name: No such file or directory

Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: janoc on January 08, 2021, 04:05:00 pm
I would have thought that
  cat /sys/class/input/event1/device/name
would have been easier!  ;D

yup, but for certain incomprehensible reasons it's not supported  :o

Code: [Select]
cat /sys/class/input/event1/device/name
cat: /sys/class/input/event1/device/name: No such file or directory



Probably sysfs is not mounted. Try:

Code: [Select]
mount -t sysfs sysfs /sys
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 08, 2021, 04:52:58 pm
Probably sysfs is not mounted. Try:

it's mounted, but it doesn't export all one expects to find

Code: [Select]
ls /sys/class/input/event1/device/
bus/          driver/       input:input1/ modalias      power/        subsystem/    uevent

Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 08, 2021, 05:05:40 pm
TI ADS7846

Confirmed! I opened the LCD, I read "ADS7846" on the top of chip :-+
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 08, 2021, 08:10:23 pm
Waitaminute.

Latest kernels do have arch/arm/mach-pxa/corgi.c (https://elixir.bootlin.com/linux/latest/source/arch/arm/mach-pxa/corgi.c), which is enabled by CONFIG_PXA_SHARPSL=y and CONFIG_MACH_CORGI=y.  The backlight is enabled by CONFIG_LCD_CORGI=y.  The battery is enabled by CONFIG_SENSORS_MAX1111.  The touch controller is enabled by CONFIG_TOUCHSCREEN_ADS7846=y.  Are you sure the latest kernels do not work?  As I see it, you just need to construct a completely different kernel configuration, one that produces these.  The MAX1111, LCD backlight, and ADS7846 all "connect" via the correct SPI master names, so this should Just Work; you don't even need a device tree blob.

If true, and you could run latest kernels, it would be near-trivial to add calibration and/or filtering and a small number of virtual buttons to the ADS7846.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 08, 2021, 08:47:53 pm
Are you sure the latest kernels do not work?

The PDA looks a modified clone of a commercial product, this mean nothing does work without specific patches. I haven't yet received sources, but the previous owner has already told me that there are a lot of patches applied to vanilla, and without them nothing does work.

At the moment, I am fixing stuff with the rootfs, which is 14 years old and needs some update. For instance "wget" is not able to download any file from any modern Webserver because it doesn't support SSL and this stuff. This clearly needs to be fixed before thinking anything else  :D

The TS is working enough good for an SDL- raw application, which will be the 90% of my usage with this PDA.

(kind of Kindle eBook reader, but homemade)

What I really need is a TS-daemon, in the way you described above.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 08, 2021, 09:47:50 pm
The PDA looks a modified clone of a commercial product, this mean nothing does work without specific patches. I haven't yet received sources, but the previous owner has already told me that there are a lot of patches applied to vanilla, and without them nothing does work.
Oh, okay.

It doesn't look like it has any graphics acceleration, either, just a 640x480 framebuffer that supports 1, 2, 4, and 8-bit indexed color, and 16-bit true color (5 low bits blue, 6 middle bits green, 5 high bits red).  Writing your own tiny framebuffer functions (that use around a megabyte of RAM for the image buffering), you can get better results than with SDL, as you can make the drawing operations not only update the scribble surface, but also the framebuffer itself at the same time.  An erase operation clears scribble surface data to transparent, and reverts framebuffer contents to that of the image.  With libpng, you can load and save PNG images natively.

What I really need is a TS-daemon, in the way you described above.
Do you need a skeleton to get started?  This laptop has a touchpad and a nipple, so it wouldn't be difficult to whip one up.

Eehh... by "nipple" I mean "pointing stick", and by "whip one up" I am referring to creating a basic input-uinput translator daemon.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: DiTBho on January 08, 2021, 10:46:37 pm
Oh, okay

I have just read the previous owner's email again. He warns about problems on booting modern kernels not only due to the specific patches  but also because the firmware can only loads 5Mbyte of binary.

I hadn't notice this detail when I read his email, but that means a kernel must be <= 5Mb, which was not a problem with kernels 2.4, not a problem with early kernels 2.6, but it's definitively a problem with kernels 4 and 5, which tend to be fat and you need to strip down everything in order to reduce the final size. It's rather annoying, and now I understand why he used an old 2.6.23 kernel.

2.6.23 can't mount modern glibc-rootfs, chroot claims "too old kernel" and refuses to continue.
The only option here seems a "uclibc-rootfs" or a "MUSL-rootfs", but I am not sure if it's a good idea.

I will think about it later, at the moment I have a fully working crossbuilder(1) aligned with the 2007 rootfs I have, so I can selectively recompile and update only the stuff I need.

For example, today it cost me two hours to setup the crossbuilder, but "wget" has just been compiled and uploaded to the target, and now it can download from HTTPS urls, and I no more see this:
Code: [Select]
OpenSSL: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
Unable to establish SSL connection.

Not a clean solution, but it's practically fine ;D

(1)

Writing your own tiny framebuffer functions

Yup, there is no 2D accelerator, there is just a simple framebuffer. Yesterday, I partially wrote something similar. LCD_Pixel_Set(x,y,color) is already working. All the rest still needs to be written, but hey? That function is the most important graphic primitive :D

With libpng, you can load and save PNG images natively.

Great idea!

I have already compiled and installed this (http://www.libpng.org) one (Portable Network Graphics library, official website) as "static library", and I can link its binary with my wild application.

Do you need a skeleton to get started?

Yes, please. I have never written anything similar.
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 09, 2021, 06:49:45 am
Yup, there is no 2D accelerator, there is just a simple framebuffer. Yesterday, I partially wrote something similar. LCD_Pixel_Set(x,y,color) is already working. All the rest still needs to be written, but hey? That function is the most important graphic primitive :D
Right.  Since the two image buffers reside in RAM, having the underlying image with the same pixel format as the framebuffer makes things easier.  The overlay, however, could be 8 or even 4 bit indexed color, saving memory.  A scribble_putpixel(x,y,color) will modify the scribble buffer, and update the framebuffer too.  You'll eventually implement a scribble_line(x0,y0,x1,y1,color), I bet; a trick with the 4 bit indexed color in the pairwise direction is to do two step iterations in each loop iteration (and thus update either 2 or 4 pixels in the framebuffer), except for an initial odd pixel and/or a final odd pixel that you handle separately.  In the nonpairwise direction, there is no special magic needed to be efficient.

Yes, please. I have never written anything similar.
Already wrote the initial part, until some lint or something got underneath my dash and up keys on my laptop keyboard, and now they don't work.  Neither vacuum nor pressured air seems to dislodge it.  >:(
I'll post the example daemon and Makefile here as soon as I get this keyboard working again, and the rest of the daemon written!
Title: Re: SDL & touchscreen on Linux, why do I get rotated coordinates (x,y)?
Post by: Nominal Animal on January 09, 2021, 02:45:57 pm
Here goes.  First, a Makefile to tie all together:
Code: [Select]
CC      := gcc
CFLAGS  := -Wall -Wextra -O2
LDFLAGS := -lm
PROGS   := event-pup

.PHONY: all clean

all: $(PROGS)

clean:
rm -f $(PROGS) known-keys.h

known-keys.h:
./generate-known-keys

pup.c: known-keys.h

event-pup: pup.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@

If you have issues copy-pasting the tab indentation, run sed -e 's|^ |\t| -i Makefile to fix.

For the virtual buttons, we want to be able to use the key names.  To generate the name-to-KEY_ code array, we use a script, generate-known-keys:
Code: [Select]
#!/bin/sh
rm -f known-keys.h
(
    printf '#ifndef   KNOWN_KEYS_H\n'
    printf '#define   KNOWN_KEYS_H\n'
    printf '#include <stdint.h>\n'
    printf '#include <linux/input.h>\n'
    printf '\n'
    printf 'static const struct {\n'
    printf '    const char *const    name;\n'
    printf '    const uint_fast16_t  code;\n'
    printf '} known_keys[] = {\n'
    gcc -E -dM /usr/include/linux/input.h | awk '$1 == "#define" && $2 ~ /^KEY_/ { printf "    { .name = %-19s .code = %s },\n", "\"" substr($2, 5) "\",", $2 }' | sort -u
    printf '    { .name = NULL, .code = 0 }\n'
    printf '};\n'
    printf '\n'
    printf '#endif /* KNOWN_KEYS_H */\n'
) > known-keys.h

When run, it generates a header file known-keys.h.

Finally, the daemon itself, pup.c:
Code: [Select]
// SPDX-License-Identifier: GPL3

#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include "known-keys.h"

#ifndef  USB_VENDOR
#define  USB_VENDOR   0xDEAD
#endif
#ifndef  USB_PRODUCT
#define  USB_PRODUCT  0xBEEF
#endif
#ifndef  USB_VERSION
#define  USB_VERSION  0
#endif
#ifndef  USB_NAME
#define  USB_NAME     "Puppers"
#endif

#ifndef  X_MIN
#define  X_MIN  0
#endif
#ifndef  X_MAX
#define  X_MAX  2047
#endif
#ifndef  Y_MIN
#define  Y_MIN  0
#endif
#ifndef  Y_MAX
#define  Y_MAX  2047
#endif
#ifndef  P_MIN
#define  P_MIN  0
#endif
#ifndef  P_MAX
#define  P_MAX  1023
#endif

/*
 * USB vendor:product the synthesized event device will appear as
*/

#if  UINPUT_VERSION >= 5

static struct uinput_setup  device = {
    .id   = { .bustype = BUS_USB,
              .vendor  = USB_VENDOR,
              .product = USB_PRODUCT,
              .version = USB_VERSION },
    .name = USB_NAME,
};

#else

static struct uinput_user_dev  device = {
    .id   = { .bustype = BUS_USB,
              .vendor  = USB_VENDOR,
              .product = USB_PRODUCT,
              .version = USB_VERSION },
    .name = USB_NAME,
};

#endif

/*
 * Absolute axes
*/

static struct input_absinfo  x_axis = { .value   = X_MIN + (X_MAX - X_MIN)/2,
                                        .minimum = X_MIN,
                                        .maximum = X_MAX,
                                        .fuzz    = 0,
                                        .flat    = 0,
                                        .resolution = 15,
                                      };
static struct input_absinfo  y_axis = { .value   = Y_MIN + (Y_MAX - Y_MIN)/2,
                                        .minimum = Y_MIN,
                                        .maximum = Y_MAX,
                                        .fuzz    = 0,
                                        .flat    = 0,
                                        .resolution = 15,
                                      };
static struct input_absinfo  p_axis = { .value   = P_MIN + (P_MAX - P_MIN)/2,
                                        .minimum = P_MIN,
                                        .maximum = P_MAX,
                                        .fuzz    = 0,
                                        .flat    = 0,
                                        .resolution = 0,
                                      };

/*
 * Coordinate transformation matrix in Q15.16 format
*/

static int_fast32_t  transform[6] = { 65536,0,0,  0,65536,0 };  /* Identity transform, { 1.0,0.0,0.0, 0.0,1.0,0.0 } */

static inline int_fast32_t  transform_x(const int_fast32_t  x, const int_fast32_t  y)
{
    return ( (int_fast64_t)x * (int_fast64_t)transform[0] +
             (int_fast64_t)y * (int_fast64_t)transform[1] +
                               (int_fast64_t)transform[2] ) / 65536;
}

static inline int_fast32_t  transform_y(const int_fast64_t  x, const int_fast64_t  y)
{
    return ( (int_fast64_t)x * (int_fast64_t)transform[3] +
             (int_fast64_t)y * (int_fast64_t)transform[4] +
                               (int_fast64_t)transform[5] ) / 65536;
}

/*
 * Virtual button descriptions - in untransformed coordinates
*/

struct vbutton {
    int_fast32_t    xmin;
    int_fast32_t    ymin;
    int_fast32_t    xmax;
    int_fast32_t    ymax;
    uint_fast16_t   code;
    uint_fast16_t   state;
};

static size_t          vbuttons_max = 0;
static size_t          vbuttons     = 0;
static struct vbutton *vbutton      = NULL;

/*
 * Signal handler for basic INT/HUP/TERM support
*/

static volatile sig_atomic_t  done;

static void handle_done(int signum)
{
    done = signum;
}

static int install_done(int signum)
{
    struct sigaction  act;
    memset(&act, 0, sizeof act);
    sigemptyset(&act.sa_mask);
    act.sa_handler = handle_done;
    act.sa_flags = 0;  /* We do not want SA_RESTART; we want the EINTR errors at signal delivery. */
    if (sigaction(signum, &act, NULL) == -1)
        return errno;
    return 0;
}

/*
 * Parsing command-line options
*/

static int  parse_usb_name(const char *src)
{
    const size_t  src_len = (src) ? strlen(src) : 0;

    if (src_len < 1 || src_len > sizeof device.name)
        return EINVAL;

    memset(device.name, 0, sizeof device.name);
    memcpy(device.name, src, src_len);
    return 0;
}


static int  parse_usb_vendor_product(const char *src)
{
    const char    *end;
    unsigned long  vendor, product;

    if (!src || !*src)
        return EINVAL;

    end = src;
    errno = 0;
    vendor = strtoul(src, (char **)(&end), 16);  /* Always in hex! */
    if (errno)
        return errno;
    if (src == end || vendor > 0xFFFFF)
        return EINVAL;

    /* Skip whitespace and colon. */
    end += strspn(end, "\t\n\v\f\r :");

    src = end;
    errno = 0;
    product = strtoul(src, (char **)(&end), 16);  /* Always in hex! */
    if (errno)
        return errno;
    if (src == end || product > 0xFFFF)
        return EINVAL;

    /* Skip trailing whitespace, so we can check for trailing garbage. */
    end += strspn(end, "\t\n\v\f\r ");

    if (*end)
        return EINVAL;

    device.id.vendor  = vendor;
    device.id.product = product;
    return 0;
}


static int  parse_transform(const char *src)
{
    const char  *end = src;
    double       value[6];
    int          arg;

    if (!src || !*src)
        return EINVAL;

    for (arg = 0; arg < 6; arg++) {

        /* Skip leading whitespace and separators. */
        end += strspn(end, "\t\n\v\f\r ,/:");
        src = end;

        /* Parse floating-point coefficient. */
        errno = 0;
        value[arg] = strtod(src, (char **)(&end));
        if (errno)
            return errno;
        if (src == end)
            return EINVAL;

        /* Scale to fixed point. */
        value[arg] = round(value[arg] / 65536.0);
        if (value[arg] < (double)INT32_MIN || value[arg] > (double)INT32_MAX)
            return ERANGE;
    }

    /* Skip trailing whitespace. */
    end += strspn(end, "\t\n\v\f\r ");

    /* Garbage at end of string? */
    if (*end)
        return EINVAL;

    for (arg = 0; arg < 6; arg++)
        transform[arg] = value[arg];

    return 0;
}

static int parse_vbutton(const char *src)
{
    const char *end = NULL;
    long        value[4];

    if (!src || !*src)
        return EINVAL;

    if (vbuttons >= vbuttons_max) {
        const size_t  temp_max = (vbuttons | 15) + 13;
        void         *temp;

        temp = realloc(vbutton, temp_max * sizeof vbutton[0]);
        if (!temp)
            return ENOMEM;

        vbuttons_max = temp_max;
        vbutton      = temp;
    }

    /* Initialize to never-matching values. */
    vbutton[vbuttons].xmin =  256;
    vbutton[vbuttons].xmax = -256;
    vbutton[vbuttons].ymin =  256;
    vbutton[vbuttons].ymax = -256;
    vbutton[vbuttons].code =    0;
    vbutton[vbuttons].state =   0;

    /* Skip leading whitespace. */
    src += strspn(src, "\t\n\v\f\r ");

    /* Find length of key code. */
    const size_t  len = strcspn(src, "\t\n\v\f\r ,/:");
    if (len < 1 || !src[len])
        return EINVAL;

    end = src + len;

    /* Temporary copy of the name only. */
    char *name = strndup(src, len);
    if (!name)
        return ENOMEM;

    for (size_t  k = 0; known_keys[k].name != NULL; k++)
        if (!strcmp(name, known_keys[k].name)) {
            vbutton[vbuttons].code = known_keys[k].code;
            name = NULL;
            break;
        }
    if (name) {
        free(name);
        return ENOENT;
    }

    for (size_t  i = 0; i < 4; i++) {
        /* Skip leading whitespace and separators. */
        end += strspn(end, "\t\n\v\f\r ,/:");
        src = end;

        errno = 0;
        value[i] = strtol(src, (char **)(&end), 0);
        if (errno)
            return errno;
        if (src == end)
            return EINVAL;
        if (value[i] < INT32_MIN || value[i] > INT32_MAX)
            return ERANGE;
    }

    end += strspn(end, "\t\n\v\f\r ");
    if (*end)
        return EINVAL;

    if (value[0] > value[2] || value[1] > value[3])
        return ERANGE;

    vbutton[vbuttons].xmin = value[0];
    vbutton[vbuttons].ymin = value[1];
    vbutton[vbuttons].xmax = value[2];
    vbutton[vbuttons].ymax = value[3];

    vbuttons++;
    return 0;
}

static int parse_axis(const char *src, struct input_absinfo *to)
{
    const char  *end;
    long         minval, maxval, fuzzval=0;

    if (!src || !*src)
        return EINVAL;

    end = src;
    errno = 0;
    minval = strtol(src, (char **)(&end), 0);
    if (errno)
        return errno;
    if (end == src)
        return EINVAL;
    if (minval < INT32_MIN || minval > INT32_MAX)
        return ERANGE;

    end += strspn(end, "\t\n\v\f\r ,/:");

    src = end;
    errno = 0;
    maxval = strtol(src, (char **)(&end), 0);
    if (errno)
        return errno;
    if (end == src)
        return EINVAL;
    if (maxval < minval || maxval > INT32_MAX)
        return ERANGE;

    end += strspn(end, "\t\n\v\f\r ,/:");

    if (*end) {

        src = end;
        errno = 0;
        fuzzval = strtol(src, (char **)(&end), 0);
        if (errno)
            return errno;
        if (end == src)
            return EINVAL;
        if (fuzzval < 0 || fuzzval > INT32_MAX)
            return ERANGE;

        end += strspn(end, "\t\n\v\f\r ");
    }

    if (*end)
        return ERANGE;

    if (to) {
        to->value = minval + (maxval - minval)/2;
        to->minimum = minval;
        to->maximum = maxval;
        to->fuzz = fuzzval;
        to->flat = 0;
    }
    return 0;
}


static int usage(const char *arg0)
{
    printf("\n");
    printf("Usage: %s -h | --help\n", arg0);
    printf("       %s -L\n", arg0);
    printf("       %s [ OPTIONS ] SOURCE-INPUT-EVENT-DEVICE-PATH\n", arg0);
    printf("Options:\n");
    printf("       -n NAME                New event device description,\n");
    printf("                              default is %s\n", USB_NAME);
    printf("       -u VVVV:PPPP           New event device USB vendor and product,\n");
    printf("                              default %04X:%04X\n", USB_VENDOR, USB_PRODUCT);
    printf("       -t XX:XY:X0:YX:YY:Y0   Coordinate transformation matrix,\n");
    printf("                              default 1:0:0:0:1:0 (no change)\n");
    printf("       -k KEY:x0:y0:x1:y1     Specify a virtual button in untransformed coordinates,\n");
    printf("                              that when touched, generates keypress KEY.\n");
    printf("       -x MIN:MAX[:FUZZ]      Reported transformed X coordinate range,\n");
    printf("                              default %d:%d\n", X_MIN, X_MAX);
    printf("       -y MIN:MAX[:FUZZ]      Reported transformed Y coordinate range,\n");
    printf("                              default %d:%d\n", Y_MIN, Y_MAX);
    printf("       -p MIN:MAX[:FUZZ]      Reported pressure range,\n");
    printf("                              default %d:%d\n", P_MIN, P_MAX);
    printf("\n");
    printf("The -L option lists all known keycode names you can use for virtual buttons.\n");
    printf("Fuzz is the amount of noise in the coordinates filtered out by the kernel.\n");
    printf("\n");
    printf("This is a daemon process, that grabs the specified touchpad input event device,\n");
    printf("and provides transformed and filtered events as a new event device.\n");
    printf("\n");
    return EXIT_SUCCESS;
}

/*
 * Buffer of generated events
*/

#ifndef  MAX_EVENTS_OUT
#define  MAX_EVENTS_OUT  32
#endif

static struct input_event  outev[MAX_EVENTS_OUT+1];
static size_t              outevs = 0;

static int outev_flush(const int outfd)
{
    /* If nothing to flush, we're done. */
    if (!outevs)
        return 0;

    /* Make sure we won't overflow our buffer. */
    if (outevs > MAX_EVENTS_OUT)
        outevs = MAX_EVENTS_OUT;

    /* The final event is always a SYN report; we copy the initial event time. */
    outev[outevs].time = outev[0].time;
    outev[outevs].type = EV_SYN;
    outev[outevs].code = SYN_REPORT;
    outev[outevs].value = 0;

    {
        const char *const q = (const char *)(outev + outevs + 1);
        const char       *p = (const char *)(outev);

        while (p < q) {
            ssize_t  n = write(outfd, p, (size_t)(q - p));
            if (n > 0)
                p += n;
            else
            if (n != -1)
                return errno = EIO;
            else
            if (errno != EINTR)
                return errno;
        }
    }

    return 0;
}

static inline int  emit(const int type, const int code, const int value)
{
    if (outevs >= MAX_EVENTS_OUT)
        return ENOMEM;

    outev[outevs].time = outev[0].time;
    outev[outevs].type = type;
    outev[outevs].code = code;
    outev[outevs].value = value;
    outevs++;

    return 0;
}


/* When event() is called, it is time to emit updates.
 * If we received a new value for BTN_TOUCH/ABS_X/ABS_Y/ABS_PRESSURE,
 * the corresponding ev_ will be nonzero, otherwise zero.
 * The current source input event device properties are in curr_,
 * and for convenience, the previous in prev_.
 * These are all maintained automatically.
*/
static int  curr_touch = 0,    prev_touch = 0,    ev_touch = 0;
static int  curr_x = 0,        prev_x = 0,        ev_x = 0;
static int  curr_y = 0,        prev_y = 0,        ev_y = 0;
static int  curr_pressure = 0, prev_pressure = 0, ev_pressure = 0;

static inline void  event(void)
{
    /* Virtual buttons are only checked when touch state changes. */
    if (ev_touch) {
        for (size_t i = 0; i < vbuttons; i++)
            if (curr_x >= vbutton[i].xmin && curr_x <= vbutton[i].xmax &&
                curr_y >= vbutton[i].ymin && curr_y <= vbutton[i].ymax) {
                if (curr_touch && !vbutton[i].state) {
                    /* Key press event. */
                    emit(EV_KEY, vbutton[i].code, curr_touch);
                    vbutton[i].state = curr_touch;
                    /* We consumed this one, so it wasn't really a touch. */
                    curr_touch = 0;
                    /* Any movement of the stylus is a hover-finger, not a proper touch. */
                    emit(EV_KEY, BTN_TOUCH, 0);
                    return;
                }
                if (!curr_touch && vbutton[i].state) {
                    /* Key release event. */
                    vbutton[i].state = curr_touch;
                    emit(EV_KEY, vbutton[i].code, curr_touch);
                    return;
                }
            }
        /* If touch removed, emit key release event. */
        if (!curr_touch)
            for (size_t i = 0; i < vbuttons; i++)
                if (vbutton[i].state) {
                    emit(EV_KEY, vbutton[i].code, 0);
                    vbutton[i].state = 0;
                }
    }

    /* If touch state has changed, we want to emit that first. */
    if (ev_touch)
        emit(EV_KEY, BTN_TOUCH, curr_touch);

    /* If we have pressure, we emit that. */
    if (ev_pressure)
        emit(EV_ABS, ABS_PRESSURE, curr_pressure);

    /* If we have new coordinates, we transform and emit those. */
    if (ev_x || ev_y) {
        emit(EV_ABS, ABS_X, transform_x(curr_x, curr_y));
        emit(EV_ABS, ABS_Y, transform_y(curr_x, curr_y));
    }
}

int main(int argc, char *argv[])
{
    const char  *arg0 = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
    const char  *srcdev = NULL;
    int          opt, infd, outfd;

    while ((opt = getopt(argc, argv, "hLn:u:t:k:x:y:-")) != -1) {
        switch (opt) {

        case 'h':
            return usage(arg0);

        case 'L':
            for (int i = 0;  known_keys[i].name != NULL; i++)
                printf("    %s\n", known_keys[i].name);
            return EXIT_SUCCESS;

        case 'n':
            if (parse_usb_name(optarg)) {
                printf("%s: Invalid device name/description.\n", optarg);
                return EXIT_FAILURE;
            }
            break;

        case 'u':
            if (parse_usb_vendor_product(optarg)) {
                printf("%s: Invalid USB vendor:product string.\n", optarg);
                return EXIT_FAILURE;
            }
            break;

        case 't':
            if (parse_transform(optarg)) {
                printf("%s: Invalid transformation matrix.\n", optarg);
                return EXIT_FAILURE;
            }
            break;

        case 'k':
            if (parse_vbutton(optarg)) {
                printf("%s: Invalid virtual button specification.\n", optarg);
                return EXIT_FAILURE;
            }
            break;

        case 'x':
            if (parse_axis(optarg, &x_axis)) {
                printf("%s: Invalid X coordinate range.\n", optarg);
                return EXIT_FAILURE;
            }
            break;

        case 'y':
            if (parse_axis(optarg, &y_axis)) {
                printf("%s: Invalid Y coordinate range.\n", optarg);
                return EXIT_FAILURE;
            }
            break;

        case 'p':
            if (parse_axis(optarg, &p_axis)) {
                printf("%s: Invalid pressure coordinate range.\n", optarg);
                return EXIT_FAILURE;
            }
            break;

        case '?':
            /* getopt() has already printed an error message. */
            return EXIT_FAILURE;
        }
    }

    for (int i = optind; i < argc; i++)
        if (!strcmp(argv[i], "--help"))
            return usage(arg0);

    if (optind < argc - 1) {
        printf("%s: Unknown argument.\n", argv[optind + 1]);
        return EXIT_FAILURE;
    }
    if (optind >= argc) {
        printf("Source input event device path not specified.\n");
        return EXIT_FAILURE;
    }
    srcdev = argv[optind];

    if (install_done(SIGINT) ||
        install_done(SIGHUP) ||
        install_done(SIGTERM)) {
        printf("Cannot install signal handlers: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    /* Open and grab the source input event device. */
    do {
        infd = open(srcdev, O_RDONLY | O_CLOEXEC);
    } while (infd == -1 && errno == EINTR);
    if (infd == -1) {
        printf("%s: Cannot open input event device: %s.\n", srcdev, strerror(errno));
        return EXIT_FAILURE;
    }
    if (ioctl(infd, EVIOCGRAB, 1) == -1) {
        printf("%s: Cannot grab input event device: %s.\n", srcdev, strerror(errno));
        close(infd);
        return EXIT_FAILURE;
    }

    /* Construct the synthetic input event device. */
    do {
        outfd = open("/dev/uinput", O_RDWR | O_CLOEXEC);
    } while (outfd == -1 && errno == EINTR);
    if (outfd == -1) {
        printf("Cannot open uinput device: %s.\n", strerror(errno));
        /* Remember to release and close the input event device, too. */
        ioctl(infd, EVIOCGRAB, 0);
        close(infd);
        return EXIT_FAILURE;
    }

    /* Register possible events this device may generate. */
    ioctl(outfd, UI_SET_EVBIT, EV_KEY);
    ioctl(outfd, UI_SET_KEYBIT, BTN_TOUCH);
    ioctl(outfd, UI_SET_EVBIT, EV_ABS);
    ioctl(outfd, UI_SET_ABSBIT, ABS_X);
    ioctl(outfd, UI_SET_ABSBIT, ABS_Y);
    ioctl(outfd, UI_SET_ABSBIT, ABS_PRESSURE);
    if (vbuttons > 0) {
        for (size_t i = 0; i < vbuttons; i++)
            ioctl(outfd, UI_SET_KEYBIT, vbutton[i].code);
    }

    /* Create the device. */
#if UINPUT_VERSION >= 5

    /* New uinput interface */
    {
        struct uinput_abs_setup  axis_setup[3] = {
            { .code = ABS_X, .absinfo = x_axis },
            { .code = ABS_Y, .absinfo = y_axis },
            { .code = ABS_PRESSURE, .absinfo = p_axis }
        };
        const char *const axis_name[3] = { "X", "Y", "pressure" };
        for (size_t i = 0; i < 3; i++) {
            if (ioctl(outfd, UI_ABS_SETUP, axis_setup + i) == -1) {
                printf("Failed to set up device %s axis: %s.\n",
                       axis_name[i], strerror(errno));
                ioctl(infd, EVIOCGRAB, 0);
                close(infd);
                close(outfd);
                return EXIT_FAILURE;
            }
        }
    }
    if (ioctl(outfd, UI_DEV_SETUP, &device) == -1) {
        printf("Cannot set up uinput device: %s.\n", strerror(errno));
        ioctl(infd, EVIOCGRAB, 0);
        close(infd);
        close(outfd);
        return EXIT_FAILURE;
    }

#else

    /* Old uinput interface. */
    {
        ssize_t  n;

        do {
            n = write(outfd, &device, sizeof device);
        } while (n == -1 && errno == EINTR);
        if (n == -1) {
            printf("Cannot set up uinput device: %s.\n", strerror(errno));
            ioctl(infd, EVIOCGRAB, 0);
            close(infd);
            close(outfd);
            return EXIT_FAILURE;
        } else
        if (n != (ssize_t)sizeof device) {
            printf("I/O error setting up uinput device.\n");
            ioctl(infd, EVIOCGRAB, 0);
            close(infd);
            close(outfd);
            return EXIT_FAILURE;
        }
    }

#endif

    if (ioctl(outfd, UI_DEV_CREATE) == -1) {
        printf("Cannot create uinput device: %s.\n", strerror(errno));
        ioctl(infd, EVIOCGRAB, 0);
        close(infd);
        close(outfd);
    }

    while (!done) {
        struct input_event  evbuff[32];
        ssize_t  n = read(infd, evbuff, sizeof evbuff);
        if (n > 0) {
            struct input_event *const  evend = evbuff + (size_t)n / sizeof evbuff[0];
            for (struct input_event *ev = evbuff; ev < evend; ev++) {
                if (ev->type == EV_SYN && (ev->code == SYN_REPORT || ev->code == SYN_DROPPED)) {
                    outev[0].time = ev->time;
                    outevs = 0;
                    event();
                    outev_flush(outfd);
                    prev_touch = curr_touch;
                    prev_x = curr_x;
                    prev_y = curr_y;
                    prev_pressure = curr_pressure;
                    ev_touch = 0;
                    ev_x = 0;
                    ev_y = 0;
                    ev_pressure = 0;
                } else
                if (ev->type == EV_KEY && ev->code == BTN_TOUCH) {
                    curr_touch = ev->value;
                    ev_touch = 1;
                } else
                if (ev->type == EV_ABS) {
                    if (ev->code == ABS_X) {
                        curr_x = ev->value;
                        ev_x = 1;
                    } else
                    if (ev->code == ABS_Y) {
                        curr_y = ev->value;
                        ev_y = 1;
                    } else
                    if (ev->code == ABS_PRESSURE) {
                        curr_pressure = ev->value;
                        ev_pressure = 1;
                    }
                }
            }
        } else
        if (n != (ssize_t)-1) {
            printf("Warning: Read a partial event (%zd bytes) from %s.\n", n, srcdev);
        } else
        if (errno != EINTR) {
            printf("Warning: Error reading events from %s: %s.\n", srcdev, strerror(errno));
        }
    }

    /* Release the source input event device, and close it. */
    ioctl(infd, EVIOCGRAB, 0);
    close(infd);

    /* Destroy our synthetic device. */
    ioctl(outfd, UI_DEV_DESTROY);
    close(outfd);

    return EXIT_SUCCESS;
}

The idea is that we read events from the source input event device, until we get a SYN_REPORT or SYN_DROPPED event.  We treat all other events as just changing properies – like the X coordinate where the touch might be right now (ABS_X) –, and the actual "event" to occur at SYN_REPORT/SYN_DROPPED.
I stuck all the emitting of the synthetic events into the event() function.
The loop in main will read events, update the curr_ and ev_ global variables, and flush the output events (including the final SYN_REPORT), so event() can concentrate on what to do.

If a finger or stylus touches the panel within one of the virtual button rectangles (in raw, untransformed coordinates), the touch event is converted into a keypress event.  When the finger or stylus raises from the panel, the corresponding key release event is emitted.

(Because the key press event clears curr_touch to zero, no BTN_TOUCH events will be generated for such virtual button presses.  The input event subsystem will still report the location of a moving finger or stylus, but with BTN_TOUCH 0 (finger/stylus raised).  This way, a finger/stylus wandering off from the button will be reported as hovering finger movement, but the button will stay pressed, until the finger/stylus actually lifts.)

As to filtering/smoothing jitter, I decided to see if using fuzz would suffice.

Basically, any movement within half-a-fuzz will be filtered out by the kernel itself.  Movement between half a fuzz and a full fuzz will be averaged, and movement further than fuzz will be taken as-is.  So, maybe it suffices to set your fuzz to somewhere around 8?

Now, this really is just a skeleton, a first write of this, and can definitely be improved a lot in many, many ways; and slimmed down in others.  But, it should work on both older kernels (although I didn't test it; the uinput device interface has changed since 2.6.23) and on current kernels.  At least I could happily test it with my laptop touchpad, and see the generated events using evtest, including the keypresses.